|
1 /* |
|
2 * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved. |
|
3 * |
|
4 * This library is free software; you can redistribute it and/or |
|
5 * modify it under the terms of the GNU Library General Public |
|
6 * License as published by the Free Software Foundation; either |
|
7 * version 2 of the License, or (at your option) any later version. |
|
8 * |
|
9 * This library is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 * Library General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU Library General Public License |
|
15 * along with this library; see the file COPYING.LIB. If not, write to |
|
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
17 * Boston, MA 02110-1301, USA. |
|
18 * |
|
19 */ |
|
20 |
|
21 #ifndef JSLock_h |
|
22 #define JSLock_h |
|
23 |
|
24 #include <wtf/Assertions.h> |
|
25 #include <wtf/Noncopyable.h> |
|
26 |
|
27 namespace JSC { |
|
28 |
|
29 // To make it safe to use JavaScript on multiple threads, it is |
|
30 // important to lock before doing anything that allocates a |
|
31 // JavaScript data structure or that interacts with shared state |
|
32 // such as the protect count hash table. The simplest way to lock |
|
33 // is to create a local JSLock object in the scope where the lock |
|
34 // must be held. The lock is recursive so nesting is ok. The JSLock |
|
35 // object also acts as a convenience short-hand for running important |
|
36 // initialization routines. |
|
37 |
|
38 // To avoid deadlock, sometimes it is necessary to temporarily |
|
39 // release the lock. Since it is recursive you actually have to |
|
40 // release all locks held by your thread. This is safe to do if |
|
41 // you are executing code that doesn't require the lock, and you |
|
42 // reacquire the right number of locks at the end. You can do this |
|
43 // by constructing a locally scoped JSLock::DropAllLocks object. The |
|
44 // DropAllLocks object takes care to release the JSLock only if your |
|
45 // thread acquired it to begin with. |
|
46 |
|
47 // For contexts other than the single shared one, implicit locking is not done, |
|
48 // but we still need to perform all the counting in order to keep debug |
|
49 // assertions working, so that clients that use the shared context don't break. |
|
50 |
|
51 class ExecState; |
|
52 |
|
53 enum JSLockBehavior { SilenceAssertionsOnly, LockForReal }; |
|
54 |
|
55 class JSLock : public Noncopyable { |
|
56 public: |
|
57 JSLock(ExecState*); |
|
58 |
|
59 JSLock(JSLockBehavior lockBehavior) |
|
60 : m_lockBehavior(lockBehavior) |
|
61 { |
|
62 #ifdef NDEBUG |
|
63 // Locking "not for real" is a debug-only feature. |
|
64 if (lockBehavior == SilenceAssertionsOnly) |
|
65 return; |
|
66 #endif |
|
67 lock(lockBehavior); |
|
68 } |
|
69 |
|
70 ~JSLock() |
|
71 { |
|
72 #ifdef NDEBUG |
|
73 // Locking "not for real" is a debug-only feature. |
|
74 if (m_lockBehavior == SilenceAssertionsOnly) |
|
75 return; |
|
76 #endif |
|
77 unlock(m_lockBehavior); |
|
78 } |
|
79 |
|
80 static void lock(JSLockBehavior); |
|
81 static void unlock(JSLockBehavior); |
|
82 static void lock(ExecState*); |
|
83 static void unlock(ExecState*); |
|
84 |
|
85 static intptr_t lockCount(); |
|
86 static bool currentThreadIsHoldingLock(); |
|
87 |
|
88 JSLockBehavior m_lockBehavior; |
|
89 |
|
90 class DropAllLocks : public Noncopyable { |
|
91 public: |
|
92 DropAllLocks(ExecState* exec); |
|
93 DropAllLocks(JSLockBehavior); |
|
94 ~DropAllLocks(); |
|
95 |
|
96 private: |
|
97 intptr_t m_lockCount; |
|
98 JSLockBehavior m_lockBehavior; |
|
99 }; |
|
100 }; |
|
101 |
|
102 } // namespace |
|
103 |
|
104 #endif // JSLock_h |