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.

434 lines
11 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name :
  4. sched.hxx
  5. Abstract:
  6. This module defines the data structures for scheduler module.
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 16-Sept-1996
  9. George V. Reilly (GeorgeRe) May-1999
  10. Project:
  11. Internet Server DLL
  12. Revision History:
  13. --*/
  14. # ifndef _SCHED_HXX_
  15. # define _SCHED_HXX_
  16. /************************************************************
  17. * Include Headers
  18. ************************************************************/
  19. # include "acache.hxx"
  20. # include <lstentry.h>
  21. # include <process.h>
  22. # include <new.h>
  23. // little-endian signatures
  24. #define SIGNATURE_SCHED_ITEM ((DWORD) 'TICS')
  25. #define SIGNATURE_SCHED_ITEM_FREE ((DWORD) 'xICS')
  26. #define SIGNATURE_SCHEDDATA ((DWORD) 'DSCS')
  27. #define SIGNATURE_SCHEDDATA_FREE ((DWORD) 'xSCS')
  28. #define SIGNATURE_THREADDATA ((DWORD) 'DTCS')
  29. #define SIGNATURE_THREADDATA_FREE ((DWORD) 'xTCS')
  30. //
  31. // Global definitions
  32. //
  33. #define NUM_SCHEDULE_THREADS_PWS 1
  34. #define NUM_SCHEDULE_THREADS_NTS 2
  35. #define MAX_THREADS (MAXIMUM_WAIT_OBJECTS/4)
  36. // #define MAX_THREADS 4
  37. /************************************************************
  38. * Forward references
  39. ************************************************************/
  40. class SCHED_ITEM;
  41. class CSchedData;
  42. class CThreadData;
  43. unsigned
  44. __stdcall
  45. SchedulerWorkerThread(
  46. void* pvParam
  47. );
  48. BOOL SchedulerInitialize( VOID );
  49. VOID SchedulerTerminate( VOID );
  50. /************************************************************
  51. * Type Definitions
  52. ************************************************************/
  53. // the state of scheduled item
  54. enum SCHED_ITEM_STATE {
  55. SI_ERROR = 0,
  56. SI_IDLE,
  57. SI_ACTIVE,
  58. SI_ACTIVE_PERIODIC,
  59. SI_CALLBACK_PERIODIC,
  60. SI_TO_BE_DELETED,
  61. SI_MAX_ITEMS
  62. };
  63. // various scheduler operations
  64. enum SCHED_OPS {
  65. SI_OP_ADD = 0,
  66. SI_OP_ADD_PERIODIC,
  67. SI_OP_CALLBACK,
  68. SI_OP_DELETE,
  69. SI_OP_MAX
  70. };
  71. extern SCHED_ITEM_STATE rg_NextState[][SI_MAX_ITEMS];
  72. # include <pshpack8.h>
  73. //
  74. // SCHED_ITEM
  75. //
  76. //
  77. class SCHED_ITEM
  78. {
  79. public:
  80. SCHED_ITEM( PFN_SCHED_CALLBACK pfnCallback,
  81. PVOID pContext,
  82. DWORD msecTime)
  83. : _pfnCallback ( pfnCallback ),
  84. _pContext ( pContext ),
  85. _dwSerialNumber ( NewSerialNumber() ),
  86. _msecInterval ( msecTime ),
  87. _Signature ( SIGNATURE_SCHED_ITEM ),
  88. _siState ( SI_IDLE ),
  89. _dwCallbackThreadId ( 0 ),
  90. _hCallbackEvent ( NULL ),
  91. _lEventRefCount ( 0 )
  92. {
  93. CalcExpiresTime();
  94. }
  95. ~SCHED_ITEM( VOID )
  96. {
  97. DBG_ASSERT( _lEventRefCount == 0 );
  98. DBG_ASSERT( _hCallbackEvent == NULL );
  99. DBG_ASSERT( _ListEntry.Flink == NULL );
  100. _Signature = SIGNATURE_SCHED_ITEM_FREE;
  101. }
  102. BOOL CheckSignature( VOID ) const
  103. { return (_Signature == SIGNATURE_SCHED_ITEM); }
  104. VOID CalcExpiresTime(VOID)
  105. { _msecExpires = GetCurrentTimeInMilliseconds() + _msecInterval; }
  106. VOID ChangeTimeInterval( DWORD msecNewTime)
  107. { _msecInterval = msecNewTime; }
  108. enum {
  109. SERIAL_NUM_INITIAL_VALUE = 1,
  110. SERIAL_NUM_INCREMENT = 2, // ensures that it will never wrap to 0,
  111. // which is considered an invalid value
  112. };
  113. // There's an extremely small possibility that in a very long-running
  114. // service, the counter will wrap and regenerate a cookie that matches
  115. // the one belonging to a long-lived periodic work item. We don't care.
  116. static DWORD
  117. NewSerialNumber()
  118. {
  119. return InterlockedExchangeAdd(&sm_lSerialNumber, SERIAL_NUM_INCREMENT);
  120. }
  121. LONG AddEvent() {
  122. // AddEvent() is always called when the list is locked
  123. // no need for Interlocked operations
  124. if (!_hCallbackEvent)
  125. _hCallbackEvent = IIS_CREATE_EVENT(
  126. "SCHED_ITEM::_hCallbackEvent",
  127. this,
  128. TRUE,
  129. FALSE
  130. );
  131. if (_hCallbackEvent)
  132. _lEventRefCount++;
  133. return _lEventRefCount;
  134. }
  135. LONG WaitForEventAndRelease() {
  136. DBG_ASSERT(_hCallbackEvent);
  137. WaitForSingleObject(_hCallbackEvent, INFINITE);
  138. // could be called from multiple threads
  139. // need for Interlock operations
  140. LONG lRefs = InterlockedDecrement(&_lEventRefCount);
  141. DBG_ASSERT(lRefs >= 0);
  142. if (lRefs == 0)
  143. {
  144. CloseHandle(_hCallbackEvent);
  145. _hCallbackEvent = NULL;
  146. }
  147. return lRefs;
  148. }
  149. BOOL FInsideCallbackOnOtherThread() const {
  150. return (_dwCallbackThreadId != 0) &&
  151. (_dwCallbackThreadId != GetCurrentThreadId());
  152. }
  153. public:
  154. DWORD _Signature;
  155. DWORD _dwSerialNumber;
  156. CListEntry _ListEntry;
  157. __int64 _msecExpires;
  158. PFN_SCHED_CALLBACK _pfnCallback;
  159. PVOID _pContext;
  160. DWORD _msecInterval;
  161. SCHED_ITEM_STATE _siState;
  162. DWORD _dwCallbackThreadId;
  163. HANDLE _hCallbackEvent;
  164. LONG _lEventRefCount;
  165. // Used as identification cookie for removing items
  166. static LONG sm_lSerialNumber;
  167. }; // class SCHED_ITEM
  168. # include <poppack.h>
  169. //
  170. // CSchedData: manages all the scheduler work items
  171. //
  172. class CSchedData
  173. {
  174. public:
  175. CSchedData()
  176. : m_dwSignature(SIGNATURE_SCHEDDATA),
  177. m_nID(InterlockedIncrement(&sm_nID)),
  178. m_hevtNotify(NULL),
  179. m_cThreads(0),
  180. m_cRefs(1), // last reference Release'd in Terminate
  181. m_fShutdown(FALSE),
  182. m_pachSchedItems(NULL)
  183. {
  184. ALLOC_CACHE_CONFIGURATION acConfig = { 1, 30, sizeof(SCHED_ITEM)};
  185. m_pachSchedItems = new ALLOC_CACHE_HANDLER( "SchedItems", &acConfig);
  186. m_hevtNotify = IIS_CREATE_EVENT("CSchedData", this,
  187. FALSE, // auto-reset
  188. FALSE); // initially non-signalled
  189. sm_lstSchedulers.InsertTail(&m_leGlobalList);
  190. }
  191. ~CSchedData();
  192. bool
  193. IsValid() const
  194. {
  195. return (m_pachSchedItems != NULL && m_hevtNotify != NULL
  196. && CheckSignature());
  197. }
  198. bool
  199. CheckSignature() const
  200. {
  201. return (m_dwSignature == SIGNATURE_SCHEDDATA);
  202. }
  203. LONG
  204. Release()
  205. {
  206. LONG l = InterlockedDecrement(&m_cRefs);
  207. if (l == 0)
  208. delete this;
  209. return l;
  210. }
  211. SCHED_ITEM* const
  212. NewSchedItem(
  213. PFN_SCHED_CALLBACK pfnCallback,
  214. PVOID pContext,
  215. DWORD msecTime)
  216. {
  217. DBG_ASSERT(m_pachSchedItems != NULL);
  218. // placement new, using the allocator
  219. LPBYTE pbsi = static_cast<LPBYTE>(m_pachSchedItems->Alloc());
  220. if (pbsi == NULL)
  221. return NULL;
  222. InterlockedIncrement(&m_cRefs);
  223. SCHED_ITEM* psi = new (pbsi) SCHED_ITEM(pfnCallback, pContext,
  224. msecTime);
  225. return psi;
  226. }
  227. void
  228. DeleteSchedItem(
  229. SCHED_ITEM* const psi)
  230. {
  231. DBG_ASSERT(m_pachSchedItems != NULL);
  232. DBG_ASSERT(psi != NULL);
  233. psi->~SCHED_ITEM(); // placement destruction
  234. m_pachSchedItems->Free(psi);
  235. Release();
  236. }
  237. // The global scheduler object
  238. static CSchedData* const
  239. Scheduler()
  240. {
  241. DBG_ASSERT( sm_psd != NULL );
  242. DBG_ASSERT( sm_psd->m_dwSignature == SIGNATURE_SCHEDDATA );
  243. return sm_psd;
  244. }
  245. void
  246. LockItems()
  247. {
  248. m_lstItems.Lock();
  249. }
  250. void
  251. UnlockItems()
  252. {
  253. m_lstItems.Unlock();
  254. }
  255. VOID
  256. InsertIntoWorkItemList(SCHED_ITEM* psi);
  257. SCHED_ITEM*
  258. FindSchedulerItem(DWORD dwCookie);
  259. void
  260. Terminate();
  261. public:
  262. DWORD m_dwSignature;
  263. const LONG m_nID;
  264. CLockedDoubleList m_lstItems; // list of SCHED_ITEMs
  265. CLockedDoubleList m_lstThreads; // list of CThreadDatas
  266. CLockedDoubleList m_lstDeadThreads; // list of dead CThreadDatas
  267. LONG m_cThreads; // #worker threads
  268. LONG m_cRefs; // outstanding references
  269. HANDLE m_hevtNotify; // Notify worker threads
  270. BOOL m_fShutdown;
  271. ALLOC_CACHE_HANDLER* m_pachSchedItems; // SCHED_ITEM allocator
  272. CListEntry m_leGlobalList;
  273. static CSchedData* sm_psd;
  274. static CLockedDoubleList sm_lstSchedulers;
  275. static LONG sm_nID;
  276. };
  277. //
  278. // CThreadData: describes a worker thread
  279. //
  280. class CThreadData
  281. {
  282. public:
  283. CThreadData(
  284. CSchedData* psdOwner)
  285. : m_dwSignature(SIGNATURE_THREADDATA),
  286. m_nID(InterlockedIncrement(&sm_nID)),
  287. m_psdOwner(psdOwner),
  288. m_hevtShutdown(NULL),
  289. m_hThreadSelf(NULL)
  290. {
  291. unsigned idThread;
  292. m_hevtShutdown = IIS_CREATE_EVENT("CThreadData", this,
  293. FALSE, // auto-reset
  294. FALSE); // initially non-signalled
  295. if (m_hevtShutdown != NULL)
  296. m_hThreadSelf = (HANDLE) _beginthreadex( NULL,
  297. 0,
  298. SchedulerWorkerThread,
  299. this,
  300. CREATE_SUSPENDED,
  301. &idThread );
  302. psdOwner->m_lstThreads.InsertTail(&m_leThreads);
  303. InterlockedIncrement(&psdOwner->m_cThreads);
  304. InterlockedIncrement(&psdOwner->m_cRefs);
  305. }
  306. ~CThreadData()
  307. {
  308. CloseHandle(m_hThreadSelf);
  309. CloseHandle(m_hevtShutdown);
  310. m_psdOwner->m_lstDeadThreads.RemoveEntry(&m_leThreads);
  311. m_dwSignature = SIGNATURE_THREADDATA_FREE;
  312. }
  313. void
  314. Release()
  315. {
  316. InterlockedDecrement(&m_psdOwner->m_cThreads);
  317. m_psdOwner->m_lstThreads.RemoveEntry(&m_leThreads);
  318. m_psdOwner->m_lstDeadThreads.InsertTail(&m_leThreads);
  319. m_psdOwner->Release();
  320. }
  321. bool
  322. IsValid() const
  323. {
  324. return (m_hevtShutdown != NULL && m_hThreadSelf != NULL
  325. && CheckSignature());
  326. }
  327. bool
  328. CheckSignature() const
  329. {
  330. return (m_dwSignature == SIGNATURE_THREADDATA);
  331. }
  332. public:
  333. DWORD m_dwSignature;
  334. const LONG m_nID;
  335. CSchedData* m_psdOwner;
  336. HANDLE m_hevtShutdown;
  337. HANDLE m_hThreadSelf;
  338. CListEntry m_leThreads;
  339. static LONG sm_nID;
  340. };
  341. # endif // _SCHED_HXX_
  342. /************************ End of File ***********************/