libzmq: Inconsistencies with ZMQ_POLLOUT and ZMQ_ROUTER in ZMQ_MANDATORY mode
(Related to PR #2622; partial fix, API and ABI compatible)
I am copying the description of the problem here from #2622:
If
ZMQ_ROUTER_MANDATORYis set, andzmq_poll()waits forZMQ_POLLOUTevents, zmq_poll() will immediately wake up if only 1 pipe has room to send, regardless of the peer, creating a busy loop ofzmq_poll()wake-up,zmq_send()(EAGAIN). There is no way for the application to selectively wait forZMQ_POLLOUTfor specific peer(s), which seems somehow necessary inZMQ_ROUTER_MANDATORY.
Some possible solutions come to my mind now (obviously, all of them breaking API and ABI unless implemented in parallel):
-
Change
zmq_poll_item_tto accept a list ofZMQ_IDENTITYtoZMQ_POLLOUTas an optional parameter. If none is specified, then current behaviour should be maintained. -
Create
zmq_pollable peerzmq_sock_t(fake), and open APIs to get thosezmq_sock_tgivenZMQ_IDENTITYto be placed as regularzmq_poll_item_t.
I tend to think 1) is a bit easier to implement and simpler to use. I would like to know the opinions. We could try to work a bit on it, either on zmq_poll() itself or a parallel version. But I want to make sure there are chances to be accepted before committing any efforts.
Thoughts?
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 1
- Comments: 27 (27 by maintainers)
Commits related to this issue
- Update NEWS for #2623 — committed to zeromq/libzmq by bluca 7 years ago
- Merge pull request #169 from bluca/news Update NEWS for #2623 — committed to zeromq/libzmq by somdoron 7 years ago
Sorry but we can’t break zmq_poll compatibility, as its API is finalised.
But we have in development a new polling implementation, you can find it as zmq_poller - I think that would be a good place to implement this functionality. That API has not yet been declared STABLE, so it can be changed if needed.
https://github.com/zeromq/libzmq/blob/master/include/zmq.h#L585 https://github.com/zeromq/libzmq/blob/master/src/zmq.cpp#L754 https://github.com/zeromq/libzmq/blob/master/src/socket_poller.cpp
So,
You can find some preliminary, incomplete work here, but I think sufficient to trigger discussion. I will continue tomorrow, but I would appreciate early feedback before going any much further.
This branch is frozen for discussion:
https://github.com/msune/libzmq/commits/poller_peer_support_discuss
In particular, this commit:
https://github.com/msune/libzmq/commit/1c386bf4eb3a1d8ab24bd96006b17f0df123b412
Short summary
Key 4 additional methods are:
I think the usage is clear. One can use regular poller methods to add the entire socket or (or in addition) use _peer to add specific ZMQ identity poller items.
To read from a specific ZMQ identity,
zmq_recv_peer()There is probably a better name than
peer(identity?). Open to suggestions.Missing
A lot:
poller_peer()methods to check that socket is multi-peerzmq_recv_peer()and support forZMQ_PEER_EVENTSingetsockopt()on sockets with multi-peer supportWhat I don’t like
I dislike using
getsockopt()with an additional structzmq_gso_peer_events_tforZMQ_PEER_EVENTS. I was following the current approach.I would very much prefer opening an API to the socket base to get that, and expose it through regular C bindings. Comments?
Some other stuff, unrelated to this feature
zmq::socket_poller_t::zero_trail_events()andzmq::socket_poller_t::check_events()Thoughts?
I think I might have a simple solution, right now we have zmq_poller_add which accept events to listen to. We can have an overload which accept a predicate (function pointer) instead of the events. The predicate will be run when the socket is signaled and return the events for the socket. This will work as zeromq socket is edge triggered.
Inside the predicate user can implement any logic, including checking if specific identity is ready.
we should also had a API function or socket option to retrieve the status of specific identity inside the router socket.