compile and configuration fixes from OSX but useful everywhere
[jack.git] / libjack / thread.c
blob89770095077d0d80b78f8f16c4124c94a339c2e8
1 /*
2 Copyright (C) 2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 Thread creation function including workarounds for real-time scheduling
19 behaviour on different glibc versions.
24 #include <config.h>
26 #include <jack/jack.h>
27 #include <jack/thread.h>
28 #include <jack/internal.h>
30 #include <pthread.h>
31 #include <sched.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
36 #include "local.h"
38 #ifdef JACK_USE_MACH_THREADS
39 #include <sysdeps/pThreadUtilities.h>
40 #endif
42 static inline void
43 log_result (char *msg, int res)
45 char outbuf[500];
46 snprintf(outbuf, sizeof(outbuf),
47 "jack_client_create_thread: error %d %s: %s",
48 res, msg, strerror(res));
49 jack_error(outbuf);
52 static void
53 maybe_get_capabilities (jack_client_t* client)
55 #ifdef USE_CAPABILITIES
57 if (client != 0) {
59 jack_request_t req;
61 if (client->engine->has_capabilities != 0) {
63 /* we need to ask the engine for realtime capabilities
64 before trying to run the thread work function
67 req.type = SetClientCapabilities;
68 req.x.cap_pid = getpid();
70 jack_client_deliver_request (client, &req);
72 if (req.status) {
74 /* what to do? engine is running realtime, it
75 is using capabilities and has them
76 (otherwise we would not get an error
77 return) but for some reason it could not
78 give the client the required capabilities.
79 for now, allow the client to run, albeit
80 non-realtime.
83 jack_error ("could not receive realtime capabilities, "
84 "client will run non-realtime");
89 #endif /* USE_CAPABILITIES */
92 static void*
93 jack_thread_proxy (void* varg)
95 jack_thread_arg_t* arg = (jack_thread_arg_t*) varg;
96 void* (*work)(void*);
97 void* warg;
98 jack_client_t* client = arg->client;
100 if (arg->realtime) {
101 maybe_get_capabilities (client);
102 jack_acquire_real_time_scheduling (pthread_self(), arg->priority);
105 warg = arg->arg;
106 work = arg->work_function;
108 free (arg);
110 return work (warg);
114 jack_client_create_thread (jack_client_t* client,
115 pthread_t* thread,
116 int priority,
117 int realtime,
118 void*(*start_routine)(void*),
119 void* arg)
121 #ifndef JACK_USE_MACH_THREADS
122 pthread_attr_t attr;
123 jack_thread_arg_t* thread_args;
124 #endif /* !JACK_USE_MACH_THREADS */
126 int result = 0;
128 if (!realtime) {
129 result = pthread_create (thread, 0, start_routine, arg);
130 if (result) {
131 log_result("creating thread with default parameters",
132 result);
134 return result;
137 /* realtime thread. this disgusting mess is a reflection of
138 * the 2nd-class nature of RT programming under POSIX in
139 * general and Linux in particular.
142 #ifndef JACK_USE_MACH_THREADS
144 pthread_attr_init(&attr);
145 result = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
146 if (result) {
147 log_result("requesting explicit scheduling", result);
148 return result;
150 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
151 if (result) {
152 log_result("requesting joinable thread creation", result);
153 return result;
155 #ifdef __OpenBSD__
156 result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
157 #else
158 result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
159 #endif
160 if (result) {
161 log_result("requesting system scheduling scope", result);
162 return result;
165 result = pthread_attr_setstacksize(&attr, THREAD_STACK);
166 if (result) {
167 log_result("setting thread stack size", result);
168 return result;
171 thread_args = (jack_thread_arg_t *) malloc (sizeof (jack_thread_arg_t));
173 thread_args->client = client;
174 thread_args->work_function = start_routine;
175 thread_args->arg = arg;
176 thread_args->realtime = 1;
177 thread_args->priority = priority;
179 result = pthread_create (thread, &attr, jack_thread_proxy, thread_args);
180 if (result) {
181 log_result ("creating realtime thread", result);
182 return result;
185 #else /* JACK_USE_MACH_THREADS */
187 result = pthread_create (thread, 0, start_routine, arg);
188 if (result) {
189 log_result ("creating realtime thread", result);
190 return result;
193 /* time constraint thread */
194 setThreadToPriority (*thread, 96, TRUE, 10000000);
196 #endif /* JACK_USE_MACH_THREADS */
198 return 0;
202 jack_client_real_time_priority (jack_client_t* client)
204 if (!client->engine->real_time) {
205 return -1;
208 return client->engine->client_priority;
212 jack_client_max_real_time_priority (jack_client_t* client)
214 if (!client->engine->real_time) {
215 return -1;
218 return client->engine->max_client_priority;
221 #if JACK_USE_MACH_THREADS
224 jack_drop_real_time_scheduling (pthread_t thread)
226 setThreadToPriority(thread, 31, FALSE, 10000000);
227 return 0;
231 jack_acquire_real_time_scheduling (pthread_t thread, int priority)
232 //priority is unused
234 setThreadToPriority(thread, 96, TRUE, 10000000);
235 return 0;
238 #else /* !JACK_USE_MACH_THREADS */
241 jack_drop_real_time_scheduling (pthread_t thread)
243 struct sched_param rtparam;
244 int x;
246 memset (&rtparam, 0, sizeof (rtparam));
247 rtparam.sched_priority = 0;
249 if ((x = pthread_setschedparam (thread, SCHED_OTHER, &rtparam)) != 0) {
250 jack_error ("cannot switch to normal scheduling priority(%s)\n",
251 strerror (errno));
252 return -1;
254 return 0;
258 jack_acquire_real_time_scheduling (pthread_t thread, int priority)
260 struct sched_param rtparam;
261 int x;
263 memset (&rtparam, 0, sizeof (rtparam));
264 rtparam.sched_priority = priority;
266 if ((x = pthread_setschedparam (thread, SCHED_FIFO, &rtparam)) != 0) {
267 jack_error ("cannot use real-time scheduling (FIFO at priority %d) "
268 "[for thread %d, from thread %d] (%d: %s)",
269 rtparam.sched_priority,
270 thread, pthread_self(),
271 x, strerror (x));
272 return -1;
275 return 0;
278 #endif /* JACK_USE_MACH_THREADS */