ensure that client-side message buffer thread calls thread_init callback if/when...
[jack.git] / libjack / thread.c
blob45dd0501a6955741490b67a49371d48f81ba4213
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 jack_thread_creator_t jack_thread_creator = pthread_create;
44 void
45 jack_set_thread_creator (jack_thread_creator_t jtc)
47 jack_thread_creator = jtc;
50 static inline void
51 log_result (char *msg, int res)
53 char outbuf[500];
54 snprintf(outbuf, sizeof(outbuf),
55 "jack_client_create_thread: error %d %s: %s",
56 res, msg, strerror(res));
57 jack_error(outbuf);
60 static void
61 maybe_get_capabilities (jack_client_t* client)
63 #ifdef USE_CAPABILITIES
65 if (client != 0) {
67 jack_request_t req;
69 if (client->engine->has_capabilities != 0) {
71 /* we need to ask the engine for realtime capabilities
72 before trying to run the thread work function
75 req.type = SetClientCapabilities;
76 req.x.cap_pid = getpid();
78 jack_client_deliver_request (client, &req);
80 if (req.status) {
82 /* what to do? engine is running realtime, it
83 is using capabilities and has them
84 (otherwise we would not get an error
85 return) but for some reason it could not
86 give the client the required capabilities.
87 for now, allow the client to run, albeit
88 non-realtime.
91 jack_error ("could not receive realtime capabilities, "
92 "client will run non-realtime");
97 #endif /* USE_CAPABILITIES */
100 static void*
101 jack_thread_proxy (void* varg)
103 jack_thread_arg_t* arg = (jack_thread_arg_t*) varg;
104 void* (*work)(void*);
105 void* warg;
106 jack_client_t* client = arg->client;
108 if (arg->realtime) {
109 maybe_get_capabilities (client);
110 jack_acquire_real_time_scheduling (pthread_self(), arg->priority);
113 warg = arg->arg;
114 work = arg->work_function;
116 free (arg);
118 return work (warg);
122 jack_client_create_thread (jack_client_t* client,
123 pthread_t* thread,
124 int priority,
125 int realtime,
126 void*(*start_routine)(void*),
127 void* arg)
129 #ifndef JACK_USE_MACH_THREADS
130 pthread_attr_t attr;
131 jack_thread_arg_t* thread_args;
132 #endif /* !JACK_USE_MACH_THREADS */
134 int result = 0;
136 if (!realtime) {
137 result = jack_thread_creator (thread, 0, start_routine, arg);
138 if (result) {
139 log_result("creating thread with default parameters",
140 result);
142 return result;
145 /* realtime thread. this disgusting mess is a reflection of
146 * the 2nd-class nature of RT programming under POSIX in
147 * general and Linux in particular.
150 #ifndef JACK_USE_MACH_THREADS
152 pthread_attr_init(&attr);
153 result = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
154 if (result) {
155 log_result("requesting explicit scheduling", result);
156 return result;
158 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
159 if (result) {
160 log_result("requesting joinable thread creation", result);
161 return result;
163 #ifdef __OpenBSD__
164 result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
165 #else
166 result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
167 #endif
168 if (result) {
169 log_result("requesting system scheduling scope", result);
170 return result;
173 result = pthread_attr_setstacksize(&attr, THREAD_STACK);
174 if (result) {
175 log_result("setting thread stack size", result);
176 return result;
179 if ((thread_args = (jack_thread_arg_t *) malloc (sizeof (jack_thread_arg_t))) == NULL) {
180 return -1;
183 thread_args->client = client;
184 thread_args->work_function = start_routine;
185 thread_args->arg = arg;
186 thread_args->realtime = 1;
187 thread_args->priority = priority;
189 result = jack_thread_creator (thread, &attr, jack_thread_proxy, thread_args);
190 if (result) {
191 log_result ("creating realtime thread", result);
192 return result;
195 #else /* JACK_USE_MACH_THREADS */
197 result = jack_thread_creator (thread, 0, start_routine, arg);
198 if (result) {
199 log_result ("creating realtime thread", result);
200 return result;
203 /* time constraint thread */
204 setThreadToPriority (*thread, 96, TRUE, 10000000);
206 #endif /* JACK_USE_MACH_THREADS */
208 return 0;
212 jack_client_real_time_priority (jack_client_t* client)
214 if (!client->engine->real_time) {
215 return -1;
218 return client->engine->client_priority;
222 jack_client_max_real_time_priority (jack_client_t* client)
224 if (!client->engine->real_time) {
225 return -1;
228 return client->engine->max_client_priority;
231 #if JACK_USE_MACH_THREADS
234 jack_drop_real_time_scheduling (pthread_t thread)
236 setThreadToPriority(thread, 31, FALSE, 10000000);
237 return 0;
241 jack_acquire_real_time_scheduling (pthread_t thread, int priority)
242 //priority is unused
244 setThreadToPriority(thread, 96, TRUE, 10000000);
245 return 0;
248 #else /* !JACK_USE_MACH_THREADS */
251 jack_drop_real_time_scheduling (pthread_t thread)
253 struct sched_param rtparam;
254 int x;
256 memset (&rtparam, 0, sizeof (rtparam));
257 rtparam.sched_priority = 0;
259 if ((x = pthread_setschedparam (thread, SCHED_OTHER, &rtparam)) != 0) {
260 jack_error ("cannot switch to normal scheduling priority(%s)\n",
261 strerror (errno));
262 return -1;
264 return 0;
268 jack_acquire_real_time_scheduling (pthread_t thread, int priority)
270 struct sched_param rtparam;
271 int x;
273 memset (&rtparam, 0, sizeof (rtparam));
274 rtparam.sched_priority = priority;
276 if ((x = pthread_setschedparam (thread, SCHED_FIFO, &rtparam)) != 0) {
277 jack_error ("cannot use real-time scheduling (FIFO at priority %d) "
278 "[for thread %d, from thread %d] (%d: %s)",
279 rtparam.sched_priority,
280 thread, pthread_self(),
281 x, strerror (x));
282 return -1;
285 return 0;
288 #endif /* JACK_USE_MACH_THREADS */