2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "Threading.h"
32 #include "StdLibExtras.h"
36 #include "CurrentTime.h"
38 #include "MainThread.h"
39 #include "RandomNumberSeed.h"
47 typedef HashMap
<ThreadIdentifier
, pthread_t
> ThreadMap
;
49 static Mutex
* atomicallyInitializedStaticMutex
;
51 static ThreadIdentifier mainThreadIdentifier
; // The thread that was the first to call initializeThreading(), which must be the main thread.
53 static Mutex
& threadMapMutex()
55 DEFINE_STATIC_LOCAL(Mutex
, mutex
, ());
59 void initializeThreading()
61 if (!atomicallyInitializedStaticMutex
) {
62 atomicallyInitializedStaticMutex
= new Mutex
;
64 initializeRandomNumberGenerator();
65 mainThreadIdentifier
= currentThread();
66 initializeMainNSThread();
67 initializeMainThread();
71 void lockAtomicallyInitializedStaticMutex()
73 ASSERT(atomicallyInitializedStaticMutex
);
74 atomicallyInitializedStaticMutex
->lock();
77 void unlockAtomicallyInitializedStaticMutex()
79 atomicallyInitializedStaticMutex
->unlock();
82 static ThreadMap
& threadMap()
84 DEFINE_STATIC_LOCAL(ThreadMap
, map
, ());
88 static ThreadIdentifier
identifierByPthreadHandle(const pthread_t
& pthreadHandle
)
90 MutexLocker
locker(threadMapMutex());
92 ThreadMap::iterator i
= threadMap().begin();
93 for (; i
!= threadMap().end(); ++i
) {
94 if (pthread_equal(i
->second
, pthreadHandle
))
101 static ThreadIdentifier
establishIdentifierForPthreadHandle(pthread_t
& pthreadHandle
)
103 ASSERT(!identifierByPthreadHandle(pthreadHandle
));
105 MutexLocker
locker(threadMapMutex());
107 static ThreadIdentifier identifierCount
= 1;
109 threadMap().add(identifierCount
, pthreadHandle
);
111 return identifierCount
++;
114 static pthread_t
pthreadHandleForIdentifier(ThreadIdentifier id
)
116 MutexLocker
locker(threadMapMutex());
118 return threadMap().get(id
);
121 static void clearPthreadHandleForIdentifier(ThreadIdentifier id
)
123 MutexLocker
locker(threadMapMutex());
125 ASSERT(threadMap().contains(id
));
127 threadMap().remove(id
);
130 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
132 pthread_t threadHandle
;
133 if (pthread_create(&threadHandle
, NULL
, entryPoint
, data
)) {
134 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint
, data
);
138 return establishIdentifierForPthreadHandle(threadHandle
);
141 int waitForThreadCompletion(ThreadIdentifier threadID
, void** result
)
145 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
147 int joinResult
= pthread_join(pthreadHandle
, result
);
148 if (joinResult
== EDEADLK
)
149 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID
);
151 clearPthreadHandleForIdentifier(threadID
);
155 void detachThread(ThreadIdentifier threadID
)
159 pthread_t pthreadHandle
= pthreadHandleForIdentifier(threadID
);
161 pthread_detach(pthreadHandle
);
163 clearPthreadHandleForIdentifier(threadID
);
166 ThreadIdentifier
currentThread()
168 pthread_t currentThread
= pthread_self();
169 if (ThreadIdentifier id
= identifierByPthreadHandle(currentThread
))
171 return establishIdentifierForPthreadHandle(currentThread
);
176 return currentThread() == mainThreadIdentifier
;
181 pthread_mutex_init(&m_mutex
, NULL
);
186 pthread_mutex_destroy(&m_mutex
);
191 if (pthread_mutex_lock(&m_mutex
) != 0)
195 bool Mutex::tryLock()
197 int result
= pthread_mutex_trylock(&m_mutex
);
201 else if (result
== EBUSY
)
210 if (pthread_mutex_unlock(&m_mutex
) != 0)
214 ThreadCondition::ThreadCondition()
216 pthread_cond_init(&m_condition
, NULL
);
219 ThreadCondition::~ThreadCondition()
221 pthread_cond_destroy(&m_condition
);
224 void ThreadCondition::wait(Mutex
& mutex
)
226 if (pthread_cond_wait(&m_condition
, &mutex
.impl()) != 0)
230 bool ThreadCondition::timedWait(Mutex
& mutex
, double absoluteTime
)
232 if (absoluteTime
< currentTime())
235 if (absoluteTime
> INT_MAX
) {
240 int timeSeconds
= static_cast<int>(absoluteTime
);
241 int timeNanoseconds
= static_cast<int>((absoluteTime
- timeSeconds
) * 1E9
);
244 targetTime
.tv_sec
= timeSeconds
;
245 targetTime
.tv_nsec
= timeNanoseconds
;
247 return pthread_cond_timedwait(&m_condition
, &mutex
.impl(), &targetTime
) == 0;
250 void ThreadCondition::signal()
252 if (pthread_cond_signal(&m_condition
) != 0)
256 void ThreadCondition::broadcast()
258 if (pthread_cond_broadcast(&m_condition
) != 0)
264 #endif // USE(PTHREADS)