Hi,
I'm currently looking for a decent method to wait on either
an I/O event _or_ a signal coming from another process.
Alas, it seems that the Linux kernel does not have any
appropriate system call to support what for example "pselect()"
tries to do: Atomically enable some signals and entering a
select.
Without a proper pselect() implementation (the one in glibc is just
a mock-up that doesn't prevent the race condition) I'm currently
unable to come up with a good idea on how to wait on both types
of events.
A somewhat bizarre solution would be to have the process create
a pipe-pair, select on the reading end, and let the signal-handler
write a byte to the pipe - but this has at least the drawback
you always spoil one "select-cycle" for each signal you get - as
the first return from the select() call happenes without any
fds being flagged as readable, only when you enter select() once
more the pipe will cause the return and tell you what happened...
Arguments against other options I considered:
- Using just signals is at least prevented by SIGIO not being
delivered for pipes, and I'm not eager to find out about
all the other problems that may arise by devices not behaving
as expected
- Unix domain sockets would be awkward to use due to the fact
I'd need to come up with some "filenames" for them to bind to,
and both security considerations and the danger of "leaking"
files that remain on disk forever make me shudder...
Any ideas?
Anyone capable of implementing a system-call for pselect() (or ppoll) ?
Regards,
Lutz Vieweg
--
Dipl. Phys. Lutz Vieweg | email: [email protected]
Innovative Software AG | Phone/Fax: +49-69-505030 -120/-505
Feuerbachstrasse 26-32 | http://www.isg.de/people/lkv/
60325 Frankfurt am Main | ^^^ PGP key available here ^^^
On Fri, 5 Oct 2001 [email protected] wrote:
> A somewhat bizarre solution would be to have the process create
> a pipe-pair, select on the reading end, and let the signal-handler
> write a byte to the pipe - but this has at least the drawback
> you always spoil one "select-cycle" for each signal you get - as
> the first return from the select() call happenes without any
> fds being flagged as readable, only when you enter select() once
> more the pipe will cause the return and tell you what happened...
fork() is cheap. Create a child, have a pipe between child and
parent and do select() on the other end of pipe. I.e. signal handler
writes into pipe and that triggers select() in the second process.
Alexander Viro wrote:
>
> On Fri, 5 Oct 2001 [email protected] wrote:
>
> > A somewhat bizarre solution would be to have the process create
> > a pipe-pair, select on the reading end, and let the signal-handler
> > write a byte to the pipe - but this has at least the drawback
> > you always spoil one "select-cycle" for each signal you get - as
> > the first return from the select() call happenes without any
> > fds being flagged as readable, only when you enter select() once
> > more the pipe will cause the return and tell you what happened...
>
> fork() is cheap. Create a child, have a pipe between child and
> parent and do select() on the other end of pipe. I.e. signal handler
> writes into pipe and that triggers select() in the second process.
What exactly would be the advantage of doubling the number of processes
running just to introduce this indirection? An additional context-switch
surely doesn't speed up things... or am I misinterpreting your proposal
completely?
Regards,
Lutz Vieweg
--
Dipl. Phys. Lutz Vieweg | email: [email protected]
Innovative Software AG | Phone/Fax: +49-69-505030 -120/-505
Feuerbachstrasse 26-32 | http://www.isg.de/people/lkv/
60325 Frankfurt am Main | ^^^ PGP key available here ^^^
[email protected] wrote:
>
> Hi,
>
> I'm currently looking for a decent method to wait on either
> an I/O event _or_ a signal coming from another process.
> - Unix domain sockets would be awkward to use due to the fact
> I'd need to come up with some "filenames" for them to bind to,
> and both security considerations and the danger of "leaking"
> files that remain on disk forever make me shudder...
If you use a named socket in the abstract namespace, then it can't "leak" to
disk....
Chris
--
Chris Friesen | MailStop: 043/33/F10
Nortel Networks | work: (613) 765-0557
3500 Carling Avenue | fax: (613) 765-2986
Nepean, ON K2H 8E9 Canada | email: [email protected]
Christopher Friesen wrote:
> > I'm currently looking for a decent method to wait on either
> > an I/O event _or_ a signal coming from another process.
>
> > - Unix domain sockets would be awkward to use due to the fact
> > I'd need to come up with some "filenames" for them to bind to,
> > and both security considerations and the danger of "leaking"
> > files that remain on disk forever make me shudder...
>
> If you use a named socket in the abstract namespace, then it can't "leak" to
> disk....
Ok, but man 7 unix says:
SCM_CREDENTIALS and the abstract namespace were introduced with
Linux 2.2 and should not be used in portable programs
... and I really do want to write portable programs...
Regards,
Lutz Vieweg
--
Dipl. Phys. Lutz Vieweg | email: [email protected]
Innovative Software AG | Phone/Fax: +49-69-505030 -120/-505
Feuerbachstrasse 26-32 | http://www.isg.de/people/lkv/
60325 Frankfurt am Main | ^^^ PGP key available here ^^^
In article <[email protected]> you wrote:
> Without a proper pselect() implementation (the one in glibc is just
> a mock-up that doesn't prevent the race condition) I'm currently
> unable to come up with a good idea on how to wait on both types
> of events.
Isnt select() returning with EINTR?
> A somewhat bizarre solution would be to have the process create
> a pipe-pair, select on the reading end, and let the signal-handler
> write a byte to the pipe - but this has at least the drawback
> you always spoil one "select-cycle" for each signal you get
Well, you can use the pipe instead of the signal. What kind of signal do you
try to trap? Looks like you want to do critical high load stuff with a
signal.
Greetings
Bernd
On Fri, Oct 05, 2001 at 10:36:53PM +0200, Bernd Eckenfels wrote:
> In article <[email protected]> you wrote:
> > Without a proper pselect() implementation (the one in glibc is just
> > a mock-up that doesn't prevent the race condition) I'm currently
> > unable to come up with a good idea on how to wait on both types
> > of events.
>
> Isnt select() returning with EINTR?
The select system call doesn't return EINTR when the signal is caught
prior to entry into select.
The problem is if you have a select loop and small signal handlers
setting flags for the loop, a signal could come in after the flag is
tested but before select is called. Instead of acting on this signal
right away, the process blocks in select.
The pselect system call offers a solution. The process blocks signals
in the select loop; pselect unblocks those signals and does a
select. The race condition mentioned earlier disappears: the signal
that arrives after the flag test is blocked. The pselect system call
unblocks the signal, so the deferred signal acts just like it arrived
while the process is blocked in select.
> > A somewhat bizarre solution would be to have the process create
> > a pipe-pair, select on the reading end, and let the signal-handler
> > write a byte to the pipe - but this has at least the drawback
> > you always spoil one "select-cycle" for each signal you get
>
> Well, you can use the pipe instead of the signal. What kind of signal do you
> try to trap? Looks like you want to do critical high load stuff with a
> signal.
He just wants to handle signals properly 100% of the time.
> The select system call doesn't return EINTR when the signal is caught
> prior to entry into select.
Your friend there is siglongjmp/sigsetjmp - the same problem was true
with old versions of alarm that did
alarm(num)
pause()
on a heavily loaded box.
Using siglongjmp cures that
On Friday October 5, [email protected] wrote:
> On Fri, Oct 05, 2001 at 10:36:53PM +0200, Bernd Eckenfels wrote:
> > In article <[email protected]> you wrote:
> > > Without a proper pselect() implementation (the one in glibc is just
> > > a mock-up that doesn't prevent the race condition) I'm currently
> > > unable to come up with a good idea on how to wait on both types
> > > of events.
> >
> > Isnt select() returning with EINTR?
>
> The select system call doesn't return EINTR when the signal is caught
> prior to entry into select.
A technique I used in a similar situation once went something like:
tv.tv_sec=bignum;
tv.tv_usec = 0;
enable_signals();
select(nfds, &readfds,&writefds,0,&tv);
and have the signal handlers set tv.tv_sec to 0. (tv is a global
variable).
Then if the signal comes before the select, the select exits
immediately.
NeilBrown
On Sat, Oct 06, 2001 at 09:21:38AM +1000, Neil Brown wrote:
> On Friday October 5, [email protected] wrote:
> > The select system call doesn't return EINTR when the signal is caught
> > prior to entry into select.
>
> A technique I used in a similar situation once went something like:
>
> tv.tv_sec=bignum;
> tv.tv_usec = 0;
> enable_signals();
> select(nfds, &readfds,&writefds,0,&tv);
>
> and have the signal handlers set tv.tv_sec to 0. (tv is a global
> variable).
I've thought about that, but I haven't been able to find any guarantee
that there will be no user space futzing around with &tv, like a
library wrapper that copies tv to another spot in memory and invokes
the syscall with that address.
>> A technique I used in a similar situation once went something like:
>> tv.tv_sec=bignum;
>> tv.tv_usec = 0;
>> enable_signals();
>> select(nfds, &readfds,&writefds,0,&tv);
>> and have the signal handlers set tv.tv_sec to 0. (tv is a global
>>variable).
>I've thought about that, but I haven't been able to find any guarantee that
>there will be no user space futzing around with &tv, like a library wrapper
>that copies tv to another spot in memory and invokes the syscall with that
>address.
This will commonly happen if, for example, the user-side timeval structure
contains seconds and microseconds and the kernel-side structure contains
seconds and nanoseconds. The signal might occur after the library has
performed the structure conversion.
DS
On Sat, Oct 06, 2001 at 12:13:17AM +0100, Alan Cox wrote:
> > The select system call doesn't return EINTR when the signal is caught
> > prior to entry into select.
>
> Your friend there is siglongjmp/sigsetjmp - the same problem was true
> with old versions of alarm that did
>
> alarm(num)
> pause()
>
> on a heavily loaded box.
>
> Using siglongjmp cures that
I was naive about siglongjump bouncing through the stack over a system
call, but it appears to be safe. Excellent.
> A technique I used in a similar situation once went something like:
>
> tv.tv_sec=bignum;
> tv.tv_usec = 0;
> enable_signals();
> select(nfds, &readfds,&writefds,0,&tv);
>
> and have the signal handlers set tv.tv_sec to 0. (tv is a global
> variable).
>
> Then if the signal comes before the select, the select exits
> immediately.
You can do this more cleanly with sigsetjmp - it avoids any risk of suprises
in the library itself - eg the select to poll mapper in some libraries - and
indeed even the variable load into registers for a syscall
> > The select system call doesn't return EINTR when the signal is caught
> > prior to entry into select.
>
> Your friend there is siglongjmp/sigsetjmp - the same problem was true
> with old versions of alarm that did
>
> alarm(num)
> pause()
>
> on a heavily loaded box.
>
> Using siglongjmp cures that
Hmmm... would you say the "siglongjmp" method is better than the "self-pipe"
method for a select on both file descriptors and signals too?
As far as I can see the trade-off is (in the non-race-condition case)
between having to call read() on the pipe (to empty it after receiving the
signal) for the "self-pipe" method and having to call sigsetjump() every time
before one enters select/poll.
My assumption would be that the "self-pipe" method is cheaper... right?
Then somebody mentioned using signals to wake up processes
for frequent events wouldn't be a good idea at all - why?
And what could be a better alternative given that there are N processes,
which all need to be able to wake up any of the other N-1 processes - where N
is big enough to prohibit dedicated channels between each possible process
pair, and given that it has to be a portable way that does not impose
the risk of leaking files to a disk?
Regards,
Lutz Vieweg
--
Dipl. Phys. Lutz Vieweg | email: [email protected]
Innovative Software AG | Phone/Fax: +49-69-505030 -120/-505
Feuerbachstrasse 26-32 | http://www.isg.de/people/lkv/
60325 Frankfurt am Main | ^^^ PGP key available here ^^^
> Hmmm... would you say the "siglongjmp" method is better than the "self-pipe"
> method for a select on both file descriptors and signals too?
siglongjmp doesnt have to make any syscalls so intuitively I'd say it
ought to be more efficient
> Then somebody mentioned using signals to wake up processes
> for frequent events wouldn't be a good idea at all - why?
Beats me
Alan
Alan Cox wrote:
>
> > Hmmm... would you say the "siglongjmp" method is better than the "self-pipe"
> > method for a select on both file descriptors and signals too?
>
> siglongjmp doesnt have to make any syscalls so intuitively I'd say it
> ought to be more efficient
Are you sure? Doesn't sigsetjmp() call sigprocmask in order to obtain
the current signal mask?
In the glibc I read:
int
__sigjmp_save (sigjmp_buf env, int savemask)
{
env[0].__mask_was_saved = (savemask &&
__sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
&env[0].__saved_mask) == 0);
return 0;
}
*sigh* things could be so easy if there was a working pselect()...
Regards,
Lutz vieweg
--
Dipl. Phys. Lutz Vieweg | email: [email protected]
Innovative Software AG | Phone/Fax: +49-69-505030 -120/-505
Feuerbachstrasse 26-32 | http://www.isg.de/people/lkv/
60325 Frankfurt am Main | ^^^ PGP key available here ^^^
> > siglongjmp doesnt have to make any syscalls so intuitively I'd say it
> > ought to be more efficient
>
> Are you sure? Doesn't sigsetjmp() call sigprocmask in order to obtain
> the current signal mask?
and intuition is a dangerouns thing. I didnt realise glibc didnt cache
the procmask
>
> > > The select system call doesn't return EINTR when the signal is caught
> > > prior to entry into select.
> >
> > Your friend there is siglongjmp/sigsetjmp - the same problem was true
> > with old versions of alarm that did
> >
> > alarm(num)
> > pause()
> >
> > on a heavily loaded box.
> >
> > Using siglongjmp cures that
>
> Hmmm... would you say the "siglongjmp" method is better than the "self-pipe"
> method for a select on both file descriptors and signals too?
>
> As far as I can see the trade-off is (in the non-race-condition case)
> between having to call read() on the pipe (to empty it after receiving the
> signal) for the "self-pipe" method and having to call sigsetjump() every time
> before one enters select/poll.
>
> My assumption would be that the "self-pipe" method is cheaper... right?
Well, but you don't have to call sigsetjmp before every select; just when you
enter the loop. Than just enable volatile flag, that the handler should now
use the siglongjmp... well, you have to care about 2 signals quickly following
one another and similar nasty cases anyway, so the pipe aproach is less
error-prone. When signal arives, select either returns EINTR, or says the pipe
is ready for writing, so you can save yourself the additional select call by
checking for both conditions.
--------------------------------------------------------------------------------
- Jan Hudec `Bulb' <[email protected]>
Jan Hudec wrote:
> Well, but you don't have to call sigsetjmp before every select; just when you
> enter the loop. Than just enable volatile flag, that the handler should now
> use the siglongjmp... well, you have to care about 2 signals quickly following
> one another and similar nasty cases anyway, so the pipe aproach is less
> error-prone.
You don't have to worry about 2 signals following each other if they are
the same signal: you can clear the volatile flag in the signal handler.
If they are different signals, e.g. SIGCHLD arrives during SIGINT
handler inside select(), then it's more complicated.
The pipe is very simple to get right and at least as fast as a signal
handler. Just make sure you can't ever make the mistake of writing to a
full pipe. Netscape 4.x does this and that's why it freezes from time
to time. It's an easy problem to avoid.
-- Jamie