Closed patacongo closed 1 year ago
Update: Per Opengroup.org, the behavior of sigprocmask() is actually undefined in a multi-threaded process:
References:
https://pubs.opengroup.org/onlinepubs/009695299/functions/pthread_sigmask.html
The pthread_sigmask() function shall examine or change (or both) the calling thread's signal mask, regardless of the number of threads in the process. The function shall be equivalent to sigprocmask(), without the restriction that the call be made in a single-threaded process.
https://pubs.opengroup.org/onlinepubs/7908799/xsh/sigprocmask.html
In a single-threaded process, the sigprocmask() function allows the calling process to examine or change (or both) the signal mask of the calling thread.
The use of the sigprocmask() function is unspecified in a multi-threaded process.
The Linux man page provide echos that statement (https://linux.die.net/man/3/sigprocmask):
The use of the sigprocmask() function is unspecified in a multi-threaded process.
So in a single threaded process (task group), sigprocmask() and pthread_sigmask() are identical. In a multi-threaded process, the behavior of sigprocmask() in undefined.
This is curious because signals are sent externally to tasks only)via APIs like kill() and not to specific threads. pthread_kill() can send a signal to a specific thread, but that only generally available within a process (task group). Signals sent to tasks may be processed by any thread in the task group that does not block the signal.
What should we do in NuttX? Currently, we treat sigprocmask() as the same as pthread_sigmask(). This has implications. Specifically, calling sigprocmask() from a thread in a multi-threaded task does NOT block the the signal in any way: It can still be handled on one of the other threads in the task group.
That behavior might surprise users. Otherwise, I suppose that is really no issue since the correct behavior is unspecified.
I think that the NuttX solution is POSIX compliant, although a little surprising. It would be nice if these spec oddities were better documented. In any event, there is no reason to keep this as an open issue.
For sigprocmask(), the sigprocmaks mask in the TCB and is modified in nxsig_procmask(). This is like:
This seems wrong to me, however. The sigprocmask is a global mask, not a per-thread mask! When the sigprocmask is set, shouldn't signals sent to the entire task group be blocked? Not just for a single thread. This needs some thought.
The primary purpose of the per-thread sigprocmask is controlling which threads can handle which signals. Disabling a signal in the per-thread sigprocmask should only effect that thread; other threads should still be able to handle the signal.
One would think that disabling a signal in the global sigprocmask should disable the receipt of the signal by all threads in the task group. But the behavior of sigprocmask() is actually undefined in a multi-thread process (aka task group).
For pthread_sigmask(), the sigprocmask is also currently set in nxsig_procmask(). This is correct, but means that pthread_sigmask() and sigprocmask() are identical. That can't be right.