|Anonymous | Login||2019-02-16 05:12 UTC|
|Main | My View | View Issues | Change Log | Docs|
|Viewing Issue Simple Details|
|ID||Category||Severity||Type||Date Submitted||Last Update|
|0001186||[1003.1(2016)/Issue7+TC2] System Interfaces||Editorial||Clarification Requested||2018-02-02 18:47||2018-02-04 20:00|
|Final Accepted Text|
|Summary||0001186: pselect specification allows for race condition that pselect was created to avoid|
As I understand it the pselect() function was created to avoid a race condition when watching for file descriptor readiness and simultaneously waiting on a signal. Typically the signal handler merely sets a flag and an application using select() can check the flag if select is interrupted and returns EINTR; The problem is that the signal can occur just before entry to select() and therefore not be noticed by the application until after select() returns. The pselect() function was supposed to solve this problem by allowing the signal(s) be "atomically" unmasked before starting to wait for file descriptor readiness (and masked again afterwards).
The current wording says only:
"If sigmask is not a null pointer, then the pselect( ) function shall replace the signal mask of the caller by the set of signals pointed to by sigmask before examining the descriptors, and shall restore the signal mask of the calling thread before returning."
This by itself would allow pselect to be implemented in terms of sigprocmask (or pthread_sigmask) and the original select function; however, such an implemented would be prone to the original race condition that pselect is supposed to avoid. The following text also appears in the description:
50863 "If none of the selected descriptors are ready for the requested operation, the pselect( ) or select( ) function shall block until at least one of the requested operations becomes ready, until the timeout occurs, or until interrupted by a signal" (...)
However "block until ... interrupted" does not imply that a signal arriving before blocking starts should not cause the function to return without blocking. Nowhere in the text is it stated that there is not a window between the unmasking of signals as per the provided signal mask and the examination of the file descriptors in which an unmasked signal can be delivered, as needs to be the case if pselect() is usable to avoid the race condition that is its raison d'être.
Furthermore the function can return EINTR only in the following conditions:
50963 "[EINTR] The function was interrupted while blocked waiting for any of the selected
descriptors to become ready and before the timeout interval expired."
This requires that the function is already blocked and waiting when the signal arrives if EINTR is to be returned, leaving open the possibility that the signal is received after it is unmasked but before the blocking/waiting occurs.
There is an additional, less drastic, issue: as well as the signal arriving between the unmasking and blocking, one might arrive between blocking (after a file descriptor has become ready) and the re-masking of signals. This is less drastic because an application that is ready for this can inspect the flag variable that the signal handler should set whenever pselect() returns. However, it seems likely that many applications will run under the assumption that if pselect() does not return with EINTR, then none of the temporarily-masked signals were handled during its execution, which seems like it should be true according to the reasoning for the creation of the interface (but again, which is not implied by the text describing the interface).
A final concern is what happens when pselect() is called when both file descriptors in the specified sets are ready and signals are pending. The text regarding EINTR implies that the function will not return EINTR in this case, since the functional cannot be interrupted while blocking if it does not in fact block. While there is no fundamental problem with this requirement, it is adds at least with the Linux implementation of pselect, and probably with others.
Change the paragraph at 50880, appending: "If a signal is unmasked as a result of the signal mask being altered by pselect(), and that signal is delivered during the execution of the pselect() function, and the signal action does not restart interruptible functions, then pselect shall immediately fail with the EINTR error after delivery of the signal."
Change the paragraph at 50963 to: "[EINTR] The function was interrupted by a signal."
|Tags||No tags attached.|
|(Perhaps the first of the two amendments above is unnecessary, since "interrupted" is described elsewhere and that can probably be understood well enough, but the second amendment (regarding the meaning of EINTR error code) is both simpler and more correct than the original text).|
See also issue 680 and the thread on austin-group-l titled "pselect() clarification" from 18-20 April 2013. The intent seems to be that [EINTR] occur only when a signal interrupts blocking and no descriptors are ready, but a signal may be delivered even if [EINTR] does not occur.
There are implementations such as FreeBSD that can both deliver a signal and return ready descriptors in a single call.
The requirement that the signal mask shall be replaced before examining the descriptors must apparently be interpreted differently than a pthread_sigmask() call, so that the signal handler is not immediately invoked, but will be invoked before pselect() returns, even if descriptors are ready or the timeout is 0.
|2018-02-02 18:47||davmac||New Issue|
|2018-02-02 18:47||davmac||Name||=> Davin McCall|
|2018-02-02 18:47||davmac||Section||=> pselect|
|2018-02-02 18:47||davmac||Page Number||=> 1554-1555|
|2018-02-02 18:47||davmac||Line Number||=> 50880|
|2018-02-02 19:33||davmac||Note Added: 0003917|
|2018-02-04 20:00||jilles||Note Added: 0003918|
|Mantis 1.1.6[^] Copyright © 2000 - 2008 Mantis Group|