The following issue has been SUBMITTED. ====================================================================== http://austingroupbugs.net/view.php?id=1263 ====================================================================== Reported By: eblake Assigned To: ====================================================================== Project: 1003.1(2016)/Issue7+TC2 Issue ID: 1263 Category: System Interfaces Type: Omission Severity: Objection Priority: normal Status: New Name: Eric Blake Organization: Red Hat User Reference: ebb.ppoll Section: poll Page Number: 1433 Line Number: 47551 Interp Status: --- Final Accepted Text: ====================================================================== Date Submitted: 2019-06-18 12:04 UTC Last Modified: 2019-06-18 12:04 UTC ====================================================================== Summary: Add ppoll( ) Description: The [p]select() interfaces do NOT scale well at handling large numbers of file descriptors. To begin with, the select() interface requires a lot of boilerplate and is destructive (you must rebuild the list of fds prior to each call) when compared to poll() (the separation of events and revents means you don't have to rebuild the list). What's more, the larger the fd, the more bits that have to be scanned even if there are the same number of file descriptors being acted on, and the list is inherently capped at FD_SETSIZE even if you can obtain a larger file descriptor. https://beesbuzz.biz/code/5739-The-problem-with-select-vs-poll is a good summary of arguments why poll() is better than select().
However, there is one thing that pselect() can do that poll() cannot - and that is atomic safety of handling blocked signals. Several operating systems provide ppoll() as a counterpart to poll() to match how pselect() improves select(), and it is high time that we standardize this interface. This proposal uses FreeBSD and Linux for guidance: https://www.freebsd.org/cgi/man.cgi?query=ppoll&apropos=0&sektion=2&manpath=FreeBSD+12.0-RELEASE+and+Ports&arch=default&format=html https://linux.die.net/man/2/ppoll Desired Action: On page 313 after line 10605 (XBD <poll.h>), insert:<blockquote>The <poll.h> header shall define the sigset_t type as described in <signal.h>. The <poll.h> header shall define the timespec structure as described in <time.h>.</blockquote> On page 313 line 10621 (XBD <poll.h>), change:<blockquote>The following shall be declared as a function and may also be defined as a macro. A function prototype shall be provided. int poll(struct pollfd [], nfds_t, int);</blockquote>to:<blockquote> The following shall be declared as functions and may also be defined as macros. Function prototypes shall be provided. int poll(struct pollfd [], nfds_t, int); int ppoll(struct pollfd [], nfds_t, const struct timespec *restrict, const sigset_t *restrict); Inclusion of the <poll.h> header may make visible all symbols from the headers <signal.h> and <time.h>.</blockquote> Add "<i>ppoll</i>( )" with correct sorting to the following lists: page 494 line 17130 (XBD 2.4.3 Signal Actions list of async-safe functions) page 501 line 17418 (XBD 2.6.1 Accessing STREAMS) page 518 line 18123 (XBD 2.9.5.2 Cancellation Points) page 626 line 21649 (XSH bind DESCRIPTION) page 702 line 24051 (XSH connect DESCRIPTION) page 3790 line 130053 (XRAT E.1 Subprofiling Option Groups POSIX_DEVICE_IO) At page 1433 line 47552 (XSH poll NAME), change:<blockquote>poll</blockquote>to:<blockquote>poll, ppoll</blockquote> After page 1433 line 47555 (XSH poll SYNOPSIS), insert:<blockquote>int ppoll(struct pollfd <i>fds</i>[], nfds_t <i>nfds</i>, const struct timespec *restrict <i>timeout</i>, const sigset_t *restrict <i>sigmask</i>);</blockquote> At page 1433 lines 47557-47561 (XSH poll DESCRIPTION), change:<blockquote>The <i>poll</i>( ) function provides applications with a mechanism for multiplexing input/output over a set of file descriptors. For each member of the array pointed to by <i>fds</i>, <i>poll</i>( ) shall examine the given file descriptor for the event(s) specified in <i>events</i>. The number of <b>pollfd</b> structures in the <i>fds</i> array is specified by <i>nfds</i>. The <i>poll</i>( ) function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.</blockquote>to:<blockquote>The <i>ppoll</i>( ) function provides applications with a mechanism for multiplexing input/output over a set of file descriptors. For each member of the array pointed to by <i>fds</i>, <i>ppoll</i>( ) shall examine the given file descriptor for the event(s) specified in <i>events</i>. The number of <b>pollfd</b> structures in the <i>fds</i> array is specified by <i>nfds</i>. The <i>ppoll</i>( ) function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred. The <i>poll</i>( ) function shall be equivalent to the <i>ppoll</i>( ) function, except as follows: • For the <i>poll</i>( ) function, the timeout period is given in milliseconds in an argument of type <b>int</b>, whereas for the <i>ppoll</i>( ) function the timeout period is given in seconds and nanoseconds in an argument of type <b>struct timespec</b>. A <i>timeout</i> of -1 for <i>poll</i>( ) is equivalent to passing a null pointer for the <i>timeout</i> for <i>ppoll</i>( ). • The <i>poll</i>( ) function has no <i>sigmask</i> argument; it shall behave as <i>ppoll</i>( ) does when <i>sigmask</i> is a null pointer.</blockquote> On page 1434 (XSH poll APPLICATION USAGE, RETURN VALUE, ERRORS), change the following instances of "<i>poll</i>( )" to "<i>poll</i>( ) or <i>ppoll</i>( )": line 47600 line 47601 line 47602 line 47603 line 47613 line 47614 line 47615 line 47623 line 47625 line 47628 line 47630 line 47633 At page 1434 lines 47606-47609 (XSH poll DESCRIPTION), change:<blockquote>If none of the defined events have occurred on any selected file descriptor, <i>poll</i>( ) shall wait at least <i>timeout</i> milliseconds for an event to occur on any of the selected file descriptors. If the value of <i>timeout</i> is 0, <i>poll</i>( ) shall return immediately. If the value of <i>timeout</i> is −1, <i>poll</i>( ) shall block until a requested event occurs or until the call is interrupted. Implementations may place limitations on the granularity</blockquote>to:<blockquote>The <i>timeout</i> parameter controls how long the <i>poll</i>( ) or <i>ppoll</i>( ) function shall take before timing out. If the <i>timeout</i> parameter is positive for <i>poll</i>( ) or not a null pointer for <i>ppoll</i>( ), it specifies a maximum interval to wait for the poll to complete. If the specified time interval expires without any requested operation becoming ready, the function shall return. If the <i>timeout</i> parameter is -1 for <i>poll</i>( ) or a null pointer for <i>ppoll</i>( ), then the call shall block indefinitely until at least one descriptor meets the specified criteria. To effect a poll, the <i>timeout</i> parameter should be 0 for <i>poll</i>( ), or for <i>ppoll</i>( ) should not be a null pointer, and should point to a zero-valued <b>timespec</b> structure. Implementations may place limitations on the maximum timeout interval supported. All implementations shall support a maximum timeout interval of at least 31 days for <i>ppoll</i>( ). If the <i>timeout</i> argument specifies a timeout interval greater than the implementation-defined maximum value, the maximum value shall be used as the actual timeout value. Implementations may also place limitations on the granularity</blockquote> After page 1434 line 47623 (XSH poll DESCRIPTION), insert:<blockquote>If <i>sigmask</i> is not a null pointer, then the <i>ppoll</i>( ) function shall replace the signal mask of the caller by the set of signals pointed to by <i>sigmask</i> before examining the descriptors, and shall restore the signal mask of the calling thread before returning. If a thread gets canceled during a <i>ppoll( ) call, the signal mask in effect when executing the registered cleanup functions is either the original signal mask or the signal mask installed as part of the <i>ppoll</i>( ) call.</blockquote> After page 1434 line 47636 (XSH poll ERRORS), insert:<blockquote>The <i>ppoll</i>( ) function shall fail if: [EINVAL] An invalid timeout interval was specified.</blockquote> At page 1436 line 47691 (XSH poll APPLICATION USAGE), change:<blockquote>None.</blockquote>to:<blockquote>Other than the difference in the precision of the timeout argument, the following <i>ppoll</i>( ) call: <code>ready = ppoll(&fds, nfds, tmo_p, &sigmask);</code> is equivalent to atomically executing the following calls: <code>sigset_t origmask; int timeout; timeout = (tmo_p == NULL) ? -1 : (tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000); pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); ready = poll(&fds, nfds, timeout); pthread_sigmask(SIG_SETMASK, &origmask, NULL);</code></blockquote> After page 1436 line 47695 (XSH poll RATIONALE), insert:<blockquote>Code which wants to avoid the ambiguity of the signal mask for thread cancellation handlers can install an additional cancellation handler which resets the signal mask to the expected value. <code>void cleanup(void *arg) { sigset_t *ss = (sigset_t *) arg; pthread_sigmask(SIG_SETMASK, ss, NULL); } int call_ppoll(struct pollfd fds[], nfds_t nfds, const struct timespec *restrict timeout, const sigset_t *restrict sigmask) { sigset_t oldmask; int result; pthread_sigmask(SIG_SETMASK, NULL, &oldmask); pthread_cleanup_push(cleanup, &oldmask); result = ppoll(fds, nfds, timeout, sigmask); pthread_cleanup_pop(0); return result; }</code></blockquote> At page 1556 line 50968 (XSH pselect APPLICATION USAGE), change:<blockquote>None.</blockquote>to:<blockquote>The use of select( ) and pselect( ) requires that the application construct the set of fds to work on each time through a polling loop, and is inherently limited from operating on file descriptors larger than FD_SETSIZE. Also, the amount of work to perform scales as <i>nfds</i> increases, even if the number of file descriptors selected within the larger set remains the same. Thus, applications may wish to consider using poll( ) and ppoll( ) instead, for better scaling.</blockquote> After page 1550 (between XSH pow and pread), insert a new page:<blockquote>NAME ppoll select — input/output multiplexing SYNOPSIS #include <poll.h> int ppoll(struct pollfd [], nfds_t, const struct timespec *restrict, const sigset_t *restrict); DESCRIPTION Refer to poll( ).</blockquote> Include ppoll if XRAT B.1.1 Change History lists new interfaces for issue 8, (compare page 3563 line 120849 listing poll for issue 7). ====================================================================== Issue History Date Modified Username Field Change ====================================================================== 2019-06-18 12:04 eblake New Issue 2019-06-18 12:04 eblake Name => Eric Blake 2019-06-18 12:04 eblake Organization => Red Hat 2019-06-18 12:04 eblake User Reference => ebb.ppoll 2019-06-18 12:04 eblake Section => poll 2019-06-18 12:04 eblake Page Number => 1433 2019-06-18 12:04 eblake Line Number => 47551 2019-06-18 12:04 eblake Interp Status => --- ======================================================================