There are a few things that you need to generally keep in mind when studying code like this. "Spinlocks" are used by low-level kernel code when it is necessary to prevent two CPUs from accessing the same data structures. "Mutexes" are used to coordinate the actions of processes and threads... kernel or otherwise. "Queues" are used obviously to manage lists of work that must happen "soon but not always immediately." The list of packets that have recently been received and the list of packets that are due to be transmitted are in both cases handled by queues.
Within the kernel, by design, most activities are non-preemptable. The kernel never has control "taken away from it," although it can "give it up." This simplifies the kernel considerably vs. the "microkernel" architecture that is used by other systems. (BTW: that's a large kettle of fish which I choose to keep firmly and tightly shut.)
Speaking generally, software drivers of all types have the same basic design: they are notified of activities by means of queues and/or flags in a data structure that they can examine "without the possibility of that data structure changing while they are doing it," and they respond (if at all) to whatever condition they discover, then loop back and do it again. For example, in the case you described, a driver might observe that "there is an ACK in the queue, and the retransmit timer has popped, and oh by the way the latest asynchronous I/O operation that you performed has been completed with error #53." The driver will now, given all of this, choose how to respond. The ACK won't disappear from the queue unless the driver removes it; the timer won't be started again unless the driver restarts it. There is only one driver instance, one way or the other, for any device.
Last edited by sundialsvcs; 05-30-2012 at 04:57 PM.
|