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 #ifdef __GNU__ /* For GNU Hurd bug workaround in set_handlers() */
14 #include <sys/stat.h> /* OS/2 needs this after sys/types.h */
16 #include <sys/types.h>
17 #ifdef HAVE_SYS_WAIT_H
24 /* This must be here, thanks to BSD. */
25 #ifdef HAVE_INTTYPES_H
26 #include <inttypes.h> /* OMG */
28 #ifdef HAVE_SYS_SELECT_H
29 #include <sys/select.h>
34 #include "intl/gettext/libintl.h"
35 #include "main/main.h"
36 #include "main/select.h"
37 #include "main/timer.h"
38 #include "osdep/signals.h"
39 #include "terminal/terminal.h"
40 #include "util/error.h"
41 #include "util/memory.h"
42 #include "util/time.h"
46 #define FD_SETSIZE 1024
50 select_handler_T read_func
;
51 select_handler_T write_func
;
52 select_handler_T error_func
;
56 #ifdef CONFIG_OS_WIN32
57 /* CreatePipe produces big numbers for handles */
59 #define FD_SETSIZE 4096
62 static struct thread threads
[FD_SETSIZE
];
65 static fd_set w_write
;
66 static fd_set w_error
;
69 static fd_set x_write
;
70 static fd_set x_error
;
75 get_file_handles_count(void)
79 for (j
= 0; j
< FD_SETSIZE
; j
++)
80 if (threads
[j
].read_func
81 || threads
[j
].write_func
82 || threads
[j
].error_func
)
88 LIST_HEAD(struct bottom_half
);
94 static INIT_LIST_OF(struct bottom_half
, bottom_halves
);
97 register_bottom_half_do(select_handler_T fn
, void *data
)
99 struct bottom_half
*bh
;
101 foreach (bh
, bottom_halves
)
102 if (bh
->fn
== fn
&& bh
->data
== data
)
105 bh
= mem_alloc(sizeof(*bh
));
109 add_to_list(bottom_halves
, bh
);
115 check_bottom_halves(void)
117 while (!list_empty(bottom_halves
)) {
118 struct bottom_half
*bh
= bottom_halves
.prev
;
119 select_handler_T fn
= bh
->fn
;
120 void *data
= bh
->data
;
129 get_handler(int fd
, enum select_handler_type tp
)
131 #ifndef CONFIG_OS_WIN32
132 assertm(fd
>= 0 && fd
< FD_SETSIZE
,
133 "get_handler: handle %d >= FD_SETSIZE %d",
135 if_assert_failed
return NULL
;
138 case SELECT_HANDLER_READ
: return threads
[fd
].read_func
;
139 case SELECT_HANDLER_WRITE
: return threads
[fd
].write_func
;
140 case SELECT_HANDLER_ERROR
: return threads
[fd
].error_func
;
141 case SELECT_HANDLER_DATA
: return threads
[fd
].data
;
144 INTERNAL("get_handler: bad type %d", tp
);
149 set_handlers(int fd
, select_handler_T read_func
, select_handler_T write_func
,
150 select_handler_T error_func
, void *data
)
152 #ifndef CONFIG_OS_WIN32
153 assertm(fd
>= 0 && fd
< FD_SETSIZE
,
154 "set_handlers: handle %d >= FD_SETSIZE %d",
156 if_assert_failed
return;
159 /* GNU Hurd pflocal bug <http://savannah.gnu.org/bugs/?22861>:
160 * If ELinks does a select() where the initial exceptfds set
161 * includes a pipe that is not listed in the other fd_sets,
162 * then select() always reports an exception there. That
163 * makes Elinks think the pipe has failed and close it.
164 * To work around this bug, do not monitor exceptions for
165 * pipes on the Hurd. */
169 if (fstat(fd
, &st
) == 0 && S_ISFIFO(st
.st_mode
))
173 threads
[fd
].read_func
= read_func
;
174 threads
[fd
].write_func
= write_func
;
175 threads
[fd
].error_func
= error_func
;
176 threads
[fd
].data
= data
;
186 FD_SET(fd
, &w_write
);
188 FD_CLR(fd
, &w_write
);
189 FD_CLR(fd
, &x_write
);
193 FD_SET(fd
, &w_error
);
195 FD_CLR(fd
, &w_error
);
196 FD_CLR(fd
, &x_error
);
199 if (read_func
|| write_func
|| error_func
) {
200 if (fd
>= w_max
) w_max
= fd
+ 1;
201 } else if (fd
== w_max
- 1) {
204 for (i
= fd
- 1; i
>= 0; i
--)
205 if (FD_ISSET(i
, &w_read
)
206 || FD_ISSET(i
, &w_write
)
207 || FD_ISSET(i
, &w_error
))
214 select_loop(void (*init
)(void))
217 int select_errors
= 0;
219 clear_signal_mask_and_handlers();
224 timeval_now(&last_time
);
226 signal(SIGPIPE
, SIG_IGN
);
229 check_bottom_halves();
231 while (!program
.terminate
) {
232 struct timeval
*timeout
= NULL
;
237 check_timers(&last_time
);
238 redraw_all_terminals();
240 memcpy(&x_read
, &w_read
, sizeof(fd_set
));
241 memcpy(&x_write
, &w_write
, sizeof(fd_set
));
242 memcpy(&x_error
, &w_error
, sizeof(fd_set
));
244 if (program
.terminate
) break;
246 has_timer
= get_next_timer_time(&t
);
247 if (!w_max
&& !has_timer
) break;
248 critical_section
= 1;
250 if (check_signals()) {
251 critical_section
= 0;
259 for (i
= 0; i
< 256; i
++)
260 if (FD_ISSET(i
, &x_read
)) printf("%d,", i
);
262 for (i
= 0; i
< 256; i
++)
263 if (FD_ISSET(i
, &x_write
)) printf("%d,", i
);
265 for (i
= 0; i
< 256; i
++)
266 if (FD_ISSET(i
, &x_error
)) printf("%d,", i
);
271 /* Be sure timeout is not negative. */
272 timeval_limit_to_zero_or_one(&t
);
273 timeout
= (struct timeval
*) &t
;
276 n
= select(w_max
, &x_read
, &x_write
, &x_error
, timeout
);
278 /* The following calls (especially gettext)
279 * might change errno. */
280 const int errno_from_select
= errno
;
282 critical_section
= 0;
284 if (errno_from_select
!= EINTR
) {
285 ERROR(gettext("The call to %s failed: %d (%s)"),
286 "select()", errno_from_select
, (unsigned char *) strerror(errno_from_select
));
287 if (++select_errors
> 10) /* Infinite loop prevention. */
288 INTERNAL(gettext("%d select() failures."),
295 critical_section
= 0;
298 /*printf("sel: %d\n", n);*/
299 check_timers(&last_time
);
302 while (n
> 0 && ++i
< w_max
) {
306 printf("C %d : %d,%d,%d\n", i
, FD_ISSET(i
, &w_read
),
307 FD_ISSET(i
, &w_write
), FD_ISSET(i
, &w_error
));
308 printf("A %d : %d,%d,%d\n", i
, FD_ISSET(i
, &x_read
),
309 FD_ISSET(i
, &x_write
), FD_ISSET(i
, &x_error
));
311 if (FD_ISSET(i
, &x_read
)) {
312 if (threads
[i
].read_func
) {
313 threads
[i
].read_func(threads
[i
].data
);
314 check_bottom_halves();
319 if (FD_ISSET(i
, &x_write
)) {
320 if (threads
[i
].write_func
) {
321 threads
[i
].write_func(threads
[i
].data
);
322 check_bottom_halves();
327 if (FD_ISSET(i
, &x_error
)) {
328 if (threads
[i
].error_func
) {
329 threads
[i
].error_func(threads
[i
].data
);
330 check_bottom_halves();
341 can_read_or_write(int fd
, int write
)
343 struct timeval tv
= {0, 0};
356 return select(fd
+ 1, rfds
, wfds
, NULL
, &tv
);
362 return can_read_or_write(fd
, 0);
368 return can_read_or_write(fd
, 1);