1
/******************************************************************************
2
* Copyright © 2012-2014 Institut für Nachrichtentechnik, Universität Rostock *
3
* Copyright © 2006-2012 Quality & Usability Lab, *
4
* Telekom Innovation Laboratories, TU Berlin *
6
* This file is part of the Audio Processing Framework (APF). *
8
* The APF is free software: you can redistribute it and/or modify it under *
9
* the terms of the GNU General Public License as published by the Free *
10
* Software Foundation, either version 3 of the License, or (at your option) *
11
* any later version. *
13
* The APF is distributed in the hope that it will be useful, but WITHOUT ANY *
14
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
15
* FOR A PARTICULAR PURPOSE. *
16
* See the GNU General Public License for more details. *
18
* You should have received a copy of the GNU General Public License along *
19
* with this program. If not, see <http://www.gnu.org/licenses/>. *
21
* http://AudioProcessingFramework.github.com *
22
******************************************************************************/
25
/// POSIX thread policy class.
27
#ifndef APF_POSIX_THREAD_POLICY_H
28
#define APF_POSIX_THREAD_POLICY_H
31
#error You need to compile with _REENTRANT defined since this uses threads!
34
#ifndef APF_MIMOPROCESSOR_THREAD_POLICY
35
#define APF_MIMOPROCESSOR_THREAD_POLICY apf::posix_thread_policy
38
// Unnamed semaphores are not implemented on Mac OS X, so we use named
39
// semaphores with an auto-generated name.
41
// But it was easier than to use some OSX-specific stuff.
42
// If you want to use proper unnamed semaphores, define APF_UNNAMED_SEMAPHORES
43
// TODO: proper synchronisation for OSX, go back to unnamed for Linux.
44
#ifndef APF_UNNAMED_SEMAPHORES
45
#define APF_PSEUDO_UNNAMED_SEMAPHORES
48
#include <stdexcept> // for std::runtime_error
49
#include <cstring> // for std::strerror()
51
#include <semaphore.h>
53
#include <unistd.h> // for usleep()
55
#ifdef APF_PSEUDO_UNNAMED_SEMAPHORES
56
#include <fcntl.h> // for O_CREAT, O_EXCL
57
#include "apf/stringtools.h" // for apf::str::A2S()
60
#include "apf/misc.h" // for NonCopyable
65
/// @c thread_policy using the POSIX thread library.
66
/// @see MimoProcessor
67
/// @ingroup apf_policies
68
class posix_thread_policy
71
using useconds_type = useconds_t;
73
template<typename F> class ScopedThread;
74
template<typename F> class DetachedThread;
75
class Lock; // TODO: read-write lock?
79
posix_thread_policy() = default; ///< Protected ctor.
80
~posix_thread_policy() = default; ///< Protected dtor.
86
class posix_thread_policy::ThreadBase
89
using native_handle_type = pthread_t;
91
void create(void* (*f)(void*), void* data)
93
if (pthread_create(&_thread_id, 0, f, data))
95
throw std::runtime_error("Can't create thread!");
99
bool join() { return !pthread_join(_thread_id, 0); }
101
native_handle_type native_handle() const { return _thread_id; }
104
ThreadBase() = default;
105
~ThreadBase() = default;
108
native_handle_type _thread_id;
112
class posix_thread_policy::ScopedThread : public ThreadBase, NonCopyable
115
ScopedThread(F f, useconds_type usleeptime)
116
: _kill_thread(false)
118
, _usleeptime(usleeptime)
120
this->create(&_thread_aux, this);
130
static void* _thread_aux(void *arg)
132
static_cast<ScopedThread*>(arg)->_thread();
138
while (!_kill_thread)
145
volatile bool _kill_thread;
147
useconds_type _usleeptime;
151
class posix_thread_policy::DetachedThread : public ThreadBase
154
explicit DetachedThread(F f)
157
this->create(&_thread_aux, this);
158
pthread_detach(this->native_handle()); // return value is ignored!
162
static void* _thread_aux(void* arg)
164
static_cast<DetachedThread*>(arg)->_thread();
180
* Wrapper class for a mutex.
182
class posix_thread_policy::Lock : NonCopyable
185
// TODO: parameter: initial lock state?
188
if (pthread_mutex_init(&_lock, nullptr))
190
throw std::runtime_error("Can't init mutex. (impossible !!!)");
194
// TODO: change return type to bool?
195
int lock() { return pthread_mutex_lock( &_lock); }
196
int unlock() { return pthread_mutex_unlock(&_lock); }
201
pthread_mutex_t _lock;
204
class posix_thread_policy::Semaphore : NonCopyable
207
using value_type = unsigned int;
209
explicit Semaphore(value_type value = 0)
210
#ifdef APF_PSEUDO_UNNAMED_SEMAPHORES
211
// Create a unique dummy name from object pointer
212
: _name("/apf_" + apf::str::A2S(this))
213
, _sem_ptr(sem_open(_name.c_str(), O_CREAT | O_EXCL, 0600, value))
217
: _sem_ptr(&_semaphore)
219
if (sem_init(_sem_ptr, 0, value))
222
throw std::runtime_error("Error initializing Semaphore! ("
223
+ std::string(std::strerror(errno)) + ")");
227
Semaphore(Semaphore&&) = default;
231
#ifdef APF_PSEUDO_UNNAMED_SEMAPHORES
232
sem_unlink(_name.c_str()); // Only for named semaphores
234
sem_destroy(_sem_ptr); // Only for unnamed semaphores
238
bool post() { return sem_post(_sem_ptr) == 0; }
239
bool wait() { return sem_wait(_sem_ptr) == 0; }
242
#ifdef APF_PSEUDO_UNNAMED_SEMAPHORES
243
const std::string _name;
247
sem_t* const _sem_ptr;
254
// Settings for Vim (http://www.vim.org/), please do not remove:
255
// vim:softtabstop=2:shiftwidth=2:expandtab:textwidth=80:cindent
256
// vim:fdm=expr:foldexpr=getline(v\:lnum)=~'/\\*\\*'&&getline(v\:lnum)!~'\\*\\*/'?'a1'\:getline(v\:lnum)=~'\\*\\*/'&&getline(v\:lnum)!~'/\\*\\*'?'s1'\:'='