timer_create.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /* Copyright (C) 2003-2019 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 <internaltypes.h>
  23. #include <nptl/pthreadP.h>
  24. #include "kernel-posix-timers.h"
  25. #include "kernel-posix-cpu-timers.h"
  26. #ifdef timer_create_alias
  27. # define timer_create timer_create_alias
  28. #endif
  29. int
  30. timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
  31. {
  32. #undef timer_create
  33. {
  34. clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID
  35. ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED)
  36. : clock_id == CLOCK_THREAD_CPUTIME_ID
  37. ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
  38. : clock_id);
  39. /* If the user wants notification via a thread we need to handle
  40. this special. */
  41. if (evp == NULL
  42. || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1))
  43. {
  44. struct sigevent local_evp;
  45. /* We avoid allocating too much memory by basically
  46. using struct timer as a derived class with the
  47. first two elements being in the superclass. We only
  48. need these two elements here. */
  49. struct timer *newp = (struct timer *) malloc (offsetof (struct timer,
  50. thrfunc));
  51. if (newp == NULL)
  52. /* No more memory. */
  53. return -1;
  54. if (evp == NULL)
  55. {
  56. /* The kernel has to pass up the timer ID which is a
  57. userlevel object. Therefore we cannot leave it up to
  58. the kernel to determine it. */
  59. local_evp.sigev_notify = SIGEV_SIGNAL;
  60. local_evp.sigev_signo = SIGALRM;
  61. local_evp.sigev_value.sival_ptr = newp;
  62. evp = &local_evp;
  63. }
  64. kernel_timer_t ktimerid;
  65. int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp,
  66. &ktimerid);
  67. if (retval != -1)
  68. {
  69. newp->sigev_notify = (evp != NULL
  70. ? evp->sigev_notify : SIGEV_SIGNAL);
  71. newp->ktimerid = ktimerid;
  72. *timerid = (timer_t) newp;
  73. }
  74. else
  75. {
  76. /* Cannot allocate the timer, fail. */
  77. free (newp);
  78. retval = -1;
  79. }
  80. return retval;
  81. }
  82. else
  83. {
  84. /* Create the helper thread. */
  85. pthread_once (&__helper_once, __start_helper_thread);
  86. if (__helper_tid == 0)
  87. {
  88. /* No resources to start the helper thread. */
  89. __set_errno (EAGAIN);
  90. return -1;
  91. }
  92. struct timer *newp;
  93. newp = (struct timer *) malloc (sizeof (struct timer));
  94. if (newp == NULL)
  95. return -1;
  96. /* Copy the thread parameters the user provided. */
  97. newp->sival = evp->sigev_value;
  98. newp->thrfunc = evp->sigev_notify_function;
  99. newp->sigev_notify = SIGEV_THREAD;
  100. /* We cannot simply copy the thread attributes since the
  101. implementation might keep internal information for
  102. each instance. */
  103. (void) pthread_attr_init (&newp->attr);
  104. if (evp->sigev_notify_attributes != NULL)
  105. {
  106. struct pthread_attr *nattr;
  107. struct pthread_attr *oattr;
  108. nattr = (struct pthread_attr *) &newp->attr;
  109. oattr = (struct pthread_attr *) evp->sigev_notify_attributes;
  110. nattr->schedparam = oattr->schedparam;
  111. nattr->schedpolicy = oattr->schedpolicy;
  112. nattr->flags = oattr->flags;
  113. nattr->guardsize = oattr->guardsize;
  114. nattr->stackaddr = oattr->stackaddr;
  115. nattr->stacksize = oattr->stacksize;
  116. }
  117. /* In any case set the detach flag. */
  118. (void) pthread_attr_setdetachstate (&newp->attr,
  119. PTHREAD_CREATE_DETACHED);
  120. /* Create the event structure for the kernel timer. */
  121. struct sigevent sev =
  122. { .sigev_value.sival_ptr = newp,
  123. .sigev_signo = SIGTIMER,
  124. .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID,
  125. ._sigev_un = { ._pad = { [0] = __helper_tid } } };
  126. /* Create the timer. */
  127. INTERNAL_SYSCALL_DECL (err);
  128. int res;
  129. res = INTERNAL_SYSCALL (timer_create, err, 3,
  130. syscall_clockid, &sev, &newp->ktimerid);
  131. if (! INTERNAL_SYSCALL_ERROR_P (res, err))
  132. {
  133. /* Add to the queue of active timers with thread
  134. delivery. */
  135. pthread_mutex_lock (&__active_timer_sigev_thread_lock);
  136. newp->next = __active_timer_sigev_thread;
  137. __active_timer_sigev_thread = newp;
  138. pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
  139. *timerid = (timer_t) newp;
  140. return 0;
  141. }
  142. /* Free the resources. */
  143. free (newp);
  144. __set_errno (INTERNAL_SYSCALL_ERRNO (res, err));
  145. return -1;
  146. }
  147. }
  148. }