ZMQ_POLLER(3)
π ZMQ_POLLER(3) β the 0MQ Manual, but make it cute β¨
okay bestie, sit down, grab a strawberry π, because we're about to talk about zmq_poller β aka the function family that does input/output multiplexing. it's in the 0MQ Manual, section 3, and it's genuinely iconic, no cap.
β¨ NAME β¨
zmq_poller β input/output multiplexing π
π¦ SYNOPSIS π¦
here's the whole lineup, exactly as it comes, don't @ me:
void *zmq_poller_new (void);
int zmq_poller_destroy (void **poller_p);
int zmq_poller_size (void *poller);
int zmq_poller_add (void *poller, void *socket, void *user_data, short
events);
int zmq_poller_modify (void *poller, void *socket, short events);
int zmq_poller_remove (void *poller, void *socket);
int zmq_poller_add_fd (void *poller, int fd, void *user_data, short
events);
int zmq_poller_modify_fd (void *poller, int fd, short events);
int zmq_poller_remove_fd (void *poller, int fd);
int zmq_poller_wait (void *poller, zmq_poller_event_t *event, long
timeout);
int zmq_poller_wait_all (void *poller, zmq_poller_event_t *events, int
n_events, long timeout);
int zmq_poller_fd (void *poller, zmq_fd_t *fd);
πΈ DESCRIPTION πΈ
the zmq_poller*_ functions are literally the friend group that lets your app multiplex input/output events across a whole set of sockets β and they do it in a level-triggered fashion. that's the vibe. β¨
π making and unmaking a poller
zmq_poller_new and zmq_poller_destroy manage the lifetime of a poller instance. zmq_poller_new creates and returns a shiny new poller instance, while zmq_poller_destroy destroys it. a pointer to a valid poller must be passed as the poller_p argument of zmq_poller_destroy. and listen β zmq_poller_destroy may not be called multiple times for the same poller instance, that's giving chaos energy and we don't do that π. on a successful execution, zmq_poller_destroy sets the passed pointer to NULL. also, zmq_poller_destroy implicitly unregisters all registered sockets and file descriptors. it cleans up after itself, we love a tidy queen π
π’ how many things are we watching
zmq_poller_size queries the number of sockets or file descriptors registered with a poller. the initial size of a poller is 0, a successful add operation increases the size by 1, and a successful remove operation decreases the size by 1. the size is unaffected by the events specified β events don't get a vote here π
π§ socket registration, the main character arc
zmq_poller_add, zmq_poller_modify and zmq_poller_remove manage the 0MQ sockets registered with a poller.
zmq_poller_addregisters a new socket with a given poller. bothpollerandsocketmust point to valid 0MQ objects. theeventsparameter specifies which event types the client wants to subscribe to. it is legal to specify no events (i.e.0), and activate them later withzmq_poller_modify. in addition,user_datamay be specified, which is not used by the poller, but passed back to the caller when an event was signalled in a call tozmq_poller_waitorzmq_poller_wait_all.user_datamay beNULL. if it is notNULL, it must be a valid pointer β otherwise, behaviour is undefined. π« you must only add a socket to a single poller instance once (unlesszmq_poller_removehas been called for that socket before). you may add a socket to multiple poller instances, if the socket itself is explicitly thread-safe (Server, Client, ...). if the socket is not, you may invoke undefined behavior. so likeβ¦ read the room, bestie.zmq_poller_modifymodifies the subscribed events for a socket. it is legal to specify no events (i.e.0) to disable events temporarily, and reactivate them later with another call tozmq_poller_modify. very pause-and-resume of it πzmq_poller_removeremoves a socket registration completely.zmq_poller_removemust be called before a socket is closed withzmq_close. periodt.
note that it is not necessary to callzmq_poller_removefor any socket before callingzmq_poller_destroy.
also note that callingzmq_poller_removeis not equivalent to callingzmq_poller_modifywith no events.zmq_poller_modifydoes not free resources associated with the socket registration, and requires that the socket remains valid. they are not the same girl, don't confuse them π
π file descriptors, the crossover episode
zmq_poller_add_fd, zmq_poller_modify_fd and zmq_poller_remove_fd are analogous to the previous functions, but they manage regular file descriptors registered with a poller. on Windows, these functions can only be used with WinSock sockets. iykyk πͺ
in the following, 0MQ sockets added with zmq_poller_add and file descriptors added with zmq_poller_add_fd are referred to as registered objects.
π the event struct, she's famous
the zmq_poller_event_t structure is defined as follows:
typedef struct
{
void *socket;
zmq_fd_t fd;
void *user_data;
short events;
} zmq_poller_event_t;
π waiting, the whole point
for each registered object, zmq_poller_wait_all() shall examine the registered objects for the event(s) currently registered.
if none of the registered events have occurred, zmq_poller_wait_all shall wait timeout milliseconds for an event to occur on any of the registered objects. if the value of timeout is 0, zmq_poller_wait_all shall return immediately. if the value of timeout is -1, zmq_poller_wait_all shall block indefinitely until one event has occurred on any of the registered objects. so -1 is giving "i'll wait forever, i'm loyal" π
the events argument of zmq_poller_wait_all must be a pointer to an array of at least n_events elements. behaviour is undefined if events does not point to an array of at least n_events elements. not a vibe, please don't.
zmq_poller_wait_all returns at most n_events events. if more than n_events events were signalled, only an unspecified subset of the signalled events is returned through events.
a caller is advised to ensure thatn_eventsis equal to the number of registered objects. otherwise, a livelock situation may result: if more thann_eventsregistered objects have an active event on each call tozmq_poller_wait_all, it might happen that the same subset of registered objects is always returned, and the caller never notices the events on the others. π΅ the number of objects registered can be queried withzmq_poller_size.
zmq_poller_wait_all returns the number of valid elements. the valid elements are placed in positions 0 to n_events - 1 in the events array. all members of a valid element are set to valid values by zmq_poller_wait_all. for socket events, socket is non-null and fd is an operating system specific value for an invalid socket (-1 or INVALID_SOCKET). for fd events, socket is NULL and fd is a valid file descriptor. the client does therefore not need to initialize the contents of the events array before a call to zmq_poller_wait_all β so no need to pre-game the array, she comes ready β¨. it is unspecified whether the the remaining elements of events are written to by zmq_poller_wait_all. (yes, the original says "the the". we're keeping it. it's part of the lore now π)
π¦ asking for the fd
zmq_poller_fd queries the file descriptor associated with the zmq_poller, and stores it in the address pointer to by fd. the zmq_poller is only guaranteed to have a file descriptor if at least one thread-safe socket is currently registered.
note that closing a socket that is registered in a poller leads to undefined behavior. the socket must be unregistered first. π¨
π EVENT TYPES π
the events parameter of zmq_poller_add and zmq_poller_modify, and the events member of the zmq_poller_event_t structure, are bit masks constructed by OR'ing a combination of the following event flags. mix and match, it's a build-your-own-adventure π
ZMQ_POLLINβ for 0MQ sockets, at least one message may be received from the socket without blocking. for standard sockets this is equivalent to thePOLLINflag of thepoll()system call and generally means that at least one byte of data may be read fromfdwithout blocking. π₯ZMQ_POLLOUTβ for 0MQ sockets, at least one message may be sent to the socket without blocking. for standard sockets this is equivalent to thePOLLOUTflag of thepoll()system call and generally means that at least one byte of data may be written tofdwithout blocking. π€ZMQ_POLLERRβ for 0MQ sockets this flag has no effect on thezmq_poller_addandzmq_poller_modifyfunctions, and is never set in theeventsmember of thezmq_poller_event_tstructure. for standard sockets, this flag is passed throughzmq_poller_wait_allto the underlyingpoll()system call and generally means that some sort of error condition is present on the socket specified byfd. πZMQ_POLLPRIβ for 0MQ sockets this flag has no effect on thezmq_poller_addandzmq_poller_modifyfunctions, and is never set in theeventsmember of thezmq_poller_event_tstructure. for standard sockets this means there is urgent data to read. refer to thePOLLPRIflag for more information. for a file descriptor, refer to your OS documentation: as an example, GPIO interrupts are signaled through aPOLLPRIevent. this flag has no effect on Windows. β οΈ
Note thezmq_poller*_functions may be implemented or emulated using operating system interfaces other thanpoll(), and as such may be subject to the limits of those interfaces in ways not defined in this documentation. so like, she's adaptable, but also slightly unpredictable. main character energy tbh π§
π«Ά THREAD SAFETY π«Ά
like most other 0MQ objects, a poller is not thread-safe. all operations must be called from the same thread. otherwise, behaviour is undefined. one poller, one thread, that's the rule π
in addition to that, if you want to add a socket to multiple existing poller instances, the socket itself needs to be thread-safe (Server, Client, ...). otherwise, behaviour is undefined. no cap.
β RETURN VALUE β
zmq_poller_newreturns a valid pointer to a poller, orNULLin case of a failure.- all functions that return an
int, return-1in case of a failure. in that case,zmq_errno()can be used to query the type of the error as described below. zmq_poller_wait_allreturns the number of events signalled and returned in theeventsarray. it never returns 0. she always has something to say β¨- all other functions return
0in case of a successful execution.
...and that's part 1, bestie β more is coming, don't go anywhere π
π₯ ERRORS π₯
okay bestie, when things go sideways, these are the error codes you might catch. vibe check each one. No cap.
On zmq_poller_new:
ENOMEMβ a new poller could not be allocated successfully. π
On zmq_poller_destroy:
EFAULTβpoller_pdid not point to a valid poller. Note that passing an invalid pointer (e.g. pointer to deallocated memory) may cause undefined behaviour (e.g. an access violation). π
On zmq_poller_size:
EFAULTβpollerdid not point to a valid poller. Note that passing an invalid pointer (e.g. pointer to deallocated memory) may cause undefined behaviour (e.g. an access violation).
On zmq_poller_add, zmq_poller_modify and zmq_poller_remove:
EFAULTβpollerdid not point to a valid poller. Note that passing an invalid pointer (e.g. pointer to deallocated memory) may cause undefined behaviour (e.g. an access violation).ENOTSOCKβsocketdid not point to a valid socket. Note that passing an invalid pointer (e.g. pointer to deallocated memory) may cause undefined behaviour (e.g. an access violation).
On zmq_poller_add:
EMFILEβ TODO π
On zmq_poller_add or zmq_poller_add_fd:
ENOMEMβ Necessary resources could not be allocated. π΅EINVALβsocketresp.fdwas already registered with the poller. π«
On zmq_poller_modify, zmq_poller_modify_fd, zmq_poller_remove or zmq_poller_remove_fd:
EINVALβsocketresp.fdwas not registered with the poller. π«
On zmq_poller_add_fd, zmq_poller_modify_fd and zmq_poller_remove_fd:
EBADFβ Thefdspecified was the retired fd. π»
On zmq_poller_wait and zmq_poller_wait_all:
ENOMEMβ Necessary resources could not be allocated. πETERMβ At least one of the registered objects is a socket whose associated 0MQ context was terminated. πEFAULTβ The providedeventswasNULL, orpollerdid not point to a valid poller, or there are no registered objects or all event subscriptions are disabled andtimeoutwas negative. π¨EINTRβ The operation was interrupted by delivery of a signal before any events were available. β‘EAGAINβ No registered event was signalled before the timeout was reached. β³
On zmq_poller_fd:
EINVALβ The poller has no associated file descriptor. π€·ββοΈEFAULTβ The providedpollerdid not point to a valid poller. π
β¨ EXAMPLE β¨
okay so imagine we're polling indefinitely for input events on both a 0MQ socket and a standard socket.. slay
void *poller = zmq_poller_new ();
/* First item refers to 0MQ socket 'socket' */
zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN);
/* Second item refers to standard socket 'fd' */
zmq_poller_add_fd (poller, fd, NULL, ZMQ_POLLIN);
zmq_poller_event_t events [2];
/* Poll for events indefinitely */
int rc = zmq_poller_wait_all (poller, events, 2, -1);
assert (rc >= 0);
/* Returned events will be stored in 'events' */
for (int i = 0; i < 2; ++i) {
if (events[i].socket == socket && events[i].events & ZMQ_POLLIN) {
// ...
} else if (events[i].fd == fd && events[i].events & ZMQ_POLLIN)) {
// ...
}
}
zmq_poller_destroy (&poller);
π SEE ALSO π
π«Ά AUTHORS π«Ά
This page was written by the 0MQ community. To make a change please read the 0MQ Contribution Policy at http://www.zeromq.org/docs:contributing. π
and that's the whole tea, bestie β this page is from 0MQ 4.3.5, dated 10/09/2023, and it's the ZMQ_POLLER(3) manual. periodt π β¨
π¦ where this page comes from
- epel 10: zeromq 4.3.5-18.el10_0 Β· MPL-2.0 AND BSD-3-Clause AND MIT
- fedora 43: zeromq 4.3.5-22.fc43 Β· MPL-2.0 AND BSD-3-Clause AND MIT
- fedora 43: zeromq 4.3.5-22.fc43 Β· MPL-2.0 AND BSD-3-Clause AND MIT
- fedora 44: zeromq 4.3.5-22.fc43 Β· MPL-2.0 AND BSD-3-Clause AND MIT
- fedora 44: zeromq 4.3.5-22.fc43 Β· MPL-2.0 AND BSD-3-Clause AND MIT
- opensuse-leap 16.0: zeromq-devel 4.3.5-160000.2.2 Β· MPL-2.0
- opensuse-leap 16.0: zeromq-devel 4.3.5-160000.2.2 Β· MPL-2.0
- opensuse-leap 16.0: zeromq-devel 4.3.5-160000.2.2 Β· MPL-2.0
- opensuse-leap 16.0: zeromq-devel 4.3.5-160000.2.2 Β· MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms