]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* select.cc |
2 | ||
bc837d22 CF |
3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
4 | 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. | |
1fd5e000 | 5 | |
1fd5e000 CF |
6 | This file is part of Cygwin. |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
1cda1322 CF |
12 | /* The following line means that the BSD socket definitions for |
13 | fd_set, FD_ISSET etc. are used in this file. */ | |
1fd5e000 CF |
14 | |
15 | #define __INSIDE_CYGWIN_NET__ | |
1fd5e000 | 16 | |
4c8d72de | 17 | #include "winsup.h" |
1fd5e000 | 18 | #include <stdlib.h> |
023c2582 | 19 | #include <sys/param.h> |
11a36faa | 20 | #include "ntdll.h" |
1fd5e000 | 21 | |
4c8d72de DD |
22 | #include <wingdi.h> |
23 | #include <winuser.h> | |
a1299ba5 | 24 | #define USE_SYS_TYPES_FD_SET |
c487f2fe | 25 | #include <winsock2.h> |
db80f635 | 26 | #include <netdb.h> |
9e2baf8d | 27 | #include "cygerrno.h" |
6b91b8d5 | 28 | #include "security.h" |
47063f00 | 29 | #include "path.h" |
7ac61736 | 30 | #include "fhandler.h" |
b4fa8164 | 31 | #include "select.h" |
bccd5e0d | 32 | #include "dtable.h" |
0381fec6 | 33 | #include "cygheap.h" |
d02099f2 | 34 | #include "pinfo.h" |
bccd5e0d | 35 | #include "sigproc.h" |
1cda1322 | 36 | #include "cygtls.h" |
4ae63783 | 37 | #include "cygwait.h" |
1fd5e000 CF |
38 | |
39 | /* | |
40 | * All these defines below should be in sys/types.h | |
41 | * but because of the includes above, they may not have | |
42 | * been included. We create special UNIX_xxxx versions here. | |
43 | */ | |
44 | ||
45 | #ifndef NBBY | |
46 | #define NBBY 8 /* number of bits in a byte */ | |
47 | #endif /* NBBY */ | |
48 | ||
49 | /* | |
50 | * Select uses bit masks of file descriptors in longs. | |
51 | * These macros manipulate such bit fields (the filesystem macros use chars). | |
52 | * FD_SETSIZE may be defined by the user, but the default here | |
53 | * should be >= NOFILE (param.h). | |
54 | */ | |
55 | ||
56 | typedef long fd_mask; | |
57 | #define UNIX_NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */ | |
58 | #ifndef unix_howmany | |
59 | #define unix_howmany(x,y) (((x)+((y)-1))/(y)) | |
60 | #endif | |
61 | ||
62 | #define unix_fd_set fd_set | |
63 | ||
a1299ba5 | 64 | #define NULL_fd_set ((fd_set *) NULL) |
1fd5e000 | 65 | #define sizeof_fd_set(n) \ |
c90e1cf1 | 66 | ((unsigned) (NULL_fd_set->fds_bits + unix_howmany ((n), UNIX_NFDBITS))) |
1fd5e000 CF |
67 | #define UNIX_FD_SET(n, p) \ |
68 | ((p)->fds_bits[(n)/UNIX_NFDBITS] |= (1L << ((n) % UNIX_NFDBITS))) | |
69 | #define UNIX_FD_CLR(n, p) \ | |
70 | ((p)->fds_bits[(n)/UNIX_NFDBITS] &= ~(1L << ((n) % UNIX_NFDBITS))) | |
71 | #define UNIX_FD_ISSET(n, p) \ | |
72 | ((p)->fds_bits[(n)/UNIX_NFDBITS] & (1L << ((n) % UNIX_NFDBITS))) | |
73 | #define UNIX_FD_ZERO(p, n) \ | |
b4fa8164 | 74 | memset ((caddr_t) (p), 0, sizeof_fd_set ((n))) |
1fd5e000 | 75 | |
b052bf26 CF |
76 | #define allocfd_set(n) ({\ |
77 | size_t __sfds = sizeof_fd_set (n) + 8; \ | |
78 | void *__res = alloca (__sfds); \ | |
79 | memset (__res, 0, __sfds); \ | |
80 | (fd_set *) __res; \ | |
81 | }) | |
82 | ||
1fd5e000 CF |
83 | #define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n)); |
84 | ||
1fd5e000 CF |
85 | #define set_handle_or_return_if_not_open(h, s) \ |
86 | h = (s)->fh->get_handle (); \ | |
0381fec6 | 87 | if (cygheap->fdtab.not_open ((s)->fd)) \ |
1fd5e000 | 88 | { \ |
169c465a | 89 | (s)->thread_errno = EBADF; \ |
1fd5e000 | 90 | return -1; \ |
45b61a88 | 91 | } |
1fd5e000 | 92 | |
b052bf26 CF |
93 | static int select (int, fd_set *, fd_set *, fd_set *, DWORD); |
94 | ||
95 | /* The main select code. */ | |
c367dfd0 | 96 | extern "C" int |
0072fdab CF |
97 | cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, |
98 | struct timeval *to) | |
1fd5e000 | 99 | { |
45b61a88 CF |
100 | select_printf ("select(%d, %p, %p, %p, %p)", maxfds, readfds, writefds, exceptfds, to); |
101 | ||
45b61a88 | 102 | pthread_testcancel (); |
962f9a2c CF |
103 | int res; |
104 | if (maxfds < 0) | |
105 | { | |
106 | set_errno (EINVAL); | |
107 | res = -1; | |
108 | } | |
1fd5e000 | 109 | else |
962f9a2c CF |
110 | { |
111 | /* Convert to milliseconds or INFINITE if to == NULL */ | |
112 | DWORD ms = to ? (to->tv_sec * 1000) + (to->tv_usec / 1000) : INFINITE; | |
113 | if (ms == 0 && to->tv_usec) | |
114 | ms = 1; /* At least 1 ms granularity */ | |
1fd5e000 | 115 | |
962f9a2c CF |
116 | if (to) |
117 | select_printf ("to->tv_sec %d, to->tv_usec %d, ms %d", to->tv_sec, to->tv_usec, ms); | |
118 | else | |
119 | select_printf ("to NULL, ms %x", ms); | |
120 | ||
121 | res = select (maxfds, readfds ?: allocfd_set (maxfds), | |
b052bf26 CF |
122 | writefds ?: allocfd_set (maxfds), |
123 | exceptfds ?: allocfd_set (maxfds), ms); | |
962f9a2c | 124 | } |
b052bf26 CF |
125 | syscall_printf ("%R = select(%d, %p, %p, %p, %p)", res, maxfds, readfds, |
126 | writefds, exceptfds, to); | |
127 | return res; | |
128 | } | |
1fd5e000 | 129 | |
b052bf26 CF |
130 | /* This function is arbitrarily split out from cygwin_select to avoid odd |
131 | gcc issues with the use of allocfd_set and improper constructor handling | |
132 | for the sel variable. */ | |
133 | static int | |
134 | select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, | |
135 | DWORD ms) | |
136 | { | |
45b61a88 | 137 | int res = select_stuff::select_loop; |
8d661d36 | 138 | |
45b61a88 CF |
139 | LONGLONG start_time = gtod.msecs (); /* Record the current time for later use. */ |
140 | ||
b052bf26 CF |
141 | select_stuff sel; |
142 | sel.return_on_signal = 0; | |
143 | ||
144 | /* Allocate some fd_set structures using the number of fds as a guide. */ | |
145 | fd_set *r = allocfd_set (maxfds); | |
146 | fd_set *w = allocfd_set (maxfds); | |
147 | fd_set *e = allocfd_set (maxfds); | |
148 | ||
45b61a88 CF |
149 | while (res == select_stuff::select_loop) |
150 | { | |
00a31243 CF |
151 | /* Build the select record per fd linked list and set state as |
152 | needed. */ | |
45b61a88 CF |
153 | for (int i = 0; i < maxfds; i++) |
154 | if (!sel.test_and_set (i, readfds, writefds, exceptfds)) | |
155 | { | |
156 | select_printf ("aborting due to test_and_set error"); | |
157 | return -1; /* Invalid fd, maybe? */ | |
158 | } | |
159 | select_printf ("sel.always_ready %d", sel.always_ready); | |
160 | ||
161 | /* Degenerate case. No fds to wait for. Just wait for time to run out | |
162 | or signal to arrive. */ | |
163 | if (sel.start.next == NULL) | |
164 | switch (cygwait (ms)) | |
165 | { | |
4ae63783 | 166 | case WAIT_SIGNALED: |
45b61a88 | 167 | select_printf ("signal received"); |
2f47bbd5 CF |
168 | /* select() is always interrupted by a signal so set EINTR, |
169 | unconditionally, ignoring any SA_RESTART detection by | |
170 | call_signal_handler(). */ | |
171 | _my_tls.call_signal_handler (); | |
172 | set_sig_errno (EINTR); | |
173 | res = select_stuff::select_signalled; | |
45b61a88 | 174 | break; |
4ae63783 | 175 | case WAIT_CANCELED: |
45b61a88 CF |
176 | sel.destroy (); |
177 | pthread::static_cancel_self (); | |
178 | /*NOTREACHED*/ | |
179 | default: | |
180 | res = select_stuff::select_set_zero; /* Set res to zero below. */ | |
181 | break; | |
182 | } | |
183 | else if (sel.always_ready || ms == 0) | |
00a31243 CF |
184 | res = 0; /* Catch any active fds via |
185 | sel.poll() below */ | |
45b61a88 | 186 | else |
00a31243 CF |
187 | res = sel.wait (r, w, e, ms); /* wait for an fd to become |
188 | become active or time out */ | |
962f9a2c | 189 | select_printf ("res %d", res); |
abf1b600 | 190 | if (res >= 0) |
45d7b637 | 191 | { |
45b61a88 CF |
192 | copyfd_set (readfds, r, maxfds); |
193 | copyfd_set (writefds, w, maxfds); | |
194 | copyfd_set (exceptfds, e, maxfds); | |
00a31243 | 195 | /* Actually set the bit mask from sel records */ |
45b61a88 CF |
196 | res = (res == select_stuff::select_set_zero) ? 0 : sel.poll (readfds, writefds, exceptfds); |
197 | } | |
00a31243 CF |
198 | /* Always clean up everything here. If we're looping then build it |
199 | all up again. */ | |
45b61a88 CF |
200 | sel.cleanup (); |
201 | sel.destroy (); | |
00a31243 | 202 | /* Recalculate the time remaining to wait if we are going to be looping. */ |
45b61a88 CF |
203 | if (res == select_stuff::select_loop && ms != INFINITE) |
204 | { | |
205 | select_printf ("recalculating ms"); | |
206 | LONGLONG now = gtod.msecs (); | |
207 | if (now > (start_time + ms)) | |
962f9a2c CF |
208 | { |
209 | select_printf ("timed out after verification"); | |
4c36016b | 210 | res = 0; |
962f9a2c | 211 | } |
45b61a88 CF |
212 | else |
213 | { | |
214 | ms -= (now - start_time); | |
215 | start_time = now; | |
216 | select_printf ("ms now %u", ms); | |
217 | } | |
45d7b637 | 218 | } |
d4f82450 CF |
219 | } |
220 | ||
7c15768a CF |
221 | if (res < -1) |
222 | res = -1; | |
d4f82450 | 223 | return res; |
1fd5e000 CF |
224 | } |
225 | ||
d02099f2 CV |
226 | extern "C" int |
227 | pselect(int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, | |
228 | const struct timespec *ts, const sigset_t *set) | |
229 | { | |
230 | struct timeval tv; | |
70300fdb | 231 | sigset_t oldset = _my_tls.sigmask; |
d02099f2 | 232 | |
893ac8e0 CF |
233 | myfault efault; |
234 | if (efault.faulted (EFAULT)) | |
235 | return -1; | |
d02099f2 CV |
236 | if (ts) |
237 | { | |
d02099f2 CV |
238 | tv.tv_sec = ts->tv_sec; |
239 | tv.tv_usec = ts->tv_nsec / 1000; | |
240 | } | |
241 | if (set) | |
962f9a2c | 242 | set_signal_mask (_my_tls.sigmask, *set); |
d02099f2 | 243 | int ret = cygwin_select (maxfds, readfds, writefds, exceptfds, |
05726ddd | 244 | ts ? &tv : NULL); |
d02099f2 | 245 | if (set) |
962f9a2c | 246 | set_signal_mask (_my_tls.sigmask, oldset); |
d02099f2 CV |
247 | return ret; |
248 | } | |
249 | ||
5835f2cf CF |
250 | /* Call cleanup functions for all inspected fds. Gets rid of any |
251 | executing threads. */ | |
252 | void | |
253 | select_stuff::cleanup () | |
1fd5e000 CF |
254 | { |
255 | select_record *s = &start; | |
256 | ||
257 | select_printf ("calling cleanup routines"); | |
258 | while ((s = s->next)) | |
259 | if (s->cleanup) | |
5835f2cf CF |
260 | { |
261 | s->cleanup (s, this); | |
262 | s->cleanup = NULL; | |
263 | } | |
264 | } | |
1fd5e000 | 265 | |
5835f2cf | 266 | /* Destroy all storage associated with select stuff. */ |
781822a6 CV |
267 | inline void |
268 | select_stuff::destroy () | |
5835f2cf | 269 | { |
45b61a88 | 270 | select_record *s; |
1fd5e000 CF |
271 | select_record *snext = start.next; |
272 | ||
273 | select_printf ("deleting select records"); | |
274 | while ((s = snext)) | |
275 | { | |
276 | snext = s->next; | |
277 | delete s; | |
278 | } | |
45b61a88 | 279 | start.next = NULL; |
1fd5e000 CF |
280 | } |
281 | ||
781822a6 CV |
282 | select_stuff::~select_stuff () |
283 | { | |
284 | cleanup (); | |
285 | destroy (); | |
286 | } | |
287 | ||
4a84997a CF |
288 | #ifdef DEBUGGING |
289 | void | |
290 | select_record::dump_select_record () | |
291 | { | |
292 | select_printf ("fd %d, h %p, fh %p, thread_errno %d, windows_handle %p", | |
293 | fd, h, fh, thread_errno, windows_handle); | |
294 | select_printf ("read_ready %d, write_ready %d, except_ready %d", | |
295 | read_ready, write_ready, except_ready); | |
296 | select_printf ("read_selected %d, write_selected %d, except_selected %d, except_on_write %d", | |
297 | read_selected, write_selected, except_selected, except_on_write); | |
298 | ||
299 | select_printf ("startup %p, peek %p, verify %p cleanup %p, next %p", | |
300 | startup, peek, verify, cleanup, next); | |
301 | } | |
302 | #endif /*DEBUGGING*/ | |
303 | ||
1fd5e000 | 304 | /* Add a record to the select chain */ |
b4fa8164 | 305 | bool |
1fd5e000 CF |
306 | select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds, |
307 | fd_set *exceptfds) | |
308 | { | |
b4fa8164 CF |
309 | if (!UNIX_FD_ISSET (i, readfds) && !UNIX_FD_ISSET (i, writefds) |
310 | && ! UNIX_FD_ISSET (i, exceptfds)) | |
311 | return true; | |
312 | ||
6dadfa56 | 313 | select_record *s = new select_record; |
b4fa8164 CF |
314 | if (!s) |
315 | return false; | |
316 | ||
317 | s->next = start.next; | |
318 | start.next = s; | |
319 | ||
320 | if (UNIX_FD_ISSET (i, readfds) && !cygheap->fdtab.select_read (i, this)) | |
321 | goto err; | |
322 | if (UNIX_FD_ISSET (i, writefds) && !cygheap->fdtab.select_write (i, this)) | |
323 | goto err; | |
324 | if (UNIX_FD_ISSET (i, exceptfds) && !cygheap->fdtab.select_except (i, this)) | |
325 | goto err; /* error */ | |
1fd5e000 CF |
326 | |
327 | if (s->read_ready || s->write_ready || s->except_ready) | |
476dfb65 | 328 | always_ready = true; |
1fd5e000 | 329 | |
8cb359d9 | 330 | if (s->windows_handle) |
476dfb65 | 331 | windows_used = true; |
1fd5e000 | 332 | |
4a84997a CF |
333 | #ifdef DEBUGGING |
334 | s->dump_select_record (); | |
335 | #endif | |
b4fa8164 CF |
336 | return true; |
337 | ||
338 | err: | |
339 | start.next = s->next; | |
340 | delete s; | |
341 | return false; | |
1fd5e000 CF |
342 | } |
343 | ||
1fd5e000 | 344 | /* The heart of select. Waits for an fd to do something interesting. */ |
45b61a88 | 345 | select_stuff::wait_states |
1fd5e000 CF |
346 | select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, |
347 | DWORD ms) | |
348 | { | |
aefbf388 | 349 | HANDLE w4[MAXIMUM_WAIT_OBJECTS]; |
1fd5e000 | 350 | select_record *s = &start; |
45b61a88 | 351 | DWORD m = 0; |
1fd5e000 | 352 | |
44aa2292 | 353 | set_signal_arrived here (w4[m++]); |
781822a6 | 354 | if ((w4[m] = pthread::get_cancel_event ()) != NULL) |
45b61a88 | 355 | m++; |
781822a6 | 356 | |
7c15768a | 357 | DWORD startfds = m; |
1fd5e000 CF |
358 | /* Loop through the select chain, starting up anything appropriate and |
359 | counting the number of active fds. */ | |
360 | while ((s = s->next)) | |
361 | { | |
fe3db6cc | 362 | if (m >= MAXIMUM_WAIT_OBJECTS) |
b5ae313a | 363 | { |
80a429d2 | 364 | set_sig_errno (EINVAL); |
45b61a88 | 365 | return select_error; |
b5ae313a | 366 | } |
1fd5e000 CF |
367 | if (!s->startup (s, this)) |
368 | { | |
169c465a | 369 | s->set_select_errno (); |
45b61a88 | 370 | return select_error; |
1fd5e000 | 371 | } |
45b61a88 | 372 | if (s->h != NULL) |
7c15768a CF |
373 | { |
374 | for (DWORD i = startfds; i < m; i++) | |
375 | if (w4[i] == s->h) | |
376 | goto next_while; | |
377 | w4[m++] = s->h; | |
378 | } | |
379 | next_while:; | |
1fd5e000 CF |
380 | } |
381 | ||
0072fdab | 382 | debug_printf ("m %d, ms %u", m, ms); |
45b61a88 CF |
383 | |
384 | DWORD wait_ret; | |
385 | if (!windows_used) | |
386 | wait_ret = WaitForMultipleObjects (m, w4, FALSE, ms); | |
387 | else | |
388 | /* Using MWMO_INPUTAVAILABLE is the officially supported solution for | |
389 | the problem that the call to PeekMessage disarms the queue state | |
390 | so that a subsequent MWFMO hangs, even if there are still messages | |
391 | in the queue. */ | |
392 | wait_ret = MsgWaitForMultipleObjectsEx (m, w4, ms, | |
393 | QS_ALLINPUT | QS_ALLPOSTMESSAGE, | |
394 | MWMO_INPUTAVAILABLE); | |
395 | select_printf ("wait_ret %d. verifying", wait_ret); | |
396 | ||
397 | wait_states res; | |
398 | switch (wait_ret) | |
1fd5e000 | 399 | { |
45b61a88 CF |
400 | case WAIT_OBJECT_0: |
401 | select_printf ("signal received"); | |
00a31243 CF |
402 | /* Need to get rid of everything when a signal occurs since we can't |
403 | be assured that a signal handler won't jump out of select entirely. */ | |
45b61a88 CF |
404 | cleanup (); |
405 | destroy (); | |
2f47bbd5 CF |
406 | /* select() is always interrupted by a signal so set EINTR, |
407 | unconditionally, ignoring any SA_RESTART detection by | |
408 | call_signal_handler(). */ | |
409 | _my_tls.call_signal_handler (); | |
410 | set_sig_errno (EINTR); | |
411 | res = select_signalled; /* Cause loop exit in cygwin_select */ | |
45b61a88 CF |
412 | break; |
413 | case WAIT_FAILED: | |
63d9f293 | 414 | system_printf ("WaitForMultipleObjects failed, %E"); |
45b61a88 CF |
415 | s = &start; |
416 | s->set_select_errno (); | |
417 | res = select_error; | |
418 | break; | |
419 | case WAIT_TIMEOUT: | |
420 | select_printf ("timed out"); | |
abf1b600 | 421 | res = select_set_zero; |
45b61a88 CF |
422 | break; |
423 | case WAIT_OBJECT_0 + 1: | |
424 | if (startfds > 1) | |
425 | { | |
8978381c | 426 | cleanup (); |
45b61a88 CF |
427 | destroy (); |
428 | pthread::static_cancel_self (); | |
429 | /*NOTREACHED*/ | |
45d7b637 | 430 | } |
45b61a88 CF |
431 | /* Fall through. This wasn't a cancel event. It was just a normal object |
432 | to wait for. */ | |
433 | default: | |
1fd5e000 | 434 | s = &start; |
45b61a88 | 435 | bool gotone = false; |
11a36faa | 436 | /* Some types of objects (e.g., consoles) wake up on "inappropriate" events |
9c510edc | 437 | like mouse movements. The verify function will detect these situations. |
915d1824 CF |
438 | If it returns false, then this wakeup was a false alarm and we should go |
439 | back to waiting. */ | |
1fd5e000 | 440 | while ((s = s->next)) |
169c465a CF |
441 | if (s->saw_error ()) |
442 | { | |
443 | set_errno (s->saw_error ()); | |
45b61a88 CF |
444 | res = select_error; /* Somebody detected an error */ |
445 | goto out; | |
169c465a | 446 | } |
fc25f200 CF |
447 | else if ((((wait_ret >= m && s->windows_handle) || s->h == w4[wait_ret])) |
448 | && s->verify (s, readfds, writefds, exceptfds)) | |
476dfb65 | 449 | gotone = true; |
1fd5e000 | 450 | |
45b61a88 CF |
451 | if (!gotone) |
452 | res = select_loop; | |
453 | else | |
454 | res = select_ok; | |
1fd5e000 | 455 | select_printf ("gotone %d", gotone); |
45b61a88 | 456 | break; |
1fd5e000 | 457 | } |
1fd5e000 | 458 | out: |
8d661d36 CF |
459 | select_printf ("returning %d", res); |
460 | return res; | |
1fd5e000 CF |
461 | } |
462 | ||
463 | static int | |
464 | set_bits (select_record *me, fd_set *readfds, fd_set *writefds, | |
711ded6d | 465 | fd_set *exceptfds) |
1fd5e000 CF |
466 | { |
467 | int ready = 0; | |
ef82f76c | 468 | fhandler_socket *sock; |
1fd5e000 CF |
469 | select_printf ("me %p, testing fd %d (%s)", me, me->fd, me->fh->get_name ()); |
470 | if (me->read_selected && me->read_ready) | |
471 | { | |
472 | UNIX_FD_SET (me->fd, readfds); | |
473 | ready++; | |
474 | } | |
475 | if (me->write_selected && me->write_ready) | |
476 | { | |
477 | UNIX_FD_SET (me->fd, writefds); | |
ef82f76c CV |
478 | if (me->except_on_write && (sock = me->fh->is_socket ())) |
479 | { | |
a6099ff8 CV |
480 | /* Special AF_LOCAL handling. */ |
481 | if (!me->read_ready && sock->connect_state () == connect_pending | |
fd5879c1 CV |
482 | && sock->af_local_connect ()) |
483 | { | |
484 | if (me->read_selected) | |
485 | UNIX_FD_SET (me->fd, readfds); | |
486 | sock->connect_state (connect_failed); | |
487 | } | |
488 | else | |
489 | sock->connect_state (connected); | |
ef82f76c | 490 | } |
1fd5e000 CF |
491 | ready++; |
492 | } | |
fd5879c1 | 493 | if (me->except_selected && me->except_ready) |
1fd5e000 | 494 | { |
fd5879c1 | 495 | UNIX_FD_SET (me->fd, exceptfds); |
1fd5e000 CF |
496 | ready++; |
497 | } | |
498 | select_printf ("ready %d", ready); | |
499 | return ready; | |
500 | } | |
501 | ||
476dfb65 CF |
502 | /* Poll every fd in the select chain. Set appropriate fd in mask. */ |
503 | int | |
504 | select_stuff::poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds) | |
505 | { | |
506 | int n = 0; | |
507 | select_record *s = &start; | |
508 | while ((s = s->next)) | |
509 | n += (!s->peek || s->peek (s, true)) ? | |
510 | set_bits (s, readfds, writefds, exceptfds) : 0; | |
476dfb65 CF |
511 | return n; |
512 | } | |
513 | ||
1fd5e000 | 514 | static int |
9cec3d45 | 515 | verify_true (select_record *, fd_set *, fd_set *, fd_set *) |
1fd5e000 CF |
516 | { |
517 | return 1; | |
518 | } | |
519 | ||
520 | static int | |
521 | verify_ok (select_record *me, fd_set *readfds, fd_set *writefds, | |
522 | fd_set *exceptfds) | |
523 | { | |
524 | return set_bits (me, readfds, writefds, exceptfds); | |
525 | } | |
526 | ||
527 | static int | |
9cec3d45 | 528 | no_startup (select_record *, select_stuff *) |
1fd5e000 CF |
529 | { |
530 | return 1; | |
531 | } | |
532 | ||
533 | static int | |
534 | no_verify (select_record *, fd_set *, fd_set *, fd_set *) | |
535 | { | |
536 | return 0; | |
537 | } | |
538 | ||
a7a12477 CF |
539 | static int |
540 | pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing) | |
541 | { | |
542 | IO_STATUS_BLOCK iosb = {0}; | |
543 | FILE_PIPE_LOCAL_INFORMATION fpli = {0}; | |
544 | ||
ee766fda CF |
545 | bool res; |
546 | if (fh->has_ongoing_io ()) | |
547 | res = false; | |
548 | else if (NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli), | |
549 | FilePipeLocalInformation)) | |
a7a12477 | 550 | { |
ee766fda CF |
551 | /* If NtQueryInformationFile fails, optimistically assume the |
552 | pipe is writable. This could happen if we somehow | |
553 | inherit a pipe that doesn't permit FILE_READ_ATTRIBUTES | |
554 | access on the write end. */ | |
555 | select_printf ("fd %d, %s, NtQueryInformationFile failed", | |
556 | fd, fh->get_name ()); | |
557 | res = writing ? true : -1; | |
558 | } | |
559 | else if (!writing) | |
560 | { | |
561 | paranoid_printf ("fd %d, %s, read avail %u", fd, fh->get_name (), | |
562 | fpli.ReadDataAvailable); | |
563 | res = !!fpli.ReadDataAvailable; | |
a7a12477 | 564 | } |
ee766fda CF |
565 | else if ((res = (fpli.WriteQuotaAvailable = (fpli.OutboundQuota - |
566 | fpli.ReadDataAvailable)))) | |
567 | /* If there is anything available in the pipe buffer then signal | |
568 | that. This means that a pipe could still block since you could | |
569 | be trying to write more to the pipe than is available in the | |
570 | buffer but that is the hazard of select(). */ | |
571 | paranoid_printf ("fd %d, %s, write: size %lu, avail %lu", fd, | |
572 | fh->get_name (), fpli.OutboundQuota, | |
573 | fpli.WriteQuotaAvailable); | |
574 | else if ((res = (fpli.OutboundQuota < PIPE_BUF && | |
575 | fpli.WriteQuotaAvailable == fpli.OutboundQuota))) | |
576 | /* If we somehow inherit a tiny pipe (size < PIPE_BUF), then consider | |
577 | the pipe writable only if it is completely empty, to minimize the | |
578 | probability that a subsequent write will block. */ | |
579 | select_printf ("fd, %s, write tiny pipe: size %lu, avail %lu", | |
580 | fd, fh->get_name (), fpli.OutboundQuota, | |
581 | fpli.WriteQuotaAvailable); | |
665f9a59 | 582 | return res ?: -!!(fpli.NamedPipeState & FILE_PIPE_CLOSING_STATE); |
a7a12477 CF |
583 | } |
584 | ||
1fd5e000 | 585 | static int |
476dfb65 | 586 | peek_pipe (select_record *s, bool from_select) |
1fd5e000 | 587 | { |
19085182 CF |
588 | HANDLE h; |
589 | set_handle_or_return_if_not_open (h, s); | |
590 | ||
1fd5e000 | 591 | int gotone = 0; |
19085182 | 592 | fhandler_base *fh = (fhandler_base *) s->fh; |
1fd5e000 | 593 | |
a7a12477 CF |
594 | DWORD dev = fh->get_device (); |
595 | if (s->read_selected && dev != FH_PIPEW) | |
1fd5e000 | 596 | { |
41010c6a CF |
597 | if (s->read_ready) |
598 | { | |
6644c628 | 599 | select_printf ("%s, already ready for read", fh->get_name ()); |
41010c6a CF |
600 | gotone = 1; |
601 | goto out; | |
602 | } | |
1fd5e000 | 603 | |
c0ac34fd | 604 | switch (fh->get_major ()) |
3f0b4935 | 605 | { |
38d732a1 | 606 | case DEV_PTYM_MAJOR: |
7b03b0d8 CF |
607 | { |
608 | fhandler_pty_master *fhm = (fhandler_pty_master *) fh; | |
609 | fhm->flush_to_slave (); | |
610 | if (fhm->need_nl) | |
611 | { | |
612 | gotone = s->read_ready = true; | |
613 | goto out; | |
614 | } | |
615 | } | |
c5d03f3d CF |
616 | break; |
617 | default: | |
476dfb65 | 618 | if (fh->get_readahead_valid ()) |
c5d03f3d CF |
619 | { |
620 | select_printf ("readahead"); | |
915d1824 | 621 | gotone = s->read_ready = true; |
c5d03f3d CF |
622 | goto out; |
623 | } | |
3f0b4935 | 624 | } |
35f879a6 CF |
625 | |
626 | if (fh->bg_check (SIGTTIN) <= bg_eof) | |
627 | { | |
915d1824 | 628 | gotone = s->read_ready = true; |
35f879a6 CF |
629 | goto out; |
630 | } | |
a7a12477 | 631 | int n = pipe_data_available (s->fd, fh, h, false); |
1fd5e000 | 632 | |
a7a12477 | 633 | if (n < 0) |
d584454c | 634 | { |
a7a12477 CF |
635 | select_printf ("read: %s, n %d", fh->get_name (), n); |
636 | if (s->except_selected) | |
637 | gotone += s->except_ready = true; | |
638 | if (s->read_selected) | |
639 | gotone += s->read_ready = true; | |
d584454c | 640 | } |
a7a12477 | 641 | else if (n > 0) |
d584454c | 642 | { |
a7a12477 CF |
643 | select_printf ("read: %s, ready for read: avail %d", fh->get_name (), n); |
644 | gotone += s->read_ready = true; | |
645 | } | |
646 | if (!gotone && s->fh->hit_eof ()) | |
647 | { | |
648 | select_printf ("read: %s, saw EOF", fh->get_name ()); | |
649 | if (s->except_selected) | |
650 | gotone += s->except_ready = true; | |
651 | if (s->read_selected) | |
652 | gotone += s->read_ready = true; | |
d584454c | 653 | } |
6644c628 CF |
654 | } |
655 | ||
a7a12477 CF |
656 | out: |
657 | if (s->write_selected && dev != FH_PIPER) | |
658 | { | |
659 | gotone += s->write_ready = pipe_data_available (s->fd, fh, h, true); | |
660 | select_printf ("write: %s, gotone %d", fh->get_name (), gotone); | |
661 | } | |
6644c628 | 662 | return gotone; |
1fd5e000 CF |
663 | } |
664 | ||
1fd5e000 CF |
665 | static int start_thread_pipe (select_record *me, select_stuff *stuff); |
666 | ||
1fd5e000 CF |
667 | static DWORD WINAPI |
668 | thread_pipe (void *arg) | |
669 | { | |
b4fa8164 | 670 | select_pipe_info *pi = (select_pipe_info *) arg; |
cfa88257 | 671 | DWORD sleep_time = 0; |
19085182 | 672 | bool looping = true; |
1fd5e000 | 673 | |
19085182 | 674 | while (looping) |
1fd5e000 | 675 | { |
19085182 | 676 | for (select_record *s = pi->start; (s = s->next); ) |
1fd5e000 CF |
677 | if (s->startup == start_thread_pipe) |
678 | { | |
476dfb65 | 679 | if (peek_pipe (s, true)) |
19085182 | 680 | looping = false; |
b4fa8164 | 681 | if (pi->stop_thread) |
1fd5e000 CF |
682 | { |
683 | select_printf ("stopping"); | |
19085182 CF |
684 | looping = false; |
685 | break; | |
1fd5e000 CF |
686 | } |
687 | } | |
19085182 | 688 | if (!looping) |
1fd5e000 | 689 | break; |
b4c53a7c CV |
690 | Sleep (sleep_time >> 3); |
691 | if (sleep_time < 80) | |
9c9959a5 | 692 | ++sleep_time; |
19085182 CF |
693 | if (pi->stop_thread) |
694 | break; | |
1fd5e000 | 695 | } |
1fd5e000 CF |
696 | return 0; |
697 | } | |
698 | ||
699 | static int | |
700 | start_thread_pipe (select_record *me, select_stuff *stuff) | |
701 | { | |
b4fa8164 CF |
702 | select_pipe_info *pi = stuff->device_specific_pipe; |
703 | if (pi->start) | |
704 | me->h = *((select_pipe_info *) stuff->device_specific_pipe)->thread; | |
705 | else | |
1fd5e000 | 706 | { |
b4fa8164 CF |
707 | pi->start = &stuff->start; |
708 | pi->stop_thread = false; | |
b9aa8149 | 709 | pi->thread = new cygthread (thread_pipe, pi, "pipesel"); |
b4fa8164 CF |
710 | me->h = *pi->thread; |
711 | if (!me->h) | |
712 | return 0; | |
1fd5e000 | 713 | } |
1fd5e000 CF |
714 | return 1; |
715 | } | |
716 | ||
717 | static void | |
9cec3d45 | 718 | pipe_cleanup (select_record *, select_stuff *stuff) |
1fd5e000 | 719 | { |
19085182 | 720 | select_pipe_info *pi = (select_pipe_info *) stuff->device_specific_pipe; |
693581e4 CF |
721 | if (!pi) |
722 | return; | |
723 | if (pi->thread) | |
1fd5e000 | 724 | { |
19085182 CF |
725 | pi->stop_thread = true; |
726 | pi->thread->detach (); | |
1fd5e000 | 727 | } |
693581e4 CF |
728 | delete pi; |
729 | stuff->device_specific_pipe = NULL; | |
1fd5e000 CF |
730 | } |
731 | ||
732 | select_record * | |
b4fa8164 | 733 | fhandler_pipe::select_read (select_stuff *ss) |
1fd5e000 | 734 | { |
b4fa8164 CF |
735 | if (!ss->device_specific_pipe |
736 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
737 | return NULL; | |
b4fa8164 CF |
738 | |
739 | select_record *s = ss->start.next; | |
1fd5e000 | 740 | s->startup = start_thread_pipe; |
1229d4f4 | 741 | s->peek = peek_pipe; |
1fd5e000 | 742 | s->verify = verify_ok; |
6644c628 | 743 | s->cleanup = pipe_cleanup; |
476dfb65 CF |
744 | s->read_selected = true; |
745 | s->read_ready = false; | |
1fd5e000 CF |
746 | return s; |
747 | } | |
748 | ||
749 | select_record * | |
b4fa8164 | 750 | fhandler_pipe::select_write (select_stuff *ss) |
1fd5e000 | 751 | { |
b4fa8164 CF |
752 | if (!ss->device_specific_pipe |
753 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
754 | return NULL; | |
b4fa8164 | 755 | select_record *s = ss->start.next; |
6644c628 | 756 | s->startup = start_thread_pipe; |
476dfb65 | 757 | s->peek = peek_pipe; |
6644c628 CF |
758 | s->verify = verify_ok; |
759 | s->cleanup = pipe_cleanup; | |
476dfb65 | 760 | s->write_selected = true; |
6644c628 | 761 | s->write_ready = false; |
1fd5e000 CF |
762 | return s; |
763 | } | |
764 | ||
765 | select_record * | |
b4fa8164 | 766 | fhandler_pipe::select_except (select_stuff *ss) |
1fd5e000 | 767 | { |
b4fa8164 CF |
768 | if (!ss->device_specific_pipe |
769 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
770 | return NULL; | |
b4fa8164 | 771 | select_record *s = ss->start.next; |
1fd5e000 | 772 | s->startup = start_thread_pipe; |
476dfb65 | 773 | s->peek = peek_pipe; |
1fd5e000 CF |
774 | s->verify = verify_ok; |
775 | s->cleanup = pipe_cleanup; | |
476dfb65 CF |
776 | s->except_selected = true; |
777 | s->except_ready = false; | |
1fd5e000 CF |
778 | return s; |
779 | } | |
780 | ||
c7ef20e7 | 781 | select_record * |
b4fa8164 | 782 | fhandler_fifo::select_read (select_stuff *ss) |
c7ef20e7 | 783 | { |
4c9a7726 CF |
784 | if (!ss->device_specific_pipe |
785 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
786 | return NULL; | |
b4fa8164 | 787 | select_record *s = ss->start.next; |
c7ef20e7 CF |
788 | s->startup = start_thread_pipe; |
789 | s->peek = peek_pipe; | |
790 | s->verify = verify_ok; | |
791 | s->cleanup = pipe_cleanup; | |
792 | s->read_selected = true; | |
793 | s->read_ready = false; | |
794 | return s; | |
795 | } | |
796 | ||
797 | select_record * | |
b4fa8164 | 798 | fhandler_fifo::select_write (select_stuff *ss) |
c7ef20e7 | 799 | { |
4c9a7726 CF |
800 | if (!ss->device_specific_pipe |
801 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
802 | return NULL; | |
b4fa8164 | 803 | select_record *s = ss->start.next; |
c7ef20e7 CF |
804 | s->startup = start_thread_pipe; |
805 | s->peek = peek_pipe; | |
806 | s->verify = verify_ok; | |
807 | s->cleanup = pipe_cleanup; | |
808 | s->write_selected = true; | |
809 | s->write_ready = false; | |
810 | return s; | |
811 | } | |
812 | ||
813 | select_record * | |
b4fa8164 | 814 | fhandler_fifo::select_except (select_stuff *ss) |
c7ef20e7 | 815 | { |
4c9a7726 CF |
816 | if (!ss->device_specific_pipe |
817 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
818 | return NULL; | |
b4fa8164 | 819 | select_record *s = ss->start.next; |
c7ef20e7 CF |
820 | s->startup = start_thread_pipe; |
821 | s->peek = peek_pipe; | |
822 | s->verify = verify_ok; | |
823 | s->cleanup = pipe_cleanup; | |
824 | s->except_selected = true; | |
825 | s->except_ready = false; | |
826 | return s; | |
827 | } | |
828 | ||
1fd5e000 | 829 | static int |
476dfb65 | 830 | peek_console (select_record *me, bool) |
1fd5e000 | 831 | { |
a9867e1b | 832 | extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *); |
1d380f59 | 833 | fhandler_console *fh = (fhandler_console *) me->fh; |
1fd5e000 CF |
834 | |
835 | if (!me->read_selected) | |
836 | return me->write_ready; | |
837 | ||
476dfb65 | 838 | if (fh->get_readahead_valid ()) |
1fd5e000 CF |
839 | { |
840 | select_printf ("readahead"); | |
915d1824 | 841 | return me->read_ready = true; |
1fd5e000 CF |
842 | } |
843 | ||
41010c6a CF |
844 | if (me->read_ready) |
845 | { | |
846 | select_printf ("already ready"); | |
847 | return 1; | |
848 | } | |
849 | ||
1fd5e000 CF |
850 | INPUT_RECORD irec; |
851 | DWORD events_read; | |
852 | HANDLE h; | |
a9867e1b | 853 | char tmpbuf[17]; |
1fd5e000 CF |
854 | set_handle_or_return_if_not_open (h, me); |
855 | ||
856 | for (;;) | |
a7cde2b9 | 857 | if (fh->bg_check (SIGTTIN) <= bg_eof) |
915d1824 | 858 | return me->read_ready = true; |
1fd5e000 CF |
859 | else if (!PeekConsoleInput (h, &irec, 1, &events_read) || !events_read) |
860 | break; | |
861 | else | |
862 | { | |
d984eb88 | 863 | fh->send_winch_maybe (); |
c060edba | 864 | if (irec.EventType == KEY_EVENT) |
d80999a1 | 865 | { |
c060edba CF |
866 | if (irec.Event.KeyEvent.bKeyDown |
867 | && (irec.Event.KeyEvent.uChar.AsciiChar | |
868 | || get_nonascii_key (irec, tmpbuf))) | |
915d1824 | 869 | return me->read_ready = true; |
d80999a1 | 870 | } |
c060edba CF |
871 | else |
872 | { | |
c060edba | 873 | if (irec.EventType == MOUSE_EVENT |
beeae482 CV |
874 | && fh->mouse_aware (irec.Event.MouseEvent)) |
875 | return me->read_ready = true; | |
876 | if (irec.EventType == FOCUS_EVENT && fh->focus_aware ()) | |
c060edba CF |
877 | return me->read_ready = true; |
878 | } | |
1fd5e000 CF |
879 | |
880 | /* Read and discard the event */ | |
881 | ReadConsoleInput (h, &irec, 1, &events_read); | |
882 | } | |
883 | ||
884 | return me->write_ready; | |
885 | } | |
9c510edc | 886 | |
763f09b9 CF |
887 | static int |
888 | verify_console (select_record *me, fd_set *rfds, fd_set *wfds, | |
889 | fd_set *efds) | |
890 | { | |
891 | return peek_console (me, true); | |
892 | } | |
893 | ||
1fd5e000 | 894 | |
1fd5e000 | 895 | select_record * |
b4fa8164 | 896 | fhandler_console::select_read (select_stuff *ss) |
1fd5e000 | 897 | { |
b4fa8164 CF |
898 | select_record *s = ss->start.next; |
899 | if (!s->startup) | |
1fd5e000 | 900 | { |
1fd5e000 | 901 | s->startup = no_startup; |
763f09b9 | 902 | s->verify = verify_console; |
e5dd8811 | 903 | set_cursor_maybe (); |
1fd5e000 CF |
904 | } |
905 | ||
1229d4f4 | 906 | s->peek = peek_console; |
1fd5e000 | 907 | s->h = get_handle (); |
476dfb65 CF |
908 | s->read_selected = true; |
909 | s->read_ready = false; | |
1fd5e000 CF |
910 | return s; |
911 | } | |
912 | ||
913 | select_record * | |
b4fa8164 | 914 | fhandler_console::select_write (select_stuff *ss) |
1fd5e000 | 915 | { |
b4fa8164 CF |
916 | select_record *s = ss->start.next; |
917 | if (!s->startup) | |
1fd5e000 | 918 | { |
1fd5e000 | 919 | s->startup = no_startup; |
1fd5e000 | 920 | s->verify = no_verify; |
e5dd8811 | 921 | set_cursor_maybe (); |
1fd5e000 CF |
922 | } |
923 | ||
476dfb65 CF |
924 | s->peek = peek_console; |
925 | s->write_selected = true; | |
926 | s->write_ready = true; | |
1fd5e000 CF |
927 | return s; |
928 | } | |
929 | ||
930 | select_record * | |
b4fa8164 | 931 | fhandler_console::select_except (select_stuff *ss) |
1fd5e000 | 932 | { |
b4fa8164 CF |
933 | select_record *s = ss->start.next; |
934 | if (!s->startup) | |
1fd5e000 | 935 | { |
1fd5e000 | 936 | s->startup = no_startup; |
1fd5e000 | 937 | s->verify = no_verify; |
e5dd8811 | 938 | set_cursor_maybe (); |
1fd5e000 CF |
939 | } |
940 | ||
476dfb65 CF |
941 | s->peek = peek_console; |
942 | s->except_selected = true; | |
943 | s->except_ready = false; | |
1fd5e000 CF |
944 | return s; |
945 | } | |
946 | ||
1fd5e000 | 947 | select_record * |
c75b5b2d | 948 | fhandler_pty_common::select_read (select_stuff *ss) |
1fd5e000 | 949 | { |
e446d6d0 CF |
950 | if (!ss->device_specific_pipe |
951 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
952 | return NULL; | |
953 | ||
954 | select_record *s = ss->start.next; | |
955 | s->startup = start_thread_pipe; | |
956 | s->peek = peek_pipe; | |
957 | s->verify = verify_ok; | |
958 | s->cleanup = pipe_cleanup; | |
959 | s->read_selected = true; | |
960 | s->read_ready = false; | |
961 | return s; | |
1fd5e000 CF |
962 | } |
963 | ||
964 | select_record * | |
c75b5b2d | 965 | fhandler_pty_common::select_write (select_stuff *ss) |
1fd5e000 | 966 | { |
e446d6d0 CF |
967 | if (!ss->device_specific_pipe |
968 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
969 | return NULL; | |
970 | select_record *s = ss->start.next; | |
971 | s->startup = start_thread_pipe; | |
972 | s->peek = peek_pipe; | |
973 | s->verify = verify_ok; | |
974 | s->cleanup = pipe_cleanup; | |
975 | s->write_selected = true; | |
976 | s->write_ready = false; | |
977 | return s; | |
1fd5e000 CF |
978 | } |
979 | ||
980 | select_record * | |
c75b5b2d | 981 | fhandler_pty_common::select_except (select_stuff *ss) |
1fd5e000 | 982 | { |
e446d6d0 CF |
983 | if (!ss->device_specific_pipe |
984 | && (ss->device_specific_pipe = new select_pipe_info) == NULL) | |
985 | return NULL; | |
986 | select_record *s = ss->start.next; | |
987 | s->startup = start_thread_pipe; | |
988 | s->peek = peek_pipe; | |
989 | s->verify = verify_ok; | |
990 | s->cleanup = pipe_cleanup; | |
991 | s->except_selected = true; | |
992 | s->except_ready = false; | |
993 | return s; | |
1fd5e000 CF |
994 | } |
995 | ||
5e8e21d9 ED |
996 | static int |
997 | verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds, | |
998 | fd_set *exceptfds) | |
999 | { | |
bd139e52 | 1000 | if (IsEventSignalled (me->h)) |
915d1824 | 1001 | me->read_ready = true; |
5e8e21d9 ED |
1002 | return set_bits (me, readfds, writefds, exceptfds); |
1003 | } | |
1004 | ||
1005 | select_record * | |
c75b5b2d | 1006 | fhandler_pty_slave::select_read (select_stuff *ss) |
5e8e21d9 | 1007 | { |
b4fa8164 | 1008 | select_record *s = ss->start.next; |
5e8e21d9 ED |
1009 | s->h = input_available_event; |
1010 | s->startup = no_startup; | |
1229d4f4 | 1011 | s->peek = peek_pipe; |
5e8e21d9 | 1012 | s->verify = verify_tty_slave; |
476dfb65 CF |
1013 | s->read_selected = true; |
1014 | s->read_ready = false; | |
5e8e21d9 ED |
1015 | s->cleanup = NULL; |
1016 | return s; | |
1017 | } | |
1018 | ||
1fd5e000 | 1019 | select_record * |
b4fa8164 | 1020 | fhandler_dev_null::select_read (select_stuff *ss) |
1fd5e000 | 1021 | { |
b4fa8164 CF |
1022 | select_record *s = ss->start.next; |
1023 | if (!s->startup) | |
1fd5e000 | 1024 | { |
1fd5e000 | 1025 | s->startup = no_startup; |
1fd5e000 CF |
1026 | s->verify = no_verify; |
1027 | } | |
1028 | s->h = get_handle (); | |
476dfb65 CF |
1029 | s->read_selected = true; |
1030 | s->read_ready = true; | |
1fd5e000 CF |
1031 | return s; |
1032 | } | |
1033 | ||
1034 | select_record * | |
b4fa8164 | 1035 | fhandler_dev_null::select_write (select_stuff *ss) |
1fd5e000 | 1036 | { |
b4fa8164 CF |
1037 | select_record *s = ss->start.next; |
1038 | if (!s->startup) | |
1fd5e000 | 1039 | { |
1fd5e000 | 1040 | s->startup = no_startup; |
1fd5e000 CF |
1041 | s->verify = no_verify; |
1042 | } | |
1043 | s->h = get_handle (); | |
476dfb65 CF |
1044 | s->write_selected = true; |
1045 | s->write_ready = true; | |
1fd5e000 CF |
1046 | return s; |
1047 | } | |
1048 | ||
1049 | select_record * | |
b4fa8164 | 1050 | fhandler_dev_null::select_except (select_stuff *ss) |
1fd5e000 | 1051 | { |
b4fa8164 CF |
1052 | select_record *s = ss->start.next; |
1053 | if (!s->startup) | |
1fd5e000 | 1054 | { |
1fd5e000 | 1055 | s->startup = no_startup; |
1fd5e000 CF |
1056 | s->verify = no_verify; |
1057 | } | |
1058 | s->h = get_handle (); | |
476dfb65 | 1059 | s->except_selected = true; |
04843bf4 | 1060 | s->except_ready = false; |
1fd5e000 CF |
1061 | return s; |
1062 | } | |
1063 | ||
1064 | static int start_thread_serial (select_record *me, select_stuff *stuff); | |
1065 | ||
1fd5e000 | 1066 | static int |
476dfb65 | 1067 | peek_serial (select_record *s, bool) |
1fd5e000 | 1068 | { |
1fd5e000 CF |
1069 | COMSTAT st; |
1070 | ||
1d380f59 | 1071 | fhandler_serial *fh = (fhandler_serial *) s->fh; |
1fd5e000 CF |
1072 | |
1073 | if (fh->get_readahead_valid () || fh->overlapped_armed < 0) | |
915d1824 | 1074 | return s->read_ready = true; |
1fd5e000 CF |
1075 | |
1076 | select_printf ("fh->overlapped_armed %d", fh->overlapped_armed); | |
1077 | ||
1078 | HANDLE h; | |
1079 | set_handle_or_return_if_not_open (h, s); | |
1080 | int ready = 0; | |
41010c6a | 1081 | |
cb7e1879 | 1082 | if ((s->read_selected && s->read_ready) || (s->write_selected && s->write_ready)) |
41010c6a CF |
1083 | { |
1084 | select_printf ("already ready"); | |
1085 | ready = 1; | |
1086 | goto out; | |
1087 | } | |
1088 | ||
9895091d CF |
1089 | /* This is apparently necessary for the com0com driver. |
1090 | See: http://cygwin.com/ml/cygwin/2009-01/msg00667.html */ | |
1091 | SetCommMask (h, 0); | |
1092 | ||
0c55f6ed | 1093 | SetCommMask (h, EV_RXCHAR); |
1fd5e000 CF |
1094 | |
1095 | if (!fh->overlapped_armed) | |
1096 | { | |
1fd5e000 CF |
1097 | COMSTAT st; |
1098 | ||
1099 | ResetEvent (fh->io_status.hEvent); | |
1100 | ||
40139114 | 1101 | if (!ClearCommError (h, &fh->ev, &st)) |
1fd5e000 CF |
1102 | { |
1103 | debug_printf ("ClearCommError"); | |
1104 | goto err; | |
1105 | } | |
1106 | else if (st.cbInQue) | |
915d1824 | 1107 | return s->read_ready = true; |
40139114 | 1108 | else if (WaitCommEvent (h, &fh->ev, &fh->io_status)) |
915d1824 | 1109 | return s->read_ready = true; |
1fd5e000 CF |
1110 | else if (GetLastError () == ERROR_IO_PENDING) |
1111 | fh->overlapped_armed = 1; | |
1112 | else | |
1113 | { | |
1114 | debug_printf ("WaitCommEvent"); | |
1115 | goto err; | |
1116 | } | |
1117 | } | |
1118 | ||
79e741ef | 1119 | switch (WaitForSingleObject (fh->io_status.hEvent, 10L)) |
1fd5e000 CF |
1120 | { |
1121 | case WAIT_OBJECT_0: | |
40139114 | 1122 | if (!ClearCommError (h, &fh->ev, &st)) |
b0e82b74 CF |
1123 | { |
1124 | debug_printf ("ClearCommError"); | |
1125 | goto err; | |
1126 | } | |
1fd5e000 | 1127 | else if (!st.cbInQue) |
79e741ef | 1128 | Sleep (10L); |
1fd5e000 CF |
1129 | else |
1130 | { | |
915d1824 | 1131 | return s->read_ready = true; |
1fd5e000 CF |
1132 | select_printf ("got something"); |
1133 | } | |
1fd5e000 | 1134 | break; |
1fd5e000 | 1135 | case WAIT_TIMEOUT: |
1fd5e000 CF |
1136 | break; |
1137 | default: | |
1fd5e000 CF |
1138 | debug_printf ("WaitForMultipleObjects"); |
1139 | goto err; | |
1140 | } | |
1141 | ||
41010c6a | 1142 | out: |
1fd5e000 CF |
1143 | return ready; |
1144 | ||
1145 | err: | |
1146 | if (GetLastError () == ERROR_OPERATION_ABORTED) | |
1147 | { | |
1148 | select_printf ("operation aborted"); | |
1149 | return ready; | |
1150 | } | |
1151 | ||
169c465a | 1152 | s->set_select_errno (); |
1fd5e000 CF |
1153 | select_printf ("error %E"); |
1154 | return -1; | |
1155 | } | |
1156 | ||
1157 | static DWORD WINAPI | |
1158 | thread_serial (void *arg) | |
1159 | { | |
b4fa8164 | 1160 | select_serial_info *si = (select_serial_info *) arg; |
19085182 | 1161 | bool looping = true; |
1fd5e000 | 1162 | |
19085182 CF |
1163 | while (looping) |
1164 | for (select_record *s = si->start; (s = s->next); ) | |
1165 | if (s->startup != start_thread_serial) | |
1166 | continue; | |
1167 | else | |
1fd5e000 | 1168 | { |
19085182 CF |
1169 | if (peek_serial (s, true)) |
1170 | looping = false; | |
1171 | if (si->stop_thread) | |
1172 | { | |
1173 | select_printf ("stopping"); | |
1174 | looping = false; | |
1175 | break; | |
1176 | } | |
1fd5e000 | 1177 | } |
1fd5e000 CF |
1178 | |
1179 | select_printf ("exiting"); | |
1180 | return 0; | |
1181 | } | |
1182 | ||
1183 | static int | |
1184 | start_thread_serial (select_record *me, select_stuff *stuff) | |
1185 | { | |
7ac61736 | 1186 | if (stuff->device_specific_serial) |
b4fa8164 CF |
1187 | me->h = *((select_serial_info *) stuff->device_specific_serial)->thread; |
1188 | else | |
1fd5e000 | 1189 | { |
b4fa8164 CF |
1190 | select_serial_info *si = new select_serial_info; |
1191 | si->start = &stuff->start; | |
1192 | si->stop_thread = false; | |
b9aa8149 | 1193 | si->thread = new cygthread (thread_serial, si, "sersel"); |
b4fa8164 CF |
1194 | me->h = *si->thread; |
1195 | stuff->device_specific_serial = si; | |
1fd5e000 | 1196 | } |
1fd5e000 CF |
1197 | return 1; |
1198 | } | |
1199 | ||
1200 | static void | |
9cec3d45 | 1201 | serial_cleanup (select_record *, select_stuff *stuff) |
1fd5e000 | 1202 | { |
b4fa8164 | 1203 | select_serial_info *si = (select_serial_info *) stuff->device_specific_serial; |
2f9c2713 CF |
1204 | if (!si) |
1205 | return; | |
1206 | if (si->thread) | |
1fd5e000 | 1207 | { |
b4fa8164 | 1208 | si->stop_thread = true; |
b6bd7037 | 1209 | si->thread->detach (); |
1fd5e000 | 1210 | } |
2f9c2713 CF |
1211 | delete si; |
1212 | stuff->device_specific_serial = NULL; | |
1fd5e000 CF |
1213 | } |
1214 | ||
1fd5e000 | 1215 | select_record * |
b4fa8164 | 1216 | fhandler_serial::select_read (select_stuff *ss) |
1fd5e000 | 1217 | { |
b4fa8164 CF |
1218 | select_record *s = ss->start.next; |
1219 | if (!s->startup) | |
1fd5e000 | 1220 | { |
1fd5e000 | 1221 | s->startup = start_thread_serial; |
1fd5e000 CF |
1222 | s->verify = verify_ok; |
1223 | s->cleanup = serial_cleanup; | |
1224 | } | |
1229d4f4 | 1225 | s->peek = peek_serial; |
476dfb65 CF |
1226 | s->read_selected = true; |
1227 | s->read_ready = false; | |
1fd5e000 CF |
1228 | return s; |
1229 | } | |
1230 | ||
1231 | select_record * | |
b4fa8164 | 1232 | fhandler_serial::select_write (select_stuff *ss) |
1fd5e000 | 1233 | { |
b4fa8164 CF |
1234 | select_record *s = ss->start.next; |
1235 | if (!s->startup) | |
1fd5e000 | 1236 | { |
1fd5e000 | 1237 | s->startup = no_startup; |
1fd5e000 CF |
1238 | s->verify = verify_ok; |
1239 | } | |
476dfb65 | 1240 | s->peek = peek_serial; |
1fd5e000 | 1241 | s->h = get_handle (); |
476dfb65 CF |
1242 | s->write_selected = true; |
1243 | s->write_ready = true; | |
1fd5e000 CF |
1244 | return s; |
1245 | } | |
1246 | ||
1247 | select_record * | |
b4fa8164 | 1248 | fhandler_serial::select_except (select_stuff *ss) |
1fd5e000 | 1249 | { |
b4fa8164 CF |
1250 | select_record *s = ss->start.next; |
1251 | if (!s->startup) | |
1fd5e000 | 1252 | { |
1fd5e000 | 1253 | s->startup = no_startup; |
1fd5e000 CF |
1254 | s->verify = verify_ok; |
1255 | } | |
1256 | s->h = NULL; | |
476dfb65 CF |
1257 | s->peek = peek_serial; |
1258 | s->except_selected = false; // Can't do this | |
1259 | s->except_ready = false; | |
1fd5e000 CF |
1260 | return s; |
1261 | } | |
1262 | ||
1fd5e000 | 1263 | select_record * |
b4fa8164 | 1264 | fhandler_base::select_read (select_stuff *ss) |
1fd5e000 | 1265 | { |
b4fa8164 CF |
1266 | select_record *s = ss->start.next; |
1267 | if (!s->startup) | |
1fd5e000 | 1268 | { |
1fd5e000 | 1269 | s->startup = no_startup; |
1fd5e000 CF |
1270 | s->verify = verify_ok; |
1271 | } | |
1272 | s->h = get_handle (); | |
476dfb65 CF |
1273 | s->read_selected = true; |
1274 | s->read_ready = true; | |
1fd5e000 CF |
1275 | return s; |
1276 | } | |
1277 | ||
1278 | select_record * | |
b4fa8164 | 1279 | fhandler_base::select_write (select_stuff *ss) |
1fd5e000 | 1280 | { |
b4fa8164 CF |
1281 | select_record *s = ss->start.next; |
1282 | if (!s->startup) | |
1fd5e000 | 1283 | { |
1fd5e000 | 1284 | s->startup = no_startup; |
1fd5e000 CF |
1285 | s->verify = verify_ok; |
1286 | } | |
1287 | s->h = get_handle (); | |
476dfb65 CF |
1288 | s->write_selected = true; |
1289 | s->write_ready = true; | |
1fd5e000 CF |
1290 | return s; |
1291 | } | |
1292 | ||
1293 | select_record * | |
b4fa8164 | 1294 | fhandler_base::select_except (select_stuff *ss) |
1fd5e000 | 1295 | { |
b4fa8164 CF |
1296 | select_record *s = ss->start.next; |
1297 | if (!s->startup) | |
1fd5e000 | 1298 | { |
1fd5e000 | 1299 | s->startup = no_startup; |
1fd5e000 CF |
1300 | s->verify = verify_ok; |
1301 | } | |
1302 | s->h = NULL; | |
476dfb65 CF |
1303 | s->except_selected = true; |
1304 | s->except_ready = false; | |
1fd5e000 CF |
1305 | return s; |
1306 | } | |
1307 | ||
1fd5e000 | 1308 | static int |
476dfb65 | 1309 | peek_socket (select_record *me, bool) |
1fd5e000 | 1310 | { |
70e476d2 CV |
1311 | fhandler_socket *fh = (fhandler_socket *) me->fh; |
1312 | long events; | |
fd5879c1 CV |
1313 | /* Don't play with the settings again, unless having taken a deep look into |
1314 | Richard W. Stevens Network Programming book. Thank you. */ | |
1315 | long evt_mask = (me->read_selected ? (FD_READ | FD_ACCEPT | FD_CLOSE) : 0) | |
1316 | | (me->write_selected ? (FD_WRITE | FD_CONNECT | FD_CLOSE) : 0) | |
1317 | | (me->except_selected ? FD_OOB : 0); | |
70e476d2 CV |
1318 | int ret = fh->evaluate_events (evt_mask, events, false); |
1319 | if (me->read_selected) | |
fd5879c1 | 1320 | me->read_ready |= ret || !!(events & (FD_READ | FD_ACCEPT | FD_CLOSE)); |
70e476d2 | 1321 | if (me->write_selected) |
fd5879c1 | 1322 | me->write_ready |= ret || !!(events & (FD_WRITE | FD_CONNECT | FD_CLOSE)); |
70e476d2 | 1323 | if (me->except_selected) |
fd5879c1 | 1324 | me->except_ready |= !!(events & FD_OOB); |
70e476d2 | 1325 | |
fd5879c1 CV |
1326 | select_printf ("read_ready: %d, write_ready: %d, except_ready: %d", |
1327 | me->read_ready, me->write_ready, me->except_ready); | |
fe00cca9 | 1328 | return me->read_ready || me->write_ready || me->except_ready; |
1fd5e000 CF |
1329 | } |
1330 | ||
1fd5e000 CF |
1331 | static int start_thread_socket (select_record *, select_stuff *); |
1332 | ||
1333 | static DWORD WINAPI | |
1334 | thread_socket (void *arg) | |
1335 | { | |
b4fa8164 | 1336 | select_socket_info *si = (select_socket_info *) arg; |
023c2582 CV |
1337 | DWORD timeout = (si->num_w4 <= MAXIMUM_WAIT_OBJECTS) |
1338 | ? INFINITE | |
1339 | : (64 / (roundup2 (si->num_w4, MAXIMUM_WAIT_OBJECTS) | |
1340 | / MAXIMUM_WAIT_OBJECTS)); | |
70e476d2 | 1341 | bool event = false; |
1fd5e000 | 1342 | |
abf1b600 | 1343 | select_printf ("stuff_start %p, timeout %u", si->start, timeout); |
70e476d2 CV |
1344 | while (!event) |
1345 | { | |
1346 | for (select_record *s = si->start; (s = s->next); ) | |
1347 | if (s->startup == start_thread_socket) | |
1348 | if (peek_socket (s, false)) | |
1349 | event = true; | |
1350 | if (!event) | |
023c2582 | 1351 | for (int i = 0; i < si->num_w4; i += MAXIMUM_WAIT_OBJECTS) |
75543537 | 1352 | switch (WaitForMultipleObjects (MIN (si->num_w4 - i, |
9565e233 CV |
1353 | MAXIMUM_WAIT_OBJECTS), |
1354 | si->w4 + i, FALSE, timeout)) | |
1fd5e000 | 1355 | { |
70e476d2 CV |
1356 | case WAIT_FAILED: |
1357 | goto out; | |
023c2582 CV |
1358 | case WAIT_TIMEOUT: |
1359 | continue; | |
9565e233 CV |
1360 | case WAIT_OBJECT_0: |
1361 | if (!i) /* Socket event set. */ | |
510a85cb | 1362 | goto out; |
023c2582 | 1363 | /*FALLTHRU*/ |
70e476d2 CV |
1364 | default: |
1365 | break; | |
1fd5e000 | 1366 | } |
70e476d2 CV |
1367 | } |
1368 | out: | |
1369 | select_printf ("leaving thread_socket"); | |
1fd5e000 CF |
1370 | return 0; |
1371 | } | |
1372 | ||
023c2582 CV |
1373 | static inline bool init_tls_select_info () __attribute__ ((always_inline)); |
1374 | static inline bool | |
1375 | init_tls_select_info () | |
1376 | { | |
1377 | if (!_my_tls.locals.select.sockevt) | |
1378 | { | |
1379 | _my_tls.locals.select.sockevt = CreateEvent (&sec_none_nih, TRUE, FALSE, | |
1380 | NULL); | |
1381 | if (!_my_tls.locals.select.sockevt) | |
1382 | return false; | |
1383 | } | |
1384 | if (!_my_tls.locals.select.ser_num) | |
1385 | { | |
1386 | _my_tls.locals.select.ser_num | |
1387 | = (LONG *) malloc (MAXIMUM_WAIT_OBJECTS * sizeof (LONG)); | |
1388 | if (!_my_tls.locals.select.ser_num) | |
1389 | return false; | |
1390 | _my_tls.locals.select.w4 | |
1391 | = (HANDLE *) malloc (MAXIMUM_WAIT_OBJECTS * sizeof (HANDLE)); | |
1392 | if (!_my_tls.locals.select.w4) | |
1393 | { | |
1394 | free (_my_tls.locals.select.ser_num); | |
1395 | _my_tls.locals.select.ser_num = NULL; | |
1396 | return false; | |
1397 | } | |
1398 | _my_tls.locals.select.max_w4 = MAXIMUM_WAIT_OBJECTS; | |
1399 | } | |
1400 | return true; | |
1401 | } | |
1402 | ||
1fd5e000 CF |
1403 | static int |
1404 | start_thread_socket (select_record *me, select_stuff *stuff) | |
1405 | { | |
b4fa8164 | 1406 | select_socket_info *si; |
1fd5e000 | 1407 | |
b4fa8164 | 1408 | if ((si = (select_socket_info *) stuff->device_specific_socket)) |
1fd5e000 | 1409 | { |
b6bd7037 | 1410 | me->h = *si->thread; |
1fd5e000 CF |
1411 | return 1; |
1412 | } | |
1413 | ||
b4fa8164 | 1414 | si = new select_socket_info; |
023c2582 CV |
1415 | |
1416 | if (!init_tls_select_info ()) | |
9565e233 | 1417 | return 0; |
023c2582 CV |
1418 | |
1419 | si->ser_num = _my_tls.locals.select.ser_num; | |
1420 | si->w4 = _my_tls.locals.select.w4; | |
1421 | ||
1422 | si->w4[0] = _my_tls.locals.select.sockevt; | |
70e476d2 | 1423 | si->num_w4 = 1; |
023c2582 CV |
1424 | |
1425 | select_record *s = &stuff->start; | |
1fd5e000 CF |
1426 | while ((s = s->next)) |
1427 | if (s->startup == start_thread_socket) | |
1428 | { | |
8f713b6b CV |
1429 | /* No event/socket should show up multiple times. Every socket |
1430 | is uniquely identified by its serial number in the global | |
1431 | wsock_events record. */ | |
9565e233 | 1432 | const LONG ser_num = ((fhandler_socket *) s->fh)->serial_number (); |
70e476d2 | 1433 | for (int i = 1; i < si->num_w4; ++i) |
8f713b6b | 1434 | if (si->ser_num[i] == ser_num) |
70e476d2 | 1435 | goto continue_outer_loop; |
023c2582 | 1436 | if (si->num_w4 >= _my_tls.locals.select.max_w4) |
8f713b6b | 1437 | { |
9565e233 | 1438 | LONG *nser = (LONG *) realloc (si->ser_num, |
023c2582 CV |
1439 | (_my_tls.locals.select.max_w4 |
1440 | + MAXIMUM_WAIT_OBJECTS) | |
9565e233 CV |
1441 | * sizeof (LONG)); |
1442 | if (!nser) | |
1443 | return 0; | |
023c2582 | 1444 | _my_tls.locals.select.ser_num = si->ser_num = nser; |
9565e233 | 1445 | HANDLE *nw4 = (HANDLE *) realloc (si->w4, |
023c2582 CV |
1446 | (_my_tls.locals.select.max_w4 |
1447 | + MAXIMUM_WAIT_OBJECTS) | |
9565e233 CV |
1448 | * sizeof (HANDLE)); |
1449 | if (!nw4) | |
1450 | return 0; | |
023c2582 CV |
1451 | _my_tls.locals.select.w4 = si->w4 = nw4; |
1452 | _my_tls.locals.select.max_w4 += MAXIMUM_WAIT_OBJECTS; | |
8f713b6b | 1453 | } |
9565e233 CV |
1454 | si->ser_num[si->num_w4] = ser_num; |
1455 | si->w4[si->num_w4++] = ((fhandler_socket *) s->fh)->wsock_event (); | |
70e476d2 CV |
1456 | continue_outer_loop: |
1457 | ; | |
1458 | } | |
b4fa8164 | 1459 | stuff->device_specific_socket = si; |
1fd5e000 CF |
1460 | si->start = &stuff->start; |
1461 | select_printf ("stuff_start %p", &stuff->start); | |
b9aa8149 | 1462 | si->thread = new cygthread (thread_socket, si, "socksel"); |
b6bd7037 CF |
1463 | me->h = *si->thread; |
1464 | return 1; | |
1fd5e000 CF |
1465 | } |
1466 | ||
1467 | void | |
9cec3d45 | 1468 | socket_cleanup (select_record *, select_stuff *stuff) |
1fd5e000 | 1469 | { |
b4fa8164 | 1470 | select_socket_info *si = (select_socket_info *) stuff->device_specific_socket; |
1fd5e000 | 1471 | select_printf ("si %p si->thread %p", si, si ? si->thread : NULL); |
2f9c2713 CF |
1472 | if (!si) |
1473 | return; | |
1474 | if (si->thread) | |
1fd5e000 | 1475 | { |
70e476d2 | 1476 | SetEvent (si->w4[0]); |
1fd5e000 | 1477 | /* Wait for thread to go away */ |
b6bd7037 | 1478 | si->thread->detach (); |
70e476d2 | 1479 | ResetEvent (si->w4[0]); |
1fd5e000 | 1480 | } |
2f9c2713 CF |
1481 | delete si; |
1482 | stuff->device_specific_socket = NULL; | |
1fd5e000 CF |
1483 | select_printf ("returning"); |
1484 | } | |
1485 | ||
1486 | select_record * | |
b4fa8164 | 1487 | fhandler_socket::select_read (select_stuff *ss) |
1fd5e000 | 1488 | { |
b4fa8164 CF |
1489 | select_record *s = ss->start.next; |
1490 | if (!s->startup) | |
1fd5e000 | 1491 | { |
1fd5e000 | 1492 | s->startup = start_thread_socket; |
1fd5e000 CF |
1493 | s->verify = verify_true; |
1494 | s->cleanup = socket_cleanup; | |
1495 | } | |
1229d4f4 | 1496 | s->peek = peek_socket; |
5835f2cf | 1497 | s->read_ready = saw_shutdown_read (); |
476dfb65 | 1498 | s->read_selected = true; |
1fd5e000 CF |
1499 | return s; |
1500 | } | |
1501 | ||
1502 | select_record * | |
b4fa8164 | 1503 | fhandler_socket::select_write (select_stuff *ss) |
1fd5e000 | 1504 | { |
b4fa8164 CF |
1505 | select_record *s = ss->start.next; |
1506 | if (!s->startup) | |
1fd5e000 | 1507 | { |
1fd5e000 | 1508 | s->startup = start_thread_socket; |
1fd5e000 CF |
1509 | s->verify = verify_true; |
1510 | s->cleanup = socket_cleanup; | |
1511 | } | |
476dfb65 | 1512 | s->peek = peek_socket; |
56551a9b | 1513 | s->write_ready = saw_shutdown_write () || connect_state () == unconnected; |
476dfb65 | 1514 | s->write_selected = true; |
04843bf4 | 1515 | if (connect_state () != unconnected) |
6bb769ef CV |
1516 | { |
1517 | s->except_ready = saw_shutdown_write () || saw_shutdown_read (); | |
1518 | s->except_on_write = true; | |
1519 | } | |
1fd5e000 CF |
1520 | return s; |
1521 | } | |
1522 | ||
1523 | select_record * | |
b4fa8164 | 1524 | fhandler_socket::select_except (select_stuff *ss) |
1fd5e000 | 1525 | { |
b4fa8164 CF |
1526 | select_record *s = ss->start.next; |
1527 | if (!s->startup) | |
1fd5e000 | 1528 | { |
1fd5e000 | 1529 | s->startup = start_thread_socket; |
1fd5e000 CF |
1530 | s->verify = verify_true; |
1531 | s->cleanup = socket_cleanup; | |
1532 | } | |
476dfb65 | 1533 | s->peek = peek_socket; |
5835f2cf CF |
1534 | /* FIXME: Is this right? Should these be used as criteria for except? */ |
1535 | s->except_ready = saw_shutdown_write () || saw_shutdown_read (); | |
476dfb65 | 1536 | s->except_selected = true; |
1fd5e000 CF |
1537 | return s; |
1538 | } | |
1539 | ||
1540 | static int | |
476dfb65 | 1541 | peek_windows (select_record *me, bool) |
1fd5e000 CF |
1542 | { |
1543 | MSG m; | |
1544 | HANDLE h; | |
1545 | set_handle_or_return_if_not_open (h, me); | |
41010c6a CF |
1546 | |
1547 | if (me->read_selected && me->read_ready) | |
1548 | return 1; | |
1549 | ||
79e741ef | 1550 | if (PeekMessageW (&m, (HWND) h, 0, 0, PM_NOREMOVE)) |
1fd5e000 | 1551 | { |
476dfb65 | 1552 | me->read_ready = true; |
fc25f200 | 1553 | select_printf ("window %d(%p) ready", me->fd, h); |
1fd5e000 CF |
1554 | return 1; |
1555 | } | |
1556 | ||
fc25f200 | 1557 | select_printf ("window %d(%p) not ready", me->fd, h); |
1fd5e000 CF |
1558 | return me->write_ready; |
1559 | } | |
1560 | ||
763f09b9 CF |
1561 | static int |
1562 | verify_windows (select_record *me, fd_set *rfds, fd_set *wfds, | |
1563 | fd_set *efds) | |
1564 | { | |
1565 | return peek_windows (me, true); | |
1566 | } | |
1567 | ||
1fd5e000 | 1568 | select_record * |
b4fa8164 | 1569 | fhandler_windows::select_read (select_stuff *ss) |
1fd5e000 | 1570 | { |
b4fa8164 CF |
1571 | select_record *s = ss->start.next; |
1572 | if (!s->startup) | |
1fd5e000 | 1573 | { |
1fd5e000 | 1574 | s->startup = no_startup; |
1fd5e000 | 1575 | } |
763f09b9 | 1576 | s->verify = verify_windows; |
1229d4f4 | 1577 | s->peek = peek_windows; |
476dfb65 CF |
1578 | s->read_selected = true; |
1579 | s->read_ready = false; | |
1fd5e000 | 1580 | s->h = get_handle (); |
476dfb65 | 1581 | s->windows_handle = true; |
1fd5e000 CF |
1582 | return s; |
1583 | } | |
1584 | ||
1585 | select_record * | |
b4fa8164 | 1586 | fhandler_windows::select_write (select_stuff *ss) |
1fd5e000 | 1587 | { |
b4fa8164 CF |
1588 | select_record *s = ss->start.next; |
1589 | if (!s->startup) | |
1fd5e000 | 1590 | { |
1fd5e000 | 1591 | s->startup = no_startup; |
1fd5e000 CF |
1592 | s->verify = verify_ok; |
1593 | } | |
476dfb65 | 1594 | s->peek = peek_windows; |
1fd5e000 | 1595 | s->h = get_handle (); |
476dfb65 CF |
1596 | s->write_selected = true; |
1597 | s->write_ready = true; | |
1598 | s->windows_handle = true; | |
1fd5e000 CF |
1599 | return s; |
1600 | } | |
1601 | ||
1602 | select_record * | |
b4fa8164 | 1603 | fhandler_windows::select_except (select_stuff *ss) |
1fd5e000 | 1604 | { |
b4fa8164 CF |
1605 | select_record *s = ss->start.next; |
1606 | if (!s->startup) | |
1fd5e000 | 1607 | { |
1fd5e000 | 1608 | s->startup = no_startup; |
1fd5e000 CF |
1609 | s->verify = verify_ok; |
1610 | } | |
476dfb65 | 1611 | s->peek = peek_windows; |
1fd5e000 | 1612 | s->h = get_handle (); |
476dfb65 | 1613 | s->except_selected = true; |
04843bf4 | 1614 | s->except_ready = false; |
476dfb65 | 1615 | s->windows_handle = true; |
1fd5e000 CF |
1616 | return s; |
1617 | } | |
13505ca8 CV |
1618 | |
1619 | static int | |
1620 | peek_mailslot (select_record *me, bool) | |
1621 | { | |
1622 | HANDLE h; | |
1623 | set_handle_or_return_if_not_open (h, me); | |
1624 | ||
1625 | if (me->read_selected && me->read_ready) | |
1626 | return 1; | |
1627 | DWORD msgcnt = 0; | |
1628 | if (!GetMailslotInfo (h, NULL, NULL, &msgcnt, NULL)) | |
1629 | { | |
1630 | select_printf ("mailslot %d(%p) error %E", me->fd, h); | |
1631 | return 1; | |
1632 | } | |
1633 | if (msgcnt > 0) | |
1634 | { | |
1635 | me->read_ready = true; | |
1636 | select_printf ("mailslot %d(%p) ready", me->fd, h); | |
1637 | return 1; | |
1638 | } | |
1639 | select_printf ("mailslot %d(%p) not ready", me->fd, h); | |
1640 | return 0; | |
1641 | } | |
1642 | ||
1643 | static int | |
1644 | verify_mailslot (select_record *me, fd_set *rfds, fd_set *wfds, | |
1645 | fd_set *efds) | |
1646 | { | |
1647 | return peek_mailslot (me, true); | |
1648 | } | |
1649 | ||
1650 | static int start_thread_mailslot (select_record *me, select_stuff *stuff); | |
1651 | ||
13505ca8 CV |
1652 | static DWORD WINAPI |
1653 | thread_mailslot (void *arg) | |
1654 | { | |
b4fa8164 | 1655 | select_mailslot_info *mi = (select_mailslot_info *) arg; |
13505ca8 | 1656 | bool gotone = false; |
cfa88257 | 1657 | DWORD sleep_time = 0; |
13505ca8 CV |
1658 | |
1659 | for (;;) | |
1660 | { | |
1661 | select_record *s = mi->start; | |
1662 | while ((s = s->next)) | |
1663 | if (s->startup == start_thread_mailslot) | |
1664 | { | |
1665 | if (peek_mailslot (s, true)) | |
1666 | gotone = true; | |
b4fa8164 | 1667 | if (mi->stop_thread) |
13505ca8 CV |
1668 | { |
1669 | select_printf ("stopping"); | |
1670 | goto out; | |
1671 | } | |
1672 | } | |
1673 | /* Paranoid check */ | |
b4fa8164 | 1674 | if (mi->stop_thread) |
13505ca8 CV |
1675 | { |
1676 | select_printf ("stopping from outer loop"); | |
1677 | break; | |
1678 | } | |
1679 | if (gotone) | |
1680 | break; | |
b4c53a7c CV |
1681 | Sleep (sleep_time >> 3); |
1682 | if (sleep_time < 80) | |
9c9959a5 | 1683 | ++sleep_time; |
13505ca8 CV |
1684 | } |
1685 | out: | |
1686 | return 0; | |
1687 | } | |
1688 | ||
1689 | static int | |
1690 | start_thread_mailslot (select_record *me, select_stuff *stuff) | |
1691 | { | |
1692 | if (stuff->device_specific_mailslot) | |
1693 | { | |
b4fa8164 | 1694 | me->h = *((select_mailslot_info *) stuff->device_specific_mailslot)->thread; |
13505ca8 CV |
1695 | return 1; |
1696 | } | |
b4fa8164 | 1697 | select_mailslot_info *mi = new select_mailslot_info; |
13505ca8 | 1698 | mi->start = &stuff->start; |
b4fa8164 | 1699 | mi->stop_thread = false; |
b9aa8149 | 1700 | mi->thread = new cygthread (thread_mailslot, mi, "mailsel"); |
13505ca8 CV |
1701 | me->h = *mi->thread; |
1702 | if (!me->h) | |
1703 | return 0; | |
b4fa8164 | 1704 | stuff->device_specific_mailslot = mi; |
13505ca8 CV |
1705 | return 1; |
1706 | } | |
1707 | ||
1708 | static void | |
1709 | mailslot_cleanup (select_record *, select_stuff *stuff) | |
1710 | { | |
b4fa8164 | 1711 | select_mailslot_info *mi = (select_mailslot_info *) stuff->device_specific_mailslot; |
2f9c2713 CF |
1712 | if (!mi) |
1713 | return; | |
1714 | if (mi->thread) | |
13505ca8 | 1715 | { |
b4fa8164 | 1716 | mi->stop_thread = true; |
13505ca8 | 1717 | mi->thread->detach (); |
13505ca8 | 1718 | } |
2f9c2713 CF |
1719 | delete mi; |
1720 | stuff->device_specific_mailslot = NULL; | |
13505ca8 CV |
1721 | } |
1722 | ||
1723 | select_record * | |
b4fa8164 | 1724 | fhandler_mailslot::select_read (select_stuff *ss) |
13505ca8 | 1725 | { |
b4fa8164 | 1726 | select_record *s = ss->start.next; |
13505ca8 CV |
1727 | s->startup = start_thread_mailslot; |
1728 | s->peek = peek_mailslot; | |
1729 | s->verify = verify_mailslot; | |
1730 | s->cleanup = mailslot_cleanup; | |
1731 | s->read_selected = true; | |
1732 | s->read_ready = false; | |
1733 | return s; | |
1734 | } |