On Thu, Sep 29, 2011 at 05:06:54PM +0100, Alaric Snell-Pym wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On 09/29/2011 04:47 PM, Alan Post wrote: > > It seems that the thread-like nature of signal handling and the > > thread-like nature of threading have been intermixed in the > > scheduler, and this particular feature is at cross-purposes. > > So it seems... Signals should always end up being handled somewhere, > unlessly explicitly set to be ignored; in that case, ignoring it IS > handling it, but not otherwise. >
I'll add too that signals have an API-level mechanism for ignoring them, which we should probably use. And yes. > IIRC, signals are handled by setting a flag and poking the stack limit > then returning. A GC is then invoked as soon as the interrupted thread > tries to allocate memory, due to the poked stack limit, but the GC > checks for the signal flag and goes off to do the signal if it has to. > > I presume that invoking the Chicken runtime inside the C-level signal > handler is unsafe on account of Chicken wanting to call non-signal-safe > C functions. > It would be something of a minor miracle were this not true. I think it is technically achievable, though I say that with zero understanding of the actual effort involved. It's more my ideal case worth banging my head against a few times than something I think we can do in practice. > I presume that allocating memory in a Chicken-level signal handler is > "risky" as you might have actually been at or near the stack limit when > the signal happened. > > I have not looked at the mechanism in code - just heard hearsay about it > - - so please take this suggestion with a pinch of salt: > > 1) Have a (signal-safe) data structure containing pending signals. This > might just be a bitmask, or if we want to be flash, a queue of generic > pending "software interrupts" if there's uses for it other than signals. > > 2) C-level signal handlers poke an entry into the structure indicating > the need to invoke a Chicken signal handler, and poke the stack limit > > [all of the above is basically what I think we already have] > > 3) The GC, invoked due to the stack limit being breached, checks for > pending signals. If there are any, it resets the stack limit to what it > was originally, then modifies the currently active continuation to a > newly-allocated one that invokes a system procedure which executes all > pending signals, then continues to the previous continuation; and returns. > > The normal stack limit needs to be set so that there will always, in the > worst case, be enough space to allocate that extra continuation frame. > If the system WAS at the edge of the stack when the signal(s) came in, > it would then still be able to allocate the special continuation; > execution of it would then almost instantly trigger a perfectly ordinary > GC, and execution would continue as usual, executing the pending signal > handler(s) then continuing with user code as before. > The Minix source code is illustrative on this point. I think a program being near the stack limit when a signal arrives is the only time in that operating system that a process will be killed without the normal mechanims the kernel goes through--It just tosses the thing out. I've never looked at how this behaves on *BSD or Linux, but I imagine there is a similar condition (or as you outline above, a reserve available). So this comes up even in C, which at least on Minux is not a handleable condition. We effectively can't handle it if our GC makes a syscall--I imagine that we minimally call sbrk() (or whatever the kids call it these days) in the event of a full, post-GC heap. That may well be a terminal case in this rabbit hole, mirroring the terminal case in the C code. > That would give you low latency, unless the GC really needed to happen, > in which case... well... it needs to happen before the handler can run. > It would run signal handlers in the context of the currently executing > thread when they happened, so to all intents and purposes it would be > normal Chicken code, and the current thread would just temporarily dart > off into signal handlers when required; I'm not sure what dynamic > environment (in the parameters/current-output-port) they should be in; > neither do I know how they are implemented in Chicken! Perhaps they > should encapsulate a copy of the dynamic environment in place when the > signal handler was registered, as the most hygienic option... > I pretty much rely on my registered signal handler being in the dynamic environment it was declared in. The EINTR test case uses this to get hold of a file descriptor created in the main thread. I'll add that we might of course get a signal while performing GC, a case that needs to be accounted for. And that we also *must* handle deferred signals before making another syscall, whether that syscall happened from user code or whether we're making a syscall in service to the need of the runtime. I think is a fantastic outline of what needs to happen. I will work on a patch, with no guarantee of how fast I will be. -Alan -- .i ma'a lo bradi cu penmi gi'e du _______________________________________________ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users