mutex.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. mutex.c
  9. Abstract:
  10. This module implements mutex support functions for the POSIX thread library.
  11. Author:
  12. Evan Green 27-Apr-2015
  13. Environment:
  14. User Mode C Library
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "pthreadp.h"
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. #define PTHREAD_MUTEX_STATE_UNLOCKED 0
  24. #define PTHREAD_MUTEX_STATE_LOCKED 1
  25. #define PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS 2
  26. #define PTHREAD_MUTEX_STATE_MASK 0x00000007
  27. #define PTHREAD_MUTEX_STATE_COUNTER_SHIFT 4
  28. #define PTHREAD_MUTEX_STATE_COUNTER_MASK 0x0000FFFF
  29. #define PTHREAD_MUTEX_STATE_COUNTER_MAX 0x0000FFFF
  30. #define PTHREAD_MUTEX_STATE_SHARED 0x20000000
  31. #define PTHREAD_MUTEX_STATE_RECURSIVE 0x40000000
  32. #define PTHREAD_MUTEX_STATE_ERRORCHECK 0x80000000
  33. #define PTHREAD_MUTEX_STATE_TYPE_MASK 0xC0000000
  34. //
  35. // ------------------------------------------------------ Data Type Definitions
  36. //
  37. //
  38. // ----------------------------------------------- Internal Function Prototypes
  39. //
  40. int
  41. ClpAcquireMutexWithTimeout (
  42. PPTHREAD_MUTEX Mutex,
  43. const struct timespec *AbsoluteTimeout,
  44. clockid_t Clock
  45. );
  46. int
  47. ClpAcquireNormalMutex (
  48. PPTHREAD_MUTEX Mutex,
  49. ULONG Shared,
  50. const struct timespec *AbsoluteTimeout,
  51. INT Clock
  52. );
  53. int
  54. ClpTryToAcquireNormalMutex (
  55. PPTHREAD_MUTEX Mutex,
  56. ULONG Shared
  57. );
  58. VOID
  59. ClpReleaseNormalMutex (
  60. PPTHREAD_MUTEX Mutex,
  61. ULONG Shared
  62. );
  63. int
  64. ClpMutexIncrementAcquireCount (
  65. PPTHREAD_MUTEX Mutex
  66. );
  67. //
  68. // -------------------------------------------------------------------- Globals
  69. //
  70. //
  71. // ------------------------------------------------------------------ Functions
  72. //
  73. PTHREAD_API
  74. int
  75. pthread_mutex_init (
  76. pthread_mutex_t *Mutex,
  77. const pthread_mutexattr_t *Attribute
  78. )
  79. /*++
  80. Routine Description:
  81. This routine initializes a mutex.
  82. Arguments:
  83. Mutex - Supplies a pointer to the mutex to initialize.
  84. Attribute - Supplies an optional pointer to the initialized attributes to
  85. set in the mutex.
  86. Return Value:
  87. 0 on success.
  88. Returns an error number on failure.
  89. --*/
  90. {
  91. PPTHREAD_MUTEX_ATTRIBUTE AttributeInternal;
  92. ULONG Flags;
  93. PPTHREAD_MUTEX MutexInternal;
  94. ULONG State;
  95. MutexInternal = (PPTHREAD_MUTEX)Mutex;
  96. ASSERT(sizeof(pthread_mutex_t) >= sizeof(PTHREAD_MUTEX));
  97. memset(MutexInternal, 0, sizeof(PTHREAD_MUTEX));
  98. if (Attribute == NULL) {
  99. return 0;
  100. }
  101. AttributeInternal = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
  102. Flags = AttributeInternal->Flags;
  103. State = 0;
  104. if ((Flags & PTHREAD_MUTEX_SHARED) != 0) {
  105. State |= PTHREAD_MUTEX_STATE_SHARED;
  106. }
  107. switch (Flags & PTHREAD_MUTEX_TYPE_MASK) {
  108. case PTHREAD_MUTEX_NORMAL:
  109. break;
  110. case PTHREAD_MUTEX_RECURSIVE:
  111. State |= PTHREAD_MUTEX_STATE_RECURSIVE;
  112. break;
  113. case PTHREAD_MUTEX_ERRORCHECK:
  114. State |= PTHREAD_MUTEX_STATE_ERRORCHECK;
  115. break;
  116. default:
  117. return EINVAL;
  118. }
  119. MutexInternal->State = State;
  120. return 0;
  121. }
  122. PTHREAD_API
  123. int
  124. pthread_mutex_destroy (
  125. pthread_mutex_t *Mutex
  126. )
  127. /*++
  128. Routine Description:
  129. This routine destroys a mutex.
  130. Arguments:
  131. Mutex - Supplies a pointer to the mutex to destroy.
  132. Return Value:
  133. 0 on success.
  134. Returns an error number on failure.
  135. --*/
  136. {
  137. PPTHREAD_MUTEX MutexInternal;
  138. int Status;
  139. //
  140. // Try to acquire the lock to ensure it's not invalid and not already
  141. // locked.
  142. //
  143. Status = pthread_mutex_trylock(Mutex);
  144. if (Status != 0) {
  145. return Status;
  146. }
  147. MutexInternal = (PPTHREAD_MUTEX)Mutex;
  148. MutexInternal->State = -1;
  149. return Status;
  150. }
  151. PTHREAD_API
  152. int
  153. pthread_mutex_lock (
  154. pthread_mutex_t *Mutex
  155. )
  156. /*++
  157. Routine Description:
  158. This routine acquires a mutex.
  159. Arguments:
  160. Mutex - Supplies a pointer to the mutex to acquire.
  161. Return Value:
  162. 0 on success.
  163. Returns an error number on failure.
  164. --*/
  165. {
  166. PPTHREAD_MUTEX MutexInternal;
  167. ULONG MutexType;
  168. ULONG Shared;
  169. MutexInternal = (PPTHREAD_MUTEX)Mutex;
  170. MutexType = MutexInternal->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
  171. Shared = MutexInternal->State & PTHREAD_MUTEX_STATE_SHARED;
  172. if (MutexType == 0) {
  173. if (ClpTryToAcquireNormalMutex(MutexInternal, Shared) == 0) {
  174. return 0;
  175. }
  176. }
  177. return ClpAcquireMutexWithTimeout(MutexInternal, NULL, 0);
  178. }
  179. PTHREAD_API
  180. int
  181. pthread_mutex_unlock (
  182. pthread_mutex_t *Mutex
  183. )
  184. /*++
  185. Routine Description:
  186. This routine releases a mutex.
  187. Arguments:
  188. Mutex - Supplies a pointer to the mutex to release.
  189. Return Value:
  190. 0 on success.
  191. EPERM if this thread is not the thread that originally acquire the mutex.
  192. --*/
  193. {
  194. ULONG Count;
  195. ULONG Counter;
  196. PPTHREAD_MUTEX MutexInternal;
  197. ULONG MutexType;
  198. ULONG OldState;
  199. ULONG Operation;
  200. ULONG ReleasedState;
  201. ULONG Shared;
  202. UINTN ThreadId;
  203. MutexInternal = (PPTHREAD_MUTEX)Mutex;
  204. MutexType = MutexInternal->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
  205. Shared = MutexInternal->State & PTHREAD_MUTEX_STATE_SHARED;
  206. //
  207. // Do a fast release for normal locks.
  208. //
  209. if (MutexType == 0) {
  210. ClpReleaseNormalMutex(MutexInternal, Shared);
  211. return 0;
  212. }
  213. //
  214. // Check the ownership of the mutex.
  215. //
  216. ThreadId = OsGetThreadId();
  217. if (ThreadId != MutexInternal->Owner) {
  218. return EPERM;
  219. }
  220. //
  221. // If the counter is non-zero, just decrement it.
  222. //
  223. Counter = (MutexInternal->State >> PTHREAD_MUTEX_STATE_COUNTER_SHIFT) &
  224. PTHREAD_MUTEX_STATE_COUNTER_MASK;
  225. if (Counter != 0) {
  226. RtlAtomicAdd32(&(MutexInternal->State),
  227. 0 - (1 << PTHREAD_MUTEX_STATE_COUNTER_SHIFT));
  228. return 0;
  229. }
  230. //
  231. // Set the state to free, and release any waiters if contended.
  232. //
  233. MutexInternal->Owner = 0;
  234. ReleasedState = MutexType | Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
  235. OldState = RtlAtomicExchange32(&(MutexInternal->State), ReleasedState);
  236. if ((OldState & PTHREAD_MUTEX_STATE_MASK) ==
  237. PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS) {
  238. Operation = UserLockWake;
  239. if (Shared == 0) {
  240. Operation |= USER_LOCK_PRIVATE;
  241. }
  242. Count = 1;
  243. OsUserLock(&(MutexInternal->State), Operation, &Count, 0);
  244. }
  245. return 0;
  246. }
  247. PTHREAD_API
  248. int
  249. pthread_mutex_trylock (
  250. pthread_mutex_t *Mutex
  251. )
  252. /*++
  253. Routine Description:
  254. This routine attempts to acquire the given mutex once.
  255. Arguments:
  256. Mutex - Supplies a pointer to the mutex to attempt to acquire.
  257. Return Value:
  258. 0 on success.
  259. EBUSY if the mutex is already held by another thread and this is an error
  260. checking mutex.
  261. --*/
  262. {
  263. ULONG Locked;
  264. PPTHREAD_MUTEX MutexInternal;
  265. ULONG MutexType;
  266. ULONG OldState;
  267. ULONG Shared;
  268. UINTN ThreadId;
  269. ULONG Unlocked;
  270. MutexInternal = (PPTHREAD_MUTEX)Mutex;
  271. MutexType = MutexInternal->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
  272. Shared = MutexInternal->State & PTHREAD_MUTEX_STATE_SHARED;
  273. //
  274. // Handle the normal fast path.
  275. //
  276. if (MutexType == 0) {
  277. return ClpTryToAcquireNormalMutex(MutexInternal, Shared);
  278. }
  279. //
  280. // Determine if the thread already owns the mutex.
  281. //
  282. ThreadId = OsGetThreadId();
  283. if (MutexInternal->Owner == ThreadId) {
  284. if (MutexType == PTHREAD_MUTEX_STATE_ERRORCHECK) {
  285. return EBUSY;
  286. }
  287. return ClpMutexIncrementAcquireCount(MutexInternal);
  288. }
  289. Unlocked = MutexType | Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
  290. Locked = MutexType | Shared | PTHREAD_MUTEX_STATE_LOCKED;
  291. //
  292. // Try to go from unlocked to locked, which is the only case under which
  293. // this attempt could succeed.
  294. //
  295. OldState = RtlAtomicCompareExchange32(&(MutexInternal->State),
  296. Locked,
  297. Unlocked);
  298. //
  299. // If acquired, set the owner and return happily.
  300. //
  301. if (OldState == Unlocked) {
  302. MutexInternal->Owner = ThreadId;
  303. return 0;
  304. }
  305. return EBUSY;
  306. }
  307. PTHREAD_API
  308. int
  309. pthread_mutex_timedlock (
  310. pthread_mutex_t *Mutex,
  311. const struct timespec *AbsoluteTimeout
  312. )
  313. /*++
  314. Routine Description:
  315. This routine attempts to acquire a mutex, giving up after a specified
  316. deadline.
  317. Arguments:
  318. Mutex - Supplies a pointer to the mutex to acquire.
  319. AbsoluteTimeout - Supplies the absolute timeout after which the attempt
  320. shall fail and time out.
  321. Return Value:
  322. 0 on success.
  323. Returns an error number on failure.
  324. --*/
  325. {
  326. int Status;
  327. Status = ClpAcquireMutexWithTimeout((PPTHREAD_MUTEX)Mutex,
  328. AbsoluteTimeout,
  329. CLOCK_REALTIME);
  330. return Status;
  331. }
  332. PTHREAD_API
  333. int
  334. pthread_mutexattr_init (
  335. pthread_mutexattr_t *Attribute
  336. )
  337. /*++
  338. Routine Description:
  339. This routine initializes a mutex attribute object.
  340. Arguments:
  341. Attribute - Supplies a pointer to the attribute to initialize.
  342. Return Value:
  343. 0 on success.
  344. Returns an error number on failure.
  345. --*/
  346. {
  347. PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
  348. MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
  349. MutexAttribute->Flags = 0;
  350. return 0;
  351. }
  352. PTHREAD_API
  353. int
  354. pthread_mutexattr_destroy (
  355. pthread_mutexattr_t *Attribute
  356. )
  357. /*++
  358. Routine Description:
  359. This routine destroys a mutex attribute object.
  360. Arguments:
  361. Attribute - Supplies a pointer to the attribute to destroy.
  362. Return Value:
  363. 0 on success.
  364. Returns an error number on failure.
  365. --*/
  366. {
  367. PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
  368. MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
  369. MutexAttribute->Flags = -1;
  370. return 0;
  371. }
  372. PTHREAD_API
  373. int
  374. pthread_mutexattr_gettype (
  375. const pthread_mutexattr_t *Attribute,
  376. int *Type
  377. )
  378. /*++
  379. Routine Description:
  380. This routine returns the mutex type given an attribute that was previously
  381. set.
  382. Arguments:
  383. Attribute - Supplies a pointer to the attribute to get the type from.
  384. Type - Supplies a pointer where the mutex type will be returned on success.
  385. Return Value:
  386. 0 on success.
  387. Returns an error number on failure.
  388. --*/
  389. {
  390. PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
  391. INT MutexType;
  392. MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
  393. MutexType = MutexAttribute->Flags & PTHREAD_MUTEX_TYPE_MASK;
  394. if ((MutexType < PTHREAD_MUTEX_NORMAL) ||
  395. (MutexType > PTHREAD_MUTEX_RECURSIVE)) {
  396. return EINVAL;
  397. }
  398. *Type = MutexType;
  399. return 0;
  400. }
  401. PTHREAD_API
  402. int
  403. pthread_mutexattr_settype (
  404. pthread_mutexattr_t *Attribute,
  405. int Type
  406. )
  407. /*++
  408. Routine Description:
  409. This routine sets a mutex type in the given mutex attributes object.
  410. Arguments:
  411. Attribute - Supplies a pointer to the attribute to set the type in.
  412. Type - Supplies the mutex type to set. See PTHREAD_MUTEX_* definitions.
  413. Return Value:
  414. 0 on success.
  415. Returns an error number on failure.
  416. --*/
  417. {
  418. PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
  419. MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
  420. if ((Type < PTHREAD_MUTEX_NORMAL) || (Type > PTHREAD_MUTEX_RECURSIVE)) {
  421. return EINVAL;
  422. }
  423. MutexAttribute->Flags &= ~PTHREAD_MUTEX_TYPE_MASK;
  424. MutexAttribute->Flags |= Type;
  425. return 0;
  426. }
  427. PTHREAD_API
  428. int
  429. pthread_mutexattr_getpshared (
  430. const pthread_mutexattr_t *Attribute,
  431. int *Shared
  432. )
  433. /*++
  434. Routine Description:
  435. This routine returns the mutex sharing type given an attribute that was
  436. previously set.
  437. Arguments:
  438. Attribute - Supplies a pointer to the attribute to get the sharing
  439. information from.
  440. Shared - Supplies a pointer where the sharing type will be returned on
  441. success. See PTHREAD_PROCESS_* definitions.
  442. Return Value:
  443. 0 on success.
  444. Returns an error number on failure.
  445. --*/
  446. {
  447. PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
  448. MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
  449. *Shared = PTHREAD_PROCESS_PRIVATE;
  450. if ((MutexAttribute->Flags & PTHREAD_MUTEX_SHARED) != 0) {
  451. *Shared = PTHREAD_PROCESS_SHARED;
  452. }
  453. return 0;
  454. }
  455. PTHREAD_API
  456. int
  457. pthread_mutexattr_setpshared (
  458. pthread_mutexattr_t *Attribute,
  459. int Shared
  460. )
  461. /*++
  462. Routine Description:
  463. This routine sets a mutex sharing type in the given mutex attributes object.
  464. Arguments:
  465. Attribute - Supplies a pointer to the attribute to set the type in.
  466. Shared - Supplies the mutex type to set. See PTHREAD_PROCESS_* definitions.
  467. Return Value:
  468. 0 on success.
  469. Returns an error number on failure.
  470. --*/
  471. {
  472. PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
  473. int Status;
  474. MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
  475. Status = 0;
  476. switch (Shared) {
  477. case PTHREAD_PROCESS_SHARED:
  478. MutexAttribute->Flags |= PTHREAD_MUTEX_SHARED;
  479. break;
  480. case PTHREAD_PROCESS_PRIVATE:
  481. MutexAttribute->Flags &= ~PTHREAD_MUTEX_SHARED;
  482. break;
  483. default:
  484. Status = EINVAL;
  485. break;
  486. }
  487. return Status;
  488. }
  489. ULONG
  490. ClpConvertAbsoluteTimespecToRelativeMilliseconds (
  491. const struct timespec *AbsoluteTime,
  492. int Clock
  493. )
  494. /*++
  495. Routine Description:
  496. This routine converts an absolute timespec structure into a number of
  497. milliseconds from now.
  498. Arguments:
  499. AbsoluteTime - Supplies a pointer to the absolute timespec to convert.
  500. Clock - Supplies the clock to query from.
  501. Return Value:
  502. Returns the number of milliseconds from now the timespec expires in.
  503. 0 if the absolute time is in the past.
  504. --*/
  505. {
  506. struct timespec Delta;
  507. ULONG Result;
  508. time_t Seconds;
  509. int Status;
  510. Status = clock_gettime(Clock, &Delta);
  511. if (Status != 0) {
  512. return 0;
  513. }
  514. Delta.tv_sec = AbsoluteTime->tv_sec - Delta.tv_sec;
  515. Delta.tv_nsec = AbsoluteTime->tv_nsec - Delta.tv_nsec;
  516. if (Delta.tv_nsec < 0) {
  517. Delta.tv_sec -= 1;
  518. Delta.tv_nsec += NANOSECONDS_PER_SECOND;
  519. }
  520. if ((Delta.tv_nsec < 0) || (Delta.tv_sec < 0)) {
  521. return 0;
  522. }
  523. if (Delta.tv_nsec >= NANOSECONDS_PER_SECOND) {
  524. Seconds = Delta.tv_nsec / NANOSECONDS_PER_SECOND;
  525. Delta.tv_sec += Seconds;
  526. Delta.tv_nsec -= (Seconds * NANOSECONDS_PER_SECOND);
  527. }
  528. Status = ClpConvertSpecificTimeoutToSystemTimeout(&Delta, &Result);
  529. if (Status != 0) {
  530. return 0;
  531. }
  532. return Result;
  533. }
  534. //
  535. // --------------------------------------------------------- Internal Functions
  536. //
  537. int
  538. ClpAcquireMutexWithTimeout (
  539. PPTHREAD_MUTEX Mutex,
  540. const struct timespec *AbsoluteTimeout,
  541. clockid_t Clock
  542. )
  543. /*++
  544. Routine Description:
  545. This routine attempts to acquire a mutex with a timeout.
  546. Arguments:
  547. Mutex - Supplies a pointer to the mutex to acquire.
  548. AbsoluteTimeout - Supplies an optional pointer to the deadline in absolute
  549. time after which the operation should time out and fail.
  550. Clock - Supplies the clock to measure the timeout against.
  551. Return Value:
  552. 0 on success.
  553. Returns an error number on failure.
  554. --*/
  555. {
  556. KSTATUS KernelStatus;
  557. ULONG Locked;
  558. ULONG LockedWithWaiters;
  559. ULONG MutexType;
  560. ULONG NewState;
  561. ULONG OldState;
  562. ULONG Operation;
  563. ULONG Shared;
  564. UINTN ThreadId;
  565. ULONG TimeoutInMilliseconds;
  566. ULONG Unlocked;
  567. OldState = Mutex->State;
  568. MutexType = Mutex->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
  569. Shared = Mutex->State & PTHREAD_MUTEX_STATE_SHARED;
  570. //
  571. // Handle the fast-ish path for normal types.
  572. //
  573. if (MutexType == 0) {
  574. return ClpAcquireNormalMutex(Mutex, Shared, AbsoluteTimeout, Clock);
  575. }
  576. //
  577. // Determine if the thread already owns the mutex.
  578. //
  579. ThreadId = OsGetThreadId();
  580. if (ThreadId == Mutex->Owner) {
  581. if (MutexType == PTHREAD_MUTEX_STATE_ERRORCHECK) {
  582. return EDEADLK;
  583. }
  584. return ClpMutexIncrementAcquireCount(Mutex);
  585. }
  586. Unlocked = MutexType | Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
  587. Locked = MutexType | Shared | PTHREAD_MUTEX_STATE_LOCKED;
  588. LockedWithWaiters = MutexType | Shared |
  589. PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
  590. //
  591. // Take an optimistic stab at acquiring the lock assuming it's uncontended.
  592. // If this works, then it gets left as locked (without waiters), which
  593. // makes the release operation lightweight.
  594. //
  595. if (OldState == Unlocked) {
  596. OldState = RtlAtomicCompareExchange32(&(Mutex->State),
  597. Locked,
  598. Unlocked);
  599. if (OldState == Unlocked) {
  600. Mutex->Owner = ThreadId;
  601. return 0;
  602. }
  603. }
  604. //
  605. // Contend for the mutex.
  606. //
  607. while (TRUE) {
  608. if (OldState == Unlocked) {
  609. //
  610. // Attempt to go from unlocked to locked with waiters. Being inside
  611. // this loop means there are definitely other threads bouncing
  612. // around here, so going directly to locked with waiters saves them
  613. // the trouble of having to go from locked to locked with waiters.
  614. //
  615. OldState = RtlAtomicCompareExchange32(&(Mutex->State),
  616. LockedWithWaiters,
  617. OldState);
  618. if (OldState == Unlocked) {
  619. Mutex->Owner = ThreadId;
  620. return 0;
  621. }
  622. continue;
  623. //
  624. // If the mutex is locked (without waiters), set it to locked with
  625. // with waiters to tell whoever does have it that they need to wake
  626. // this thread up. The comparison cannot simply be against the locked
  627. // local variable because a recursive lock may have added to the
  628. // counter.
  629. //
  630. } else if ((OldState & PTHREAD_MUTEX_STATE_MASK) ==
  631. PTHREAD_MUTEX_STATE_LOCKED) {
  632. NewState = (OldState & ~PTHREAD_MUTEX_STATE_MASK) |
  633. PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
  634. OldState = RtlAtomicCompareExchange32(&(Mutex->State),
  635. NewState,
  636. OldState);
  637. continue;
  638. }
  639. ASSERT((OldState & PTHREAD_MUTEX_STATE_MASK) ==
  640. PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS);
  641. if (AbsoluteTimeout != NULL) {
  642. TimeoutInMilliseconds =
  643. ClpConvertAbsoluteTimespecToRelativeMilliseconds(
  644. AbsoluteTimeout,
  645. Clock);
  646. if (TimeoutInMilliseconds == 0) {
  647. return ETIMEDOUT;
  648. }
  649. } else {
  650. TimeoutInMilliseconds = SYS_WAIT_TIME_INDEFINITE;
  651. }
  652. //
  653. // Call the kernel to go down for a wait.
  654. //
  655. Operation = UserLockWait;
  656. if (Shared == 0) {
  657. Operation |= USER_LOCK_PRIVATE;
  658. }
  659. KernelStatus = OsUserLock(&(Mutex->State),
  660. Operation,
  661. &OldState,
  662. TimeoutInMilliseconds);
  663. if (KernelStatus == STATUS_TIMEOUT) {
  664. return ETIMEDOUT;
  665. }
  666. OldState = Mutex->State;
  667. }
  668. //
  669. // This code is never reached.
  670. //
  671. ASSERT(FALSE);
  672. return EINVAL;
  673. }
  674. int
  675. ClpAcquireNormalMutex (
  676. PPTHREAD_MUTEX Mutex,
  677. ULONG Shared,
  678. const struct timespec *AbsoluteTimeout,
  679. INT Clock
  680. )
  681. /*++
  682. Routine Description:
  683. This routine acquires a normal mutex. That is one without any recursive or
  684. error checking attributes.
  685. Arguments:
  686. Mutex - Supplies a pointer to the mutex to acquire.
  687. Shared - Supplies the shared flag for the mutex.
  688. AbsoluteTimeout - Supplies an optional pointer to the absolute timeout for
  689. the operation.
  690. Clock - Supplies the clock source.
  691. Return Value:
  692. 0 if the lock was acquired.
  693. Returns an error code on failure or timeout.
  694. --*/
  695. {
  696. KSTATUS KernelStatus;
  697. ULONG LockedWithWaiters;
  698. ULONG OldState;
  699. ULONG Operation;
  700. ULONG TimeoutInMilliseconds;
  701. ULONG Unlocked;
  702. //
  703. // Give it a quick fast attempt first.
  704. //
  705. if (ClpTryToAcquireNormalMutex(Mutex, Shared) == 0) {
  706. return 0;
  707. }
  708. LockedWithWaiters = Shared | PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
  709. Unlocked = Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
  710. //
  711. // Set the lock to acquired with waiters (since the quick attempt above
  712. // failed).
  713. //
  714. while (TRUE) {
  715. OldState = RtlAtomicExchange32(&(Mutex->State), LockedWithWaiters);
  716. //
  717. // If the lock was acquired, break out for success.
  718. //
  719. if (OldState == Unlocked) {
  720. break;
  721. }
  722. if (AbsoluteTimeout != NULL) {
  723. TimeoutInMilliseconds =
  724. ClpConvertAbsoluteTimespecToRelativeMilliseconds(
  725. AbsoluteTimeout,
  726. Clock);
  727. if (TimeoutInMilliseconds == 0) {
  728. return ETIMEDOUT;
  729. }
  730. } else {
  731. TimeoutInMilliseconds = SYS_WAIT_TIME_INDEFINITE;
  732. }
  733. //
  734. // Call the kernel to go down for a wait.
  735. //
  736. Operation = UserLockWait;
  737. if (Shared == 0) {
  738. Operation |= USER_LOCK_PRIVATE;
  739. }
  740. OldState = LockedWithWaiters;
  741. KernelStatus = OsUserLock(&(Mutex->State),
  742. Operation,
  743. &OldState,
  744. TimeoutInMilliseconds);
  745. if (KernelStatus == STATUS_TIMEOUT) {
  746. return ETIMEDOUT;
  747. }
  748. }
  749. return 0;
  750. }
  751. int
  752. ClpTryToAcquireNormalMutex (
  753. PPTHREAD_MUTEX Mutex,
  754. ULONG Shared
  755. )
  756. /*++
  757. Routine Description:
  758. This routine performs a single non-blocking attempt at acquiring a mutex
  759. without any fancy attributes like error checking or recursion.
  760. Arguments:
  761. Mutex - Supplies a pointer to the mutex to attempt to acquire.
  762. Shared - Supplies the shared flag for the mutex.
  763. Return Value:
  764. 0 if the mutex was acquired.
  765. EBUSY if the mutex was not successfully acquired.
  766. --*/
  767. {
  768. ULONG Locked;
  769. ULONG OldState;
  770. ULONG Unlocked;
  771. Locked = Shared | PTHREAD_MUTEX_STATE_LOCKED;
  772. Unlocked = Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
  773. OldState = RtlAtomicCompareExchange32(&(Mutex->State), Locked, Unlocked);
  774. if (OldState == Unlocked) {
  775. return 0;
  776. }
  777. return EBUSY;
  778. }
  779. VOID
  780. ClpReleaseNormalMutex (
  781. PPTHREAD_MUTEX Mutex,
  782. ULONG Shared
  783. )
  784. /*++
  785. Routine Description:
  786. This routine releases a mutex without any recursive or error checking
  787. attributes.
  788. Arguments:
  789. Mutex - Supplies a pointer to the mutex to release.
  790. Shared - Supplies the shared flag for the mutex.
  791. Return Value:
  792. None.
  793. --*/
  794. {
  795. ULONG Count;
  796. ULONG LockedWithWaiters;
  797. ULONG OldState;
  798. ULONG Operation;
  799. ULONG Unlocked;
  800. Unlocked = Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
  801. LockedWithWaiters = Shared | PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
  802. //
  803. // Exchange out the state to unlocked. If it had waiters, wake them up.
  804. //
  805. OldState = RtlAtomicExchange32(&(Mutex->State), Unlocked);
  806. if (OldState == LockedWithWaiters) {
  807. Operation = UserLockWake;
  808. if (Shared == 0) {
  809. Operation |= USER_LOCK_PRIVATE;
  810. }
  811. Count = 1;
  812. OsUserLock(&(Mutex->State), Operation, &Count, 0);
  813. }
  814. return;
  815. }
  816. int
  817. ClpMutexIncrementAcquireCount (
  818. PPTHREAD_MUTEX Mutex
  819. )
  820. /*++
  821. Routine Description:
  822. This routine increments the acquire count on a mutex that's already held
  823. by the current thread.
  824. Arguments:
  825. Mutex - Supplies a pointer to the mutex to increment.
  826. Return Value:
  827. 0 on success.
  828. EAGAIN if the maximum number of recursive acquires was reached (the
  829. internal counter would overflow).
  830. --*/
  831. {
  832. ULONG Count;
  833. Count = (Mutex->State >> PTHREAD_MUTEX_STATE_COUNTER_SHIFT) &
  834. PTHREAD_MUTEX_STATE_COUNTER_MASK;
  835. if (Count == PTHREAD_MUTEX_STATE_COUNTER_MAX) {
  836. return EAGAIN;
  837. }
  838. //
  839. // Since other threads might be atomically changing the lower bits, the
  840. // atomic add is necessary.
  841. //
  842. RtlAtomicAdd32(&(Mutex->State), 1 << PTHREAD_MUTEX_STATE_COUNTER_SHIFT);
  843. return 0;
  844. }