2 Copyright (C) 2012 Paul Davis
3 Author: David Robillard
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.
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.
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.
20 #ifndef __pbd_semaphore_h__
21 #define __pbd_semaphore_h__
24 # include <mach/mach.h>
25 #elif defined(PLATFORM_WINDOWS)
28 #define INFINITE 0xffffffffL
31 # include <semaphore.h>
35 #include "pbd/libpbd_visibility.h"
36 #include "pbd/failed_constructor.h"
41 Unnamed (process local) counting semaphore.
43 The civilized person's synchronisation primitive. A counting semaphore is
44 an integer which is always non-negative, so, an attempted decrement (or
45 "wait") will block if the value is 0, until another thread does an increment
48 At least on Lignux, the main advantage of this is that it is fast and the
49 only safe way to reliably signal from a real-time audio thread. The
50 counting semantics also complement ringbuffers of events nicely.
52 class /*LIBPBD_API*/ Semaphore
56 Create a new semaphore.
58 Chances are you want 1 wait() per 1 post(), an initial value of 0.
60 inline Semaphore(unsigned initial);
64 /** Post/Increment/Signal */
67 /** Wait/Decrement. Returns false on error. */
70 /** Attempt Wait/Decrement. Returns true iff a decrement occurred. */
71 inline bool try_wait();
74 #if defined(__APPLE__)
75 semaphore_t _sem; // sem_t is a worthless broken mess on OSX
76 #elif defined(PLATFORM_WINDOWS)
77 HANDLE _sem; // types are overrated anyway
86 Semaphore::Semaphore(unsigned initial)
88 if (semaphore_create(mach_task_self(), &_sem, SYNC_POLICY_FIFO, initial)) {
89 throw failed_constructor();
94 Semaphore::~Semaphore()
96 semaphore_destroy(mach_task_self(), _sem);
102 semaphore_signal(_sem);
108 if (semaphore_wait(_sem) != KERN_SUCCESS) {
115 Semaphore::try_wait()
117 const mach_timespec_t zero = { 0, 0 };
118 return semaphore_timedwait(_sem, zero) == KERN_SUCCESS;
121 #elif defined(PLATFORM_WINDOWS)
124 Semaphore::Semaphore(unsigned initial)
126 if (!(_sem = CreateSemaphore(NULL, initial, LONG_MAX, NULL))) {
127 throw failed_constructor();
132 Semaphore::~Semaphore()
140 ReleaseSemaphore(_sem, 1, NULL);
146 if (WaitForSingleObject(_sem, INFINITE) != WAIT_OBJECT_0) {
153 Semaphore::try_wait()
155 return WaitForSingleObject(_sem, 0) == WAIT_OBJECT_0;
158 #else /* !defined(__APPLE__) && !defined(PLATFORM_WINDOWS) */
160 Semaphore::Semaphore(unsigned initial)
162 if (sem_init(&_sem, 0, initial)) {
163 throw failed_constructor();
168 Semaphore::~Semaphore()
182 while (sem_wait(&_sem)) {
183 if (errno != EINTR) {
184 return false; // We are all doomed
186 /* Otherwise, interrupted (rare/weird), so try again. */
193 Semaphore::try_wait()
195 return (sem_trywait(&_sem) == 0);
202 #endif /* __pbd_semaphore_h__ */