nanomsgxx-polling(7) -- Nanomsgxx Polling
=========================================

## DESCRIPTION

The nanomsg C API provides a powerful polling system that is mirrored on POSIX's
polling interface. C++ though doesn't have any sort of interface for polling
events on file descriptors in the standard library, so nanomsgxx comes with its
own API for polling on nanomsg sockets instead of integrating with an existing one.  
The wrapper is very small and mostly is syntaxing sugar on top of the C API.

## ENTRIES

Polling is done by passing a vector or nnxx::poll_entry objects to the `nnxx::poll`
function, such objects are defined as:

```
class poll_entry : public nn_pollfd {
public:
  poll_entry() noexcept;
  poll_entry(int socket, int events) noexcept;
  poll_entry(socket &socket, int events) noexcept;

  void clear() noexcept;
  void set(int socket, int events) noexcept;
  void set(socket &socket, int events) noexcept;

  bool is(const socket &s) const noexcept;
  bool recv_ready() const noexcept;
  bool send_ready() const noexcept;
};
```

They are simple descriptors associtating sockets to a set of events that we wnat
to wait for and will get filled with events that happened while calling `nnxx::poll`.
They inherit from nn_pollfd for compatibility with the C API, and simply add some
useful operations.  
Read `nn_poll`'s documentation to learn more about how the polling mechanism works.

## POLL

`nnxx::poll` is available in different versions that makes it easy to use in
multiple situations. The two main interfaces are as follow:

```
poll_vector  poll(poll_vector &&, <timeout>, <flags>);
poll_vector &poll(poll_vector  &, <timeout>, <flags>);
```

The first version accepts a temporary vector object that is used for polling the
entries it contains and will be returned by the function with a move operation,
so no extra memory will be allocated.

The second version accepts a reference to a vector object allocated somewhere
else in the program. Based on the use case one may find useful to use one version
or the other.

The vector returned by nnxx::poll has its entries set with whatever events have
been found on the sockets, the entries then should be iterated and checked to
verify which events are available for which socket.  
nanomsgxx comes with two useful functions, `nnxx::recv_ready` and `nnxx::send_ready`,
that return iterable objects that will filter entries that were marked by `nnxx::poll`
as ready for receiving or sending messages.  
Here's an usage example:

```
nnxx::socket s1 { /* ... */ };
nnxx::socket s2 { /* ... */ };

// ...

// Polling the socket, nnxx::poll_vector can be initialized from a
// std::initializer_list<nnxx::poll_entry>
nnxx::poll_vector entries = nnxx::poll({
    { s1, nnxx::EV_POLLIN },
    { s2, nnxx::EV_POLLIN | nnxx::EV_POLLOUT },
  });

for (auto e : nnxx::recv_ready(entries)) {
  // All entries enumerated here won't block on a receive operation.
}

for (auto e : nnxx::send_ready(entries)) {
  // All entries enumerated here won't block on a send operation.
}
```

- **Note**

The C API uses NN_POLIN and NN_POLOUT as event flags, so nanomsgxx should have
named its constants `nnxx::POLLIN` and `nnxx::POLLOUT`, but these names are macros
defined on POSIX systems supporting the poll interface and would cause compilation
to fail. That's why nanomsgxx uses `nnxx::EV_POLLIN` and `nnxx::EV_POLLOUT` instead.

- **Timeouts**

Polling is by nature a blocking operation, so the API has to provides a way to set
a timeout that will give the hand back to the program in case nothing happens for
a while because we may have to do some other things once in a while.

As described in the design section, exceptions are used to report timeouts in the
nanomsgxx API.  
A timeout can be specified as second argument to the nnxx::poll function, it may
be give as a std::chrono::duration (if we want to set how long the function should
wait), or as a std::chrono::time_point (if we want to set when the function should
return).  
Here's how we'd handle a timeout:

```
nnxx::poll_vector entries;

// ...

try {
  // Polls for events, waits at most one second.
  entries = nnxx::poll({
      { s1, nnxx::EV_POLLIN },
      { s2, nnxx::EV_POLLIN | nnxx::EV_POLLOUT },
    },
    std::chrono::second(1));
}
catch (const nnxx::timeout_error &) {
  // Nothing happened for more than one second.
}
```

## SEE ALSO

nnxx::poll(3)  
nanomsgxx(7)  
nanomsgxx-sockets(7)  
nanomsg(7)  

## AUTHORS

Achille Roussel
