A signal fairy tale
Once upon a time a hacker named Xman
wrote a library that used aio, and decided
to use sigtimedwait() to pick up completion notifications. It worked well, and his I/O
was blazing fast (since was using a copy
of Linux that was patched to have good aio).
But when he tried to integrate his library
into a large application someone else had written, woe! that application's use of signals conflicted with his library. "Fsck!" said Xman. At that moment a fairy appeared, and said
"Young man, watch your language, or I'm going to have to turn you into a goon! I'm the good fairy Eunice. Can I help you?" Xman explained his problem to Eunice, who smiled and said "All you need is right here, just type 'man 2 sigopen'". Xman did, and saw:
SIGOPEN(2) Linux Programmer's Manual SIGOPEN(2)
NAME
sigopen - open a signal as a file descriptor
SYNOPSIS
#include <signal.h>
int sigopen(int signum);DESCRIPTION
The sigopen system call opens signal number signum as a file descriptor. That signal is no longer delivered normally or available for pickup with sigwait() et al. Instead, it must be picked up by calling read() on the file descriptor returned by sigwait(); the buffer passed to read() must have a size which is a multiple of sizeof(siginfo_t). Multiple signals may be picked up with a single call to read(). When that file descriptor is closed, the signal is available once more for traditional use.
A signal number cannot be opened more than once concurrently; sigopen() thus provides a way to avoid signal usage clashes in large programs.
RETURN VALUE
signal returns the new file descriptor, or -1 on error (in which case, errno is set appropriately).
ERRORS
EWOULDBLOCK signal is already open
NOTES
read() will block when reading from a file descriptor opened by sigopen() until a signal is available unless fcntl(fd, F_SETFL, O_NONBLOCK) is called to set it into nonblocking mode.
HISTORY
sigopen() first appeared in the 2.5.2 Linux kernel.
Linux July, 2001 1
When he finished reading, he knew just how to solve his problem, and he lived happily ever after.
The End.
- Dan
Quoted 8 lines · --On Tuesday, June 26, 2001 05:54:37 -0700 Dan Kegel <[email protected]> wrote:
Once upon a time a hacker named Xman
wrote a library that used aio, and decided
to usesigtimedwait()to pick up completion
notifications. It worked well, and his I/O
was blazing fast (since was using a copy
of Linux that was patched to have good aio).
But when he tried to integrate his library
into a large application someone else had
Quoted 8 lines
written, woe! that application's use of signals conflicted with his library. "Fsck!" said Xman. At that moment a fairy appeared, and said
"Young man, watch your language, or I'm going to have to turn you into a goon! I'm the good fairy Eunice. Can I help you?" Xman explained his problem to Eunice, who smiled and said "All you need is right here, just type 'man 2 sigopen'". Xman did, and saw:
I must thank the god fair Eunice. ;-) From a programming standpoint, this looks like a really nice approach. I must say I prefer this approach to the various "event" strategies I've seen to date, as it fixes the primary problem with signals, while still allowing us to hook in to all the standard POSIX API's that already use signals. It'd be nice if I could pass in a 0 for signum and have the kernel select from unused signals (problem being that "unused" is not necessarily easy to define), althouh I guess an inefficient version of this could be handled in userland.
I presume the fd could be shared between threads and otherwise behave like a normal fd, which would be sooooper nice.
I guess the main thing I'm thinking is this could require some significant changes to the way the kernel behaves. Still, it's worth taking a "try it and see approach". If anyone else thinks this is a good idea I may hack together a sample patch and give it a whirl.
Thanks again good fairy Dan/Eunice. ;-)
--Chris
Shouldn't there be a sigclose() and other operations to make the API orthogonal. sigopen() should be selective about the signals it allows as argument. Try and make sigopen() thread specific, so that if one thread does a sigopen(), it does not imply it will do all the signal handling for all the threads.
Does using sigopen() imply that signal(), sigaction(), etc cannot be used. In the same process one could do a sigopen() in the library, but the process could use sigaction()/signal() without knowing what the library does (which signals it handles, etc).
Let me know, when somebody has a patch or needs help, I would like to help or take a look at it.
Balbir
|NAME | sigopen - open a signal as a file descriptor | |SYNOPSIS | #include <signal.h> | | int sigopen(int signum); | |DESCRIPTION | The sigopen system call opens signal number signum as a file descriptor. | That signal is no longer delivered normally or available for pickup | with sigwait() et al. Instead, it must be picked up by calling | read() on the file descriptor returned by sigwait(); the buffer passed to | read() must have a size which is a multiple of sizeof(siginfo_t). | Multiple signals may be picked up with a single call to read(). | When that file descriptor is closed, the signal is available once more | for traditional use. | A signal number cannot be opened more than once concurrently; sigopen() | thus provides a way to avoid signal usage clashes in large programs. | |RETURN VALUE | signal returns the new file descriptor, or -1 on error (in which case, errno | is set appropriately). | |ERRORS | EWOULDBLOCK signal is already open | |NOTES | read() will block when reading from a file descriptor opened by sigopen() | until a signal is available unless fcntl(fd, F_SETFL, O_NONBLOCK) is called | to set it into nonblocking mode. | |HISTORY | sigopen() first appeared in the 2.5.2 Linux kernel. | |Linux July, 2001 1 |
Quoted 1 line · --On Wednesday, June 27, 2001 11:51:36 +0530 Balbir Singh…
Shouldn't there be a
sigclose()and other operations to make the API
Wouldn't the existing close() be good enough for that?
Quoted 4 lines
orthogonal.
sigopen()should be selective about the signals it allows as argument. Try and makesigopen()thread specific, so that if one thread does asigopen(), it does not imply it will do all the signal handling for all the threads.
Actually, this is exactly what you do want to happen. Linux's existing signals + threads semantics are not exactly ideal for high-performance computing. Of course, fd's are shared by all threads, so all of the threads would be able to read the siginfo structures into memory.
Quoted 4 lines
Does using
sigopen()imply thatsignal(),sigaction(), etc cannot be used. In the same process one could do asigopen()in the library, but the process could use sigaction()/signal() without knowing what the library does (which signals it handles, etc).
If I understood Dan's intentions correctly, you could use signal() and sigaction(), but while the fd is open, signals would be queued up to the fd rather than passed off to a signal handler or sigwaitinfo(). Care to comment Dan?
Quoted 2 lines
Let me know, when somebody has a patch or needs help, I would like to help or take a look at it.
Maybe we can both hack on this.
--Chris
| |> Let me know, when somebody has a patch or needs help, I would like to |> help or take a look at it. | |Maybe we can both hack on this. |
Sure, that should be interesting, did you have something in mind ? We can start right away.
Quoted 5 lines · Dan Kegel
That signal is no longer delivered normally or available for pickup with
sigwait()et al. Instead, it must be picked up by callingread()on the file descriptor returned bysigwait(); the buffer passed toread()must have a size which is a multiple ofsizeof(siginfo_t).
Does this mean that the read() call must write sizeof(siginfo_t) bytes for each signal delivered?
At the moment, the kernel does not have to write the whole siginfo_t structure to userspace -- it can write just those fields which are relevant for a particular signal.
Quoted 3 lines
A signal number cannot be opened more than once concurrently;
sigopen()thus provides a way to avoid signal usage clashes in large programs.
sigopen() won't prevent signal usage clashes if the other user is using sigaction() and sigtimedwait(), or will it?
Btw, this functionality is already available using sigaction(). Just search for a signal whose handler is SIG_DFL. If you then block that signal before changing, checking the result, and unblocking the signal, you can avoid race conditions too. (This is what my programs do).
-- Jamie
Quoted 4 lines · --On Wednesday, June 27, 2001 11:18:28 +0200 Jamie Lokier…
Btw, this functionality is already available using
sigaction(). Just search for a signal whose handler isSIG_DFL. If you then block that signal before changing, checking the result, and unblocking the signal, you can avoid race conditions too. (This is what my programs do).
It's more than whether a signal is blocked or not, unfortunately. Lots of applications will invoke sigwaitinfo() on whatever the current signal mask is, which means you can't rely on sigaction to solve your problems. :-(
--Chris
Dan Kegel <[email protected]> writes:
[...]
Quoted 3 lines
A signal number cannot be opened more than once concurrently;
sigopen()thus provides a way to avoid signal usage clashes in large programs.
Signals are a pretty dopey API anyway - so instead of trying to patch them up, why not think of something better for AIO?
[...]
Signature · 1 line
http://ape.n3.net
Quoted 6 lines · John Fremlin
Quoted 3 lines · Dan Kegel
A signal number cannot be opened more than once concurrently;
sigopen()thus provides a way to avoid signal usage clashes in large programs.Signals are a pretty dopey API anyway - so instead of trying to patch them up, why not think of something better for AIO?
You assume that this issue only comes up when you're doing AIO. If we do something that makes signals work better, we can have a much broader impact that just AIO. If nothing else, the signal usage clashing issue has nothing to do with AIO.
--Chris
Quoted 6 lines · John Fremlin
Quoted 3 lines
A signal number cannot be opened more than once concurrently;
sigopen()thus provides a way to avoid signal usage clashes in large programs.Signals are a pretty dopey API anyway - so instead of trying to patch them up, why not think of something better for AIO?
Keep in mind that SIGRTxxx signals are not just used for AIO.
-- Jamie
Christopher Smith <[email protected]> writes:
[...]
Quoted 7 lines
Quoted 2 lines
Signals are a pretty dopey API anyway - so instead of trying to patch them up, why not think of something better for AIO?
You assume that this issue only comes up when you're doing AIO. If we do something that makes signals work better, we can have a much broader impact that just AIO. If nothing else, the signal usage clashing issue has nothing to do with AIO.
So what. Signals are bad system already. Therefore don't try to force them to do more stuff. Just because they have already been forced to do more doesn't mean it was a good idea at all, or that we should keep on patching bits and pieces onto them, IMHO.
Signature · 1 line
http://ape.n3.net