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