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>
42 jack_thread_creator_t jack_thread_creator
= pthread_create
;
45 jack_set_thread_creator (jack_thread_creator_t jtc
)
47 jack_thread_creator
= jtc
;
51 log_result (char *msg
, int res
)
54 snprintf(outbuf
, sizeof(outbuf
),
55 "jack_client_create_thread: error %d %s: %s",
56 res
, msg
, strerror(res
));
61 maybe_get_capabilities (jack_client_t
* client
)
63 #ifdef USE_CAPABILITIES
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
);
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
91 jack_error ("could not receive realtime capabilities, "
92 "client will run non-realtime");
97 #endif /* USE_CAPABILITIES */
101 jack_thread_proxy (void* varg
)
103 jack_thread_arg_t
* arg
= (jack_thread_arg_t
*) varg
;
104 void* (*work
)(void*);
106 jack_client_t
* client
= arg
->client
;
109 maybe_get_capabilities (client
);
110 jack_acquire_real_time_scheduling (pthread_self(), arg
->priority
);
114 work
= arg
->work_function
;
122 jack_client_create_thread (jack_client_t
* client
,
126 void*(*start_routine
)(void*),
129 #ifndef JACK_USE_MACH_THREADS
131 jack_thread_arg_t
* thread_args
;
132 #endif /* !JACK_USE_MACH_THREADS */
137 result
= jack_thread_creator (thread
, 0, start_routine
, arg
);
139 log_result("creating thread with default parameters",
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
);
155 log_result("requesting explicit scheduling", result
);
158 result
= pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_JOINABLE
);
160 log_result("requesting joinable thread creation", result
);
164 result
= pthread_attr_setscope(&attr
, PTHREAD_SCOPE_PROCESS
);
166 result
= pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
169 log_result("requesting system scheduling scope", result
);
173 result
= pthread_attr_setstacksize(&attr
, THREAD_STACK
);
175 log_result("setting thread stack size", result
);
179 if ((thread_args
= (jack_thread_arg_t
*) malloc (sizeof (jack_thread_arg_t
))) == NULL
) {
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
);
191 log_result ("creating realtime thread", result
);
195 #else /* JACK_USE_MACH_THREADS */
197 result
= jack_thread_creator (thread
, 0, start_routine
, arg
);
199 log_result ("creating realtime thread", result
);
203 /* time constraint thread */
204 setThreadToPriority (*thread
, 96, TRUE
, 10000000);
206 #endif /* JACK_USE_MACH_THREADS */
212 jack_client_real_time_priority (jack_client_t
* client
)
214 if (!client
->engine
->real_time
) {
218 return client
->engine
->client_priority
;
222 jack_client_max_real_time_priority (jack_client_t
* client
)
224 if (!client
->engine
->real_time
) {
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);
241 jack_acquire_real_time_scheduling (pthread_t thread
, int priority
)
244 setThreadToPriority(thread
, 96, TRUE
, 10000000);
248 #else /* !JACK_USE_MACH_THREADS */
251 jack_drop_real_time_scheduling (pthread_t thread
)
253 struct sched_param rtparam
;
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",
268 jack_acquire_real_time_scheduling (pthread_t thread
, int priority
)
270 struct sched_param rtparam
;
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(),
288 #endif /* JACK_USE_MACH_THREADS */