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
20         static void AnnotateHappensBefore(const char*, int, void*) {}
21         static void AnnotateHappensAfter (const char*, int, void*) {}
22     #endif
23 
24     struct SkBaseSemaphore::OSSemaphore {
25         semaphore_t fSemaphore;
26 
27         OSSemaphore()  {
28             semaphore_create(mach_task_self(), &fSemaphore, SYNC_POLICY_LIFO, 0/*initial count*/);
29         }
30         ~OSSemaphore() { semaphore_destroy(mach_task_self(), fSemaphore); }
31 
32         void signal(int n) {
33             while (n --> 0) {
34                 AnnotateHappensBefore(__FILE__, __LINE__, &fSemaphore);
35                 semaphore_signal(fSemaphore);
36             }
37         }
38         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 
47         OSSemaphore()  {
48             fSemaphore = CreateSemaphore(nullptr    /*security attributes, optional*/,
49                                          0       /*initial count*/,
50                                          MAXLONG /*max count*/,
51                                          nullptr    /*name, optional*/);
52         }
53         ~OSSemaphore() { CloseHandle(fSemaphore); }
54 
55         void signal(int n) {
56             ReleaseSemaphore(fSemaphore, n, nullptr/*returns previous count, optional*/);
57         }
58         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 
67         OSSemaphore()  { sem_init(&fSemaphore, 0/*cross process?*/, 0/*initial count*/); }
68         ~OSSemaphore() { sem_destroy(&fSemaphore); }
69 
70         void signal(int n) { while (n --> 0) { sem_post(&fSemaphore); } }
71         void wait() {
72             // Try until we're not interrupted.
73             while(sem_wait(&fSemaphore) == -1 && errno == EINTR);
74         }
75     };
76 #endif
77 
78 ///////////////////////////////////////////////////////////////////////////////
79 
80 void SkBaseSemaphore::osSignal(int n) {
81     fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
82     fOSSemaphore->signal(n);
83 }
84 
85 void SkBaseSemaphore::osWait() {
86     fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
87     fOSSemaphore->wait();
88 }
89 
90 void SkBaseSemaphore::cleanup() {
91     delete fOSSemaphore;
92 }
93 
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