• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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 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.
17  *
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.
28  */
29 
30 #include "config.h"
31 #include "Threading.h"
32 
33 #if !USE(PTHREADS)
34 
35 #include "CurrentTime.h"
36 #include "HashMap.h"
37 #include "MainThread.h"
38 #include "RandomNumberSeed.h"
39 
40 #include <glib.h>
41 #include <limits.h>
42 
43 namespace WTF {
44 
45 static Mutex* atomicallyInitializedStaticMutex;
46 
47 static ThreadIdentifier mainThreadIdentifier;
48 
threadMapMutex()49 static Mutex& threadMapMutex()
50 {
51     static Mutex mutex;
52     return mutex;
53 }
54 
initializeThreading()55 void initializeThreading()
56 {
57     if (!g_thread_supported())
58         g_thread_init(NULL);
59     ASSERT(g_thread_supported());
60 
61     if (!atomicallyInitializedStaticMutex) {
62         atomicallyInitializedStaticMutex = new Mutex;
63         threadMapMutex();
64         initializeRandomNumberGenerator();
65         mainThreadIdentifier = currentThread();
66         initializeMainThread();
67     }
68 }
69 
lockAtomicallyInitializedStaticMutex()70 void lockAtomicallyInitializedStaticMutex()
71 {
72     ASSERT(atomicallyInitializedStaticMutex);
73     atomicallyInitializedStaticMutex->lock();
74 }
75 
unlockAtomicallyInitializedStaticMutex()76 void unlockAtomicallyInitializedStaticMutex()
77 {
78     atomicallyInitializedStaticMutex->unlock();
79 }
80 
threadMap()81 static HashMap<ThreadIdentifier, GThread*>& threadMap()
82 {
83     static HashMap<ThreadIdentifier, GThread*> map;
84     return map;
85 }
86 
identifierByGthreadHandle(GThread * & thread)87 static ThreadIdentifier identifierByGthreadHandle(GThread*& thread)
88 {
89     MutexLocker locker(threadMapMutex());
90 
91     HashMap<ThreadIdentifier, GThread*>::iterator i = threadMap().begin();
92     for (; i != threadMap().end(); ++i) {
93         if (i->second == thread)
94             return i->first;
95     }
96 
97     return 0;
98 }
99 
establishIdentifierForThread(GThread * & thread)100 static ThreadIdentifier establishIdentifierForThread(GThread*& thread)
101 {
102     ASSERT(!identifierByGthreadHandle(thread));
103 
104     MutexLocker locker(threadMapMutex());
105 
106     static ThreadIdentifier identifierCount = 1;
107 
108     threadMap().add(identifierCount, thread);
109 
110     return identifierCount++;
111 }
112 
threadForIdentifier(ThreadIdentifier id)113 static GThread* threadForIdentifier(ThreadIdentifier id)
114 {
115     MutexLocker locker(threadMapMutex());
116 
117     return threadMap().get(id);
118 }
119 
clearThreadForIdentifier(ThreadIdentifier id)120 static void clearThreadForIdentifier(ThreadIdentifier id)
121 {
122     MutexLocker locker(threadMapMutex());
123 
124     ASSERT(threadMap().contains(id));
125 
126     threadMap().remove(id);
127 }
128 
createThreadInternal(ThreadFunction entryPoint,void * data,const char *)129 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
130 {
131     GThread* thread;
132     if (!(thread = g_thread_create(entryPoint, data, TRUE, 0))) {
133         LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
134         return 0;
135     }
136 
137     ThreadIdentifier threadID = establishIdentifierForThread(thread);
138     return threadID;
139 }
140 
setThreadNameInternal(const char *)141 void setThreadNameInternal(const char*)
142 {
143 }
144 
waitForThreadCompletion(ThreadIdentifier threadID,void ** result)145 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
146 {
147     ASSERT(threadID);
148 
149     GThread* thread = threadForIdentifier(threadID);
150 
151     void* joinResult = g_thread_join(thread);
152     if (result)
153         *result = joinResult;
154 
155     clearThreadForIdentifier(threadID);
156     return 0;
157 }
158 
detachThread(ThreadIdentifier)159 void detachThread(ThreadIdentifier)
160 {
161 }
162 
currentThread()163 ThreadIdentifier currentThread()
164 {
165     GThread* currentThread = g_thread_self();
166     if (ThreadIdentifier id = identifierByGthreadHandle(currentThread))
167         return id;
168     return establishIdentifierForThread(currentThread);
169 }
170 
isMainThread()171 bool isMainThread()
172 {
173     return currentThread() == mainThreadIdentifier;
174 }
175 
Mutex()176 Mutex::Mutex()
177     : m_mutex(g_mutex_new())
178 {
179 }
180 
~Mutex()181 Mutex::~Mutex()
182 {
183 }
184 
lock()185 void Mutex::lock()
186 {
187     g_mutex_lock(m_mutex.get());
188 }
189 
tryLock()190 bool Mutex::tryLock()
191 {
192     return g_mutex_trylock(m_mutex.get());
193 }
194 
unlock()195 void Mutex::unlock()
196 {
197     g_mutex_unlock(m_mutex.get());
198 }
199 
ThreadCondition()200 ThreadCondition::ThreadCondition()
201     : m_condition(g_cond_new())
202 {
203 }
204 
~ThreadCondition()205 ThreadCondition::~ThreadCondition()
206 {
207 }
208 
wait(Mutex & mutex)209 void ThreadCondition::wait(Mutex& mutex)
210 {
211     g_cond_wait(m_condition.get(), mutex.impl().get());
212 }
213 
timedWait(Mutex & mutex,double absoluteTime)214 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
215 {
216     // Time is in the past - return right away.
217     if (absoluteTime < currentTime())
218         return false;
219 
220     // Time is too far in the future for g_cond_timed_wait - wait forever.
221     if (absoluteTime > INT_MAX) {
222         wait(mutex);
223         return true;
224     }
225 
226     int timeSeconds = static_cast<int>(absoluteTime);
227     int timeMicroseconds = static_cast<int>((absoluteTime - timeSeconds) * 1000000.0);
228 
229     GTimeVal targetTime;
230     targetTime.tv_sec = timeSeconds;
231     targetTime.tv_usec = timeMicroseconds;
232 
233     return g_cond_timed_wait(m_condition.get(), mutex.impl().get(), &targetTime);
234 }
235 
signal()236 void ThreadCondition::signal()
237 {
238     g_cond_signal(m_condition.get());
239 }
240 
broadcast()241 void ThreadCondition::broadcast()
242 {
243     g_cond_broadcast(m_condition.get());
244 }
245 
246 
247 }
248 
249 #endif // !USE(PTHREADS)
250