This is the mail archive of the ecos-bugs@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug 1002143] New: sigwait does not wake up on blocked signals.


Please do not reply to this email, use the link below.

http://bugs.ecos.sourceware.org/show_bug.cgi?id=1002143

            Bug ID: 1002143
           Summary: sigwait does not wake up on blocked signals.
           Product: eCos
           Version: 3.0
            Target: All
 Architecture/Host_ Other
                OS:
            Status: UNCONFIRMED
          Severity: enhancement
          Priority: low
         Component: POSIX
          Assignee: unassigned@bugs.ecos.sourceware.org
          Reporter: ehoffman@positronaccess.com
        QA Contact: ecos-bugs@ecos.sourceware.org
                CC: ecos-bugs@ecos.sourceware.org

Hello

I came into the same problem as discussed in 2009 in the mailing list

Ref: https://sourceware.org/ml/ecos-discuss/2009-09/msg00159.html

The discussion thread ended up short with no real satisfactory answer, and I do
think the original question is really pointing a bug.

Basically, the issue is that if you have a pthread, and in that POSIX thread
you block some signals (SIGUSR1 for example), and you do a sigwait, waiting for
that signal, then the thread is supposed to wait for that signal to be in the
signal queue, and return when the signal is present in the queue (removing it
from the signal queue).  It is normal behavior to wait on blocked signals,
sigwait POSIX documentation say that the signal should be blocked before
calling sigwait.  This is to prevent signal handler from dispatching the signal
and removing it from the queue:

[...]If no signal in set is pending at the time of the call, the thread shall
be suspended until one or more becomes pending. The signals defined by set
shall have been blocked at the time of the call to sigwait(); otherwise, the
behavior is undefined[...]

So, the normal usage is is as follow:
- Thread X (pthread) block a specific signal, using pthread_sigmask().
- Thread X call sigwait(), waiting for that signal to be present in the signal
set/queue.
- Thread Y call pthread_kill(), sending signal to thread X.
- Thread X get the signal in the queue (or from the signal set).  Since the
signal is blocked, no signal handler is called.  However, since you have called
sigwait(), the sigwait() function returns and remove the signal from the queue.

If thread Y sends the signal to thread X before thread X call sigwait(), the
signal is set in thread X.  Nothing happen since it's blocked in thread X with
the previous call to pthread_sigmask().  However, as soon as thread X call
sigwait(), sigwait() returns immediately (removing the signal from the queue). 
That behavior is properly respected by eCos.

If thread X call sigwait() before it receive a signal, it goes to sleep,
waiting for signal.  When thread Y send signal to thread X (using
pthread_kill), the signal is then put in thread Y signal queue (or signal set).
 Thread Y then wake up and "consume" the signal, returning from sigwait(). 
That is NOT working in eCos, and it's what's discussed in the mailing list I
mentioned above.

I also checked and confirmed that this behavior seem to be related to the code
in signal.cxx:

if( thread != NULL )
{
    sigaddset( &thread->sigpending, signo );
    // just wake the thread up now if it's blocked somewhere
    if ((thread->sigpending & ~thread->sigmask) != 0)
    {
        thread->thread->set_asr_pending();
        thread->thread->release();
    }
}

This code will wake up the thread ONLY if the signal is not blocked in the
thread.  This behavior is erroneous.  If the signal is blocked in the receiving
thread, it MUST be awaken if the receiving thread is waiting for signal
(sigwait/sigtimedwait).  However the behavior is correct if the receiving
thread is sleeping for other reasons.

So, to correct the behavior, a new state variable is required on the receiving
thread to indicate that the thread is actively waiting for signal.  The thread
must be awaken if either the signal is unblocked, or if the thread is waiting
for the specified signal. Something that goes like:

if ((thread->sigpending & (~thread->sigmask | thread->sigwaitset)) != 0)
...

thread->sigwaitset should be set before putting thread to sleep (before calling
signal_sigwait.wait()), and cleared after awaking from sleep.

This is applicable to both cyg_sigqueue() function and in
cyg_posix_pthread_release_thread() function in signal.cxx.


Also, the sigwait family can return EAGAIN in case of timeout (sigtimedwait)
and EINTR in case of interruption by a signal other than the signals the
sigwait/sigtimedwait was waiting for (which wasn't blocked).  eCos now only
have hardcoded EAGAIN.  EAGAIN must only be used for when timeout occur. 
Otherwise, EINTR must be returned.  So when returning from the
signal_sigwait.wait() function, the wake reason must be checked (and not just
hardcode EGAIN).

Regards,
Eric Hoffman

-- 
You are receiving this mail because:
You are the assignee for the bug.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]