1
0
mirror of https://github.com/JoelBender/bacpypes synced 2025-09-28 22:15:23 +08:00
bacpypes/doc/source/modules/iocb.rst

405 lines
15 KiB
ReStructuredText

.. BACpypes IO control block module
.. module:: iocb
IO Control Block
================
The IO Control Block (IOCB) is a data structure that is used to store parameters
for some kind of processing and then used to retrieve the results of that
processing at a later time. An IO Controller (IOController) is the executor
of that processing.
They are modeled after the VAX/VMS IO subsystem API in which a single function
could take a wide variety of combinations of parameters and the application
did not necessarily wait for the operation to complete, but could be notified
when it was by an event flag or semaphore. It could also provide a callback
function to be called when processing was complete.
For example, given a simple function call::
result = some_function(arg1, arg2, kwarg1=1)
The IOCB would contain the arguments and keyword arguments, the some_function()
would be the controller, and the result would alo be stored in the IOCB when
the function is complete.
If the IOController encountered an error during processing, some value specifying
the error is also stored in the IOCB.
Classes
-------
There are two fundamental classes in this module, the :class:`IOCB` for bundling
request parameters together and processing the result, and :class:`IOController`
for executing requests.
The :class:`IOQueue` is an object that manages a queue of IOCB requests when
some functionality needs to be processed one at a time, and an :class:`IOQController`
which has the same signature as an IOController but takes advantage of a queue.
The :class:`IOGroup` is used to bundle a collection of requests together that
may be processed by separate controllers at different times but has `wait()`
and `add_callback()` functions and can be otherwise treated as an IOCB.
.. class:: IOCB
The IOCB contains a unique identifier, references to the arguments and
keyword arguments used when it was constructed, and placeholders for
processing results or errors.
.. attribute:: ioID
Every IOCB has a unique identifier that persists for the lifetime of
the block. Similar to the Invoke ID for confirmed services, it can be used
to synchronize communications and related functions.
The default identifier value is a thread safe monotonically increasing
value.
.. attribute:: args, kwargs
These are copies of the arguments and keyword arguments passed during the
construction of the IOCB.
.. attribute:: ioState
The ioState of an IOCB is the state of processing for the block.
* *idle* - an IOCB is idle when it is first constructed and before it has been given to a controller.
* *pending* - the IOCB has been given to a controller but the processing of the request has not started.
* *active* - the IOCB is being processed by the controller.
* *completed* - the processing of the IOCB has completed and the positive results have been stored in `ioResponse`.
* *aborted* - the processing of the IOCB has encountered an error of some kind and the error condition has been stored in `ioError`.
.. attribute:: ioResponse
The result that some controller is providing to the application that
created the IOCB.
.. attribute:: ioError
The error condition that the controller is providing when the processing
resulted in an error.
.. method:: __init__(*args, **kwargs)
:param args: arbitrary arguments
:param kwargs: arbitrary keyword arguments
Create an IOCB and store the arguments and keyword arguments in it. The
IOCB will be given a unique identifier and start in the *idle* state.
.. method:: complete(msg)
:param msg: positive result of request
.. method:: abort(msg)
:param msg: negative results of request
.. method:: trigger()
This method is called by complete() or abort() after the positive or
negative result has been stored in the IOCB.
.. method:: wait(*args)
:param args: arbitrary arguments
Block until the IO operation is complete and the positive or negative
result has been placed in the ICOB. The arguments are passed to the
`wait()` function of the ioComplete event.
.. method:: add_callback(fn, *args, **kwargs)
:param fn: the function to call when the IOCB is triggered
:param args: additional arguments passed to the function
:param kwargs: additional keyword arguments passed to the function
Add the function `fn` to a list of functions to call when the IOCB is
triggered because it is complete or aborted. When the function is
called the first parameter will be the IOCB that was triggered.
An IOCB can have any number of callback functions added to it and they
will be called in the order they were added to the IOCB.
If the IOCB is has already been triggered then the callback function
will be called immediately. Callback functions are typically added
to an IOCB before it is given to a controller.
.. method:: set_timeout(delay, err=TimeoutError)
:param seconds delay: the time limit for processing the IOCB
:param err: the error to use when the IOCB is aborted
Set a time limit on the amount of time an IOCB can take to be completed,
and if the time is exceeded then the IOCB is aborted.
.. class:: IOController
An IOController is an API for processing an IOCB. It has one method
`process_io()` provided by a derived class which will be called for each IOCB
that is requested of it. It calls one of its `complete_io()` or `abort_io()`
functions as necessary to satisfy the request.
This class does not restrict a controller from processing more than one
IOCB simultaneously.
.. method:: request_io(iocb)
:param iocb: the IOCB to be processed
This method is called by the application requesting the service of a
controller.
.. method:: process_io(iocb)
:param iocb: the IOCB to be processed
The implementation of `process_io()` should be written using "functional
programming" principles by not modifying the arguments or keyword arguments
in the IOCB, and without side effects that would require the application
using the controller to submit IOCBs in a particular order. There may be
occasions following a "remote procedure call" model where the application
making the request is not in the same process, or even on the same machine,
as the controller providing the functionality.
.. method:: active_io(iocb)
:param iocb: the IOCB being processed
This method is called by the derived class when it would like to signal
to other types of applications that the IOCB is being processed.
.. method:: complete_io(iocb, msg)
:param iocb: the IOCB to be processed
:param msg: the message to be returned
This method is called by the derived class when the IO processing is
complete. The `msg`, which may be None, is put in the `ioResponse`
attribute of the IOCB which is then triggered.
IOController derived classes should call this function rather than
the `complete()` function of the IOCB.
.. method:: abort_io(iocb, msg)
:param iocb: the IOCB to be processed
:param msg: the error to be returned
This method is called by the derived class when the IO processing has
encountered an error. The `msg` is put in the `ioError`
attribute of the IOCB which is then triggered.
IOController derived classes should call this function rather than
the `abort()` function of the IOCB.
.. method:: abort(err)
:param msg: the error to be returned
This method is called to abort all of the IOCBs associated with the
controller. There is no default implementation of this method.
.. class:: IOQueue
An IOQueue is simply a first-in-first-out priority queue of IOCBs, but the
IOCBs are modified to know that they can been queued. If an IOCB is aborted
before being retrieved from the queue, it will ask the queue to remove it.
.. method:: put(iocb)
:param iocb: add an IOCB to the queue
.. method:: get(block=1, delay=None)
:param block: wait for an IOCB to be available in the queue
:param delay: maximum time to wait for an IOCB
The `get()` request returns the next IOCB in the queue and waits for one
if there are none available. If `block` is false and the queue is
empty, it will return None.
.. method:: remove(iocb)
:param iocb: an IOCB to remove from the queue
Removes an IOCB from the queue. If the IOCB is not in the queue, no
action is performed.
.. method:: abort(err)
:param msg: the error to be returned
This method is called to abort all of the IOCBs in the queue.
.. class:: IOQController
An `IOQController` has an identical interface as the `IOContoller`, but
provides additional hooks to make sure that only one IOCB is being processed
at a time.
.. method:: request_io(iocb)
:param iocb: the IOCB to be processed
This method is called by the application requesting the service of a
controller. If the controller is already busy processing a request,
this IOCB is queued until the current processing is complete.
.. method:: process_io(iocb)
:param iocb: the IOCB to be processed
Provided by a derived class, this is identical to `IOController.process_io`.
.. method:: active_io(iocb)
:param iocb: the IOCB to be processed
Called by a derived class, this is identical to `IOController.active_io`.
.. method:: complete_io(iocb, msg)
:param iocb: the IOCB to be processed
Called by a derived class, this is identical to `IOController.complete_io`.
.. method:: abort_io(iocb, msg)
:param iocb: the IOCB to be processed
Called by a derived class, this is identical to `IOController.abort_io`.
.. method:: abort(err)
:param msg: the error to be returned
This method is called to abort all of the IOCBs associated with the
controller. All of the pending IOCBs will be aborted with this error.
.. class:: IOGroup(IOCB)
An `IOGroup` is like a set that is an IOCB. The group will complete
when all of the IOCBs that have been added to the group are complete.
.. method:: add(iocb)
:param iocb: an IOCB to include in the group
Adds an IOCB to the group.
.. method:: abort(err)
:param err: the error to be returned
This method is call to abort all of the IOCBs that are members of
the group.
.. method:: group_callback(iocb)
: param iocb: the member IOCB that has completed
This method is added as a callback to all of the IOCBs that are added
to the group and it is called when each one completes. Its purpose
is to check to see if all of the IOCBs have completed and if they
have, trigger the group as completed.
.. class:: IOChainMixIn
The IOChainMixIn class adds an additional API to things that act like
an IOCB and can be mixed into the inheritance chain for translating
requests from one form to another.
.. method:: __init__(iocb)
:param iocb: the IOCB to chain from
Create an object that is chained from some request.
.. method:: encode()
This method is called to transform the arguments and keyword arguments
into something suitable for the other controller. It is typically
overridden by a derived class to perform this function.
.. method:: decode()
This method is called to transform the result or error returned by
the other controller into something suitable to return. It is typically
overridden by a derived class to perform this function.
.. method:: chain_callback(iocb)
:param iocb: the IOCB that has completed, which is itself
When a chained IOCB has completed, the results are translated or
decoded for the next higher level of the application. The `iocb`
parameter is redundant because the IOCB becomes its own controller,
but the callback API requires the parameter.
.. method:: abort_io(iocb, err)
:param iocb: the IOCB that is being aborted
:param err: the error to be used as the abort reason
Call this method to abort the IOCB, which will in turn cascade the
abort operation to the chained IOCBs. This has the same function
signature that is used by an IOController because this instance
becomes its own controller.
.. class:: IOChain(IOCB, IOChainMixIn)
An IOChain is a class that is an IOCB that includes the IOChain API.
Chains are used by controllers when they need the services of some other
controller and results need to be processed further.
Controllers that operate this way are similar to an adapter, they take
arguments in one form, encode them in some way in an IOCB, pass it to the
other controller, then decode the results.
.. class:: ClientController(Client, IOQController)
An instance of this class is a controller that sits at the top of a
protocol stack as a client. The IOCBs to be processed contain a single
PDU parameter that is sent down the stack. Any PDU coming back up
the stack is assumed to complete the current request.
This class is used for protocol stacks with a strict master/slave
architecture.
This class inherits from `IOQController` so if there is already an active
request then subsequent requests are queued.
.. class:: _SieveQueue(IOQController)
This is a special purpose controller used by the `SieveClientController`
to serialize requests for the same source/destination address.
.. class:: SieveClientController(Client, IOController)
Similar to the `ClientController`, this class is a controller that also
sits at the top of a protocol stack as a client. The IOCBs to be processed
contain a single PDU parameter with a `pduDestination` address. Unlike
the `ClientController`, this class creates individual queues for each
destination address so it can process multiple requests simultaneously while
maintaining a strict master/slave relationship with each address.
When an upstream PDU is received, the `pduSource` address is used to
associate this response with the correct request.
Functions
---------
.. function:: register_controller(controller)
:param controller: controller to register
The module keeps a dictionary of "registered" controllers so that other
parts of the application can find the controller instance. For example,
if an HTTP controller provided a GET service and it was registered then
other parts of the application could take advantage of the service the
controller provides.