Update copyright notices with scripts/update-copyrights
[glibc.git] / nptl / sysdeps / unix / sysv / linux / timer_create.c
blob8b20aba53bcdb0f755f20b8d18074b9c13ce11fd
1 /* Copyright (C) 2003-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, see <http://www.gnu.org/licenses/>. */
19 #include <errno.h>
20 #include <pthread.h>
21 #include <signal.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <sysdep.h>
26 #include <kernel-features.h>
27 #include <internaltypes.h>
28 #include <nptl/pthreadP.h>
29 #include "kernel-posix-timers.h"
30 #include "kernel-posix-cpu-timers.h"
33 #ifdef timer_create_alias
34 # define timer_create timer_create_alias
35 #endif
38 int
39 timer_create (clock_id, evp, timerid)
40 clockid_t clock_id;
41 struct sigevent *evp;
42 timer_t *timerid;
44 #undef timer_create
46 clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID
47 ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED)
48 : clock_id == CLOCK_THREAD_CPUTIME_ID
49 ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
50 : clock_id);
52 /* If the user wants notification via a thread we need to handle
53 this special. */
54 if (evp == NULL
55 || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1))
57 struct sigevent local_evp;
59 /* We avoid allocating too much memory by basically
60 using struct timer as a derived class with the
61 first two elements being in the superclass. We only
62 need these two elements here. */
63 struct timer *newp = (struct timer *) malloc (offsetof (struct timer,
64 thrfunc));
65 if (newp == NULL)
66 /* No more memory. */
67 return -1;
69 if (evp == NULL)
71 /* The kernel has to pass up the timer ID which is a
72 userlevel object. Therefore we cannot leave it up to
73 the kernel to determine it. */
74 local_evp.sigev_notify = SIGEV_SIGNAL;
75 local_evp.sigev_signo = SIGALRM;
76 local_evp.sigev_value.sival_ptr = newp;
78 evp = &local_evp;
81 kernel_timer_t ktimerid;
82 int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp,
83 &ktimerid);
85 if (retval != -1)
87 newp->sigev_notify = (evp != NULL
88 ? evp->sigev_notify : SIGEV_SIGNAL);
89 newp->ktimerid = ktimerid;
91 *timerid = (timer_t) newp;
93 else
95 /* Cannot allocate the timer, fail. */
96 free (newp);
97 retval = -1;
100 return retval;
102 else
104 /* Create the helper thread. */
105 pthread_once (&__helper_once, __start_helper_thread);
106 if (__helper_tid == 0)
108 /* No resources to start the helper thread. */
109 __set_errno (EAGAIN);
110 return -1;
113 struct timer *newp;
114 newp = (struct timer *) malloc (sizeof (struct timer));
115 if (newp == NULL)
116 return -1;
118 /* Copy the thread parameters the user provided. */
119 newp->sival = evp->sigev_value;
120 newp->thrfunc = evp->sigev_notify_function;
121 newp->sigev_notify = SIGEV_THREAD;
123 /* We cannot simply copy the thread attributes since the
124 implementation might keep internal information for
125 each instance. */
126 (void) pthread_attr_init (&newp->attr);
127 if (evp->sigev_notify_attributes != NULL)
129 struct pthread_attr *nattr;
130 struct pthread_attr *oattr;
132 nattr = (struct pthread_attr *) &newp->attr;
133 oattr = (struct pthread_attr *) evp->sigev_notify_attributes;
135 nattr->schedparam = oattr->schedparam;
136 nattr->schedpolicy = oattr->schedpolicy;
137 nattr->flags = oattr->flags;
138 nattr->guardsize = oattr->guardsize;
139 nattr->stackaddr = oattr->stackaddr;
140 nattr->stacksize = oattr->stacksize;
143 /* In any case set the detach flag. */
144 (void) pthread_attr_setdetachstate (&newp->attr,
145 PTHREAD_CREATE_DETACHED);
147 /* Create the event structure for the kernel timer. */
148 struct sigevent sev =
149 { .sigev_value.sival_ptr = newp,
150 .sigev_signo = SIGTIMER,
151 .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID,
152 ._sigev_un = { ._pad = { [0] = __helper_tid } } };
154 /* Create the timer. */
155 INTERNAL_SYSCALL_DECL (err);
156 int res;
157 res = INTERNAL_SYSCALL (timer_create, err, 3,
158 syscall_clockid, &sev, &newp->ktimerid);
159 if (! INTERNAL_SYSCALL_ERROR_P (res, err))
161 /* Add to the queue of active timers with thread
162 delivery. */
163 pthread_mutex_lock (&__active_timer_sigev_thread_lock);
164 newp->next = __active_timer_sigev_thread;
165 __active_timer_sigev_thread = newp;
166 pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
168 *timerid = (timer_t) newp;
169 return 0;
172 /* Free the resources. */
173 free (newp);
175 __set_errno (INTERNAL_SYSCALL_ERRNO (res, err));
177 return -1;