I've got a bit of an odd hypothetical question dealing with signals and setjmp/longjmp. I've looked at POSIX/susv3 and I can't find anything dealing with what happens if you call longjmp with pending signals.
Suppose we have an app with multiple signals pending. (Say, SIGALRM and SIGSEGV.) In the signal handler for SIGSEGV, we're going to call call longjmp(). (Yes, I'm aware of the issues.)
At this point we're still in the kernel and both SIGSEGV and SIGALARM are pending. What happens?
If we run the SIGSEGV handler does the SIGALARM stay pending until the segfault handler completes? What happens when the segfault handler calls longjmp()? Does the SIGALARM handler get called on the logical return from sigsetjmp(), and if so how does that happen since the glibc code for setjmp/longjmp doesn't seem to call any kernel syscalls?
Chris Friesen <cbf...@mail.usask.ca> writes: >I've got a bit of an odd hypothetical question dealing with signals and >setjmp/longjmp. I've looked at POSIX/susv3 and I can't find anything >dealing with what happens if you call longjmp with pending signals.
>Suppose we have an app with multiple signals pending. (Say, SIGALRM and >SIGSEGV.) In the signal handler for SIGSEGV, we're going to call call >longjmp(). (Yes, I'm aware of the issues.)
>At this point we're still in the kernel and both SIGSEGV and SIGALARM >are pending. What happens?
>If we run the SIGSEGV handler does the SIGALARM stay pending until the >segfault handler completes? What happens when the segfault handler >calls longjmp()? Does the SIGALARM handler get called on the logical >return from sigsetjmp(), and if so how does that happen since the glibc >code for setjmp/longjmp doesn't seem to call any kernel syscalls?
>Thanks for any information you can provide...
>Chris
It all depends whether you use signal(2) or sigaction(2), what your current sigprocmask(2) is, and what mask you tell the system to use when delivering the signal (see sigaction(2)).
Also, you should be using siglongjmp, not longjmp.
btw - the handler runs in the context of your application, not the kernel.
> Chris Friesen <cbf...@mail.usask.ca> writes: >> I've got a bit of an odd hypothetical question dealing with signals and >> setjmp/longjmp. I've looked at POSIX/susv3 and I can't find anything >> dealing with what happens if you call longjmp with pending signals.
>> Suppose we have an app with multiple signals pending. (Say, SIGALRM and >> SIGSEGV.) In the signal handler for SIGSEGV, we're going to call call >> longjmp(). (Yes, I'm aware of the issues.)
>> At this point we're still in the kernel and both SIGSEGV and SIGALARM >> are pending. What happens?
>> If we run the SIGSEGV handler does the SIGALARM stay pending until the >> segfault handler completes? What happens when the segfault handler >> calls longjmp()? Does the SIGALARM handler get called on the logical >> return from sigsetjmp(), and if so how does that happen since the glibc >> code for setjmp/longjmp doesn't seem to call any kernel syscalls?
>> Thanks for any information you can provide...
>> Chris
> It all depends whether you use signal(2) or sigaction(2), what your > current sigprocmask(2) is, and what mask you tell the system to use > when delivering the signal (see sigaction(2)).
> Also, you should be using siglongjmp, not longjmp.
> btw - the handler runs in the context of your application, not the > kernel.
Okay, for sake of discussion let's say that we're using sigaction for each signal handler, and in each case the only signal masked is the signal being handled. Also assume that initially no signals are blocked.
For the purposes of the discussion I specifically asked about longjmp because it doesn't reset the signal mask and thus (at least for glibc) doesn't issue any kernel syscalls.
I'm aware that the handler runs in the context of the app. However, for a signal to interrupt the application the kernel must be involved. Normally when you finish a signal handler you return back to the kernel and if there is a pending signal it will switch back to userspace and run the signal handlers before returning back to the main thread of execution of the app.
If I call longjmp from the initial signal handler, rather than returning back to the kernel the app switches context to what it was at the time of the setjmp. As far as I can tell at least for glibc this doesn't involve any syscalls so nothing triggers the kernel to run any additional pending signals.
The whole point of this line of questioning is that I'm curious if there's anything in the posix/sus spec that I've missed that deals with what specificially is supposed to happen if I call longjmp with pending signals. i.e...when are they supposed to be delivered?
Chris Friesen <cbf...@mail.usask.ca> writes: >On 11/06/2009 05:52 PM, Scott Lurndal wrote:
>> It all depends whether you use signal(2) or sigaction(2), what your >> current sigprocmask(2) is, and what mask you tell the system to use >> when delivering the signal (see sigaction(2)).
>> Also, you should be using siglongjmp, not longjmp.
>Okay, for sake of discussion let's say that we're using sigaction for >each signal handler, and in each case the only signal masked is the >signal being handled. Also assume that initially no signals are blocked.
>For the purposes of the discussion I specifically asked about longjmp >because it doesn't reset the signal mask and thus (at least for glibc) >doesn't issue any kernel syscalls.
>I'm aware that the handler runs in the context of the app. However, for >a signal to interrupt the application the kernel must be involved. >Normally when you finish a signal handler you return back to the kernel >and if there is a pending signal it will switch back to userspace and >run the signal handlers before returning back to the main thread of >execution of the app.
>If I call longjmp from the initial signal handler, rather than returning >back to the kernel the app switches context to what it was at the time >of the setjmp. As far as I can tell at least for glibc this doesn't >involve any syscalls so nothing triggers the kernel to run any >additional pending signals.
>The whole point of this line of questioning is that I'm curious if >there's anything in the posix/sus spec that I've missed that deals with >what specificially is supposed to happen if I call longjmp with pending >signals. i.e...when are they supposed to be delivered?
POSIX doesn't define when signals are delivered. I don't recall that the order is specified either (although most kernels will use a find-first-set-bit instruction to find the next signal to deliver, implying that lower signal numbers will be delivered ahead of higher signal numbers).
Synchronously generated signals (such as SIGSEGV, SIGBUS, SIGFPE) will always be delivered immediately (on the instruction and/or system call that generated the signal).
I think you've answered your own question; POSIX defines sigsetjmp so that the signal mask _will_ be restored as part of the siglongjmp; If sigaction was used and the kernel had masked the signal during delivery, it is expecting the signal handler to be returned from in order to remove sa_mask. If you don't return from the signal handler and you use longjmp, the signal that caused entry to the signal handler will remain masked.
As for when signals get delivered, they can be delivered upon return from a system call or can be delivered whenever the process is context switched (consider an interval timer interrupting a user-mode loop, where no system call is invoked).
A portable program must expect that a pending signal can be delivered at any time it is not masked, even during the longjmp (if, for example, your process was pre-empted by a higher priority processor or an interrupt). Ensuring that you don't invoke any system call won't prevent synchronous nor asynchronous unmasked signals from being delivered.