1 /************************** BEGIN thread.h **************************/
2 /************************************************************************
3 FAUST Architecture File
4 Copyright (C) 2020 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This Architecture section is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 3 of
9 the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; If not, see <http://www.gnu.org/licenses/>.
18
19 EXCEPTION : As a special exception, you may create a larger work
20 that contains this FAUST architecture section and distribute
21 that work under terms of your choice, so long as this FAUST
22 architecture section is not modified.
23 ************************************************************************/
24
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <pthread.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <semaphore.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <math.h>
38
39 using namespace std;
40
41 #ifdef __cplusplus
42 extern "C"
43 {
44 #endif
45
46 #ifdef __ICC
47 #define INLINE __forceinline
48 #else
49 #define INLINE inline
50 #endif
51
52 // Globals
53
54 #define THREAD_POOL_SIZE 16
55 #define JACK_SCHED_POLICY SCHED_FIFO
56
57 /* use 512KB stack per thread - the default is way too high to be feasible
58 * with mlockall() on many systems */
59 #define THREAD_STACK 524288
60
61 typedef void* (ThreadHandler) (void* arg);
62
GetPID()63 static int GetPID()
64 {
65 #ifdef WIN32
66 return _getpid();
67 #else
68 return getpid();
69 #endif
70 }
71
72 #ifdef __APPLE__
73 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
74 #include <mach/thread_policy.h>
75 #include <mach/thread_act.h>
76
77 #include <mach/thread_policy.h>
78 #include <mach/thread_act.h>
79
80 #define THREAD_SET_PRIORITY 0
81 #define THREAD_SCHEDULED_PRIORITY 1
82
83 static UInt32 GetThreadPriority(pthread_t thread, int inWhichPriority);
84
85 // returns the thread's priority as it was last set by the API
GetThreadSetPriority(pthread_t thread)86 static UInt32 GetThreadSetPriority(pthread_t thread)
87 {
88 return GetThreadPriority(thread, THREAD_SET_PRIORITY);
89 }
90
91 // returns the thread's priority as it was last scheduled by the Kernel
GetThreadScheduledPriority(pthread_t thread)92 static UInt32 GetThreadScheduledPriority(pthread_t thread)
93 {
94 return GetThreadPriority(thread, THREAD_SCHEDULED_PRIORITY);
95 }
96
SetThreadToPriority(pthread_t thread,UInt32 inPriority,Boolean inIsFixed,UInt64 period,UInt64 computation,UInt64 constraint)97 static int SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint)
98 {
99 if (inPriority == 96) {
100 // REAL-TIME / TIME-CONSTRAINT THREAD
101 thread_time_constraint_policy_data_t theTCPolicy;
102 theTCPolicy.period = period;
103 theTCPolicy.computation = computation;
104 theTCPolicy.constraint = constraint;
105 theTCPolicy.preemptible = true;
106 kern_return_t res = thread_policy_set(pthread_mach_thread_np(thread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&theTCPolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT);
107 return (res == KERN_SUCCESS) ? 0 : -1;
108 } else {
109 // OTHER THREADS
110 thread_extended_policy_data_t theFixedPolicy;
111 thread_precedence_policy_data_t thePrecedencePolicy;
112 SInt32 relativePriority;
113
114 // [1] SET FIXED / NOT FIXED
115 theFixedPolicy.timeshare = !inIsFixed;
116 thread_policy_set(pthread_mach_thread_np(thread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
117
118 // [2] SET PRECEDENCE
119 // N.B.: We expect that if thread A created thread B, and the program wishes to change
120 // the priority of thread B, then the call to change the priority of thread B must be
121 // made by thread A.
122 // This assumption allows us to use pthread_self() to correctly calculate the priority
123 // of the feeder thread (since precedency policy's importance is relative to the
124 // spawning thread's priority.)
125 relativePriority = inPriority - GetThreadSetPriority(pthread_self());
126
127 thePrecedencePolicy.importance = relativePriority;
128 kern_return_t res = thread_policy_set(pthread_mach_thread_np(thread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
129 return (res == KERN_SUCCESS) ? 0 : -1;
130 }
131 }
132
GetThreadPriority(pthread_t thread,int inWhichPriority)133 static UInt32 GetThreadPriority(pthread_t thread, int inWhichPriority)
134 {
135 thread_basic_info_data_t threadInfo;
136 policy_info_data_t thePolicyInfo;
137 unsigned int count;
138
139 // get basic info
140 count = THREAD_BASIC_INFO_COUNT;
141 thread_info(pthread_mach_thread_np(thread), THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &count);
142
143 switch (threadInfo.policy) {
144 case POLICY_TIMESHARE:
145 count = POLICY_TIMESHARE_INFO_COUNT;
146 thread_info(pthread_mach_thread_np(thread), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&(thePolicyInfo.ts), &count);
147 if (inWhichPriority == THREAD_SCHEDULED_PRIORITY) {
148 return thePolicyInfo.ts.cur_priority;
149 } else {
150 return thePolicyInfo.ts.base_priority;
151 }
152 break;
153
154 case POLICY_FIFO:
155 count = POLICY_FIFO_INFO_COUNT;
156 thread_info(pthread_mach_thread_np(thread), THREAD_SCHED_FIFO_INFO, (thread_info_t)&(thePolicyInfo.fifo), &count);
157 if ((thePolicyInfo.fifo.depressed) && (inWhichPriority == THREAD_SCHEDULED_PRIORITY)) {
158 return thePolicyInfo.fifo.depress_priority;
159 }
160 return thePolicyInfo.fifo.base_priority;
161 break;
162
163 case POLICY_RR:
164 count = POLICY_RR_INFO_COUNT;
165 thread_info(pthread_mach_thread_np(thread), THREAD_SCHED_RR_INFO, (thread_info_t)&(thePolicyInfo.rr), &count);
166 if ((thePolicyInfo.rr.depressed) && (inWhichPriority == THREAD_SCHEDULED_PRIORITY)) {
167 return thePolicyInfo.rr.depress_priority;
168 }
169 return thePolicyInfo.rr.base_priority;
170 break;
171 }
172
173 return 0;
174 }
175
GetParams(pthread_t thread,UInt64 * period,UInt64 * computation,UInt64 * constraint)176 static int GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint)
177 {
178 thread_time_constraint_policy_data_t theTCPolicy;
179 mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
180 boolean_t get_default = false;
181
182 kern_return_t res = thread_policy_get(pthread_mach_thread_np(thread),
183 THREAD_TIME_CONSTRAINT_POLICY,
184 (thread_policy_t)&theTCPolicy,
185 &count,
186 &get_default);
187 if (res == KERN_SUCCESS) {
188 *period = theTCPolicy.period;
189 *computation = theTCPolicy.computation;
190 *constraint = theTCPolicy.constraint;
191 return 0;
192 } else {
193 return -1;
194 }
195 }
196
197 static UInt64 period = 0;
198 static UInt64 computation = 0;
199 static UInt64 constraint = 0;
200
GetRealTime()201 INLINE void GetRealTime()
202 {
203 if (period == 0) {
204 GetParams(pthread_self(), &period, &computation, &constraint);
205 }
206 }
207
SetRealTime()208 INLINE void SetRealTime()
209 {
210 SetThreadToPriority(pthread_self(), 96, true, period, computation, constraint);
211 }
212
213 #endif
214
215 struct RunThread {
216
217 pthread_t fThread;
218 sem_t* fSemaphore;
219 char fName[128];
220 bool fRealTime;
221
222 #ifdef __APPLE__
223
CancelRunThread224 void Cancel()
225 {
226 mach_port_t machThread = pthread_mach_thread_np(fThread);
227 thread_terminate(machThread);
228 }
229
JoinRunThread230 void Join()
231 {
232 sem_post(fSemaphore);
233 pthread_join(fThread, NULL);
234 }
235
236
237 #endif
238
239 #ifdef __linux__
240
CancelRunThread241 void Cancel()
242 {
243 pthread_cancel(fThread);
244 pthread_join(fThread, NULL);
245 }
246
JoinRunThread247 void Join()
248 {
249 sem_post(fSemaphore);
250 pthread_join(fThread, NULL);
251 }
252
253 #endif
254
RunThreadRunThread255 RunThread()
256 {
257 sprintf(fName, "faust_sem_%d_%p", GetPID(), this);
258 if ((fSemaphore = sem_open(fName, O_CREAT, 0777, 0)) == (sem_t*)SEM_FAILED) {
259 std::cerr << "Allocate: can't check in named semaphore name = " <<fName << " " << strerror(errno) << std::endl;
260 throw std::bad_alloc();
261 }
262 }
263
~RunThreadRunThread264 ~RunThread()
265 {
266 sem_unlink(fName);
267 sem_close(fSemaphore);
268 }
269
WaitRunThread270 void Wait()
271 {
272 while (sem_wait(fSemaphore) != 0) {}
273 }
274
SignalRunThread275 void Signal()
276 {
277 sem_post(fSemaphore);
278 }
279
StartRunThread280 int Start(bool realtime, ThreadHandler fun, void* arg)
281 {
282 pthread_attr_t attributes;
283 struct sched_param rt_param;
284 pthread_attr_init(&attributes);
285
286 int priority = 70; // TODO
287 int res;
288
289 if (realtime) {
290 fRealTime = true;
291 }else {
292 fRealTime = getenv("OMP_REALTIME") ? strtol(getenv("OMP_REALTIME"), NULL, 10) : true;
293 }
294
295 if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) {
296 printf("Cannot request joinable thread creation for real-time thread res = %d err = %s\n", res, strerror(errno));
297 return -1;
298 }
299
300 if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
301 printf("Cannot set scheduling scope for real-time thread res = %d err = %s\n", res, strerror(errno));
302 return -1;
303 }
304
305 if (realtime) {
306
307 if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) {
308 printf("Cannot request explicit scheduling for RT thread res = %d err = %s\n", res, strerror(errno));
309 return -1;
310 }
311
312 if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) {
313 printf("Cannot set RR scheduling class for RT thread res = %d err = %s\n", res, strerror(errno));
314 return -1;
315 }
316
317 memset(&rt_param, 0, sizeof(rt_param));
318 rt_param.sched_priority = priority;
319
320 if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) {
321 printf("Cannot set scheduling priority for RT thread res = %d err = %s\n", res, strerror(errno));
322 return -1;
323 }
324
325 } else {
326
327 if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_INHERIT_SCHED))) {
328 printf("Cannot request explicit scheduling for RT thread res = %d err = %s\n", res, strerror(errno));
329 return -1;
330 }
331 }
332
333 if ((res = pthread_attr_setstacksize(&attributes, THREAD_STACK))) {
334 printf("Cannot set thread stack size res = %d err = %s\n", res, strerror(errno));
335 return -1;
336 }
337
338 if ((res = pthread_create(&fThread, &attributes, fun, arg))) {
339 printf("Cannot create thread res = %d err = %s\n", res, strerror(errno));
340 return -1;
341 }
342
343 pthread_attr_destroy(&attributes);
344 return 0;
345 }
346
StopRunThread347 void Stop()
348 {
349 Cancel();
350 }
351
352 };
353
load_program_source(const char * filename)354 char* load_program_source(const char* filename)
355 {
356 struct stat statbuf;
357 FILE* fh;
358 char* source;
359
360 fh = fopen(filename, "r");
361 if (fh == 0) return 0;
362
363 stat(filename, &statbuf);
364 source = (char*)malloc(statbuf.st_size + 1);
365 fread(source, statbuf.st_size, 1, fh);
366 source[statbuf.st_size] = '\0';
367
368 return source;
369 }
370
371 #ifdef __cplusplus
372 }
373 #endif
374 /************************** END thread.h **************************/
375