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.

402 lines
9.7 KiB

  1. #include <stdio.h>
  2. #include <windows.h>
  3. //
  4. // Global Critical Sections have two components. One piece is shared between all
  5. // applications using the global lock. This portion will typically reside in some
  6. // sort of shared memory
  7. //
  8. // The second piece is per-process. This contains a per-process handle to the shared
  9. // critical section lock semaphore. The semaphore is itself shared, but each process
  10. // may have a different handle value to the semaphore.
  11. //
  12. // Global critical sections are attached to by name. The application wishing to
  13. // attach must know the name of the critical section (actually the name of the shared
  14. // lock semaphore, and must know the address of the global portion of the critical
  15. // section
  16. //
  17. typedef struct _GLOBAL_SHARED_CRITICAL_SECTION {
  18. LONG LockCount;
  19. LONG RecursionCount;
  20. DWORD OwningThread;
  21. DWORD Reserved;
  22. } GLOBAL_SHARED_CRITICAL_SECTION, *PGLOBAL_SHARED_CRITICAL_SECTION;
  23. typedef struct _GLOBAL_LOCAL_CRITICAL_SECTION {
  24. PGLOBAL_SHARED_CRITICAL_SECTION GlobalPortion;
  25. HANDLE LockSemaphore;
  26. DWORD Reserved1;
  27. DWORD Reserved2;
  28. } GLOBAL_LOCAL_CRITICAL_SECTION, *PGLOBAL_LOCAL_CRITICAL_SECTION;
  29. BOOL
  30. WINAPI
  31. AttachToGlobalCriticalSection(
  32. PGLOBAL_LOCAL_CRITICAL_SECTION lpLocalPortion,
  33. PGLOBAL_SHARED_CRITICAL_SECTION lpGlobalPortion,
  34. LPCSTR lpName
  35. )
  36. /*++
  37. Routine Description:
  38. This routine attaches to an existing global critical section, or creates and
  39. initializes the global critical section if it does not already exist.
  40. Arguments:
  41. lpLocalPortion - Supplies the address of a per-app local portion of the global
  42. critical section.
  43. lpGlobalPortion - Supplies the address of the global shared portion of the
  44. critical section. If the critical section is new, the caller will initialize it.
  45. lpName - Supplies the name of the critical section. If an existing
  46. critical section with this name already exists, then it is not
  47. reinitialized. In this case, the caller simply attaches to it.
  48. Return Value:
  49. TRUE - The operation was successful.
  50. FALSE - The operation failed.
  51. --*/
  52. {
  53. HANDLE GlobalMutex;
  54. HANDLE LockSemaphore;
  55. BOOL rv;
  56. DWORD WaitResult;
  57. //
  58. // Serialize all global critical section initialization
  59. //
  60. GlobalMutex = CreateMutex(NULL,TRUE,"GlobalCsMutex");
  61. //
  62. // If the mutex create/open failed, then bail
  63. //
  64. if ( !GlobalMutex ) {
  65. return FALSE;
  66. }
  67. if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
  68. //
  69. // Since the mutex already existed, the request for ownership has no effect.
  70. // wait for the mutex
  71. //
  72. WaitResult = WaitForSingleObject(GlobalMutex,INFINITE);
  73. if ( WaitResult == WAIT_FAILED ) {
  74. CloseHandle(GlobalMutex);
  75. return FALSE;
  76. }
  77. }
  78. //
  79. // We now own the global critical section creation mutex. Create/Open the
  80. // named semaphore. If we are the creator, then initialize the critical
  81. // section. Otherwise just point to it. The global critical section creation
  82. // allows us to do this safely.
  83. //
  84. rv = FALSE;
  85. LockSemaphore = NULL;
  86. try {
  87. LockSemaphore = CreateSemaphore(NULL,0,MAXLONG-1,lpName);
  88. //
  89. // If the semaphore create/open failed, then bail
  90. //
  91. if ( !GlobalMutex ) {
  92. rv = FALSE;
  93. goto finallyexit;
  94. }
  95. //
  96. // See if we attached to the semaphore, or if we created it. If we created it,
  97. // then we need to init the global structure.
  98. //
  99. if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
  100. //
  101. // We Created the semaphore, so init the global portion.
  102. //
  103. lpGlobalPortion->LockCount = -1;
  104. lpGlobalPortion->RecursionCount = 0;
  105. lpGlobalPortion->OwningThread = 0;
  106. lpGlobalPortion->Reserved = 0;
  107. }
  108. lpLocalPortion->LockSemaphore = LockSemaphore;
  109. LockSemaphore = NULL;
  110. lpLocalPortion->GlobalPortion = lpGlobalPortion;
  111. lpLocalPortion->Reserved1 = 0;
  112. lpLocalPortion->Reserved2 = 0;
  113. rv = TRUE;
  114. finallyexit:;
  115. }
  116. finally {
  117. ReleaseMutex(GlobalMutex);
  118. CloseHandle(GlobalMutex);
  119. if ( LockSemaphore ) {
  120. CloseHandle(LockSemaphore);
  121. }
  122. }
  123. return rv;
  124. }
  125. BOOL
  126. WINAPI
  127. DetachFromGlobalCriticalSection(
  128. PGLOBAL_LOCAL_CRITICAL_SECTION lpLocalPortion
  129. )
  130. /*++
  131. Routine Description:
  132. This routine detaches from an existing global critical section.
  133. Arguments:
  134. lpLocalPortion - Supplies the address of a per-app local portion of the global
  135. critical section.
  136. Return Value:
  137. TRUE - The operation was successful.
  138. FALSE - The operation failed.
  139. --*/
  140. {
  141. HANDLE LockSemaphore;
  142. HANDLE GlobalMutex;
  143. DWORD WaitResult;
  144. BOOL rv;
  145. //
  146. // Serialize all global critical section initialization
  147. //
  148. GlobalMutex = CreateMutex(NULL,TRUE,"GlobalCsMutex");
  149. //
  150. // If the mutex create/open failed, then bail
  151. //
  152. if ( !GlobalMutex ) {
  153. return FALSE;
  154. }
  155. if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
  156. //
  157. // Since the mutex already existed, the request for ownership has no effect.
  158. // wait for the mutex
  159. //
  160. WaitResult = WaitForSingleObject(GlobalMutex,INFINITE);
  161. if ( WaitResult == WAIT_FAILED ) {
  162. CloseHandle(GlobalMutex);
  163. return FALSE;
  164. }
  165. }
  166. LockSemaphore = NULL;
  167. rv = FALSE;
  168. try {
  169. LockSemaphore = lpLocalPortion->LockSemaphore;
  170. ZeroMemory(lpLocalPortion,sizeof(*lpLocalPortion));
  171. rv = TRUE;
  172. }
  173. finally {
  174. if ( LockSemaphore ) {
  175. CloseHandle(LockSemaphore);
  176. }
  177. ReleaseMutex(GlobalMutex);
  178. CloseHandle(GlobalMutex);
  179. }
  180. return rv;
  181. }
  182. VOID
  183. WINAPI
  184. EnterGlobalCriticalSection(
  185. PGLOBAL_LOCAL_CRITICAL_SECTION lpLocalPortion
  186. )
  187. {
  188. PGLOBAL_SHARED_CRITICAL_SECTION GlobalPortion;
  189. DWORD ThreadId;
  190. LONG IncResult;
  191. DWORD WaitResult;
  192. ThreadId = GetCurrentThreadId();
  193. GlobalPortion = lpLocalPortion->GlobalPortion;
  194. //
  195. // Increment the lock variable. On the transition to 0, the caller
  196. // becomes the absolute owner of the lock. Otherwise, the caller is
  197. // either recursing, or is going to have to wait
  198. //
  199. IncResult = InterlockedIncrement(&GlobalPortion->LockCount);
  200. if ( !IncResult ) {
  201. //
  202. // lock count went from 0 to 1, so the caller
  203. // is the owner of the lock
  204. //
  205. GlobalPortion->RecursionCount = 1;
  206. GlobalPortion->OwningThread = ThreadId;
  207. }
  208. else {
  209. //
  210. // If the caller is recursing, then increment the recursion count
  211. //
  212. if ( GlobalPortion->OwningThread == ThreadId ) {
  213. GlobalPortion->RecursionCount++;
  214. }
  215. else {
  216. WaitResult = WaitForSingleObject(lpLocalPortion->LockSemaphore,INFINITE);
  217. if ( WaitResult == WAIT_FAILED ) {
  218. RaiseException(GetLastError(),0,0,NULL);
  219. }
  220. GlobalPortion->RecursionCount = 1;
  221. GlobalPortion->OwningThread = ThreadId;
  222. }
  223. }
  224. }
  225. VOID
  226. WINAPI
  227. LeaveGlobalCriticalSection(
  228. PGLOBAL_LOCAL_CRITICAL_SECTION lpLocalPortion
  229. )
  230. {
  231. PGLOBAL_SHARED_CRITICAL_SECTION GlobalPortion;
  232. LONG DecResult;
  233. GlobalPortion = lpLocalPortion->GlobalPortion;
  234. //
  235. // decrement the recursion count. If it is still non-zero, then
  236. // we are still the owner so don't do anything other than dec the lock
  237. // count
  238. //
  239. if (--GlobalPortion->RecursionCount) {
  240. InterlockedDecrement(&GlobalPortion->LockCount);
  241. }
  242. else {
  243. //
  244. // We are really leaving, so give up ownership and decrement the
  245. // lock count
  246. //
  247. GlobalPortion->OwningThread = 0;
  248. DecResult = InterlockedDecrement(&GlobalPortion->LockCount);
  249. //
  250. // Check to see if there are other waiters. If so, then wake up a waiter
  251. //
  252. if ( DecResult >= 0 ) {
  253. ReleaseSemaphore(lpLocalPortion->LockSemaphore,1,NULL);
  254. }
  255. }
  256. }
  257. GLOBAL_LOCAL_CRITICAL_SECTION LocalPortion;
  258. int __cdecl
  259. main(
  260. int argc,
  261. char *argv[],
  262. char *envp[]
  263. )
  264. {
  265. HANDLE hFileMap;
  266. LPVOID SharedMem;
  267. BOOL b;
  268. int i;
  269. DWORD Start,End;
  270. HANDLE Mutex1;
  271. //
  272. // open or create a shared file mapping object
  273. //
  274. hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,1024,"MyMem");
  275. if ( !hFileMap ) {
  276. printf("create file map failed\n");
  277. ExitProcess(1);
  278. }
  279. SharedMem = MapViewOfFile(hFileMap,FILE_MAP_WRITE,0,0,0);
  280. if ( !SharedMem ) {
  281. printf("map view failed\n");
  282. ExitProcess(1);
  283. }
  284. b = AttachToGlobalCriticalSection(&LocalPortion,SharedMem,"MyGlobalCs");
  285. if ( !b ) {
  286. printf("attach failed\n");
  287. ExitProcess(1);
  288. }
  289. if ( argc > 1 ) {
  290. for(i=0;i<30;i++){
  291. EnterGlobalCriticalSection(&LocalPortion);
  292. printf("Thread %x is in\n",GetCurrentThreadId());
  293. Sleep(500);
  294. LeaveGlobalCriticalSection(&LocalPortion);
  295. }
  296. }
  297. Start = GetTickCount();
  298. for(i=0;i<1000000;i++){
  299. EnterGlobalCriticalSection(&LocalPortion);
  300. LeaveGlobalCriticalSection(&LocalPortion);
  301. }
  302. End = GetTickCount();
  303. printf("Global CS Time %dms\n",End-Start);
  304. Mutex1 = CreateMutex(NULL,FALSE,NULL);
  305. Start = GetTickCount();
  306. for(i=0;i<100000;i++){
  307. WaitForSingleObject(Mutex1,INFINITE);
  308. ReleaseMutex(Mutex1);
  309. }
  310. End = GetTickCount();
  311. printf("Mutex Time %dms\n",(End-Start)*10);
  312. DetachFromGlobalCriticalSection(&LocalPortion);
  313. }