Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(629)

Side by Side Diff: Source/WTF/wtf/ThreadingPthreads.cpp

Issue 14238015: Move Source/WTF/wtf to Source/wtf (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
4 * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "Threading.h"
33
34 #if USE(PTHREADS)
35
36 #include "DateMath.h"
37 #include "dtoa.h"
38 #include "dtoa/cached-powers.h"
39 #include "HashMap.h"
40 #include "RandomNumberSeed.h"
41 #include "StackStats.h"
42 #include "StdLibExtras.h"
43 #include "ThreadFunctionInvocation.h"
44 #include "ThreadIdentifierDataPthreads.h"
45 #include "ThreadSpecific.h"
46 #include "UnusedParam.h"
47 #include <wtf/OwnPtr.h>
48 #include <wtf/PassOwnPtr.h>
49 #include <wtf/WTFThreadData.h>
50 #include <errno.h>
51
52 #if !COMPILER(MSVC)
53 #include <limits.h>
54 #include <sched.h>
55 #include <sys/time.h>
56 #endif
57
58 #if OS(MAC_OS_X) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
59 #include <objc/objc-auto.h>
60 #endif
61
62 namespace WTF {
63
64 class PthreadState {
65 WTF_MAKE_FAST_ALLOCATED;
66 public:
67 enum JoinableState {
68 Joinable, // The default thread state. The thread can be joined on.
69
70 Joined, // Somebody waited on this thread to exit and this thread finall y exited. This state is here because there can be a
71 // period of time between when the thread exits (which causes pt hread_join to return and the remainder of waitOnThreadCompletion to run)
72 // and when threadDidExit is called. We need threadDidExit to ta ke charge and delete the thread data since there's
73 // nobody else to pick up the slack in this case (since waitOnTh readCompletion has already returned).
74
75 Detached // The thread has been detached and can no longer be joined on. At this point, the thread must take care of cleaning up after itself.
76 };
77
78 // Currently all threads created by WTF start out as joinable.
79 PthreadState(pthread_t handle)
80 : m_joinableState(Joinable)
81 , m_didExit(false)
82 , m_pthreadHandle(handle)
83 {
84 }
85
86 JoinableState joinableState() { return m_joinableState; }
87 pthread_t pthreadHandle() { return m_pthreadHandle; }
88 void didBecomeDetached() { m_joinableState = Detached; }
89 void didExit() { m_didExit = true; }
90 void didJoin() { m_joinableState = Joined; }
91 bool hasExited() { return m_didExit; }
92
93 private:
94 JoinableState m_joinableState;
95 bool m_didExit;
96 pthread_t m_pthreadHandle;
97 };
98
99 typedef HashMap<ThreadIdentifier, OwnPtr<PthreadState> > ThreadMap;
100
101 static Mutex* atomicallyInitializedStaticMutex;
102
103 void unsafeThreadWasDetached(ThreadIdentifier);
104 void threadDidExit(ThreadIdentifier);
105 void threadWasJoined(ThreadIdentifier);
106
107 static Mutex& threadMapMutex()
108 {
109 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
110 return mutex;
111 }
112
113 #if OS(QNX) && CPU(ARM_THUMB2)
114 static void enableIEEE754Denormal()
115 {
116 // Clear the ARM_VFP_FPSCR_FZ flag in FPSCR.
117 unsigned fpscr;
118 asm volatile("vmrs %0, fpscr" : "=r"(fpscr));
119 fpscr &= ~0x01000000u;
120 asm volatile("vmsr fpscr, %0" : : "r"(fpscr));
121 }
122 #endif
123
124 void initializeThreading()
125 {
126 if (atomicallyInitializedStaticMutex)
127 return;
128
129 #if OS(QNX) && CPU(ARM_THUMB2)
130 enableIEEE754Denormal();
131 #endif
132
133 WTF::double_conversion::initialize();
134 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
135 // so ensure it has been initialized from here.
136 StringImpl::empty();
137 atomicallyInitializedStaticMutex = new Mutex;
138 threadMapMutex();
139 initializeRandomNumberGenerator();
140 ThreadIdentifierData::initializeOnce();
141 StackStats::initialize();
142 wtfThreadData();
143 s_dtoaP5Mutex = new Mutex;
144 initializeDates();
145 }
146
147 void lockAtomicallyInitializedStaticMutex()
148 {
149 ASSERT(atomicallyInitializedStaticMutex);
150 atomicallyInitializedStaticMutex->lock();
151 }
152
153 void unlockAtomicallyInitializedStaticMutex()
154 {
155 atomicallyInitializedStaticMutex->unlock();
156 }
157
158 static ThreadMap& threadMap()
159 {
160 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
161 return map;
162 }
163
164 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle )
165 {
166 MutexLocker locker(threadMapMutex());
167
168 ThreadMap::iterator i = threadMap().begin();
169 for (; i != threadMap().end(); ++i) {
170 if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value ->hasExited())
171 return i->key;
172 }
173
174 return 0;
175 }
176
177 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pth readHandle)
178 {
179 ASSERT(!identifierByPthreadHandle(pthreadHandle));
180 MutexLocker locker(threadMapMutex());
181 static ThreadIdentifier identifierCount = 1;
182 threadMap().add(identifierCount, adoptPtr(new PthreadState(pthreadHandle)));
183 return identifierCount++;
184 }
185
186 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
187 {
188 return threadMap().get(id)->pthreadHandle();
189 }
190
191 static void* wtfThreadEntryPoint(void* param)
192 {
193 // Balanced by .leakPtr() in createThreadInternal.
194 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFun ctionInvocation*>(param));
195 invocation->function(invocation->data);
196 return 0;
197 }
198
199 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, con st char*)
200 {
201 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInv ocation(entryPoint, data));
202 pthread_t threadHandle;
203 if (pthread_create(&threadHandle, 0, wtfThreadEntryPoint, invocation.get())) {
204 LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtf ThreadEntryPoint, invocation.get());
205 return 0;
206 }
207
208 // Balanced by adoptPtr() in wtfThreadEntryPoint.
209 ThreadFunctionInvocation* leakedInvocation = invocation.leakPtr();
210 UNUSED_PARAM(leakedInvocation);
211
212 return establishIdentifierForPthreadHandle(threadHandle);
213 }
214
215 void initializeCurrentThreadInternal(const char* threadName)
216 {
217 #if HAVE(PTHREAD_SETNAME_NP)
218 pthread_setname_np(threadName);
219 #elif OS(QNX)
220 pthread_setname_np(pthread_self(), threadName);
221 #else
222 UNUSED_PARAM(threadName);
223 #endif
224
225 #if OS(MAC_OS_X) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
226 // All threads that potentially use APIs above the BSD layer must be registe red with the Objective-C
227 // garbage collector in case API implementations use garbage-collected memor y.
228 objc_registerThreadWithCollector();
229 #endif
230
231 #if OS(QNX) && CPU(ARM_THUMB2)
232 enableIEEE754Denormal();
233 #endif
234
235 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
236 ASSERT(id);
237 ThreadIdentifierData::initialize(id);
238 }
239
240 int waitForThreadCompletion(ThreadIdentifier threadID)
241 {
242 pthread_t pthreadHandle;
243 ASSERT(threadID);
244
245 {
246 // We don't want to lock across the call to join, since that can block o ur thread and cause deadlock.
247 MutexLocker locker(threadMapMutex());
248 pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
249 ASSERT(pthreadHandle);
250 }
251
252 int joinResult = pthread_join(pthreadHandle, 0);
253
254 if (joinResult == EDEADLK)
255 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit ", threadID);
256 else if (joinResult)
257 LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
258
259 MutexLocker locker(threadMapMutex());
260 PthreadState* state = threadMap().get(threadID);
261 ASSERT(state);
262 ASSERT(state->joinableState() == PthreadState::Joinable);
263
264 // The thread has already exited, so clean up after it.
265 if (state->hasExited())
266 threadMap().remove(threadID);
267 // The thread hasn't exited yet, so don't clean anything up. Just signal tha t we've already joined on it so that it will clean up after itself.
268 else
269 state->didJoin();
270
271 return joinResult;
272 }
273
274 void detachThread(ThreadIdentifier threadID)
275 {
276 ASSERT(threadID);
277
278 MutexLocker locker(threadMapMutex());
279 pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(thre adID);
280 ASSERT(pthreadHandle);
281
282 int detachResult = pthread_detach(pthreadHandle);
283 if (detachResult)
284 LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
285
286 PthreadState* state = threadMap().get(threadID);
287 ASSERT(state);
288 if (state->hasExited())
289 threadMap().remove(threadID);
290 else
291 threadMap().get(threadID)->didBecomeDetached();
292 }
293
294 void threadDidExit(ThreadIdentifier threadID)
295 {
296 MutexLocker locker(threadMapMutex());
297 PthreadState* state = threadMap().get(threadID);
298 ASSERT(state);
299
300 state->didExit();
301
302 if (state->joinableState() != PthreadState::Joinable)
303 threadMap().remove(threadID);
304 }
305
306 void yield()
307 {
308 sched_yield();
309 }
310
311 ThreadIdentifier currentThread()
312 {
313 ThreadIdentifier id = ThreadIdentifierData::identifier();
314 if (id)
315 return id;
316
317 // Not a WTF-created thread, ThreadIdentifier is not established yet.
318 id = establishIdentifierForPthreadHandle(pthread_self());
319 ThreadIdentifierData::initialize(id);
320 return id;
321 }
322
323 Mutex::Mutex()
324 {
325 pthread_mutexattr_t attr;
326 pthread_mutexattr_init(&attr);
327 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
328
329 int result = pthread_mutex_init(&m_mutex, &attr);
330 ASSERT_UNUSED(result, !result);
331
332 pthread_mutexattr_destroy(&attr);
333 }
334
335 Mutex::~Mutex()
336 {
337 int result = pthread_mutex_destroy(&m_mutex);
338 ASSERT_UNUSED(result, !result);
339 }
340
341 void Mutex::lock()
342 {
343 int result = pthread_mutex_lock(&m_mutex);
344 ASSERT_UNUSED(result, !result);
345 }
346
347 bool Mutex::tryLock()
348 {
349 int result = pthread_mutex_trylock(&m_mutex);
350
351 if (result == 0)
352 return true;
353 if (result == EBUSY)
354 return false;
355
356 ASSERT_NOT_REACHED();
357 return false;
358 }
359
360 void Mutex::unlock()
361 {
362 int result = pthread_mutex_unlock(&m_mutex);
363 ASSERT_UNUSED(result, !result);
364 }
365
366 ThreadCondition::ThreadCondition()
367 {
368 pthread_cond_init(&m_condition, NULL);
369 }
370
371 ThreadCondition::~ThreadCondition()
372 {
373 pthread_cond_destroy(&m_condition);
374 }
375
376 void ThreadCondition::wait(Mutex& mutex)
377 {
378 int result = pthread_cond_wait(&m_condition, &mutex.impl());
379 ASSERT_UNUSED(result, !result);
380 }
381
382 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
383 {
384 if (absoluteTime < currentTime())
385 return false;
386
387 if (absoluteTime > INT_MAX) {
388 wait(mutex);
389 return true;
390 }
391
392 int timeSeconds = static_cast<int>(absoluteTime);
393 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
394
395 timespec targetTime;
396 targetTime.tv_sec = timeSeconds;
397 targetTime.tv_nsec = timeNanoseconds;
398
399 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0 ;
400 }
401
402 void ThreadCondition::signal()
403 {
404 int result = pthread_cond_signal(&m_condition);
405 ASSERT_UNUSED(result, !result);
406 }
407
408 void ThreadCondition::broadcast()
409 {
410 int result = pthread_cond_broadcast(&m_condition);
411 ASSERT_UNUSED(result, !result);
412 }
413
414 } // namespace WTF
415
416 #endif // USE(PTHREADS)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698