[Gc] GC, signals and interrupts
hans.boehm at hp.com
Tue Oct 21 17:40:11 PDT 2008
> -----Original Message-----
> From: gc-bounces at napali.hpl.hp.com
> [mailto:gc-bounces at napali.hpl.hp.com] On Behalf Of Juan Jose
> Sent: Friday, October 10, 2008 2:08 PM
> To: gc at napali.hpl.hp.com
> Subject: [Gc] GC, signals and interrupts
> [I posted this through gmane, but did not show up in the
> archives, hence I decided to try my luck again, but via ordinary mail]
> I was wondering whether there are some simple guidelines on
> using the garbage collector with our Common Lisp interpreter.
> Roughly I am now worrying about the following issues:
> 1 - ECL needs to detect stack overflows. Currently by
> installing the handler _before_ calling GC_init, it seems
> that the garbage collector honors our handler and it gets
> called for any SIGSEGV related to stack overflows and not to
> GC. Is this ok?
I think this should generally work. It was certainly the intention whenever it's possible. I think there may be some issues with honoring some of the other prior information associated with the old handler, notably with SA_SIGINFO.
A lot of the details here depend on whether you need/use thread support in the GC and/or incremental GC. Otherwise the GC makes minimal use of signals.
> 2 - Not long ago, we used to call arbitrary lisp code from
> the signal handler. I learnt the hard way this is evil and
> thus I am now delaying signals by using a global flag. Should
> I also prevent interrupts by setting this flag around calls
> to the garbage collector? I insist our handler is not
> delaying GC signals, only SIGINT and the like.
I'm not sure I understand your scheme exactly. You set a flag in the mainline code to disable the handler? Or you set a flag in the handler, and run the "interrupt" code from the mainline code instead?
You don't want to run Lisp code while the collector is active. Memory allocation probably won't work correctly at that stage. With threads, it's likely to deadlock, since the GC will already hold the lock.
> 3 - If we are not to prevent signals from happening during
> allocation and garbage collection, is it safe to use
> longjmp() from the signal handler and jump to a point before
> the call to the allocator (*)? I presume not and then the
> answer to 2 should be really: please defer signals.
If I understand correctly, then this is correct. Old versions of the collector used to make some attempt at being safe against interruption by a signal. But with modern compilers, that's pretty much impossible without declaring all GC state volatile (and whether that's likely to work will probably depend on the platform).
> 4 - Skimming the mailing list I learnt that the library uses
> signals to suspend threads. Will this cause failure of C
> functions or only those related to I/O?
> Should I then surround all those calls with GC_start/end_blocking?
This rarely causes problems even with system calls, since SA_RESTART should be set for the handler. It does seem to very occasionally cause problems with some system calls, not user level C functions. I think it's more likely to cause failures while the process is being debugged.
GC_start/end_blocking has an inherent issue with ensuring that callee-save registers are reliably scanned. I don't think anyone has seen it fail in practice. But that's the reason for the interface change to GC_do_blocking in 7.x. My inclination would be to use GC_do_blocking around calls in which many threads are likely to be blocked at GC time (since that may improve performance), and around any that are empirically discovered to be otherwise problematic.
> 5 - What signals should we _not_ handle? Or is it ok if we
> just install our handlers before GC_init? In particular, for
> fast detection of pending signals I am currently using
> mprotect to block writes to the disable_signal flag. That
> means we need to be able to handle SIGBUS for regions which
> are not garbage collected.
I think that should work, but you're on slightly thin ice with incremental GC.
For threads, the collector uses SIG_SUSPEND and SIG_THR_RESTART, which are defined in somehat complicated platform-specific ways by gcconfig.h and gc_priv.h. On Linux, it usually uses SIGPWR and SIGXCPU. Probably the collector build process should generate a header file that includes these for client use. But it currently doesn't.
The incremental GC typically uses SIGBUS or SIGSEGV, depending on what the platform generates on a protection fault. On some platforms, one of these isalso used near startup to identify bounds of address space sections.
> 6 - Am I missing other questions?
> Thanks in advance,
> (*) I know using longjmp() from a signal handler is typically
> a bad practice, but as I said before, we only do that when we
> know the handler was only invoked from safe code and did not
> interrupt calls to the C library.
> Instituto de Física Fundamental, CSIC
> c/ Serrano, 113b, Madrid 28009 (Spain)
> Gc mailing list
> Gc at linux.hpl.hp.com
More information about the Gc