Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Sep 2010 10:11:46 +0000
From:      David Xu <davidxu@freebsd.org>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        freebsd-bugs@freebsd.org, Tijl Coosemans <tijl@coosemans.org>
Subject:   Re: kern/131597: [kernel] c++ exceptions very slow on FreeBSD 7.1/amd64
Message-ID:  <4C909BE2.1050903@freebsd.org>
In-Reply-To: <20100914225327.B825@delplex.bde.org>
References:  <201009140940.o8E9e3dH040847@freefall.freebsd.org> <20100914225327.B825@delplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Bruce Evans wrote:
> On Tue, 14 Sep 2010, Tijl Coosemans wrote:
> 
>> On Thu, Jul 08, 2010 at 11:29:50AM -0400, John Baldwin wrote:
>> > ...longjmp(3) isn't safe in a signal context...
>>
>> POSIX says it's supposed to be safe:
>>
>>   "As it bypasses the usual function call and return mechanisms,
>>   longjmp() shall execute correctly in contexts of interrupts, signals,
>>   and any of their associated functions. However, if longjmp() is
>>   invoked from a nested signal handler (that is, from a function
>>   invoked as a result of a signal raised during the handling of another
>>   signal), the behavior is undefined."
> 
> It cannot be really safe.  It can only execute correctly (where the
> definition of "correctly" must not require much more than restoring the
> context saved by setjmp().  Consider a signal interrupting almost any
> library function that acts on global storage.  Only return from the
> signal handler (after not clobbering the global storage acted on by the
> function) can let the function complete correctly.
> 
> POSIX also says:
> 23731              All accessible objects have values, and all other 
> components of the abstract machine have state
> 23732              (for example, floating-point status flags and open 
> files), as of the time longjmp( ) was called,
> 23733              except that the values of objects of automatic 
> storage duration are unspecified if they meet all
> 23734              the following conditions:
> 
> I don't really understand unwinding, but this seems to forbid significant
> unwinding.  This also expicitly requires broken behaviour for the floating
> point state.  Keeping the floating point status flags at the time of the
> longjmp() is good in general (so that the flags accumulate), but not when
> the longjmp() is from a signal handler since signal handlers should get a
> clean FP state.  Keeping other parts of the FP environment at the time of
> the longjmp() is not so good in general, and worse for longjmp() from 
> signal
> handlers.  FreeBSD is supposed to keep the FP status flags at the time of
> the longjmp() and restore the FP control flags at the time of the setjmp(),
> but gets this wrong in more than half of the 24 cases (24 cases = 2 arches
> times 3 longjmp()s (also _longjmp() and siglongjmp()) times 4 sets of flags
> (mxcsr control/status and i387-environment control/status); only 1 of the
> 6 longjmp files has been updated to understand mxcsr, and it still uses the
> old method of clearing the i386 status flags.
> 
> Bruce

The pthread asynchronous cancellation has to unwind from signal handler,
for C language, it has pthread_cleanup_push/pop to handle it. but for
other languages, this is a ugly hack.

I found the standard to unwind stack at here:
http://www.codesourcery.com/public/cxx-abi/abi-eh.html
the unwinding never returns, I think they must take care of the cpu
flags, it does not mean it uses setjmp+longjmp, it uses elf sections
dig out cleanup handler,

but unwinding from signal handler is always trouble, look the bug:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26208
It seems i387 would be a serious problem.

The asynchronous cancellation also needs instruction level unwinding
info, gcc flag -fasynchronous-unwind-tables is needed, and some cfi
entry needs to insert into asm code.
http://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/gnu-assembler/cfi-directives.html
all things can cause very large library size, and if any piece of code
missing the unwinding info, the unwinding can be broken.
I think asynchronous cancellation is non-practical for C++ like
language, it is not constructed in this way.

a realisitic and economy solution would be defer-mode cancellation or
if a user wants asynchronous cancel thread while it is doing pure
computation,it can use sigsetjmp + siglongjmp.

for example, if user is doing some heavy computation, he can:

if (sigsetjmp(&jbuf)) {
	pthread_exit(..);
}

/* start doing heavy computation, can be cancelled anywhere: */

...

in signal handler:
it can
void sighandler(int sig) {
     siglongjmp(&jbuf)
}




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4C909BE2.1050903>