* rt/tst-cpuclock1.c: New file.
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / timer_create.c
1 /* Copyright (C) 2003,2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
4
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.
9
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.
14
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 not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <pthread.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <sysdep.h>
27 #include <kernel-features.h>
28 #include <internaltypes.h>
29 #include <nptl/pthreadP.h>
30 #include "kernel-posix-timers.h"
31 #include "kernel-posix-cpu-timers.h"
32
33
34 #ifdef __NR_timer_create
35 # ifndef __ASSUME_POSIX_TIMERS
36 static int compat_timer_create (clockid_t clock_id, struct sigevent *evp,
37                                 timer_t *timerid);
38 #  define timer_create static compat_timer_create
39 #  include <nptl/sysdeps/pthread/timer_create.c>
40 #  undef timer_create
41
42 /* Nonzero if the system calls are not available.  */
43 int __no_posix_timers attribute_hidden;
44 # endif
45
46 # ifdef timer_create_alias
47 #  define timer_create timer_create_alias
48 # endif
49
50
51 int
52 timer_create (clock_id, evp, timerid)
53      clockid_t clock_id;
54      struct sigevent *evp;
55      timer_t *timerid;
56 {
57 # undef timer_create
58 # ifndef __ASSUME_POSIX_TIMERS
59   if  (__no_posix_timers >= 0)
60 # endif
61     {
62       clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID
63                                    ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED)
64                                    : clock_id == CLOCK_THREAD_CPUTIME_ID
65                                    ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
66                                    : clock_id);
67
68       /* If the user wants notification via a thread we need to handle
69          this special.  */
70       if (evp == NULL
71           || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1))
72         {
73           struct sigevent local_evp;
74
75           /* We avoid allocating too much memory by basically
76              using struct timer as a derived class with the
77              first two elements being in the superclass.  We only
78              need these two elements here.  */
79           struct timer *newp = (struct timer *) malloc (offsetof (struct timer,
80                                                                   thrfunc));
81           if (newp == NULL)
82             /* No more memory.  */
83             return -1;
84
85           if (evp == NULL)
86             {
87               /* The kernel has to pass up the timer ID which is a
88                  userlevel object.  Therefore we cannot leave it up to
89                  the kernel to determine it.  */
90               local_evp.sigev_notify = SIGEV_SIGNAL;
91               local_evp.sigev_signo = SIGALRM;
92               local_evp.sigev_value.sival_ptr = newp;
93
94               evp = &local_evp;
95             }
96
97           kernel_timer_t ktimerid;
98           int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp,
99                                        &ktimerid);
100
101 # ifndef __ASSUME_POSIX_TIMERS
102           if (retval != -1 || errno != ENOSYS)
103 # endif
104             {
105 # ifndef __ASSUME_POSIX_TIMERS
106               __no_posix_timers = 1;
107 # endif
108
109               if (retval != -1)
110                 {
111                   newp->sigev_notify = (evp != NULL
112                                         ? evp->sigev_notify : SIGEV_SIGNAL);
113                   newp->ktimerid = ktimerid;
114
115                   *timerid = (timer_t) newp;
116                 }
117               else
118                 {
119                   /* Cannot allocate the timer, fail.  */
120                   free (newp);
121                   retval = -1;
122                 }
123
124               return retval;
125             }
126
127           free (newp);
128
129 # ifndef __ASSUME_POSIX_TIMERS
130           /* When we come here the syscall does not exist.  Make sure we
131              do not try to use it again.  */
132           __no_posix_timers = -1;
133 # endif
134         }
135       else
136         {
137 # ifndef __ASSUME_POSIX_TIMERS
138           /* Make sure we have the necessary kernel support.  */
139           if (__no_posix_timers == 0)
140             {
141               INTERNAL_SYSCALL_DECL (err);
142               struct timespec ts;
143               int res;
144               res = INTERNAL_SYSCALL (clock_getres, err, 2,
145                                       CLOCK_REALTIME, &ts);
146               __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err)
147                                    ? -1 : 1);
148             }
149
150           if (__no_posix_timers > 0)
151 # endif
152             {
153               /* Create the helper thread.  */
154               pthread_once (&__helper_once, __start_helper_thread);
155               if (__helper_tid == 0)
156                 {
157                   /* No resources to start the helper thread.  */
158                   __set_errno (EAGAIN);
159                   return -1;
160                 }
161
162               struct timer *newp;
163               newp = (struct timer *) malloc (sizeof (struct timer));
164               if (newp == NULL)
165                 return -1;
166
167               /* Copy the thread parameters the user provided.  */
168               newp->sival = evp->sigev_value;
169               newp->thrfunc = evp->sigev_notify_function;
170
171               /* We cannot simply copy the thread attributes since the
172                  implementation might keep internal information for
173                  each instance.  */
174               (void) pthread_attr_init (&newp->attr);
175               if (evp->sigev_notify_attributes != NULL)
176                 {
177                   struct pthread_attr *nattr;
178                   struct pthread_attr *oattr;
179
180                   nattr = (struct pthread_attr *) &newp->attr;
181                   oattr = (struct pthread_attr *) evp->sigev_notify_attributes;
182
183                   nattr->schedparam = oattr->schedparam;
184                   nattr->schedpolicy = oattr->schedpolicy;
185                   nattr->flags = oattr->flags;
186                   nattr->guardsize = oattr->guardsize;
187                   nattr->stackaddr = oattr->stackaddr;
188                   nattr->stacksize = oattr->stacksize;
189                 }
190
191               /* In any case set the detach flag.  */
192               (void) pthread_attr_setdetachstate (&newp->attr,
193                                                   PTHREAD_CREATE_DETACHED);
194
195               /* Create the event structure for the kernel timer.  */
196               struct sigevent sev;
197               sev.sigev_value.sival_ptr = newp;
198               sev.sigev_signo = SIGTIMER;
199               sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
200               /* This is the thread ID of the helper thread.  */
201               sev._sigev_un._pad[0] = __helper_tid;
202
203               /* Create the timer.  */
204               INTERNAL_SYSCALL_DECL (err);
205               int res;
206               res = INTERNAL_SYSCALL (timer_create, err, 3,
207                                       syscall_clockid, &sev, &newp->ktimerid);
208               if (! INTERNAL_SYSCALL_ERROR_P (res, err))
209                 {
210                   *timerid = (timer_t) newp;
211                   return 0;
212                 }
213
214               /* Free the resources.  */
215               free (newp);
216
217               __set_errno (INTERNAL_SYSCALL_ERRNO (res, err));
218
219               return -1;
220             }
221         }
222     }
223
224 # ifndef __ASSUME_POSIX_TIMERS
225   /* Compatibility code.  */
226   return compat_timer_create (clock_id, evp, timerid);
227 # endif
228 }
229 #else
230 # ifdef timer_create_alias
231 #  define timer_create timer_create_alias
232 # endif
233 /* The new system calls are not available.  Use the userlevel
234    implementation.  */
235 # include <nptl/sysdeps/pthread/timer_create.c>
236 #endif