Home | History | Annotate | Download | only in core
      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