1d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com/*
2d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com * Copyright 2013 Google Inc.
3d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com *
4d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com * Use of this source code is governed by a BSD-style license that can be
5d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com * found in the LICENSE file.
6d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com */
7d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
8d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com#ifndef SkMutex_pthread_DEFINED
9d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com#define SkMutex_pthread_DEFINED
10d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
11d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com/** Posix pthread_mutex based mutex. */
12d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
13d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com#include <errno.h>
14d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com#include <pthread.h>
15d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
16d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// A SkBaseMutex is a POD structure that can be directly initialized
17d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// at declaration time with SK_DECLARE_STATIC/GLOBAL_MUTEX. This avoids the
18d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// generation of a static initializer in the final machine code (and
19d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// a corresponding static finalizer).
20d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.comstruct SkBaseMutex {
21b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    void acquire() {
22e486ec48b1dbdc6e8276a765abeb8eabcbf5c22ehalcanary        SkASSERT(fOwner != pthread_self());  // SkMutex is not re-entrant
23b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        pthread_mutex_lock(&fMutex);
24b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        SkDEBUGCODE(fOwner = pthread_self();)
25b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    }
26b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    void release() {
27b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        this->assertHeld();
28b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        SkDEBUGCODE(fOwner = 0;)
29b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        pthread_mutex_unlock(&fMutex);
30b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    }
31b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    void assertHeld() {
32b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        SkASSERT(pthread_self() == fOwner);
33b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    }
34b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein
35d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    pthread_mutex_t fMutex;
36b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    SkDEBUGCODE(pthread_t fOwner;)
37d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com};
38d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
39d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// A normal mutex that requires to be initialized through normal C++ construction,
40d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// i.e. when it's a member of another class, or allocated on the heap.
41d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.comclass SkMutex : public SkBaseMutex {
42d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.compublic:
43d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    SkMutex() {
44b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        SkDEBUGCODE(int status = )pthread_mutex_init(&fMutex, NULL);
45b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        SkDEBUGCODE(
46d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            if (status != 0) {
47d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com                print_pthread_error(status);
48d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com                SkASSERT(0 == status);
49d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            }
50d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        )
51d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    }
52d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
53d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    ~SkMutex() {
54b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        SkDEBUGCODE(int status = )pthread_mutex_destroy(&fMutex);
55b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein        SkDEBUGCODE(
56d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            if (status != 0) {
57d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com                print_pthread_error(status);
58d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com                SkASSERT(0 == status);
59d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            }
60d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        )
61d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    }
62d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
63d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.comprivate:
64d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    SkMutex(const SkMutex&);
65d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    SkMutex& operator=(const SkMutex&);
66d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
67d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    static void print_pthread_error(int status) {
68d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        switch (status) {
69d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        case 0: // success
70d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            break;
71d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        case EINVAL:
72d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            SkDebugf("pthread error [%d] EINVAL\n", status);
73d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            break;
74d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        case EBUSY:
75d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            SkDebugf("pthread error [%d] EBUSY\n", status);
76d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            break;
77d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        default:
78d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            SkDebugf("pthread error [%d] unknown\n", status);
79d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            break;
80d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com        }
81d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com    }
82d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com};
83d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
84b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein#define SK_BASE_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, SkDEBUGCODE(0) }
85b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein
86d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// Using POD-style initialization prevents the generation of a static initializer.
87b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name = SK_BASE_MUTEX_INIT
88d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
89d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com// Special case used when the static mutex must be available globally.
90b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein#define SK_DECLARE_GLOBAL_MUTEX(name) SkBaseMutex name = SK_BASE_MUTEX_INIT
91d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com
92d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com#endif
93