1 // ----------------------------------------------------------------------------
2 //
3 //  Copyright (C) 2010-2016 Fons Adriaensen <fons@linuxaudio.org>
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 3 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, see <http://www.gnu.org/licenses/>.
17 //
18 // ----------------------------------------------------------------------------
19 
20 
21 #ifndef __PXTHREAD_H
22 #define __PXTHREAD_H
23 
24 
25 // ----------------------------------------------------------------------------
26 
27 
28 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__) || defined(__APPLE__) || defined(__FreeBSD__)
29 
30 // NOTE: __FreeBSD_kernel__  and __GNU__ were added by the Debian maintainers
31 // (the latter for the HURD version of Debian). Things are reported to work
32 // with some applications but probably have not been tested in depth.
33 
34 
35 #include <unistd.h>
36 #include <pthread.h>
37 #include <semaphore.h>
38 
39 
40 class Pxthread
41 {
42 public:
43 
44     Pxthread (void);
45     virtual ~Pxthread (void);
46     Pxthread (const Pxthread&);
47     Pxthread& operator=(const Pxthread&);
48 
49     virtual void thr_main (void) = 0;
50     virtual int  thr_start (int policy, int priority, size_t stacksize = 0);
51 
52 private:
53 
54     pthread_t  _thrid;
55 };
56 
57 
58 #endif
59 
60 
61 // ----------------------------------------------------------------------------
62 
63 
64 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
65 
66 class Pxsema
67 {
68 public:
69 
Pxsema(void)70     Pxsema (void) { init (0, 0); }
~Pxsema(void)71     ~Pxsema (void) { sem_destroy (&_sema); }
72 
73     Pxsema (const Pxsema&); // disabled
74     Pxsema& operator= (const Pxsema&); // disabled
75 
init(int s,int v)76     int init (int s, int v) { return sem_init (&_sema, s, v); }
post(void)77     int post (void) { return sem_post (&_sema); }
wait(void)78     int wait (void) { return sem_wait (&_sema); }
trywait(void)79     int trywait (void) { return sem_trywait (&_sema); }
80 
81 private:
82 
83     sem_t  _sema;
84 };
85 
86 #define PXSEMA_IS_IMPLEMENTED
87 #endif
88 
89 
90 // ----------------------------------------------------------------------------
91 
92 
93 #ifdef __APPLE__
94 
95 
96 // NOTE:  ***** I DO NOT REPEAT NOT PROVIDE SUPPORT FOR OSX *****
97 //
98 // The following code partially emulates the POSIX sem_t for which
99 // OSX has only a crippled implementation. It may or may not compile,
100 // and if it compiles it may or may not work correctly. Blame APPLE
101 // for not following POSIX standards.
102 
103 
104 #include <unistd.h>
105 #include <pthread.h>
106 
107 
108 class Pxsema
109 {
110 public:
111 
Pxsema(void)112     Pxsema (void) : _count (0)
113     {
114         init (0, 0);
115     }
116 
~Pxsema(void)117     ~Pxsema (void)
118     {
119         pthread_mutex_destroy (&_mutex);
120         pthread_cond_destroy (&_cond);
121     }
122 
123     Pxsema (const Pxsema&); // disabled
124     Pxsema& operator= (const Pxsema&); // disabled
125 
init(int s,int v)126     int init (int s, int v)
127     {
128 	_count = v;
129         return pthread_mutex_init (&_mutex, 0) || pthread_cond_init (&_cond, 0);
130     }
131 
post(void)132     int post (void)
133     {
134 	pthread_mutex_lock (&_mutex);
135 	_count++;
136 	if (_count == 1) pthread_cond_signal (&_cond);
137 	pthread_mutex_unlock (&_mutex);
138 	return 0;
139     }
140 
wait(void)141     int wait (void)
142     {
143 	pthread_mutex_lock (&_mutex);
144 	while (_count < 1) pthread_cond_wait (&_cond, &_mutex);
145 	_count--;
146 	pthread_mutex_unlock (&_mutex);
147 	return 0;
148     }
149 
trywait(void)150     int trywait (void)
151     {
152 	if (pthread_mutex_trylock (&_mutex)) return -1;
153 	if (_count < 1)
154 	{
155 	    pthread_mutex_unlock (&_mutex);
156 	    return -1;
157 	}
158         _count--;
159         pthread_mutex_unlock (&_mutex);
160         return 0;
161     }
162 
163 private:
164 
165     int              _count;
166     pthread_mutex_t  _mutex;
167     pthread_cond_t   _cond;
168 };
169 
170 #define PXSEMA_IS_IMPLEMENTED
171 #endif
172 
173 
174 // ----------------------------------------------------------------------------
175 
176 
177 #if defined(_WIN32) || defined(WIN32)
178 
179 #include <windows.h>
180 
181 
182 #define usleep(t) Sleep ((t) / 1000);
183 
184 #define SCHED_OTHER 0
185 #define SCHED_FIFO  1
186 #define SCHED_RR    2
187 
188 
189 // ---------------------------------------------------------------------
190 //
191 // Mapping of policy and priority pararmeters on Windows
192 //
193 // If the policy parameter is SCHED_FIFO or SCHED_RR then
194 //
195 //   priority parameter       Windows thread priority
196 //   ------------------------------------------------
197 //     < 60                   THREAD_PRIORITY_TIME_CRITICAL
198 //     60..69                 MMCSS Pro Audio, LOW
199 //     70..79                 MMCSS Pro Audio, NORMAL
200 //     80..89                 MMCSS Pro Audio, HIGH
201 //     >= 90                  MMCSS Pro Audio, CRITICAL
202 //
203 // If the policy parameter is not SCHED_FIFO or SCHED_RR then
204 // the default thread priority is used.
205 //
206 // ---------------------------------------------------------------------
207 
208 
209 class Pxthread
210 {
211 public:
212 
213     Pxthread (void);
214     virtual ~Pxthread (void);
215     Pxthread (const Pxthread&);
216     Pxthread& operator=(const Pxthread&);
217 
handle(void)218     void *handle (void) { return _handle; }
priority(void)219     int priority (void) { return _prior; }
220 
221     virtual void thr_main (void) = 0;
222     int thr_start (int policy, int priority, size_t stacksize = 0);
223 
224     void mmcssprio (void);
225 
226 private:
227 
228     void          *_handle;
229     unsigned long  _thrid;
230     int            _prior;
231 
232 
233     static unsigned long  _index;
234 };
235 
236 
237 class Pxsema
238 {
239 public:
240 
Pxsema(void)241     Pxsema (void) { _handle = CreateSemaphore (0, 0, 999999999, 0); }
~Pxsema(void)242     ~Pxsema (void) { CloseHandle (_handle); }
243 
244     Pxsema (const Pxsema&); // disabled
245     Pxsema& operator= (const Pxsema&); // disabled
246 
247 //    int init (void) { return 0; }
post(void)248     int post (void) { return ReleaseSemaphore (_handle, 1, 0) ? 0 : -1; }
wait(void)249     int wait (void) { return WaitForSingleObject (_handle, INFINITE); }
trywait(void)250     int trywait (void) { return WaitForSingleObject (_handle, 0); }
251 
252 private:
253 
254     void  *_handle;
255 };
256 
257 
258 #define PXSEMA_IS_IMPLEMENTED
259 #endif
260 
261 
262 // ----------------------------------------------------------------------------
263 
264 
265 #ifndef PXSEMA_IS_IMPLEMENTED
266 #error "The Pxsema class is not implemented."
267 #endif
268 
269 
270 #endif
271