public inbox for ecos-discuss@sourceware.org
 help / color / mirror / Atom feed
* [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).