]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* select.cc |
2 | ||
cec48792 | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. |
1fd5e000 CF |
4 | |
5 | Written by Christopher Faylor of Cygnus Solutions | |
6 | cgf@cygnus.com | |
7 | ||
8 | This file is part of Cygwin. | |
9 | ||
10 | This software is a copyrighted work licensed under the terms of the | |
11 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
12 | details. */ | |
13 | ||
1cda1322 CF |
14 | /* The following line means that the BSD socket definitions for |
15 | fd_set, FD_ISSET etc. are used in this file. */ | |
1fd5e000 CF |
16 | |
17 | #define __INSIDE_CYGWIN_NET__ | |
1fd5e000 | 18 | |
4c8d72de | 19 | #include "winsup.h" |
1fd5e000 CF |
20 | #include <sys/socket.h> |
21 | #include <stdlib.h> | |
22 | #include <sys/time.h> | |
23 | ||
4c8d72de DD |
24 | #include <wingdi.h> |
25 | #include <winuser.h> | |
1fd5e000 CF |
26 | #include <netdb.h> |
27 | #include <unistd.h> | |
6644c628 | 28 | #include <limits.h> |
a1299ba5 | 29 | #define USE_SYS_TYPES_FD_SET |
1fd5e000 CF |
30 | #include <winsock.h> |
31 | #include "select.h" | |
9e2baf8d | 32 | #include "cygerrno.h" |
6b91b8d5 | 33 | #include "security.h" |
47063f00 | 34 | #include "path.h" |
7ac61736 | 35 | #include "fhandler.h" |
bccd5e0d | 36 | #include "dtable.h" |
0381fec6 | 37 | #include "cygheap.h" |
bccd5e0d CF |
38 | #include "sigproc.h" |
39 | #include "perthread.h" | |
29ac7f89 | 40 | #include "tty.h" |
b6bd7037 | 41 | #include "cygthread.h" |
6644c628 | 42 | #include "ntdll.h" |
1cda1322 CF |
43 | #include "cygtls.h" |
44 | #include <asm/byteorder.h> | |
1fd5e000 CF |
45 | |
46 | /* | |
47 | * All these defines below should be in sys/types.h | |
48 | * but because of the includes above, they may not have | |
49 | * been included. We create special UNIX_xxxx versions here. | |
50 | */ | |
51 | ||
52 | #ifndef NBBY | |
53 | #define NBBY 8 /* number of bits in a byte */ | |
54 | #endif /* NBBY */ | |
55 | ||
56 | /* | |
57 | * Select uses bit masks of file descriptors in longs. | |
58 | * These macros manipulate such bit fields (the filesystem macros use chars). | |
59 | * FD_SETSIZE may be defined by the user, but the default here | |
60 | * should be >= NOFILE (param.h). | |
61 | */ | |
62 | ||
63 | typedef long fd_mask; | |
64 | #define UNIX_NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */ | |
65 | #ifndef unix_howmany | |
66 | #define unix_howmany(x,y) (((x)+((y)-1))/(y)) | |
67 | #endif | |
68 | ||
69 | #define unix_fd_set fd_set | |
70 | ||
a1299ba5 | 71 | #define NULL_fd_set ((fd_set *) NULL) |
1fd5e000 | 72 | #define sizeof_fd_set(n) \ |
c90e1cf1 | 73 | ((unsigned) (NULL_fd_set->fds_bits + unix_howmany ((n), UNIX_NFDBITS))) |
1fd5e000 CF |
74 | #define UNIX_FD_SET(n, p) \ |
75 | ((p)->fds_bits[(n)/UNIX_NFDBITS] |= (1L << ((n) % UNIX_NFDBITS))) | |
76 | #define UNIX_FD_CLR(n, p) \ | |
77 | ((p)->fds_bits[(n)/UNIX_NFDBITS] &= ~(1L << ((n) % UNIX_NFDBITS))) | |
78 | #define UNIX_FD_ISSET(n, p) \ | |
79 | ((p)->fds_bits[(n)/UNIX_NFDBITS] & (1L << ((n) % UNIX_NFDBITS))) | |
80 | #define UNIX_FD_ZERO(p, n) \ | |
81 | bzero ((caddr_t)(p), sizeof_fd_set ((n))) | |
82 | ||
0072fdab | 83 | #define allocfd_set(n) ((fd_set *) memset (alloca (sizeof_fd_set (n)), 0, sizeof_fd_set (n))) |
1fd5e000 CF |
84 | #define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n)); |
85 | ||
1fd5e000 CF |
86 | #define set_handle_or_return_if_not_open(h, s) \ |
87 | h = (s)->fh->get_handle (); \ | |
0381fec6 | 88 | if (cygheap->fdtab.not_open ((s)->fd)) \ |
1fd5e000 | 89 | { \ |
476dfb65 | 90 | (s)->saw_error = true; \ |
80a429d2 | 91 | set_sig_errno (EBADF); \ |
1fd5e000 CF |
92 | return -1; \ |
93 | } \ | |
94 | ||
95 | /* The main select code. | |
96 | */ | |
c367dfd0 | 97 | extern "C" int |
0072fdab CF |
98 | cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, |
99 | struct timeval *to) | |
1fd5e000 CF |
100 | { |
101 | select_stuff sel; | |
0072fdab CF |
102 | fd_set *dummy_readfds = allocfd_set (maxfds); |
103 | fd_set *dummy_writefds = allocfd_set (maxfds); | |
104 | fd_set *dummy_exceptfds = allocfd_set (maxfds); | |
1fd5e000 | 105 | |
0072fdab | 106 | select_printf ("%d, %p, %p, %p, %p", maxfds, readfds, writefds, exceptfds, to); |
1fd5e000 | 107 | |
1fd5e000 | 108 | if (!readfds) |
0072fdab | 109 | readfds = dummy_readfds; |
1fd5e000 | 110 | if (!writefds) |
0072fdab | 111 | writefds = dummy_writefds; |
1fd5e000 | 112 | if (!exceptfds) |
0072fdab | 113 | exceptfds = dummy_exceptfds; |
1fd5e000 | 114 | |
0072fdab | 115 | for (int i = 0; i < maxfds; i++) |
1fd5e000 CF |
116 | if (!sel.test_and_set (i, readfds, writefds, exceptfds)) |
117 | { | |
118 | select_printf ("aborting due to test_and_set error"); | |
119 | return -1; /* Invalid fd, maybe? */ | |
120 | } | |
121 | ||
122 | /* Convert to milliseconds or INFINITE if to == NULL */ | |
123 | DWORD ms = to ? (to->tv_sec * 1000) + (to->tv_usec / 1000) : INFINITE; | |
124 | if (ms == 0 && to->tv_usec) | |
125 | ms = 1; /* At least 1 ms granularity */ | |
126 | ||
127 | if (to) | |
128 | select_printf ("to->tv_sec %d, to->tv_usec %d, ms %d", to->tv_sec, to->tv_usec, ms); | |
129 | else | |
130 | select_printf ("to NULL, ms %x", ms); | |
131 | ||
aefbf388 | 132 | select_printf ("sel.always_ready %d", sel.always_ready); |
1fd5e000 | 133 | |
8d661d36 CF |
134 | int timeout = 0; |
135 | /* Allocate some fd_set structures using the number of fds as a guide. */ | |
136 | fd_set *r = allocfd_set (maxfds); | |
137 | fd_set *w = allocfd_set (maxfds); | |
138 | fd_set *e = allocfd_set (maxfds); | |
139 | ||
1fd5e000 | 140 | /* Degenerate case. No fds to wait for. Just wait. */ |
aefbf388 | 141 | if (sel.start.next == NULL) |
1fd5e000 | 142 | { |
955dfa52 | 143 | if (WaitForSingleObject (signal_arrived, ms) == WAIT_OBJECT_0) |
1fd5e000 CF |
144 | { |
145 | select_printf ("signal received"); | |
146 | set_sig_errno (EINTR); | |
147 | return -1; | |
148 | } | |
8d661d36 | 149 | timeout = 1; |
1fd5e000 | 150 | } |
8d661d36 | 151 | else if (sel.always_ready || ms == 0) |
a3cfd73a | 152 | /* Don't bother waiting. */; |
8d661d36 | 153 | else if ((timeout = sel.wait (r, w, e, ms) < 0)) |
0072fdab CF |
154 | return -1; /* some kind of error */ |
155 | ||
5835f2cf | 156 | sel.cleanup (); |
0072fdab CF |
157 | copyfd_set (readfds, r, maxfds); |
158 | copyfd_set (writefds, w, maxfds); | |
159 | copyfd_set (exceptfds, e, maxfds); | |
8d661d36 | 160 | return timeout ? 0 : sel.poll (readfds, writefds, exceptfds); |
1fd5e000 CF |
161 | } |
162 | ||
5835f2cf CF |
163 | /* Call cleanup functions for all inspected fds. Gets rid of any |
164 | executing threads. */ | |
165 | void | |
166 | select_stuff::cleanup () | |
1fd5e000 CF |
167 | { |
168 | select_record *s = &start; | |
169 | ||
170 | select_printf ("calling cleanup routines"); | |
171 | while ((s = s->next)) | |
172 | if (s->cleanup) | |
5835f2cf CF |
173 | { |
174 | s->cleanup (s, this); | |
175 | s->cleanup = NULL; | |
176 | } | |
177 | } | |
1fd5e000 | 178 | |
5835f2cf CF |
179 | /* Destroy all storage associated with select stuff. */ |
180 | select_stuff::~select_stuff () | |
181 | { | |
182 | cleanup (); | |
183 | select_record *s = &start; | |
1fd5e000 CF |
184 | select_record *snext = start.next; |
185 | ||
186 | select_printf ("deleting select records"); | |
187 | while ((s = snext)) | |
188 | { | |
189 | snext = s->next; | |
190 | delete s; | |
191 | } | |
192 | } | |
193 | ||
194 | /* Add a record to the select chain */ | |
195 | int | |
196 | select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds, | |
197 | fd_set *exceptfds) | |
198 | { | |
199 | select_record *s = NULL; | |
0381fec6 | 200 | if (UNIX_FD_ISSET (i, readfds) && (s = cygheap->fdtab.select_read (i, s)) == NULL) |
1fd5e000 | 201 | return 0; /* error */ |
0381fec6 | 202 | if (UNIX_FD_ISSET (i, writefds) && (s = cygheap->fdtab.select_write (i, s)) == NULL) |
1fd5e000 | 203 | return 0; /* error */ |
0381fec6 | 204 | if (UNIX_FD_ISSET (i, exceptfds) && (s = cygheap->fdtab.select_except (i, s)) == NULL) |
1fd5e000 CF |
205 | return 0; /* error */ |
206 | if (s == NULL) | |
207 | return 1; /* nothing to do */ | |
208 | ||
209 | if (s->read_ready || s->write_ready || s->except_ready) | |
476dfb65 | 210 | always_ready = true; |
1fd5e000 CF |
211 | |
212 | if (s->windows_handle || s->windows_handle || s->windows_handle) | |
476dfb65 | 213 | windows_used = true; |
1fd5e000 CF |
214 | |
215 | s->next = start.next; | |
216 | start.next = s; | |
1fd5e000 CF |
217 | return 1; |
218 | } | |
219 | ||
1fd5e000 CF |
220 | /* The heart of select. Waits for an fd to do something interesting. */ |
221 | int | |
222 | select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, | |
223 | DWORD ms) | |
224 | { | |
225 | int wait_ret; | |
aefbf388 | 226 | HANDLE w4[MAXIMUM_WAIT_OBJECTS]; |
1fd5e000 CF |
227 | select_record *s = &start; |
228 | int m = 0; | |
8d661d36 | 229 | int res = 0; |
1fd5e000 CF |
230 | |
231 | w4[m++] = signal_arrived; /* Always wait for the arrival of a signal. */ | |
232 | /* Loop through the select chain, starting up anything appropriate and | |
233 | counting the number of active fds. */ | |
234 | while ((s = s->next)) | |
235 | { | |
fe3db6cc | 236 | if (m >= MAXIMUM_WAIT_OBJECTS) |
b5ae313a | 237 | { |
80a429d2 | 238 | set_sig_errno (EINVAL); |
b5ae313a CF |
239 | return -1; |
240 | } | |
1fd5e000 CF |
241 | if (!s->startup (s, this)) |
242 | { | |
243 | __seterrno (); | |
244 | return -1; | |
245 | } | |
246 | if (s->h == NULL) | |
247 | continue; | |
248 | for (int i = 1; i < m; i++) | |
249 | if (w4[i] == s->h) | |
250 | goto next_while; | |
251 | w4[m++] = s->h; | |
252 | next_while: | |
253 | continue; | |
254 | } | |
255 | ||
1fd5e000 CF |
256 | DWORD start_time = GetTickCount (); /* Record the current time for later use. */ |
257 | ||
0072fdab | 258 | debug_printf ("m %d, ms %u", m, ms); |
1fd5e000 CF |
259 | for (;;) |
260 | { | |
261 | if (!windows_used) | |
262 | wait_ret = WaitForMultipleObjects (m, w4, FALSE, ms); | |
263 | else | |
264 | wait_ret = MsgWaitForMultipleObjects (m, w4, FALSE, ms, QS_ALLINPUT); | |
265 | ||
266 | switch (wait_ret) | |
267 | { | |
268 | case WAIT_OBJECT_0: | |
269 | select_printf ("signal received"); | |
270 | set_sig_errno (EINTR); | |
271 | return -1; | |
272 | case WAIT_FAILED: | |
273 | select_printf ("WaitForMultipleObjects failed"); | |
274 | __seterrno (); | |
275 | return -1; | |
276 | case WAIT_TIMEOUT: | |
277 | select_printf ("timed out"); | |
8d661d36 | 278 | res = 1; |
1fd5e000 CF |
279 | goto out; |
280 | } | |
281 | ||
282 | select_printf ("woke up. wait_ret %d. verifying", wait_ret); | |
283 | s = &start; | |
2e008fb9 | 284 | bool gotone = false; |
915d1824 | 285 | /* Some types of object (e.g., consoles) wake up on "inappropriate" events |
9c510edc | 286 | like mouse movements. The verify function will detect these situations. |
915d1824 CF |
287 | If it returns false, then this wakeup was a false alarm and we should go |
288 | back to waiting. */ | |
1fd5e000 CF |
289 | while ((s = s->next)) |
290 | if (s->saw_error) | |
291 | return -1; /* Somebody detected an error */ | |
292 | else if ((((wait_ret >= m && s->windows_handle) || s->h == w4[wait_ret])) && | |
0072fdab | 293 | s->verify (s, readfds, writefds, exceptfds)) |
476dfb65 | 294 | gotone = true; |
1fd5e000 CF |
295 | |
296 | select_printf ("gotone %d", gotone); | |
297 | if (gotone) | |
298 | goto out; | |
299 | ||
300 | if (ms == INFINITE) | |
301 | { | |
302 | select_printf ("looping"); | |
303 | continue; | |
304 | } | |
305 | select_printf ("recalculating ms"); | |
306 | ||
307 | DWORD now = GetTickCount (); | |
308 | if (now > (start_time + ms)) | |
309 | { | |
310 | select_printf ("timed out after verification"); | |
311 | goto out; | |
312 | } | |
313 | ms -= (now - start_time); | |
314 | start_time = now; | |
315 | select_printf ("ms now %u", ms); | |
316 | } | |
317 | ||
318 | out: | |
8d661d36 CF |
319 | select_printf ("returning %d", res); |
320 | return res; | |
1fd5e000 CF |
321 | } |
322 | ||
323 | static int | |
324 | set_bits (select_record *me, fd_set *readfds, fd_set *writefds, | |
711ded6d | 325 | fd_set *exceptfds) |
1fd5e000 CF |
326 | { |
327 | int ready = 0; | |
328 | select_printf ("me %p, testing fd %d (%s)", me, me->fd, me->fh->get_name ()); | |
329 | if (me->read_selected && me->read_ready) | |
330 | { | |
331 | UNIX_FD_SET (me->fd, readfds); | |
332 | ready++; | |
333 | } | |
334 | if (me->write_selected && me->write_ready) | |
335 | { | |
336 | UNIX_FD_SET (me->fd, writefds); | |
7ac61736 | 337 | if (me->except_on_write && me->fh->is_socket ()) |
56551a9b | 338 | ((fhandler_socket *) me->fh)->connect_state (connected); |
1fd5e000 CF |
339 | ready++; |
340 | } | |
6bb769ef | 341 | if ((me->except_selected || me->except_on_write) && me->except_ready) |
1fd5e000 | 342 | { |
6bb769ef | 343 | if (me->except_on_write) /* Only on sockets */ |
6cae97d5 | 344 | { |
6bb769ef | 345 | UNIX_FD_SET (me->fd, writefds); |
7ac61736 | 346 | if (me->fh->is_socket ()) |
56551a9b | 347 | ((fhandler_socket *) me->fh)->connect_state (connected); |
6cae97d5 | 348 | } |
6bb769ef CV |
349 | if (me->except_selected) |
350 | UNIX_FD_SET (me->fd, exceptfds); | |
1fd5e000 CF |
351 | ready++; |
352 | } | |
353 | select_printf ("ready %d", ready); | |
354 | return ready; | |
355 | } | |
356 | ||
476dfb65 CF |
357 | /* Poll every fd in the select chain. Set appropriate fd in mask. */ |
358 | int | |
359 | select_stuff::poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds) | |
360 | { | |
361 | int n = 0; | |
362 | select_record *s = &start; | |
363 | while ((s = s->next)) | |
364 | n += (!s->peek || s->peek (s, true)) ? | |
365 | set_bits (s, readfds, writefds, exceptfds) : 0; | |
366 | select_printf ("returning %d", n); | |
367 | return n; | |
368 | } | |
369 | ||
1fd5e000 | 370 | static int |
9cec3d45 | 371 | verify_true (select_record *, fd_set *, fd_set *, fd_set *) |
1fd5e000 CF |
372 | { |
373 | return 1; | |
374 | } | |
375 | ||
376 | static int | |
377 | verify_ok (select_record *me, fd_set *readfds, fd_set *writefds, | |
378 | fd_set *exceptfds) | |
379 | { | |
380 | return set_bits (me, readfds, writefds, exceptfds); | |
381 | } | |
382 | ||
383 | static int | |
9cec3d45 | 384 | no_startup (select_record *, select_stuff *) |
1fd5e000 CF |
385 | { |
386 | return 1; | |
387 | } | |
388 | ||
389 | static int | |
390 | no_verify (select_record *, fd_set *, fd_set *, fd_set *) | |
391 | { | |
392 | return 0; | |
393 | } | |
394 | ||
395 | static int | |
476dfb65 | 396 | peek_pipe (select_record *s, bool from_select) |
1fd5e000 CF |
397 | { |
398 | int n = 0; | |
399 | int gotone = 0; | |
400 | fhandler_base *fh = s->fh; | |
401 | ||
402 | HANDLE h; | |
403 | set_handle_or_return_if_not_open (h, s); | |
404 | ||
915d1824 CF |
405 | /* pipes require a guard mutex to guard against the situation where multiple |
406 | readers are attempting to read from the same pipe. In this scenario, it | |
407 | is possible for PeekNamedPipe to report available data to two readers but | |
408 | only one will actually get the data. This will result in the other reader | |
409 | entering fhandler_base::raw_read and blocking indefinitely in an interruptible | |
410 | state. This causes things like "make -j2" to hang. So, for the non-select case | |
411 | we use the pipe mutex, if it is available. */ | |
476dfb65 | 412 | HANDLE guard_mutex = from_select ? NULL : fh->get_guard (); |
915d1824 | 413 | |
1fd5e000 CF |
414 | /* Don't perform complicated tests if we don't need to. */ |
415 | if (!s->read_selected && !s->except_selected) | |
416 | goto out; | |
417 | ||
3f0b4935 | 418 | if (s->read_selected) |
1fd5e000 | 419 | { |
41010c6a CF |
420 | if (s->read_ready) |
421 | { | |
6644c628 | 422 | select_printf ("%s, already ready for read", fh->get_name ()); |
41010c6a CF |
423 | gotone = 1; |
424 | goto out; | |
425 | } | |
1fd5e000 | 426 | |
c5d03f3d | 427 | switch (fh->get_device ()) |
3f0b4935 | 428 | { |
c5d03f3d CF |
429 | case FH_PTYM: |
430 | case FH_TTYM: | |
1d380f59 | 431 | if (((fhandler_pty_master *) fh)->need_nl) |
c5d03f3d | 432 | { |
915d1824 | 433 | gotone = s->read_ready = true; |
c5d03f3d CF |
434 | goto out; |
435 | } | |
436 | break; | |
437 | default: | |
476dfb65 | 438 | if (fh->get_readahead_valid ()) |
c5d03f3d CF |
439 | { |
440 | select_printf ("readahead"); | |
915d1824 | 441 | gotone = s->read_ready = true; |
c5d03f3d CF |
442 | goto out; |
443 | } | |
3f0b4935 | 444 | } |
35f879a6 CF |
445 | |
446 | if (fh->bg_check (SIGTTIN) <= bg_eof) | |
447 | { | |
915d1824 | 448 | gotone = s->read_ready = true; |
35f879a6 CF |
449 | goto out; |
450 | } | |
1fd5e000 CF |
451 | } |
452 | ||
5e733918 | 453 | if (fh->get_device () == FH_PIPEW) |
6644c628 CF |
454 | select_printf ("%s, select for read/except on write end of pipe", |
455 | fh->get_name ()); | |
32638384 CF |
456 | else if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL)) |
457 | { | |
458 | select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ()); | |
459 | n = -1; | |
460 | } | |
c4157069 | 461 | else if (!n || !guard_mutex) |
907dc7d0 | 462 | /* no guard mutex or nothing to read from the pipe. */; |
c4157069 CF |
463 | else if (WaitForSingleObject (guard_mutex, 0) != WAIT_OBJECT_0) |
464 | { | |
465 | select_printf ("%s, couldn't get mutex %p, %E", fh->get_name (), | |
466 | guard_mutex); | |
467 | n = 0; | |
468 | } | |
469 | else | |
5e733918 | 470 | { |
243a041b | 471 | /* Now that we have the mutex, make sure that no one else has snuck |
c4157069 | 472 | in and grabbed the data that we originally saw. */ |
243a041b CF |
473 | if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL)) |
474 | { | |
475 | select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ()); | |
476 | n = -1; | |
477 | } | |
478 | if (n <= 0) | |
479 | ReleaseMutex (guard_mutex); /* Oops. We lost the race. */ | |
5e733918 | 480 | } |
1fd5e000 CF |
481 | |
482 | if (n < 0) | |
483 | { | |
915d1824 | 484 | fh->set_eof (); /* Flag that other end of pipe is gone */ |
1fd5e000 CF |
485 | select_printf ("%s, n %d", fh->get_name (), n); |
486 | if (s->except_selected) | |
476dfb65 | 487 | gotone += s->except_ready = true; |
1fd5e000 | 488 | if (s->read_selected) |
476dfb65 | 489 | gotone += s->read_ready = true; |
1fd5e000 CF |
490 | } |
491 | if (n > 0 && s->read_selected) | |
492 | { | |
6644c628 | 493 | select_printf ("%s, ready for read: avail %d", fh->get_name (), n); |
476dfb65 | 494 | gotone += s->read_ready = true; |
1fd5e000 CF |
495 | } |
496 | if (!gotone && s->fh->hit_eof ()) | |
497 | { | |
498 | select_printf ("%s, saw EOF", fh->get_name ()); | |
499 | if (s->except_selected) | |
6644c628 | 500 | gotone += s->except_ready = true; |
1fd5e000 | 501 | if (s->read_selected) |
476dfb65 | 502 | gotone += s->read_ready = true; |
1fd5e000 CF |
503 | } |
504 | ||
505 | out: | |
6644c628 CF |
506 | if (s->write_selected) |
507 | { | |
508 | if (s->write_ready) | |
d584454c CF |
509 | { |
510 | select_printf ("%s, already ready for write", fh->get_name ()); | |
511 | gotone++; | |
512 | } | |
6644c628 CF |
513 | /* Do we need to do anything about SIGTTOU here? */ |
514 | else if (fh->get_device () == FH_PIPER) | |
515 | select_printf ("%s, select for write on read end of pipe", | |
516 | fh->get_name ()); | |
517 | else | |
d584454c CF |
518 | { |
519 | /* We don't worry about the guard mutex, because that only applies | |
520 | when from_select is false, and peek_pipe is never called that | |
521 | way for writes. */ | |
522 | ||
523 | IO_STATUS_BLOCK iosb = {0}; | |
524 | FILE_PIPE_LOCAL_INFORMATION fpli = {0}; | |
525 | ||
526 | if (NtQueryInformationFile (h, | |
527 | &iosb, | |
528 | &fpli, | |
529 | sizeof (fpli), | |
530 | FilePipeLocalInformation)) | |
531 | { | |
532 | /* If NtQueryInformationFile fails, optimistically assume the | |
533 | pipe is writable. This could happen on Win9x, because | |
534 | NtQueryInformationFile is not available, or if we somehow | |
535 | inherit a pipe that doesn't permit FILE_READ_ATTRIBUTES | |
536 | access on the write end. */ | |
537 | select_printf ("%s, NtQueryInformationFile failed", | |
538 | fh->get_name ()); | |
539 | gotone += s->write_ready = true; | |
540 | } | |
541 | /* Ensure that enough space is available for atomic writes, | |
542 | as required by POSIX. Subsequent writes with size > PIPE_BUF | |
543 | can still block, but most (all?) UNIX variants seem to work | |
544 | this way (e.g., BSD, Linux, Solaris). */ | |
545 | else if (fpli.WriteQuotaAvailable >= PIPE_BUF) | |
546 | { | |
547 | select_printf ("%s, ready for write: size %lu, avail %lu", | |
548 | fh->get_name (), | |
549 | fpli.OutboundQuota, | |
550 | fpli.WriteQuotaAvailable); | |
551 | gotone += s->write_ready = true; | |
552 | } | |
553 | /* If we somehow inherit a tiny pipe (size < PIPE_BUF), then consider | |
554 | the pipe writable only if it is completely empty, to minimize the | |
555 | probability that a subsequent write will block. */ | |
556 | else if (fpli.OutboundQuota < PIPE_BUF && | |
557 | fpli.WriteQuotaAvailable == fpli.OutboundQuota) | |
558 | { | |
559 | select_printf ("%s, tiny pipe: size %lu, avail %lu", | |
560 | fh->get_name (), | |
561 | fpli.OutboundQuota, | |
562 | fpli.WriteQuotaAvailable); | |
563 | gotone += s->write_ready = true; | |
564 | } | |
565 | } | |
6644c628 CF |
566 | } |
567 | ||
568 | return gotone; | |
1fd5e000 CF |
569 | } |
570 | ||
1fd5e000 CF |
571 | static int start_thread_pipe (select_record *me, select_stuff *stuff); |
572 | ||
573 | struct pipeinf | |
574 | { | |
b6bd7037 | 575 | cygthread *thread; |
2e008fb9 | 576 | bool stop_thread_pipe; |
1fd5e000 CF |
577 | select_record *start; |
578 | }; | |
579 | ||
580 | static DWORD WINAPI | |
581 | thread_pipe (void *arg) | |
582 | { | |
1d380f59 | 583 | pipeinf *pi = (pipeinf *) arg; |
2e008fb9 | 584 | bool gotone = false; |
1fd5e000 CF |
585 | |
586 | for (;;) | |
587 | { | |
588 | select_record *s = pi->start; | |
589 | while ((s = s->next)) | |
590 | if (s->startup == start_thread_pipe) | |
591 | { | |
476dfb65 CF |
592 | if (peek_pipe (s, true)) |
593 | gotone = true; | |
1fd5e000 CF |
594 | if (pi->stop_thread_pipe) |
595 | { | |
596 | select_printf ("stopping"); | |
597 | goto out; | |
598 | } | |
599 | } | |
2a6a56c2 CF |
600 | /* Paranoid check */ |
601 | if (pi->stop_thread_pipe) | |
602 | { | |
603 | select_printf ("stopping from outer loop"); | |
604 | break; | |
605 | } | |
1fd5e000 CF |
606 | if (gotone) |
607 | break; | |
608 | Sleep (10); | |
609 | } | |
610 | out: | |
611 | return 0; | |
612 | } | |
613 | ||
614 | static int | |
615 | start_thread_pipe (select_record *me, select_stuff *stuff) | |
616 | { | |
7ac61736 | 617 | if (stuff->device_specific_pipe) |
1fd5e000 | 618 | { |
7ac61736 | 619 | me->h = *((pipeinf *) stuff->device_specific_pipe)->thread; |
1fd5e000 CF |
620 | return 1; |
621 | } | |
622 | pipeinf *pi = new pipeinf; | |
623 | pi->start = &stuff->start; | |
2e008fb9 | 624 | pi->stop_thread_pipe = false; |
1d380f59 | 625 | pi->thread = new cygthread (thread_pipe, (LPVOID) pi, "select_pipe"); |
b6bd7037 | 626 | me->h = *pi->thread; |
1fd5e000 CF |
627 | if (!me->h) |
628 | return 0; | |
7ac61736 | 629 | stuff->device_specific_pipe = (void *) pi; |
1fd5e000 CF |
630 | return 1; |
631 | } | |
632 | ||
633 | static void | |
9cec3d45 | 634 | pipe_cleanup (select_record *, select_stuff *stuff) |
1fd5e000 | 635 | { |
7ac61736 | 636 | pipeinf *pi = (pipeinf *) stuff->device_specific_pipe; |
1fd5e000 CF |
637 | if (pi && pi->thread) |
638 | { | |
476dfb65 | 639 | pi->stop_thread_pipe = true; |
b6bd7037 | 640 | pi->thread->detach (); |
1fd5e000 | 641 | delete pi; |
7ac61736 | 642 | stuff->device_specific_pipe = NULL; |
1fd5e000 CF |
643 | } |
644 | } | |
645 | ||
1d380f59 CF |
646 | int |
647 | fhandler_pipe::ready_for_read (int fd, DWORD howlong) | |
648 | { | |
0eaf24fe CF |
649 | int res; |
650 | if (howlong) | |
651 | res = true; | |
652 | else | |
653 | res = fhandler_base::ready_for_read (fd, howlong); | |
1d380f59 | 654 | |
0eaf24fe CF |
655 | if (res) |
656 | get_guard (); | |
657 | return res; | |
1d380f59 CF |
658 | } |
659 | ||
1fd5e000 CF |
660 | select_record * |
661 | fhandler_pipe::select_read (select_record *s) | |
662 | { | |
663 | if (!s) | |
664 | s = new select_record; | |
665 | s->startup = start_thread_pipe; | |
1229d4f4 | 666 | s->peek = peek_pipe; |
1fd5e000 | 667 | s->verify = verify_ok; |
6644c628 | 668 | s->cleanup = pipe_cleanup; |
476dfb65 CF |
669 | s->read_selected = true; |
670 | s->read_ready = false; | |
1fd5e000 CF |
671 | return s; |
672 | } | |
673 | ||
674 | select_record * | |
675 | fhandler_pipe::select_write (select_record *s) | |
676 | { | |
677 | if (!s) | |
6644c628 CF |
678 | s = new select_record; |
679 | s->startup = start_thread_pipe; | |
476dfb65 | 680 | s->peek = peek_pipe; |
6644c628 CF |
681 | s->verify = verify_ok; |
682 | s->cleanup = pipe_cleanup; | |
476dfb65 | 683 | s->write_selected = true; |
6644c628 | 684 | s->write_ready = false; |
1fd5e000 CF |
685 | return s; |
686 | } | |
687 | ||
688 | select_record * | |
689 | fhandler_pipe::select_except (select_record *s) | |
690 | { | |
691 | if (!s) | |
6644c628 | 692 | s = new select_record; |
1fd5e000 | 693 | s->startup = start_thread_pipe; |
476dfb65 | 694 | s->peek = peek_pipe; |
1fd5e000 CF |
695 | s->verify = verify_ok; |
696 | s->cleanup = pipe_cleanup; | |
476dfb65 CF |
697 | s->except_selected = true; |
698 | s->except_ready = false; | |
1fd5e000 CF |
699 | return s; |
700 | } | |
701 | ||
702 | static int | |
476dfb65 | 703 | peek_console (select_record *me, bool) |
1fd5e000 | 704 | { |
a9867e1b | 705 | extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *); |
1d380f59 | 706 | fhandler_console *fh = (fhandler_console *) me->fh; |
1fd5e000 CF |
707 | |
708 | if (!me->read_selected) | |
709 | return me->write_ready; | |
710 | ||
476dfb65 | 711 | if (fh->get_readahead_valid ()) |
1fd5e000 CF |
712 | { |
713 | select_printf ("readahead"); | |
915d1824 | 714 | return me->read_ready = true; |
1fd5e000 CF |
715 | } |
716 | ||
41010c6a CF |
717 | if (me->read_ready) |
718 | { | |
719 | select_printf ("already ready"); | |
720 | return 1; | |
721 | } | |
722 | ||
1fd5e000 CF |
723 | INPUT_RECORD irec; |
724 | DWORD events_read; | |
725 | HANDLE h; | |
a9867e1b | 726 | char tmpbuf[17]; |
1fd5e000 CF |
727 | set_handle_or_return_if_not_open (h, me); |
728 | ||
729 | for (;;) | |
a7cde2b9 | 730 | if (fh->bg_check (SIGTTIN) <= bg_eof) |
915d1824 | 731 | return me->read_ready = true; |
1fd5e000 CF |
732 | else if (!PeekConsoleInput (h, &irec, 1, &events_read) || !events_read) |
733 | break; | |
734 | else | |
735 | { | |
c060edba | 736 | if (irec.EventType == KEY_EVENT) |
d80999a1 | 737 | { |
c060edba CF |
738 | if (irec.Event.KeyEvent.bKeyDown |
739 | && (irec.Event.KeyEvent.uChar.AsciiChar | |
740 | || get_nonascii_key (irec, tmpbuf))) | |
915d1824 | 741 | return me->read_ready = true; |
d80999a1 | 742 | } |
c060edba CF |
743 | else |
744 | { | |
745 | fh->send_winch_maybe (); | |
746 | if (irec.EventType == MOUSE_EVENT | |
747 | && fh->mouse_aware () | |
748 | && (irec.Event.MouseEvent.dwEventFlags == 0 | |
749 | || irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)) | |
750 | return me->read_ready = true; | |
751 | } | |
1fd5e000 CF |
752 | |
753 | /* Read and discard the event */ | |
754 | ReadConsoleInput (h, &irec, 1, &events_read); | |
755 | } | |
756 | ||
757 | return me->write_ready; | |
758 | } | |
9c510edc | 759 | |
763f09b9 CF |
760 | static int |
761 | verify_console (select_record *me, fd_set *rfds, fd_set *wfds, | |
762 | fd_set *efds) | |
763 | { | |
764 | return peek_console (me, true); | |
765 | } | |
766 | ||
1fd5e000 | 767 | |
1fd5e000 CF |
768 | select_record * |
769 | fhandler_console::select_read (select_record *s) | |
770 | { | |
771 | if (!s) | |
772 | { | |
773 | s = new select_record; | |
774 | s->startup = no_startup; | |
763f09b9 | 775 | s->verify = verify_console; |
e5dd8811 | 776 | set_cursor_maybe (); |
1fd5e000 CF |
777 | } |
778 | ||
1229d4f4 | 779 | s->peek = peek_console; |
1fd5e000 | 780 | s->h = get_handle (); |
476dfb65 CF |
781 | s->read_selected = true; |
782 | s->read_ready = false; | |
1fd5e000 CF |
783 | return s; |
784 | } | |
785 | ||
786 | select_record * | |
787 | fhandler_console::select_write (select_record *s) | |
788 | { | |
789 | if (!s) | |
790 | { | |
791 | s = new select_record; | |
792 | s->startup = no_startup; | |
1fd5e000 | 793 | s->verify = no_verify; |
e5dd8811 | 794 | set_cursor_maybe (); |
1fd5e000 CF |
795 | } |
796 | ||
476dfb65 CF |
797 | s->peek = peek_console; |
798 | s->write_selected = true; | |
799 | s->write_ready = true; | |
1fd5e000 CF |
800 | return s; |
801 | } | |
802 | ||
803 | select_record * | |
804 | fhandler_console::select_except (select_record *s) | |
805 | { | |
806 | if (!s) | |
807 | { | |
808 | s = new select_record; | |
809 | s->startup = no_startup; | |
1fd5e000 | 810 | s->verify = no_verify; |
e5dd8811 | 811 | set_cursor_maybe (); |
1fd5e000 CF |
812 | } |
813 | ||
476dfb65 CF |
814 | s->peek = peek_console; |
815 | s->except_selected = true; | |
816 | s->except_ready = false; | |
1fd5e000 CF |
817 | return s; |
818 | } | |
819 | ||
1fd5e000 CF |
820 | select_record * |
821 | fhandler_tty_common::select_read (select_record *s) | |
822 | { | |
1d380f59 | 823 | return ((fhandler_pipe *) this)->fhandler_pipe::select_read (s); |
1fd5e000 CF |
824 | } |
825 | ||
826 | select_record * | |
827 | fhandler_tty_common::select_write (select_record *s) | |
828 | { | |
1d380f59 | 829 | return ((fhandler_pipe *) this)->fhandler_pipe::select_write (s); |
1fd5e000 CF |
830 | } |
831 | ||
832 | select_record * | |
833 | fhandler_tty_common::select_except (select_record *s) | |
834 | { | |
1d380f59 | 835 | return ((fhandler_pipe *) this)->fhandler_pipe::select_except (s); |
1fd5e000 CF |
836 | } |
837 | ||
5e8e21d9 ED |
838 | static int |
839 | verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds, | |
840 | fd_set *exceptfds) | |
841 | { | |
842 | if (WaitForSingleObject (me->h, 0) == WAIT_OBJECT_0) | |
915d1824 | 843 | me->read_ready = true; |
5e8e21d9 ED |
844 | return set_bits (me, readfds, writefds, exceptfds); |
845 | } | |
846 | ||
847 | select_record * | |
848 | fhandler_tty_slave::select_read (select_record *s) | |
849 | { | |
850 | if (!s) | |
851 | s = new select_record; | |
852 | s->h = input_available_event; | |
853 | s->startup = no_startup; | |
1229d4f4 | 854 | s->peek = peek_pipe; |
5e8e21d9 | 855 | s->verify = verify_tty_slave; |
476dfb65 CF |
856 | s->read_selected = true; |
857 | s->read_ready = false; | |
5e8e21d9 ED |
858 | s->cleanup = NULL; |
859 | return s; | |
860 | } | |
861 | ||
1fd5e000 CF |
862 | select_record * |
863 | fhandler_dev_null::select_read (select_record *s) | |
864 | { | |
865 | if (!s) | |
866 | { | |
867 | s = new select_record; | |
868 | s->startup = no_startup; | |
1fd5e000 CF |
869 | s->verify = no_verify; |
870 | } | |
871 | s->h = get_handle (); | |
476dfb65 CF |
872 | s->read_selected = true; |
873 | s->read_ready = true; | |
1fd5e000 CF |
874 | return s; |
875 | } | |
876 | ||
877 | select_record * | |
878 | fhandler_dev_null::select_write (select_record *s) | |
879 | { | |
880 | if (!s) | |
881 | { | |
882 | s = new select_record; | |
883 | s->startup = no_startup; | |
1fd5e000 CF |
884 | s->verify = no_verify; |
885 | } | |
886 | s->h = get_handle (); | |
476dfb65 CF |
887 | s->write_selected = true; |
888 | s->write_ready = true; | |
1fd5e000 CF |
889 | return s; |
890 | } | |
891 | ||
892 | select_record * | |
893 | fhandler_dev_null::select_except (select_record *s) | |
894 | { | |
895 | if (!s) | |
896 | { | |
897 | s = new select_record; | |
898 | s->startup = no_startup; | |
1fd5e000 CF |
899 | s->verify = no_verify; |
900 | } | |
901 | s->h = get_handle (); | |
476dfb65 CF |
902 | s->except_selected = true; |
903 | s->except_ready = true; | |
1fd5e000 CF |
904 | return s; |
905 | } | |
906 | ||
907 | static int start_thread_serial (select_record *me, select_stuff *stuff); | |
908 | ||
909 | struct serialinf | |
910 | { | |
b6bd7037 | 911 | cygthread *thread; |
2e008fb9 | 912 | bool stop_thread_serial; |
1fd5e000 CF |
913 | select_record *start; |
914 | }; | |
915 | ||
916 | static int | |
476dfb65 | 917 | peek_serial (select_record *s, bool) |
1fd5e000 | 918 | { |
1fd5e000 CF |
919 | COMSTAT st; |
920 | ||
1d380f59 | 921 | fhandler_serial *fh = (fhandler_serial *) s->fh; |
1fd5e000 CF |
922 | |
923 | if (fh->get_readahead_valid () || fh->overlapped_armed < 0) | |
915d1824 | 924 | return s->read_ready = true; |
1fd5e000 CF |
925 | |
926 | select_printf ("fh->overlapped_armed %d", fh->overlapped_armed); | |
927 | ||
928 | HANDLE h; | |
929 | set_handle_or_return_if_not_open (h, s); | |
930 | int ready = 0; | |
41010c6a CF |
931 | |
932 | if (s->read_selected && s->read_ready || (s->write_selected && s->write_ready)) | |
933 | { | |
934 | select_printf ("already ready"); | |
935 | ready = 1; | |
936 | goto out; | |
937 | } | |
938 | ||
1fd5e000 CF |
939 | (void) SetCommMask (h, EV_RXCHAR); |
940 | ||
941 | if (!fh->overlapped_armed) | |
942 | { | |
1fd5e000 CF |
943 | COMSTAT st; |
944 | ||
945 | ResetEvent (fh->io_status.hEvent); | |
946 | ||
40139114 | 947 | if (!ClearCommError (h, &fh->ev, &st)) |
1fd5e000 CF |
948 | { |
949 | debug_printf ("ClearCommError"); | |
950 | goto err; | |
951 | } | |
952 | else if (st.cbInQue) | |
915d1824 | 953 | return s->read_ready = true; |
40139114 | 954 | else if (WaitCommEvent (h, &fh->ev, &fh->io_status)) |
915d1824 | 955 | return s->read_ready = true; |
1fd5e000 CF |
956 | else if (GetLastError () == ERROR_IO_PENDING) |
957 | fh->overlapped_armed = 1; | |
958 | else | |
959 | { | |
960 | debug_printf ("WaitCommEvent"); | |
961 | goto err; | |
962 | } | |
963 | } | |
964 | ||
965 | HANDLE w4[2]; | |
966 | DWORD to; | |
967 | ||
968 | w4[0] = fh->io_status.hEvent; | |
969 | w4[1] = signal_arrived; | |
970 | to = 10; | |
971 | ||
972 | switch (WaitForMultipleObjects (2, w4, FALSE, to)) | |
973 | { | |
974 | case WAIT_OBJECT_0: | |
40139114 | 975 | if (!ClearCommError (h, &fh->ev, &st)) |
b0e82b74 CF |
976 | { |
977 | debug_printf ("ClearCommError"); | |
978 | goto err; | |
979 | } | |
1fd5e000 CF |
980 | else if (!st.cbInQue) |
981 | Sleep (to); | |
982 | else | |
983 | { | |
915d1824 | 984 | return s->read_ready = true; |
1fd5e000 CF |
985 | select_printf ("got something"); |
986 | } | |
1fd5e000 CF |
987 | break; |
988 | case WAIT_OBJECT_0 + 1: | |
1fd5e000 CF |
989 | select_printf ("interrupt"); |
990 | set_sig_errno (EINTR); | |
991 | ready = -1; | |
992 | break; | |
993 | case WAIT_TIMEOUT: | |
1fd5e000 CF |
994 | break; |
995 | default: | |
1fd5e000 CF |
996 | debug_printf ("WaitForMultipleObjects"); |
997 | goto err; | |
998 | } | |
999 | ||
41010c6a | 1000 | out: |
1fd5e000 CF |
1001 | return ready; |
1002 | ||
1003 | err: | |
1004 | if (GetLastError () == ERROR_OPERATION_ABORTED) | |
1005 | { | |
1006 | select_printf ("operation aborted"); | |
1007 | return ready; | |
1008 | } | |
1009 | ||
1010 | __seterrno (); | |
476dfb65 | 1011 | s->saw_error = true; |
1fd5e000 CF |
1012 | select_printf ("error %E"); |
1013 | return -1; | |
1014 | } | |
1015 | ||
1016 | static DWORD WINAPI | |
1017 | thread_serial (void *arg) | |
1018 | { | |
1d380f59 | 1019 | serialinf *si = (serialinf *) arg; |
2e008fb9 | 1020 | bool gotone = false; |
1fd5e000 CF |
1021 | |
1022 | for (;;) | |
1023 | { | |
1024 | select_record *s = si->start; | |
1025 | while ((s = s->next)) | |
1026 | if (s->startup == start_thread_serial) | |
1027 | { | |
476dfb65 CF |
1028 | if (peek_serial (s, true)) |
1029 | gotone = true; | |
1fd5e000 CF |
1030 | } |
1031 | if (si->stop_thread_serial) | |
1032 | { | |
1033 | select_printf ("stopping"); | |
1034 | break; | |
1035 | } | |
1036 | if (gotone) | |
1037 | break; | |
1038 | } | |
1039 | ||
1040 | select_printf ("exiting"); | |
1041 | return 0; | |
1042 | } | |
1043 | ||
1044 | static int | |
1045 | start_thread_serial (select_record *me, select_stuff *stuff) | |
1046 | { | |
7ac61736 | 1047 | if (stuff->device_specific_serial) |
1fd5e000 | 1048 | { |
7ac61736 | 1049 | me->h = *((serialinf *) stuff->device_specific_serial)->thread; |
1fd5e000 CF |
1050 | return 1; |
1051 | } | |
1052 | serialinf *si = new serialinf; | |
1053 | si->start = &stuff->start; | |
2e008fb9 | 1054 | si->stop_thread_serial = false; |
1d380f59 | 1055 | si->thread = new cygthread (thread_serial, (LPVOID) si, "select_serial"); |
b6bd7037 | 1056 | me->h = *si->thread; |
7ac61736 | 1057 | stuff->device_specific_serial = (void *) si; |
1fd5e000 CF |
1058 | return 1; |
1059 | } | |
1060 | ||
1061 | static void | |
9cec3d45 | 1062 | serial_cleanup (select_record *, select_stuff *stuff) |
1fd5e000 | 1063 | { |
7ac61736 | 1064 | serialinf *si = (serialinf *) stuff->device_specific_serial; |
1fd5e000 CF |
1065 | if (si && si->thread) |
1066 | { | |
476dfb65 | 1067 | si->stop_thread_serial = true; |
b6bd7037 | 1068 | si->thread->detach (); |
1fd5e000 | 1069 | delete si; |
7ac61736 | 1070 | stuff->device_specific_serial = NULL; |
1fd5e000 CF |
1071 | } |
1072 | } | |
1073 | ||
1fd5e000 CF |
1074 | select_record * |
1075 | fhandler_serial::select_read (select_record *s) | |
1076 | { | |
1077 | if (!s) | |
1078 | { | |
1079 | s = new select_record; | |
1080 | s->startup = start_thread_serial; | |
1fd5e000 CF |
1081 | s->verify = verify_ok; |
1082 | s->cleanup = serial_cleanup; | |
1083 | } | |
1229d4f4 | 1084 | s->peek = peek_serial; |
476dfb65 CF |
1085 | s->read_selected = true; |
1086 | s->read_ready = false; | |
1fd5e000 CF |
1087 | return s; |
1088 | } | |
1089 | ||
1090 | select_record * | |
1091 | fhandler_serial::select_write (select_record *s) | |
1092 | { | |
1093 | if (!s) | |
1094 | { | |
1095 | s = new select_record; | |
1096 | s->startup = no_startup; | |
1fd5e000 CF |
1097 | s->verify = verify_ok; |
1098 | } | |
476dfb65 | 1099 | s->peek = peek_serial; |
1fd5e000 | 1100 | s->h = get_handle (); |
476dfb65 CF |
1101 | s->write_selected = true; |
1102 | s->write_ready = true; | |
1fd5e000 CF |
1103 | return s; |
1104 | } | |
1105 | ||
1106 | select_record * | |
1107 | fhandler_serial::select_except (select_record *s) | |
1108 | { | |
1109 | if (!s) | |
1110 | { | |
1111 | s = new select_record; | |
1112 | s->startup = no_startup; | |
1fd5e000 CF |
1113 | s->verify = verify_ok; |
1114 | } | |
1115 | s->h = NULL; | |
476dfb65 CF |
1116 | s->peek = peek_serial; |
1117 | s->except_selected = false; // Can't do this | |
1118 | s->except_ready = false; | |
1fd5e000 CF |
1119 | return s; |
1120 | } | |
1121 | ||
1122 | int | |
476dfb65 | 1123 | fhandler_base::ready_for_read (int fd, DWORD howlong) |
1fd5e000 | 1124 | { |
1229d4f4 CF |
1125 | int avail = 0; |
1126 | select_record me (this); | |
1127 | me.fd = fd; | |
1128 | while (!avail) | |
1129 | { | |
1130 | (void) select_read (&me); | |
476dfb65 | 1131 | avail = me.read_ready ?: me.peek (&me, false); |
1229d4f4 CF |
1132 | |
1133 | if (fd >= 0 && cygheap->fdtab.not_open (fd)) | |
1134 | { | |
80a429d2 | 1135 | set_sig_errno (EBADF); |
1229d4f4 CF |
1136 | avail = 0; |
1137 | break; | |
1138 | } | |
1139 | ||
1140 | if (howlong != INFINITE) | |
1141 | { | |
1142 | if (!avail) | |
80a429d2 | 1143 | set_sig_errno (EAGAIN); |
1229d4f4 CF |
1144 | break; |
1145 | } | |
1146 | ||
1147 | if (WaitForSingleObject (signal_arrived, avail ? 0 : 10) == WAIT_OBJECT_0) | |
1148 | { | |
9a4d574b | 1149 | debug_printf ("interrupted"); |
80a429d2 | 1150 | set_sig_errno (EINTR); |
1229d4f4 CF |
1151 | avail = 0; |
1152 | break; | |
1153 | } | |
1154 | } | |
1155 | ||
53f00290 CF |
1156 | if (get_guard () && !avail && me.read_ready) |
1157 | ReleaseMutex (get_guard ()); | |
1158 | ||
1229d4f4 CF |
1159 | select_printf ("read_ready %d, avail %d", me.read_ready, avail); |
1160 | return avail; | |
1fd5e000 CF |
1161 | } |
1162 | ||
1163 | select_record * | |
1164 | fhandler_base::select_read (select_record *s) | |
1165 | { | |
1166 | if (!s) | |
1167 | { | |
1168 | s = new select_record; | |
1169 | s->startup = no_startup; | |
1fd5e000 CF |
1170 | s->verify = verify_ok; |
1171 | } | |
1172 | s->h = get_handle (); | |
476dfb65 CF |
1173 | s->read_selected = true; |
1174 | s->read_ready = true; | |
1fd5e000 CF |
1175 | return s; |
1176 | } | |
1177 | ||
1178 | select_record * | |
1179 | fhandler_base::select_write (select_record *s) | |
1180 | { | |
1181 | if (!s) | |
1182 | { | |
1183 | s = new select_record; | |
1184 | s->startup = no_startup; | |
1fd5e000 CF |
1185 | s->verify = verify_ok; |
1186 | } | |
1187 | s->h = get_handle (); | |
476dfb65 CF |
1188 | s->write_selected = true; |
1189 | s->write_ready = true; | |
1fd5e000 CF |
1190 | return s; |
1191 | } | |
1192 | ||
1193 | select_record * | |
1194 | fhandler_base::select_except (select_record *s) | |
1195 | { | |
1196 | if (!s) | |
1197 | { | |
1198 | s = new select_record; | |
1199 | s->startup = no_startup; | |
1fd5e000 CF |
1200 | s->verify = verify_ok; |
1201 | } | |
1202 | s->h = NULL; | |
476dfb65 CF |
1203 | s->except_selected = true; |
1204 | s->except_ready = false; | |
1fd5e000 CF |
1205 | return s; |
1206 | } | |
1207 | ||
1208 | struct socketinf | |
1209 | { | |
b6bd7037 | 1210 | cygthread *thread; |
1fd5e000 CF |
1211 | winsock_fd_set readfds, writefds, exceptfds; |
1212 | SOCKET exitsock; | |
1fd5e000 CF |
1213 | select_record *start; |
1214 | }; | |
1215 | ||
1216 | static int | |
476dfb65 | 1217 | peek_socket (select_record *me, bool) |
1fd5e000 CF |
1218 | { |
1219 | winsock_fd_set ws_readfds, ws_writefds, ws_exceptfds; | |
01cf5d0f | 1220 | struct timeval tv = {0, 0}; |
1fd5e000 CF |
1221 | WINSOCK_FD_ZERO (&ws_readfds); |
1222 | WINSOCK_FD_ZERO (&ws_writefds); | |
1223 | WINSOCK_FD_ZERO (&ws_exceptfds); | |
1fd5e000 CF |
1224 | |
1225 | HANDLE h; | |
1226 | set_handle_or_return_if_not_open (h, me); | |
1227 | select_printf ("considering handle %p", h); | |
1228 | ||
d5591d9d | 1229 | if (me->read_selected && !me->read_ready) |
1fd5e000 CF |
1230 | { |
1231 | select_printf ("adding read fd_set %s, fd %d", me->fh->get_name (), | |
1232 | me->fd); | |
1233 | WINSOCK_FD_SET (h, &ws_readfds); | |
1234 | } | |
d5591d9d | 1235 | if (me->write_selected && !me->write_ready) |
1fd5e000 CF |
1236 | { |
1237 | select_printf ("adding write fd_set %s, fd %d", me->fh->get_name (), | |
1238 | me->fd); | |
1239 | WINSOCK_FD_SET (h, &ws_writefds); | |
1240 | } | |
6bb769ef | 1241 | if ((me->except_selected || me->except_on_write) && !me->except_ready) |
1fd5e000 CF |
1242 | { |
1243 | select_printf ("adding except fd_set %s, fd %d", me->fh->get_name (), | |
1244 | me->fd); | |
1245 | WINSOCK_FD_SET (h, &ws_exceptfds); | |
1246 | } | |
d5591d9d CV |
1247 | int r; |
1248 | if ((me->read_selected && !me->read_ready) | |
1249 | || (me->write_selected && !me->write_ready) | |
6bb769ef | 1250 | || ((me->except_selected || me->except_on_write) && !me->except_ready)) |
1fd5e000 | 1251 | { |
d5591d9d CV |
1252 | r = WINSOCK_SELECT (0, &ws_readfds, &ws_writefds, &ws_exceptfds, &tv); |
1253 | select_printf ("WINSOCK_SELECT returned %d", r); | |
1254 | if (r == -1) | |
1255 | { | |
1256 | select_printf ("error %d", WSAGetLastError ()); | |
1257 | set_winsock_errno (); | |
1258 | return 0; | |
1259 | } | |
1260 | if (WINSOCK_FD_ISSET (h, &ws_readfds) || (me->read_selected && me->read_ready)) | |
1261 | me->read_ready = true; | |
1262 | if (WINSOCK_FD_ISSET (h, &ws_writefds) || (me->write_selected && me->write_ready)) | |
1263 | me->write_ready = true; | |
6bb769ef | 1264 | if (WINSOCK_FD_ISSET (h, &ws_exceptfds) || ((me->except_selected || me->except_on_write) && me->except_ready)) |
d5591d9d | 1265 | me->except_ready = true; |
1fd5e000 | 1266 | } |
fe00cca9 | 1267 | return me->read_ready || me->write_ready || me->except_ready; |
1fd5e000 CF |
1268 | } |
1269 | ||
1fd5e000 CF |
1270 | static int start_thread_socket (select_record *, select_stuff *); |
1271 | ||
1272 | static DWORD WINAPI | |
1273 | thread_socket (void *arg) | |
1274 | { | |
1d380f59 | 1275 | socketinf *si = (socketinf *) arg; |
1fd5e000 CF |
1276 | |
1277 | select_printf ("stuff_start %p", &si->start); | |
1278 | int r = WINSOCK_SELECT (0, &si->readfds, &si->writefds, &si->exceptfds, NULL); | |
1279 | select_printf ("Win32 select returned %d", r); | |
1280 | if (r == -1) | |
1281 | select_printf ("error %d", WSAGetLastError ()); | |
1282 | select_record *s = si->start; | |
1283 | while ((s = s->next)) | |
1284 | if (s->startup == start_thread_socket) | |
1285 | { | |
1286 | HANDLE h = s->fh->get_handle (); | |
1287 | select_printf ("s %p, testing fd %d (%s)", s, s->fd, s->fh->get_name ()); | |
1288 | if (WINSOCK_FD_ISSET (h, &si->readfds)) | |
1289 | { | |
1290 | select_printf ("read_ready"); | |
476dfb65 | 1291 | s->read_ready = true; |
1fd5e000 CF |
1292 | } |
1293 | if (WINSOCK_FD_ISSET (h, &si->writefds)) | |
1294 | { | |
1295 | select_printf ("write_ready"); | |
476dfb65 | 1296 | s->write_ready = true; |
1fd5e000 CF |
1297 | } |
1298 | if (WINSOCK_FD_ISSET (h, &si->exceptfds)) | |
1299 | { | |
1300 | select_printf ("except_ready"); | |
476dfb65 | 1301 | s->except_ready = true; |
1fd5e000 CF |
1302 | } |
1303 | } | |
1304 | ||
1305 | if (WINSOCK_FD_ISSET (si->exitsock, &si->readfds)) | |
1306 | select_printf ("saw exitsock read"); | |
1fd5e000 CF |
1307 | return 0; |
1308 | } | |
1309 | ||
1fd5e000 CF |
1310 | static int |
1311 | start_thread_socket (select_record *me, select_stuff *stuff) | |
1312 | { | |
1313 | socketinf *si; | |
1314 | ||
7ac61736 | 1315 | if ((si = (socketinf *) stuff->device_specific_socket)) |
1fd5e000 | 1316 | { |
b6bd7037 | 1317 | me->h = *si->thread; |
1fd5e000 CF |
1318 | return 1; |
1319 | } | |
1320 | ||
1321 | si = new socketinf; | |
1322 | WINSOCK_FD_ZERO (&si->readfds); | |
1323 | WINSOCK_FD_ZERO (&si->writefds); | |
1324 | WINSOCK_FD_ZERO (&si->exceptfds); | |
1325 | select_record *s = &stuff->start; | |
1326 | while ((s = s->next)) | |
1327 | if (s->startup == start_thread_socket) | |
1328 | { | |
1329 | HANDLE h = s->fh->get_handle (); | |
1330 | select_printf ("Handle %p", h); | |
d5591d9d | 1331 | if (s->read_selected && !s->read_ready) |
1fd5e000 CF |
1332 | { |
1333 | WINSOCK_FD_SET (h, &si->readfds); | |
1334 | select_printf ("Added to readfds"); | |
1335 | } | |
d5591d9d | 1336 | if (s->write_selected && !s->write_ready) |
1fd5e000 CF |
1337 | { |
1338 | WINSOCK_FD_SET (h, &si->writefds); | |
1339 | select_printf ("Added to writefds"); | |
1340 | } | |
6bb769ef | 1341 | if ((s->except_selected || s->except_on_write) && !s->except_ready) |
1fd5e000 CF |
1342 | { |
1343 | WINSOCK_FD_SET (h, &si->exceptfds); | |
1344 | select_printf ("Added to exceptfds"); | |
1345 | } | |
1346 | } | |
1347 | ||
1cda1322 | 1348 | if (_my_tls.locals.exitsock != INVALID_SOCKET) |
1fd5e000 | 1349 | { |
d134b48f CF |
1350 | char buf[1]; |
1351 | si->exitsock = _my_tls.locals.exitsock; | |
1352 | select_printf ("read a byte from %p", si->exitsock); | |
1353 | recv (si->exitsock, buf, 1, 0); | |
1fd5e000 | 1354 | } |
1cda1322 | 1355 | else |
1fd5e000 | 1356 | { |
1cda1322 CF |
1357 | si->exitsock = _my_tls.locals.exitsock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
1358 | if (_my_tls.locals.exitsock == INVALID_SOCKET) | |
1359 | { | |
1360 | set_winsock_errno (); | |
1361 | select_printf ("cannot create socket, %E"); | |
1362 | return -1; | |
1363 | } | |
1cda1322 CF |
1364 | int sin_len = sizeof (_my_tls.locals.exitsock_sin); |
1365 | memset (&_my_tls.locals.exitsock_sin, 0, sin_len); | |
1366 | _my_tls.locals.exitsock_sin.sin_family = AF_INET; | |
1367 | _my_tls.locals.exitsock_sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
1368 | if (bind (si->exitsock, (struct sockaddr *) &_my_tls.locals.exitsock_sin, sin_len) < 0) | |
1369 | { | |
1370 | select_printf ("cannot bind socket %p, %E", si->exitsock); | |
1371 | goto err; | |
1372 | } | |
1fd5e000 | 1373 | |
1cda1322 CF |
1374 | if (getsockname (si->exitsock, (struct sockaddr *) &_my_tls.locals.exitsock_sin, &sin_len) < 0) |
1375 | { | |
1376 | select_printf ("getsockname error"); | |
1377 | goto err; | |
1378 | } | |
1fd5e000 CF |
1379 | } |
1380 | ||
1381 | select_printf ("exitsock %p", si->exitsock); | |
1382 | WINSOCK_FD_SET ((HANDLE) si->exitsock, &si->readfds); | |
1383 | WINSOCK_FD_SET ((HANDLE) si->exitsock, &si->exceptfds); | |
7ac61736 | 1384 | stuff->device_specific_socket = (void *) si; |
1fd5e000 CF |
1385 | si->start = &stuff->start; |
1386 | select_printf ("stuff_start %p", &stuff->start); | |
1d380f59 | 1387 | si->thread = new cygthread (thread_socket, (LPVOID) si, "select_socket"); |
b6bd7037 CF |
1388 | me->h = *si->thread; |
1389 | return 1; | |
1fd5e000 CF |
1390 | |
1391 | err: | |
1392 | set_winsock_errno (); | |
1393 | closesocket (si->exitsock); | |
1394 | return -1; | |
1395 | } | |
1396 | ||
1397 | void | |
9cec3d45 | 1398 | socket_cleanup (select_record *, select_stuff *stuff) |
1fd5e000 | 1399 | { |
7ac61736 | 1400 | socketinf *si = (socketinf *) stuff->device_specific_socket; |
1fd5e000 CF |
1401 | select_printf ("si %p si->thread %p", si, si ? si->thread : NULL); |
1402 | if (si && si->thread) | |
1403 | { | |
1cda1322 CF |
1404 | char buf[] = ""; |
1405 | int res = sendto (_my_tls.locals.exitsock, buf, 1, 0, | |
1406 | (sockaddr *) &_my_tls.locals.exitsock_sin, | |
1407 | sizeof (_my_tls.locals.exitsock_sin)); | |
1408 | select_printf ("sent a byte to the exit sock %p, res %d", _my_tls.locals.exitsock, res); | |
1fd5e000 | 1409 | /* Wait for thread to go away */ |
b6bd7037 | 1410 | si->thread->detach (); |
7ac61736 | 1411 | stuff->device_specific_socket = NULL; |
1fd5e000 CF |
1412 | delete si; |
1413 | } | |
1414 | select_printf ("returning"); | |
1415 | } | |
1416 | ||
1417 | select_record * | |
1418 | fhandler_socket::select_read (select_record *s) | |
1419 | { | |
1420 | if (!s) | |
1421 | { | |
1422 | s = new select_record; | |
1423 | s->startup = start_thread_socket; | |
1fd5e000 CF |
1424 | s->verify = verify_true; |
1425 | s->cleanup = socket_cleanup; | |
1426 | } | |
1229d4f4 | 1427 | s->peek = peek_socket; |
5835f2cf | 1428 | s->read_ready = saw_shutdown_read (); |
476dfb65 | 1429 | s->read_selected = true; |
1fd5e000 CF |
1430 | return s; |
1431 | } | |
1432 | ||
1433 | select_record * | |
1434 | fhandler_socket::select_write (select_record *s) | |
1435 | { | |
1436 | if (!s) | |
1437 | { | |
1438 | s = new select_record; | |
1439 | s->startup = start_thread_socket; | |
1fd5e000 CF |
1440 | s->verify = verify_true; |
1441 | s->cleanup = socket_cleanup; | |
1442 | } | |
476dfb65 | 1443 | s->peek = peek_socket; |
56551a9b | 1444 | s->write_ready = saw_shutdown_write () || connect_state () == unconnected; |
476dfb65 | 1445 | s->write_selected = true; |
56551a9b | 1446 | if (connect_state () == connect_pending) |
6bb769ef CV |
1447 | { |
1448 | s->except_ready = saw_shutdown_write () || saw_shutdown_read (); | |
1449 | s->except_on_write = true; | |
1450 | } | |
1fd5e000 CF |
1451 | return s; |
1452 | } | |
1453 | ||
1454 | select_record * | |
1455 | fhandler_socket::select_except (select_record *s) | |
1456 | { | |
1457 | if (!s) | |
1458 | { | |
1459 | s = new select_record; | |
1460 | s->startup = start_thread_socket; | |
1fd5e000 CF |
1461 | s->verify = verify_true; |
1462 | s->cleanup = socket_cleanup; | |
1463 | } | |
476dfb65 | 1464 | s->peek = peek_socket; |
5835f2cf CF |
1465 | /* FIXME: Is this right? Should these be used as criteria for except? */ |
1466 | s->except_ready = saw_shutdown_write () || saw_shutdown_read (); | |
476dfb65 | 1467 | s->except_selected = true; |
1fd5e000 CF |
1468 | return s; |
1469 | } | |
1470 | ||
1471 | static int | |
476dfb65 | 1472 | peek_windows (select_record *me, bool) |
1fd5e000 CF |
1473 | { |
1474 | MSG m; | |
1475 | HANDLE h; | |
1476 | set_handle_or_return_if_not_open (h, me); | |
41010c6a CF |
1477 | |
1478 | if (me->read_selected && me->read_ready) | |
1479 | return 1; | |
1480 | ||
1fd5e000 CF |
1481 | if (PeekMessage (&m, (HWND) h, 0, 0, PM_NOREMOVE)) |
1482 | { | |
476dfb65 | 1483 | me->read_ready = true; |
1fd5e000 CF |
1484 | select_printf ("window %d(%p) ready", me->fd, me->fh->get_handle ()); |
1485 | return 1; | |
1486 | } | |
1487 | ||
1488 | select_printf ("window %d(%p) not ready", me->fd, me->fh->get_handle ()); | |
1489 | return me->write_ready; | |
1490 | } | |
1491 | ||
763f09b9 CF |
1492 | static int |
1493 | verify_windows (select_record *me, fd_set *rfds, fd_set *wfds, | |
1494 | fd_set *efds) | |
1495 | { | |
1496 | return peek_windows (me, true); | |
1497 | } | |
1498 | ||
1fd5e000 CF |
1499 | select_record * |
1500 | fhandler_windows::select_read (select_record *s) | |
1501 | { | |
1502 | if (!s) | |
1503 | { | |
1504 | s = new select_record; | |
1505 | s->startup = no_startup; | |
1fd5e000 | 1506 | } |
763f09b9 | 1507 | s->verify = verify_windows; |
1229d4f4 | 1508 | s->peek = peek_windows; |
476dfb65 CF |
1509 | s->read_selected = true; |
1510 | s->read_ready = false; | |
1fd5e000 | 1511 | s->h = get_handle (); |
476dfb65 | 1512 | s->windows_handle = true; |
1fd5e000 CF |
1513 | return s; |
1514 | } | |
1515 | ||
1516 | select_record * | |
1517 | fhandler_windows::select_write (select_record *s) | |
1518 | { | |
1519 | if (!s) | |
1520 | { | |
1521 | s = new select_record; | |
1522 | s->startup = no_startup; | |
1fd5e000 CF |
1523 | s->verify = verify_ok; |
1524 | } | |
476dfb65 | 1525 | s->peek = peek_windows; |
1fd5e000 | 1526 | s->h = get_handle (); |
476dfb65 CF |
1527 | s->write_selected = true; |
1528 | s->write_ready = true; | |
1529 | s->windows_handle = true; | |
1fd5e000 CF |
1530 | return s; |
1531 | } | |
1532 | ||
1533 | select_record * | |
1534 | fhandler_windows::select_except (select_record *s) | |
1535 | { | |
1536 | if (!s) | |
1537 | { | |
1538 | s = new select_record; | |
1539 | s->startup = no_startup; | |
1fd5e000 CF |
1540 | s->verify = verify_ok; |
1541 | } | |
476dfb65 | 1542 | s->peek = peek_windows; |
1fd5e000 | 1543 | s->h = get_handle (); |
476dfb65 CF |
1544 | s->except_selected = true; |
1545 | s->except_ready = true; | |
1546 | s->windows_handle = true; | |
1fd5e000 CF |
1547 | return s; |
1548 | } |