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.

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