File: npth-sigev.c

package info (click to toggle)
npth 0.90-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,628 kB
  • sloc: sh: 11,457; ansic: 2,013; makefile: 126
file content (164 lines) | stat: -rw-r--r-- 4,650 bytes parent folder | download
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* npth.h - a lightweight implementation of pth over pthread.

   This file is part of NPTH.

   NPTH is free software; you can redistribute it and/or modify it
   under the terms of either

   - 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.

   or
   
   - the GNU General Public License as published by the Free
   Software Foundation; either version 2 of the License, or (at
   your option) any later version.
    
   or both in parallel, as here.
 
   NPTH 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 General Public
   License for more details.

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

/* This is a support interface to make it easier to handle signals.

   The interfaces here support one (and only one) thread (here called
   "main thread") in the application to monitor several signals while
   selecting on filedescriptors.

   First, the main thread should call npth_sigev_init.  This
   initializes some global data structures used to record interesting
   and pending signals.

   Then, the main thread should call npth_sigev_add for every signal
   it is interested in observing, and finally npth_sigev_fini.  This
   will block the signal in the main threads sigmask.  Note that these
   signals should also be blocked in all other threads.  Since they
   are blocked in the main thread after calling npth_sigev_add, it is
   recommended to call npth_sigev_add in the main thread before
   creating any threads.

   The function npth_sigev_sigmask is a convenient function that
   returns the sigmask of the thread at time of npth_sigev_init, but
   with all registered signals unblocked.  It is recommended to do all
   other changes to the main thread's sigmask before calling
   npth_sigev_init, so that the return value of npth_sigev_sigmask can
   be used in the npth_pselect invocation.

   In any case, the main thread should invoke npth_pselect with a
   sigmask that has all signals that should be monitored unblocked.

   After npth_pselect returns, npth_sigev_get_pending can be called in
   a loop until it returns 0 to iterate over the list of pending
   signals.  Each time a signal is returned by that function, its
   status is reset to non-pending.  */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <signal.h>
#include <assert.h>

#include "npth.h"

/* Record events that have been noticed.  */
static sigset_t sigev_pending;

/* The signal mask during normal operation.  */
static sigset_t sigev_block;

/* The signal mask during pselect.  */
static sigset_t sigev_unblock;

/* Registered signal numbers.  Needed to iterate over sigset_t.
   Bah.  */
#define SIGEV_MAX 32
static int sigev_signum[SIGEV_MAX];
static int sigev_signum_cnt;

/* The internal handler which just sets a global flag.  */
static void
_sigev_handler (int signum)
{
  sigaddset (&sigev_pending, signum);
}


/* Start setting up signal event handling.  */
void
npth_sigev_init (void)
{
  sigemptyset (&sigev_pending);
  pthread_sigmask (SIG_SETMASK, NULL, &sigev_block);
  pthread_sigmask (SIG_SETMASK, NULL, &sigev_unblock);
}


/* Add signal SIGNUM to the list of watched signals.  */
void
npth_sigev_add (int signum)
{
  struct sigaction sa;
  sigset_t ss;

  sigemptyset(&ss);

  assert (sigev_signum_cnt < SIGEV_MAX);
  sigev_signum[sigev_signum_cnt++] = signum;

  /* Make sure we can receive it.  */
  sigdelset (&sigev_unblock, signum);
  sigaddset (&sigev_block, signum);

  sa.sa_handler = _sigev_handler;
  sa.sa_mask = ss;
  sa.sa_flags = 0; /* NOT setting SA_RESTART! */

  sigaction (signum, &sa, NULL);
}


/* Finish the list of watched signals.  This starts to block them,
   too.  */
void
npth_sigev_fini (void)
{
  /* Block the interesting signals.  */
  pthread_sigmask (SIG_SETMASK, &sigev_block, NULL);
}


/* Get the sigmask as needed for pselect.  */
sigset_t *
npth_sigev_sigmask (void)
{
  return &sigev_unblock;
}


/* Return the next signal event that occured.  Returns if none are
   left, 1 on success.  */
int
npth_sigev_get_pending (int *r_signum)
{
  int i;
  for (i = 0; i < sigev_signum_cnt; i++)
    {
      int signum = sigev_signum[i];
      if (sigismember (&sigev_pending, signum))
	{
	  sigdelset (&sigev_pending, signum);
	  *r_signum = signum;
	  return 1;
	}
    }
  return 0;
}