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 "include/private/SkSemaphore.h"
9 #include "src/core/SkLeanWindows.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 between
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 SkSemaphore::OSSemaphore {
25 semaphore_t fSemaphore;
26
OSSemaphoreSkSemaphore::OSSemaphore27 OSSemaphore() {
28 semaphore_create(mach_task_self(), &fSemaphore, SYNC_POLICY_LIFO, 0/*initial count*/);
29 }
~OSSemaphoreSkSemaphore::OSSemaphore30 ~OSSemaphore() { semaphore_destroy(mach_task_self(), fSemaphore); }
31
signalSkSemaphore::OSSemaphore32 void signal(int n) {
33 while (n --> 0) {
34 AnnotateHappensBefore(__FILE__, __LINE__, &fSemaphore);
35 semaphore_signal(fSemaphore);
36 }
37 }
waitSkSemaphore::OSSemaphore38 void wait() {
39 while (true) {
40 kern_return_t result = semaphore_wait(fSemaphore);
41 if (result == KERN_SUCCESS) {
42 AnnotateHappensAfter(__FILE__, __LINE__, &fSemaphore);
43 return;
44 }
45 SkASSERT(result == KERN_ABORTED);
46 }
47 }
48 };
49 #elif defined(SK_BUILD_FOR_WIN)
50 struct SkSemaphore::OSSemaphore {
51 HANDLE fSemaphore;
52
OSSemaphoreSkSemaphore::OSSemaphore53 OSSemaphore() {
54 fSemaphore = CreateSemaphore(nullptr /*security attributes, optional*/,
55 0 /*initial count*/,
56 MAXLONG /*max count*/,
57 nullptr /*name, optional*/);
58 }
~OSSemaphoreSkSemaphore::OSSemaphore59 ~OSSemaphore() { CloseHandle(fSemaphore); }
60
signalSkSemaphore::OSSemaphore61 void signal(int n) {
62 ReleaseSemaphore(fSemaphore, n, nullptr/*returns previous count, optional*/);
63 }
waitSkSemaphore::OSSemaphore64 void wait() { WaitForSingleObject(fSemaphore, INFINITE/*timeout in ms*/); }
65 };
66 #else
67 // It's important we test for Mach before this. This code will compile but not work there.
68 #include <errno.h>
69 #include <semaphore.h>
70 struct SkSemaphore::OSSemaphore {
71 sem_t fSemaphore;
72
OSSemaphoreSkSemaphore::OSSemaphore73 OSSemaphore() { sem_init(&fSemaphore, 0/*cross process?*/, 0/*initial count*/); }
~OSSemaphoreSkSemaphore::OSSemaphore74 ~OSSemaphore() { sem_destroy(&fSemaphore); }
75
signalSkSemaphore::OSSemaphore76 void signal(int n) { while (n --> 0) { sem_post(&fSemaphore); } }
waitSkSemaphore::OSSemaphore77 void wait() {
78 // Try until we're not interrupted.
79 while(sem_wait(&fSemaphore) == -1 && errno == EINTR);
80 }
81 };
82 #endif
83
84 ///////////////////////////////////////////////////////////////////////////////
85
~SkSemaphore()86 SkSemaphore::~SkSemaphore() {
87 delete fOSSemaphore;
88 }
89
osSignal(int n)90 void SkSemaphore::osSignal(int n) {
91 fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
92 fOSSemaphore->signal(n);
93 }
94
osWait()95 void SkSemaphore::osWait() {
96 fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
97 fOSSemaphore->wait();
98 }
99
try_wait()100 bool SkSemaphore::try_wait() {
101 int count = fCount.load(std::memory_order_relaxed);
102 if (count > 0) {
103 return fCount.compare_exchange_weak(count, count-1, std::memory_order_acquire);
104 }
105 return false;
106 }
107