1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "../private/SkLeanWindows.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "../private/SkSemaphore.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include <mach/mach.h>
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We've got to teach TSAN that there is a happens-before edge beteween
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // semaphore_signal() and semaphore_wait().
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #if __has_feature(thread_sanitizer)
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        extern "C" void AnnotateHappensBefore(const char*, int, void*);
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        extern "C" void AnnotateHappensAfter (const char*, int, void*);
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #else
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static void AnnotateHappensBefore(const char*, int, void*) {}
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static void AnnotateHappensAfter (const char*, int, void*) {}
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #endif
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct SkBaseSemaphore::OSSemaphore {
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        semaphore_t fSemaphore;
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        OSSemaphore()  {
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            semaphore_create(mach_task_self(), &fSemaphore, SYNC_POLICY_LIFO, 0/*initial count*/);
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ~OSSemaphore() { semaphore_destroy(mach_task_self(), fSemaphore); }
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void signal(int n) {
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (n --> 0) {
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                AnnotateHappensBefore(__FILE__, __LINE__, &fSemaphore);
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                semaphore_signal(fSemaphore);
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void wait() {
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            semaphore_wait(fSemaphore);
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            AnnotateHappensAfter(__FILE__, __LINE__, &fSemaphore);
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#elif defined(SK_BUILD_FOR_WIN)
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct SkBaseSemaphore::OSSemaphore {
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        HANDLE fSemaphore;
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        OSSemaphore()  {
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fSemaphore = CreateSemaphore(nullptr    /*security attributes, optional*/,
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         0       /*initial count*/,
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         MAXLONG /*max count*/,
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         nullptr    /*name, optional*/);
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ~OSSemaphore() { CloseHandle(fSemaphore); }
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void signal(int n) {
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ReleaseSemaphore(fSemaphore, n, nullptr/*returns previous count, optional*/);
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void wait() { WaitForSingleObject(fSemaphore, INFINITE/*timeout in ms*/); }
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // It's important we test for Mach before this.  This code will compile but not work there.
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include <errno.h>
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include <semaphore.h>
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct SkBaseSemaphore::OSSemaphore {
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sem_t fSemaphore;
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        OSSemaphore()  { sem_init(&fSemaphore, 0/*cross process?*/, 0/*initial count*/); }
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ~OSSemaphore() { sem_destroy(&fSemaphore); }
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void signal(int n) { while (n --> 0) { sem_post(&fSemaphore); } }
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void wait() {
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Try until we're not interrupted.
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while(sem_wait(&fSemaphore) == -1 && errno == EINTR);
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBaseSemaphore::osSignal(int n) {
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fOSSemaphore->signal(n);
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBaseSemaphore::osWait() {
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fOSSemaphoreOnce([this] { fOSSemaphore = new OSSemaphore; });
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fOSSemaphore->wait();
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBaseSemaphore::cleanup() {
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    delete fOSSemaphore;
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkBaseSemaphore::try_wait() {
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count = fCount.load(std::memory_order_relaxed);
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (count > 0) {
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fCount.compare_exchange_weak(count, count-1, std::memory_order_acquire);
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
101