jmutex.hpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #ifndef __JMUTEX__
  14. #define __JMUTEX__
  15. #include <assert.h>
  16. #include "jiface.hpp"
  17. #include "jsem.hpp"
  18. extern jlib_decl void ThreadYield();
  19. #ifdef _DEBUG
  20. //#define SPINLOCK_USE_MUTEX // for testing
  21. //#define SPINLOCK_RR_CHECK // checks for realtime threads
  22. #define _ASSERT_LOCK_SUPPORT
  23. #endif
  24. #ifdef SPINLOCK_USE_MUTEX
  25. #define NRESPINLOCK_USE_SPINLOCK
  26. #endif
  27. #if (_WIN32 || ((__GNUC__ < 4 || (__GNUC_MINOR__ < 1 && __GNUC__ == 4)) || (!defined(__x86_64__) && !defined(__i386__))))
  28. #define NRESPINLOCK_USE_SPINLOCK
  29. #endif
  30. #ifdef _WIN32
  31. class jlib_decl Mutex
  32. {
  33. protected:
  34. Mutex(const char *name)
  35. {
  36. mutex = CreateMutex(NULL, FALSE, name);
  37. assertex(mutex);
  38. lockcount = 0;
  39. owner = 0;
  40. }
  41. public:
  42. Mutex()
  43. {
  44. mutex = CreateMutex(NULL, FALSE, NULL);
  45. lockcount = 0;
  46. owner = 0;
  47. }
  48. ~Mutex()
  49. {
  50. if (owner != 0)
  51. printf("Warning - Owned mutex destroyed"); // can't use PrintLog here!
  52. CloseHandle(mutex);
  53. }
  54. void lock()
  55. {
  56. WaitForSingleObject(mutex, INFINITE);
  57. if (lockcount) {
  58. if(owner!=GetCurrentThreadId()) // I think only way this can happen is with unhandled thread exception
  59. lockcount = 0; // (don't assert as unhandled error may get lost)
  60. }
  61. lockcount++;
  62. owner=GetCurrentThreadId();
  63. }
  64. bool lockWait(unsigned timeout)
  65. {
  66. if (WaitForSingleObject(mutex, (long)timeout)!=WAIT_OBJECT_0)
  67. return false;
  68. if (lockcount) {
  69. if(owner!=GetCurrentThreadId()) // I think only way this can happen is with unhandled thread exception
  70. lockcount = 0; // (don't assert as unhandled error may get lost)
  71. }
  72. lockcount++;
  73. owner=GetCurrentThreadId();
  74. return true;
  75. }
  76. void unlock()
  77. {
  78. assertex(owner==GetCurrentThreadId());
  79. --lockcount;
  80. if (lockcount==0)
  81. owner = 0;
  82. ReleaseMutex(mutex);
  83. }
  84. protected:
  85. MutexId mutex;
  86. ThreadId owner;
  87. int unlockAll()
  88. {
  89. assertex(owner==GetCurrentThreadId());
  90. assertex(lockcount);
  91. int ret = lockcount;
  92. int lc = ret;
  93. while (lc--)
  94. unlock();
  95. return ret;
  96. }
  97. void lockAll(int count)
  98. {
  99. while (count--)
  100. lock();
  101. }
  102. private:
  103. int lockcount;
  104. };
  105. class jlib_decl NamedMutex: public Mutex
  106. {
  107. public:
  108. NamedMutex(const char *name)
  109. : Mutex(name)
  110. {
  111. }
  112. };
  113. #else // posix
  114. class jlib_decl Mutex
  115. {
  116. public:
  117. Mutex();
  118. // Mutex(const char *name); //not supported
  119. ~Mutex();
  120. void lock();
  121. bool lockWait(unsigned timeout);
  122. void unlock();
  123. protected:
  124. MutexId mutex;
  125. ThreadId owner;
  126. int unlockAll();
  127. void lockAll(int);
  128. private:
  129. int lockcount;
  130. pthread_cond_t lock_free;
  131. };
  132. class jlib_decl NamedMutex
  133. {
  134. public:
  135. NamedMutex(const char *name);
  136. ~NamedMutex();
  137. void lock();
  138. bool lockWait(unsigned timeout);
  139. void unlock();
  140. private:
  141. Mutex threadmutex;
  142. char *mutexfname;
  143. };
  144. #endif
  145. class jlib_decl synchronized
  146. {
  147. private:
  148. Mutex &mutex;
  149. void throwLockException(unsigned timeout);
  150. public:
  151. synchronized(Mutex &m) : mutex(m) { mutex.lock(); };
  152. synchronized(Mutex &m,unsigned timeout) : mutex(m) { if(!mutex.lockWait(timeout)) throwLockException(timeout); }
  153. inline ~synchronized() { mutex.unlock(); };
  154. };
  155. #ifdef _WIN32
  156. extern "C" {
  157. WINBASEAPI
  158. BOOL
  159. WINAPI
  160. TryEnterCriticalSection(
  161. IN OUT LPCRITICAL_SECTION lpCriticalSection
  162. );
  163. };
  164. class jlib_decl CriticalSection
  165. {
  166. // lightweight mutex within a single process
  167. private:
  168. CRITICAL_SECTION flags;
  169. #ifdef _ASSERT_LOCK_SUPPORT
  170. ThreadId owner;
  171. unsigned depth;
  172. #endif
  173. inline CriticalSection(CriticalSection & value) { assert(false); } // dummy to prevent inadvertant use as block
  174. public:
  175. inline CriticalSection()
  176. {
  177. InitializeCriticalSection(&flags);
  178. #ifdef _ASSERT_LOCK_SUPPORT
  179. owner = 0;
  180. depth = 0;
  181. #endif
  182. };
  183. inline ~CriticalSection()
  184. {
  185. #ifdef _ASSERT_LOCK_SUPPORT
  186. assertex(owner==0 && depth==0);
  187. #endif
  188. DeleteCriticalSection(&flags);
  189. };
  190. inline void enter()
  191. {
  192. EnterCriticalSection(&flags);
  193. #ifdef _ASSERT_LOCK_SUPPORT
  194. if (owner)
  195. {
  196. assertex(owner==GetCurrentThreadId());
  197. depth++;
  198. }
  199. else
  200. owner = GetCurrentThreadId();
  201. #endif
  202. };
  203. inline void leave()
  204. {
  205. #ifdef _ASSERT_LOCK_SUPPORT
  206. assertex(owner==GetCurrentThreadId());
  207. if (depth)
  208. depth--;
  209. else
  210. owner = 0;
  211. #endif
  212. LeaveCriticalSection(&flags);
  213. };
  214. inline void assertLocked()
  215. {
  216. #ifdef _ASSERT_LOCK_SUPPORT
  217. assertex(owner == GetCurrentThreadId());
  218. #endif
  219. }
  220. #ifdef ENABLE_CHECKEDCRITICALSECTIONS
  221. bool wouldBlock() { if (TryEnterCriticalSection(&flags)) { leave(); return false; } return true; } // debug only
  222. #endif
  223. };
  224. #else
  225. /**
  226. * Mutex locking wrapper. Use enter/leave to lock/unlock.
  227. */
  228. class CriticalSection
  229. {
  230. private:
  231. MutexId mutex;
  232. #ifdef _ASSERT_LOCK_SUPPORT
  233. ThreadId owner;
  234. unsigned depth;
  235. #endif
  236. CriticalSection (const CriticalSection &);
  237. public:
  238. inline CriticalSection()
  239. {
  240. pthread_mutexattr_t attr;
  241. pthread_mutexattr_init(&attr);
  242. #ifdef _DEBUG
  243. verifyex(pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE)==0); // verify supports attr
  244. #else
  245. pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
  246. #endif
  247. pthread_mutex_init(&mutex, &attr);
  248. pthread_mutexattr_destroy(&attr);
  249. #ifdef _ASSERT_LOCK_SUPPORT
  250. owner = 0;
  251. depth = 0;
  252. #endif
  253. }
  254. inline ~CriticalSection()
  255. {
  256. #ifdef _ASSERT_LOCK_SUPPORT
  257. assertex(owner==0 && depth==0);
  258. #endif
  259. pthread_mutex_destroy(&mutex);
  260. }
  261. inline void enter()
  262. {
  263. pthread_mutex_lock(&mutex);
  264. #ifdef _ASSERT_LOCK_SUPPORT
  265. if (owner)
  266. {
  267. assertex(owner==GetCurrentThreadId());
  268. depth++;
  269. }
  270. else
  271. owner = GetCurrentThreadId();
  272. #endif
  273. }
  274. inline void leave()
  275. {
  276. #ifdef _ASSERT_LOCK_SUPPORT
  277. assertex(owner==GetCurrentThreadId());
  278. if (depth)
  279. depth--;
  280. else
  281. owner = 0;
  282. #endif
  283. pthread_mutex_unlock(&mutex);
  284. }
  285. inline void assertLocked()
  286. {
  287. #ifdef _ASSERT_LOCK_SUPPORT
  288. assertex(owner == GetCurrentThreadId());
  289. #endif
  290. }
  291. };
  292. #endif
  293. /**
  294. * Critical section delimiter, using scope to define lifetime of
  295. * the lock on a critical section (parameter).
  296. * Blocks on construction, unblocks on destruction.
  297. */
  298. class CriticalBlock
  299. {
  300. CriticalSection &crit;
  301. public:
  302. inline CriticalBlock(CriticalSection &c) : crit(c) { crit.enter(); }
  303. inline ~CriticalBlock() { crit.leave(); }
  304. };
  305. /**
  306. * Critical section delimiter, using scope to define lifetime of
  307. * the lock on a critical section (parameter).
  308. * Unblocks on construction, blocks on destruction.
  309. */
  310. class CriticalUnblock
  311. {
  312. CriticalSection &crit;
  313. public:
  314. inline CriticalUnblock(CriticalSection &c) : crit(c) { crit.leave(); }
  315. inline ~CriticalUnblock() { crit.enter(); }
  316. };
  317. #ifdef SPINLOCK_USE_MUTEX // for testing
  318. class SpinLock
  319. {
  320. CriticalSection sect;
  321. public:
  322. inline void enter()
  323. {
  324. sect.enter();
  325. }
  326. inline void leave()
  327. {
  328. sect.leave();
  329. }
  330. };
  331. #else
  332. class jlib_decl SpinLock
  333. {
  334. atomic_t value;
  335. unsigned nesting; // not volatile since it is only accessed by one thread at a time
  336. struct { volatile ThreadId tid; } owner;
  337. inline SpinLock(SpinLock & value) { assert(false); } // dummy to prevent inadvetant use as block
  338. public:
  339. inline SpinLock()
  340. {
  341. owner.tid = 0;
  342. nesting = 0;
  343. atomic_set(&value, 0);
  344. }
  345. #ifdef _DEBUG
  346. ~SpinLock()
  347. {
  348. if (atomic_read(&value))
  349. printf("Warning - Owned Spinlock destroyed"); // can't use PrintLog here!
  350. }
  351. #endif
  352. inline void enter()
  353. {
  354. ThreadId self = GetCurrentThreadId();
  355. #ifdef SPINLOCK_RR_CHECK // as requested by RKC
  356. int policy;
  357. sched_param param;
  358. if ((pthread_getschedparam(self, &policy, &param)==0)&&(policy==SCHED_RR)) {
  359. param.sched_priority = 0;
  360. pthread_setschedparam(self, SCHED_OTHER, &param); // otherwise will likely re-enter
  361. assertex(!"SpinLock enter on SCHED_RR thread");
  362. }
  363. #endif
  364. if (self==owner.tid) { // this is atomic
  365. #ifdef _DEBUG
  366. assertex(atomic_read(&value));
  367. #endif
  368. nesting++;
  369. return;
  370. }
  371. while (!atomic_cas(&value,1,0))
  372. ThreadYield();
  373. owner.tid = self;
  374. }
  375. inline void leave()
  376. {
  377. //It is safe to access nesting - since this thread is the only one that can access
  378. //it, so no need for a synchronized access
  379. if (nesting == 0)
  380. {
  381. owner.tid = 0;
  382. //Ensure that no code that precedes the setting of value gets moved after it
  383. //(unlikely since code is conditional and owner.tid is also volatile)
  384. compiler_memory_barrier();
  385. atomic_set(&value, 0);
  386. }
  387. else
  388. nesting--;
  389. }
  390. };
  391. #endif
  392. class SpinBlock
  393. {
  394. SpinLock &lock;
  395. public:
  396. inline SpinBlock(SpinLock & _lock) : lock(_lock) { lock.enter(); }
  397. inline ~SpinBlock() { lock.leave(); }
  398. };
  399. class SpinUnblock
  400. {
  401. SpinLock &lock;
  402. public:
  403. inline SpinUnblock(SpinLock & _lock) : lock(_lock) { lock.leave(); }
  404. inline ~SpinUnblock() { lock.enter(); }
  405. };
  406. // Non re-entrant Spin locks where *absolutely* certain enters are not nested on same thread
  407. // (debug version checks and asserts if are, release version will deadlock
  408. #ifdef NRESPINLOCK_USE_SPINLOCK
  409. class jlib_decl NonReentrantSpinLock: public SpinLock
  410. {
  411. };
  412. #else
  413. #ifdef _DEBUG
  414. class jlib_decl NonReentrantSpinLock
  415. {
  416. atomic_t value;
  417. struct { volatile ThreadId tid; } owner; // atomic
  418. inline NonReentrantSpinLock(NonReentrantSpinLock & value) { assert(false); } // dummy to prevent inadvertent use as block
  419. public:
  420. inline NonReentrantSpinLock()
  421. {
  422. owner.tid = 0;
  423. atomic_set(&value, 0);
  424. }
  425. inline void enter()
  426. {
  427. ThreadId self = GetCurrentThreadId();
  428. assertex(self!=owner.tid); // check for reentrancy
  429. while (!atomic_cas(&value,1,0))
  430. ThreadYield();
  431. owner.tid = self;
  432. }
  433. inline void leave()
  434. {
  435. assertex(GetCurrentThreadId()==owner.tid); // check for spurious leave
  436. owner.tid = 0;
  437. //Ensure that no code that precedes the leave() gets moved after value is cleared
  438. compiler_memory_barrier();
  439. atomic_set(&value, 0);
  440. }
  441. };
  442. #else
  443. class jlib_decl NonReentrantSpinLock
  444. {
  445. atomic_t value;
  446. inline NonReentrantSpinLock(NonReentrantSpinLock & value) { assert(false); } // dummy to prevent inadvertent use as block
  447. public:
  448. inline NonReentrantSpinLock()
  449. {
  450. atomic_set(&value, 0);
  451. }
  452. inline void enter()
  453. {
  454. while (!atomic_cas(&value,1,0))
  455. ThreadYield();
  456. }
  457. inline void leave()
  458. {
  459. //Ensure that no code that precedes the leave() gets moved after value is cleared
  460. compiler_memory_barrier();
  461. atomic_set(&value, 0);
  462. }
  463. };
  464. #endif
  465. #endif
  466. class NonReentrantSpinBlock
  467. {
  468. NonReentrantSpinLock &lock;
  469. public:
  470. inline NonReentrantSpinBlock(NonReentrantSpinLock & _lock) : lock(_lock) { lock.enter(); }
  471. inline ~NonReentrantSpinBlock() { lock.leave(); }
  472. };
  473. class NonReentrantSpinUnblock
  474. {
  475. NonReentrantSpinLock &lock;
  476. public:
  477. inline NonReentrantSpinUnblock(NonReentrantSpinLock & _lock) : lock(_lock) { lock.leave(); }
  478. inline ~NonReentrantSpinUnblock() { lock.enter(); }
  479. };
  480. class jlib_decl Monitor: public Mutex
  481. {
  482. // Like a java object - you can synchronize on it for a block, wait for a notify on it, or notify on it
  483. Semaphore *sem;
  484. int waiting;
  485. void *last;
  486. public:
  487. Monitor() : Mutex() { sem = new Semaphore(); waiting = 0; last = NULL; }
  488. // Monitor(const char *name) : Mutex(name) { sem = new Semaphore(name); waiting = 0; last = NULL; } // not supported
  489. ~Monitor() {delete sem;};
  490. void wait(); // only called when locked
  491. void notify(); // only called when locked
  492. void notifyAll(); // only called when locked -- notifys for all waiting threads
  493. };
  494. class jlib_decl ReadWriteLock
  495. {
  496. bool lockRead(bool timed, unsigned timeout) {
  497. cs.enter();
  498. if (writeLocks == 0)
  499. {
  500. readLocks++;
  501. cs.leave();
  502. }
  503. else
  504. {
  505. readWaiting++;
  506. cs.leave();
  507. if (timed)
  508. {
  509. if (!readSem.wait(timeout)) {
  510. cs.enter();
  511. if (!readSem.wait(0)) {
  512. readWaiting--;
  513. cs.leave();
  514. return false;
  515. }
  516. cs.leave();
  517. }
  518. }
  519. else
  520. readSem.wait();
  521. //NB: waiting and locks adjusted before the signal occurs.
  522. }
  523. return true;
  524. }
  525. bool lockWrite(bool timed, unsigned timeout) {
  526. cs.enter();
  527. if ((readLocks == 0) && (writeLocks == 0))
  528. {
  529. writeLocks++;
  530. cs.leave();
  531. }
  532. else
  533. {
  534. writeWaiting++;
  535. cs.leave();
  536. if (timed)
  537. {
  538. if (!writeSem.wait(timeout)) {
  539. cs.enter();
  540. if (!writeSem.wait(0)) {
  541. writeWaiting--;
  542. cs.leave();
  543. return false;
  544. }
  545. cs.leave();
  546. }
  547. }
  548. else
  549. writeSem.wait();
  550. //NB: waiting and locks adjusted before the signal occurs.
  551. }
  552. #ifdef _DEBUG
  553. exclWriteOwner = GetCurrentThreadId();
  554. #endif
  555. return true;
  556. }
  557. public:
  558. ReadWriteLock()
  559. {
  560. readLocks = 0; writeLocks = 0; readWaiting = 0; writeWaiting = 0;
  561. #ifdef _DEBUG
  562. exclWriteOwner = 0;
  563. #endif
  564. }
  565. ~ReadWriteLock() { assertex(readLocks == 0 && writeLocks == 0); }
  566. void lockRead() { lockRead(false, 0); }
  567. void lockWrite() { lockWrite(false, 0); }
  568. bool lockRead(unsigned timeout) { return lockRead(true, timeout); }
  569. bool lockWrite(unsigned timeout) { return lockWrite(true, timeout); }
  570. void unlock() {
  571. cs.enter();
  572. if (readLocks) readLocks--;
  573. else
  574. {
  575. writeLocks--;
  576. #ifdef _DEBUG
  577. exclWriteOwner = 0;
  578. #endif
  579. }
  580. assertex(writeLocks == 0);
  581. if (readLocks == 0)
  582. {
  583. if (readWaiting)
  584. {
  585. unsigned numWaiting = readWaiting;
  586. readWaiting = 0;
  587. readLocks += numWaiting;
  588. readSem.signal(numWaiting);
  589. }
  590. else if (writeWaiting)
  591. {
  592. writeWaiting--;
  593. writeLocks++;
  594. writeSem.signal();
  595. }
  596. }
  597. cs.leave();
  598. }
  599. bool queryWriteLocked() { return (writeLocks != 0); }
  600. void unlockRead() { unlock(); }
  601. void unlockWrite() { unlock(); }
  602. //MORE: May want to use the pthread implementations under linux.
  603. protected:
  604. CriticalSection cs;
  605. Semaphore readSem;
  606. Semaphore writeSem;
  607. unsigned readLocks;
  608. unsigned writeLocks;
  609. unsigned readWaiting;
  610. unsigned writeWaiting;
  611. #ifdef _DEBUG
  612. ThreadId exclWriteOwner;
  613. #endif
  614. };
  615. class ReadLockBlock
  616. {
  617. ReadWriteLock *lock;
  618. public:
  619. ReadLockBlock(ReadWriteLock &l) : lock(&l) { lock->lockRead(); }
  620. ~ReadLockBlock() { if (lock) lock->unlockRead(); }
  621. void clear()
  622. {
  623. if (lock)
  624. {
  625. lock->unlockRead();
  626. lock = NULL;
  627. }
  628. }
  629. };
  630. class WriteLockBlock
  631. {
  632. ReadWriteLock *lock;
  633. public:
  634. WriteLockBlock(ReadWriteLock &l) : lock(&l) { lock->lockWrite(); }
  635. ~WriteLockBlock() { if (lock) lock->unlockWrite(); }
  636. void clear()
  637. {
  638. if (lock)
  639. {
  640. lock->unlockWrite();
  641. lock = NULL;
  642. }
  643. }
  644. };
  645. class Barrier
  646. {
  647. CriticalSection crit;
  648. int limit, remaining, waiting;
  649. Semaphore sem;
  650. public:
  651. Barrier(int _limit) { init(_limit); }
  652. Barrier() { init(0); }
  653. void init(int _limit)
  654. {
  655. waiting = 0;
  656. limit = _limit;
  657. remaining = limit;
  658. }
  659. void wait() // blocks until 'limit' barrier points are entered.
  660. {
  661. CriticalBlock block(crit);
  662. while (remaining==0) {
  663. if (waiting) {
  664. crit.leave();
  665. ThreadYield();
  666. crit.enter();
  667. }
  668. else
  669. remaining = limit;
  670. }
  671. remaining--;
  672. if (remaining==0)
  673. sem.signal(waiting);
  674. else if (remaining>0) {
  675. waiting++;
  676. crit.leave();
  677. sem.wait();
  678. crit.enter();
  679. waiting--;
  680. }
  681. }
  682. void abort()
  683. {
  684. CriticalBlock block(crit);
  685. remaining = -1;
  686. sem.signal(waiting);
  687. }
  688. void cancel(int n, bool remove) // cancel n barrier points from this instance, if remove=true reduces barrier width
  689. {
  690. CriticalBlock block(crit);
  691. while (remaining==0) {
  692. if (waiting) {
  693. crit.leave();
  694. ThreadYield();
  695. crit.enter();
  696. }
  697. else
  698. remaining = limit;
  699. }
  700. assertex(remaining>=n);
  701. remaining-=n;
  702. if (remaining==0)
  703. sem.signal(waiting);
  704. if (remove)
  705. limit-=n;
  706. }
  707. };
  708. // checked versions of critical block and readwrite blocks - report deadlocks
  709. #define USECHECKEDCRITICALSECTIONS
  710. #ifdef USECHECKEDCRITICALSECTIONS
  711. typedef Mutex CheckedCriticalSection;
  712. void jlib_decl checkedCritEnter(CheckedCriticalSection &crit, unsigned timeout, const char *fname, unsigned lnum);
  713. void jlib_decl checkedCritLeave(CheckedCriticalSection &crit);
  714. class jlib_decl CheckedCriticalBlock
  715. {
  716. CheckedCriticalSection &crit;
  717. public:
  718. CheckedCriticalBlock(CheckedCriticalSection &c, unsigned timeout, const char *fname,unsigned lnum);
  719. ~CheckedCriticalBlock()
  720. {
  721. crit.unlock();
  722. }
  723. };
  724. class jlib_decl CheckedCriticalUnblock
  725. {
  726. CheckedCriticalSection &crit;
  727. const char *fname;
  728. unsigned lnum;
  729. unsigned timeout;
  730. public:
  731. CheckedCriticalUnblock(CheckedCriticalSection &c,unsigned _timeout,const char *_fname,unsigned _lnum)
  732. : crit(c)
  733. {
  734. timeout = _timeout;
  735. fname = _fname;
  736. lnum = _lnum;
  737. crit.unlock();
  738. }
  739. ~CheckedCriticalUnblock();
  740. };
  741. #define CHECKEDCRITICALBLOCK(sect,timeout) CheckedCriticalBlock glue(block,__LINE__)(sect,timeout,__FILE__,__LINE__)
  742. #define CHECKEDCRITICALUNBLOCK(sect,timeout) CheckedCriticalUnblock glue(unblock,__LINE__)(sect,timeout,__FILE__,__LINE__)
  743. #define CHECKEDCRITENTER(sect,timeout) checkedCritEnter(sect,timeout,__FILE__,__LINE__)
  744. #define CHECKEDCRITLEAVE(sect) checkedCritLeave(sect)
  745. class jlib_decl CheckedReadLockBlock
  746. {
  747. ReadWriteLock &lock;
  748. public:
  749. CheckedReadLockBlock(ReadWriteLock &l, unsigned timeout, const char *fname,unsigned lnum);
  750. ~CheckedReadLockBlock() { lock.unlockRead(); }
  751. };
  752. class jlib_decl CheckedWriteLockBlock
  753. {
  754. ReadWriteLock &lock;
  755. public:
  756. CheckedWriteLockBlock(ReadWriteLock &l, unsigned timeout, const char *fname, unsigned lnum);
  757. ~CheckedWriteLockBlock() { lock.unlockWrite(); }
  758. };
  759. void jlib_decl checkedReadLockEnter(ReadWriteLock &l, unsigned timeout, const char *fname, unsigned lnum);
  760. void jlib_decl checkedWriteLockEnter(ReadWriteLock &l, unsigned timeout, const char *fname, unsigned lnum);
  761. #define CHECKEDREADLOCKBLOCK(l,timeout) CheckedReadLockBlock glue(block,__LINE__)(l,timeout,__FILE__,__LINE__)
  762. #define CHECKEDWRITELOCKBLOCK(l,timeout) CheckedWriteLockBlock glue(block,__LINE__)(l,timeout,__FILE__,__LINE__)
  763. #define CHECKEDREADLOCKENTER(l,timeout) checkedReadLockEnter(l,timeout,__FILE__,__LINE__)
  764. #define CHECKEDWRITELOCKENTER(l,timeout) checkedWriteLockEnter(l,timeout,__FILE__,__LINE__)
  765. #else
  766. #define CheckedCriticalSection CriticalSection
  767. #define CheckedCriticalBlock CriticalBlock
  768. #define CheckedCriticalUnblock CriticalUnblock
  769. #define CHECKEDCRITENTER(sect,timeout) (sect).enter()
  770. #define CHECKEDCRITLEAVE(sect) (sect).leave()
  771. #define CHECKEDCRITICALBLOCK(sect,timeout) CheckedCriticalBlock glue(block,__LINE__)(sect)
  772. #define CHECKEDCRITICALUNBLOCK(sect,timeout) CheckedCriticalUnblock glue(unblock,__LINE__)(sect)
  773. #define CHECKEDREADLOCKBLOCK(l,timeout) ReadLockBlock glue(block,__LINE__)(l)
  774. #define CHECKEDWRITELOCKBLOCK(l,timeout) WriteLockBlock glue(block,__LINE__)(l)
  775. #define CHECKEDREADLOCKENTER(l,timeout) (l).lockRead()
  776. #define CHECKEDWRITELOCKENTER(l,timeout) (l).lockWrite()
  777. #endif
  778. class CSingletonLock // a lock that will generally only be locked once (for locking singleton objects - see below for examples
  779. {
  780. volatile bool needlock;
  781. CriticalSection sect;
  782. public:
  783. inline CSingletonLock()
  784. {
  785. needlock = true;
  786. }
  787. inline bool lock()
  788. {
  789. if (needlock) {
  790. sect.enter();
  791. //prevent compiler from moving any code before the critical section (unlikely)
  792. compiler_memory_barrier();
  793. return true;
  794. }
  795. //Prevent the value of the protected object from being evaluated before the condition
  796. compiler_memory_barrier();
  797. return false;
  798. }
  799. inline void unlock()
  800. {
  801. //Ensure that no code that precedes unlock() gets moved to after needlock being cleared.
  802. compiler_memory_barrier();
  803. needlock = false;
  804. sect.leave();
  805. }
  806. };
  807. /* Usage example
  808. void *get()
  809. {
  810. static void *sobj = NULL;
  811. static CSingletonLock slock;
  812. if (slock.lock()) {
  813. if (!sobj) // required
  814. sobj = createSObj();
  815. slock.unlock();
  816. }
  817. return sobj;
  818. }
  819. */
  820. #endif