• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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