Test for stack alignment.
[jlayton/glibc.git] / linuxthreads / sysdeps / pthread / posix-timer.h
1 /* Definitions for POSIX timer implementation on top of LinuxThreads.
2    Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <limits.h>
22 #include <signal.h>
23
24 /* Double linked list.  */
25 struct list_links
26 {
27   struct list_links *next;
28   struct list_links *prev;
29 };
30
31
32 /* Forward declaration.  */
33 struct timer_node;
34
35
36 /* Definitions for an internal thread of the POSIX timer implementation.  */
37 struct thread_node
38 {
39   struct list_links links;
40   pthread_attr_t attr;
41   pthread_t id;
42   unsigned int exists;
43   struct list_links timer_queue;
44   pthread_cond_t cond;
45   struct timer_node *current_timer;
46   pthread_t captured;
47   clockid_t clock_id;
48 };
49
50
51 /* Internal representation of a timer.  */
52 struct timer_node
53 {
54   struct list_links links;
55   struct sigevent event;
56   clockid_t clock;
57   struct itimerspec value;
58   struct timespec expirytime;
59   pthread_attr_t attr;
60   unsigned int abstime;
61   unsigned int armed;
62   enum {
63     TIMER_FREE, TIMER_INUSE, TIMER_DELETED
64   } inuse;
65   struct thread_node *thread;
66   pid_t creator_pid;
67   int refcount;
68   int overrun_count;
69 };
70
71
72 /* Static array with the structures for all the timers.  */
73 extern struct timer_node __timer_array[TIMER_MAX];
74
75 /* Global lock to protect operation on the lists.  */
76 extern pthread_mutex_t __timer_mutex;
77
78 /* Variable to protext initialization.  */
79 extern pthread_once_t __timer_init_once_control;
80
81 /* Nonzero if initialization of timer implementation failed.  */
82 extern int __timer_init_failed;
83
84 /* Nodes for the threads used to deliver signals.  */
85 /* A distinct thread is used for each clock type.  */
86
87 extern struct thread_node __timer_signal_thread_rclk;
88
89
90 /* Return pointer to timer structure corresponding to ID.  */
91 static inline struct timer_node *
92 timer_id2ptr (timer_t timerid)
93 {
94   if (timerid >= 0 && timerid < TIMER_MAX)
95     return &__timer_array[timerid];
96
97   return NULL;
98 }
99
100 /* Return ID of TIMER.  */
101 static inline int
102 timer_ptr2id (struct timer_node *timer)
103 {
104   return timer - __timer_array;
105 }
106
107 /* Check whether timer is valid; global mutex must be held. */
108 static inline int
109 timer_valid (struct timer_node *timer)
110 {
111   return timer && timer->inuse == TIMER_INUSE;
112 }
113
114 /* Timer refcount functions; need global mutex. */
115 extern void __timer_dealloc (struct timer_node *timer);
116
117 static inline void
118 timer_addref (struct timer_node *timer)
119 {
120   timer->refcount++;
121 }
122
123 static inline void
124 timer_delref (struct timer_node *timer)
125 {
126   if (--timer->refcount == 0)
127     __timer_dealloc (timer);
128 }
129
130 /* Timespec helper routines.  */
131 static inline int
132 timespec_compare (const struct timespec *left, const struct timespec *right)
133 {
134   if (left->tv_sec < right->tv_sec)
135     return -1;
136   if (left->tv_sec > right->tv_sec)
137     return 1;
138
139   if (left->tv_nsec < right->tv_nsec)
140     return -1;
141   if (left->tv_nsec > right->tv_nsec)
142     return 1;
143
144   return 0;
145 }
146
147 static inline void
148 timespec_add (struct timespec *sum, const struct timespec *left,
149               const struct timespec *right)
150 {
151   sum->tv_sec = left->tv_sec + right->tv_sec;
152   sum->tv_nsec = left->tv_nsec + right->tv_nsec;
153
154   if (sum->tv_nsec >= 1000000000)
155     {
156       ++sum->tv_sec;
157       sum->tv_nsec -= 1000000000;
158     }
159 }
160
161 static inline void
162 timespec_sub (struct timespec *diff, const struct timespec *left,
163               const struct timespec *right)
164 {
165   diff->tv_sec = left->tv_sec - right->tv_sec;
166   diff->tv_nsec = left->tv_nsec - right->tv_nsec;
167
168   if (diff->tv_nsec < 0)
169     {
170       --diff->tv_sec;
171       diff->tv_nsec += 1000000000;
172     }
173 }
174
175
176 /* We need one of the list functions in the other modules.  */
177 static inline void
178 list_unlink_ip (struct list_links *list)
179 {
180   struct list_links *lnext = list->next, *lprev = list->prev;
181
182   lnext->prev = lprev;
183   lprev->next = lnext;
184
185   /* The suffix ip means idempotent; list_unlink_ip can be called
186    * two or more times on the same node.
187    */
188
189   list->next = list;
190   list->prev = list;
191 }
192
193
194 /* Functions in the helper file.  */
195 extern void __timer_mutex_cancel_handler (void *arg);
196 extern void __timer_init_once (void);
197 extern struct timer_node *__timer_alloc (void);
198 extern int __timer_thread_start (struct thread_node *thread);
199 extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t);
200 extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t);
201 extern void __timer_thread_dealloc (struct thread_node *thread);
202 extern int __timer_thread_queue_timer (struct thread_node *thread,
203                                        struct timer_node *insert);
204 extern void __timer_thread_wakeup (struct thread_node *thread);