* [ECOS] Wake select() with a signal
@ 2002-11-01 9:04 Roland Caßebohm
2002-11-04 9:53 ` Roland Caßebohm
0 siblings, 1 reply; 10+ messages in thread
From: Roland Caßebohm @ 2002-11-01 9:04 UTC (permalink / raw)
To: ecos-discuss
Hi everyone,
I want to wake a waiting select by sending a signal to the thread.
This does not always work. I think the reason is that the thread in which
select() is call is not really sleeping all the time, even though it doesn't
return. The pthread_kill() function respectively Cyg_Thread::release() only
wakes a thread if the thread is sleeping. That makes sense, but what can I do
if I want a waiting select() to return triggered from another thread?
Thanks,
Roland
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-01 9:04 [ECOS] Wake select() with a signal Roland Caßebohm
@ 2002-11-04 9:53 ` Roland Caßebohm
2002-11-04 19:46 ` Jonathan Larmour
0 siblings, 1 reply; 10+ messages in thread
From: Roland Caßebohm @ 2002-11-04 9:53 UTC (permalink / raw)
To: ecos-discuss
[-- Attachment #1: Type: text/plain, Size: 935 bytes --]
On Friday, 1. November 2002 18:04, Roland CaÃebohm wrote:
> Hi everyone,
>
> I want to wake a waiting select by sending a signal to the thread.
>
> This does not always work. I think the reason is that the thread in which
> select() is call is not really sleeping all the time, even though it
> doesn't return. The pthread_kill() function respectively
> Cyg_Thread::release() only wakes a thread if the thread is sleeping. That
> makes sense, but what can I do if I want a waiting select() to return
> triggered from another thread?
>
I just changed the select() function that it looks for the asr_pending flag before it goes to sleep. I don't really think, that this is the right solution, but in my case it works.
Now the select() always returns with errno=EINTR if the thread receives a signal.
Does anybody know if the select() systemcall or every other systemcall should always return if the thread receives a signal?
Roland
[-- Attachment #2: select.cxx.diff --]
[-- Type: text/x-diff, Size: 884 bytes --]
Index: io/fileio/current/src/select.cxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/fileio/current/src/select.cxx,v
retrieving revision 1.8
diff -u -5 -p -r1.8 select.cxx
--- io/fileio/current/src/select.cxx 9 Aug 2002 17:10:21 -0000 1.8
+++ io/fileio/current/src/select.cxx 4 Nov 2002 17:35:02 -0000
@@ -209,10 +213,22 @@ select(int nfd, fd_set *in, fd_set *out,
select_mutex.unlock();
FILEIO_RETURN_VALUE(num);
}
Cyg_Scheduler::lock();
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+ Cyg_Thread *self_thread = Cyg_Thread::self();
+ if (self_thread->get_asr_pending())
+ {
+ error = EINTR;
+ Cyg_Scheduler::unlock();
+ break;
+ }
+#endif
if( wake_count == selwake_count )
{
// Nothing found, see if we want to wait
if (tv)
[-- Attachment #3: Type: text/plain, Size: 146 bytes --]
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-04 9:53 ` Roland Caßebohm
@ 2002-11-04 19:46 ` Jonathan Larmour
2002-11-05 1:57 ` Roland Caßebohm
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Larmour @ 2002-11-04 19:46 UTC (permalink / raw)
To: Roland Caßebohm; +Cc: ecos-discuss
Roland CaÃebohm wrote:
> On Friday, 1. November 2002 18:04, Roland CaÃebohm wrote:
>
>> Hi everyone,
>>
>> I want to wake a waiting select by sending a signal to the thread.
>>
>> This does not always work. I think the reason is that the thread in
>> which select() is call is not really sleeping all the time, even
>> though it doesn't return. The pthread_kill() function respectively
>> Cyg_Thread::release() only wakes a thread if the thread is sleeping.
>> That makes sense, but what can I do if I want a waiting select() to
>> return triggered from another thread?
>>
>
> I just changed the select() function that it looks for the asr_pending
> flag before it goes to sleep. I don't really think, that this is the
> right solution, but in my case it works. Now the select() always
> returns with errno=EINTR if the thread receives a signal.
Hmmm... Before the scheduler lock, the ASR should run. After the scheduler
lock, nothing should be able to trigger an ASR to be scheduled; in
particular nothing should be able to call pthread_kill. You're not calling
pthread_kill from an ISR by any chance are you?
Oh, hold on, is it just that the pthread_kill is happening before the lock
for the first time? If so, then I'm afraid that's tough - you could just
as easily have pthread_kill'd it when the CPU was just making the call
into the select function. From a programmatic point of view, that can just
as easily happen. But your signal handler should definitely run
regardless, or are you saying it doesn't do that either?
> Does anybody know if the select() systemcall or every other systemcall
> should always return if the thread receives a signal?
It should return if select() is actually waiting at the time.
Jifl
--
eCosCentric http://www.eCosCentric.com/ <info@eCosCentric.com>
--[ "You can complain because roses have thorns, or you ]--
--[ can rejoice because thorns have roses." -Lincoln ]-- Opinions==mine
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-04 19:46 ` Jonathan Larmour
@ 2002-11-05 1:57 ` Roland Caßebohm
2002-11-05 8:57 ` Jonathan Larmour
0 siblings, 1 reply; 10+ messages in thread
From: Roland Caßebohm @ 2002-11-05 1:57 UTC (permalink / raw)
To: Jonathan Larmour; +Cc: ecos-discuss
On Dienstag, 5. November 2002 04:46, Jonathan Larmour wrote:
> Roland CaÃebohm wrote:
> > On Friday, 1. November 2002 18:04, Roland CaÃebohm wrote:
> >> Hi everyone,
> >>
> >> I want to wake a waiting select by sending a signal to the thread.
> >>
> >> This does not always work. I think the reason is that the thread in
> >> which select() is call is not really sleeping all the time, even
> >> though it doesn't return. The pthread_kill() function respectively
> >> Cyg_Thread::release() only wakes a thread if the thread is sleeping.
> >> That makes sense, but what can I do if I want a waiting select() to
> >> return triggered from another thread?
> >
> > I just changed the select() function that it looks for the asr_pending
> > flag before it goes to sleep. I don't really think, that this is the
> > right solution, but in my case it works. Now the select() always
> > returns with errno=EINTR if the thread receives a signal.
>
> Hmmm... Before the scheduler lock, the ASR should run. After the scheduler
> lock, nothing should be able to trigger an ASR to be scheduled; in
> particular nothing should be able to call pthread_kill. You're not calling
> pthread_kill from an ISR by any chance are you?
I call pthread_kill() from another thread.
>
> Oh, hold on, is it just that the pthread_kill is happening before the lock
> for the first time? If so, then I'm afraid that's tough - you could just
> as easily have pthread_kill'd it when the CPU was just making the call
> into the select function. From a programmatic point of view, that can just
> as easily happen.
It could happen before the scheduler is locked for the first time, but
allthough if an driver calls cyg_selwakeup() every select() function stops
waiting and looks if one of the filedescriptors have a state which the user
expected. If not, select() goes to sleep again.
In this time the scheduler is not locked, so pthread_kill() can be called.
> But your signal handler should definitely run
> regardless, or are you saying it doesn't do that either?
The signal handler doesn't run too. I think this is because by calling
selwait.wait() asr_inhibit is set.
// Avoid calling ASRs during the following unlock.
self->set_asr_inhibit();
>
> > Does anybody know if the select() systemcall or every other systemcall
> > should always return if the thread receives a signal?
>
> It should return if select() is actually waiting at the time.
Shouldn't it allthough return, if it is for any reason not waiting? I think
the application just expects, that select() returns if a signal is received.
Roland
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-05 1:57 ` Roland Caßebohm
@ 2002-11-05 8:57 ` Jonathan Larmour
2002-11-05 9:29 ` Roland Caßebohm
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Larmour @ 2002-11-05 8:57 UTC (permalink / raw)
To: Roland Caßebohm; +Cc: ecos-discuss
Roland CaÃebohm wrote:
> On Dienstag, 5. November 2002 04:46, Jonathan Larmour wrote:
>
>>Roland CaÃebohm wrote:
>> > On Friday, 1. November 2002 18:04, Roland CaÃebohm wrote:
>> >> Hi everyone,
>> >>
>> >> I want to wake a waiting select by sending a signal to the thread.
>> >>
>> >> This does not always work. I think the reason is that the thread in
>> >> which select() is call is not really sleeping all the time, even
>> >> though it doesn't return. The pthread_kill() function respectively
>> >> Cyg_Thread::release() only wakes a thread if the thread is sleeping.
>> >> That makes sense, but what can I do if I want a waiting select() to
>> >> return triggered from another thread?
>> >
>> > I just changed the select() function that it looks for the asr_pending
>> > flag before it goes to sleep. I don't really think, that this is the
>> > right solution, but in my case it works. Now the select() always
>> > returns with errno=EINTR if the thread receives a signal.
>>
>>Hmmm... Before the scheduler lock, the ASR should run. After the scheduler
>>lock, nothing should be able to trigger an ASR to be scheduled; in
>>particular nothing should be able to call pthread_kill. You're not calling
>>pthread_kill from an ISR by any chance are you?
>
>
> I call pthread_kill() from another thread.
Oh well, it was a thought :-).
>
>>Oh, hold on, is it just that the pthread_kill is happening before the lock
>>for the first time? If so, then I'm afraid that's tough - you could just
>>as easily have pthread_kill'd it when the CPU was just making the call
>>into the select function. From a programmatic point of view, that can just
>>as easily happen.
>
>
> It could happen before the scheduler is locked for the first time, but
> allthough if an driver calls cyg_selwakeup() every select() function stops
> waiting and looks if one of the filedescriptors have a state which the user
> expected. If not, select() goes to sleep again.
> In this time the scheduler is not locked, so pthread_kill() can be called.
If the wait is broken by cyg_selwakeup, wait will return 0 and therefore
EINTR will be returned. Also when the wait returns, the kernel has already
ensured the scheduler is still locked, hence the need to unlock it before
returning.
So I think you're worried about the wait returning 1 and going round the
while (!error) loop again. That shouldn't really happen though in this
situation.
>
>>But your signal handler should definitely run
>>regardless, or are you saying it doesn't do that either?
>
>
> The signal handler doesn't run too. I think this is because by calling
> selwait.wait() asr_inhibit is set.
>
> // Avoid calling ASRs during the following unlock.
> self->set_asr_inhibit();
Ah, now that seems more interesting. But still, the signal should cause
the thread to be released, the ASR inhibit then gets cleared, and the
signal handler should be called when wait() unlocks the scheduler.
Now I'm talking about what *should* happen, not necessarily what does, if
you're symptoms suggest otherwise :-).
>> > Does anybody know if the select() systemcall or every other systemcall
>> > should always return if the thread receives a signal?
>>
>>It should return if select() is actually waiting at the time.
>
>
> Shouldn't it allthough return, if it is for any reason not waiting? I think
> the application just expects, that select() returns if a signal is received.
That needn't be guaranteed, and it's flawed for the app to expect it to be
guaranteed. The reason is that you could just as easily get the signal
*just* before entering select(), i.e.:
FD_SET( fd, &fds );
<--- signal could happen exactly here
err = select( numfds, &fds, NULL, NULL, NULL );
So it's a problem that doesn't need to be solved because an app that tried
to rely on it would be broken anyway.
However if select has *already* started waiting, *then* it should wake up
with EINTR. And I believe that _is_ what you are talking about here anyway.
Jifl
--
eCosCentric http://www.eCosCentric.com/ <info@eCosCentric.com>
--[ "You can complain because roses have thorns, or you ]--
--[ can rejoice because thorns have roses." -Lincoln ]-- Opinions==mine
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-05 8:57 ` Jonathan Larmour
@ 2002-11-05 9:29 ` Roland Caßebohm
2002-11-06 10:37 ` Nick Garnett
0 siblings, 1 reply; 10+ messages in thread
From: Roland Caßebohm @ 2002-11-05 9:29 UTC (permalink / raw)
To: Jonathan Larmour; +Cc: ecos-discuss
On Dienstag, 5. November 2002 17:57, Jonathan Larmour wrote:
> Roland CaÃebohm wrote:
> > On Dienstag, 5. November 2002 04:46, Jonathan Larmour wrote:
> >>Roland CaÃebohm wrote:
> >> > On Friday, 1. November 2002 18:04, Roland CaÃebohm wrote:
> >> >> Hi everyone,
> >> >>
> >> >> I want to wake a waiting select by sending a signal to the thread.
> >> >>
> >> >> This does not always work. I think the reason is that the thread in
> >> >> which select() is call is not really sleeping all the time, even
> >> >> though it doesn't return. The pthread_kill() function respectively
> >> >> Cyg_Thread::release() only wakes a thread if the thread is sleeping.
> >> >> That makes sense, but what can I do if I want a waiting select() to
> >> >> return triggered from another thread?
> >> >
> >> > I just changed the select() function that it looks for the asr_pending
> >> > flag before it goes to sleep. I don't really think, that this is the
> >> > right solution, but in my case it works. Now the select() always
> >> > returns with errno=EINTR if the thread receives a signal.
> >>
> >>Hmmm... Before the scheduler lock, the ASR should run. After the
> >> scheduler lock, nothing should be able to trigger an ASR to be
> >> scheduled; in particular nothing should be able to call pthread_kill.
> >> You're not calling pthread_kill from an ISR by any chance are you?
> >
> > I call pthread_kill() from another thread.
>
> Oh well, it was a thought :-).
>
> >>Oh, hold on, is it just that the pthread_kill is happening before the
> >> lock for the first time? If so, then I'm afraid that's tough - you could
> >> just as easily have pthread_kill'd it when the CPU was just making the
> >> call into the select function. From a programmatic point of view, that
> >> can just as easily happen.
> >
> > It could happen before the scheduler is locked for the first time, but
> > allthough if an driver calls cyg_selwakeup() every select() function
> > stops waiting and looks if one of the filedescriptors have a state which
> > the user expected. If not, select() goes to sleep again.
> > In this time the scheduler is not locked, so pthread_kill() can be
> > called.
>
> If the wait is broken by cyg_selwakeup, wait will return 0 and therefore
> EINTR will be returned. Also when the wait returns, the kernel has already
> ensured the scheduler is still locked, hence the need to unlock it before
> returning.
>
> So I think you're worried about the wait returning 1 and going round the
> while (!error) loop again. That shouldn't really happen though in this
> situation.
>
> >>But your signal handler should definitely run
> >>regardless, or are you saying it doesn't do that either?
> >
> > The signal handler doesn't run too. I think this is because by calling
> > selwait.wait() asr_inhibit is set.
> >
> > // Avoid calling ASRs during the following unlock.
> > self->set_asr_inhibit();
>
> Ah, now that seems more interesting. But still, the signal should cause
> the thread to be released, the ASR inhibit then gets cleared, and the
> signal handler should be called when wait() unlocks the scheduler.
The ASR inhibit gets cleared after unlocking the scheduler:
// Avoid calling ASRs during the following unlock.
self->set_asr_inhibit();
// Unlock the scheduler and switch threads
Cyg_Scheduler::unlock_reschedule();
// Allow ASRs again
self->clear_asr_inhibit();
So the ASR inhibit will not be cleared if nobody wakes the thread again.
>
> Now I'm talking about what *should* happen, not necessarily what does, if
> you're symptoms suggest otherwise :-).
>
> >> > Does anybody know if the select() systemcall or every other systemcall
> >> > should always return if the thread receives a signal?
> >>
> >>It should return if select() is actually waiting at the time.
> >
> > Shouldn't it allthough return, if it is for any reason not waiting? I
> > think the application just expects, that select() returns if a signal is
> > received.
>
> That needn't be guaranteed, and it's flawed for the app to expect it to be
> guaranteed. The reason is that you could just as easily get the signal
> *just* before entering select(), i.e.:
>
> FD_SET( fd, &fds );
> <--- signal could happen exactly here
> err = select( numfds, &fds, NULL, NULL, NULL );
>
>
> So it's a problem that doesn't need to be solved because an app that tried
> to rely on it would be broken anyway.
Yes, I think that could be a problem for my application too. This is
definitely not a problem of eCos, but do you know how can I solve this?
>
> However if select has *already* started waiting, *then* it should wake up
> with EINTR. And I believe that _is_ what you are talking about here anyway.
Yes.
Roland
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-05 9:29 ` Roland Caßebohm
@ 2002-11-06 10:37 ` Nick Garnett
2002-11-07 9:46 ` Roland Caßebohm
0 siblings, 1 reply; 10+ messages in thread
From: Nick Garnett @ 2002-11-06 10:37 UTC (permalink / raw)
To: Roland Caßebohm; +Cc: Jonathan Larmour, ecos-discuss
Roland Caßebohm <roland.cassebohm@visionsystems.de> writes:
> On Dienstag, 5. November 2002 17:57, Jonathan Larmour wrote:
> > Ah, now that seems more interesting. But still, the signal should cause
> > the thread to be released, the ASR inhibit then gets cleared, and the
> > signal handler should be called when wait() unlocks the scheduler.
>
> The ASR inhibit gets cleared after unlocking the scheduler:
>
> // Avoid calling ASRs during the following unlock.
> self->set_asr_inhibit();
>
> // Unlock the scheduler and switch threads
> Cyg_Scheduler::unlock_reschedule();
>
> // Allow ASRs again
> self->clear_asr_inhibit();
But wait_inner() also subsequently calls mx->lock() to relock the
mutex, so any pending ASRs will be called during the unlock in there.
However, in select() the FILEIO_ENTRY() and FILEIO_RETURN_VALUE()
macros contain calls to cyg_posix_function_start() and
cyg_posix_function_finish() which inhibit and uninhibit ASRs around
the whole function, so any manipulation that wait_inner() does is
superflous. The finish function deliberately blips the scheduler lock
so that any pending ASRs will be deferred until select() exits.
>
> So the ASR inhibit will not be cleared if nobody wakes the thread again.
>
This is true, but is also true in the signal-just-before-select case
too.
> > So it's a problem that doesn't need to be solved because an app that tried
> > to rely on it would be broken anyway.
>
> Yes, I think that could be a problem for my application too. This is
> definitely not a problem of eCos, but do you know how can I solve this?
This is a general failing of the design of the select() and signal
mechanisms in Unix. They were invented when all processes were single
threaded. With the introduction of threads, there is the potential for
a race condition, between signal delivery and the decision to call
select().
In Unix I suppose one way of fixing this would have been to add a pipe
to the set of read FDs and have the other thread write to that to wake
the select() -- you probably don't need to use a signal at all. We do
not have pipes in eCos, but a loop-back TCP socket would probably do
the same thing.
The POSIX-200X standard has added a pselect() call, which takes an
additional signal mask argument, specifically to allow this race
condition to be eliminated.
--
Nick Garnett - eCos Kernel Architect
http://www.eCosCentric.com/
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-06 10:37 ` Nick Garnett
@ 2002-11-07 9:46 ` Roland Caßebohm
2002-11-07 15:14 ` Nick Garnett
0 siblings, 1 reply; 10+ messages in thread
From: Roland Caßebohm @ 2002-11-07 9:46 UTC (permalink / raw)
To: Nick Garnett; +Cc: Jonathan Larmour, ecos-discuss
On Mittwoch, 6. November 2002 18:13, Nick Garnett wrote:
> In Unix I suppose one way of fixing this would have been to add a pipe
> to the set of read FDs and have the other thread write to that to wake
> the select() -- you probably don't need to use a signal at all. We do
> not have pipes in eCos, but a loop-back TCP socket would probably do
> the same thing.
>
> The POSIX-200X standard has added a pselect() call, which takes an
> additional signal mask argument, specifically to allow this race
> condition to be eliminated.
You are right, this will be a general problem for me. Till now I never had the
race condition if the signal comes just before calling select(), but I think
this is only, because my application waits most of the time in the select().
To be sure that my application work always, I have to use one of the solutions
you have written.
I'm thinking of implementing a pselect() call. Where should this function be
located, in packages/compat/posix or in packages/io/fileio?
Roland
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-07 9:46 ` Roland Caßebohm
@ 2002-11-07 15:14 ` Nick Garnett
2002-11-08 2:58 ` Roland Caßebohm
0 siblings, 1 reply; 10+ messages in thread
From: Nick Garnett @ 2002-11-07 15:14 UTC (permalink / raw)
To: Roland Caßebohm; +Cc: Jonathan Larmour, ecos-discuss
Roland Caßebohm <roland.cassebohm@visionsystems.de> writes:
> On Mittwoch, 6. November 2002 18:13, Nick Garnett wrote:
> > In Unix I suppose one way of fixing this would have been to add a pipe
> > to the set of read FDs and have the other thread write to that to wake
> > the select() -- you probably don't need to use a signal at all. We do
> > not have pipes in eCos, but a loop-back TCP socket would probably do
> > the same thing.
> >
> > The POSIX-200X standard has added a pselect() call, which takes an
> > additional signal mask argument, specifically to allow this race
> > condition to be eliminated.
>
> You are right, this will be a general problem for me. Till now I never had the
> race condition if the signal comes just before calling select(), but I think
> this is only, because my application waits most of the time in the select().
> To be sure that my application work always, I have to use one of the solutions
> you have written.
>
> I'm thinking of implementing a pselect() call. Where should this function be
> located, in packages/compat/posix or in packages/io/fileio?
>
It should go in the FILEIO package. The best approach would be to
convert the current select() into pselect() and then add a new
select() that just calls pselect() with a NULL sigmask argument. And
pselect() takes a struct timespec rather than a struct timeval for the
timeout, so that would have to be converted too. Here are the
declarations for comparison:
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *errorfds, const struct timespec *timeout,
const sigset_t *sigmask);
int select(int nfds, fd_set *restrict readfds,
fd_set *restrict writefds, fd_set *restrict errorfds,
struct timeval *restrict timeout);
As for where to set the new mask, that is a bit more complex. Simply
calling pthread_sigmask() is not the right thing to do. And the code
in select() would need some restructuring.
Hmm, this is not looking as simple as it did when I started this
message. I'll need to think about this a while. In the meantime you
may want to investigate the socket option.
--
Nick Garnett - eCos Kernel Architect
http://www.eCosCentric.com/
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [ECOS] Wake select() with a signal
2002-11-07 15:14 ` Nick Garnett
@ 2002-11-08 2:58 ` Roland Caßebohm
0 siblings, 0 replies; 10+ messages in thread
From: Roland Caßebohm @ 2002-11-08 2:58 UTC (permalink / raw)
To: Nick Garnett; +Cc: Jonathan Larmour, ecos-discuss
On Freitag, 8. November 2002 00:00, Nick Garnett wrote:
> Roland CaÃebohm <roland.cassebohm@visionsystems.de> writes:
> > On Mittwoch, 6. November 2002 18:13, Nick Garnett wrote:
> > > In Unix I suppose one way of fixing this would have been to add a pipe
> > > to the set of read FDs and have the other thread write to that to wake
> > > the select() -- you probably don't need to use a signal at all. We do
> > > not have pipes in eCos, but a loop-back TCP socket would probably do
> > > the same thing.
> > >
> > > The POSIX-200X standard has added a pselect() call, which takes an
> > > additional signal mask argument, specifically to allow this race
> > > condition to be eliminated.
> >
> > You are right, this will be a general problem for me. Till now I never
> > had the race condition if the signal comes just before calling select(),
> > but I think this is only, because my application waits most of the time
> > in the select(). To be sure that my application work always, I have to
> > use one of the solutions you have written.
> >
> > I'm thinking of implementing a pselect() call. Where should this function
> > be located, in packages/compat/posix or in packages/io/fileio?
>
> It should go in the FILEIO package. The best approach would be to
> convert the current select() into pselect() and then add a new
> select() that just calls pselect() with a NULL sigmask argument. And
> pselect() takes a struct timespec rather than a struct timeval for the
> timeout, so that would have to be converted too. Here are the
> declarations for comparison:
>
> int pselect(int nfds, fd_set *readfds, fd_set *writefds,
> fd_set *errorfds, const struct timespec *timeout,
> const sigset_t *sigmask);
>
> int select(int nfds, fd_set *restrict readfds,
> fd_set *restrict writefds, fd_set *restrict errorfds,
> struct timeval *restrict timeout);
>
> As for where to set the new mask, that is a bit more complex. Simply
> calling pthread_sigmask() is not the right thing to do. And the code
> in select() would need some restructuring.
>
> Hmm, this is not looking as simple as it did when I started this
> message. I'll need to think about this a while. In the meantime you
> may want to investigate the socket option.
I have just tried it, but I have written a extra _pselect() function which
take a timeval structure, so for the normal and more used select() the
timeout don't have to be converted.
//==========================================================================
// Select API function
//roland
# define TIMESPEC_TO_TIMEVAL(tv, ts) { \
(tv)->tv_sec = (ts)->tv_sec; \
(tv)->tv_usec = (ts)->tv_nsec / 1000; \
}
//roland
extern sigset_t sig_pending;
extern Cyg_Mutex signal_mutex;
__externC int
_pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
struct timeval *tv, const sigset_t *sigmask)
{
FILEIO_ENTRY();
int error = ENOERR;
int fd, mode, num;
cyg_file *fp;
fd_set in_res, out_res, ex_res; // Result sets
fd_set *selection[3], *result[3];
cyg_tick_count ticks;
int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0};
cyg_uint32 wake_count;
//
sigset_t oldsigmask;
FD_ZERO(&in_res);
FD_ZERO(&out_res);
FD_ZERO(&ex_res);
// Set up sets
selection[0] = in; result[0] = &in_res;
selection[1] = out; result[1] = &out_res;
selection[2] = ex; result[2] = &ex_res;
// Compute end time
if (tv)
ticks = cyg_timeval_to_ticks( tv );
else ticks = 0;
// Lock the mutex
select_mutex.lock();
//roland
pthread_info *self = pthread_self_info();
oldsigmask=self->sigmask;
// Scan sets for possible I/O until something found, timeout or error.
while (!error)
{
wake_count = selwake_count;
num = 0; // Total file descriptors "ready"
for (mode = 0; !error && mode < 3; mode++)
{
if (selection[mode]) {
for (fd = 0; !error && fd < nfd; fd++)
{
if (FD_ISSET(fd, selection[mode]))
{
fp = cyg_fp_get( fd );
if( fp == NULL )
{
error = EBADF;
break;
}
if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0))
{
FD_SET(fd, result[mode]);
num++;
}
cyg_fp_free( fp );
}
}
}
}
if (num)
{
// Found something, update user's sets
if (in) FD_COPY( &in_res, in );
if (out) FD_COPY( &out_res, out );
if (ex) FD_COPY( &ex_res, ex );
select_mutex.unlock();
FILEIO_RETURN_VALUE(num);
}
Cyg_Scheduler::lock();
//roland
if (~*sigmask & (self->sigpending|sig_pending))
{
diag_printf("sigpending!!!!\n");
if (sigmask)
self->sigmask = *sigmask;
error = EINTR;
break;
}
if( wake_count == selwake_count )
{
// Nothing found, see if we want to wait
if (tv)
{
if (ticks == 0)
{
// Special case of "poll"
select_mutex.unlock();
Cyg_Scheduler::unlock();
FILEIO_RETURN_VALUE(0);
}
ticks += Cyg_Clock::real_time_clock->current_value();
//roland
if (sigmask)
self->sigmask = *sigmask;
if( !selwait.wait( ticks ) )
{
// A non-standard wakeup, if the current time is equal to
// or past the timeout, return zero. Otherwise return
// EINTR, since we have been released.
if( Cyg_Clock::real_time_clock->current_value() >= ticks )
{
//FIXME: maybe don't deliver signals here? There can't be one
error = 0;
}
else
error = EINTR;
break;
}
//roland
if (sigmask)
self->sigmask = oldsigmask;
ticks -= Cyg_Clock::real_time_clock->current_value();
}
else
{
// Wait forever (until something happens)
//roland
if (sigmask)
self->sigmask = *sigmask;
if( !selwait.wait() )
{
error = EINTR;
break;
}
//roland
if (sigmask)
self->sigmask = oldsigmask;
}
}
Cyg_Scheduler::unlock();
} // while(!error)
//roland
signal_mutex.lock();
Cyg_Scheduler::unlock();
cyg_deliver_signals();
if (sigmask)
self->sigmask = oldsigmask;
signal_mutex.unlock();
select_mutex.unlock();
FILEIO_RETURN(error);
}
__externC int
select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
{
return _pselect(nfd,in,out,ex,tv,NULL);
}
__externC int
pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
const struct timespec *ts, const sigset_t *sigmask)
{
struct timeval tv;
if (ts != NULL)
TIMESPEC_TO_TIMEVAL (&tv, ts);
return _pselect(nfd,in,out,ex,&tv,sigmask);
}
//==========================================================================
In my first impression it seems to work.
The prototype of pthread_self_info() is in the private headerfile pprivate.h
in compat/posix/current/src, which I can't access from select.cxx, so I have
to move this somewhere else.
Furthermore I have to include some #ifdef if signals are not implemented.
What do you think about my advice?
Roland
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2002-11-08 10:58 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-11-01 9:04 [ECOS] Wake select() with a signal Roland Caßebohm
2002-11-04 9:53 ` Roland Caßebohm
2002-11-04 19:46 ` Jonathan Larmour
2002-11-05 1:57 ` Roland Caßebohm
2002-11-05 8:57 ` Jonathan Larmour
2002-11-05 9:29 ` Roland Caßebohm
2002-11-06 10:37 ` Nick Garnett
2002-11-07 9:46 ` Roland Caßebohm
2002-11-07 15:14 ` Nick Garnett
2002-11-08 2:58 ` Roland Caßebohm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).