add 0.5 second sleep after closing JACK connection so that next startup/connect is...
[ardour.git] / libs / pbd / pbd / semaphore.h
1 /*
2   Copyright (C) 2012 Paul Davis
3   Author: David Robillard
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifndef __pbd_semaphore_h__
21 #define __pbd_semaphore_h__
22
23 #ifdef __APPLE__
24 #    include <mach/mach.h>
25 #elif defined(_WIN32)
26 #    include <windows.h>
27 #else
28 #    include <semaphore.h>
29 #    include <errno.h>
30 #endif
31
32 #include "pbd/failed_constructor.h"
33
34 namespace PBD {
35
36 /**
37    Unnamed (process local) counting semaphore.
38
39    The civilized person's synchronisation primitive.  A counting semaphore is
40    an integer which is always non-negative, so, an attempted decrement (or
41    "wait") will block if the value is 0, until another thread does an increment
42    (or "post").
43
44    At least on Lignux, the main advantage of this is that it is fast and the
45    only safe way to reliably signal from a real-time audio thread.  The
46    counting semantics also complement ringbuffers of events nicely.
47 */
48 class Semaphore
49 {
50 public:
51         /**
52            Create a new semaphore.
53
54            Chances are you want 1 wait() per 1 post(), an initial value of 0.
55         */
56         inline Semaphore(unsigned initial);
57
58         inline ~Semaphore();
59
60         /** Post/Increment/Signal */
61         inline void post();
62
63         /** Wait/Decrement.  Returns false on error. */
64         inline bool wait();
65
66         /** Attempt Wait/Decrement.  Returns true iff a decrement occurred. */
67         inline bool try_wait();
68
69 private:
70 #if defined(__APPLE__)
71         semaphore_t _sem;  // sem_t is a worthless broken mess on OSX
72 #elif defined(_WIN32)
73         HANDLE _sem;  // types are overrated anyway
74 #else
75         sem_t _sem;
76 #endif
77 };
78
79 #ifdef __APPLE__
80
81 inline
82 Semaphore::Semaphore(unsigned initial)
83 {
84         if (semaphore_create(mach_task_self(), &_sem, SYNC_POLICY_FIFO, initial)) {
85                 throw failed_constructor();
86         }
87 }
88
89 inline
90 Semaphore::~Semaphore()
91 {
92         semaphore_destroy(mach_task_self(), _sem);
93 }
94
95 inline void
96 Semaphore::post()
97 {
98         semaphore_signal(_sem);
99 }
100
101 inline bool
102 Semaphore::wait()
103 {
104         if (semaphore_wait(_sem) != KERN_SUCCESS) {
105                 return false;
106         }
107         return true;
108 }
109
110 inline bool
111 Semaphore::try_wait()
112 {
113         const mach_timespec_t zero = { 0, 0 };
114         return semaphore_timedwait(_sem, zero) == KERN_SUCCESS;
115 }
116
117 #elif defined(_WIN32)
118
119 inline
120 Semaphore::Semaphore(unsigned initial)
121 {
122         if (!(_sem = CreateSemaphore(NULL, initial, LONG_MAX, NULL))) {
123                 throw failed_constructor();
124         }
125 }
126
127 inline
128 Semaphore::~Semaphore()
129 {
130         CloseHandle(_sem);
131 }
132
133 inline void
134 Semaphore::post()
135 {
136         ReleaseSemaphore(_sem, 1, NULL);
137 }
138
139 inline bool
140 Semaphore::wait()
141 {
142         if (WaitForSingleObject(_sem, INFINITE) != WAIT_OBJECT_0) {
143                 return false;
144         }
145         return true;
146 }
147
148 inline bool
149 Semaphore::try_wait()
150 {
151         return WaitForSingleObject(_sem, 0) == WAIT_OBJECT_0;
152 }
153
154 #else  /* !defined(__APPLE__) && !defined(_WIN32) */
155
156 Semaphore::Semaphore(unsigned initial)
157 {
158         if (sem_init(&_sem, 0, initial)) {
159                 throw failed_constructor();
160         }
161 }
162
163 inline
164 Semaphore::~Semaphore()
165 {
166         sem_destroy(&_sem);
167 }
168
169 inline void
170 Semaphore::post()
171 {
172         sem_post(&_sem);
173 }
174
175 inline bool
176 Semaphore::wait()
177 {
178         while (sem_wait(&_sem)) {
179                 if (errno != EINTR) {
180                         return false;  // We are all doomed
181                 }
182                 /* Otherwise, interrupted (rare/weird), so try again. */
183         }
184
185         return true;
186 }
187
188 inline bool
189 Semaphore::try_wait()
190 {
191         return (sem_trywait(&_sem) == 0);
192 }
193
194 #endif
195
196 }  // namespace PBD
197
198 #endif  /* __pbd_semaphore_h__ */