* job_toiface stays the same (RR to channel with idle TXer) * job_tochan which is called when job_toiface finds an available channel or when chan_handle_write sees an idle TXer and there's work on the iface queue, adds the job to the channel's job ring. The recv queue was a limited depth fifo (job_tochan adds to head, job_fromchan and chan_handle_read use tail), but it's now a ring (array) for both sync and async interfaces. Rings work fine as fifos, and finding a random job there is only O(1). * The job ticket attribute selected using the 'jobticket' interface parameter in the configuration filae may be either of string or integer type. * For interfaces with windows > 1, job tickets are not mandatory, but if the interface has a job ticket attribute defined, a job ticket must always be specified in each message from the module, otherwise it is considered an error and the message is ignored. Eventually the module will time out and be restarted if it doesn't provide timely and valid responses. * main calls proc_handle_read and chan_handle_read, in that order; they don't call each other. * chan_handle_read receives messages on an AV list local to the channel instead of straight on chan->recvqt->vm->replist. When the message is complete, it call job_fromchan, supplying the received list. * job_fromchan scans the list received from the module for an attribute defined in iface->jobticket and takes its value. It then checks the value against the boundaries of the full ring and verifies whether the indicated slot contains a job. If so, it takes the job from the ring and advances the read pointer if appropriate. * The subprocess watchdog used to guard the progress of data reception. However, with asynchronous interfaces, this would not prevent stale jobs that the subprocess forgets about. Therefore it's now been made to guard the oldest job in its channel's job ring. If a subprocess forgets about any job it was assigned, it's eventually killed and all the jobs on its channel's ring are aborted. Subprocesses should always reply to each job within the timeout period specified for the interface. If it may encounter a timeout from a lower layer itself, it must handle that itself; it must always reply, possibly with an indication of the lower level timeout in some attribute, so that the behaviour file can do the right thing. * job_tochan and chan_handle_read now together manage the channel's subprocess' timer in states idle and rxing, and perform some state transitions (idle -> txing, rxing -> idle); the other states and timers used by them are still managed by the subprocs themselves. Essentially, how it works is this. job_tochan sets an expiry time on a job. If the subprocess' timer was shut down (not waiting for an older job), it is set to this time as well. Then, at the end of chan_handle_read, it looks at the job ring. If it's empty, the receiver is shut down and if the subprocess is now idle, the timer is shut down as well. If it's not, it sets the subprocess timer to the timeout of the oldest job on the ring.