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.

249 lines
7.4KB

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