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.
26 #include <jack/jack.h>
27 #include <jack/thread.h>
28 #include <jack/internal.h>
38 #ifdef JACK_USE_MACH_THREADS
39 #include <sysdeps/pThreadUtilities.h>
43 log_result (char *msg
, int res
)
46 snprintf(outbuf
, sizeof(outbuf
),
47 "jack_client_create_thread: error %d %s: %s",
48 res
, msg
, strerror(res
));
53 maybe_get_capabilities (jack_client_t
* client
)
55 #ifdef USE_CAPABILITIES
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
);
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
83 jack_error ("could not receive realtime capabilities, "
84 "client will run non-realtime");
89 #endif /* USE_CAPABILITIES */
93 jack_thread_proxy (void* varg
)
95 jack_thread_arg_t
* arg
= (jack_thread_arg_t
*) varg
;
98 jack_client_t
* client
= arg
->client
;
101 maybe_get_capabilities (client
);
102 jack_acquire_real_time_scheduling (pthread_self(), arg
->priority
);
106 work
= arg
->work_function
;
114 jack_client_create_thread (jack_client_t
* client
,
118 void*(*start_routine
)(void*),
121 #ifndef JACK_USE_MACH_THREADS
123 jack_thread_arg_t
* thread_args
;
124 #endif /* !JACK_USE_MACH_THREADS */
129 result
= pthread_create (thread
, 0, start_routine
, arg
);
131 log_result("creating thread with default parameters",
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
);
147 log_result("requesting explicit scheduling", result
);
150 result
= pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_JOINABLE
);
152 log_result("requesting joinable thread creation", result
);
156 result
= pthread_attr_setscope(&attr
, PTHREAD_SCOPE_PROCESS
);
158 result
= pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
161 log_result("requesting system scheduling scope", result
);
165 result
= pthread_attr_setstacksize(&attr
, THREAD_STACK
);
167 log_result("setting thread stack size", 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
);
181 log_result ("creating realtime thread", result
);
185 #else /* JACK_USE_MACH_THREADS */
187 result
= pthread_create (thread
, 0, start_routine
, arg
);
189 log_result ("creating realtime thread", result
);
193 /* time constraint thread */
194 setThreadToPriority (*thread
, 96, TRUE
, 10000000);
196 #endif /* JACK_USE_MACH_THREADS */
202 jack_client_real_time_priority (jack_client_t
* client
)
204 if (!client
->engine
->real_time
) {
208 return client
->engine
->client_priority
;
212 jack_client_max_real_time_priority (jack_client_t
* client
)
214 if (!client
->engine
->real_time
) {
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);
231 jack_acquire_real_time_scheduling (pthread_t thread
, int priority
)
234 setThreadToPriority(thread
, 96, TRUE
, 10000000);
238 #else /* !JACK_USE_MACH_THREADS */
241 jack_drop_real_time_scheduling (pthread_t thread
)
243 struct sched_param rtparam
;
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",
258 jack_acquire_real_time_scheduling (pthread_t thread
, int priority
)
260 struct sched_param rtparam
;
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(),
278 #endif /* JACK_USE_MACH_THREADS */