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.

257 lines
7.5KB

  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. #define log_internal(msg, res, fatal) \
  30. if (res) { \
  31. char outbuf[500]; \
  32. snprintf(outbuf, sizeof(outbuf), \
  33. "jack_create_thread: error %d %s: %s", \
  34. res, msg, strerror(res)); \
  35. jack_error(outbuf); \
  36. if (fatal) \
  37. return res; \
  38. }
  39. #define log_result(msg) log_internal(msg, result, 1);
  40. #define log_result_nonfatal(msg) log_internal(msg, result, 0);
  41. int
  42. jack_create_thread (pthread_t* thread,
  43. int priority,
  44. int realtime,
  45. void*(*start_routine)(void*),
  46. void* arg)
  47. {
  48. #ifndef JACK_USE_MACH_THREADS
  49. pthread_attr_t attr;
  50. int policy;
  51. struct sched_param param;
  52. int actual_policy;
  53. struct sched_param actual_param;
  54. #endif /* JACK_USE_MACH_THREADS */
  55. int result = 0;
  56. if (!realtime) {
  57. result = pthread_create (thread, 0, start_routine, arg);
  58. log_result("creating thread with default parameters");
  59. return 0;
  60. }
  61. /* realtime thread. this disgusting mess is a
  62. * reflection of the 2nd-class nature of RT
  63. * programming under POSIX in 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. log_result("requesting explicit scheduling");
  71. result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  72. log_result("requesting joinable thread creation");
  73. result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
  74. log_result("requesting system scheduling scope");
  75. result = pthread_attr_setschedpolicy(&attr, policy);
  76. log_result("requesting non-standard scheduling policy");
  77. result = pthread_attr_setschedparam(&attr, &param);
  78. log_result("requesting thread priority");
  79. /* with respect to getting scheduling class+priority set up
  80. correctly, there are three possibilities here:
  81. a) the call sets them and returns zero
  82. ===================================
  83. this is great, obviously.
  84. b) the call fails to set them and returns an error code
  85. ====================================================
  86. this could happen for a number of reasons,
  87. but the important one is that we do not have the
  88. priviledges required to create a realtime
  89. thread. this could be correct, or it could be
  90. bogus: there is at least one version of glibc
  91. that checks only for UID in
  92. pthread_attr_setschedpolicy(), and does not
  93. check capabilities.
  94. c) the call fails to set them and does not return an error code
  95. ============================================================
  96. this last case is caused by a stupid workaround in NPTL 0.60
  97. where scheduling parameters are simply ignored, with no indication
  98. of an error.
  99. */
  100. result = pthread_create (thread, &attr, start_routine, arg);
  101. if (result) {
  102. /* this workaround temporarily switches the
  103. current thread to the proper scheduler
  104. and priority, using a call that
  105. correctly checks for capabilities, then
  106. starts the realtime thread so that it
  107. can inherit them and finally switches
  108. the current thread back to what it was
  109. before.
  110. */
  111. int current_policy;
  112. struct sched_param current_param;
  113. pthread_attr_t inherit_attr;
  114. current_policy = sched_getscheduler (0);
  115. sched_getparam (0, &current_param);
  116. result = sched_setscheduler (0, policy, &param);
  117. log_result("switching current thread to rt for inheritance");
  118. pthread_attr_init (&inherit_attr);
  119. result = pthread_attr_setscope (&inherit_attr,
  120. PTHREAD_SCOPE_SYSTEM);
  121. log_result("requesting system scheduling scope for inheritance");
  122. result = pthread_attr_setinheritsched (&inherit_attr,
  123. PTHREAD_INHERIT_SCHED);
  124. log_result("requesting inheritance of scheduling parameters");
  125. result = pthread_create (thread, &inherit_attr, start_routine,
  126. arg);
  127. log_result_nonfatal("creating real-time thread by inheritance");
  128. sched_setscheduler (0, current_policy, &current_param);
  129. if (result)
  130. return result;
  131. }
  132. /* Still here? Good. Let's see if this worked... */
  133. result = pthread_getschedparam (*thread, &actual_policy, &actual_param);
  134. log_result ("verifying scheduler parameters");
  135. if (actual_policy == policy &&
  136. actual_param.sched_priority == param.sched_priority) {
  137. /* everything worked OK */
  138. return 0;
  139. }
  140. /* we failed to set the sched class and priority,
  141. * even though no error was returned by
  142. * pthread_create(). fix this by setting them
  143. * explicitly, which as far as is known will
  144. * work even when using thread attributes does not.
  145. */
  146. result = pthread_setschedparam (*thread, policy, &param);
  147. log_result("setting scheduler parameters after thread creation");
  148. #else /* JACK_USE_MACH_THREADS */
  149. result = pthread_create (thread, 0, start_routine, arg);
  150. log_result ("creating realtime thread");
  151. /* time constraint thread */
  152. setThreadToPriority (*thread, 96, TRUE, 10000000);
  153. #endif /* JACK_USE_MACH_THREADS */
  154. return 0;
  155. }
  156. #if JACK_USE_MACH_THREADS
  157. int
  158. jack_drop_real_time_scheduling (pthread_t thread)
  159. {
  160. setThreadToPriority(thread, 31, FALSE, 10000000);
  161. return 0;
  162. }
  163. int
  164. jack_acquire_real_time_scheduling (pthread_t thread, int priority)
  165. //priority is unused
  166. {
  167. setThreadToPriority(thread, 96, TRUE, 10000000);
  168. return 0;
  169. }
  170. #else /* !JACK_USE_MACH_THREADS */
  171. int
  172. jack_drop_real_time_scheduling (pthread_t thread)
  173. {
  174. struct sched_param rtparam;
  175. int x;
  176. memset (&rtparam, 0, sizeof (rtparam));
  177. rtparam.sched_priority = 0;
  178. if ((x = pthread_setschedparam (thread, SCHED_OTHER, &rtparam)) != 0) {
  179. jack_error ("cannot switch to normal scheduling priority(%s)\n",
  180. strerror (errno));
  181. return -1;
  182. }
  183. return 0;
  184. }
  185. int
  186. jack_acquire_real_time_scheduling (pthread_t thread, int priority)
  187. {
  188. struct sched_param rtparam;
  189. int x;
  190. memset (&rtparam, 0, sizeof (rtparam));
  191. rtparam.sched_priority = priority;
  192. if ((x = pthread_setschedparam (thread, SCHED_FIFO, &rtparam)) != 0) {
  193. jack_error ("cannot use real-time scheduling (FIFO/%d) "
  194. "(%d: %s)", rtparam.sched_priority, x,
  195. strerror (x));
  196. return -1;
  197. }
  198. return 0;
  199. }
  200. #endif /* JACK_USE_MACH_THREADS */