~ubuntu-branches/ubuntu/vivid/soundscaperenderer/vivid

« back to all changes in this revision

Viewing changes to apf/apf/posix_thread_policy.h

  • Committer: Package Import Robot
  • Author(s): IOhannes m zmölnig (Debian/GNU)
  • Date: 2014-05-08 16:58:09 UTC
  • Revision ID: package-import@ubuntu.com-20140508165809-7tz9dhu5pvo5wy25
Tags: upstream-0.4.1~dfsg
Import upstream version 0.4.1~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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           *
 
5
 *                                                                            *
 
6
 * This file is part of the Audio Processing Framework (APF).                 *
 
7
 *                                                                            *
 
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.                                                         *
 
12
 *                                                                            *
 
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.                       *
 
17
 *                                                                            *
 
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/>.            *
 
20
 *                                                                            *
 
21
 *                                 http://AudioProcessingFramework.github.com *
 
22
 ******************************************************************************/
 
23
 
 
24
/// @file
 
25
/// POSIX thread policy class.
 
26
 
 
27
#ifndef APF_POSIX_THREAD_POLICY_H
 
28
#define APF_POSIX_THREAD_POLICY_H
 
29
 
 
30
#ifndef _REENTRANT
 
31
#error You need to compile with _REENTRANT defined since this uses threads!
 
32
#endif
 
33
 
 
34
#ifndef APF_MIMOPROCESSOR_THREAD_POLICY
 
35
#define APF_MIMOPROCESSOR_THREAD_POLICY apf::posix_thread_policy
 
36
#endif
 
37
 
 
38
// Unnamed semaphores are not implemented on Mac OS X, so we use named
 
39
// semaphores with an auto-generated name.
 
40
// That's a hack.
 
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
 
46
#endif
 
47
 
 
48
#include <stdexcept>  // for std::runtime_error
 
49
#include <cstring>  // for std::strerror()
 
50
#include <pthread.h>
 
51
#include <semaphore.h>
 
52
#include <cerrno>
 
53
#include <unistd.h>  // for usleep()
 
54
 
 
55
#ifdef APF_PSEUDO_UNNAMED_SEMAPHORES
 
56
#include <fcntl.h>  // for O_CREAT, O_EXCL
 
57
#include "apf/stringtools.h"  // for apf::str::A2S()
 
58
#endif
 
59
 
 
60
#include "apf/misc.h"  // for NonCopyable
 
61
 
 
62
namespace apf
 
