1 /* Copyright (C) 2003-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, see <https://www.gnu.org/licenses/>. */
25 #include <internaltypes.h>
27 #include "kernel-posix-timers.h"
28 #include "kernel-posix-cpu-timers.h"
29 #include <shlib-compat.h>
32 ___timer_create (clockid_t clock_id
, struct sigevent
*evp
, timer_t
*timerid
)
35 clockid_t syscall_clockid
= (clock_id
== CLOCK_PROCESS_CPUTIME_ID
37 : clock_id
== CLOCK_THREAD_CPUTIME_ID
41 /* If the user wants notification via a thread we need to handle
44 || __builtin_expect (evp
->sigev_notify
!= SIGEV_THREAD
, 1))
46 struct sigevent local_evp
;
50 /* The kernel has to pass up the timer ID which is a
51 userlevel object. Therefore we cannot leave it up to
52 the kernel to determine it. */
53 local_evp
.sigev_notify
= SIGEV_SIGNAL
;
54 local_evp
.sigev_signo
= SIGALRM
;
55 local_evp
.sigev_value
.sival_ptr
= NULL
;
60 kernel_timer_t ktimerid
;
61 if (INLINE_SYSCALL_CALL (timer_create
, syscall_clockid
, evp
,
65 *timerid
= kernel_timer_to_timerid (ktimerid
);
69 /* Create the helper thread. */
70 __pthread_once (&__timer_helper_once
, __timer_start_helper_thread
);
71 if (__timer_helper_tid
== 0)
73 /* No resources to start the helper thread. */
78 struct timer
*newp
= malloc (sizeof (struct timer
));
82 /* Copy the thread parameters the user provided. */
83 newp
->sival
= evp
->sigev_value
;
84 newp
->thrfunc
= evp
->sigev_notify_function
;
86 /* We cannot simply copy the thread attributes since the
87 implementation might keep internal information for
89 __pthread_attr_init (&newp
->attr
);
90 if (evp
->sigev_notify_attributes
!= NULL
)
92 struct pthread_attr
*nattr
;
93 struct pthread_attr
*oattr
;
95 nattr
= (struct pthread_attr
*) &newp
->attr
;
96 oattr
= (struct pthread_attr
*) evp
->sigev_notify_attributes
;
98 nattr
->schedparam
= oattr
->schedparam
;
99 nattr
->schedpolicy
= oattr
->schedpolicy
;
100 nattr
->flags
= oattr
->flags
;
101 nattr
->guardsize
= oattr
->guardsize
;
102 nattr
->stackaddr
= oattr
->stackaddr
;
103 nattr
->stacksize
= oattr
->stacksize
;
106 /* In any case set the detach flag. */
107 __pthread_attr_setdetachstate (&newp
->attr
, PTHREAD_CREATE_DETACHED
);
109 /* Create the event structure for the kernel timer. */
110 struct sigevent sev
=
111 { .sigev_value
.sival_ptr
= newp
,
112 .sigev_signo
= SIGTIMER
,
113 .sigev_notify
= SIGEV_SIGNAL
| SIGEV_THREAD_ID
,
114 ._sigev_un
= { ._pad
= { [0] = __timer_helper_tid
} } };
116 /* Create the timer. */
118 res
= INTERNAL_SYSCALL_CALL (timer_create
, syscall_clockid
, &sev
,
120 if (INTERNAL_SYSCALL_ERROR_P (res
))
123 __set_errno (INTERNAL_SYSCALL_ERRNO (res
));
127 /* Add to the queue of active timers with thread delivery. */
128 __pthread_mutex_lock (&__timer_active_sigev_thread_lock
);
129 newp
->next
= __timer_active_sigev_thread
;
130 __timer_active_sigev_thread
= newp
;
131 __pthread_mutex_unlock (&__timer_active_sigev_thread_lock
);
133 *timerid
= timer_to_timerid (newp
);
139 versioned_symbol (libc
, ___timer_create
, timer_create
, GLIBC_2_34
);
140 libc_hidden_ver (___timer_create
, __timer_create
)
142 #if TIMER_T_WAS_INT_COMPAT
143 # if OTHER_SHLIB_COMPAT (librt, GLIBC_2_3_3, GLIBC_2_34)
144 compat_symbol (librt
, ___timer_create
, timer_create
, GLIBC_2_3_3
);
147 # if OTHER_SHLIB_COMPAT (librt, GLIBC_2_2, GLIBC_2_3_3)
148 timer_t __timer_compat_list
[OLD_TIMER_MAX
];
151 __timer_create_old (clockid_t clock_id
, struct sigevent
*evp
, int *timerid
)
155 int res
= __timer_create (clock_id
, evp
, &newp
);
159 for (i
= 0; i
< OLD_TIMER_MAX
; ++i
)
160 if (__timer_compat_list
[i
] == NULL
161 && ! atomic_compare_and_exchange_bool_acq (&__timer_compat_list
[i
],
168 if (__glibc_unlikely (i
== OLD_TIMER_MAX
))
171 __timer_delete (newp
);
172 __set_errno (EINVAL
);
179 compat_symbol (librt
, __timer_create_old
, timer_create
, GLIBC_2_2
);
180 # endif /* OTHER_SHLIB_COMPAT */
182 #else /* !TIMER_T_WAS_INT_COMPAT */
183 # if OTHER_SHLIB_COMPAT (librt, GLIBC_2_2, GLIBC_2_34)
184 compat_symbol (librt
, ___timer_create
, timer_create
, GLIBC_2_2
);
186 #endif /* !TIMER_T_WAS_INT_COMPAT */