1 /* 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Justin Haygood (jhaygood (at) 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 50 static Mutex& threadMapMutex() 51 { 52 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); 53 return mutex; 54 } 55 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 69 void lockAtomicallyInitializedStaticMutex() 70 { 71 ASSERT(atomicallyInitializedStaticMutex); 72 atomicallyInitializedStaticMutex->lock(); 73 } 74 75 void unlockAtomicallyInitializedStaticMutex() 76 { 77 atomicallyInitializedStaticMutex->unlock(); 78 } 79 80 static ThreadMap& threadMap() 81 { 82 DEFINE_STATIC_LOCAL(ThreadMap, map, ()); 83 return map; 84 } 85 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 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 112 static GThread* threadForIdentifier(ThreadIdentifier id) 113 { 114 MutexLocker locker(threadMapMutex()); 115 116 return threadMap().get(id); 117 } 118 119 static void clearThreadForIdentifier(ThreadIdentifier id) 120 { 121 MutexLocker locker(threadMapMutex()); 122 123 ASSERT(threadMap().contains(id)); 124 125 threadMap().remove(id); 126 } 127 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 140 void initializeCurrentThreadInternal(const char*) 141 { 142 } 143 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 158 void detachThread(ThreadIdentifier) 159 { 160 } 161 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 170 void yield() 171 { 172 g_thread_yield(); 173 } 174 175 Mutex::Mutex() 176 : m_mutex(g_mutex_new()) 177 { 178 } 179 180 Mutex::~Mutex() 181 { 182 } 183 184 void Mutex::lock() 185 { 186 g_mutex_lock(m_mutex.get()); 187 } 188 189 bool Mutex::tryLock() 190 { 191 return g_mutex_trylock(m_mutex.get()); 192 } 193 194 void Mutex::unlock() 195 { 196 g_mutex_unlock(m_mutex.get()); 197 } 198 199 ThreadCondition::ThreadCondition() 200 : m_condition(g_cond_new()) 201 { 202 } 203 204 ThreadCondition::~ThreadCondition() 205 { 206 } 207 208 void ThreadCondition::wait(Mutex& mutex) 209 { 210 g_cond_wait(m_condition.get(), mutex.impl().get()); 211 } 212 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 235 void ThreadCondition::signal() 236 { 237 g_cond_signal(m_condition.get()); 238 } 239 240 void ThreadCondition::broadcast() 241 { 242 g_cond_broadcast(m_condition.get()); 243 } 244 245 246 } 247 248 #endif // !USE(PTHREADS) 249