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 44namespace WTF { 45 46typedef HashMap<ThreadIdentifier, GThread*> ThreadMap; 47 48static Mutex* atomicallyInitializedStaticMutex; 49 50static Mutex& threadMapMutex() 51{ 52 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); 53 return mutex; 54} 55 56void 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 69void lockAtomicallyInitializedStaticMutex() 70{ 71 ASSERT(atomicallyInitializedStaticMutex); 72 atomicallyInitializedStaticMutex->lock(); 73} 74 75void unlockAtomicallyInitializedStaticMutex() 76{ 77 atomicallyInitializedStaticMutex->unlock(); 78} 79 80static ThreadMap& threadMap() 81{ 82 DEFINE_STATIC_LOCAL(ThreadMap, map, ()); 83 return map; 84} 85 86static 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 99static 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 112static GThread* threadForIdentifier(ThreadIdentifier id) 113{ 114 MutexLocker locker(threadMapMutex()); 115 116 return threadMap().get(id); 117} 118 119static void clearThreadForIdentifier(ThreadIdentifier id) 120{ 121 MutexLocker locker(threadMapMutex()); 122 123 ASSERT(threadMap().contains(id)); 124 125 threadMap().remove(id); 126} 127 128ThreadIdentifier 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 140void initializeCurrentThreadInternal(const char*) 141{ 142} 143 144int 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 158void detachThread(ThreadIdentifier) 159{ 160} 161 162ThreadIdentifier currentThread() 163{ 164 GThread* currentThread = g_thread_self(); 165 if (ThreadIdentifier id = identifierByGthreadHandle(currentThread)) 166 return id; 167 return establishIdentifierForThread(currentThread); 168} 169 170void yield() 171{ 172 g_thread_yield(); 173} 174 175Mutex::Mutex() 176 : m_mutex(g_mutex_new()) 177{ 178} 179 180Mutex::~Mutex() 181{ 182} 183 184void Mutex::lock() 185{ 186 g_mutex_lock(m_mutex.get()); 187} 188 189bool Mutex::tryLock() 190{ 191 return g_mutex_trylock(m_mutex.get()); 192} 193 194void Mutex::unlock() 195{ 196 g_mutex_unlock(m_mutex.get()); 197} 198 199ThreadCondition::ThreadCondition() 200 : m_condition(g_cond_new()) 201{ 202} 203 204ThreadCondition::~ThreadCondition() 205{ 206} 207 208void ThreadCondition::wait(Mutex& mutex) 209{ 210 g_cond_wait(m_condition.get(), mutex.impl().get()); 211} 212 213bool 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 235void ThreadCondition::signal() 236{ 237 g_cond_signal(m_condition.get()); 238} 239 240void ThreadCondition::broadcast() 241{ 242 g_cond_broadcast(m_condition.get()); 243} 244 245 246} 247 248#endif // !USE(PTHREADS) 249