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