Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
8.7 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. rxworkq.h
  5. Abstract:
  6. This module defines the data structures required to implement the dispatching
  7. mechanism in RDBSS for use by RDBSS as well as all the mini redirectors.
  8. Author:
  9. Balan Sethu Raman [SethuR] 20-Mar-96
  10. --*/
  11. #ifndef _RXWORKQ_H_
  12. #define _RXWORKQ_H_
  13. //
  14. // The worker thread routine prototype definition.
  15. //
  16. typedef
  17. VOID
  18. (NTAPI *PRX_WORKERTHREAD_ROUTINE) (
  19. IN PVOID Context
  20. );
  21. //
  22. // The RDBSS needs to keep track of the work items on a per device object basis.
  23. // This enables the race conditions associated with loading/unloading as well as
  24. // a mechanism for preventing a single mini redirector from unfairly hogging all
  25. // the resources.
  26. //
  27. #ifdef __cplusplus
  28. typedef struct _RX_WORK_QUEUE_ITEM_ : public WORK_QUEUE_ITEM {
  29. // the work queue item as defined in NTOS
  30. #else // !__cplusplus
  31. typedef struct _RX_WORK_QUEUE_ITEM_ {
  32. WORK_QUEUE_ITEM; // the work queue item as defined in NTOS
  33. #endif // __cplusplus
  34. PRDBSS_DEVICE_OBJECT pDeviceObject;
  35. } RX_WORK_QUEUE_ITEM, *PRX_WORK_QUEUE_ITEM;
  36. //
  37. // There are certain scenarios in which dispatching of work items is inevitable.
  38. // In such instance the WORK_QUEUE_ITEM is allocated as part of another data
  39. // structure to avoid frequent allocation/freeing. In other scenarios where
  40. // dispatching is rare it pays to avoid the allocation of the memory till it
  41. // is rquired. The RDBSS work queue implementations provide for both these
  42. // scenarios in the form of dispatching and posting work queue requests. In
  43. // the case of dispatching no memory for the WORK_QUEUE_ITEM need be allocated
  44. // by the caller while for posting the memory for WORK_QUEUE_ITEM needs to be
  45. // allocated by the caller.
  46. //
  47. typedef struct _RX_WORK_DISPATCH_ITEM_ {
  48. RX_WORK_QUEUE_ITEM WorkQueueItem;
  49. PRX_WORKERTHREAD_ROUTINE DispatchRoutine;
  50. PVOID DispatchRoutineParameter;
  51. } RX_WORK_DISPATCH_ITEM, *PRX_WORK_DISPATCH_ITEM;
  52. //
  53. // The work queues typically come up in a active state and continue till either
  54. // a non recoverable situation is encountered ( lack of system resources ) when
  55. // it transitions to the Inactive state. When a rundown is initiated it transitions
  56. // to the rundown in progress state.
  57. //
  58. typedef enum _RX_WORK_QUEUE_STATE_ {
  59. RxWorkQueueActive,
  60. RxWorkQueueInactive,
  61. RxWorkQueueRundownInProgress
  62. } RX_WORK_QUEUE_STATE, *PRX_WORK_QUEUE_STATE;
  63. //
  64. // The rundown of work queues is not complete when the threads have been spun down.
  65. // The termination of the threads needs to be ensured before the data structures
  66. // can be torn down. The work queue implementation follows a protocol in which
  67. // each of the threads being spundown stashes a reference to the thread object
  68. // in the rundown context. The rundown issuing thread ( which does not belong to
  69. // the work queue ) waits for the completion of all the threads spundown before
  70. // tearing down the data structures.
  71. //
  72. typedef struct _RX_WORK_QUEUE_RUNDOWN_CONTEXT_ {
  73. KEVENT RundownCompletionEvent;
  74. LONG NumberOfThreadsSpunDown;
  75. PETHREAD *ThreadPointers;
  76. } RX_WORK_QUEUE_RUNDOWN_CONTEXT, *PRX_WORK_QUEUE_RUNDOWN_CONTEXT;
  77. //
  78. // The work queue implementation is built around a KQUEUE implementation. The
  79. // additional support involves the regulation of number of threads that are
  80. // actively waiting for the work items. Each work queue data structure is
  81. // allocated in nonpaged pool and has its own synchronization mechanism ( spinlock).
  82. //
  83. // In addition to the bookkeeing information, i.e., state, type etc. it also includes
  84. // statistics that are gathered over the lifetime of the queue. This will
  85. // provide valuable information in tuning a work queue instance. The number of items
  86. // that have been processed , the number of items that have to be processed and
  87. // the cumulative queue length is recorded. The cumulative queue length is the
  88. // intersiting metric, it is the sum of the number of items awaiting to be processed
  89. // each time an additional work item was queued. The cumulative queue length
  90. // divided by the sum of the total number of items processed and the anumber of
  91. // items to be processed gives an indication of the average length of the
  92. // queue. A value much greater than one signifies that the minimum number of
  93. // worker threads associated with the work queue can be increased. A value much
  94. // less than one signifies that the maximum number of work threads associated
  95. // with the queue can be decreased.
  96. //
  97. typedef struct _RX_WORK_QUEUE_ {
  98. USHORT State;
  99. BOOLEAN SpinUpRequestPending;
  100. UCHAR Type;
  101. KSPIN_LOCK SpinLock;
  102. PRX_WORK_QUEUE_RUNDOWN_CONTEXT pRundownContext;
  103. LONG NumberOfWorkItemsDispatched;
  104. LONG NumberOfWorkItemsToBeDispatched;
  105. LONG CumulativeQueueLength;
  106. LONG NumberOfSpinUpRequests;
  107. LONG MaximumNumberOfWorkerThreads;
  108. LONG MinimumNumberOfWorkerThreads;
  109. LONG NumberOfActiveWorkerThreads;
  110. LONG NumberOfIdleWorkerThreads;
  111. LONG NumberOfFailedSpinUpRequests;
  112. LONG WorkQueueItemForSpinUpWorkerThreadInUse;
  113. RX_WORK_QUEUE_ITEM WorkQueueItemForTearDownWorkQueue;
  114. RX_WORK_QUEUE_ITEM WorkQueueItemForSpinUpWorkerThread;
  115. RX_WORK_QUEUE_ITEM WorkQueueItemForSpinDownWorkerThread;
  116. KQUEUE Queue;
  117. // The next field is for debugging purposes and will be removed from the
  118. // FREE build.
  119. PETHREAD *ThreadPointers;
  120. } RX_WORK_QUEUE, *PRX_WORK_QUEUE;
  121. //
  122. // The dispatching mechanism in RDBSS provides for multiple levels of work queues
  123. // on a per processor basis. There are three levels of work queues currently
  124. // supported, Critical,Delayed and HyperCritical. The distinction between Critical
  125. // and delayed is one of priority where as HyperCritical iss different from the
  126. // other two in that the routines should not block, i.e., wait for any resource.
  127. // This requirement cannot be enforced hence the effectiveness of the dispatching
  128. // mechanism relies on the implicit cooperation of the clients.
  129. //
  130. typedef struct _RX_WORK_QUEUE_DISPATCHER_ {
  131. RX_WORK_QUEUE WorkQueue[MaximumWorkQueue];
  132. } RX_WORK_QUEUE_DISPATCHER, *PRX_WORK_QUEUE_DISPATCHER;
  133. //
  134. // The dispatcher typically come up in a active state and continue till either
  135. // a non recoverable situation is encountered ( lack of system resources ) when
  136. // it transitions to the Inactive state. When a rundown is initiated it transitions
  137. // to the rundown in progress state.
  138. //
  139. typedef enum _RX_DISPATCHER_STATE_ {
  140. RxDispatcherActive,
  141. RxDispatcherInactive
  142. } RX_DISPATCHER_STATE, *PRX_DISPATCHER_STATE;
  143. //
  144. // The RDBSS dispatching mechanism on any machine is an array of the dispatchers
  145. // associated with each processor. When a work queue item is queued a best effort
  146. // is made to contain the work emanating from a processor onto the same processor.
  147. // This ensures that processor affinities setup by the NT dispatcher are not
  148. // destroyed by the RDBSS dispatching mechanism as this could lead to excessive
  149. // sloshing. When the work needs to be moved there are two metrics that will be
  150. // useful in making the decision, teh amount of delay that will be experienced
  151. // by the work item in the current queue and the effort involved in moving the
  152. // work item to the other queue. It is very easy to quantify the former but very
  153. // difficult to quantify the later.
  154. //
  155. typedef struct _RX_DISPATCHER_ {
  156. LONG NumberOfProcessors;
  157. PEPROCESS OwnerProcess;
  158. PRX_WORK_QUEUE_DISPATCHER pWorkQueueDispatcher;
  159. RX_DISPATCHER_STATE State;
  160. LIST_ENTRY SpinUpRequests;
  161. KSPIN_LOCK SpinUpRequestsLock;
  162. KEVENT SpinUpRequestsEvent;
  163. KEVENT SpinUpRequestsTearDownEvent;
  164. } RX_DISPATCHER, *PRX_DISPATCHER;
  165. //
  166. // The function prototypes used for dispatching/posting work queue items
  167. //
  168. extern NTSTATUS
  169. NTAPI
  170. RxPostToWorkerThread (
  171. IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
  172. IN WORK_QUEUE_TYPE WorkQueueType,
  173. IN PRX_WORK_QUEUE_ITEM pWorkQueueItem,
  174. IN PRX_WORKERTHREAD_ROUTINE Routine,
  175. IN PVOID pContext
  176. );
  177. extern NTSTATUS
  178. NTAPI
  179. RxDispatchToWorkerThread(
  180. IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
  181. IN WORK_QUEUE_TYPE WorkQueueType,
  182. IN PRX_WORKERTHREAD_ROUTINE Routine,
  183. IN PVOID pContext);
  184. extern BOOLEAN //should only be called from raised IRQL
  185. NTAPI
  186. RxIsWorkItemQueued(
  187. IN OUT PWORK_QUEUE_ITEM WorkItem
  188. );
  189. //
  190. // The routines for initializing/tearing down the dispatching mechanism
  191. //
  192. extern NTSTATUS
  193. RxInitializeDispatcher();
  194. extern NTSTATUS
  195. RxTearDownDispatcher();
  196. extern NTSTATUS
  197. RxInitializeMRxDispatcher(
  198. IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject);
  199. extern NTSTATUS
  200. RxSpinDownMRxDispatcher(
  201. IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject);
  202. #endif _RXWORKQ_H_
  203.