]>
Commit | Line | Data |
---|---|---|
b37bf2e1 | 1 | /* |
9dae56ea | 2 | * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved. |
b37bf2e1 A |
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 | ||
9dae56ea A |
21 | #ifndef JSLock_h |
22 | #define JSLock_h | |
b37bf2e1 A |
23 | |
24 | #include <wtf/Assertions.h> | |
25 | #include <wtf/Noncopyable.h> | |
6fe7ccc8 A |
26 | #include <wtf/RefPtr.h> |
27 | #include <wtf/TCSpinLock.h> | |
28 | #include <wtf/Threading.h> | |
b37bf2e1 | 29 | |
9dae56ea | 30 | namespace JSC { |
b37bf2e1 A |
31 | |
32 | // To make it safe to use JavaScript on multiple threads, it is | |
33 | // important to lock before doing anything that allocates a | |
34 | // JavaScript data structure or that interacts with shared state | |
35 | // such as the protect count hash table. The simplest way to lock | |
6fe7ccc8 A |
36 | // is to create a local JSLockHolder object in the scope where the lock |
37 | // must be held and pass it the context that requires protection. | |
38 | // The lock is recursive so nesting is ok. The JSLock | |
b37bf2e1 A |
39 | // object also acts as a convenience short-hand for running important |
40 | // initialization routines. | |
41 | ||
42 | // To avoid deadlock, sometimes it is necessary to temporarily | |
43 | // release the lock. Since it is recursive you actually have to | |
44 | // release all locks held by your thread. This is safe to do if | |
45 | // you are executing code that doesn't require the lock, and you | |
46 | // reacquire the right number of locks at the end. You can do this | |
47 | // by constructing a locally scoped JSLock::DropAllLocks object. The | |
48 | // DropAllLocks object takes care to release the JSLock only if your | |
49 | // thread acquired it to begin with. | |
50 | ||
9dae56ea | 51 | class ExecState; |
93a37866 | 52 | class VM; |
9dae56ea | 53 | |
6fe7ccc8 | 54 | // This class is used to protect the initialization of the legacy single |
93a37866 | 55 | // shared VM. |
6fe7ccc8 A |
56 | class GlobalJSLock { |
57 | WTF_MAKE_NONCOPYABLE(GlobalJSLock); | |
58 | public: | |
59 | JS_EXPORT_PRIVATE GlobalJSLock(); | |
60 | JS_EXPORT_PRIVATE ~GlobalJSLock(); | |
93a37866 A |
61 | |
62 | static void initialize(); | |
63 | private: | |
64 | static Mutex* s_sharedInstanceLock; | |
6fe7ccc8 A |
65 | }; |
66 | ||
67 | class JSLockHolder { | |
68 | public: | |
93a37866 A |
69 | JS_EXPORT_PRIVATE JSLockHolder(VM*); |
70 | JS_EXPORT_PRIVATE JSLockHolder(VM&); | |
6fe7ccc8 A |
71 | JS_EXPORT_PRIVATE JSLockHolder(ExecState*); |
72 | ||
73 | JS_EXPORT_PRIVATE ~JSLockHolder(); | |
74 | private: | |
93a37866 A |
75 | void init(); |
76 | ||
77 | RefPtr<VM> m_vm; | |
6fe7ccc8 | 78 | }; |
f9bf01c6 | 79 | |
93a37866 | 80 | class JSLock : public ThreadSafeRefCounted<JSLock> { |
14957cd0 | 81 | WTF_MAKE_NONCOPYABLE(JSLock); |
b37bf2e1 | 82 | public: |
93a37866 | 83 | JSLock(VM*); |
6fe7ccc8 A |
84 | JS_EXPORT_PRIVATE ~JSLock(); |
85 | ||
86 | JS_EXPORT_PRIVATE void lock(); | |
87 | JS_EXPORT_PRIVATE void unlock(); | |
88 | ||
9dae56ea A |
89 | static void lock(ExecState*); |
90 | static void unlock(ExecState*); | |
93a37866 A |
91 | static void lock(VM&); |
92 | static void unlock(VM&); | |
93 | ||
94 | VM* vm() { return m_vm; } | |
6fe7ccc8 A |
95 | |
96 | JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock(); | |
9dae56ea | 97 | |
93a37866 A |
98 | unsigned dropAllLocks(SpinLock&); |
99 | unsigned dropAllLocksUnconditionally(SpinLock&); | |
100 | void grabAllLocks(unsigned lockCount, SpinLock&); | |
b37bf2e1 | 101 | |
93a37866 | 102 | void willDestroyVM(VM*); |
b37bf2e1 | 103 | |
14957cd0 A |
104 | class DropAllLocks { |
105 | WTF_MAKE_NONCOPYABLE(DropAllLocks); | |
b37bf2e1 | 106 | public: |
93a37866 | 107 | #if PLATFORM(IOS) |
6fe7ccc8 A |
108 | // This is a hack to allow Mobile Safari to always release the locks since |
109 | // hey depend on the behavior that DropAllLocks does indeed always drop all | |
110 | // locks, which isn't always the case with the default behavior. | |
111 | enum AlwaysDropLocksTag { DontAlwaysDropLocks = 0, AlwaysDropLocks }; | |
112 | JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec, AlwaysDropLocksTag alwaysDropLocks = DontAlwaysDropLocks); | |
93a37866 A |
113 | JS_EXPORT_PRIVATE DropAllLocks(VM*, AlwaysDropLocksTag alwaysDropLocks = DontAlwaysDropLocks); |
114 | #else | |
115 | JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec); | |
116 | JS_EXPORT_PRIVATE DropAllLocks(VM*); | |
117 | #endif | |
6fe7ccc8 | 118 | JS_EXPORT_PRIVATE ~DropAllLocks(); |
b37bf2e1 A |
119 | |
120 | private: | |
9dae56ea | 121 | intptr_t m_lockCount; |
93a37866 | 122 | RefPtr<VM> m_vm; |
b37bf2e1 | 123 | }; |
93a37866 A |
124 | |
125 | private: | |
126 | SpinLock m_spinLock; | |
127 | Mutex m_lock; | |
128 | ThreadIdentifier m_ownerThread; | |
129 | intptr_t m_lockCount; | |
130 | unsigned m_lockDropDepth; | |
131 | VM* m_vm; | |
b37bf2e1 A |
132 | }; |
133 | ||
134 | } // namespace | |
135 | ||
9dae56ea | 136 | #endif // JSLock_h |