1/*
2 * Copyright (C) 2007, 2008, 2010 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
31#pragma once
32
33#include <limits.h>
34#include <wtf/FastMalloc.h>
35#include <wtf/Locker.h>
36#include <wtf/Noncopyable.h>
37#include <wtf/WallTime.h>
38
39#if OS(WINDOWS)
40#include <windows.h>
41#endif
42
43#if USE(PTHREADS)
44#include <pthread.h>
45#if !defined(PTHREAD_KEYS_MAX)
46// PTHREAD_KEYS_MAX is not defined in bionic nor in Hurd, so explicitly define it here.
47#define PTHREAD_KEYS_MAX 1024
48#endif
49#endif
50
51#if OS(WINDOWS) && CPU(X86)
52#define THREAD_SPECIFIC_CALL __stdcall
53#else
54#define THREAD_SPECIFIC_CALL
55#endif
56
57namespace WTF {
58
59using ThreadFunction = void (*)(void* argument);
60
61#if USE(PTHREADS)
62using PlatformThreadHandle = pthread_t;
63using PlatformMutex = pthread_mutex_t;
64using PlatformCondition = pthread_cond_t;
65using ThreadSpecificKey = pthread_key_t;
66#elif OS(WINDOWS)
67using ThreadIdentifier = uint32_t;
68using PlatformThreadHandle = HANDLE;
69using PlatformMutex = SRWLOCK;
70using PlatformCondition = CONDITION_VARIABLE;
71using ThreadSpecificKey = DWORD;
72#else
73#error "Not supported platform"
74#endif
75
76class Mutex {
77 WTF_MAKE_NONCOPYABLE(Mutex);
78 WTF_MAKE_FAST_ALLOCATED;
79public:
80 constexpr Mutex() = default;
81 WTF_EXPORT_PRIVATE ~Mutex();
82
83 WTF_EXPORT_PRIVATE void lock();
84 WTF_EXPORT_PRIVATE bool tryLock();
85 WTF_EXPORT_PRIVATE void unlock();
86
87 PlatformMutex& impl() { return m_mutex; }
88
89private:
90#if USE(PTHREADS)
91 PlatformMutex m_mutex = PTHREAD_MUTEX_INITIALIZER;
92#elif OS(WINDOWS)
93 PlatformMutex m_mutex = SRWLOCK_INIT;
94#endif
95};
96
97typedef Locker<Mutex> MutexLocker;
98
99class ThreadCondition {
100 WTF_MAKE_NONCOPYABLE(ThreadCondition);
101 WTF_MAKE_FAST_ALLOCATED;
102public:
103 constexpr ThreadCondition() = default;
104 WTF_EXPORT_PRIVATE ~ThreadCondition();
105
106 WTF_EXPORT_PRIVATE void wait(Mutex& mutex);
107 // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past.
108 WTF_EXPORT_PRIVATE bool timedWait(Mutex&, WallTime absoluteTime);
109 WTF_EXPORT_PRIVATE void signal();
110 WTF_EXPORT_PRIVATE void broadcast();
111
112private:
113#if USE(PTHREADS)
114 PlatformCondition m_condition = PTHREAD_COND_INITIALIZER;
115#elif OS(WINDOWS)
116 PlatformCondition m_condition = CONDITION_VARIABLE_INIT;
117#endif
118};
119
120#if USE(PTHREADS)
121
122static constexpr ThreadSpecificKey InvalidThreadSpecificKey = PTHREAD_KEYS_MAX;
123
124inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
125{
126 int error = pthread_key_create(key, destructor);
127 if (error)
128 CRASH();
129}
130
131inline void threadSpecificKeyDelete(ThreadSpecificKey key)
132{
133 int error = pthread_key_delete(key);
134 if (error)
135 CRASH();
136}
137
138inline void threadSpecificSet(ThreadSpecificKey key, void* value)
139{
140 pthread_setspecific(key, value);
141}
142
143inline void* threadSpecificGet(ThreadSpecificKey key)
144{
145 return pthread_getspecific(key);
146}
147
148#elif OS(WINDOWS)
149
150static constexpr ThreadSpecificKey InvalidThreadSpecificKey = FLS_OUT_OF_INDEXES;
151
152inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (THREAD_SPECIFIC_CALL *destructor)(void *))
153{
154 DWORD flsKey = FlsAlloc(destructor);
155 if (flsKey == FLS_OUT_OF_INDEXES)
156 CRASH();
157
158 *key = flsKey;
159}
160
161inline void threadSpecificKeyDelete(ThreadSpecificKey key)
162{
163 FlsFree(key);
164}
165
166inline void threadSpecificSet(ThreadSpecificKey key, void* data)
167{
168 FlsSetValue(key, data);
169}
170
171inline void* threadSpecificGet(ThreadSpecificKey key)
172{
173 return FlsGetValue(key);
174}
175
176#endif
177
178} // namespace WTF
179
180using WTF::Mutex;
181using WTF::MutexLocker;
182using WTF::ThreadCondition;
183