PageRenderTime 69ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

/gecko_api/include/nsAutoLock.h

http://firefox-mac-pdf.googlecode.com/
C Header | 449 lines | 195 code | 54 blank | 200 comment | 13 complexity | a320ed5672f0bbee8cebd52641da21f0 MD5 | raw file
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is mozilla.org code.
  16. *
  17. * The Initial Developer of the Original Code is
  18. * Netscape Communications Corporation.
  19. * Portions created by the Initial Developer are Copyright (C) 1998
  20. * the Initial Developer. All Rights Reserved.
  21. *
  22. * Contributor(s):
  23. *
  24. * Alternatively, the contents of this file may be used under the terms of
  25. * either of the GNU General Public License Version 2 or later (the "GPL"),
  26. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. * in which case the provisions of the GPL or the LGPL are applicable instead
  28. * of those above. If you wish to allow use of your version of this file only
  29. * under the terms of either the GPL or the LGPL, and not to allow others to
  30. * use your version of this file under the terms of the MPL, indicate your
  31. * decision by deleting the provisions above and replace them with the notice
  32. * and other provisions required by the GPL or the LGPL. If you do not delete
  33. * the provisions above, a recipient may use your version of this file under
  34. * the terms of any one of the MPL, the GPL or the LGPL.
  35. *
  36. * ***** END LICENSE BLOCK ***** */
  37. /*
  38. A stack-based lock object that makes using PRLock a bit more
  39. convenient. It acquires the monitor when constructed, and releases
  40. it when it goes out of scope.
  41. For example,
  42. class Foo {
  43. private:
  44. PRLock* mLock;
  45. public:
  46. Foo(void) {
  47. mLock = PR_NewLock();
  48. }
  49. ~Foo(void) {
  50. PR_DestroyLock(mLock);
  51. }
  52. void ThreadSafeMethod(void) {
  53. // we're don't hold the lock yet...
  54. nsAutoLock lock(mLock);
  55. // ...but now we do.
  56. // we even can do wacky stuff like return from arbitrary places w/o
  57. // worrying about forgetting to release the lock
  58. if (some_weird_condition)
  59. return;
  60. // otherwise do some other stuff
  61. }
  62. void ThreadSafeBlockScope(void) {
  63. // we're not in the lock here...
  64. {
  65. nsAutoLock lock(mLock);
  66. // but we are now, at least until the block scope closes
  67. }
  68. // ...now we're not in the lock anymore
  69. }
  70. };
  71. A similar stack-based locking object is available for PRMonitor. The
  72. major difference is that the PRMonitor must be created and destroyed
  73. via the static methods on nsAutoMonitor.
  74. For example:
  75. Foo::Foo() {
  76. mMon = nsAutoMonitor::NewMonitor("FooMonitor");
  77. }
  78. nsresult Foo::MyMethod(...) {
  79. nsAutoMonitor mon(mMon);
  80. ...
  81. // go ahead and do deeply nested returns...
  82. return NS_ERROR_FAILURE;
  83. ...
  84. // or call Wait or Notify...
  85. mon.Wait();
  86. ...
  87. // cleanup is automatic
  88. }
  89. */
  90. #ifndef nsAutoLock_h__
  91. #define nsAutoLock_h__
  92. #include "nscore.h"
  93. #include "prlock.h"
  94. #include "prlog.h"
  95. /**
  96. * nsAutoLockBase
  97. * This is the base class for the stack-based locking objects.
  98. * Clients of derived classes need not play with this superclass.
  99. **/
  100. class NS_COM_GLUE nsAutoLockBase {
  101. friend class nsAutoUnlockBase;
  102. protected:
  103. nsAutoLockBase() {}
  104. enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
  105. #ifdef DEBUG
  106. nsAutoLockBase(void* addr, nsAutoLockType type);
  107. ~nsAutoLockBase();
  108. void Show();
  109. void Hide();
  110. void* mAddr;
  111. nsAutoLockBase* mDown;
  112. nsAutoLockType mType;
  113. #else
  114. nsAutoLockBase(void* addr, nsAutoLockType type) {}
  115. ~nsAutoLockBase() {}
  116. void Show() {}
  117. void Hide() {}
  118. #endif
  119. };
  120. /**
  121. * nsAutoUnlockBase
  122. * This is the base class for stack-based unlocking objects.
  123. * It unlocks locking objects based on nsAutoLockBase.
  124. **/
  125. class NS_COM_GLUE nsAutoUnlockBase {
  126. protected:
  127. nsAutoUnlockBase() {}
  128. #ifdef DEBUG
  129. nsAutoUnlockBase(void* addr);
  130. ~nsAutoUnlockBase();
  131. nsAutoLockBase* mLock;
  132. #else
  133. nsAutoUnlockBase(void* addr) {}
  134. ~nsAutoUnlockBase() {}
  135. #endif
  136. };
  137. /**
  138. * nsAutoLock
  139. * Stack-based locking object for PRLock.
  140. **/
  141. class NS_COM_GLUE nsAutoLock : public nsAutoLockBase {
  142. private:
  143. PRLock* mLock;
  144. PRBool mLocked;
  145. // Not meant to be implemented. This makes it a compiler error to
  146. // construct or assign an nsAutoLock object incorrectly.
  147. nsAutoLock(void) {}
  148. nsAutoLock(nsAutoLock& /*aLock*/) {}
  149. nsAutoLock& operator =(nsAutoLock& /*aLock*/) {
  150. return *this;
  151. }
  152. // Not meant to be implemented. This makes it a compiler error to
  153. // attempt to create an nsAutoLock object on the heap.
  154. static void* operator new(size_t /*size*/) CPP_THROW_NEW {
  155. return nsnull;
  156. }
  157. static void operator delete(void* /*memory*/) {}
  158. public:
  159. /**
  160. * NewLock
  161. * Allocates a new PRLock for use with nsAutoLock. name is
  162. * not checked for uniqueness.
  163. * @param name A name which can reference this lock
  164. * @param lock A valid PRLock* that was created by nsAutoLock::NewLock()
  165. * @returns nsnull if failure
  166. * A valid PRLock* if successful, which must be destroyed
  167. * by nsAutoLock::DestroyLock()
  168. **/
  169. static PRLock* NewLock(const char* name);
  170. static void DestroyLock(PRLock* lock);
  171. /**
  172. * Constructor
  173. * The constructor aquires the given lock. The destructor
  174. * releases the lock.
  175. *
  176. * @param aLock A valid PRLock* returned from the NSPR's
  177. * PR_NewLock() function.
  178. **/
  179. nsAutoLock(PRLock* aLock)
  180. : nsAutoLockBase(aLock, eAutoLock),
  181. mLock(aLock),
  182. mLocked(PR_TRUE) {
  183. PR_ASSERT(mLock);
  184. // This will assert deep in the bowels of NSPR if you attempt
  185. // to re-enter the lock.
  186. PR_Lock(mLock);
  187. }
  188. ~nsAutoLock(void) {
  189. if (mLocked)
  190. PR_Unlock(mLock);
  191. }
  192. /**
  193. * lock
  194. * Client may call this to reaquire the given lock. Take special
  195. * note that attempting to aquire a locked lock will hang or crash.
  196. **/
  197. void lock() {
  198. Show();
  199. PR_ASSERT(!mLocked);
  200. PR_Lock(mLock);
  201. mLocked = PR_TRUE;
  202. }
  203. /**
  204. * unlock
  205. * Client may call this to release the given lock. Take special
  206. * note unlocking an unlocked lock has undefined results.
  207. **/
  208. void unlock() {
  209. PR_ASSERT(mLocked);
  210. PR_Unlock(mLock);
  211. mLocked = PR_FALSE;
  212. Hide();
  213. }
  214. };
  215. class nsAutoUnlock : nsAutoUnlockBase
  216. {
  217. private:
  218. PRLock *mLock;
  219. public:
  220. nsAutoUnlock(PRLock *lock) :
  221. nsAutoUnlockBase(lock),
  222. mLock(lock)
  223. {
  224. PR_Unlock(mLock);
  225. }
  226. ~nsAutoUnlock() {
  227. PR_Lock(mLock);
  228. }
  229. };
  230. #include "prcmon.h"
  231. #include "nsError.h"
  232. #include "nsDebug.h"
  233. class NS_COM_GLUE nsAutoMonitor : public nsAutoLockBase {
  234. public:
  235. /**
  236. * NewMonitor
  237. * Allocates a new PRMonitor for use with nsAutoMonitor.
  238. * @param name A (unique /be?) name which can reference this monitor
  239. * @returns nsnull if failure
  240. * A valid PRMonitor* is successful while must be destroyed
  241. * by nsAutoMonitor::DestroyMonitor()
  242. **/
  243. static PRMonitor* NewMonitor(const char* name);
  244. static void DestroyMonitor(PRMonitor* mon);
  245. /**
  246. * Constructor
  247. * The constructor locks the given monitor. During destruction
  248. * the monitor will be unlocked.
  249. *
  250. * @param mon A valid PRMonitor* returned from
  251. * nsAutoMonitor::NewMonitor().
  252. **/
  253. nsAutoMonitor(PRMonitor* mon)
  254. : nsAutoLockBase((void*)mon, eAutoMonitor),
  255. mMonitor(mon), mLockCount(0)
  256. {
  257. NS_ASSERTION(mMonitor, "null monitor");
  258. if (mMonitor) {
  259. PR_EnterMonitor(mMonitor);
  260. mLockCount = 1;
  261. }
  262. }
  263. ~nsAutoMonitor() {
  264. NS_ASSERTION(mMonitor, "null monitor");
  265. if (mMonitor && mLockCount) {
  266. #ifdef DEBUG
  267. PRStatus status =
  268. #endif
  269. PR_ExitMonitor(mMonitor);
  270. NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
  271. }
  272. }
  273. /**
  274. * Enter
  275. * Client may call this to reenter the given monitor.
  276. * @see prmon.h
  277. **/
  278. void Enter();
  279. /**
  280. * Exit
  281. * Client may call this to exit the given monitor.
  282. * @see prmon.h
  283. **/
  284. void Exit();
  285. /**
  286. * Wait
  287. * @see prmon.h
  288. **/
  289. nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
  290. return PR_Wait(mMonitor, interval) == PR_SUCCESS
  291. ? NS_OK : NS_ERROR_FAILURE;
  292. }
  293. /**
  294. * Notify
  295. * @see prmon.h
  296. **/
  297. nsresult Notify() {
  298. return PR_Notify(mMonitor) == PR_SUCCESS
  299. ? NS_OK : NS_ERROR_FAILURE;
  300. }
  301. /**
  302. * NotifyAll
  303. * @see prmon.h
  304. **/
  305. nsresult NotifyAll() {
  306. return PR_NotifyAll(mMonitor) == PR_SUCCESS
  307. ? NS_OK : NS_ERROR_FAILURE;
  308. }
  309. private:
  310. PRMonitor* mMonitor;
  311. PRInt32 mLockCount;
  312. // Not meant to be implemented. This makes it a compiler error to
  313. // construct or assign an nsAutoLock object incorrectly.
  314. nsAutoMonitor(void) {}
  315. nsAutoMonitor(nsAutoMonitor& /*aMon*/) {}
  316. nsAutoMonitor& operator =(nsAutoMonitor& /*aMon*/) {
  317. return *this;
  318. }
  319. // Not meant to be implemented. This makes it a compiler error to
  320. // attempt to create an nsAutoLock object on the heap.
  321. static void* operator new(size_t /*size*/) CPP_THROW_NEW {
  322. return nsnull;
  323. }
  324. static void operator delete(void* /*memory*/) {}
  325. };
  326. ////////////////////////////////////////////////////////////////////////////////
  327. // Once again, this time with a cache...
  328. // (Using this avoids the need to allocate a PRMonitor, which may be useful when
  329. // a large number of objects of the same class need associated monitors.)
  330. #include "prcmon.h"
  331. #include "nsError.h"
  332. class NS_COM_GLUE nsAutoCMonitor : public nsAutoLockBase {
  333. public:
  334. nsAutoCMonitor(void* lockObject)
  335. : nsAutoLockBase(lockObject, eAutoCMonitor),
  336. mLockObject(lockObject), mLockCount(0)
  337. {
  338. NS_ASSERTION(lockObject, "null lock object");
  339. PR_CEnterMonitor(mLockObject);
  340. mLockCount = 1;
  341. }
  342. ~nsAutoCMonitor() {
  343. if (mLockCount) {
  344. #ifdef DEBUG
  345. PRStatus status =
  346. #endif
  347. PR_CExitMonitor(mLockObject);
  348. NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed");
  349. }
  350. }
  351. void Enter();
  352. void Exit();
  353. nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
  354. return PR_CWait(mLockObject, interval) == PR_SUCCESS
  355. ? NS_OK : NS_ERROR_FAILURE;
  356. }
  357. nsresult Notify() {
  358. return PR_CNotify(mLockObject) == PR_SUCCESS
  359. ? NS_OK : NS_ERROR_FAILURE;
  360. }
  361. nsresult NotifyAll() {
  362. return PR_CNotifyAll(mLockObject) == PR_SUCCESS
  363. ? NS_OK : NS_ERROR_FAILURE;
  364. }
  365. private:
  366. void* mLockObject;
  367. PRInt32 mLockCount;
  368. // Not meant to be implemented. This makes it a compiler error to
  369. // construct or assign an nsAutoLock object incorrectly.
  370. nsAutoCMonitor(void) {}
  371. nsAutoCMonitor(nsAutoCMonitor& /*aMon*/) {}
  372. nsAutoCMonitor& operator =(nsAutoCMonitor& /*aMon*/) {
  373. return *this;
  374. }
  375. // Not meant to be implemented. This makes it a compiler error to
  376. // attempt to create an nsAutoLock object on the heap.
  377. static void* operator new(size_t /*size*/) CPP_THROW_NEW {
  378. return nsnull;
  379. }
  380. static void operator delete(void* /*memory*/) {}
  381. };
  382. #endif // nsAutoLock_h__