-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsig_interrupt.c
165 lines (145 loc) · 5.4 KB
/
sig_interrupt.c
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
165
/* --------------------------------------------------------------------------
* Exercise 20-4: Implement siginterrupt() using sigaction().
*
* NAME
* siginterrupt - allow signals to interrupt system calls
*
* SYNOPSIS
* #include <signal.h>
*
* int siginterrupt(int sig, int flag);
*
* Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
*
* siginterrupt():
* _XOPEN_SOURCE >= 500
* || Since glibc 2.12: _POSIX_C_SOURCE >= 200809L
* || Glibc versions <= 2.19: _BSD_SOURCE
*
* DESCRIPTION
* The siginterrupt() function changes the restart behavior when a
* system call is interrupted by the signal sig. If the flag argument
* is false (0), then system calls will be restarted if interrupted by
* the specified signal sig. This is the default behavior in Linux.
*
* If the flag argument is true (1) and no data has been transferred,
* then a system call interrupted by the signal sig will return -1 and
* errno will be set to EINTR.
*
* If the flag argument is true (1) and data transfer has started, then
* the system call will be interrupted and will return the actual amount
* of data transferred.
*
* RETURN VALUE
* The siginterrupt() function returns 0 on success. It returns -1 if
* the signal number sig is invalid, with errno set to indicate the
* cause of the error.
*
* ERRORS
* EINVAL The specified signal number is invalid.
*
* -------------------------------------------------------------------------- */
#define _GNU_SOURCE
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
/* --------------------------------------------------------------------------
* My implementation of siginterrupt
* -------------------------------------------------------------------------- */
int my_siginterrupt(int sig, int flag) {
static struct sigaction oldact;
if (sigaction(sig, NULL, &oldact) == -1) return -1;
oldact.sa_flags |= SA_RESTART;
if (flag) oldact.sa_flags ^= SA_RESTART;
return (sigaction(sig, &oldact, NULL));
}
/* --------------------------------------------------------------------------
* Signal handler
* -------------------------------------------------------------------------- */
volatile sig_atomic_t sigint_received = 0;
volatile sig_atomic_t sigusr1_received = 0;
static void signal_handler(int signal) {
switch (signal) {
case SIGINT:
sigint_received = 1;
break;
case SIGUSR1:
sigusr1_received = 1;
break;
default:
break;
}
} /* signal_handler */
int main(int argc, char *argv[]) {
char *full_pgm_name = strdup(argv[0]);
if (full_pgm_name == NULL) {
fprintf(stderr,
"%s: unable to duplicate program name: %m\n",
argv[0]);
exit(EXIT_FAILURE);
}
char *pgm_name = basename(full_pgm_name);
if (pgm_name == NULL) {
fprintf(stderr,
"%s: Unable to extract base name for program: %m\n",
argv[0]);
exit(EXIT_FAILURE);
}
static struct sigaction new_signal_action;
pid_t my_pid = getpid();
printf("%s: Enable signal handler for SIGUSR1\n", pgm_name);
new_signal_action.sa_flags = 0;
sigemptyset(&new_signal_action.sa_mask);
new_signal_action.sa_handler = signal_handler;
if (sigaction(SIGUSR1, &new_signal_action, NULL) == -1) {
fprintf(stderr,
"%s: adding of signal handler (signal_handler) for signal=%d through sigaction() failed: %m",
pgm_name,
10);
exit(EXIT_FAILURE);
}
printf("%s: Send SIGUSR1 to self\n", pgm_name);
if (kill(my_pid, SIGUSR1) == -1) {
fprintf(stderr, "%s: send of SIGUSR1 to self failed: %m\n", pgm_name);
exit(EXIT_FAILURE);
}
printf("%s: signal was %sreceived.\n", pgm_name, (sigusr1_received) ? "" : "not ");
printf("%s: setting of signal handler (signal_handler) through siginterrupt(%d,0)\n",
pgm_name,
10);
if (my_siginterrupt(SIGUSR1,0) == -1) {
fprintf(stderr,
"%s: setting of signal handler (signal_handler) through siginterrupt(%d,0) failed: %m",
pgm_name,
10);
exit(EXIT_FAILURE);
}
sigusr1_received = 0;
printf("%s: Send SIGUSR1 to self\n", pgm_name);
if (kill(my_pid, SIGUSR1) == -1) {
fprintf(stderr, "%s: send of SIGUSR1 to self failed: %m\n", pgm_name);
exit(EXIT_FAILURE);
}
printf("%s: signal was %sreceived.\n", pgm_name, (sigusr1_received) ? "" : "not ");
printf("%s: setting of signal handler (signal_handler) through siginterrupt(%d,1)\n",
pgm_name,
10);
if (my_siginterrupt(SIGUSR1,1) == -1) {
fprintf(stderr,
"%s: setting of signal handler (signal_handler) through siginterrupt(%d,1) failed: %m\n",
pgm_name,
10);
exit(EXIT_FAILURE);
}
sigusr1_received = 0;
printf("%s: Send SIGUSR1 to self\n", pgm_name);
if (kill(my_pid, SIGUSR1) == -1) {
fprintf(stderr, "%s: send of SIGUSR1 to self failed: %m\n", pgm_name);
exit(EXIT_FAILURE);
}
printf("%s: signal was %sreceived.\n", pgm_name, (sigusr1_received) ? "" : "not ");
printf("%s: Exit.\n", pgm_name);
exit(EXIT_SUCCESS);
}