timer_create.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /* Copyright (C) 2003,2004, 2007, 2009 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation; either version 2.1 of the
  7. License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; see the file COPYING.LIB. If
  14. not, see <http://www.gnu.org/licenses/>. */
  15. #include <errno.h>
  16. #include <pthread.h>
  17. #include <signal.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <time.h>
  21. #include <sysdep.h>
  22. #include <bits/kernel-features.h>
  23. #include <internaltypes.h>
  24. #include <pthreadP.h>
  25. #include "kernel-posix-timers.h"
  26. #include "kernel-posix-cpu-timers.h"
  27. #ifdef __NR_timer_create
  28. # ifndef __ASSUME_POSIX_TIMERS
  29. static int compat_timer_create (clockid_t clock_id, struct sigevent *evp,
  30. timer_t *timerid);
  31. # define timer_create static compat_timer_create
  32. # include <nptl/sysdeps/pthread/timer_create.c>
  33. # undef timer_create
  34. /* Nonzero if the system calls are not available. */
  35. int __no_posix_timers attribute_hidden;
  36. # endif
  37. # ifdef timer_create_alias
  38. # define timer_create timer_create_alias
  39. # endif
  40. int
  41. timer_create (
  42. clockid_t clock_id,
  43. struct sigevent *evp,
  44. timer_t *timerid)
  45. {
  46. # undef timer_create
  47. # ifndef __ASSUME_POSIX_TIMERS
  48. if (__no_posix_timers >= 0)
  49. # endif
  50. {
  51. clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID
  52. ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED)
  53. : clock_id == CLOCK_THREAD_CPUTIME_ID
  54. ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
  55. : clock_id);
  56. /* If the user wants notification via a thread we need to handle
  57. this special. */
  58. if (evp == NULL
  59. || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1))
  60. {
  61. struct sigevent local_evp;
  62. /* We avoid allocating too much memory by basically
  63. using struct timer as a derived class with the
  64. first two elements being in the superclass. We only
  65. need these two elements here. */
  66. struct timer *newp = (struct timer *) malloc (offsetof (struct timer,
  67. thrfunc));
  68. if (newp == NULL)
  69. /* No more memory. */
  70. return -1;
  71. if (evp == NULL)
  72. {
  73. /* The kernel has to pass up the timer ID which is a
  74. userlevel object. Therefore we cannot leave it up to
  75. the kernel to determine it. */
  76. local_evp.sigev_notify = SIGEV_SIGNAL;
  77. local_evp.sigev_signo = SIGALRM;
  78. local_evp.sigev_value.sival_ptr = newp;
  79. evp = &local_evp;
  80. }
  81. kernel_timer_t ktimerid;
  82. int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp,
  83. &ktimerid);
  84. # ifndef __ASSUME_POSIX_TIMERS
  85. if (retval != -1 || errno != ENOSYS)
  86. # endif
  87. {
  88. # ifndef __ASSUME_POSIX_TIMERS
  89. __no_posix_timers = 1;
  90. # endif
  91. if (retval != -1)
  92. {
  93. newp->sigev_notify = (evp != NULL
  94. ? evp->sigev_notify : SIGEV_SIGNAL);
  95. newp->ktimerid = ktimerid;
  96. *timerid = (timer_t) newp;
  97. }
  98. else
  99. {
  100. /* Cannot allocate the timer, fail. */
  101. free (newp);
  102. retval = -1;
  103. }
  104. return retval;
  105. }
  106. free (newp);
  107. # ifndef __ASSUME_POSIX_TIMERS
  108. /* When we come here the syscall does not exist. Make sure we
  109. do not try to use it again. */
  110. __no_posix_timers = -1;
  111. # endif
  112. }
  113. else
  114. {
  115. # ifndef __ASSUME_POSIX_TIMERS
  116. /* Make sure we have the necessary kernel support. */
  117. if (__no_posix_timers == 0)
  118. {
  119. INTERNAL_SYSCALL_DECL (err);
  120. struct timespec ts;
  121. int res;
  122. res = INTERNAL_SYSCALL (clock_getres, err, 2,
  123. CLOCK_REALTIME, &ts);
  124. __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err)
  125. ? -1 : 1);
  126. }
  127. if (__no_posix_timers > 0)
  128. # endif
  129. {
  130. /* Create the helper thread. */
  131. pthread_once (&__helper_once, __start_helper_thread);
  132. if (__helper_tid == 0)
  133. {
  134. /* No resources to start the helper thread. */
  135. __set_errno (EAGAIN);
  136. return -1;
  137. }
  138. struct timer *newp;
  139. newp = (struct timer *) malloc (sizeof (struct timer));
  140. if (newp == NULL)
  141. return -1;
  142. /* Copy the thread parameters the user provided. */
  143. newp->sival = evp->sigev_value;
  144. newp->thrfunc = evp->sigev_notify_function;
  145. newp->sigev_notify = SIGEV_THREAD;
  146. /* We cannot simply copy the thread attributes since the
  147. implementation might keep internal information for
  148. each instance. */
  149. (void) pthread_attr_init (&newp->attr);
  150. if (evp->sigev_notify_attributes != NULL)
  151. {
  152. struct pthread_attr *nattr;
  153. struct pthread_attr *oattr;
  154. nattr = (struct pthread_attr *) &newp->attr;
  155. oattr = (struct pthread_attr *) evp->sigev_notify_attributes;
  156. nattr->schedparam = oattr->schedparam;
  157. nattr->schedpolicy = oattr->schedpolicy;
  158. nattr->flags = oattr->flags;
  159. nattr->guardsize = oattr->guardsize;
  160. nattr->stackaddr = oattr->stackaddr;
  161. nattr->stacksize = oattr->stacksize;
  162. }
  163. /* In any case set the detach flag. */
  164. (void) pthread_attr_setdetachstate (&newp->attr,
  165. PTHREAD_CREATE_DETACHED);
  166. /* Create the event structure for the kernel timer. */
  167. struct sigevent sev =
  168. { .sigev_value.sival_ptr = newp,
  169. .sigev_signo = SIGTIMER,
  170. .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID,
  171. ._sigev_un = { ._pad = { [0] = __helper_tid } } };
  172. /* Create the timer. */
  173. INTERNAL_SYSCALL_DECL (err);
  174. int res;
  175. res = INTERNAL_SYSCALL (timer_create, err, 3,
  176. syscall_clockid, &sev, &newp->ktimerid);
  177. if (! INTERNAL_SYSCALL_ERROR_P (res, err))
  178. {
  179. /* Add to the queue of active timers with thread
  180. delivery. */
  181. pthread_mutex_lock (&__active_timer_sigev_thread_lock);
  182. newp->next = __active_timer_sigev_thread;
  183. __active_timer_sigev_thread = newp;
  184. pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
  185. *timerid = (timer_t) newp;
  186. return 0;
  187. }
  188. /* Free the resources. */
  189. free (newp);
  190. __set_errno (INTERNAL_SYSCALL_ERRNO (res, err));
  191. return -1;
  192. }
  193. }
  194. }
  195. # ifndef __ASSUME_POSIX_TIMERS
  196. /* Compatibility code. */
  197. return compat_timer_create (clock_id, evp, timerid);
  198. # endif
  199. }
  200. #else
  201. # ifdef timer_create_alias
  202. # define timer_create timer_create_alias
  203. # endif
  204. /* The new system calls are not available. Use the userlevel
  205. implementation. */
  206. # include <nptl/sysdeps/pthread/timer_create.c>
  207. #endif