mirror of
https://github.com/JoelBender/bacpypes
synced 2025-09-28 22:15:23 +08:00
405 lines
15 KiB
ReStructuredText
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.
|