-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrt_sigio.c
More file actions
153 lines (130 loc) · 2.94 KB
/
rt_sigio.c
File metadata and controls
153 lines (130 loc) · 2.94 KB
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
/**
* Example of using the linux 'real time signal' feature with
* signal driven io.
*/
// For F_SETSIG
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define RTSIG ( SIGRTMIN )
static volatile sig_atomic_t signalled;
static struct termios *tios_reset;
static int set_cbrk() {
struct termios tios;
if (tcgetattr(STDIN_FILENO, &tios) == -1)
return -1;
tios.c_lflag ^= ~(ICANON | ECHO);
tios.c_lflag |= ISIG;
tios.c_iflag &= ~ICRNL;
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios) == -1)
return -1;
return 0;
}
static void spin() {
int i;
float f;
for(i = 0; i < 100000000; i++)
f *= 2.1;
}
static int set_nblock(int fd) {
int flags;
if ((flags = fcntl(fd, F_GETFL)) == -1)
return -1;
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
return -1;
return 0;
}
static int set_async(int fd) {
int flags;
if ((flags = fcntl(fd, F_GETFL)) == -1)
return -1;
if (fcntl(fd, F_SETOWN, getpid()) == -1)
return -1;
if (fcntl(fd, F_SETFL, flags | O_ASYNC) == -1)
return -1;
return 0;
}
static void exit_err(char *reason) {
perror(reason);
if (tios_reset != NULL)
tcsetattr(STDIN_FILENO, TCSAFLUSH, tios_reset);
exit(EXIT_FAILURE);
}
static void handle(int sig, siginfo_t *info, void *ucontext) {
char *code;
signalled = 1;
switch (info->si_code) {
case POLL_IN:
code = "POLL_IN";
break;
case POLL_OUT:
code = "POLL_OUT";
break;
case POLL_MSG:
code = "POLL_MSG";
break;
case POLL_ERR:
code = "POLL_ERR";
break;
case POLL_PRI:
code = "POLL_PRIO";
break;
case POLL_HUP:
code = "POLL_HUP";
break;
default:
code = "UNKNOWN";
}
// Not async signal safe...
printf("si_fd: %d\n", info->si_fd);
printf("si_code: %s\n", code);
}
static int setup_handler() {
struct sigaction sigact;
memset(&sigact, 0, sizeof(sigact));
sigact.sa_sigaction = handle;
sigact.sa_flags = SA_SIGINFO;
sigemptyset(&sigact.sa_mask);
return sigaction(RTSIG, &sigact, NULL);
}
int main(int argc, char **argv) {
int count;
char c;
struct termios old;
if (tcgetattr(STDIN_FILENO, &old) == -1)
exit_err("tcgetattr");
tios_reset = &old;
if (set_nblock(STDIN_FILENO) == -1)
exit_err("set stdin nonblock");
if (setup_handler() == -1)
exit_err("setup handler");
// Set this before async to avoid potentially getting a SIGINFO.
if (fcntl(STDIN_FILENO, F_SETSIG, RTSIG) == -1)
exit_err("Setup realtime signal");
if (set_async(STDIN_FILENO) == -1)
exit_err("set async");
if (set_cbrk() == -1)
exit_err("set cbreak mode");
puts("Press # to exit.");
for(count = 0, c = ' '; c != '#'; count++) {
spin();
if (signalled) {
signalled = 0;
while (read(STDIN_FILENO, &c, 1) > 0) {
printf("INPUT: %c. COUNT: %d\n", c, count);
if (c == '#')
break;
}
}
}
tcsetattr(STDIN_FILENO, TCSAFLUSH, &old);
exit(EXIT_SUCCESS);
}