63
{
 
64
 
 
65
/// @c thread_policy using the POSIX thread library.
 
66
/// @see MimoProcessor
 
67
/// @ingroup apf_policies
 
68
class posix_thread_policy
 
69
{
 
70
  public:
 
71
    using useconds_type = useconds_t;
 
72
 
 
73
    template<typename F> class ScopedThread;
 
74
    template<typename F> class DetachedThread;
 
75
    class Lock;  // TODO: read-write lock?
 
76
    class Semaphore;
 
77
 
 
78
  protected:
 
79
     posix_thread_policy() = default;  ///< Protected ctor.
 
80
    ~posix_thread_policy() = default;  ///< Protected dtor.
 
81
 
 
82
  private:
 
83
    class ThreadBase;
 
84
};
 
85
 
 
86
class posix_thread_policy::ThreadBase
 
87
{
 
88
  public:
 
89
    using native_handle_type = pthread_t;
 
90
 
 
91
    void create(void* (*f)(void*), void* data)
 
92
    {
 
93
      if (pthread_create(&_thread_id, 0, f, data))
 
94
      {
 
95
        throw std::runtime_error("Can't create thread!");
 
96
      }
 
97
    }
 
98
 
 
99
    bool join() { return !pthread_join(_thread_id, 0); }
 
100
 
 
101
    native_handle_type native_handle() const { return _thread_id; }
 
102
 
 
103
  protected:
 
104
    ThreadBase() = default;
 
105
    ~ThreadBase() = default;
 
106
 
 
107
  private:
 
108
    native_handle_type _thread_id;
 
109
};
 
110
 
 
111
template<typename F>
 
112
class posix_thread_policy::ScopedThread : public ThreadBase, NonCopyable
 
113
{
 
114
  public:
 
115
    ScopedThread(F f, useconds_type usleeptime)
 
116
      : _kill_thread(false)
 
117
      , _function(f)
 
118
      , _usleeptime(usleeptime)
 
119
    {
 
120
      this->create(&_thread_aux, this);
 
121
    }
 
122
 
 
123
    ~ScopedThread()
 
124
    {
 
125
      _kill_thread = true;
 
126
      this->join();
 
127
    }
 
128
 
 
129
  private:
 
130
    static void* _thread_aux(void *arg)
 
131
    {
 
132
      static_cast<ScopedThread*>(arg)->_thread();
 
133
      return nullptr;
 
134
    }
 
135
 
 
136
    void _thread()
 
137
    {
 
138
      while (!_kill_thread)
 
139
      {
 
140
        _function();
 
141
        usleep(_usleeptime);
 
142
      }
 
143
    }
 
144
 
 
145
    volatile bool _kill_thread;
 
146
    F _function;
 
147
    useconds_type _usleeptime;
 
148
};
 
149
 
 
150
template<typename F>
 
151
class posix_thread_policy::DetachedThread : public ThreadBase
 
152
{
 
153
  public:
 
154
    explicit DetachedThread(F f)
 
155
      : _function(f)
 
156
    {
 
157
      this->create(&_thread_aux, this);
 
158
      pthread_detach(this->native_handle());  // return value is ignored!
 
159
    }
 
160
 
 
161
  private:
 
162
    static void* _thread_aux(void* arg)
 
163
    {
 
164
      static_cast<DetachedThread*>(arg)->_thread();
 
165
      return nullptr;
 
166
    }
 
167
 
 
168
    void _thread()
 
169
    {
 
170
      for (;;)
 
171
      {
 
172
        _function();
 
173
      }
 
174
    }
 
175
 
 
176
    F _function;
 
177
};
 
178
 
 
179
/** Inner type Lock.
 
180
 * Wrapper class for a mutex.
 
181
 **/
 
182
class posix_thread_policy::Lock : NonCopyable
 
183
{
 
184
  public:
 
185
    // TODO: parameter: initial lock state?
 
186
    Lock()
 
187
    {
 
188
      if (pthread_mutex_init(&_lock, nullptr))
 
189
      {
 
190
        throw std::runtime_error("Can't init mutex. (impossible !!!)");
 
191
      }
 
192
    }
 
193
 
 
194
    // TODO: change return type to bool?
 
195
    int   lock() { return pthread_mutex_lock(  &_lock); }
 
196
    int unlock() { return pthread_mutex_unlock(&_lock); }
 
197
 
 
198
    // TODO: trylock?
 
199
 
 
200
  private:
 
201
    pthread_mutex_t _lock;
 
202
};
 
203
 
 
204
class posix_thread_policy::Semaphore : NonCopyable
 
205
{
 
206
  public:
 
207
    using value_type = unsigned int;
 
208
 
 
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))
 
214
    {
 
215
      if (!_sem_ptr)
 
216
#else
 
217
      : _sem_ptr(&_semaphore)
 
218
    {
 
219
      if (sem_init(_sem_ptr, 0, value))
 
220
#endif
 
221
      {
 
222
        throw std::runtime_error("Error initializing Semaphore! ("
 
223
            + std::string(std::strerror(errno)) + ")");
 
224
      }
 
225
    }
 
226
 
 
227
    Semaphore(Semaphore&&) = default;
 
228
 
 
229
    ~Semaphore()
 
230
    {
 
231
#ifdef APF_PSEUDO_UNNAMED_SEMAPHORES
 
232
      sem_unlink(_name.c_str());  // Only for named semaphores
 
233
#else
 
234
      sem_destroy(_sem_ptr);  // Only for unnamed semaphores
 
235
#endif
 
236
    }
 
237
 
 
238
    bool post() { return sem_post(_sem_ptr) == 0; }
 
239
    bool wait() { return sem_wait(_sem_ptr) == 0; }
 
240
 
 
241
  private:
 
242
#ifdef APF_PSEUDO_UNNAMED_SEMAPHORES
 
243
    const std::string _name;
 
244
#else
 
245
    sem_t _semaphore;
 
246
#endif
 
247
    sem_t* const _sem_ptr;
 
248
};
 
249
 
 
250
}  // namespace apf
 
251
 
 
252
#endif
 
253
 
 
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'\:'='