timer_create.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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. #if defined(__UCLIBC_USE_TIME64__) && defined(__NR_clock_getres_time64)
  123. res = INTERNAL_SYSCALL (clock_getres_time64, err, 2,
  124. CLOCK_REALTIME, &ts);
  125. #else
  126. res = INTERNAL_SYSCALL (clock_getres, err, 2,
  127. CLOCK_REALTIME, &ts);
  128. #endif
  129. __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err)
  130. ? -1 : 1);
  131. }
  132. if (__no_posix_timers > 0)
  133. # endif
  134. {
  135. /* Create the helper thread. */
  136. pthread_once (&__helper_once, __start_helper_thread);
  137. if (__helper_tid == 0)
  138. {
  139. /* No resources to start the helper thread. */
  140. __set_errno (EAGAIN);
  141. return -1;
  142. }
  143. struct timer *newp;
  144. newp = (struct timer *) malloc (sizeof (struct timer));
  145. if (newp == NULL)
  146. return -1;
  147. /* Copy the thread parameters the user provided. */
  148. newp->sival = evp->sigev_value;
  149. newp->thrfunc = evp->sigev_notify_function;
  150. newp->sigev_notify = SIGEV_THREAD;
  151. /* We cannot simply copy the thread attributes since the
  152. implementation might keep internal information for
  153. each instance. */
  154. (void) pthread_attr_init (&newp->attr);
  155. if (evp->sigev_notify_attributes != NULL)
  156. {
  157. struct pthread_attr *nattr;
  158. struct pthread_attr *oattr;
  159. nattr = (struct pthread_attr *) &newp->attr;
  160. oattr = (struct pthread_attr *) evp->sigev_notify_attributes;
  161. nattr->schedparam = oattr->schedparam;
  162. nattr->schedpolicy = oattr->schedpolicy;
  163. nattr->flags = oattr->flags;
  164. nattr->guardsize = oattr->guardsize;
  165. nattr->stackaddr = oattr->stackaddr;
  166. nattr->stacksize = oattr->stacksize;
  167. }
  168. /* In any case set the detach flag. */
  169. (void) pthread_attr_setdetachstate (&newp->attr,
  170. PTHREAD_CREATE_DETACHED);
  171. /* Create the event structure for the kernel timer. */
  172. struct sigevent sev =
  173. { .sigev_value.sival_ptr = newp,
  174. .sigev_signo = SIGTIMER,
  175. .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID,
  176. ._sigev_un = { ._pad = { [0] = __helper_tid } } };
  177. /* Create the timer. */
  178. INTERNAL_SYSCALL_DECL (err);
  179. int res;
  180. res = INTERNAL_SYSCALL (timer_create, err, 3,
  181. syscall_clockid, &sev, &newp->ktimerid);
  182. if (! INTERNAL_SYSCALL_ERROR_P (res, err))
  183. {
  184. /* Add to the queue of active timers with thread
  185. delivery. */
  186. pthread_mutex_lock (&__active_timer_sigev_thread_lock);
  187. newp->next = __active_timer_sigev_thread;
  188. __active_timer_sigev_thread = newp;
  189. pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
  190. *timerid = (timer_t) newp;
  191. return 0;
  192. }
  193. /* Free the resources. */
  194. free (newp);
  195. __set_errno (INTERNAL_SYSCALL_ERRNO (res, err));
  196. return -1;
  197. }
  198. }
  199. }
  200. # ifndef __ASSUME_POSIX_TIMERS
  201. /* Compatibility code. */
  202. return compat_timer_create (clock_id, evp, timerid);
  203. # endif
  204. }
  205. #else
  206. # ifdef timer_create_alias
  207. # define timer_create timer_create_alias
  208. # endif
  209. /* The new system calls are not available. Use the userlevel
  210. implementation. */
  211. # include <nptl/sysdeps/pthread/timer_create.c>
  212. #endif