Austin Group Defect Tracker

Aardvark Mark IV

Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001186 [1003.1(2016/18)/Issue7+TC2] System Interfaces Editorial Clarification Requested 2018-02-02 18:47 2024-06-11 09:08
Reporter davmac View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Closed  
Name Davin McCall
User Reference
Section pselect
Page Number 1554-1555
Line Number 50880
Interp Status ---
Final Accepted Text Note: 0004273
Summary 0001186: pselect specification allows for race condition that pselect was created to avoid
Description 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.
Desired Action 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 tc3-2008
Attached Files

- Relationships
related to 0000680Closed 1003.1(2013)/Issue7+TC1 pselect EINTR error case clarification 
related to 0001263Closed 1003.1(2016/18)/Issue7+TC2 Add ppoll( ) 

-  Notes
davmac (reporter)
2018-02-02 19:33

(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).
jilles (reporter)
2018-02-04 20:00

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.
geoffclare (manager)
2019-03-04 16:17

Change the paragraph at 50880, appending:
If a signal is unmasked as a result of the signal mask being altered by pselect(), and a signal-catching function is called for that signal during the execution of the pselect() function, and SA_RESTART is clear for the interrupting signal, then
  • If none of the selected file descriptors are ready, pselect() shall immediately fail with the [EINTR] error after the signal-catching function returns.

  • If one or more of the selected file descriptors are ready, it is unspecified whether pselect() behaves the same as if none of the descriptors were ready (failing with [EINTR] as above) or behaves the same as if it was not interrupted (returning the total number of ready descriptors).

Change the paragraph at 50957 from:
[EINTR] The function was interrupted while blocked waiting for any of the selected descriptors to become ready and before the timeout interval expired.
[EINTR] The function was interrupted by a signal.

- Issue History
Date Modified Username Field Change
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
2019-02-28 16:52 eblake Relationship added related to 0000680
2019-03-04 16:17 geoffclare Note Added: 0004273
2019-03-04 16:18 geoffclare Interp Status => ---
2019-03-04 16:18 geoffclare Final Accepted Text => Note: 0004273
2019-03-04 16:18 geoffclare Status New => Resolved
2019-03-04 16:18 geoffclare Resolution Open => Accepted As Marked
2019-03-04 16:18 geoffclare Tag Attached: tc3-2008
2019-06-18 14:20 eblake Relationship added related to 0001263
2019-11-08 11:39 geoffclare Status Resolved => Applied
2024-06-11 09:08 agadmin Status Applied => Closed

Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker