Work queue in windows

Transmit and receive queues

Overview

Packet queues, or datapath queues are objects introduced in NetAdapterCx to enable client drivers to model their hardware features, such as hardware transmit and receive queues, more explicitly in software drivers. This topic explains how to work with transmit and receive queues in NetAdapterCx.

When your client driver calls NET_ADAPTER_DATAPATH_CALLBACKS_INIT, typically from its EVT_WDF_DRIVER_DEVICE_ADD event callback function, it provides two queue creation callbacks: EVT_NET_ADAPTER_CREATE_TXQUEUE and EVT_NET_ADAPTER_CREATE_RXQUEUE. The client creates transmit and receive queues in these callbacks respectively.

The framework empties queues before transitioning to a low power state and deletes them before deleting the adapter.

Creating packet queues

When creating a packet queue, either a transmit queue or a receive queue, the client must provide pointers to the following three callback functions:

In addition, the client can provide these optional callback functions after initializing the queue configuration structure:

Creating a transmit queue

NetAdapterCx calls EVT_NET_ADAPTER_CREATE_TXQUEUE at the very end of the power-up sequence. During this callback, client drivers typically do the following:

  • Optionally register start and stop callbacks for the queue.
  • Call NetTxQueueInitGetQueueId to retrieve the identifier of the transmit queue to set up.
  • Call NetTxQueueCreate to allocate a queue.
    • If NetTxQueueCreate fails, the EvtNetAdapterCreateTxQueue callback function should return an error code.
  • Query for packet extension offsets.

The following example shows how these steps might look in code. Error handling code has been left out of this example for clarity.

Creating a receive queue

To create a receive queue from EVT_NET_ADAPTER_CREATE_RXQUEUE, use the same pattern as a transmit queue and call NetRxQueueCreate.

The following example shows how creating a receive queue might look in code. Error handling code has been left out of this example for clarity.

Polling model

The NetAdapter data path is a polling model, and the polling operation on one packet queue is completely independent of other queues. The polling model is implemented by calling the client driver’s queue advance callbacks, as shown in the following figure:

Advancing packet queues

The sequence of a polling operation on a packet queue is as follows:

  1. The OS gives buffers to the client driver for either transmitting or receiving.
  2. The client driver programs the packets to hardware.
  3. The client driver returns the completed packets to the OS.

Polling operations occur within the client driver’s EvtPacketQueueAdvance callback function. Each packet queue in a client driver is backed by underlying data structures called net rings, which contain or link to the actual network data buffers in system memory. During EvtPacketQueueAdvance, client drivers carry out send and receive operations on the net rings by controlling indices within the rings, transferring buffer ownership between hardware and the OS as data is transmitted or received.

For more information about net rings, see Introduction to net rings.

For an example of implementing EvtPacketQueueAdvance for a transmit queue, see Sending network data with net rings. For an example of implementing EvtPacketQueueAdvance for a receive queue, see Receiving network data with net rings.

Enabling and disabling packet queue notification

When a client driver receives new packets in a packet queue’s net rings, NetAdapterCx invokes the client driver’s EvtPacketQueueSetNotificationEnabled callback function. This callback indicates to a client driver that polling (of EvtPacketQueueAdvance or EvtPacketQueueCancel) will stop and will not continue until the client driver calls NetTxQueueNotifyMoreCompletedPacketsAvailable or NetRxQueueNotifyMoreReceivedPacketsAvailable. Typically, a PCI device uses this callback to enable Tx or Rx interrupts. Once an interrupt is received, interrupts can be disabled again and the client driver calls NetTxQueueNotifyMoreCompletedPacketsAvailable or NetRxQueueNotifyMoreReceivedPacketsAvailable to trigger the framework to begin polling again.

Enabling and disabling notification for a transmit queue

For a PCI NIC, enabling transmit queue notification typically means enabling the transmit queue’s hardware interrupt. When the hardware interrupt fires, the client calls NetTxQueueNotifyMoreCompletedPacketsAvailable from its DPC.

Читайте также:  Windows forms как сделать всплывающее окно

Similarly, for a PCI NIC, disabling queue notification means disabling the interrupt associated with the queue.

For a device that has an asynchronous I/O model, the client typically uses an internal flag to track the enabled state. When an asynchronous operation completes, the completion handler checks this flag and calls NetTxQueueNotifyMoreCompletedPacketsAvailable if it is set.

If NetAdapterCx calls EvtPacketQueueSetNotificationEnabled with NotificationEnabled set to FALSE, the client must not call NetTxQueueNotifyMoreCompletedPacketsAvailable until NetAdapterCx next calls this callback function with NotificationEnabled set to TRUE.

Enabling and disabling notification for a receive queue

For a PCI NIC, enabling receive queue notification looks very similar to a Tx queue. This typically means enabling the receive queue’s hardware interrupt. When the hardware interrupt fires, the client calls NetRxQueueNotifyMoreReceivedPacketsAvailable from its DPC.

For a USB device, or any other queue with a software receive completion mechanism, the client driver should track in its own Context whether the queue’s notification is enabled. From the completion routine (triggered for example when a message becomes available in the USB continuous reader), call NetRxQueueNotifyMoreReceivedPacketsAvailable if the notification is enabled. The following example shows how you might do this.

Canceling packet queues

When the OS stops the data path, it begins by invoking the client driver’s EvtPacketQueueCancel callback function. This callback is where client drivers perform any processing needed before the framework deletes the packet queues. Canceling for a transmit queue is optional and depends on whether the hardware supports in-flight transmit cancellation, but canceling for a receive queue is required.

During EvtPacketQueueCancel, drivers return packets to the OS as needed. For code examples of transmit queue and receive queue cancellation, see Canceling network data with net rings.

After calling the driver’s EvtPacketQueueCancel callback, the framework continues to poll the driver’s EvtPacketQueueAdvance callback until all packets and buffers have been returned to the OS.

Work Queue Identifiers

The following constants identify the standard Media Foundation work queues.

Applications should use MFASYNC_CALLBACK_QUEUE_MULTITHREADED or use a work queue obtained from MFLockSharedWorkQueue if they want to control the execution priority. Note that the default platform work queue priorities can dynamically change when an application calls RegisterPlatformWithMMCSS. For more information about work queues, see Work Queues.

Constant/value Description
MFASYNC_CALLBACK_QUEUE_STANDARD 0x00000001 In most cases, applications should use MFASYNC_CALLBACK_QUEUE_MULTITHREADED.
This work queue is used for synchronous operations. Using the standard work queue may run the risk of deadlocking. Applications can create a private synchronous queue on top of the multithreaded queue by using MFAllocateSerialWorkQueue.
MFASYNC_CALLBACK_QUEUE_RT 0x00000002 Not for general application use.
MFASYNC_CALLBACK_QUEUE_IO 0x00000003 Not for general application use.
This work queue is used internally for I/O operations such as reading files and reading from the network.
MFASYNC_CALLBACK_QUEUE_TIMER 0x00000004 Not for general application use.
This work queue is used for periodic callbacks and scheduled work items. The following functions put work items in this queue:
  • MFAddPeriodicCallback
  • MFScheduleWorkItem
  • MFScheduleWorkItemEx
MFASYNC_CALLBACK_QUEUE_MULTITHREADED 0x00000005 This multithreaded work queue should be used in most cases.
This work queue is used for asynchronous operations throughout Media Foundation.
MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION 0x00000007 Not for general application use. Applications should instead use MFASYNC_CALLBACK_QUEUE_MULTITHREADED.

In addition, the following constants are used in connection with work queues.

Work Queue and Threading Improvements

This topic describes improvements in WindowsВ 8 for work queues and threading in the Microsoft Media Foundation platform.

Windows 7 Behavior

This section summarizes the behavior of Media Foundation work queues in WindowsВ 7.

Work Queues

The Media Foundation platform creates several standard work queues. Only two are documented as being for general application use:

  • MFASYNC_CALLBACK_QUEUE_STANDARD
  • MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION

An application or component can allocate new work queues by calling MFAllocateWorkQueue or MFAllocateWorkQueueEx. The MFAllocateWorkQueueEx function defines two types of work queue:

  • MF_STANDARD_WORKQUEUE creates a work queue without a message loop.
  • MF_WINDOW_WORKQUEUE creates a work queue with a message loop.

To queue a work item, call MFPutWorkItem or MFPutWorkItemEx. The platform executes the work item by invoking the caller-provided implementation of IMFAsyncCallback. In WindowsВ 7 and earlier, the platform creates one thread per work queue.

MMCSS Support

The Multimedia Class Scheduler Service (MMCSS) manages thread priorities so that multimedia applications get regular slices of CPU time, without denying CPU resources to lower-priority applications. MMCSS defines a set of tasks that have different CPU utilization profiles. When a thread joins an MMCSS task, MMCSS sets the priority of the thread based on several factors:

  • The base priority of the task, which is set in the registry.
  • The relative thread priority, which is set at run time by calling AvSetMmThreadPriority.
  • Various run-time characteristics, such as whether the application is in the foreground, and how much CPU time is being consumed by the threads in each MMCSS class.

An application can register a work queue with MMCSS by calling MFBeginRegisterWorkQueueWithMMCSS. This function takes a work queue ID, an MMCSS class (task name), and the MMCSS task identifier. Internally, it calls AvSetMmThreadCharacteristics with the task name and task ID. After a work queue is registered with MMCSS, you can get the class and task ID by calling MFGetWorkQueueMMCSSClass and MFGetWorkQueueMMCSSTaskId.

The Media Session provides somewhat higher-level access to these APIs, through the IMFWorkQueueServices interface. This interface provides two primary methods:

Method Description
BeginRegisterPlatformWorkQueueWithMMCSS Registers a work queue with an MMCSS task. This method is essentially a thin wrapper around MFBeginRegisterWorkQueueWithMMCSS, but you can pass the value MFASYNC_CALLBACK_QUEUE_ALL to register all of the platform work queues at once.
BeginRegisterTopologyWorkQueuesWithMMCSS Registers a branch of the topology with a work queue.

To register a topology branch, do the following.

  1. Set the MF_TOPONODE_WORKQUEUE_ID attribute on the source node for the branch. Use any application-defined value.
  2. Optionally, set the MF_TOPONODE_WORKQUEUE_MMCSS_CLASS to join the work queue to an MMCSS task.
  3. Call BeginRegisterTopologyWorkQueuesWithMMCSS on the resolved topology.

The Media Session allocates a new work queue for each unique value of MF_TOPONODE_WORKQUEUE_ID. For each topology branch, asynchronous pipeline operations are performed on the work queue that is assigned to the branch.

IMFRealTimeClient

The IMFRealTimeClient interface is intended for pipeline components that either create their own threads or use work queues for asynchronous operations. The Media Session uses this interface to notify the pipeline component of the correct behavior, as follows:

  • If the pipeline component creates a worker thread, the IMFRealTimeClient::RegisterThreads method notifies the component which MMCSS class to join.
  • If the pipeline component uses a work queue, the IMFRealTimeClient::SetWorkQueue method tells the component which work queue to use.

Typically, a pipeline component uses either a thread or a work queue to perform asynchronous tasks, but not both.

Windows 8 Improvements

Multithreaded Work Queues

In WindowsВ 8, Media Foundation supports a new type of work queue called the multithreaded queue. A multithreaded queue uses a system thread pool to dispatch work items. The multithreaded queue scales better than the previous single-threaded queues. For example,

Several components can share a multithreaded queue without blocking one another, requiring the creation of fewer threads.

Work items are optimized to avoid context switches if an event is already set. This is more efficient than creating your own threads to wait on events.

When using IMFRealTimeClientEx, applications should avoid spinning up threads and instead should use the work queues. To accomplish this, applications should implement SetWorkQueueEx and not use RegisterThreads and UnregisterThreads.

When the Media Foundation platform is initialized, it creates a multithreaded queue with the identifier MFASYNC_CALLBACK_QUEUE_MULTITHREADED.

A multithreaded queue does not serialize work items. Whenever a thread from the thread pool becomes available, the next work item on the queue is dispatched. The caller must ensure that work is serialized correctly. To make this easier, Media Foundation defines a serial work queue. A serial queue wraps another work queue but guarantees fully serialized execution. The next item on the queue is not dispatched until the previous item completes.

The following code creates a serializer queue over the platform multithreaded queue.

More than one serial queue can wrap the same multithreaded queue. The serial queues then share the same thread pool, and serialized execution is enforced within each queue.

The standard work queues that existed prior to WindowsВ 8 are now implemented as serial work queues that wrap the platform multithreaded queue. This change preserves backward compatibility.

