jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
7.6KB

  1. /*
  2. Copyright (C) 2004 Paul Davis
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2.1 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. Thread creation function including workarounds for real-time scheduling
  15. behaviour on different glibc versions.
  16. $Id$
  17. */
  18. #include <config.h>
  19. #include <jack/thread.h>
  20. #include <jack/internal.h>
  21. #include <pthread.h>
  22. #include <sched.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <errno.h>
  26. #ifdef JACK_USE_MACH_THREADS
  27. #include <sysdeps/pThreadUtilities.h>
  28. #endif
  29. static inline void
  30. log_result (char *msg, int res)
  31. {
  32. char outbuf[500];
  33. snprintf(outbuf, sizeof(outbuf),
  34. "jack_create_thread: error %d %s: %s",
  35. res, msg, strerror(res));
  36. jack_error(outbuf);
  37. }
  38. int
  39. jack_create_thread (pthread_t* thread,
  40. int priority,
  41. int realtime,
  42. void*(*start_routine)(void*),
  43. void* arg)
  44. {
  45. #ifndef JACK_USE_MACH_THREADS
  46. pthread_attr_t attr;
  47. int policy;
  48. struct sched_param param;
  49. int actual_policy;
  50. struct sched_param actual_param;
  51. #endif /* !JACK_USE_MACH_THREADS */
  52. int result = 0;
  53. if (!realtime) {
  54. result = pthread_create (thread, 0, start_routine, arg);
  55. if (result) {
  56. log_result("creating thread with default parameters",
  57. result);
  58. }
  59. return result;
  60. }
  61. /* realtime thread. this disgusting mess is a reflection of
  62. * the 2nd-class nature of RT programming under POSIX in
  63. * general and Linux in particular.
  64. */
  65. #ifndef JACK_USE_MACH_THREADS
  66. pthread_attr_init(&attr);
  67. policy = SCHED_FIFO;
  68. param.sched_priority = priority;
  69. result = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
  70. if (result) {
  71. log_result("requesting explicit scheduling", result);
  72. return result;
  73. }
  74. result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  75. if (result) {
  76. log_result("requesting joinable thread creation", result);
  77. return result;
  78. }
  79. result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
  80. if (result) {
  81. log_result("requesting system scheduling scope", result);
  82. return result;
  83. }
  84. result = pthread_attr_setschedpolicy(&attr, policy);
  85. if (result) {
  86. log_result("requesting non-standard scheduling policy", result);
  87. return result;
  88. }
  89. result = pthread_attr_setschedparam(&attr, &param);
  90. if (result) {
  91. log_result("requesting thread priority", result);
  92. return result;
  93. }
  94. /* with respect to getting scheduling class+priority set up
  95. correctly, there are three possibilities here:
  96. a) the call sets them and returns zero
  97. ===================================
  98. this is great, obviously.
  99. b) the call fails to set them and returns an error code
  100. ====================================================
  101. this could happen for a number of reasons,
  102. but the important one is that we do not have the
  103. priviledges required to create a realtime
  104. thread. this could be correct, or it could be
  105. bogus: there is at least one version of glibc
  106. that checks only for UID in
  107. pthread_attr_setschedpolicy(), and does not
  108. check capabilities.
  109. c) the call fails to set them and does not return an error code
  110. ============================================================
  111. this last case is caused by a stupid workaround in NPTL 0.60
  112. where scheduling parameters are simply ignored, with no indication
  113. of an error.
  114. */
  115. result = pthread_create (thread, &attr, start_routine, arg);
  116. if (result) {
  117. /* this workaround temporarily switches the
  118. current thread to the proper scheduler
  119. and priority, using a call that
  120. correctly checks for capabilities, then
  121. starts the realtime thread so that it
  122. can inherit them and finally switches
  123. the current thread back to what it was
  124. before.
  125. */
  126. int current_policy;
  127. struct sched_param current_param;
  128. pthread_attr_t inherit_attr;
  129. current_policy = sched_getscheduler (0);
  130. sched_getparam (0, &current_param);
  131. result = sched_setscheduler (0, policy, &param);
  132. if (result) {
  133. log_result("switching current thread to rt for "
  134. "inheritance", result);
  135. return result;
  136. }
  137. pthread_attr_init (&inherit_attr);
  138. result = pthread_attr_setscope (&inherit_attr,
  139. PTHREAD_SCOPE_SYSTEM);
  140. if (result) {
  141. log_result("requesting system scheduling scope "
  142. "for inheritance", result);
  143. return result;
  144. }
  145. result = pthread_attr_setinheritsched (&inherit_attr,
  146. PTHREAD_INHERIT_SCHED);
  147. if (result) {
  148. log_result("requesting inheritance of scheduling "
  149. "parameters", result);
  150. return result;
  151. }
  152. result = pthread_create (thread, &inherit_attr, start_routine,
  153. arg);
  154. if (result) {
  155. log_result("creating real-time thread by inheritance",
  156. result);
  157. }
  158. sched_setscheduler (0, current_policy, &current_param);
  159. if (result)
  160. return result;
  161. }
  162. /* Still here? Good. Let's see if this worked... */
  163. result = pthread_getschedparam (*thread, &actual_policy, &actual_param);
  164. if (result) {
  165. log_result ("verifying scheduler parameters", result);
  166. return result;
  167. }
  168. if (actual_policy == policy &&
  169. actual_param.sched_priority == param.sched_priority) {
  170. return 0; /* everything worked OK */
  171. }
  172. /* we failed to set the sched class and priority,
  173. * even though no error was returned by
  174. * pthread_create(). fix this by setting them
  175. * explicitly, which as far as is known will
  176. * work even when using thread attributes does not.
  177. */
  178. result = pthread_setschedparam (*thread, policy, &param);
  179. if (result) {
  180. log_result("setting scheduler parameters after thread "
  181. "creation", result);
  182. return result;
  183. }
  184. #else /* JACK_USE_MACH_THREADS */
  185. result = pthread_create (thread, 0, start_routine, arg);
  186. if (result) {
  187. log_result ("creating realtime thread", result);
  188. return result;
  189. }
  190. /* time constraint thread */
  191. setThreadToPriority (*thread, 96, TRUE, 10000000);
  192. #endif /* JACK_USE_MACH_THREADS */
  193. return 0;
  194. }
  195. #if JACK_USE_MACH_THREADS
  196. int
  197. jack_drop_real_time_scheduling (pthread_t thread)
  198. {
  199. setThreadToPriority(thread, 31, FALSE, 10000000);
  200. return 0;
  201. }
  202. int
  203. jack_acquire_real_time_scheduling (pthread_t thread, int priority)
  204. //priority is unused
  205. {
  206. setThreadToPriority(thread, 96, TRUE, 10000000);
  207. return 0;
  208. }
  209. #else /* !JACK_USE_MACH_THREADS */
  210. int
  211. jack_drop_real_time_scheduling (pthread_t thread)
  212. {
  213. struct sched_param rtparam;
  214. int x;
  215. memset (&rtparam, 0, sizeof (rtparam));
  216. rtparam.sched_priority = 0;
  217. if ((x = pthread_setschedparam (thread, SCHED_OTHER, &rtparam)) != 0) {
  218. jack_error ("cannot switch to normal scheduling priority(%s)\n",
  219. strerror (errno));
  220. return -1;
  221. }
  222. return 0;
  223. }
  224. int
  225. jack_acquire_real_time_scheduling (pthread_t thread, int priority)
  226. {
  227. struct sched_param rtparam;
  228. int x;
  229. memset (&rtparam, 0, sizeof (rtparam));
  230. rtparam.sched_priority = priority;
  231. if ((x = pthread_setschedparam (thread, SCHED_FIFO, &rtparam)) != 0) {
  232. jack_error ("cannot use real-time scheduling (FIFO/%d) "
  233. "(%d: %s)", rtparam.sched_priority, x,
  234. strerror (x));
  235. return -1;
  236. }
  237. return 0;
  238. }
  239. #endif /* JACK_USE_MACH_THREADS */