tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

layeredpoll.rst (6131B)


      1 PR_Poll() and the layered I/O
      2 =============================
      3 
      4 *[last edited by AOF 8 August 1998]*
      5 This memo discusses some of the nuances of using PR_Poll() in
      6 conjunction with *layered I/O*. This is a relatively new feature in NSPR
      7 2.0, not that it hasn't been in the source tree for a while, but in that
      8 it has had no clients.
      9 
     10 Implementation
     11 --------------
     12 
     13 NSPR provides a public API function, PR_Poll() that is modeled after
     14 UNIX' ``poll()`` system call.
     15 
     16 The implementation of :ref:`PR_Poll` is somewhat complicated. Not only
     17 does it map the :ref:`PRPollDesc` array into structures needed by the
     18 underlying OS, it also must deal with layered I/O. This is done despite
     19 the fact that :ref:`PR_Poll` itself is *not* layered. For every element
     20 of the :ref:`PRPollDesc` array that has a non-NULL :ref:`PRFileDesc` and whose
     21 ``in_flags`` are not zero, it calls the file descriptor's
     22 ``poll() method``.
     23 The ``poll()`` method is one of the vector contained in the
     24 :ref:`PRIOMethods` table. In the case of layered I/O, the elements (the
     25 methods) of the methods table may be overridden by the implementer of
     26 that layer. The layers are then *stacked.* I/O using that *stack* will
     27 call through the method at the top layer, and each layer may make
     28 altering decisions regarding how the I/O operation should proceed.
     29 
     30 The purpose of the ``poll()`` method is to allow a layer to modify the
     31 flags that will ultimately be used in the call to the underlying OS'
     32 ``poll()`` (or equivalent) function. Such modification might be useful
     33 if one was implementing an augmented stream protocol (*e.g.,* **SSL**).
     34 SSL stands for **Secure Socket Layer**, hence the obvious applicability
     35 as an example. But it is way to complicated to describe in this memo, so
     36 this memo will use a much simpler layered protocol.
     37 The example protocol is one that, in order to send *n* bytes, it must
     38 first ask the connection's peer if the peer is willing to receive that
     39 many bytes. The form of the request is 4 bytes (binary) stating the
     40 number of bytes the sender wishes to transmit. The peer will send back
     41 the number of bytes it is willing to receive (in the test code there are
     42 no error conditions, so don't even ask).
     43 
     44 The implication of the protocol is obvious. In order to do a
     45 :ref:`PR_Send` operation, the layer must first do a *different* send and
     46 then *receive* a response. Doing this and keeping the *stack's* client
     47 unaware is the goal. **It is not a goal of NSPR 2.0 to hide the nuances
     48 of synchronous verses non-blocking I/O**.
     49 
     50 The layered methods
     51 -------------------
     52 
     53 Each layer must implement a suitable function for *every* element of the
     54 methods table. One can get a copy of default methods by calling
     55 :ref:`PR_GetDefaultIOMethods` These methods simply pass all calls
     56 through the layer on to the next lower layer of the stack.
     57 
     58 A layer implementer might copy the elements of the ``PRIOMethods``
     59 acquired from this function into a methods table of its own, then
     60 override just those methods of interest. *Usually* (with only a single
     61 exception) a layered method will perform its design duties and then call
     62 the next lower layer's equivalent function.
     63 
     64 Layered ``poll()``
     65 ------------------
     66 
     67 One of the more interesting methods is the ``poll()``. It is called by
     68 the runtime whenever the client calls :ref:`PR_Poll`. It may be called at
     69 the *top* layer for *every* file descriptor in the poll descriptor. It
     70 may be called zero or more times. The purpose of the ``poll()`` method
     71 is to provide the layer an opportunity to adjust the polling bits as
     72 needed. For instance, if a client (*i.e.*, top layer) is calling
     73 :ref:`PR_Poll` for a particular file descriptor with a *read* poll
     74 request, a lower layer might decide that it must perform a *write*
     75 first.
     76 In that case, the layer's ``poll()`` method would be called with
     77 **``in_flags``** including a ``PR_POLL_READ`` flag. However, the
     78 ``poll()`` method would call the next lower layer's ``poll()`` method
     79 with a ``PR_POLL_WRITE`` bit set. This process of re-assigning the poll
     80 flags can happen as many times as there are layers in the stack. It is
     81 the final value, the one returned to the caller of the top layer's
     82 ``poll()`` method (:ref:`PR_Poll`) that will be used by the runtime when
     83 calling the OS' ``poll()`` (or equivalent) system call.
     84 
     85 It is expected that the modification of the polling bits propagate from
     86 the top of the stack down, allowing the layer closest to the bottom of
     87 the stack to provide the final setting. The implication is that there
     88 should be no modifications of the **``in_flags``** during the *return*
     89 phase of the layered function.
     90 
     91 For example:
     92 
     93 It is not advised to modify the ``final_in_flags`` between the call to
     94 the lower layer's ``poll()`` method and the ``return`` statement.
     95 The third argument of the ``poll()`` method is a pointer to a 16-bit
     96 word. If the layer sets a value in memory through that pointer *and*
     97 returns with a value that has *corresponding* bits, the runtime assumes
     98 that the file descriptor is ready immediately.
     99 
    100 There are two important deviations from the normal. First, this is the
    101 one (known) exception to having a layered routine call the stack's next
    102 lower layer method. If bits are set in the ``out_flags`` the method
    103 should return *directly*. Second, the runtime will observe that the
    104 layer claims this file descriptor is ready and suppress the call to the
    105 OS' ``poll()`` system call.
    106 
    107 At this time the only known use for this feature is to allow a layer to
    108 indicate it has buffered *input*. Note that it is not appropriate for
    109 buffered *output* since in order to write/send output the runtime must
    110 still confirm with the OS that such an operation is permitted.
    111 
    112 Since the ``poll()`` method may be called zero or more times it must
    113 therefore be *idempotent* or at least *functional*. It will need to look
    114 at the layer's state, but must not make modifications to that state that
    115 would cause subsequent calls within the same :ref:`PR_Poll` call to
    116 return a different answer. Since the ``poll()`` method may not be called
    117 at all, so there is not guarantee that any modifications that would have
    118 been performed by the routine will every happen.