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
0001263 [1003.1(2016/18)/Issue7+TC2] System Interfaces Objection Omission 2019-06-18 12:04 2021-05-07 15:45
Reporter eblake View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Applied  
Name Eric Blake
Organization Red Hat
User Reference ebb.ppoll
Section poll
Page Number 1433
Line Number 47551
Interp Status ---
Final Accepted Text Note: 0005343
Summary 0001263: 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:
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>.


On page 313 line 10621 (XBD <poll.h>), change:
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);
to:

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>.


Add "ppoll( )" 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:
poll
to:
poll, ppoll


After page 1433 line 47555 (XSH poll SYNOPSIS), insert:
int ppoll(struct pollfd fds[], nfds_t nfds, const struct timespec *restrict timeout, const sigset_t *restrict sigmask);


At page 1433 lines 47557-47561 (XSH poll DESCRIPTION), change:
The poll( ) 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 fds, poll( ) shall examine the given file descriptor for the event(s) specified in events. The number of pollfd structures in the fds array is specified by nfds. The poll( ) function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.
to:
The ppoll( ) 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 fds, ppoll( ) shall examine the given file descriptor for the event(s) specified in events. The number of pollfd structures in the fds array is specified by nfds. The ppoll( ) function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.

The poll( ) function shall be equivalent to the ppoll( ) function, except as follows:
• For the poll( ) function, the timeout period is given in milliseconds in an argument of type int, whereas for the ppoll( ) function the timeout period is given in seconds and nanoseconds in an argument of type struct timespec. A timeout of -1 for poll( ) is equivalent to passing a null pointer for the timeout for ppoll( ).
• The poll( ) function has no sigmask argument; it shall behave as ppoll( ) does when sigmask is a null pointer.


On page 1434 (XSH poll APPLICATION USAGE, RETURN VALUE, ERRORS), change the following instances of "poll( )" to "poll( ) or ppoll( )":
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:
If none of the defined events have occurred on any selected file descriptor, poll( ) shall wait at least timeout milliseconds for an event to occur on any of the selected file descriptors. If the value of timeout is 0, poll( ) shall return immediately. If the value of timeout is −1, poll( ) shall block until a requested event occurs or until the call is interrupted.
Implementations may place limitations on the granularity
to:
The timeout parameter controls how long the poll( ) or ppoll( ) function shall take before timing out. If the timeout parameter is positive for poll( ) or not a null pointer for ppoll( ), 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 timeout parameter is -1 for poll( ) or a null pointer for ppoll( ), then the call shall block indefinitely until at least one descriptor meets the specified criteria. To effect a poll, the timeout parameter should be 0 for poll( ), or for ppoll( ) should not be a null pointer, and should point to a zero-valued timespec 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 ppoll( ). If the timeout 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


After page 1434 line 47623 (XSH poll DESCRIPTION), insert:
If sigmask is not a null pointer, then the ppoll( ) 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.

If a thread gets canceled during a 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 ppoll( ) call.


After page 1434 line 47636 (XSH poll ERRORS), insert:
The ppoll( ) function shall fail if:
[EINVAL] An invalid timeout interval was specified.


At page 1436 line 47691 (XSH poll APPLICATION USAGE), change:
None.
to:
Other than the difference in the precision of the timeout argument, the following ppoll( ) 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>


After page 1436 line 47695 (XSH poll RATIONALE), insert:
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>


At page 1556 line 50968 (XSH pselect APPLICATION USAGE), change:
None.
to:
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 nfds 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.


After page 1550 (between XSH pow and pread), insert a new page:
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( ).


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).
Tags issue8
Attached Files

- Relationships
has duplicate 0000881Closedajosey 1003.1(2013)/Issue7+TC1 add ppoll() 
related to 0001186Applied 1003.1(2016/18)/Issue7+TC2 pselect specification allows for race condition that pselect was created to avoid 

-  Notes
(0004427)
joerg (reporter)
2019-06-18 12:36

That interface exists since 2003 in Solaris as _pollsys() and got a ppoll() alias in 2010.
(0004428)
geoffclare (manager)
2019-06-18 14:15
edited on: 2019-06-18 14:15

Should there be an addition equivalent to what we are adding for pselect() at line 50880 via bug 0001186 ?

E.g.:
If a signal is unmasked as a result of the signal mask being altered by ppoll(), and a signal-catching function is called for that signal during the execution of the ppoll() function, and SA_RESTART is clear for the interrupting signal, then
  • If none of the defined events have occurred on any selected file descriptor, ppoll() shall immediately fail with the [EINTR] error after the signal-catching function returns.

  • If one or more of the defined events have occurred, it is unspecified whether ppoll() behaves the same as if none of the events had occurred (failing with [EINTR] as above) or behaves the same as if it was not interrupted (returning the total number of pollfd structures that have selected events).


(0004429)
kre (reporter)
2019-06-18 15:54

NetBSD has had this interface, under the name pollts() since early 2005
(first released in NetBSD 3). I doubt there would be any issue with
adding a ppoll() alias for pollts() if that is the more popular name (though
I never really understood the logic behind the choice of "pselect" as the
name for the interface that inspired all of this).

Re Note: 0004428 - yes., internally poll/select and popllts/pselect[/ppoll]
are just different APIs to get the same information, any caveats that affect
pselect will also affect ppoll/pollts.

I will send to the mailing list some comments on some of the description
provided for this issue which are irrelevant to the issue to be decided.
(0004430)
eblake (manager)
2019-06-18 16:51

Should ppoll() be required to leave the timeout parameter unchanged, or permitted to update it according to the time elapsed? Recall that the standard permits select() to alter its timeout but pselect() must not. Other considerations: in GNU/Linux systems, the kernel's syscall alters the timeout but glibc uses a local variable to the syscall so that the caller does not see an alteration.
(0005047)
geoffclare (manager)
2020-10-16 09:04

The ppoll() additions have been made in the Issue8NewAPIs branch in gitlab, based on the desired action and Note: 0004428.
(0005342)
rhansen (manager)
2021-04-29 15:55

Re: Note: 0004430:
> Should ppoll() be required to leave the timeout parameter unchanged, or permitted to update it according to the time elapsed?

The synopsis has <tt>const struct timespec</tt>, so the implementation is not permitted to update it.
(0005343)
geoffclare (manager)
2021-04-29 15:56

Make the changes from "Additional APIs for Issue 8, Part 1" (Austin/1110).

- 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 => ---
2019-06-18 12:09 eblake Desired Action Updated
2019-06-18 12:36 joerg Note Added: 0004427
2019-06-18 14:15 geoffclare Note Added: 0004428
2019-06-18 14:15 geoffclare Note Edited: 0004428
2019-06-18 14:20 eblake Relationship added related to 0001186
2019-06-18 15:54 kre Note Added: 0004429
2019-06-18 16:51 eblake Note Added: 0004430
2019-08-03 15:22 eblake Relationship added has duplicate 0000881
2020-10-16 09:04 geoffclare Note Added: 0005047
2021-04-29 15:55 rhansen Note Added: 0005342
2021-04-29 15:56 geoffclare Note Added: 0005343
2021-04-29 15:57 geoffclare Final Accepted Text => Note: 0005343
2021-04-29 15:57 geoffclare Status New => Resolved
2021-04-29 15:57 geoffclare Resolution Open => Accepted As Marked
2021-04-29 15:57 geoffclare Tag Attached: issue8
2021-05-07 15:45 geoffclare Status Resolved => Applied


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