~ubuntu-branches/ubuntu/quantal/uclibc/quantal

« back to all changes in this revision

Viewing changes to libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c

  • Committer: Bazaar Package Importer
  • Author(s): Hector Oron
  • Date: 2011-06-11 03:06:20 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110611030620-ywjfvyuqvrpsm282
Tags: 0.9.32-1
* New upstream release
* Add myself as maintainer
* Bump standards version 
* Add Vcs-Git, Vcs-Browser and Homepage fields
* Add watch file 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2003, 2004, 2005, 2006, 2007 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 <setjmp.h>
 
22
#include <signal.h>
 
23
#include <stdbool.h>
 
24
#include <sysdep.h>
 
25
#include <bits/kernel-features.h>
 
26
#include <pthreadP.h>
 
27
#include "kernel-posix-timers.h"
 
28
 
 
29
 
 
30
/* List of active SIGEV_THREAD timers.  */
 
31
struct timer *__active_timer_sigev_thread;
 
32
/* Lock for the __active_timer_sigev_thread.  */
 
33
pthread_mutex_t __active_timer_sigev_thread_lock = PTHREAD_MUTEX_INITIALIZER;
 
34
 
 
35
 
 
36
struct thread_start_data
 
37
{
 
38
  void (*thrfunc) (sigval_t);
 
39
  sigval_t sival;
 
40
};
 
41
 
 
42
 
 
43
#ifdef __NR_timer_create
 
44
/* Helper thread to call the user-provided function.  */
 
45
static void *
 
46
timer_sigev_thread (void *arg)
 
47
{
 
48
  /* The parent thread has all signals blocked.  This is a bit
 
49
     surprising for user code, although valid.  We unblock all
 
50
     signals.  */
 
51
  sigset_t ss;
 
52
  sigemptyset (&ss);
 
53
  INTERNAL_SYSCALL_DECL (err);
 
54
  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8);
 
55
 
 
56
  struct thread_start_data *td = (struct thread_start_data *) arg;
 
57
 
 
58
  void (*thrfunc) (sigval_t) = td->thrfunc;
 
59
  sigval_t sival = td->sival;
 
60
 
 
61
  /* The TD object was allocated in timer_helper_thread.  */
 
62
  free (td);
 
63
 
 
64
  /* Call the user-provided function.  */
 
65
  thrfunc (sival);
 
66
 
 
67
  return NULL;
 
68
}
 
69
 
 
70
 
 
71
/* Helper function to support starting threads for SIGEV_THREAD.  */
 
72
static void *
 
73
timer_helper_thread (void *arg)
 
74
{
 
75
  /* Wait for the SIGTIMER signal, allowing the setXid signal, and
 
76
     none else.  */
 
77
  sigset_t ss;
 
78
  sigemptyset (&ss);
 
79
  __sigaddset (&ss, SIGTIMER);
 
80
 
 
81
  /* Endless loop of waiting for signals.  The loop is only ended when
 
82
     the thread is canceled.  */
 
83
  while (1)
 
84
    {
 
85
      siginfo_t si;
 
86
 
 
87
      /* sigwaitinfo cannot be used here, since it deletes
 
88
         SIGCANCEL == SIGTIMER from the set.  */
 
89
 
 
90
      int oldtype = LIBC_CANCEL_ASYNC ();
 
91
 
 
92
      /* XXX The size argument hopefully will have to be changed to the
 
93
         real size of the user-level sigset_t.  */
 
94
      int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL,
 
95
                                   _NSIG / 8);
 
96
 
 
97
      LIBC_CANCEL_RESET (oldtype);
 
98
 
 
99
      if (result > 0)
 
100
        {
 
101
          if (si.si_code == SI_TIMER)
 
102
            {
 
103
              struct timer *tk = (struct timer *) si.si_ptr;
 
104
 
 
105
              /* Check the timer is still used and will not go away
 
106
                 while we are reading the values here.  */
 
107
              pthread_mutex_lock (&__active_timer_sigev_thread_lock);
 
108
 
 
109
              struct timer *runp = __active_timer_sigev_thread;
 
110
              while (runp != NULL)
 
111
                if (runp == tk)
 
112
                  break;
 
113
                else
 
114
                  runp = runp->next;
 
115
 
 
116
              if (runp != NULL)
 
117
                {
 
118
                  struct thread_start_data *td = malloc (sizeof (*td));
 
119
 
 
120
                  /* There is not much we can do if the allocation fails.  */
 
121
                  if (td != NULL)
 
122
                    {
 
123
                      /* This is the signal we are waiting for.  */
 
124
                      td->thrfunc = tk->thrfunc;
 
125
                      td->sival = tk->sival;
 
126
 
 
127
                      pthread_t th;
 
128
                      (void) pthread_create (&th, &tk->attr,
 
129
                                             timer_sigev_thread, td);
 
130
                    }
 
131
                }
 
132
 
 
133
              pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
 
134
            }
 
135
          else if (si.si_code == SI_TKILL)
 
136
            /* The thread is canceled.  */
 
137
            pthread_exit (NULL);
 
138
        }
 
139
    }
 
140
}
 
141
 
 
142
 
 
143
/* Control variable for helper thread creation.  */
 
144
pthread_once_t __helper_once attribute_hidden;
 
145
 
 
146
 
 
147
/* TID of the helper thread.  */
 
148
pid_t __helper_tid attribute_hidden;
 
149
 
 
150
 
 
151
/* Reset variables so that after a fork a new helper thread gets started.  */
 
152
static void
 
153
reset_helper_control (void)
 
154
{
 
155
  __helper_once = PTHREAD_ONCE_INIT;
 
156
  __helper_tid = 0;
 
157
}
 
158
 
 
159
 
 
160
void
 
161
attribute_hidden
 
162
__start_helper_thread (void)
 
163
{
 
164
  /* The helper thread needs only very little resources
 
165
     and should go away automatically when canceled.  */
 
166
  pthread_attr_t attr;
 
167
  (void) pthread_attr_init (&attr);
 
168
  (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
 
169
 
 
170
  /* Block all signals in the helper thread but SIGSETXID.  To do this
 
171
     thoroughly we temporarily have to block all signals here.  The
 
172
     helper can lose wakeups if SIGCANCEL is not blocked throughout,
 
173
     but sigfillset omits it SIGSETXID.  So, we add SIGCANCEL back
 
174
     explicitly here.  */
 
175
  sigset_t ss;
 
176
  sigset_t oss;
 
177
  sigfillset (&ss);
 
178
  /*__sigaddset (&ss, SIGCANCEL); - already done by sigfillset */
 
179
  INTERNAL_SYSCALL_DECL (err);
 
180
  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8);
 
181
 
 
182
  /* Create the helper thread for this timer.  */
 
183
  pthread_t th;
 
184
  int res = pthread_create (&th, &attr, timer_helper_thread, NULL);
 
185
  if (res == 0)
 
186
    /* We managed to start the helper thread.  */
 
187
    __helper_tid = ((struct pthread *) th)->tid;
 
188
 
 
189
  /* Restore the signal mask.  */
 
190
  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL,
 
191
                    _NSIG / 8);
 
192
 
 
193
  /* No need for the attribute anymore.  */
 
194
  (void) pthread_attr_destroy (&attr);
 
195
 
 
196
  /* We have to make sure that after fork()ing a new helper thread can
 
197
     be created.  */
 
198
  pthread_atfork (NULL, NULL, reset_helper_control);
 
199
}
 
200
#endif
 
201
 
 
202
#ifndef __ASSUME_POSIX_TIMERS
 
203
# include <nptl/sysdeps/pthread/timer_routines.c>
 
204
#endif