1 /* File descriptors managment and switching */
9 #include <string.h> /* FreeBSD FD_ZERO() macro calls bzero() */
10 #ifdef HAVE_SYS_SIGNAL_H
11 #include <sys/signal.h>
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_WAIT_H
21 /* This must be here, thanks to BSD. */
22 #ifdef HAVE_INTTYPES_H
23 #include <inttypes.h> /* OMG */
25 #ifdef HAVE_SYS_SELECT_H
26 #include <sys/select.h>
31 #include "intl/gettext/libintl.h"
32 #include "main/main.h"
33 #include "main/select.h"
34 #include "main/timer.h"
35 #include "osdep/signals.h"
36 #include "terminal/terminal.h"
37 #include "util/error.h"
38 #include "util/memory.h"
39 #include "util/time.h"
43 #define FD_SETSIZE 1024
47 select_handler_T read_func
;
48 select_handler_T write_func
;
49 select_handler_T error_func
;
53 static struct thread threads
[FD_SETSIZE
];
56 static fd_set w_write
;
57 static fd_set w_error
;
60 static fd_set x_write
;
61 static fd_set x_error
;
66 get_file_handles_count(void)
70 for (j
= 0; j
< FD_SETSIZE
; j
++)
71 if (threads
[j
].read_func
72 || threads
[j
].write_func
73 || threads
[j
].error_func
)
79 LIST_HEAD(struct bottom_half
);
85 static INIT_LIST_HEAD(bottom_halves
);
88 register_bottom_half_do(select_handler_T fn
, void *data
)
90 struct bottom_half
*bh
;
92 foreach (bh
, bottom_halves
)
93 if (bh
->fn
== fn
&& bh
->data
== data
)
96 bh
= mem_alloc(sizeof(*bh
));
100 add_to_list(bottom_halves
, bh
);
106 check_bottom_halves(void)
108 while (!list_empty(bottom_halves
)) {
109 struct bottom_half
*bh
= bottom_halves
.prev
;
110 select_handler_T fn
= bh
->fn
;
111 void *data
= bh
->data
;
120 get_handler(int fd
, enum select_handler_type tp
)
122 #ifndef CONFIG_OS_WIN32
123 assertm(fd
>= 0 && fd
< FD_SETSIZE
,
124 "get_handler: handle %d >= FD_SETSIZE %d",
126 if_assert_failed
return NULL
;
129 case SELECT_HANDLER_READ
: return threads
[fd
].read_func
;
130 case SELECT_HANDLER_WRITE
: return threads
[fd
].write_func
;
131 case SELECT_HANDLER_ERROR
: return threads
[fd
].error_func
;
132 case SELECT_HANDLER_DATA
: return threads
[fd
].data
;
135 INTERNAL("get_handler: bad type %d", tp
);
140 set_handlers(int fd
, select_handler_T read_func
, select_handler_T write_func
,
141 select_handler_T error_func
, void *data
)
143 #ifndef CONFIG_OS_WIN32
144 assertm(fd
>= 0 && fd
< FD_SETSIZE
,
145 "set_handlers: handle %d >= FD_SETSIZE %d",
147 if_assert_failed
return;
149 threads
[fd
].read_func
= read_func
;
150 threads
[fd
].write_func
= write_func
;
151 threads
[fd
].error_func
= error_func
;
152 threads
[fd
].data
= data
;
162 FD_SET(fd
, &w_write
);
164 FD_CLR(fd
, &w_write
);
165 FD_CLR(fd
, &x_write
);
169 FD_SET(fd
, &w_error
);
171 FD_CLR(fd
, &w_error
);
172 FD_CLR(fd
, &x_error
);
175 if (read_func
|| write_func
|| error_func
) {
176 if (fd
>= w_max
) w_max
= fd
+ 1;
177 } else if (fd
== w_max
- 1) {
180 for (i
= fd
- 1; i
>= 0; i
--)
181 if (FD_ISSET(i
, &w_read
)
182 || FD_ISSET(i
, &w_write
)
183 || FD_ISSET(i
, &w_error
))
190 select_loop(void (*init
)(void))
193 int select_errors
= 0;
195 clear_signal_mask_and_handlers();
200 timeval_now(&last_time
);
202 signal(SIGPIPE
, SIG_IGN
);
205 check_bottom_halves();
207 while (!program
.terminate
) {
208 struct timeval
*timeout
= NULL
;
213 check_timers(&last_time
);
214 redraw_all_terminals();
216 memcpy(&x_read
, &w_read
, sizeof(fd_set
));
217 memcpy(&x_write
, &w_write
, sizeof(fd_set
));
218 memcpy(&x_error
, &w_error
, sizeof(fd_set
));
220 if (program
.terminate
) break;
222 has_timer
= get_next_timer_time(&t
);
223 if (!w_max
&& !has_timer
) break;
224 critical_section
= 1;
226 if (check_signals()) {
227 critical_section
= 0;
235 for (i
= 0; i
< 256; i
++)
236 if (FD_ISSET(i
, &x_read
)) printf("%d,", i
);
238 for (i
= 0; i
< 256; i
++)
239 if (FD_ISSET(i
, &x_write
)) printf("%d,", i
);
241 for (i
= 0; i
< 256; i
++)
242 if (FD_ISSET(i
, &x_error
)) printf("%d,", i
);
247 /* Be sure timeout is not negative. */
248 timeval_limit_to_zero_or_one(&t
);
249 timeout
= (struct timeval
*) &t
;
252 n
= select(w_max
, &x_read
, &x_write
, &x_error
, timeout
);
254 /* The following calls (especially gettext)
255 * might change errno. */
256 const int errno_from_select
= errno
;
258 critical_section
= 0;
260 if (errno_from_select
!= EINTR
) {
261 ERROR(gettext("The call to %s failed: %d (%s)"),
262 "select()", errno_from_select
, (unsigned char *) strerror(errno_from_select
));
263 if (++select_errors
> 10) /* Infinite loop prevention. */
264 INTERNAL(gettext("%d select() failures."),
271 critical_section
= 0;
274 /*printf("sel: %d\n", n);*/
275 check_timers(&last_time
);
278 while (n
> 0 && ++i
< w_max
) {
282 printf("C %d : %d,%d,%d\n", i
, FD_ISSET(i
, &w_read
),
283 FD_ISSET(i
, &w_write
), FD_ISSET(i
, &w_error
));
284 printf("A %d : %d,%d,%d\n", i
, FD_ISSET(i
, &x_read
),
285 FD_ISSET(i
, &x_write
), FD_ISSET(i
, &x_error
));
287 if (FD_ISSET(i
, &x_read
)) {
288 if (threads
[i
].read_func
) {
289 threads
[i
].read_func(threads
[i
].data
);
290 check_bottom_halves();
295 if (FD_ISSET(i
, &x_write
)) {
296 if (threads
[i
].write_func
) {
297 threads
[i
].write_func(threads
[i
].data
);
298 check_bottom_halves();
303 if (FD_ISSET(i
, &x_error
)) {
304 if (threads
[i
].error_func
) {
305 threads
[i
].error_func(threads
[i
].data
);
306 check_bottom_halves();
317 can_read_or_write(int fd
, int write
)
319 struct timeval tv
= {0, 0};
332 return select(fd
+ 1, rfds
, wfds
, NULL
, &tv
);
338 return can_read_or_write(fd
, 0);
344 return can_read_or_write(fd
, 1);