~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/JavaScriptCore/runtime/JSLock.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
60
60
}
61
61
 
62
62
JSLock::JSLock(ExecState* exec)
63
 
    : m_lockingForReal(exec->globalData().isSharedInstance)
 
63
    : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly)
64
64
{
65
 
    lock(m_lockingForReal);
 
65
    lock(m_lockBehavior);
66
66
}
67
67
 
68
 
void JSLock::lock(bool lockForReal)
 
68
void JSLock::lock(JSLockBehavior lockBehavior)
69
69
{
70
70
#ifdef NDEBUG
71
71
    // Locking "not for real" is a debug-only feature.
72
 
    if (!lockForReal)
 
72
    if (lockBehavior == SilenceAssertionsOnly)
73
73
        return;
74
74
#endif
75
75
 
76
76
    pthread_once(&createJSLockCountOnce, createJSLockCount);
77
77
 
78
78
    intptr_t currentLockCount = lockCount();
79
 
    if (!currentLockCount && lockForReal) {
 
79
    if (!currentLockCount && lockBehavior == LockForReal) {
80
80
        int result;
81
81
        result = pthread_mutex_lock(&JSMutex);
82
82
        ASSERT(!result);
84
84
    setLockCount(currentLockCount + 1);
85
85
}
86
86
 
87
 
void JSLock::unlock(bool lockForReal)
 
87
void JSLock::unlock(JSLockBehavior lockBehavior)
88
88
{
89
89
    ASSERT(lockCount());
90
90
 
91
91
#ifdef NDEBUG
92
92
    // Locking "not for real" is a debug-only feature.
93
 
    if (!lockForReal)
 
93
    if (lockBehavior == SilenceAssertionsOnly)
94
94
        return;
95
95
#endif
96
96
 
97
97
    intptr_t newLockCount = lockCount() - 1;
98
98
    setLockCount(newLockCount);
99
 
    if (!newLockCount && lockForReal) {
 
99
    if (!newLockCount && lockBehavior == LockForReal) {
100
100
        int result;
101
101
        result = pthread_mutex_unlock(&JSMutex);
102
102
        ASSERT(!result);
105
105
 
106
106
void JSLock::lock(ExecState* exec)
107
107
{
108
 
    lock(exec->globalData().isSharedInstance);
 
108
    lock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly);
109
109
}
110
110
 
111
111
void JSLock::unlock(ExecState* exec)
112
112
{
113
 
    unlock(exec->globalData().isSharedInstance);
 
113
    unlock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly);
114
114
}
115
115
 
116
116
bool JSLock::currentThreadIsHoldingLock()
119
119
    return !!pthread_getspecific(JSLockCount);
120
120
}
121
121
 
 
122
// This is fairly nasty.  We allow multiple threads to run on the same
 
123
// context, and we do not require any locking semantics in doing so -
 
124
// clients of the API may simply use the context from multiple threads
 
125
// concurently, and assume this will work.  In order to make this work,
 
126
// We lock the context when a thread enters, and unlock it when it leaves.
 
127
// However we do not only unlock when the thread returns from its
 
128
// entry point (evaluate script or call function), we also unlock the
 
129
// context if the thread leaves JSC by making a call out to an external
 
130
// function through a callback.
 
131
//
 
132
// All threads using the context share the same JS stack (the RegisterFile).
 
133
// Whenever a thread calls into JSC it starts using the RegisterFile from the
 
134
// previous 'high water mark' - the maximum point the stack has ever grown to
 
135
// (returned by RegisterFile::end()).  So if a first thread calls out to a
 
136
// callback, and a second thread enters JSC, then also exits by calling out
 
137
// to a callback, we can be left with stackframes from both threads in the
 
138
// RegisterFile.  As such, a problem may occur should the first thread's
 
139
// callback complete first, and attempt to return to JSC.  Were we to allow
 
140
// this to happen, and were its stack to grow further, then it may potentially
 
141
// write over the second thread's call frames.
 
142
//
 
143
// In avoid JS stack corruption we enforce a policy of only ever allowing two
 
144
// threads to use a JS context concurrently, and only allowing the second of
 
145
// these threads to execute until it has completed and fully returned from its
 
146
// outermost call into JSC.  We enforce this policy using 'lockDropDepth'.  The
 
147
// first time a thread exits it will call DropAllLocks - which will do as expected
 
148
// and drop locks allowing another thread to enter.  Should another thread, or the
 
149
// same thread again, enter JSC (through evaluate script or call function), and exit
 
150
// again through a callback, then the locks will not be dropped when DropAllLocks
 
151
// is called (since lockDropDepth is non-zero).  Since this thread is still holding
 
152
// the locks, only it will re able to re-enter JSC (either be returning from the
 
153
// callback, or by re-entering through another call to evaulate script or call
 
154
// function).
 
155
//
 
156
// This policy is slightly more restricive than it needs to be for correctness -
 
157
// we could validly allow futher entries into JSC from other threads, we only
 
158
// need ensure that callbacks return in the reverse chronological order of the
 
159
// order in which they were made - though implementing the less restrictive policy
 
160
// would likely increase complexity and overhead.
 
161
//
 
162
static unsigned lockDropDepth = 0;
 
163
 
122
164
JSLock::DropAllLocks::DropAllLocks(ExecState* exec)
123
 
    : m_lockingForReal(exec->globalData().isSharedInstance)
 
165
    : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly)
124
166
{
125
167
    pthread_once(&createJSLockCountOnce, createJSLockCount);
126
168
 
 
169
    if (lockDropDepth++) {
 
170
        m_lockCount = 0;
 
171
        return;
 
172
    }
 
173
 
127
174
    m_lockCount = JSLock::lockCount();
128
175
    for (intptr_t i = 0; i < m_lockCount; i++)
129
 
        JSLock::unlock(m_lockingForReal);
 
176
        JSLock::unlock(m_lockBehavior);
130
177
}
131
178
 
132
 
JSLock::DropAllLocks::DropAllLocks(bool lockingForReal)
133
 
    : m_lockingForReal(lockingForReal)
 
179
JSLock::DropAllLocks::DropAllLocks(JSLockBehavior JSLockBehavior)
 
180
    : m_lockBehavior(JSLockBehavior)
134
181
{
135
182
    pthread_once(&createJSLockCountOnce, createJSLockCount);
136
183
 
 
184
    if (lockDropDepth++) {
 
185
        m_lockCount = 0;
 
186
        return;
 
187
    }
 
188
 
137
189
    // It is necessary to drop even "unreal" locks, because having a non-zero lock count
138
190
    // will prevent a real lock from being taken.
139
191
 
140
192
    m_lockCount = JSLock::lockCount();
141
193
    for (intptr_t i = 0; i < m_lockCount; i++)
142
 
        JSLock::unlock(m_lockingForReal);
 
194
        JSLock::unlock(m_lockBehavior);
143
195
}
144
196
 
145
197
JSLock::DropAllLocks::~DropAllLocks()
146
198
{
147
199
    for (intptr_t i = 0; i < m_lockCount; i++)
148
 
        JSLock::lock(m_lockingForReal);
 
200
        JSLock::lock(m_lockBehavior);
 
201
 
 
202
    --lockDropDepth;
149
203
}
150
204
 
151
205
#else
152
206
 
153
207
JSLock::JSLock(ExecState*)
154
 
    : m_lockingForReal(false)
 
208
    : m_lockBehavior(SilenceAssertionsOnly)
155
209
{
156
210
}
157
211
 
167
221
    return true;
168
222
}
169
223
 
170
 
void JSLock::lock(bool)
 
224
void JSLock::lock(JSLockBehavior)
171
225
{
172
226
}
173
227
 
174
 
void JSLock::unlock(bool)
 
228
void JSLock::unlock(JSLockBehavior)
175
229
{
176
230
}
177
231
 
187
241
{
188
242
}
189
243
 
190
 
JSLock::DropAllLocks::DropAllLocks(bool)
 
244
JSLock::DropAllLocks::DropAllLocks(JSLockBehavior)
191
245
{
192
246
}
193
247