Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(907)

Side by Side Diff: third_party/WebKit/Source/wtf/ThreadingWin.cpp

Issue 2767153004: Move files in wtf/ to platform/wtf/ (Part 12). (Closed)
Patch Set: Rebase. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /*
32 * There are numerous academic and practical works on how to implement
33 * pthread_cond_wait/pthread_cond_signal/pthread_cond_broadcast
34 * functions on Win32. Here is one example:
35 * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html which is widely credited as
36 * a 'starting point' of modern attempts. There are several more or less proven
37 * implementations, one in Boost C++ library (http://www.boost.org) and another
38 * in pthreads-win32 (http://sourceware.org/pthreads-win32/).
39 *
40 * The number of articles and discussions is the evidence of significant
41 * difficulties in implementing these primitives correctly. The brief search
42 * of revisions, ChangeLog entries, discussions in comp.programming.threads and
43 * other places clearly documents numerous pitfalls and performance problems
44 * the authors had to overcome to arrive to the suitable implementations.
45 * Optimally, WebKit would use one of those supported/tested libraries
46 * directly. To roll out our own implementation is impractical, if even for
47 * the lack of sufficient testing. However, a faithful reproduction of the code
48 * from one of the popular supported libraries seems to be a good compromise.
49 *
50 * The early Boost implementation
51 * (http://www.boxbackup.org/trac/browser/box/nick/win/lib/win32/boost_1_32_0/li bs/thread/src/condition.cpp?rev=30)
52 * is identical to pthreads-win32
53 * (http://sourceware.org/cgi-bin/cvsweb.cgi/pthreads/pthread_cond_wait.c?rev=1. 10&content-type=text/x-cvsweb-markup&cvsroot=pthreads-win32).
54 * Current Boost uses yet another (although seemingly equivalent) algorithm
55 * which came from their 'thread rewrite' effort.
56 *
57 * This file includes timedWait/signal/broadcast implementations translated to
58 * WebKit coding style from the latest algorithm by Alexander Terekhov and
59 * Louis Thomas, as captured here:
60 * http://sourceware.org/cgi-bin/cvsweb.cgi/pthreads/pthread_cond_wait.c?rev=1.1 0&content-type=text/x-cvsweb-markup&cvsroot=pthreads-win32
61 * It replaces the implementation of their previous algorithm, also documented
62 * in the same source above. The naming and comments are left very close to
63 * original to enable easy cross-check.
64 *
65 * The corresponding Pthreads-win32 License is included below, and CONTRIBUTORS
66 * file which it refers to is added to source directory (as
67 * CONTRIBUTORS.pthreads-win32).
68 */
69
70 /*
71 * Pthreads-win32 - POSIX Threads Library for Win32
72 * Copyright(C) 1998 John E. Bossom
73 * Copyright(C) 1999,2005 Pthreads-win32 contributors
74 *
75 * Contact Email: rpj@callisto.canberra.edu.au
76 *
77 * The current list of contributors is contained
78 * in the file CONTRIBUTORS included with the source
79 * code distribution. The list can also be seen at the
80 * following World Wide Web location:
81 * http://sources.redhat.com/pthreads-win32/contributors.html
82 *
83 * This library is free software; you can redistribute it and/or
84 * modify it under the terms of the GNU Lesser General Public
85 * License as published by the Free Software Foundation; either
86 * version 2 of the License, or (at your option) any later version.
87 *
88 * This library is distributed in the hope that it will be useful,
89 * but WITHOUT ANY WARRANTY; without even the implied warranty of
90 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
91 * Lesser General Public License for more details.
92 *
93 * You should have received a copy of the GNU Lesser General Public
94 * License along with this library in the file COPYING.LIB;
95 * if not, write to the Free Software Foundation, Inc.,
96 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
97 */
98
99 #include "wtf/Threading.h"
100
101 #if OS(WIN)
102
103 #include "wtf/CurrentTime.h"
104 #include "wtf/DateMath.h"
105 #include "wtf/HashMap.h"
106 #include "wtf/MathExtras.h"
107 #include "wtf/ThreadSpecific.h"
108 #include "wtf/ThreadingPrimitives.h"
109 #include "wtf/WTFThreadData.h"
110 #include "wtf/dtoa/double-conversion.h"
111 #include <errno.h>
112 #include <process.h>
113 #include <windows.h>
114
115 namespace WTF {
116
117 // THREADNAME_INFO comes from
118 // <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
119 #pragma pack(push, 8)
120 typedef struct tagTHREADNAME_INFO {
121 DWORD dwType; // must be 0x1000
122 LPCSTR szName; // pointer to name (in user addr space)
123 DWORD dwThreadID; // thread ID (-1=caller thread)
124 DWORD dwFlags; // reserved for future use, must be zero
125 } THREADNAME_INFO;
126 #pragma pack(pop)
127
128 namespace internal {
129
130 ThreadIdentifier currentThreadSyscall() {
131 return static_cast<ThreadIdentifier>(GetCurrentThreadId());
132 }
133
134 } // namespace internal
135
136 void initializeThreading() {
137 // This should only be called once.
138 WTFThreadData::initialize();
139
140 initializeDates();
141 // Force initialization of static DoubleToStringConverter converter variable
142 // inside EcmaScriptConverter function while we are in single thread mode.
143 double_conversion::DoubleToStringConverter::EcmaScriptConverter();
144 }
145
146 namespace {
147 ThreadSpecificKey s_currentThreadKey;
148 bool s_currentThreadKeyInitialized = false;
149 } // namespace
150
151 void initializeCurrentThread() {
152 DCHECK(!s_currentThreadKeyInitialized);
153 threadSpecificKeyCreate(&s_currentThreadKey, [](void*) {});
154 s_currentThreadKeyInitialized = true;
155 }
156
157 ThreadIdentifier currentThread() {
158 // This doesn't use WTF::ThreadSpecific (e.g. WTFThreadData) because
159 // ThreadSpecific now depends on currentThread. It is necessary to avoid this
160 // or a similar loop:
161 //
162 // currentThread
163 // -> wtfThreadData
164 // -> ThreadSpecific::operator*
165 // -> isMainThread
166 // -> currentThread
167 static_assert(sizeof(ThreadIdentifier) <= sizeof(void*),
168 "ThreadIdentifier must fit in a void*.");
169 DCHECK(s_currentThreadKeyInitialized);
170 void* value = threadSpecificGet(s_currentThreadKey);
171 if (UNLIKELY(!value)) {
172 value = reinterpret_cast<void*>(internal::currentThreadSyscall());
173 DCHECK(value);
174 threadSpecificSet(s_currentThreadKey, value);
175 }
176 return reinterpret_cast<intptr_t>(threadSpecificGet(s_currentThreadKey));
177 }
178
179 MutexBase::MutexBase(bool recursive) {
180 m_mutex.m_recursionCount = 0;
181 InitializeCriticalSection(&m_mutex.m_internalMutex);
182 }
183
184 MutexBase::~MutexBase() {
185 DeleteCriticalSection(&m_mutex.m_internalMutex);
186 }
187
188 void MutexBase::lock() {
189 EnterCriticalSection(&m_mutex.m_internalMutex);
190 ++m_mutex.m_recursionCount;
191 }
192
193 void MutexBase::unlock() {
194 DCHECK(m_mutex.m_recursionCount);
195 --m_mutex.m_recursionCount;
196 LeaveCriticalSection(&m_mutex.m_internalMutex);
197 }
198
199 bool Mutex::tryLock() {
200 // This method is modeled after the behavior of pthread_mutex_trylock,
201 // which will return an error if the lock is already owned by the
202 // current thread. Since the primitive Win32 'TryEnterCriticalSection'
203 // treats this as a successful case, it changes the behavior of several
204 // tests in WebKit that check to see if the current thread already
205 // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
206 DWORD result = TryEnterCriticalSection(&m_mutex.m_internalMutex);
207
208 if (result != 0) { // We got the lock
209 // If this thread already had the lock, we must unlock and return
210 // false since this is a non-recursive mutex. This is to mimic the
211 // behavior of POSIX's pthread_mutex_trylock. We don't do this
212 // check in the lock method (presumably due to performance?). This
213 // means lock() will succeed even if the current thread has already
214 // entered the critical section.
215 if (m_mutex.m_recursionCount > 0) {
216 LeaveCriticalSection(&m_mutex.m_internalMutex);
217 return false;
218 }
219 ++m_mutex.m_recursionCount;
220 return true;
221 }
222
223 return false;
224 }
225
226 bool RecursiveMutex::tryLock() {
227 // CRITICAL_SECTION is recursive/reentrant so TryEnterCriticalSection will
228 // succeed if the current thread is already in the critical section.
229 DWORD result = TryEnterCriticalSection(&m_mutex.m_internalMutex);
230 if (result == 0) { // We didn't get the lock.
231 return false;
232 }
233 ++m_mutex.m_recursionCount;
234 return true;
235 }
236
237 bool PlatformCondition::timedWait(PlatformMutex& mutex,
238 DWORD durationMilliseconds) {
239 // Enter the wait state.
240 DWORD res = WaitForSingleObject(m_blockLock, INFINITE);
241 DCHECK_EQ(res, WAIT_OBJECT_0);
242 ++m_waitersBlocked;
243 res = ReleaseSemaphore(m_blockLock, 1, 0);
244 DCHECK(res);
245
246 --mutex.m_recursionCount;
247 LeaveCriticalSection(&mutex.m_internalMutex);
248
249 // Main wait - use timeout.
250 bool timedOut =
251 (WaitForSingleObject(m_blockQueue, durationMilliseconds) == WAIT_TIMEOUT);
252
253 res = WaitForSingleObject(m_unblockLock, INFINITE);
254 DCHECK_EQ(res, WAIT_OBJECT_0);
255
256 int signalsLeft = m_waitersToUnblock;
257
258 if (m_waitersToUnblock) {
259 --m_waitersToUnblock;
260 } else if (++m_waitersGone == (INT_MAX / 2)) {
261 // timeout/canceled or spurious semaphore timeout or spurious wakeup
262 // occured, normalize the m_waitersGone count this may occur if many
263 // calls to wait with a timeout are made and no call to notify_* is made
264 res = WaitForSingleObject(m_blockLock, INFINITE);
265 DCHECK_EQ(res, WAIT_OBJECT_0);
266 m_waitersBlocked -= m_waitersGone;
267 res = ReleaseSemaphore(m_blockLock, 1, 0);
268 DCHECK(res);
269 m_waitersGone = 0;
270 }
271
272 res = ReleaseMutex(m_unblockLock);
273 DCHECK(res);
274
275 if (signalsLeft == 1) {
276 res = ReleaseSemaphore(m_blockLock, 1, 0); // Open the gate.
277 DCHECK(res);
278 }
279
280 EnterCriticalSection(&mutex.m_internalMutex);
281 ++mutex.m_recursionCount;
282
283 return !timedOut;
284 }
285
286 void PlatformCondition::signal(bool unblockAll) {
287 unsigned signalsToIssue = 0;
288
289 DWORD res = WaitForSingleObject(m_unblockLock, INFINITE);
290 DCHECK_EQ(res, WAIT_OBJECT_0);
291
292 if (m_waitersToUnblock) { // the gate is already closed
293 if (!m_waitersBlocked) { // no-op
294 res = ReleaseMutex(m_unblockLock);
295 DCHECK(res);
296 return;
297 }
298
299 if (unblockAll) {
300 signalsToIssue = m_waitersBlocked;
301 m_waitersToUnblock += m_waitersBlocked;
302 m_waitersBlocked = 0;
303 } else {
304 signalsToIssue = 1;
305 ++m_waitersToUnblock;
306 --m_waitersBlocked;
307 }
308 } else if (m_waitersBlocked > m_waitersGone) {
309 res = WaitForSingleObject(m_blockLock, INFINITE); // Close the gate.
310 DCHECK_EQ(res, WAIT_OBJECT_0);
311 if (m_waitersGone != 0) {
312 m_waitersBlocked -= m_waitersGone;
313 m_waitersGone = 0;
314 }
315 if (unblockAll) {
316 signalsToIssue = m_waitersBlocked;
317 m_waitersToUnblock = m_waitersBlocked;
318 m_waitersBlocked = 0;
319 } else {
320 signalsToIssue = 1;
321 m_waitersToUnblock = 1;
322 --m_waitersBlocked;
323 }
324 } else { // No-op.
325 res = ReleaseMutex(m_unblockLock);
326 DCHECK(res);
327 return;
328 }
329
330 res = ReleaseMutex(m_unblockLock);
331 DCHECK(res);
332
333 if (signalsToIssue) {
334 res = ReleaseSemaphore(m_blockQueue, signalsToIssue, 0);
335 DCHECK(res);
336 }
337 }
338
339 static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
340
341 ThreadCondition::ThreadCondition() {
342 m_condition.m_waitersGone = 0;
343 m_condition.m_waitersBlocked = 0;
344 m_condition.m_waitersToUnblock = 0;
345 m_condition.m_blockLock = CreateSemaphore(0, 1, 1, 0);
346 m_condition.m_blockQueue = CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
347 m_condition.m_unblockLock = CreateMutex(0, 0, 0);
348
349 if (!m_condition.m_blockLock || !m_condition.m_blockQueue ||
350 !m_condition.m_unblockLock) {
351 if (m_condition.m_blockLock)
352 CloseHandle(m_condition.m_blockLock);
353 if (m_condition.m_blockQueue)
354 CloseHandle(m_condition.m_blockQueue);
355 if (m_condition.m_unblockLock)
356 CloseHandle(m_condition.m_unblockLock);
357
358 m_condition.m_blockLock = nullptr;
359 m_condition.m_blockQueue = nullptr;
360 m_condition.m_unblockLock = nullptr;
361 }
362 }
363
364 ThreadCondition::~ThreadCondition() {
365 if (m_condition.m_blockLock)
366 CloseHandle(m_condition.m_blockLock);
367 if (m_condition.m_blockQueue)
368 CloseHandle(m_condition.m_blockQueue);
369 if (m_condition.m_unblockLock)
370 CloseHandle(m_condition.m_unblockLock);
371 }
372
373 void ThreadCondition::wait(MutexBase& mutex) {
374 m_condition.timedWait(mutex.impl(), INFINITE);
375 }
376
377 bool ThreadCondition::timedWait(MutexBase& mutex, double absoluteTime) {
378 DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
379
380 if (!interval) {
381 // Consider the wait to have timed out, even if our condition has already
382 // been signaled, to match the pthreads implementation.
383 return false;
384 }
385
386 return m_condition.timedWait(mutex.impl(), interval);
387 }
388
389 void ThreadCondition::signal() {
390 m_condition.signal(false); // Unblock only 1 thread.
391 }
392
393 void ThreadCondition::broadcast() {
394 m_condition.signal(true); // Unblock all threads.
395 }
396
397 DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime) {
398 double currentTime = WTF::currentTime();
399
400 // Time is in the past - return immediately.
401 if (absoluteTime < currentTime)
402 return 0;
403
404 // Time is too far in the future (and would overflow unsigned long) - wait
405 // forever.
406 if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0)
407 return INFINITE;
408
409 return static_cast<DWORD>((absoluteTime - currentTime) * 1000.0);
410 }
411
412 #if DCHECK_IS_ON()
413 static bool s_threadCreated = false;
414
415 bool isBeforeThreadCreated() {
416 return !s_threadCreated;
417 }
418
419 void willCreateThread() {
420 s_threadCreated = true;
421 }
422 #endif
423
424 } // namespace WTF
425
426 #endif // OS(WIN)
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/ThreadingPthreads.cpp ('k') | third_party/WebKit/Source/wtf/WTF.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698