kern/131597: [kernel] c++ exceptions very slow on FreeBSD
7.1/amd64
David Xu
davidxu at freebsd.org
Wed Sep 15 02:11:48 UTC 2010
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)
}
More information about the freebsd-bugs
mailing list