1/*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20/*
21    Locks.h
22    Scoped Locking Primitives
23    Copyright (c) 2004-2011 Apple Inc. All rights reserved.
24 */
25
26#pragma once
27#ifndef __AUTO_LOCK__
28#define __AUTO_LOCK__
29
30
31#include <assert.h>
32
33#include "Definitions.h"
34#include "auto_impl_utilities.h"
35
36namespace Auto {
37
38    //----- LockedBoolean -----//
39
40    // Interlocked Boolean value.
41
42    struct LockedBoolean {
43        volatile bool state;
44        spin_lock_t lock;
45        LockedBoolean() : state(false), lock(0) {}
46    };
47
48    //----- SpinLock -----//
49
50    // Scoped uses of spin_lock() / spin_unlock().
51
52    class SpinLock {
53        spin_lock_t *_lock;
54    public:
55        SpinLock(spin_lock_t *lock) : _lock(lock)   { spin_lock(_lock); }
56        ~SpinLock()                                 { spin_unlock(_lock); }
57    };
58
59    class TrySpinLock {
60        spin_lock_t *_lock;
61    public:
62        TrySpinLock(spin_lock_t *lock) : _lock(lock) { if (_lock && !spin_lock_try(_lock)) _lock = NULL; }
63        operator int()                               { return (_lock != NULL); }
64        ~TrySpinLock()                               { if (_lock) spin_unlock(_lock); }
65    };
66
67    // Scoped conditional uses of spin_lock() / spin_unlock().
68
69    class ConditionBarrier {
70    private:
71        spin_lock_t *_lock;
72
73        void check(bool volatile *condition, spin_lock_t *lock) {
74            if (*condition) {
75                spin_lock(lock);
76                if (!*condition) {
77                    spin_unlock(lock);
78                } else {
79                    _lock = lock;
80                }
81            }
82        }
83    public:
84        ConditionBarrier(bool volatile *condition, spin_lock_t *lock) : _lock(NULL) {
85            check(condition, lock);
86        }
87        ConditionBarrier(LockedBoolean &condition) : _lock(NULL) {
88            check(&condition.state, &condition.lock);
89        }
90        operator int() { return _lock != NULL; }
91        ~ConditionBarrier() { if (_lock) spin_unlock(_lock); }
92    };
93
94    class UnconditionalBarrier {
95        bool volatile *_condition;
96        spin_lock_t *_lock;
97    public:
98        UnconditionalBarrier(bool volatile *condition, spin_lock_t *lock) : _condition(condition), _lock(lock) {
99            spin_lock(_lock);
100        }
101        UnconditionalBarrier(LockedBoolean &condition) : _condition(&condition.state), _lock(&condition.lock) {
102            spin_lock(_lock);
103        }
104        operator int() { return (*_condition != false); }
105        ~UnconditionalBarrier() { spin_unlock(_lock); }
106    };
107
108    // Scoped uses of pthread_mutex_t.
109
110    class Mutex {
111        pthread_mutex_t *_mutex;
112    public:
113        Mutex(pthread_mutex_t *mutex) : _mutex(mutex) { if (_mutex) pthread_mutex_lock(_mutex); }
114        ~Mutex() { if (_mutex) pthread_mutex_unlock(_mutex); }
115    };
116
117    class TryMutex {
118        pthread_mutex_t *_mutex;
119    public:
120        TryMutex(pthread_mutex_t *mutex) : _mutex(mutex) { if (_mutex && pthread_mutex_trylock(_mutex) != 0) _mutex = NULL; }
121        operator int() { return (_mutex != NULL); }
122        ~TryMutex() { if (_mutex) pthread_mutex_unlock(_mutex); }
123    };
124
125    class ReadLock {
126        pthread_rwlock_t *_lock;
127    public:
128        ReadLock(pthread_rwlock_t *lock) : _lock(lock) { if (_lock) pthread_rwlock_rdlock(_lock); }
129        ~ReadLock() { if (_lock) pthread_rwlock_unlock(_lock); }
130    };
131
132    class WriteLock {
133        pthread_rwlock_t *_lock;
134    public:
135        WriteLock(pthread_rwlock_t *lock) : _lock(lock) { if (_lock) pthread_rwlock_wrlock(_lock); }
136        ~WriteLock() { if (_lock) pthread_rwlock_unlock(_lock); }
137    };
138
139    class TryWriteLock {
140        pthread_rwlock_t *_lock;
141    public:
142        TryWriteLock(pthread_rwlock_t *lock) : _lock(lock) { if (_lock && pthread_rwlock_trywrlock(_lock) != 0) _lock = NULL; }
143        operator int() { return (_lock != NULL); }
144        ~TryWriteLock() { if (_lock) pthread_rwlock_unlock(_lock); }
145    };
146
147    typedef uint32_t sentinel_t;
148#define SENTINEL_T_INITIALIZER 0
149
150    class Sentinel {
151        sentinel_t &_guard;
152    public:
153        Sentinel(sentinel_t &guard) : _guard(guard) {
154            _guard++;
155        }
156
157        ~Sentinel() { _guard--; }
158
159        inline static boolean_t is_guarded(sentinel_t &guard) { return guard != 0; }
160        inline static void assert_guarded(sentinel_t &guard) { assert(is_guarded(guard)); }
161    };
162};
163
164#endif // __AUTO_LOCK__
165