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>