summaryrefslogtreecommitdiff
path: root/signal/sigwaiter.c
blob: 8d041ac165c9d52e6132986d40cf97c1e82394c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* sigwaiter.c - Signal handling functions.
   Copyright (C) 2008 Free Software Foundation, Inc.
   Written by Neal H. Walfield <neal@gnu.org>.

   This file is part of the GNU Hurd.

   The GNU Hurd is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 3 of
   the License, or (at your option) any later version.

   The GNU Hurd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this program.  If not, see
   <http://www.gnu.org/licenses/>.  */

#include "sig-internal.h"

#include <hurd/futex.h>

struct sigwaiter *sigwaiters;

siginfo_t
sigwaiter_block (struct signal_state *ss, const sigset_t *restrict set)
{
  assert (pthread_mutex_trylock (&sig_lock) == EBUSY);
  assert (pthread_mutex_trylock (&ss->lock) == EBUSY);

  assert (! ss->sigwaiter);

  struct sigwaiter waiter;

  waiter.next = sigwaiters;
  if (waiter.next)
    {
      assert (! waiter.next->prev);
      waiter.next->prev = &waiter;
    }
  waiter.prev = 0;
  sigwaiters = &waiter;

  waiter.ss = ss;
  waiter.info.si_signo = 0;
  waiter.signals = *set;

  ss->sigwaiter = &waiter;

  pthread_mutex_unlock (&ss->lock);
  pthread_mutex_unlock (&sig_lock);

  futex_wait (&waiter.info.si_signo, 0);

#ifndef NDEBUG
  pthread_mutex_lock (&ss->lock);
  ss->sigwaiter = 0;
  pthread_mutex_unlock (&ss->lock);
#endif

  assert (waiter.info.si_signo);
  return waiter.info;
}

void
sigwaiter_unblock (struct sigwaiter *waiter)
{
  assert (pthread_mutex_trylock (&sig_lock) == EBUSY);
  assert (pthread_mutex_trylock (&waiter->ss->lock) == EBUSY);

  struct sigwaiter *prev = waiter->prev;
  struct sigwaiter *next = waiter->next;

  if (next)
    next->prev = prev;

  if (prev)
    prev->next = next;
  else
    sigwaiters = next;

  sigdelset (&process_pending, waiter->info.si_signo);
  sigdelset (&waiter->ss->pending, waiter->info.si_signo);

  pthread_mutex_unlock (&waiter->ss->lock);
  pthread_mutex_unlock (&sig_lock);

  futex_wake (&waiter->info.si_signo, 1);
}