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.

702 lines
12 KiB

  1. /***
  2. *mtlock.c - Multi-thread locking routines
  3. *
  4. * Copyright (c) 1987-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Contains definitions for general-purpose multithread locking functions.
  8. * _mtlockinit()
  9. * _mtlock()
  10. * _mtunlock()
  11. *
  12. *Revision History:
  13. * 03-10-92 KRS Created from mlock.c.
  14. * 04-06-93 SKS Replace _CRTAPI1/2 with __cdecl, _CRTVAR1 with nothing
  15. * 10-28-93 SKS Add _mttermlock() to delete o.s. resources associated
  16. * with a Critical Section. (Called by ~ios & ~streamb.)
  17. * 09-06-94 CFW Remove Cruiser support.
  18. * 02-06-95 CFW assert -> _ASSERTE, DEBUG -> _IOSDEBUG.
  19. * 05-10-96 SKS Add _CRTIMP1 to prototypes of _mtlock/_mtunlock
  20. * 04-29-02 GB Added try-finally arounds lock-unlock.
  21. *
  22. *******************************************************************************/
  23. #include <cruntime.h>
  24. #include <oscalls.h>
  25. #include <internal.h>
  26. #include <mtdll.h>
  27. #include <rterr.h>
  28. #include <stddef.h>
  29. #include <limits.h>
  30. #ifdef _MT
  31. void __cdecl _mtlockinit( PRTL_CRITICAL_SECTION pLk)
  32. {
  33. /*
  34. * Initialize the critical section.
  35. */
  36. InitializeCriticalSection( pLk );
  37. }
  38. void __cdecl _mtlockterm( PRTL_CRITICAL_SECTION pLk)
  39. {
  40. /*
  41. * Initialize the critical section.
  42. */
  43. DeleteCriticalSection( pLk );
  44. }
  45. _CRTIMP1 void __cdecl _mtlock ( PRTL_CRITICAL_SECTION pLk)
  46. {
  47. /*
  48. * Enter the critical section.
  49. */
  50. EnterCriticalSection( pLk );
  51. }
  52. _CRTIMP1 void __cdecl _mtunlock ( PRTL_CRITICAL_SECTION pLk)
  53. {
  54. /*
  55. * leave the critical section.
  56. */
  57. LeaveCriticalSection( pLk );
  58. }
  59. #endif /* _MT */
  60. /* history: mlock.c */
  61. #ifdef _IOSDEBUG
  62. #include <dbgint.h>
  63. /*
  64. * Local routines
  65. */
  66. static void __cdecl _lock_create (unsigned);
  67. #ifdef _IOSDEBUG
  68. static struct _debug_lock * __cdecl _lock_validate(int);
  69. #endif
  70. /*
  71. * Global Data
  72. */
  73. /*
  74. * Lock Table
  75. * This table contains the critical section management structure of each
  76. * lock.
  77. */
  78. RTL_CRITICAL_SECTION _locktable[_TOTAL_LOCKS]; /* array of locks */
  79. /*
  80. * Lock Bit Map
  81. * This table contains one bit for each lock (i.e., each entry in the
  82. * _locktable[] array).
  83. *
  84. * If bit = 0, lock has not been created/opened
  85. * If bit = 1, lock has been created/opened
  86. */
  87. char _lockmap[(_TOTAL_LOCKS/CHAR_BIT)+1]; /* lock bit map */
  88. #ifdef _LOCKCOUNT
  89. /*
  90. * Total number of locks held
  91. */
  92. unsigned _lockcnt = 0;
  93. #endif
  94. #ifdef _IOSDEBUG
  95. /*
  96. * Lock Debug Data Table Segment
  97. * Contains debugging data for each lock.
  98. */
  99. struct _debug_lock _debug_locktable[_TOTAL_LOCKS];
  100. #endif
  101. #define _FATAL _amsg_exit(_RT_LOCK)
  102. /***
  103. * Bit map macros
  104. *
  105. *Purpose:
  106. * _CLEARBIT() - Clear the specified bit
  107. * _SETBIT() - Set the specified bit
  108. * _TESTBIT() - Test the specified bit
  109. *
  110. *Entry:
  111. * char a[] = character array
  112. * unsigned b = bit number (0-based, range from 0 to whatever)
  113. * unsigned x = bit number (0-based, range from 0 to 31)
  114. *
  115. *Exit:
  116. * _CLEARBIT() = void
  117. * _SETBIT() = void
  118. * _TESTBIT() = 0 or 1
  119. *
  120. *Exceptions:
  121. *
  122. *******************************************************************************/
  123. /*
  124. * Macros for use when managing a bit in a character array (e.g., _lockmap)
  125. * a = character array
  126. * b = bit number (0-based)
  127. */
  128. #define _CLEARBIT(a,b) \
  129. ( a[b>>3] &= (~(1<<(b&7))) )
  130. #define _SETBIT(a,b) \
  131. ( a[b>>3] |= (1<<(b&7)) )
  132. #define _TESTBIT(a,b) \
  133. ( a[b>>3] & (1<<(b&7)) )
  134. /*
  135. * Macros for use when managing a bit in an unsigned int
  136. * x = bit number (0-31)
  137. */
  138. #define _BIT_INDEX(x) (1 << (x & 0x1F))
  139. /***
  140. *_mtinitlocks() - Initialize the semaphore lock data base
  141. *
  142. *Purpose:
  143. * Initialize the mthread semaphore lock data base.
  144. *
  145. * NOTES:
  146. * (1) Only to be called ONCE at startup
  147. * (2) Must be called BEFORE any mthread requests are made
  148. *
  149. * Schemes for creating the mthread locks:
  150. *
  151. * Create the locks one at a time on demand the first
  152. * time the lock is attempted. This is more complicated but
  153. * is much faster than creating them all at startup time.
  154. * These is currently the default scheme.
  155. *
  156. * Create and open the semaphore that protects the lock data
  157. * base.
  158. *
  159. *Entry:
  160. * <none>
  161. *
  162. *Exit:
  163. * returns on success
  164. * calls _amsg_exit on failure
  165. *
  166. *Exceptions:
  167. *
  168. *******************************************************************************/
  169. void __cdecl _mtinitlocks (
  170. void
  171. )
  172. {
  173. /*
  174. * All we need to do is create the lock table lock
  175. */
  176. _lock_create(_LOCKTAB_LOCK);
  177. /*
  178. * Make sure the assumptions we make in this source are correct.
  179. * The following is a tricky way to validate sizeof() assumptions
  180. * at compile time without generating any runtime code (can't
  181. * use sizeof() in an #ifdef). If the assumption fails, the
  182. * compiler will generate a divide by 0 error.
  183. *
  184. * This here only because it must be inside a subroutine.
  185. */
  186. ( (sizeof(char) == 1) ? 1 : (1/0) );
  187. ( (sizeof(int) == 4) ? 1 : (1/0) );
  188. }
  189. /***
  190. *_lock_create() - Create and open a lock
  191. *
  192. *Purpose:
  193. * Create and open a mthread lock.
  194. *
  195. * NOTES:
  196. *
  197. * (1) The caller must have previously determined that the lock
  198. * needs to be created/opened (and this hasn't already been done).
  199. *
  200. * (2) The caller must have aquired the _LOCKTAB_LOCK, if needed.
  201. * (The only time this isn't required is at init time.)
  202. *
  203. *Entry:
  204. * unsigned locknum = lock to create
  205. *
  206. *Exit:
  207. *
  208. *Exceptions:
  209. *
  210. *******************************************************************************/
  211. static void __cdecl _lock_create (
  212. unsigned locknum
  213. )
  214. {
  215. #ifdef _IOSDEBUG
  216. /*
  217. * See if the lock already exists; if so, die.
  218. */
  219. if (_TESTBIT(_lockmap, locknum))
  220. _FATAL;
  221. #endif
  222. /*
  223. * Convert the lock number into a lock address
  224. * and create the semaphore.
  225. */
  226. /*
  227. * Convert the lock number into a lock address
  228. * and initialize the critical section.
  229. */
  230. InitializeCriticalSection( &_locktable[locknum] );
  231. /*
  232. * Set the appropriate bit in the lock bit map.
  233. */
  234. _SETBIT(_lockmap, locknum);
  235. }
  236. /***
  237. * _lock_stream, etc. - Routines to lock/unlock streams, files, etc.
  238. *
  239. *Purpose:
  240. * _lock_stream = Lock a stdio stream
  241. * _unlock_stream = Unlock a stdio stream
  242. * _lock_file = Lock a lowio file
  243. * _unlock_file = Unlock a lowio file
  244. *
  245. *Entry:
  246. * stream/file identifier
  247. *
  248. *Exit:
  249. *
  250. *Exceptions:
  251. *
  252. *******************************************************************************/
  253. void __cdecl _lock_stream (
  254. int stream_id
  255. )
  256. {
  257. _lock(stream_id+_STREAM_LOCKS);
  258. }
  259. void __cdecl _unlock_stream (
  260. int stream_id
  261. )
  262. {
  263. _unlock(stream_id+_STREAM_LOCKS);
  264. }
  265. void __cdecl _lock_file (
  266. int fh
  267. )
  268. {
  269. _lock(fh+_FH_LOCKS);
  270. }
  271. void __cdecl _unlock_file (
  272. int fh
  273. )
  274. {
  275. _unlock(fh+_FH_LOCKS);
  276. }
  277. /***
  278. * _lock - Acquire a multi-thread lock
  279. *
  280. *Purpose:
  281. * Note that it is legal for a thread to aquire _EXIT_LOCK1
  282. * multiple times.
  283. *
  284. *Entry:
  285. * locknum = number of the lock to aquire
  286. *
  287. *Exit:
  288. *
  289. *Exceptions:
  290. *
  291. *******************************************************************************/
  292. void __cdecl _lock (
  293. int locknum
  294. )
  295. {
  296. #ifdef _IOSDEBUG
  297. struct _debug_lock *deblock;
  298. unsigned tidbit;
  299. #endif
  300. /*
  301. * Create/open the lock, if necessary
  302. */
  303. if (!_TESTBIT(_lockmap, locknum)) {
  304. _mlock(_LOCKTAB_LOCK); /*** WARNING: Recursive lock call ***/
  305. __TRY
  306. /* if lock still doesn't exist, create it */
  307. if (!_TESTBIT(_lockmap, locknum))
  308. _lock_create(locknum);
  309. __FINALLY
  310. _munlock(_LOCKTAB_LOCK);
  311. __END_TRY_FINALLY
  312. }
  313. #ifdef _IOSDEBUG
  314. /*
  315. * Validate the lock and get pointer to debug lock structure, etc.
  316. */
  317. deblock = _lock_validate(locknum);
  318. /*
  319. * Set tidbit to 2**(index of ptd[] entry).
  320. *
  321. * call non-locking form of _getptd to avoid recursing
  322. */
  323. tidbit = _getptd_lk() - _ptd; /* index of _ptd[] entry */
  324. tidbit = _BIT_INDEX(tidbit);
  325. /*
  326. * Make sure we're not trying to get lock we already have
  327. * (except for _EXIT_LOCK1).
  328. */
  329. if (locknum != _EXIT_LOCK1)
  330. if ((deblock->holder) & tidbit)
  331. _FATAL;
  332. /*
  333. * Set waiter bit for this thread
  334. */
  335. deblock->waiters |= tidbit;
  336. #endif /* _IOSDEBUG */
  337. /*
  338. * Get the lock
  339. */
  340. #ifdef _LOCKCOUNT
  341. _lockcnt++;
  342. #endif
  343. /*
  344. * Enter the critical section.
  345. */
  346. EnterCriticalSection( &_locktable[locknum] );
  347. #ifdef _IOSDEBUG
  348. /*
  349. * Clear waiter bit
  350. */
  351. deblock->waiters &= (~tidbit);
  352. /*
  353. * Make sure there are no lock holders (unless this is
  354. * _EXIT_LOCK1); then set holder bit and bump lock count.
  355. */
  356. _ASSERTE(THREADINTS==1);
  357. if (locknum != _EXIT_LOCK1)
  358. if ( (unsigned) deblock->holder != 0)
  359. _FATAL;
  360. deblock->holder &= tidbit;
  361. deblock->lockcnt++;
  362. #endif
  363. }
  364. /***
  365. * _unlock - Release multi-thread lock
  366. *
  367. *Purpose:
  368. * Note that it is legal for a thread to aquire _EXIT_LOCK1
  369. * multiple times.
  370. *
  371. *Entry:
  372. * locknum = number of the lock to release
  373. *
  374. *Exit:
  375. *
  376. *Exceptions:
  377. *
  378. *******************************************************************************/
  379. void __cdecl _unlock (
  380. int locknum
  381. )
  382. {
  383. #ifdef _IOSDEBUG
  384. struct _debug_lock *deblock;
  385. unsigned tidbit;
  386. #endif
  387. #ifdef _IOSDEBUG
  388. /*
  389. * Validate the lock and get pointer to debug lock structure, etc.
  390. */
  391. deblock = _lock_validate(locknum);
  392. /*
  393. * Set tidbit to 2**(index of ptd[] entry).
  394. */
  395. tidbit = _getptd_lk() - _ptd; /* index of _ptd[] entry */
  396. tidbit = _BIT_INDEX(tidbit);
  397. /*
  398. * Make sure we hold this lock then clear holder bit.
  399. * [Note: Since it is legal to aquire _EXIT_LOCK1 several times,
  400. * it's possible the holder bit is already clear.]
  401. */
  402. if (locknum != _EXIT_LOCK1)
  403. if (!((deblock->holder) & tidbit))
  404. _FATAL;
  405. deblock->holder &= (~tidbit);
  406. /*
  407. * See if anyone else is waiting for this lock.
  408. */
  409. _ASSERTE(THREADINTS==1);
  410. if ((unsigned) deblock->waiters != 0)
  411. deblock->collcnt++;
  412. #endif
  413. /*
  414. * leave the critical section.
  415. */
  416. LeaveCriticalSection( &_locktable[locknum] );
  417. #ifdef _LOCKCOUNT
  418. _lockcnt--;
  419. #endif
  420. }
  421. /*
  422. * Debugging code
  423. */
  424. #ifdef _IOSDEBUG
  425. /***
  426. *_lock_validate() - Validate a lock
  427. *
  428. *Purpose:
  429. * Debug lock validations common to both lock and unlock.
  430. *
  431. *Entry:
  432. * lock number
  433. *
  434. *Exit:
  435. * ptr to lock's debug structure
  436. *
  437. *Exceptions:
  438. *
  439. *******************************************************************************/
  440. static struct _debug_lock * __cdecl _lock_validate (
  441. int locknum
  442. )
  443. {
  444. /*
  445. * Make sure lock is legal
  446. */
  447. if (locknum > _TOTAL_LOCKS)
  448. _FATAL;
  449. /*
  450. * Return pointer to this lock's debug structure
  451. */
  452. return(&_debug_locktable[locknum]);
  453. }
  454. /***
  455. *_fh_locknum() - Return the lock number for a file handle
  456. *
  457. *Purpose:
  458. *
  459. *Entry:
  460. * int fh = file handle
  461. *
  462. *Exit:
  463. * int locknum = corresponding lock number
  464. *
  465. *Exceptions:
  466. *
  467. *******************************************************************************/
  468. int __cdecl _fh_locknum (
  469. int fh
  470. )
  471. {
  472. return(fh+_FH_LOCKS);
  473. }
  474. /***
  475. *_stream_locknum() - Return the lock number for a stream
  476. *
  477. *Purpose:
  478. *
  479. *Entry:
  480. * int stream = stream number (i.e., offset of the stream
  481. * in the _iob table)
  482. *
  483. *Exit:
  484. * int locknum = corresponding lock number
  485. *
  486. *Exceptions:
  487. *
  488. *******************************************************************************/
  489. int __cdecl _stream_locknum (
  490. int stream
  491. )
  492. {
  493. return(stream+_STREAM_LOCKS);
  494. }
  495. /***
  496. *_collide_cnt() - Return the collision count for a lock
  497. *
  498. *Purpose:
  499. *
  500. *Entry:
  501. * int lock = lock number
  502. *
  503. *Exit:
  504. * int count = collision count
  505. *
  506. *Exceptions:
  507. *
  508. *******************************************************************************/
  509. int __cdecl _collide_cnt (
  510. int locknum
  511. )
  512. {
  513. return(_debug_locktable[locknum].collcnt);
  514. }
  515. /***
  516. *_lock_cnt() - Return the lock count for a lock
  517. *
  518. *Purpose:
  519. *
  520. *Entry:
  521. * int lock = lock number
  522. *
  523. *Exit:
  524. * int count = lock count
  525. *
  526. *Exceptions:
  527. *
  528. *******************************************************************************/
  529. int __cdecl _lock_cnt (
  530. int locknum
  531. )
  532. {
  533. return(_debug_locktable[locknum].lockcnt);
  534. }
  535. /***
  536. *_lock_exist() - Check to see if a lock exists
  537. *
  538. *Purpose:
  539. * Test lock bit map to see if the lock has
  540. * been created or not.
  541. *
  542. *Entry:
  543. * int lock = lock number
  544. *
  545. *Exit:
  546. * int 0 = lock has NOT been created
  547. * 1 = lock HAS been created
  548. *
  549. *Exceptions:
  550. *
  551. *******************************************************************************/
  552. int __cdecl _lock_exist (
  553. int locknum
  554. )
  555. {
  556. if (_TESTBIT(_lockmap, locknum))
  557. return(1);
  558. else
  559. return(0);
  560. }
  561. #endif
  562. #endif