Hi,
I have developed a simple WDF function driver for a IEEE 1394 device. The function driver uses the Microsoft 1394 bus driver in the FIFO list backing store mode. In this mode the function driver adds backing store to an interlocked single linked list, and the 1394 bus driver retrieves backing store from the list when it receives a packet and returns the packet to the function driver using a callback.
From user mode an application thread uses the driver in the following way:
- opens a handle to the device
- creates an I/O completion port (IOCP) for the handle with a concurrency count of 1
- passes 300 backing store requests (IOCTL, METHOD_IN_DIRECT) to the driver
- calls GetQueuedCompletionStatus on the completion port
- processes the completed request, and
- returns the backing store request to the driver
- repeats from step 4
The packets I receive on the address range contain an ascending sequence number. A bus analyser confirms that the packets appear in order on the bus and there are no retransmissions or corrupted packets.
I have tested this implementation with Windows XP Professional Version 2002 SP2 on IBM R51, R60, and T60 laptops. It works fine except on the R60 with a Intel Celeron M 420 CPU @ 1.60 GHz. Here to my surprise the application thread sometimes receive packets out of order from the IOCP!
To further investigate the problem I have introduced the following check in the callback invoked by the bus driver:
- acquire a spinlock
- check that the received packet is the successor to the previously received packet, otherwise trace the error
- complete the associated request
- release spinlock
This check confirms that the driver completes packets in order. However, the application thread still sometimes receives packets out of order.
Am I wrong in my understanding of completion ports: threads are queued in LIFO order and completed requests are queued in FIFO order? From my understanding I concluded that if only a single thread received packets from the IOCP then the thread would receive the packets in the order they were completed, thus packets would appear to the application thread in order.
According to my understanding the following happens when my driver completes a request: an APC is queued on the thread that submitted the request, when the thread is scheduled the APC is executed finalizing the completion of the request in the context of the submitting thread in this case queuing a completion packet on the IOCP. When the APC terminates the application thread performs its own work.
Am I doing any obvious mistakes? I thought I had created a text book example on using IOCPs…