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/SkSemaphore.h"
      9 
     10 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
     11     #include <mach/mach.h>
     12     struct SkBaseSemaphore::OSSemaphore {
     13         semaphore_t fSemaphore;
     14 
     15         OSSemaphore()  {
     16             semaphore_create(mach_task_self(), &fSemaphore, SYNC_POLICY_LIFO, 0/*initial count*/);
     17         }
     18         ~OSSemaphore() { semaphore_destroy(mach_task_self(), fSemaphore); }
     19 
     20         void signal(int n) { while (n --> 0) { semaphore_signal(fSemaphore); } }
     21         void wait() { semaphore_wait(fSemaphore); }
     22     };
     23 #elif defined(SK_BUILD_FOR_WIN32)
     24     struct SkBaseSemaphore::OSSemaphore {
     25         HANDLE fSemaphore;
     26 
     27         OSSemaphore()  {
     28             fSemaphore = CreateSemaphore(nullptr    /*security attributes, optional*/,
     29                                          0       /*initial count*/,
     30                                          MAXLONG /*max count*/,
     31                                          nullptr    /*name, optional*/);
     32         }
     33         ~OSSemaphore() { CloseHandle(fSemaphore); }
     34 
     35         void signal(int n) {
     36             ReleaseSemaphore(fSemaphore, n, nullptr/*returns previous count, optional*/);
     37         }
     38         void wait() { WaitForSingleObject(fSemaphore, INFINITE/*timeout in ms*/); }
     39     };
     40 #else
     41     // It's important we test for Mach before this.  This code will compile but not work there.
     42     #include <errno.h>
     43     #include <semaphore.h>
     44     struct SkBaseSemaphore::OSSemaphore {
     45         sem_t fSemaphore;
     46 
     47         OSSemaphore()  { sem_init(&fSemaphore, 0/*cross process?*/, 0/*initial count*/); }
     48         ~OSSemaphore() { sem_destroy(&fSemaphore); }
     49 
     50         void signal(int n) { while (n --> 0) { sem_post(&fSemaphore); } }
     51         void wait() {
     52             // Try until we're not interrupted.
     53             while(sem_wait(&fSemaphore) == -1 && errno == EINTR);
     54         }
     55     };
     56 #endif
     57 
     58 ///////////////////////////////////////////////////////////////////////////////
     59 
     60 void SkBaseSemaphore::signal(int n) {
     61     SkASSERT(n >= 0);
     62 
     63     // We only want to call the OS semaphore when our logical count crosses
     64     // from <= 0 to >0 (when we need to wake sleeping threads).
     65     //
     66     // This is easiest to think about with specific examples of prev and n.
     67     // If n == 5 and prev == -3, there are 3 threads sleeping and we signal
     68     // SkTMin(-(-3), 5) == 3 times on the OS semaphore, leaving the count at 2.
     69     //
     70     // If prev >= 0, no threads are waiting, SkTMin(-prev, n) is always <= 0,
     71     // so we don't call the OS semaphore, leaving the count at (prev + n).
     72     int prev = sk_atomic_fetch_add(&fCount, n, sk_memory_order_release);
     73     int toSignal = SkTMin(-prev, n);
     74     if (toSignal > 0) {
     75         this->osSignal(toSignal);
     76     }
     77 }
     78 
     79 static SkBaseSemaphore::OSSemaphore* semaphore(SkBaseSemaphore* semaphore) {
     80     return semaphore->fOSSemaphore.get([](){ return new SkBaseSemaphore::OSSemaphore(); });
     81 }
     82 
     83 void SkBaseSemaphore::osSignal(int n) { semaphore(this)->signal(n); }
     84 
     85 void SkBaseSemaphore::osWait() { semaphore(this)->wait(); }
     86 
     87 void SkBaseSemaphore::deleteSemaphore() {
     88     delete (OSSemaphore*) fOSSemaphore;
     89 }
     90 
     91 ///////////////////////////////////////////////////////////////////////////////
     92 
     93 SkSemaphore::SkSemaphore(){ fBaseSemaphore = {0, {0}}; }
     94 
     95 SkSemaphore::~SkSemaphore() { fBaseSemaphore.deleteSemaphore(); }
     96 
     97 void SkSemaphore::wait() { fBaseSemaphore.wait(); }
     98 
     99 void SkSemaphore::signal(int n) {fBaseSemaphore.signal(n); }
    100