Shared Task Work Queues

To work correctly with the kernel scheduler, there should be one multithreaded work queue for each MMCSS task that you use. The Media Foundation platform allocates these as needed, up to one per MMCSS task, per process. To get the shared work queue for a particular MMCSS task, call MFLockSharedWorkQueue and specify the task name. The function looks up the task name in a table. If a work queue does not already exist for this task, the function allocates a new MT work queue and immediately joins it to the MMCSS task. If a work queue already exists for that task, the function returns the identifier of the existing work queue.

Wait Queue

The wait queue is a special platform work queue that waits on events to be signaled. If a component needs to wait for an event to be signaled, it can use the wait queue instead of creating a worker thread to wait on the event.

To use the wait queue, call MFPutWaitingWorkItem. The parameters include the event handle and an IMFAsyncResult pointer. When the event is signaled, the wait queue invokes your callback. There is a single platform wait queue; applications cannot create their own wait queues.

Enhancements to MMCSS Support

The following new Media Foundation platform functions relate to MMCSS.

Function Description
MFBeginRegisterWorkQueueWithMMCSSEx Registers a work queue with MMCSS. This function includes a parameter to specify relative thread priority. Internally, this value is translated into a call to AvSetMmThreadPriority.
MFGetWorkQueueMMCSSPriority Queries the priority of a work queue.
MFRegisterPlatformWithMMCSS Registers all of the platform work queues with an MMCSS task. This function is similar to the IMFWorkQueueServices::BeginRegisterPlatformWorkQueueWithMMCSS method, but it can be used without creating an instance of the Media Session. In addition, the function includes a parameter to specify the base thread priority.

Applications that use the Media Session should set the MF_TOPONODE_WORKQUEUE_MMCSS_CLASS attribute to «Audio» for the audio rendering branch. Set the attribute to «Playback» for the video rendering branch.

IMFRealTimeClientEx

The IMFRealTimeClientEx interface to replaces IMFRealTimeClient, for pipeline components that perform asynchronous operations.

Method Description
RegisterThreadsEx Notifies the component to register its threads with MMCSS. This method is equivalent to IMFRealTimeClient::RegisterThreads, but it adds a parameter for the base thread priority.
SetWorkQueueEx Notifies the component to use a specific work queue. This method is equivalent to IMFReadTimeClient::SetWorkQueue, but it adds a parameter for the work item priority.
UnregisterThreads Notifies the component to unregister its threads from MMCSS. This method is identical to the IMFRealTimeClient::UnregisterThreads method.

Pipeline components should use work queues, and should not create worker threads, for the following reasons:

  • Work queues scale better, because they use the OS thread pools.
  • The platform handles the details of registering work queues with MMCSS.
  • A worker thread can easily cause a deadlock that is hard to debug.

Also, consider using the serializer work queue if you need to serialize your asynchronous operations.

Topology Branches

If the MF_TOPONODE_WORKQUEUE_MMCSS_CLASS attribute registers a topology branch with MMCSS, in WindowsВ 8 the Media Session uses the shared MT work queues. In earlier versions of Windows, the Media Session allocated a new work queue.

Two new attributes are defined for registering a topology branch with MMCSS.

Attribute Description
MF_TOPONODE_WORKQUEUE_MMCSS_PRIORITY Specifies the base thread priority.
MF_TOPONODE_WORKQUEUE_ITEM_PRIORITY Specifies the work item priority.

Recommendations

  • Applications that use the Media Session should set MF_TOPONODE_WORKQUEUE_MMCSS_CLASS to «Audio» for the audio rendering branch and «Playback» for the video rendering branch.
  • Applications that use the Media Session should call IMFWorkQueueServices::BeginRegisterTopologyWorkQueuesWithMMCSS on the topology.
  • For pipeline components, work queues are recommended instead of worker threads. If the component uses either work queues or worker threads, implement IMFRealTimeClientEx.
  • Do not create private work queues, as this defeats the purpose of the platform work queues. Use either the platform multithreaded queue or a serial queue that wraps the platform multithreaded queue.
  • If you need to serialize asynchronous operations, use a serial queue.

Summary

The following Media Foundation platform APIs that relate to threads and work queues are new for WindowsВ 8.

Читайте также:  Grub rescue установка linux
Оцените статью