~ubuntu-branches/ubuntu/trusty/eglibc/trusty

« back to all changes in this revision

Viewing changes to .pc/hurd-i386/unsubmitted-setitimer_fix.diff/sysdeps/mach/hurd/setitimer.c

  • Committer: Package Import Robot
  • Author(s): Adam Conrad
  • Date: 2013-01-10 18:39:35 UTC
  • mfrom: (1.5.2) (4.4.24 experimental)
  • Revision ID: package-import@ubuntu.com-20130110183935-afsgfxkmg7wk5eaj
Tags: 2.17-0ubuntu1
* Merge with Debian, bringing in a new upstream and many small fixes:
  - patches/any/cvs-malloc-deadlock.diff: Dropped, merged upstream.
  - patches/ubuntu/lddebug-scopes.diff: Rebase for upstream changes.
  - patches/ubuntu/local-CVE-2012-3406.diff: Rebased against upstream.
  - patches/ubuntu/no-asm-mtune-i686.diff: Fixed in recent binutils.
* This upstream merge fixes a nasty hang in pulseaudio (LP: #1085342)
* Bump MIN_KERNEL_SUPPORTED to 2.6.32 on ARM, now that we no longer
  have to support shonky 2.6.31 kernels on imx51 babbage builders.
* Drop patches/ubuntu/local-disable-nscd-host-caching.diff, as these
  issues were apparently resolved upstream a while ago (LP: #613662)
* Fix the compiled-in bug URL to point to launchpad.net, not Debian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 1994-2012 Free Software Foundation, Inc.
 
2
   This file is part of the GNU C Library.
 
3
 
 
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
 
6
   License as published by the Free Software Foundation; either
 
7
   version 2.1 of the License, or (at your option) any later version.
 
8
 
 
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.
 
13
 
 
14
   You should have received a copy of the GNU Lesser General Public
 
15
   License along with the GNU C Library; if not, see
 
16
   <http://www.gnu.org/licenses/>.  */
 
17
 
 
18
#include <stddef.h>
 
19
#include <errno.h>
 
20
#include <sys/time.h>
 
21
#include <time.h>
 
22
#include <hurd.h>
 
23
#include <hurd/signal.h>
 
24
#include <hurd/sigpreempt.h>
 
25
#include <hurd/msg_request.h>
 
26
#include <mach/message.h>
 
27
 
 
28
/* XXX Temporary cheezoid implementation of ITIMER_REAL/SIGALRM.  */
 
29
 
 
30
spin_lock_t _hurd_itimer_lock = SPIN_LOCK_INITIALIZER;
 
31
struct itimerval _hurd_itimerval; /* Current state of the timer.  */
 
32
mach_port_t _hurd_itimer_port;  /* Port the timer thread blocks on.  */
 
33
thread_t _hurd_itimer_thread;   /* Thread waiting for timeout.  */
 
34
int _hurd_itimer_thread_suspended; /* Nonzero if that thread is suspended.  */
 
35
vm_address_t _hurd_itimer_thread_stack_base; /* Base of its stack.  */
 
36
vm_address_t _hurd_itimer_thread_stack_size; /* Size of its stack.  */
 
37
struct timeval _hurd_itimer_started; /* Time the thread started waiting.  */
 
38
 
 
39
static void
 
40
quantize_timeval (struct timeval *tv)
 
41
{
 
42
  static time_t quantum = -1;
 
43
 
 
44
  if (quantum == -1)
 
45
    quantum = 1000000 / __getclktck ();
 
46
 
 
47
  tv->tv_usec = ((tv->tv_usec + (quantum - 1)) / quantum) * quantum;
 
48
  if (tv->tv_usec >= 1000000)
 
49
    {
 
50
      ++tv->tv_sec;
 
51
      tv->tv_usec -= 1000000;
 
52
    }
 
53
}
 
54
 
 
55
static inline void
 
56
subtract_timeval (struct timeval *from, const struct timeval *subtract)
 
57
{
 
58
  from->tv_usec -= subtract->tv_usec;
 
59
  from->tv_sec -= subtract->tv_sec;
 
60
  while (from->tv_usec < 0)
 
61
    {
 
62
      --from->tv_sec;
 
63
      from->tv_usec += 1000000;
 
64
    }
 
65
}
 
66
 
 
67
/* Function run by the itimer thread.
 
68
   This code must be very careful not ever to require a MiG reply port.  */
 
69
 
 
70
static void
 
71
timer_thread (void)
 
72
{
 
73
  while (1)
 
74
    {
 
75
      error_t err;
 
76
      /* The only message we ever expect to receive is the reply from the
 
77
         signal thread to a sig_post call we did.  We never examine the
 
78
         contents.  */
 
79
      struct
 
80
        {
 
81
          mach_msg_header_t header;
 
82
          error_t return_code;
 
83
        } msg;
 
84
 
 
85
      /* Wait for a message on a port that noone sends to.  The purpose is
 
86
         the receive timeout.  Notice interrupts so that if we are
 
87
         thread_abort'd, we will loop around and fetch new values from
 
88
         _hurd_itimerval.  */
 
89
      err = __mach_msg (&msg.header,
 
90
                        MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT,
 
91
                        0, 0, _hurd_itimer_port,
 
92
                        _hurd_itimerval.it_value.tv_sec * 1000 +
 
93
                        _hurd_itimerval.it_value.tv_usec / 1000,
 
94
                        MACH_PORT_NULL);
 
95
      switch (err)
 
96
        {
 
97
        case MACH_RCV_TIMED_OUT:
 
98
          /* We got the expected timeout.  Send a message to the signal
 
99
             thread to tell it to post a SIGALRM signal.  We use
 
100
             _hurd_itimer_port as the reply port just so we will block until
 
101
             the signal thread has frobnicated things to reload the itimer or
 
102
             has terminated this thread.  */
 
103
          __msg_sig_post_request (_hurd_msgport,
 
104
                                  _hurd_itimer_port,
 
105
                                  MACH_MSG_TYPE_MAKE_SEND_ONCE,
 
106
                                  SIGALRM, SI_TIMER, __mach_task_self ());
 
107
          break;
 
108
 
 
109
        case MACH_RCV_INTERRUPTED:
 
110
          /* We were thread_abort'd.  This is to tell us that
 
111
             _hurd_itimerval has changed and we need to reexamine it
 
112
             and start waiting with the new timeout value.  */
 
113
          break;
 
114
 
 
115
        case MACH_MSG_SUCCESS:
 
116
          /* We got the reply message from the sig_post_request above.
 
117
             Ignore it and reexamine the timer value.  */
 
118
          __mach_msg_destroy (&msg.header); /* Just in case.  */
 
119
          break;
 
120
 
 
121
        default:
 
122
          /* Unexpected lossage.  Oh well, keep trying.  */
 
123
          break;
 
124
        }
 
125
    }
 
126
}
 
127
 
 
128
 
 
129
/* Forward declaration.  */
 
130
static int setitimer_locked (const struct itimerval *new,
 
131
                             struct itimerval *old, void *crit);
 
132
 
 
133
static sighandler_t
 
134
restart_itimer (struct hurd_signal_preemptor *preemptor,
 
135
                struct hurd_sigstate *ss,
 
136
                int *signo, struct hurd_signal_detail *detail)
 
137
{
 
138
  /* This function gets called in the signal thread
 
139
     each time a SIGALRM is arriving (even if blocked).  */
 
140
  struct itimerval it;
 
141
 
 
142
  /* Either reload or disable the itimer.  */
 
143
  __spin_lock (&_hurd_itimer_lock);
 
144
  it.it_value = it.it_interval = _hurd_itimerval.it_interval;
 
145
  setitimer_locked (&it, NULL, NULL);
 
146
 
 
147
  /* Continue with normal delivery (or hold, etc.) of SIGALRM.  */
 
148
  return SIG_ERR;
 
149
}
 
150
 
 
151
 
 
152
/* Called before any normal SIGALRM signal is delivered.
 
153
   Reload the itimer, or disable the itimer.  */
 
154
 
 
155
static int
 
156
setitimer_locked (const struct itimerval *new, struct itimerval *old,
 
157
                  void *crit)
 
158
{
 
159
  struct itimerval newval;
 
160
  struct timeval now, remaining, elapsed;
 
161
  struct timeval old_interval;
 
162
  error_t err;
 
163
 
 
164
  inline void kill_itimer_thread (void)
 
165
    {
 
166
      __thread_terminate (_hurd_itimer_thread);
 
167
      __vm_deallocate (__mach_task_self (),
 
168
                       _hurd_itimer_thread_stack_base,
 
169
                       _hurd_itimer_thread_stack_size);
 
170
      _hurd_itimer_thread = MACH_PORT_NULL;
 
171
    }
 
172
 
 
173
  if (!new)
 
174
    {
 
175
      /* Just return the current value in OLD without changing anything.
 
176
         This is what BSD does, even though it's not documented. */
 
177
      if (old)
 
178
        *old = _hurd_itimerval;
 
179
      spin_unlock (&_hurd_itimer_lock);
 
180
      _hurd_critical_section_unlock (crit);
 
181
      return 0;
 
182
    }
 
183
 
 
184
  newval = *new;
 
185
  quantize_timeval (&newval.it_interval);
 
186
  quantize_timeval (&newval.it_value);
 
187
  if ((newval.it_value.tv_sec | newval.it_value.tv_usec) != 0)
 
188
    {
 
189
      /* Make sure the itimer thread is set up.  */
 
190
 
 
191
      /* Set up a signal preemptor global for all threads to
 
192
         run `restart_itimer' each time a SIGALRM would arrive.  */
 
193
      static struct hurd_signal_preemptor preemptor =
 
194
        {
 
195
          __sigmask (SIGALRM), 0, 0,
 
196
          &restart_itimer,
 
197
        };
 
198
      __mutex_lock (&_hurd_siglock);
 
199
      if (! preemptor.next && _hurdsig_preemptors != &preemptor)
 
200
        {
 
201
          preemptor.next = _hurdsig_preemptors;
 
202
          _hurdsig_preemptors = &preemptor;
 
203
        }
 
204
      __mutex_unlock (&_hurd_siglock);
 
205
 
 
206
      if (_hurd_itimer_port == MACH_PORT_NULL)
 
207
        {
 
208
          /* Allocate a receive right that the itimer thread will
 
209
             block waiting for a message on.  */
 
210
          if (err = __mach_port_allocate (__mach_task_self (),
 
211
                                          MACH_PORT_RIGHT_RECEIVE,
 
212
                                          &_hurd_itimer_port))
 
213
            goto out;
 
214
        }
 
215
 
 
216
      if (_hurd_itimer_thread == MACH_PORT_NULL)
 
217
        {
 
218
          /* Start up the itimer thread running `timer_thread' (below).  */
 
219
          if (err = __thread_create (__mach_task_self (),
 
220
                                     &_hurd_itimer_thread))
 
221
            goto out;
 
222
          _hurd_itimer_thread_stack_base = 0; /* Anywhere.  */
 
223
          _hurd_itimer_thread_stack_size = __vm_page_size; /* Small stack.  */
 
224
          if ((err = __mach_setup_thread (__mach_task_self (),
 
225
                                         _hurd_itimer_thread,
 
226
                                         &timer_thread,
 
227
                                         &_hurd_itimer_thread_stack_base,
 
228
                                         &_hurd_itimer_thread_stack_size))
 
229
              || (err = __mach_setup_tls(_hurd_itimer_thread)))
 
230
            {
 
231
              __thread_terminate (_hurd_itimer_thread);
 
232
              _hurd_itimer_thread = MACH_PORT_NULL;
 
233
              goto out;
 
234
            }
 
235
          _hurd_itimer_thread_suspended = 1;
 
236
        }
 
237
    }
 
238
 
 
239
  if ((newval.it_value.tv_sec | newval.it_value.tv_usec) != 0 || old != NULL)
 
240
    {
 
241
      /* Calculate how much time is remaining for the pending alarm.  */
 
242
      if (__gettimeofday (&now, NULL) < 0)
 
243
        {
 
244
          __spin_unlock (&_hurd_itimer_lock);
 
245
          _hurd_critical_section_unlock (crit);
 
246
          return -1;
 
247
        }
 
248
      elapsed = now;
 
249
      subtract_timeval (&elapsed, &_hurd_itimer_started);
 
250
      remaining = _hurd_itimerval.it_value;
 
251
      if (timercmp (&remaining, &elapsed, <))
 
252
        {
 
253
          /* Hmm.  The timer should have just gone off, but has not been reset.
 
254
             This is a possible timing glitch.  The alarm will signal soon. */
 
255
          /* XXX wrong */
 
256
          remaining.tv_sec = 0;
 
257
          remaining.tv_usec = 0;
 
258
        }
 
259
      else
 
260
        subtract_timeval (&remaining, &elapsed);
 
261
 
 
262
      /* Remember the old reload interval before changing it.  */
 
263
      old_interval = _hurd_itimerval.it_interval;
 
264
 
 
265
      /* Record the starting time that the timer interval relates to.  */
 
266
      _hurd_itimer_started = now;
 
267
    }
 
268
 
 
269
  /* Load the new itimer value.  */
 
270
  _hurd_itimerval = newval;
 
271
 
 
272
  if ((newval.it_value.tv_sec | newval.it_value.tv_usec) == 0)
 
273
    {
 
274
      /* Disable the itimer.  */
 
275
      if (_hurd_itimer_thread && !_hurd_itimer_thread_suspended)
 
276
        {
 
277
          /* Suspend the itimer thread so it does nothing.  Then abort its
 
278
             kernel context so that when the thread is resumed, mach_msg
 
279
             will return to timer_thread (below) and it will fetch new
 
280
             values from _hurd_itimerval.  */
 
281
          if ((err = __thread_suspend (_hurd_itimer_thread)) ||
 
282
              (err = __thread_abort (_hurd_itimer_thread)))
 
283
            /* If we can't save it for later, nuke it.  */
 
284
            kill_itimer_thread ();
 
285
          else
 
286
            _hurd_itimer_thread_suspended = 1;
 
287
        }
 
288
    }
 
289
  /* See if the timeout changed.  If so, we must alert the itimer thread.  */
 
290
  else if (remaining.tv_sec != newval.it_value.tv_sec ||
 
291
           remaining.tv_usec != newval.it_value.tv_usec)
 
292
    {
 
293
      /* The timeout value is changing.  Tell the itimer thread to
 
294
         reexamine it and start counting down.  If the itimer thread is
 
295
         marked as suspended, either we just created it, or it was
 
296
         suspended and thread_abort'd last time the itimer was disabled;
 
297
         either way it will wake up and start waiting for the new timeout
 
298
         value when we resume it.  If it is not suspended, the itimer
 
299
         thread is waiting to deliver a pending alarm that we will override
 
300
         (since it would come later than the new alarm being set);
 
301
         thread_abort will make mach_msg return MACH_RCV_INTERRUPTED, so it
 
302
         will loop around and use the new timeout value.  */
 
303
      if (err = (_hurd_itimer_thread_suspended
 
304
                 ? __thread_resume : __thread_abort) (_hurd_itimer_thread))
 
305
        {
 
306
          kill_itimer_thread ();
 
307
          goto out;
 
308
        }
 
309
      _hurd_itimer_thread_suspended = 0;
 
310
    }
 
311
 
 
312
  __spin_unlock (&_hurd_itimer_lock);
 
313
  _hurd_critical_section_unlock (crit);
 
314
 
 
315
  if (old != NULL)
 
316
    {
 
317
      old->it_value = remaining;
 
318
      old->it_interval = old_interval;
 
319
    }
 
320
  return 0;
 
321
 
 
322
 out:
 
323
  __spin_unlock (&_hurd_itimer_lock);
 
324
  _hurd_critical_section_unlock (crit);
 
325
  return __hurd_fail (err);
 
326
}
 
327
 
 
328
/* Set the timer WHICH to *NEW.  If OLD is not NULL,
 
329
   set *OLD to the old value of timer WHICH.
 
330
   Returns 0 on success, -1 on errors.  */
 
331
int
 
332
__setitimer (enum __itimer_which which, const struct itimerval *new,
 
333
             struct itimerval *old)
 
334
{
 
335
  void *crit;
 
336
 
 
337
  switch (which)
 
338
    {
 
339
    default:
 
340
      return __hurd_fail (EINVAL);
 
341
 
 
342
    case ITIMER_VIRTUAL:
 
343
    case ITIMER_PROF:
 
344
      return __hurd_fail (ENOSYS);
 
345
 
 
346
    case ITIMER_REAL:
 
347
      break;
 
348
    }
 
349
 
 
350
  crit = _hurd_critical_section_lock ();
 
351
  __spin_lock (&_hurd_itimer_lock);
 
352
  return setitimer_locked (new, old, crit);
 
353
}
 
354
 
 
355
static void
 
356
fork_itimer (void)
 
357
{
 
358
  /* We must restart the itimer in the child.  */
 
359
 
 
360
  struct itimerval it;
 
361
 
 
362
  __spin_lock (&_hurd_itimer_lock);
 
363
  _hurd_itimer_thread = MACH_PORT_NULL;
 
364
  it = _hurd_itimerval;
 
365
  it.it_value = it.it_interval;
 
366
 
 
367
  setitimer_locked (&it, NULL, NULL);
 
368
 
 
369
  (void) &fork_itimer;          /* Avoid gcc optimizing out the function.  */
 
370
}
 
371
text_set_element (_hurd_fork_child_hook, fork_itimer);
 
372
 
 
373
weak_alias (__setitimer, setitimer)