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.

796 lines
16 KiB

  1. /*++
  2. This header file exists to provide templates which support
  3. mutlithreaded software servers.
  4. --*/
  5. #include <windows.h>
  6. #include "lockq.h"
  7. #include "smartptr.h"
  8. #ifndef _MTLIB_H_
  9. #define _MTLIB_H_
  10. class CStateStackInterface : public CRefCount {
  11. //
  12. // This class defines a pure virtual interface used
  13. // to allocate memory for CCallState objects.
  14. //
  15. public :
  16. enum STACK_CONSTANTS {
  17. MAX_STACK_RESERVE = 4096
  18. } ;
  19. //
  20. // Initialize the stack !
  21. //
  22. virtual BOOL
  23. Init( DWORD cbReserve ) = 0 ;
  24. //
  25. // Allocate bytes for the object
  26. //
  27. virtual LPVOID
  28. Allocate( DWORD cb ) = 0 ;
  29. //
  30. // Release the bytes associated with the object
  31. //
  32. virtual BOOL
  33. Release( LPVOID lpvState ) = 0 ;
  34. //
  35. // Provide virtual do nothing destructor.
  36. //
  37. virtual
  38. ~CStateStackInterface() {
  39. }
  40. } ;
  41. typedef CRefPtr< CStateStackInterface > STACKPTR ;
  42. //
  43. // This is just a definition of this symbol which
  44. // is used to implement these stack objects but otherwise
  45. // is hidden from clients !
  46. //
  47. class CStateStackBase ;
  48. //
  49. // A Smart Pointer TYPE for CStateStackBase objects !
  50. //
  51. typedef CRefPtr< CStateStackBase > STACKBPTR ;
  52. class CStateStack : public CStateStackInterface {
  53. /*++
  54. This is the object that users should instantiate when
  55. they are ready to be allocating memory from these stack objects !
  56. --*/
  57. private :
  58. //
  59. // Signature for recognizing these stacks in memory
  60. //
  61. DWORD m_dwSignature ;
  62. //
  63. // Points to the object we delegate all operations to.
  64. // This is really the top of a stack of such objects !
  65. //
  66. STACKBPTR m_pImp ;
  67. //
  68. // Push a CStateStackBase derived object onto our stack
  69. // that can handle the next allocation !
  70. //
  71. BOOL
  72. NewStack( DWORD cbReserve ) ;
  73. //
  74. // Copy construction not allowed !
  75. //
  76. CStateStack( CStateStack& ) ;
  77. public :
  78. //
  79. // We have do nothing Constructor and Destructors - however
  80. // we declare and define them so that the STACKBPTR type
  81. // is only referenced in the mtserver library.
  82. //
  83. CStateStack() ;
  84. ~CStateStack() ;
  85. //
  86. // Prepare the initial stack
  87. //
  88. BOOL
  89. Init( DWORD cbReserve ) ;
  90. //
  91. // Allocate bytes for the object
  92. //
  93. LPVOID
  94. Allocate( DWORD cb ) ;
  95. //
  96. // Release the bytes associated with the object
  97. //
  98. BOOL
  99. Release( LPVOID lpvState ) ;
  100. } ;
  101. class CCall : public CQElement {
  102. //
  103. // This class defines a base class for Call Objects created with
  104. // the TMFnCallAndCompletion objects.
  105. // This base class will provide for memory management of Call Objects.
  106. //
  107. private :
  108. //
  109. // Do Nothing Constructor is private - everybody has
  110. // to provide args to constructor !
  111. //
  112. CCall() ;
  113. //
  114. // Signature for these things !
  115. //
  116. DWORD m_dwSignature ;
  117. //
  118. // This is a reference to the allocator that should be used
  119. // to create all Child CCallState objects of this one !
  120. //
  121. CStateStackInterface& m_Allocator ;
  122. protected :
  123. //
  124. // The only method we provide for retrieving the allocator !
  125. //
  126. CStateStackInterface&
  127. Allocator() {
  128. return m_Allocator ;
  129. }
  130. public:
  131. //
  132. // The only constructor we provide REQUIRES an allocator,
  133. // we don't take a pointer as that would let you pass a NULL!
  134. //
  135. CCall( CStateStackInterface& allocator ) :
  136. m_dwSignature( DWORD('laCC') ),
  137. m_Allocator( allocator ) {
  138. #ifdef DEBUG
  139. LPVOID lpv = this ;
  140. _ASSERT( *((CStateStackInterface**)lpv) = &allocator ) ;
  141. #endif
  142. }
  143. //
  144. // Allocate a CCallState object !
  145. //
  146. void*
  147. operator new( size_t size, CStateStackInterface& stack ) {
  148. size += sizeof( CStateStackInterface* ) ;
  149. LPVOID lpv = stack.Allocate( size ) ;
  150. if( lpv != 0 ) {
  151. *((CStateStackInterface**)lpv) = &stack ;
  152. lpv = (LPVOID)(((CStateStackInterface**)lpv)+1) ;
  153. }
  154. return lpv ;
  155. }
  156. //
  157. // Users are required to not use this version of operator new! -
  158. // The language doesn't let us hide it - so it will DebugBreak()
  159. // at runtime if necessary !
  160. //
  161. void*
  162. operator new( size_t size ) {
  163. DebugBreak() ;
  164. return 0 ;
  165. }
  166. //
  167. // Free a CCallState derived object !
  168. //
  169. void
  170. operator delete( void* lpv ) {
  171. if( lpv != 0 ) {
  172. CStateStackInterface* pStack = ((CStateStackInterface**)lpv)[-1] ;
  173. lpv = (LPVOID)(((CStateStackInterface**)lpv)-1) ;
  174. pStack->Release( lpv ) ;
  175. }
  176. }
  177. } ;
  178. template< class RESULT >
  179. class TCompletion {
  180. //
  181. // This template defines an interface for Completion
  182. // objects which have a Virtual Function taking a
  183. // particular kind of result.
  184. //
  185. public :
  186. //
  187. // One pure virtual function which gets the results !
  188. //
  189. virtual void
  190. Complete( RESULT& result ) = 0 ;
  191. //
  192. // This function is called when the request is unable to be
  193. // completed for whatever reason (most likely, we're in a
  194. // shutdown state.)
  195. //
  196. virtual void
  197. ErrorComplete( DWORD dwReserved ) = 0 ;
  198. void*
  199. operator new( size_t size, CStateStackInterface& stack ) {
  200. size += sizeof( CStateStackInterface* ) ;
  201. LPVOID lpv = stack.Allocate( size ) ;
  202. if( lpv != 0 ) {
  203. *((CStateStackInterface**)lpv) = &stack ;
  204. lpv = (LPVOID)(((CStateStackInterface**)lpv)+1) ;
  205. }
  206. return lpv ;
  207. }
  208. //
  209. // Free a CCallState derived object !
  210. //
  211. void
  212. operator delete( void* lpv ) {
  213. if( lpv != 0 ) {
  214. CStateStackInterface* pStack = ((CStateStackInterface**)lpv)[-1] ;
  215. lpv = (LPVOID)(((CStateStackInterface**)lpv)-1) ;
  216. pStack->Release( lpv ) ;
  217. }
  218. }
  219. } ;
  220. template< class SERVER >
  221. class ICall : public CCall {
  222. //
  223. // This template defines the interface to CCallState objects
  224. // that are to operate against SERVER's of type 'SERVER'.
  225. //
  226. // We define 2 virtual functions - ExecuteCall and CompleteCall.
  227. // This template only exists to provide a base class definition
  228. // for objects which are passed into the TMtService< SERVER >
  229. // QueueRequest function.
  230. //
  231. // Derived Objects must manage their own destruction in a
  232. // fashion which guarantees they are destroyed BEFORE the
  233. // caller is notified of the completion. This is because CCallState
  234. // objects are created with a memory manager that is managed
  235. // by the caller, which won't be in any other threads untill the
  236. // completion is called.
  237. //
  238. protected:
  239. //
  240. // Only derived classes are allowed to construct these things !
  241. //
  242. ICall( CStateStackInterface& allocator ) :
  243. CCall( allocator ) {}
  244. public :
  245. typedef CStateStackInterface INITIALIZER ;
  246. //
  247. // A return value of TRUE means that the CCallState object
  248. // should be kept for a later call to CompleteCall
  249. //
  250. virtual BOOL
  251. ExecuteCall( SERVER& server ) = 0 ;
  252. //
  253. // This function is only called if ExecuteCall() return TRUE -
  254. // indicating that all the thread safe aspects of the Execution
  255. // had been completed, and that the CCallState could be called
  256. // again to notify the original caller of the results.
  257. //
  258. virtual void
  259. CompleteCall( SERVER& server ) = 0 ;
  260. //
  261. // This function is called when we won't be given a change to
  262. // execute our request. This occurs during shutdown for instance.
  263. // dwReserved is for future use (i.e. indicate error conditions.)
  264. //
  265. virtual void
  266. CancelCall( DWORD dwReserved ) = 0 ;
  267. } ;
  268. template< class SERVER,
  269. class RESULT,
  270. class ARGUMENT,
  271. class BASECLASS = ICall<SERVER>
  272. >
  273. class TMFnCall : public BASECLASS {
  274. //
  275. // This defines a call state object which can be passed to a TMtService<SERVER,BASECLASS>
  276. // The call object holds onto the arguments to which should be passed to the
  277. // member function of the server.
  278. //
  279. // This object will call the member function and imediately complete the operation !
  280. //
  281. public :
  282. //
  283. // Define the signature of the member function we will call.
  284. //
  285. // The member function must not have any return value.
  286. //
  287. typedef void (SERVER::*FUNC_SIGNATURE)( ARGUMENT, RESULT& ) ;
  288. //
  289. // Define the signature of the object which will handle the completion
  290. // of the Async Call.
  291. //
  292. typedef TCompletion<RESULT> COMPLETION_OBJECT ;
  293. private :
  294. //
  295. // Pointer to a member function of the server
  296. //
  297. FUNC_SIGNATURE m_pfn ;
  298. //
  299. // An argument for the member function of the server.
  300. //
  301. ARGUMENT m_Arg ;
  302. //
  303. // The object we will notify when the call completes !
  304. //
  305. COMPLETION_OBJECT* m_pCompletion ;
  306. public :
  307. //
  308. // Construct a TMFnCallAndCompletion object.
  309. // We require a pointer to a function and a pointer
  310. // to a Completion object.
  311. //
  312. //
  313. TMFnCall(
  314. BASECLASS::INITIALIZER& baseInit,
  315. FUNC_SIGNATURE pfn,
  316. ARGUMENT arg,
  317. COMPLETION_OBJECT* pCompletion
  318. ) :
  319. BASECLASS( baseInit ),
  320. m_pfn( pfn ),
  321. m_Arg( arg ),
  322. m_pCompletion( pCompletion ) {
  323. }
  324. TMFnCall(
  325. FUNC_SIGNATURE pfn,
  326. ARGUMENT arg,
  327. COMPLETION_OBJECT* pCompletion
  328. ) :
  329. m_pfn( pfn ),
  330. m_Arg( arg ),
  331. m_pCompletion( pCompletion ) {
  332. }
  333. //
  334. // Execute the call !
  335. //
  336. //
  337. BOOL
  338. ExecuteCall( SERVER& server ) {
  339. RESULT results ;
  340. (server.*m_pfn)( m_Arg, results ) ;
  341. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  342. delete this ;
  343. if( pCompletion )
  344. pCompletion->Complete( results ) ;
  345. return FALSE ;
  346. }
  347. //
  348. // Do nothing - no delayed completions
  349. //
  350. virtual void
  351. CompleteCall( SERVER& server ) {
  352. }
  353. //
  354. // Notify the caller that the call will not be executed.
  355. //
  356. void
  357. CancelCall( DWORD dwReserved ) {
  358. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  359. delete this ;
  360. if( pCompletion )
  361. pCompletion->ErrorComplete() ;
  362. }
  363. } ;
  364. template< class SERVER,
  365. class RESULT,
  366. class ARGUMENT,
  367. class BASECLASS = ICall<SERVER>
  368. >
  369. class TMFnDelay : public BASECLASS {
  370. //
  371. // This defines a call state object which can be passed to a TMtService<SERVER>
  372. // The call object holds onto the arguments to which should be passed to the
  373. // member function of the server.
  374. //
  375. // The main property of this object is that it can postpone calling the
  376. // callers completion object until the worker thread is out of its critical
  377. // region !
  378. //
  379. public :
  380. //
  381. // Define the signature of the member function we will call.
  382. // NOTE : the function takes references to the values !!
  383. //
  384. typedef BOOL (SERVER::*FUNC_SIGNATURE)( ARGUMENT&, RESULT& ) ;
  385. //
  386. // Define the signature of the object which will handle the completion
  387. // of the Async Call.
  388. //
  389. typedef TCompletion<RESULT> COMPLETION_OBJECT ;
  390. private :
  391. //
  392. // Pointer to a member function of the server
  393. //
  394. FUNC_SIGNATURE m_pfn ;
  395. //
  396. // An argument for the member function of the server.
  397. //
  398. ARGUMENT m_Arg ;
  399. //
  400. // Temporary to hold the results of the function
  401. //
  402. RESULT m_Result ;
  403. //
  404. // Pointer to the object which gets notified of the async completion.
  405. //
  406. COMPLETION_OBJECT* m_pCompletion ;
  407. public :
  408. TMFnDelay(
  409. BASECLASS::INITIALIZER& baseinit,
  410. FUNC_SIGNATURE pfn,
  411. ARGUMENT arg,
  412. COMPLETION_OBJECT* pCompletion
  413. ) :
  414. BASECLASS( baseinit ),
  415. m_pfn( pfn ),
  416. m_Arg( arg ),
  417. m_pCompletion( pCompletion ) {
  418. }
  419. TMFnDelay(
  420. FUNC_SIGNATURE pfn,
  421. ARGUMENT arg,
  422. COMPLETION_OBJECT* pCompletion
  423. ) :
  424. m_pfn( pfn ),
  425. m_Arg( arg ),
  426. m_pCompletion( pCompletion ) {
  427. }
  428. //
  429. // Execute the call !
  430. //
  431. // If we return TRUE, then this object will be
  432. // put into a queue for a later call to CompletCall()
  433. //
  434. //
  435. BOOL
  436. ExecuteCall( SERVER& server ) {
  437. if( (server.*m_pfn)( m_Arg, m_Result ) ) {
  438. return TRUE ;
  439. }
  440. RESULT results = m_Result ;
  441. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  442. delete this ;
  443. if( pCompletion )
  444. pCompletion->Complete( results ) ;
  445. return FALSE ;
  446. }
  447. //
  448. // Destroy ourselves before invoking the completion object !
  449. //
  450. virtual void
  451. CompleteCall( SERVER& server ) {
  452. RESULT results = m_Result ;
  453. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  454. delete this ;
  455. if( pCompletion )
  456. pCompletion->Complete( results ) ;
  457. }
  458. //
  459. // Notify the caller that the call will not be executed.
  460. //
  461. void
  462. CancelCall( DWORD dwReserved ) {
  463. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  464. delete this ;
  465. if( pCompletion )
  466. pCompletion->ErrorComplete( dwReserved ) ;
  467. }
  468. } ;
  469. template< class SERVER,
  470. class RESULT,
  471. class BASECLASS = ICall< SERVER >
  472. >
  473. class TMFnNoArgDelay : public BASECLASS {
  474. //
  475. // This defines a call state object which can be passed to a TMtService<SERVER>
  476. // The call object holds onto the arguments to which should be passed to the
  477. // member function of the server.
  478. //
  479. public :
  480. //
  481. // Define the signature of the member function we will call.
  482. // NOTE : the function takes references to the values !!
  483. //
  484. typedef BOOL (SERVER::*FUNC_SIGNATURE)( RESULT& ) ;
  485. //
  486. // Define the signature of the object which will handle the completion
  487. // of the Async Call.
  488. //
  489. typedef TCompletion<RESULT> COMPLETION_OBJECT ;
  490. private :
  491. //
  492. // Pointer to a member function of the server
  493. //
  494. FUNC_SIGNATURE m_pfn ;
  495. //
  496. // Temporary to hold the results of the function
  497. //
  498. RESULT m_Result ;
  499. //
  500. // Pointer to the object which gets notified of the async completion.
  501. //
  502. COMPLETION_OBJECT* m_pCompletion ;
  503. public :
  504. TMFnNoArgDelay(
  505. BASECLASS::INITIALIZER& baseInit,
  506. FUNC_SIGNATURE pfn,
  507. COMPLETION_OBJECT* pCompletion
  508. ) :
  509. BASECLASS( baseInit ),
  510. m_pfn( pfn ),
  511. m_pCompletion( pCompletion ) {
  512. }
  513. TMFnNoArgDelay(
  514. FUNC_SIGNATURE pfn,
  515. COMPLETION_OBJECT* pCompletion
  516. ) :
  517. BASECLASS( baseInit ),
  518. m_pfn( pfn ),
  519. m_pCompletion( pCompletion ) {
  520. }
  521. //
  522. // Execute the call !
  523. //
  524. // If we return TRUE, then this object will be
  525. // put into a queue for a later call to CompletCall()
  526. //
  527. //
  528. BOOL
  529. ExecuteCall( SERVER& server ) {
  530. if( (server.*m_pfn)( m_Result ) ) {
  531. return TRUE ;
  532. }
  533. RESULT results = m_Result ;
  534. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  535. delete this ;
  536. if( pCompletion )
  537. pCompletion->Complete( results ) ;
  538. return FALSE ;
  539. }
  540. //
  541. // Destroy ourselves before invoking the completion object !
  542. //
  543. virtual void
  544. CompleteCall( SERVER& server ) {
  545. RESULT results = m_Result ;
  546. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  547. delete this ;
  548. if( pCompletion )
  549. pCompletion->Complete( results ) ;
  550. }
  551. //
  552. // Notify the caller that the call will not be executed.
  553. //
  554. void
  555. CancelCall( DWORD dwReserved ) {
  556. COMPLETION_OBJECT* pCompletion = m_pCompletion ;
  557. delete this ;
  558. if( pCompletion )
  559. pCompletion->ErrorComplete( dwReserved ) ;
  560. }
  561. } ;
  562. template< class SERVER,
  563. class CALLBASE = ICall< SERVER > >
  564. class TMtService {
  565. //
  566. // This template defines the class that manages the
  567. // multithreading issues for objects of type 'SERVER'
  568. //
  569. public :
  570. typedef CALLBASE CALL_OBJECT ;
  571. private :
  572. //
  573. // Queue of requests from different clients.
  574. //
  575. TLockQueue< CALL_OBJECT > m_PendingCalls ;
  576. ///
  577. // Is somebody trying to shut us down ?
  578. //
  579. BOOL m_fShutdown ;
  580. //
  581. // The Server object that will be provided to the call objects !
  582. //
  583. SERVER& m_Server ;
  584. //
  585. // Can't construct us without providing all of our parameters !
  586. //
  587. TMtService() ;
  588. public :
  589. //
  590. // Initialize us !
  591. //
  592. TMtService( SERVER& server ) :
  593. m_Server( server ),
  594. m_fShutdown( FALSE ) {
  595. }
  596. //
  597. // Queue a request to be executed !
  598. //
  599. void
  600. QueueRequest( CALL_OBJECT* pcallobj ) {
  601. //
  602. // Use this to keep a stack of Calls that we did not
  603. // immediately complete !
  604. //
  605. CALL_OBJECT* pDelayedCompletion = 0 ;
  606. //
  607. // If Append returns FALSE then another thread will service the request !
  608. //
  609. if( m_PendingCalls.Append( pcallobj ) ) {
  610. //
  611. // We're the first thread in - still may be no work to do though -
  612. // Try to get a CALL_OBJECT to service.
  613. //
  614. while( (pcallobj = m_PendingCalls.RemoveAndRelease()) != 0 ) {
  615. //
  616. // If we're shutting down then we don't execute requests -
  617. // just fail them.
  618. //
  619. if( m_fShutdown ) {
  620. pcallobj->CancelCall( 0 ) ;
  621. } else {
  622. //
  623. // If Execute Call returns
  624. //
  625. if( pcallobj->ExecuteCall( m_Server ) ) {
  626. pcallobj->m_pNext = pDelayedCompletion ;
  627. pDelayedCompletion = pcallobj ;
  628. }
  629. }
  630. }
  631. //
  632. // At this point, other threads may be executing in the service
  633. // and we are only giving those CALL_OBJECTS who can deal with
  634. // it a chance to notify their invokers.
  635. //
  636. // NOTE : pDelayedCompletion is basically a stack - get better
  637. // value out of the CPU Cache that way.
  638. //
  639. while( pDelayedCompletion != 0 ) {
  640. pcallobj = (CALL_OBJECT*)pDelayedCompletion->m_pNext ;
  641. pDelayedCompletion->m_pNext = 0 ;
  642. pDelayedCompletion->CompleteCall( m_Server ) ;
  643. pDelayedCompletion = pcallobj ;
  644. }
  645. }
  646. }
  647. } ;
  648. #endif // _MTLIB_H_