std.poll
API summary (generated from the Beans source by npm run coverage): 1 package function · 3 types · 1 constructor · 4 static methods · 7 instance methods · 7 public fields.
std.poll lets one thread wait on many descriptors at once and learn which ones
are ready. It uses epoll on Linux and kqueue on macOS, in level-triggered
mode. Read the source at
stdlib/std/poll/poll.b.
import std.pollYou register descriptors with a poller, each under a token you choose. When you wait, each ready descriptor comes back carrying its token. The token is your own value, never a raw descriptor, so you can use it as an index or an id into your own data. That matters because a descriptor number is reused the moment it is closed, so an event keyed on one could name a different thing by the time you handle it.
Interest
Section titled “Interest”What you want to watch a descriptor for. An ordinary value, so build one and reuse it.
pub class Interestnew Interest(read: bool, write: bool)
pub read: boolpub write: bool
pub static fn read_only() -> Interestpub static fn write_only() -> Interestpub static fn both() -> Interestread_onlywatches for incoming data, or for a connection on a listener.write_onlywatches for room to write.bothwatches for both.
One descriptor that became ready, as returned by wait.
pub class Eventpub token: intpub readable: boolpub writable: boolpub hangup: boolpub error: booltokenis the value you gave toadd, yours to interpret.readablemeans data has arrived or a listener has a connection waiting.writablemeans there is room to write.hangupmeans the peer is gone; a socket can be readable and hung up, and the buffered data is still worth reading.errormeans the descriptor itself failed.
Poller
Section titled “Poller”The set of descriptors to wait on. It is a unique class: move-only, and it
closes itself on drop.
pub unique class Poller
pub static fn open() -> Result<Poller>
pub fn add(fd: int, token: int, want: Interest) -> Result<bool>pub fn modify(fd: int, token: int, want: Interest) -> Result<bool>pub fn remove(fd: int) -> Result<bool>pub fn wait(max_events: int, timeout_ms: int) -> Result<List<Event>>pub fn wake() -> Result<bool>pub fn wake_handle() -> intpub fn close() -> Result<bool>opencan fail rather than being a constructor because a poller carries an internal pipe sowake()works.addstarts watchingfdand reportstokenwhen it is ready. Registering the same descriptor twice replaces the earlier registration rather than failing.modifychanges what a descriptor is watched for, and its token.removestops watching a descriptor. Do this before closing the descriptor. Closing does drop it from the kernel’s set, but events already in the current batch still carry its token, and by then the number may belong to something else.waitreturns the ready descriptors, at mostmax_eventsof them, which bounds the allocation. A negativetimeout_mswaits indefinitely,0is a non-blocking check, and any other value waits up to that many milliseconds. Running out of time gives an empty list, not an error.wakemakes a blockedwaitreturn promptly. Repeated wakes collapse into one, and a wake is never reported as an event.wake_handlereturns anintthat can cross a thread boundary. It is not the descriptor: it names a slot and a generation, so a wake issued after this poller closes reports kindclosedinstead of writing into whatever inherited the descriptor number.- Every method returns kind
closedonce the poller is closed.
Waking from another thread
Section titled “Waking from another thread”If another thread needs to wake a blocked poller, it calls the module-level
function with the poller’s wake_handle(). It is a free function rather than a
method because the whole point is that the caller does not hold the Poller. A
stale handle, from a poller that has since closed, is an err with kind closed.
pub fn wake(signal: int) -> Result<bool>Register a listener and wait for a connection to arrive:
import std.ioimport std.pollimport std.net
fn main() { let listener: net.TcpListener = net.TcpListener.bind("127.0.0.1", 0).expect("bind") let poller: poll.Poller = poll.Poller.open().expect("open") poller.add(listener.poll_handle(), 1, poll.Interest.read_only()).expect("add") let events: List<poll.Event> = poller.wait(8, 1000).expect("wait") for e in events { if e.token == 1 && e.readable { io.println("a connection is waiting") } }}See also
Section titled “See also”- std.net, sockets expose a
poll_handle(). - std.signal, a
Signalsalso has apoll_handle().