about summary refs log tree commit diff
path: root/sysdeps/hurd/include/hurd/signal.h
blob: fab8d1b67c2b87361791903199c673fe55f92193 (plain) (blame)
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
92
93
94
95
96
97
98
99
100
101
102
103
extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates.  */

#ifndef	_HURD_SIGNAL_H
extern struct hurd_sigstate *_hurd_self_sigstate (void) __attribute__ ((__const__));
#ifndef _ISOMAC
libc_hidden_proto (_hurd_self_sigstate)
#endif

#include_next <hurd/signal.h>

#ifndef _ISOMAC

#if defined __USE_EXTERN_INLINES
# if IS_IN (libc) || IS_IN (libpthread)
#  include <sigsetops.h>
#  include <tls.h>
# endif
#endif

#ifndef _HURD_SIGNAL_H_EXTERN_INLINE
#define _HURD_SIGNAL_H_EXTERN_INLINE __extern_inline
#endif

#if defined __USE_EXTERN_INLINES && IS_IN (libc)
_HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate *
_hurd_self_sigstate (void)
{
  struct hurd_sigstate *ss = THREAD_GETMEM (THREAD_SELF, _hurd_sigstate);
  if (__glibc_unlikely (ss == NULL))
    {
      thread_t self = __mach_thread_self ();

      /* The thread variable is unset; this must be the first time we've
        asked for it.  In this case, the critical section flag cannot
        possible already be set.  Look up our sigstate structure the slow
        way.  */
      ss = _hurd_thread_sigstate (self);
      THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, ss);
      __mach_port_deallocate (__mach_task_self (), self);
    }
  return ss;
}

_HURD_SIGNAL_H_EXTERN_INLINE void *
_hurd_critical_section_lock (void)
{
  struct hurd_sigstate *ss;

  if (__LIBC_NO_TLS ())
    /* TLS is currently initializing, no need to enter critical section.  */
    return NULL;

  ss = _hurd_self_sigstate ();

  if (! __spin_try_lock (&ss->critical_section_lock))
    /* We are already in a critical section, so do nothing.  */
    return NULL;

  /* With the critical section lock held no signal handler will run.
     Return our sigstate pointer; this will be passed to
     _hurd_critical_section_unlock to unlock it.  */
  return ss;
}

_HURD_SIGNAL_H_EXTERN_INLINE void
_hurd_critical_section_unlock (void *our_lock)
{
  if (our_lock == NULL)
    /* The critical section lock was held when we began.  Do nothing.  */
    return;
  else
    {
      /* It was us who acquired the critical section lock.  Unlock it.  */
      struct hurd_sigstate *ss = (struct hurd_sigstate *) our_lock;
      sigset_t pending;
      _hurd_sigstate_lock (ss);
      __spin_unlock (&ss->critical_section_lock);
      pending = _hurd_sigstate_pending (ss) & ~ss->blocked;
      _hurd_sigstate_unlock (ss);
      if (__glibc_unlikely (!__sigisemptyset (&pending)))
	/* There are unblocked signals pending, which weren't
	   delivered because we were in the critical section.
	   Tell the signal thread to deliver them now.  */
	__msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
    }
}
#endif /* defined __USE_EXTERN_INLINES && IS_IN (libc) */


libc_hidden_proto (_hurd_exception2signal)
libc_hidden_proto (_hurd_intr_rpc_mach_msg)
libc_hidden_proto (_hurd_thread_sigstate)
libc_hidden_proto (_hurd_raise_signal)
libc_hidden_proto (_hurd_sigstate_set_global_rcv)
libc_hidden_proto (_hurd_sigstate_lock)
libc_hidden_proto (_hurd_sigstate_pending)
libc_hidden_proto (_hurd_sigstate_unlock)
libc_hidden_proto (_hurd_sigstate_delete)
#endif
#ifdef _HURD_SIGNAL_H_HIDDEN_DEF
libc_hidden_def (_hurd_self_sigstate)
#endif
#endif