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.

491 lines
13 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1992
  5. //
  6. // File: fastlock.cxx
  7. //
  8. // Contents: Implementation of CDfMutex methods for DocFiles
  9. //
  10. // History: 26-Jul-94 DonnaLi Created
  11. //
  12. //---------------------------------------------------------------
  13. #include <dfhead.cxx>
  14. #pragma hdrstop
  15. #include <df32.hxx>
  16. #include <secdes.hxx> // from com\inc
  17. #ifdef UNICODE
  18. #define GLOBAL_CS L"GlobalCsMutex"
  19. #else
  20. #define GLOBAL_CS "GlobalCsMutex"
  21. #endif
  22. //
  23. // This is the number of characters to skip over in the name
  24. // pased to CDfMutex::Init. The name consists of the string
  25. // OleDfRoot followed by the hex representation of a unique
  26. // number for each Docfile. We skip CHARS_TO_SKIP number of
  27. // characters in the name to produce a related and yet unique
  28. // name for the file mapping containing global state for the
  29. // critical section.
  30. //
  31. #define CHARS_TO_SKIP 3
  32. //+--------------------------------------------------------------
  33. //
  34. // Member: CDfMutex::Init, public
  35. //
  36. // Synopsis: This routine creates and initializes the global
  37. // critical section if it does not already exist.
  38. // It then attaches to the global critical section.
  39. //
  40. // Arguments: [lpName] - Supplies the critical section name
  41. //
  42. // Returns: Appropriate status code
  43. //
  44. // History: 26-Jul-94 DonnaLi Created
  45. //
  46. // Algorithm: Uses a mutex to serialize global critical section
  47. // creation and initialization
  48. // The name passed in is used to create or open the
  49. // semaphore embedded in the global critical section.
  50. // The name with the first CHARS_TO_SKIP characters
  51. // skipped is used to create or open the file mapping
  52. // containing global state of the critical section.
  53. // If a file mapping with that name already exists,
  54. // it is not reinitialized. The caller instead just
  55. // attaches to it.
  56. //
  57. //---------------------------------------------------------------
  58. SCODE
  59. CDfMutex::Init(
  60. TCHAR * lpName
  61. )
  62. {
  63. HANDLE hGlobalMutex;
  64. SCODE scResult = S_OK;
  65. DWORD dwResult;
  66. LPSECURITY_ATTRIBUTES lpsa = NULL;
  67. #if WIN32 == 100 || WIN32 > 200
  68. CGlobalSecurity gs;
  69. if (FAILED(scResult = gs.Init(TRUE))) return scResult;
  70. #else
  71. LPSECURITY_ATTRIBUTES gs = NULL;
  72. #endif
  73. #ifndef MULTIHEAP
  74. #if WIN32 == 100 || WIN32 > 200
  75. CWorldSecurityDescriptor wsd;
  76. SECURITY_ATTRIBUTES secattr;
  77. secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
  78. secattr.lpSecurityDescriptor = &wsd;
  79. secattr.bInheritHandle = FALSE;
  80. #endif
  81. //
  82. // Serialize all global critical section initialization
  83. //
  84. hGlobalMutex = CreateMutex(
  85. #if WIN32 == 100 || WIN32 > 200
  86. &secattr, // LPSECURITY_ATTRIBUTES lpsa
  87. #else
  88. gs,
  89. #endif
  90. TRUE, // BOOL fInitialOwner
  91. GLOBAL_CS // LPCTSTR lpszMutexName
  92. );
  93. //
  94. // If the mutex create/open failed, then bail
  95. //
  96. if ( !hGlobalMutex )
  97. {
  98. return LAST_SCODE;
  99. }
  100. if ( GetLastError() == ERROR_ALREADY_EXISTS )
  101. {
  102. //
  103. // Since the mutex already existed, the request for ownership has
  104. // no effect.
  105. //
  106. // wait for the mutex
  107. //
  108. if ( WaitForSingleObject (hGlobalMutex, INFINITE) == WAIT_FAILED )
  109. {
  110. scResult = LAST_SCODE;
  111. CloseHandle (hGlobalMutex);
  112. return scResult;
  113. }
  114. }
  115. //
  116. // We now own the global critical section creation mutex. Create/Open the
  117. // named semaphore.
  118. //
  119. #endif
  120. _hLockSemaphore = CreateSemaphore (
  121. gs, // LPSECURITY_ATTRIBUTES lpsa
  122. 0, // LONG cSemInitial
  123. MAXLONG-1, // LONG cSemMax
  124. lpName // LPCTSTR lpszSemName
  125. );
  126. //
  127. // If the semaphore create/open failed, then bail
  128. //
  129. if ( !_hLockSemaphore )
  130. {
  131. scResult = LAST_SCODE;
  132. }
  133. else
  134. {
  135. //
  136. // Create/open a shared file mapping object
  137. // If we created it, we need to initialize the global structure.
  138. // Otherwise just point to it.
  139. // The global critical section creation mutex allows us to do
  140. // this safely.
  141. //
  142. _hSharedMapping = CreateFileMappingT (
  143. INVALID_HANDLE_VALUE, // HANDLE hFile
  144. gs, // LPSECURITY_ATTRIBUTES lpsa
  145. PAGE_READWRITE, // DWORD fdwProtect
  146. 0, // DWORD dwMaximumSizeHigh
  147. 1024, // DWORD dwMaximumSizeLow
  148. lpName+CHARS_TO_SKIP// LPCTSTR lpszMapName
  149. );
  150. if ( !_hSharedMapping )
  151. {
  152. scResult = LAST_SCODE;
  153. CloseHandle (_hLockSemaphore);
  154. _hLockSemaphore = (HANDLE)NULL;
  155. }
  156. else
  157. {
  158. dwResult = GetLastError();
  159. _pGlobalPortion = (PGLOBAL_SHARED_CRITICAL_SECTION)
  160. MapViewOfFile (
  161. _hSharedMapping, // HANDLE hMapObject
  162. FILE_MAP_WRITE, // DWORD fdwAccess
  163. 0, // DWORD dwOffsetHigh
  164. 0, // DWORD dwOffsetLow
  165. 0 // DWORD cbMap
  166. );
  167. if (!_pGlobalPortion)
  168. {
  169. scResult = LAST_SCODE;
  170. CloseHandle (_hLockSemaphore);
  171. _hLockSemaphore = (HANDLE)NULL;
  172. CloseHandle (_hSharedMapping);
  173. _hSharedMapping = (HANDLE)NULL;
  174. }
  175. else if (dwResult != ERROR_ALREADY_EXISTS )
  176. {
  177. //
  178. // We created the file mapping, so initialize the
  179. // global portion.
  180. //
  181. _pGlobalPortion->LockCount = -1;
  182. #ifdef SUPPORT_RECURSIVE_LOCK
  183. _pGlobalPortion->RecursionCount = 0;
  184. _pGlobalPortion->OwningThread = 0;
  185. #else
  186. #if DBG == 1
  187. _pGlobalPortion->OwningThread = 0;
  188. #endif
  189. #endif
  190. _pGlobalPortion->Reserved = 0;
  191. }
  192. }
  193. }
  194. #ifndef MULTIHEAP
  195. ReleaseMutex (hGlobalMutex);
  196. CloseHandle (hGlobalMutex);
  197. #endif
  198. return scResult;
  199. }
  200. //+--------------------------------------------------------------
  201. //
  202. // Member: CDfMutex::~CDfMutex, public
  203. //
  204. // Synopsis: This routine detaches from an existing global
  205. // critical section.
  206. //
  207. // History: 26-Jul-94 DonnaLi Created
  208. //
  209. // Algorithm: Create or get the entry from the multistream
  210. //
  211. //---------------------------------------------------------------
  212. CDfMutex::~CDfMutex(
  213. void
  214. )
  215. {
  216. //If we're holding the mutex, we need to get rid of it here.
  217. #ifdef SUPPORT_RECURSIVE_LOCK
  218. if ((_pGlobalPortion) &&
  219. (_pGlobalPortion->OwningThread == GetCurrentThreadId()))
  220. {
  221. #else
  222. if (_pGlobalPortion)
  223. {
  224. #if DBG == 1
  225. olAssert (_pGlobalPortion->OwningThread == 0 || _pGlobalPortion->OwningThread == GetCurrentThreadId());
  226. #endif
  227. #endif
  228. Release();
  229. }
  230. if ( _pGlobalPortion )
  231. {
  232. UnmapViewOfFile (_pGlobalPortion);
  233. }
  234. if ( _hLockSemaphore )
  235. {
  236. CloseHandle (_hLockSemaphore);
  237. }
  238. if ( _hSharedMapping )
  239. {
  240. CloseHandle (_hSharedMapping);
  241. }
  242. }
  243. //+--------------------------------------------------------------
  244. //
  245. // Member: CDfMutex::Take, public
  246. //
  247. // Synopsis: This routine enters the global critical section.
  248. //
  249. // Arguments: [dwTimeout] - Supplies the timeout
  250. //
  251. // Returns: Appropriate status code
  252. //
  253. // History: 26-Jul-94 DonnaLi Created
  254. //
  255. // Algorithm: Enters the critical section if nobody owns it or
  256. // if the current thread already owns it.
  257. // Waits for the critical section otherwise.
  258. //
  259. //---------------------------------------------------------------
  260. SCODE
  261. CDfMutex::Take (
  262. DWORD dwTimeout
  263. )
  264. {
  265. olAssert (_pGlobalPortion->LockCount >= -1);
  266. #ifdef SUPPORT_RECURSIVE_LOCK
  267. olAssert (_pGlobalPortion->RecursionCount >= 0);
  268. DWORD ThreadId;
  269. ThreadId = GetCurrentThreadId();
  270. #endif
  271. //
  272. // Increment the lock variable. On the transition to 0, the caller
  273. // becomes the absolute owner of the lock. Otherwise, the caller is
  274. // either recursing, or is going to have to wait
  275. //
  276. if ( !InterlockedIncrement (&_pGlobalPortion->LockCount) )
  277. {
  278. //
  279. // lock count went from -1 to 0, so the caller
  280. // is the owner of the lock
  281. //
  282. #ifdef SUPPORT_RECURSIVE_LOCK
  283. _pGlobalPortion->RecursionCount = 1;
  284. _pGlobalPortion->OwningThread = ThreadId;
  285. #else
  286. #if DBG == 1
  287. _pGlobalPortion->OwningThread = GetCurrentThreadId();
  288. #endif
  289. #endif
  290. return S_OK;
  291. }
  292. else
  293. {
  294. #ifdef SUPPORT_RECURSIVE_LOCK
  295. //
  296. // If the caller is recursing, then increment the recursion count
  297. //
  298. if ( _pGlobalPortion->OwningThread == ThreadId )
  299. {
  300. _pGlobalPortion->RecursionCount++;
  301. return S_OK;
  302. }
  303. else
  304. {
  305. #else
  306. #if DBG == 1
  307. olAssert (_pGlobalPortion->OwningThread != GetCurrentThreadId());
  308. #endif
  309. #endif
  310. switch (WaitForSingleObject(
  311. _hLockSemaphore,
  312. dwTimeout
  313. ))
  314. {
  315. case WAIT_OBJECT_0:
  316. case WAIT_ABANDONED:
  317. #ifdef SUPPORT_RECURSIVE_LOCK
  318. _pGlobalPortion->RecursionCount = 1;
  319. _pGlobalPortion->OwningThread = ThreadId;
  320. #else
  321. #if DBG == 1
  322. _pGlobalPortion->OwningThread = GetCurrentThreadId();
  323. #endif
  324. #endif
  325. return S_OK;
  326. case WAIT_TIMEOUT:
  327. return STG_E_INUSE;
  328. default:
  329. return LAST_SCODE;
  330. }
  331. #ifdef SUPPORT_RECURSIVE_LOCK
  332. }
  333. #endif
  334. }
  335. }
  336. //+--------------------------------------------------------------
  337. //
  338. // Member: CDfMutex::Release, public
  339. //
  340. // Synopsis: This routine leaves the global critical section
  341. //
  342. // History: 26-Jul-94 DonnaLi Created
  343. //
  344. // Algorithm: Leaves the critical section if this is the owning
  345. // thread.
  346. //
  347. //---------------------------------------------------------------
  348. VOID
  349. CDfMutex::Release(
  350. void
  351. )
  352. {
  353. #ifdef SUPPORT_RECURSIVE_LOCK
  354. if ( _pGlobalPortion->OwningThread != GetCurrentThreadId() ) return;
  355. #else
  356. #if DBG == 1
  357. olAssert (_pGlobalPortion->OwningThread == 0 || _pGlobalPortion->OwningThread == GetCurrentThreadId());
  358. #endif
  359. #endif
  360. olAssert (_pGlobalPortion->LockCount >= -1);
  361. #ifdef SUPPORT_RECURSIVE_LOCK
  362. olAssert (_pGlobalPortion->RecursionCount >= 0);
  363. //
  364. // decrement the recursion count. If it is still non-zero, then
  365. // we are still the owner so don't do anything other than dec the lock
  366. // count
  367. //
  368. if ( --_pGlobalPortion->RecursionCount )
  369. {
  370. InterlockedDecrement(&_pGlobalPortion->LockCount);
  371. }
  372. else
  373. {
  374. //
  375. // We are really leaving, so give up ownership and decrement the
  376. // lock count
  377. //
  378. _pGlobalPortion->OwningThread = 0;
  379. #else
  380. #if DBG == 1
  381. _pGlobalPortion->OwningThread = 0;
  382. #endif
  383. #endif
  384. //
  385. // Check to see if there are other waiters. If so, then wake up a waiter
  386. //
  387. if ( InterlockedDecrement(&_pGlobalPortion->LockCount) >= 0 )
  388. {
  389. ReleaseSemaphore(
  390. _hLockSemaphore, // HANDLE hSemaphore
  391. 1, // LONG cReleaseCount
  392. NULL // LPLONG lplPreviousCount
  393. );
  394. }
  395. #ifdef SUPPORT_RECURSIVE_LOCK
  396. }
  397. #endif
  398. }
  399. //+--------------------------------------------------------------
  400. //
  401. // Member: CDfMutex::IsHandleValid, public
  402. //
  403. // Synopsis: This routine checks the mutex handle for validity
  404. //
  405. // History: 09-May-2001 HenryLee created
  406. //
  407. //---------------------------------------------------------------
  408. BOOL CDfMutex::IsHandleValid (TCHAR *ptcsName)
  409. {
  410. #if WIN32 == 100
  411. BOOL fValid = FALSE;
  412. NTSTATUS nts = STATUS_SUCCESS;
  413. WCHAR wcsBuffer[MAX_PATH] = L"";
  414. OBJECT_NAME_INFORMATION *poni = (OBJECT_NAME_INFORMATION *) wcsBuffer;
  415. nts = NtQueryObject (_hLockSemaphore, ObjectNameInformation, poni,
  416. sizeof(wcsBuffer), NULL);
  417. if (NT_SUCCESS(nts))
  418. {
  419. if (poni->Name.Length < sizeof(wcsBuffer) - sizeof (*poni))
  420. {
  421. poni->Name.Buffer[poni->Name.Length / sizeof(WCHAR)] = L'\0';
  422. if (!lstrcmp (poni->Name.Buffer, ptcsName))
  423. fValid = TRUE;
  424. }
  425. }
  426. #else
  427. BOOL fValid = TRUE;
  428. #endif
  429. return fValid;
  430. }