Leaked source code of windows server 2003
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.

481 lines
16 KiB

  1. /***
  2. *mlock.c - Multi-thread locking routines
  3. *
  4. * Copyright (c) 1987-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 05-07-90 JCR Module created.
  10. * 06-04-90 GJF Changed error message interface.
  11. * 08-08-90 GJF Removed 32 from API names.
  12. * 08-08-90 SBM _lockmap no longer 8 times required size
  13. * 10-08-90 GJF New-style function declarators. Removed questionable
  14. * return statements from void functions (weren't needed
  15. * and the compiler was bitching).
  16. * 10-09-90 GJF Thread ids are unsigned longs.
  17. * 06-06-91 GJF Adapted for Win32 [_WIN32_].
  18. * 09-29-91 GJF Fixed infinite recursion problem with DEBUG version
  19. * of _lock [_WIN32_].
  20. * 03-06-92 GJF Removed _[un]lock_fh() and _[un]lock_stream for Win32
  21. * targets.
  22. * 05-28-92 GJF Added _mtdeletelocks() for Win32 for DLLs with contain
  23. * the C runtime (e.g., crtdll.dll).
  24. * 10-06-92 SRW Make _locktable an array of PCRITICAL_SECTION pointers
  25. * instead of structures. Allocate each critical section
  26. * as it is needed.
  27. * 02-25-93 GJF Substantially revised. Restored static critical section
  28. * structures for some locks. Replaced bit-array scheme
  29. * of keeping track of locks. Removed Cruiser support and
  30. * replaced obsolete DEBUG code.
  31. * 03-03-93 GJF Made CRITICAL_SECTION structure for _HEAP_LOCK static.
  32. * 03-08-93 SKS Fix ptr use error in DEBUG version of _mtdeletelocks
  33. * 03-08-93 SKS Fix deletion of the special critical sections,
  34. * especially the heap lock.
  35. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  36. * 05-05-93 GJF Turned DEBUG code off.
  37. * 06-03-93 SRW Disable FPO optimizations for this file so it can call
  38. * CriticalSection routines on a checked build even though
  39. * the C Runtimes are compiled free.
  40. * 10-19-93 GJF Merged in NT SDK version. Enclosed #pragma-s in
  41. * #ifdef _M_IX86 / #endif. Replaced MTHREAD with _MT.
  42. * 04-12-94 GJF Made into empty functions for the Win32s version of
  43. * msvcrt*.dll.
  44. * 01-10-95 CFW Debug CRT allocs.
  45. * 01-30-95 GJF Made CRITICAL_SECTION structure for _SIGNAL_LOCK
  46. * static.
  47. * 03-06-95 GJF Added _[un]lock_file[2] to lock stdio files (__piob[]
  48. * entries).
  49. * 03-23-95 BWT Store the critsec in the locktable *after* it's
  50. * initialized.
  51. * 10-03-95 GJF Added comments to the effect that the _LC_*_LOCK
  52. * locks are obsolete.
  53. * 11-15-95 JWM Correct syntax error in 2nd '#pragma optimize()'.
  54. * 06-19-97 GJF Moved _[un]lock_file[2]() to stdio\_file.c to improve
  55. * granularity.
  56. * 05-13-99 PML Remove Win32s
  57. * 10-14-99 PML Replace InitializeCriticalSection with wrapper function
  58. * __crtInitCritSecAndSpinCount
  59. * 12-10-99 GB Added a new Lock _UNDNAME_LOCK for critical section in
  60. * unDName().
  61. * 03-06-00 PML Call __crtExitProcess instead of ExitProcess.
  62. * 02-20-01 PML vs7#172586 Avoid _RT_LOCK by preallocating all locks
  63. * that will be required, and returning failure back on
  64. * inability to allocate a lock.
  65. * 03-07-01 PML vs7#221122 Release preallocated locks after heap ones,
  66. * so _HEAP_LOCK is around while we're still freeing mem.
  67. * 03-22-01 PML Add _DEBUG_LOCK for _CrtSetReportHook2 (vs7#124998)
  68. * 06-12-01 BWT ntbug: 414059 - cleanup from mtinit failure
  69. *
  70. *******************************************************************************/
  71. #ifdef _MT
  72. #include <cruntime.h>
  73. #include <oscalls.h>
  74. #include <internal.h>
  75. #include <mtdll.h>
  76. #include <rterr.h>
  77. #include <stddef.h>
  78. #include <malloc.h>
  79. #include <limits.h>
  80. #include <stdio.h>
  81. #include <dbgint.h>
  82. #include <errno.h>
  83. /*
  84. * Local routines
  85. */
  86. void __cdecl _lockerr_exit(char *);
  87. /*
  88. * Global Data
  89. */
  90. /*
  91. * Statically allocated critical section structures for all preallocated locks.
  92. * These are most of the named locks before _STREAM_LOCKS, along with the locks
  93. * for stdin/stdout/stderr. These must be preallocated so we do not hit fatal
  94. * memory conditions on failing to initialize a critical section, except at
  95. * runtime startup, since these locks may be taken where we have no good way
  96. * to return a non-fatal error.
  97. */
  98. #define NUM_STD_FILE_LOCKS 3
  99. #define NUM_NON_PREALLOC_LOCKS 5
  100. #define NUM_PREALLOC_LOCKS \
  101. ( _STREAM_LOCKS + NUM_STD_FILE_LOCKS - NUM_NON_PREALLOC_LOCKS )
  102. static CRITICAL_SECTION lclcritsects[NUM_PREALLOC_LOCKS];
  103. /*
  104. * Lock Table
  105. * This table contains a pointer to the critical section management structure
  106. * for each lock.
  107. *
  108. * Locks marked lkPrealloc have their critical sections statically allocated
  109. * and initialized at startup in _mtinitlocks. Locks marked lkNormal must
  110. * be allocated when first used, via a call to _mtinitlocknum.
  111. */
  112. static struct {
  113. PCRITICAL_SECTION lock;
  114. enum { lkNormal = 0, lkPrealloc, lkDeleted } kind;
  115. } _locktable[_TOTAL_LOCKS] = {
  116. { NULL, lkPrealloc }, /* 0 == _SIGNAL_LOCK */
  117. { NULL, lkPrealloc }, /* 1 == _IOB_SCAN_LOCK */
  118. { NULL, lkNormal }, /* 2 == _TMPNAM_LOCK - not preallocated */
  119. { NULL, lkPrealloc }, /* 3 == _CONIO_LOCK */
  120. { NULL, lkPrealloc }, /* 4 == _HEAP_LOCK */
  121. { NULL, lkNormal }, /* 5 == _UNDNAME_LOCK - not preallocated */
  122. { NULL, lkPrealloc }, /* 6 == _TIME_LOCK */
  123. { NULL, lkPrealloc }, /* 7 == _ENV_LOCK */
  124. { NULL, lkPrealloc }, /* 8 == _EXIT_LOCK1 */
  125. { NULL, lkNormal }, /* 9 == _POPEN_LOCK - not preallocated */
  126. { NULL, lkPrealloc }, /* 10 == _LOCKTAB_LOCK */
  127. { NULL, lkNormal }, /* 11 == _OSFHND_LOCK - not preallocated */
  128. { NULL, lkPrealloc }, /* 12 == _SETLOCALE_LOCK */
  129. { NULL, lkPrealloc }, /* 13 == _MB_CP_LOCK */
  130. { NULL, lkPrealloc }, /* 14 == _TYPEINFO_LOCK */
  131. { NULL, lkNormal }, /* 15 == _DEBUG_LOCK - not preallocated */
  132. { NULL, lkPrealloc }, /* 16 == _STREAM_LOCKS+0 - stdin */
  133. { NULL, lkPrealloc }, /* 17 == _STREAM_LOCKS+1 - stdout */
  134. { NULL, lkPrealloc }, /* 18 == _STREAM_LOCKS+2 - stderr */
  135. /* { NULL, lkNormal }, /* ... */
  136. };
  137. #ifndef NT_BUILD
  138. #ifdef _M_IX86
  139. #pragma optimize("y",off)
  140. #endif
  141. #endif
  142. /***
  143. *_mtinitlocks() - Initialize multi-thread lock scheme
  144. *
  145. *Purpose:
  146. * Perform whatever initialization is required for the multi-thread
  147. * locking (synchronization) scheme. This routine should be called
  148. * exactly once, during startup, and this must be before any requests
  149. * are made to assert locks.
  150. *
  151. * NOTES: In Win32, the multi-thread locks are created individually,
  152. * each upon its first use. That is when any particular lock is asserted
  153. * for the first time, the underlying critical section is then allocated,
  154. * initialized and (finally) entered. This allocation and initialization
  155. * is protected under _LOCKTAB_LOCK. It is _mtinitlocks' job to set up
  156. * _LOCKTAB_LOCK.
  157. *
  158. * All other named (non-FILE) locks are also preallocated in _mtinitlocks.
  159. * That is because a failure to allocate a lock on its first use in _lock
  160. * triggers a fatal error, which cannot be permitted since that can bring
  161. * down a long-lived app without warning.
  162. *
  163. *Entry:
  164. * <none>
  165. *
  166. *Exit:
  167. * returns FALSE on failure
  168. *
  169. *Exceptions:
  170. *
  171. *******************************************************************************/
  172. int __cdecl _mtinitlocks (
  173. void
  174. )
  175. {
  176. int locknum;
  177. int idxPrealloc = 0;
  178. /*
  179. * Scan _locktable[] and allocate all entries marked lkPrealloc.
  180. */
  181. for ( locknum = 0 ; locknum < _TOTAL_LOCKS ; locknum++ ) {
  182. #ifdef DEBUG
  183. if ( _locktable[locknum].lock != NULL )
  184. _lockerr_exit("fatal error in _mtinitlocks #1\n");
  185. #endif /* DEBUG */
  186. if ( _locktable[locknum].kind == lkPrealloc ) {
  187. _locktable[locknum].lock = &lclcritsects[idxPrealloc++];
  188. if ( !__crtInitCritSecAndSpinCount( _locktable[locknum].lock,
  189. _CRT_SPINCOUNT ))
  190. {
  191. _locktable[locknum].lock = NULL;
  192. return FALSE;
  193. }
  194. }
  195. }
  196. #ifdef DEBUG
  197. if ( idxPrealloc != NUM_PREALLOC_LOCKS )
  198. _lockerr_exit("fatal error in _mtinitlocks #2\n");
  199. #endif /* DEBUG */
  200. return TRUE;
  201. }
  202. /***
  203. *_mtdeletelocks() - Delete all initialized locks
  204. *
  205. *Purpose:
  206. * Walks _locktable[] and _lockmap, and deletes every 'lock' (i.e.,
  207. * critical section) which has been initialized.
  208. *
  209. * This function is intended for use in DLLs containing the C runtime
  210. * (i.e., crtdll.dll and user DLLs built using libcmt.lib and the
  211. * special startup objects). It is to be called from within the DLL's
  212. * entrypoint function when that function is called with
  213. * DLL_PROCESS_DETACH.
  214. *
  215. *Entry:
  216. * <none>
  217. *
  218. *Exit:
  219. *
  220. *Exceptions:
  221. * behavior undefined/unknown if a lock is being held when this routine
  222. * is called.
  223. *
  224. *******************************************************************************/
  225. void __cdecl _mtdeletelocks(
  226. void
  227. )
  228. {
  229. int locknum;
  230. /*
  231. * Delete and free all normal locks that have been created.
  232. */
  233. for ( locknum = 0 ; locknum < _TOTAL_LOCKS ; locknum++ ) {
  234. if ( _locktable[locknum].lock != NULL &&
  235. _locktable[locknum].kind != lkPrealloc )
  236. {
  237. PCRITICAL_SECTION pcs = _locktable[locknum].lock;
  238. DeleteCriticalSection(pcs);
  239. /*
  240. * Free the memory for the CritSect after deleting it.
  241. */
  242. #ifdef DEBUG
  243. /* check that it's an undeleted normal lock */
  244. if ( _locktable[locknum].kind != lkNormal )
  245. _lockerr_exit("fatal error in _mtdeletelocks #1\n");
  246. /* mark as deleted */
  247. _locktable[locknum].kind = lkDeleted;
  248. #endif /* DEBUG */
  249. _free_crt(pcs);
  250. _locktable[locknum].lock = NULL;
  251. }
  252. }
  253. /*
  254. * Delete all preallocated locks after all normal ones are
  255. * freed (so preallocated _HEAP_LOCK outlives all heap usages).
  256. */
  257. for ( locknum = 0 ; locknum < _TOTAL_LOCKS ; locknum++ ) {
  258. if ( _locktable[locknum].lock != NULL &&
  259. _locktable[locknum].kind == lkPrealloc )
  260. {
  261. PCRITICAL_SECTION pcs = _locktable[locknum].lock;
  262. DeleteCriticalSection(pcs);
  263. }
  264. }
  265. }
  266. /***
  267. * _mtinitlocknum - Allocate a non-preallocated multi-thread lock
  268. *
  269. *Purpose:
  270. * Allocate a new, non-preallocated multi-thread lock. This should be
  271. * used whenever a new lock is known to be needed, so that failure to
  272. * allocate can return an error, instead of allowing _lock() to issue
  273. * a fatal _RT_LOCK instead.
  274. *
  275. * It is not an error to call this on a normal lock which has already
  276. * been allocated. It is used to ensure that certain named locks which
  277. * are not preallocated are available.
  278. *
  279. * It is also called by _lock, in case any other paths exist which call
  280. * _lock without calling _mtinitlocknum first. This is not expected,
  281. * and can allow fatal _RT_LOCK errors to be issued.
  282. *
  283. * Since a failure sets errno to ENOMEM, this should only be called
  284. * after the per-thread data has been set up (after _mtinit).
  285. *
  286. *Entry:
  287. * locknum = number of the lock to aquire
  288. *
  289. *Exit:
  290. * Returns FALSE on failure, and sets errno to ENOMEM.
  291. *
  292. *Exceptions:
  293. *
  294. *******************************************************************************/
  295. int __cdecl _mtinitlocknum (
  296. int locknum
  297. )
  298. {
  299. PCRITICAL_SECTION pcs;
  300. #ifdef DEBUG
  301. if ( _locktable[locknum].kind != lkNormal )
  302. _lockerr_exit("fatal error in _mtinitlocknum #1\n");
  303. #endif /* DEBUG */
  304. if ( _locktable[locknum].lock != NULL )
  305. return TRUE;
  306. if ( (pcs = _malloc_crt(sizeof(CRITICAL_SECTION))) == NULL ) {
  307. errno = ENOMEM;
  308. return FALSE;
  309. }
  310. _mlock(_LOCKTAB_LOCK);
  311. if ( _locktable[locknum].lock == NULL ) {
  312. if ( !__crtInitCritSecAndSpinCount(pcs, _CRT_SPINCOUNT) ) {
  313. _free_crt(pcs);
  314. _munlock(_LOCKTAB_LOCK);
  315. errno = ENOMEM;
  316. return FALSE;
  317. }
  318. _locktable[locknum].lock = pcs;
  319. }
  320. else {
  321. _free_crt(pcs);
  322. }
  323. _munlock(_LOCKTAB_LOCK);
  324. return TRUE;
  325. }
  326. /***
  327. * _lock - Acquire a multi-thread lock
  328. *
  329. *Purpose:
  330. * Acquire a multi-thread lock. If the lock has not already been
  331. * allocated, do so, but that is an internal CRT error, since all locks
  332. * should be allocated before first being acquired, either in
  333. * _mtinitlocks or individually in _mtinitlocknum.
  334. *
  335. * Note that it is legal for a thread to aquire _EXIT_LOCK1
  336. * multiple times.
  337. *
  338. *Entry:
  339. * locknum = number of the lock to aquire
  340. *
  341. *Exit:
  342. *
  343. *Exceptions:
  344. * A failure to allocate a new lock results in a fatal _RT_LOCK error.
  345. *
  346. *******************************************************************************/
  347. void __cdecl _lock (
  348. int locknum
  349. )
  350. {
  351. #ifdef DEBUG
  352. if ( _locktable[locknum].kind != lkNormal &&
  353. _locktable[locknum].kind != lkPrealloc )
  354. _lockerr_exit("fatal error in _lock #1\n");
  355. #endif /* DEBUG */
  356. /*
  357. * Create/open the lock, if necessary
  358. */
  359. if ( _locktable[locknum].lock == NULL ) {
  360. #ifdef DEBUG
  361. if ( _locktable[locknum].kind != lkNormal )
  362. _lockerr_exit("fatal error in _lock #2\n");
  363. /*
  364. * All locks should be allocated before first being acquired.
  365. * Failure to do so is an internal CRT error, which we silently
  366. * allow in a production CRT, but that can lead to fatal _RT_LOCK
  367. * errors which result in an ExitProcess call.
  368. */
  369. _lockerr_exit("fatal error in _lock #3\n");
  370. #endif /* DEBUG */
  371. if ( !_mtinitlocknum(locknum) )
  372. _amsg_exit( _RT_LOCK );
  373. }
  374. /*
  375. * Enter the critical section.
  376. */
  377. EnterCriticalSection( _locktable[locknum].lock );
  378. }
  379. /***
  380. * _unlock - Release multi-thread lock
  381. *
  382. *Purpose:
  383. * Note that it is legal for a thread to aquire _EXIT_LOCK1
  384. * multiple times.
  385. *
  386. *Entry:
  387. * locknum = number of the lock to release
  388. *
  389. *Exit:
  390. *
  391. *Exceptions:
  392. *
  393. *******************************************************************************/
  394. void __cdecl _unlock (
  395. int locknum
  396. )
  397. {
  398. /*
  399. * leave the critical section.
  400. */
  401. LeaveCriticalSection( _locktable[locknum].lock );
  402. }
  403. #ifndef NT_BUILD
  404. #ifdef _M_IX86
  405. #pragma optimize("y",on)
  406. #endif
  407. #endif
  408. /***
  409. *_lockerr_exit() - Write error message and die
  410. *
  411. *Purpose:
  412. * Attempt to write out the unexpected lock error message, then terminate
  413. * the program by a direct API call. This function is used in place of
  414. * amsg_exit(_RT_LOCK) when it is judged unsafe to allow further lock
  415. * or unlock calls.
  416. *
  417. *Entry:
  418. *
  419. *Exit:
  420. *
  421. *Exceptions:
  422. *
  423. *******************************************************************************/
  424. void __cdecl _lockerr_exit (
  425. char *msg
  426. )
  427. {
  428. FatalAppExit(0, msg); /* Die with message box */
  429. __crtExitProcess(255); /* Just die */
  430. }
  431. #endif /* _MT */