1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "../private/SkLeanWindows.h"
9 #include "../private/SkSemaphore.h"
10
11 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
12 #include <mach/mach.h>
13
14 // We've got to teach TSAN that there is a happens-before edge beteween
15 // semaphore_signal() and semaphore_wait().
16 #if __has_feature(thread_sanitizer)
17 extern "C" void AnnotateHappensBefore(const char*, int, void*);
18 extern "C" void AnnotateHappensAfter (const char*, int, void*);
19 #else
AnnotateHappensBefore(const char *,int,void *)20 static void AnnotateHappensBefore(const char*, int, void*) {}
AnnotateHappensAfter(const char *,int,void *)21 static void AnnotateHappensAfter (const char*, int, void*) {}
22 #endif
23
24 struct SkBaseSemaphore::OSSemaphore {
25 semaphore_t fSemaphore;
26
OSSemaphoreSkBaseSemaphore::OSSemaphore27 OSSemaphore() {
28 semaphore_create(mach_task_self(), &fSemaphore, SYNC_POLICY_LIFO, 0/*initial count*/);
29 }
~OSSemaphoreSkBaseSemaphore::OSSemaphore30 ~OSSemaphore() { semaphore_destroy(mach_task_self(), fSemaphore); }
31
signalSkBaseSemaphore::OSSemaphore32 void signal(int n) {
33 while (n --> 0) {
34 AnnotateHappensBefore(__FILE__, __LINE__, &fSemaphore);
35 semaphore_signal(fSemaphore);
36 }
37 }
waitSkBaseSemaphore::OSSemaphore38 void wait() {
39 semaphore_wait(fSemaphore);
40 AnnotateHappensAfter(__FILE__, __LINE__, &fSemaphore);
41 }
42 };
43 #elif defined(SK_BUILD_FOR_WIN)
44 struct SkBaseSemaphore::OSSemaphore {
45 HANDLE fSemaphore;
46
OSSemaphoreSkBaseSemaphore::OSSemaphore47 OSSemaphore() {
48 fSemaphore = CreateSemaphore(nullptr /*security attributes, optional*/,
49 0 /*initial count*/,
50 MAXLONG /*max count*/,
51 nullptr /*name, optional*/);
52 }
~OSSemaphoreSkBaseSemaphore::OSSemaphore53 ~OSSemaphore() { CloseHandle(fSemaphore); }
54
signalSkBaseSemaphore::OSSemaphore55 void signal(int n) {
56 ReleaseSemaphore(fSemaphore, n, nullptr/*returns previous count, optional*/);
57 }
waitSkBaseSemaphore::OSSemaphore58 void wait() { WaitForSingleObject(fSemaphore, INFINITE/*timeout in ms*/); }
59 };
60 #else
61 // It's important we test for Mach before this. This code will compile but not work there.
62 #include <errno.h>
63 #include <semaphore.h>
64 struct SkBaseSemaphore::OSSemaphore {
65 sem_t fSemaphore;
66
OSSemaphoreSkBaseSemaphore::OSSemaphore67 OSSemaphore() { sem_init(&fSemaphore, 0/*cross process?*/, 0/*initial count*/); }
~OSSemaphoreSkBaseSemaphore::OSSemaphore68 ~OSSemaphore() { sem_destroy(&fSemaphore); }
69
signalSkBaseSemaphore::OSSemaphore70 void signal(int n) { while (n --> 0) { sem_post(&fSemaphore); } }
waitSkBaseSemaphore::OSSemaphore71 void wait() {
72 // Try until we're not interrupted.
73 while(sem_wait(&fSemaphore) == -1 && errno == EINTR);
74 }
75 };
76 #endif
77
78 ///////////////////////////////////////////////////////////////////////////////
79
osSignal(int n)80 void SkBaseSemaphore::osSignal(int n) {
81 fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
82 fOSSemaphore->signal(n);
83 }
84
osWait()85 void SkBaseSemaphore::osWait() {
86 fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
87 fOSSemaphore->wait();
88 }
89
cleanup()90 void SkBaseSemaphore::cleanup() {
91 delete fOSSemaphore;
92 }
93
try_wait()94 bool SkBaseSemaphore::try_wait() {
95 int count = fCount.load(std::memory_order_relaxed);
96 if (count > 0) {
97 return fCount.compare_exchange_weak(count, count-1, std::memory_order_acquire);
98 }
99 return false;
100 }
101