Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per-thread vs Global sigprocmask #9978

Closed
patacongo opened this issue Jul 31, 2023 · 2 comments
Closed

Per-thread vs Global sigprocmask #9978

patacongo opened this issue Jul 31, 2023 · 2 comments

Comments

@patacongo
Copy link
Contributor

patacongo commented Jul 31, 2023

For sigprocmask(), the sigprocmaks mask in the TCB and is modified in nxsig_procmask(). This is like:

121           case SIG_BLOCK:
122             sigorset(&rtcb->sigprocmask, &rtcb->sigprocmask, set);
123             break;
124
129           case SIG_UNBLOCK:
130             nxsig_nandset(&rtcb->sigprocmask, &rtcb->sigprocmask, set);
131             break;
132
135           case SIG_SETMASK:
136             rtcb->sigprocmask = *set;
137  

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.

@patacongo
Copy link
Contributor Author

patacongo commented Jul 31, 2023

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.

@patacongo
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant