Watt-32 tcp/ip  2.2 dev-rel.10
select.c
Go to the documentation of this file.
1 
5 /* BSD sockets functionality for Watt-32 TCP/IP
6  *
7  * Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  * must display the following acknowledgement:
19  * This product includes software developed by Gisle Vanem
20  * Bergen, Norway.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Version
34  *
35  * 0.5 : Dec 18, 1997 : G. Vanem - created
36  * 0.6 : Nov 05, 1999 : G. Vanem - several changes;
37  * Protect select-loop as critical region.
38  * Changed criteria for read/writeability.
39  */
40 
41 #include "socket.h"
42 
43 #if defined(USE_BSD_API)
44 
45 #ifdef __HIGHC__ /* set warning for stack-usage */
46 #pragma stack_size_warn (16000) /* ~3*MAX_SOCKETS */
47 #endif
48 
49 #define ALWAYS_YIELD 0
50 
51 #ifndef STDIN_FILENO
52 #define STDIN_FILENO 0
53 #endif
54 
55 #ifndef STDOUT_FILENO
56 #define STDOUT_FILENO 1
57 #endif
58 
59 #ifndef STDERR_FILENO
60 #define STDERR_FILENO 2
61 #endif
62 
63 
68 static struct timeval sel_min_block = { 0, 500000 }; /* 0.5 sec */
69 
70 /*
71  * Select sockets for read, write or exceptions
72  * Returns 1 if socket is ready or
73  * Returns 0 if socket isn't selectable
74  */
75 static int read_select (int s, Socket *socket);
76 static int write_select (int s, Socket *socket);
77 static int exc_select (int s, Socket *socket);
78 
79 /*
80  * Setup for read/write/except_select()
81  */
82 static __inline Socket *setup_select (int s, BOOL first_loop)
83 {
85 
86  if (first_loop && !socket)
87  {
88  if (_sock_dos_fd(s))
89  {
90  SOCK_DEBUGF ((", ENOTSOCK (%d)", s));
91  SOCK_ERRNO (ENOTSOCK);
92  }
93  else
94  {
95  SOCK_DEBUGF ((", EBADF (%d)", s));
96  SOCK_ERRNO (EBADF);
97  }
98  }
99  return (socket);
100 }
101 
112 int W32_CALL select_s (int nfds, fd_set *readfds, fd_set *writefds,
113  fd_set *exceptfds, struct timeval *timeout)
114 {
115  fd_set tmp_read [NUM_SOCK_FDSETS];
116  fd_set tmp_write [NUM_SOCK_FDSETS];
117  fd_set tmp_except[NUM_SOCK_FDSETS];
118  struct timeval starttime, expiry, now;
119 
120  int num_fd = nfds;
121  int ret_count = 0;
122  BOOL expired = FALSE;
123  BOOL loop_1st = TRUE;
124  int s, loops;
125 
126 #if defined(USE_DEBUG)
127  unsigned total_rd = 0;
128  unsigned total_wr = 0;
129  unsigned total_ex = 0;
130 #endif
131 
132  SOCK_DEBUGF (("\nselect_s: n=0-%d, %c%c%c", num_fd-1,
133  readfds ? 'r' : '-',
134  writefds ? 'w' : '-',
135  exceptfds ? 'x' : '-'));
136 
137 
138  /* num_fd == 0 is permitted. Often used to perform delays:
139  * select (0,NULL,NULL,NULL,&tv);
140  *
141  * Some programs uses -1 to mean all possible sockets.
142  */
143  if (num_fd > MAX_SOCKETS || num_fd < 0)
144  num_fd = MAX_SOCKETS;
145 
146  if (timeout)
147  {
148  if ((long)timeout->tv_sec < 0 || timeout->tv_usec < 0)
149  {
150  SOCK_DEBUGF ((", EINVAL (negative timeout)"));
151  SOCK_ERRNO (EINVAL);
152  return (-1);
153  }
154 
155  gettimeofday2 (&starttime, NULL); /* initialize start time */
156 
157  expiry.tv_sec = starttime.tv_sec + timeout->tv_sec;
158  expiry.tv_usec = starttime.tv_usec + timeout->tv_usec;
159  while (expiry.tv_usec >= 1000000L)
160  {
161  expiry.tv_usec -= 1000000L;
162  expiry.tv_sec++;
163  }
164 
165  SOCK_DEBUGF ((", timeout %lu.%06lds",
166  (DWORD)timeout->tv_sec, timeout->tv_usec));
167  }
168  else
169  SOCK_DEBUGF ((", timeout undef"));
170 
171 
177  memset (tmp_read, 0, sizeof(tmp_read));
178  memset (tmp_write, 0, sizeof(tmp_write));
179  memset (tmp_except, 0, sizeof(tmp_except));
180 
181  /* If application catches same signals we do, we must exit
182  * gracefully from the do-while and for loops below.
183  */
184  if (_sock_sig_setup() < 0)
185  goto select_intr;
186 
187  /*
188  * Loop until specified timeout expires or event(s) satisfied.
189  */
190  for (loop_1st = TRUE, loops = 1;; loop_1st = FALSE, loops++)
191  {
192  /* Poll for caught signals (SIGINT/SIGALRM)
193  */
194  if (_sock_sig_pending())
195  goto select_intr;
196 
197  for (s = 0; s < num_fd; s++)
198  {
199  /* read/write/except counters for socket 's'
200  */
201  int do_read = 0, do_write = 0, do_exc = 0;
202  int read_cnt = 0, write_cnt = 0, exc_cnt = 0;
203  Socket *socket = NULL;
204 
205  /* Not safe to run sock_daemon() (or other "tasks") now
206  */
208 
209  if (readfds && FD_ISSET(s,readfds))
210  do_read = 1;
211 
212  if (writefds && FD_ISSET(s,writefds))
213  do_write = 1;
214 
215  if (exceptfds && FD_ISSET(s,exceptfds))
216  do_exc = 1;
217 
218  if (do_read || do_write || do_exc)
219  {
220  tcp_tick (NULL); /* must do tcp_tick() here */
221  if (s >= SK_FIRST)
222  {
223  socket = setup_select (s, loop_1st);
224  if (!socket) /* skip this fd */
225  do_read = do_write = do_exc = 0;
226  }
227  }
228 
229  /* Check this socket for readability ?
230  */
231  if (do_read)
232  {
233  read_cnt = read_select (s, socket);
234  if (read_cnt > 0)
235  FD_SET (s, &tmp_read[0]);
236  }
237 
238  /* Check this socket for writeability ?
239  */
240  if (do_write)
241  {
242  write_cnt = write_select (s, socket);
243  if (write_cnt > 0)
244  FD_SET (s, &tmp_write[0]);
245  }
246 
247  /* Check this socket for exception ?
248  */
249  if (do_exc)
250  {
251  exc_cnt = exc_select (s, socket);
252  if (exc_cnt > 0)
253  FD_SET (s, &tmp_except[0]);
254  }
255 
256  /* Increment the return and total counters (may increment by 0)
257  */
258  ret_count += (read_cnt + write_cnt + exc_cnt);
259 
260 #if defined(USE_DEBUG)
261  total_rd += read_cnt;
262  total_wr += write_cnt;
263  total_ex += exc_cnt;
264 #endif
265 
266  /* Safe to run other "tasks" now.
267  */
268  _sock_crit_stop();
269  SOCK_DBUG_FLUSH();
270 
271  } /* end of for loop; all sockets checked at least once */
272 
273 
274  /* WATT_YIELD() sometimes hangs for approx 250msec under Win-XP.
275  * Don't yield for "small" timeouts.
276  */
277 #if (!ALWAYS_YIELD)
278  if (!timeout || timercmp(timeout,&sel_min_block,>))
279 #endif
280  {
281  if (ret_count == 0)
282  {
283  WATT_YIELD();
284  tcp_tick (NULL);
285  }
286  }
287 
288  if (timeout)
289  {
290  gettimeofday2 (&now, NULL);
291  if (now.tv_sec > expiry.tv_sec ||
292  (now.tv_sec == expiry.tv_sec && now.tv_usec >= expiry.tv_usec))
293  expired = TRUE;
294  }
295 
296  /* If atleast 1 event is set.
297  */
298  if (ret_count > 0)
299  {
300  SOCK_DEBUGF ((", cnt=%d (%dr/%dw/%dx)",
301  ret_count, total_rd, total_wr, total_ex));
302 
303  /* Copy our working fd_sets to output fd_sets
304  */
305  for (s = 0; s < num_fd; s++)
306  {
307  if (readfds)
308  {
309  if (FD_ISSET(s, &tmp_read[0]))
310  FD_SET (s, readfds);
311  else FD_CLR (s, readfds);
312  }
313  if (writefds)
314  {
315  if (FD_ISSET(s, &tmp_write[0]))
316  FD_SET (s, writefds);
317  else FD_CLR (s, writefds);
318  }
319  if (exceptfds)
320  {
321  if (FD_ISSET(s, &tmp_except[0]))
322  FD_SET (s, exceptfds);
323  else FD_CLR (s, exceptfds);
324  }
325  }
326 
327  /* Do as Linux and return the time left of the period.
328  * NB! The 'tv_sec' can be negative if select_s() took too long.
329  */
330  if (timeout)
331  {
332  double remaining = timeval_diff (&now, &expiry);
333 
334  timeout->tv_sec = (long)(remaining / 1E6);
335  timeout->tv_usec = (long)remaining % 1000000UL;
336  }
337  goto select_ok;
338  }
339 
340  if (expired)
341  {
342  SOCK_DEBUGF ((", timeout!: %.6fs", timeval_diff(&now, &starttime)/1E6));
343 
344  if (readfds)
345  for (s = 0; s < num_fd; s++)
346  FD_CLR (s, readfds);
347 
348  if (writefds)
349  for (s = 0; s < num_fd; s++)
350  FD_CLR (s, writefds);
351 
352  if (exceptfds)
353  for (s = 0; s < num_fd; s++)
354  FD_CLR (s, exceptfds);
355 
356  ret_count = 0; /* should already be 0 */
357  goto select_ok;
358  }
359  }
360 
361 select_intr:
362  SOCK_DEBUGF ((", EINTR"));
363  SOCK_ERRNO (EINTR);
364  ret_count = -1;
365  _sock_crit_stop();
366 
367 select_ok:
368  _sock_sig_restore();
369 
370  return (ret_count);
371 }
372 
373 #if defined(WIN32)
374 int W32_CALL select (int nfds, fd_set *read_fds, fd_set *write_fds,
375  fd_set *except_fds, struct timeval *timeout)
376 {
377  return select_s (nfds, read_fds, write_fds, except_fds, timeout);
378 }
379 #endif
380 
381 
382 #ifdef NOT_YET
383 int pselect (int nfds, fd_set *readfds, fd_set *writefds,
384  fd_set *exceptfds, struct timespec *timeout,
385  const sigset_t *sigmask)
386 {
387  struct timeval tv;
388  sigset_t old_mask;
389  int rc;
390 
391  if (timeout)
392  {
393  tv.tv_sec = tv_sec;
394  tv_tv_nsec = 1000UL * tv_usec;
395  }
396  if (sigmask)
397  sigprocmask (SIG_BLOCK, sigmask, &old_mask);
398 
399  rc = select (nfds, readfs, writefds, exceptfds, timeout ? &tv : NULL);
400 
401  if (sigmask)
402  sigprocmask (SIG_UNBLOCK, &old_mask, NULL);
403 
404  return (rc);
405 }
406 #endif
407 
408 /*
409  * Check listen-queue for first connected TCB.
410  * Only called for listening (accepting) sockets.
411  */
412 static __inline int listen_queued (Socket *socket)
413 {
414  int i;
415 
416  for (i = 0; i < socket->backlog && i < DIM(socket->listen_queue); i++)
417  {
418  _tcp_Socket *tcb = socket->listen_queue[i];
419 
420  if (!tcb)
421  continue;
422 
423  /* Socket has reached Established state or receive data above
424  * low water mark. This means, socket may have reached Closed,
425  * but this still counts as a readable event.
426  */
427  if (tcb->state == tcp_StateESTAB ||
428  sock_rbused((sock_type*)tcb) > socket->recv_lowat)
429  return (1);
430  }
431  return (0);
432 }
433 
434 /*
435  * Return TRUE if socket has a "real" error and not a "pending" error.
436  * I.e. EALREADY is not a real error, but a pending condition until a
437  * non-blocking socket is actually connected. Or if connection fails,
438  * in which case the error is ECONNREFUSED.
439  *
440  * This signalled read/write state is assumed to persist for the
441  * remaining life of the socket.
442  */
443 #define READ_STATE_MASK (SS_CANTRCVMORE) /* set in recv() or shutdown() */
444 #define WRITE_STATE_MASK (SS_CANTSENDMORE | SS_ISCONNECTED)
445 
446 static __inline int sock_signalled (Socket *socket, int mask)
447 {
448  if (socket->so_state & mask)
449  return (1);
450 
451  /* A normal blocking socket. 'so_error' is set in
452  * connect(), a "ICMP Unreachable" callback or when RST received
453  * in pctcp.c. Otherwise 'so_error' is zero.
454  */
455  if (!(socket->so_state & SS_NBIO))
456  return (socket->so_error);
457 
458 #if 0
459  if (socket->so_options & SO_ACCEPTCONN) /* non-blocking listen sock */
460  return (0);
461 
462  if (socket->so_error == EALREADY) /* temporary non-blocking error */
463  return (0);
464  return (1);
465 #else
466  return (0);
467 #endif
468 }
469 
470 #if defined(__MSDOS__)
471 /*
472  * Check if a standard handle is ready.
473  * This should return TRUE if handle is redirected.
474  */
475 static BOOL handle_ready (int hnd)
476 {
477  union REGS regs;
478 
479 #if defined(__HIGHC__) || defined(__DMC__)
480  regs.x.ax = 0x4406;
481  regs.x.bx = hnd;
482 #else
483  regs.w.ax = 0x4406;
484  regs.w.bx = hnd;
485 #endif
486 
487  intdos (&regs, &regs);
488  return (regs.h.al == 0xFF); /* ready character device */
489 }
490 #else
491 #define handle_ready(hnd) 0
492 #endif
493 
494 /*
495  * Check if 's' can be read from.
496  */
497 static int read_select (int s, Socket *socket)
498 {
499  if (s == STDIN_FILENO)
500  {
501 #if defined(__DJGPP__) && 0
502  struct timeval tv = { 0, 0 };
503  fd_set rd;
504  int rc;
505 
506  FD_ZERO (&rd);
507  FD_SET (STDIN_FILENO, &rd);
508  rc = (select) (1, &rd, NULL, NULL, &tv);
509  return (rc == 1 ? 1 : 0);
510 #else
511  return (watt_kbhit() || handle_ready(STDIN_FILENO));
512 #endif
513  }
514 
515  if (s <= STDERR_FILENO)
516  return (0);
517 
518  if (socket->so_type == SOCK_PACKET)
519  return sock_packet_rbused (socket) ? 1 : 0;
520 
521  if (socket->so_type == SOCK_RAW)
522  {
523 #if defined(USE_IPV6)
524  if (socket->so_family == AF_INET6)
525  return sock_rbused ((sock_type*)socket->raw6_sock) ? 1 : 0;
526 #endif
527  return sock_rbused ((sock_type*)socket->raw_sock) ? 1 : 0;
528  }
529 
530  if (socket->so_type == SOCK_DGRAM)
531  {
532  size_t len;
533 
534  if (socket->so_state & SS_PRIV)
535  len = sock_recv_used ((sock_type*)socket->udp_sock);
536  else len = sock_rbused ((sock_type*)socket->udp_sock);
537 
538  if (len > socket->recv_lowat ||
539  sock_signalled(socket,READ_STATE_MASK))
540  return (1);
541  return (0);
542  }
543 
544  if (socket->so_type == SOCK_STREAM)
545  {
546  sock_type *sk = (sock_type*) socket->tcp_sock;
547 
548  if ((socket->so_state & SS_NBIO) &&
549  sk->tcp.state == tcp_StateESTAB &&
550  socket->so_error == EALREADY)
551  socket->so_error = EISCONN;
552 
553  if (sock_signalled(socket,READ_STATE_MASK) || /* signalled for read_s() */
554  sk->tcp.state >= tcp_StateLASTACK || /* got FIN from peer */
555  sock_rbused(sk) > socket->recv_lowat) /* Rx-data above low-limit */
556  return (1);
557 
558  if ((socket->so_options & SO_ACCEPTCONN) && /* connection pending */
559  listen_queued(socket))
560  return (1);
561  }
562  return (0);
563 }
564 
565 /*
566  * Check if 's' can be written to.
567  */
568 static int write_select (int s, Socket *socket)
569 {
570 #if defined(__DJGPP__) && 0
571  if (s == STDOUT_FILENO || s == STDERR_FILENO)
572  {
573  struct timeval tv = { 0, 0 };
574  fd_set wr;
575  int rc;
576 
577  FD_ZERO (&wr);
578  FD_SET (s, &wr);
579  rc = (select) (1, NULL, &wr, NULL, &tv);
580  return (rc == 1 ? 1 : 0);
581  }
582 #else
583  if (s == STDOUT_FILENO)
584  return !ferror (stdout);
585 
586  if (s == STDERR_FILENO)
587  return !ferror (stderr);
588 #endif
589 
590  if (s == STDIN_FILENO)
591  return (0);
592 
593  /* SOCK_PACKET, SOCK_RAW and SOCK_DGRAM sockets are always writeable
594  */
595  if (socket->so_type == SOCK_PACKET ||
596  socket->so_type == SOCK_RAW ||
597  socket->so_type == SOCK_DGRAM)
598  return (1);
599 
600  if (socket->so_type == SOCK_STREAM)
601  {
602  sock_type *sk = (sock_type*) socket->tcp_sock;
603 
604  if (sk->tcp.state == tcp_StateESTAB)
605  {
606  if ((socket->so_state & SS_NBIO) && socket->so_error == EALREADY)
607  socket->so_error = EISCONN;
608 
609  if (sock_tbleft(sk) > socket->send_lowat) /* Tx room above low-limit */
610  return (1);
611  }
612  if (sk->tcp.state >= tcp_StateESTCL)
613  return (1);
614 
615  if (sock_signalled(socket,WRITE_STATE_MASK)) /* signalled for write */
616  return (1);
617  }
618  return (0);
619 }
620 
621 /*
622  * Check 's' for exception or faulty condition.
623  */
624 static int exc_select (int s, Socket *socket)
625 {
626  if (s < SK_FIRST)
627  return (0);
628 
631 #if 0
632  if (sock_signalled(socket, READ_STATE_MASK|WRITE_STATE_MASK))
633  return (1);
634 #endif
635 
636  ARGSUSED (socket);
637  return (0);
638 }
639 #endif /* USE_BSD_API */
640 
641 
642 /*
643  * A small test program (for djgpp/Watcom/HighC/DMC)
644  */
645 #if defined(TEST_PROG)
646 
647 #include <time.h>
648 
649 #ifndef __CYGWIN__
650 #include <conio.h>
651 #endif
652 
653 #ifndef _MSC_VER
654 #include <unistd.h>
655 #endif
656 
657 void usage (const char *argv0)
658 {
659  fprintf (stderr,
660  "Usage: %s [-s select_size] [-w micro-sec] [-hid]\n"
661  "\t\t -s set the number of fd's to select for (default 1)\n"
662  "\t\t -w time to wait in select (default 0.5)\n"
663  "\t\t -h don't use 8254 hi-resolution timer function\n"
664  "\t\t -i use timer ISR (init_timer_isr)\n"
665  "\t\t -d write debug to wattcp.sk/wattcp.dbg\n", argv0);
666  exit (-1);
667 }
668 
669 char *fd_set_str (char *buf, size_t len, const fd_set *fd)
670 {
671  char *p = buf;
672  char *end = buf + len;
673  int i, num;
674 
675 #if 0
676  p += sprintf (p, "%d: ", fd->fd_count);
677 #endif
678 
679  for (i = 0, num = 0; i < 8*FD_SETSIZE; i++)
680  {
681  if (FD_ISSET(i,fd))
682  {
683  p += sprintf (p, "%d,", i);
684  num++;
685  }
686  if (p > end - 12)
687  {
688  strcat(p, "<overflow>");
689  break;
690  }
691  }
692  if (p < end - 12)
693  strcat (p, "<none set>");
694  return (buf);
695 }
696 
697 void select_dump (int sock_err, int num_fd, const struct timeval *tv,
698  const fd_set *fd_read,
699  const fd_set *fd_write,
700  const fd_set *fd_except)
701 {
702  char buf1[512], buf2[512], buf3[512];
703 
704  printf ("select_dump: sock_err %d, num_fd %d, timeout %ld.06%lu\n"
705  "\tread-fds: %s\n"
706  "\twrite-fds: %s\n"
707  "\texcept-fds: %s\n",
708  sock_err, num_fd, (long)tv->tv_sec, tv->tv_usec,
709  fd_set_str(buf1,sizeof(buf1),fd_read),
710  fd_set_str(buf2,sizeof(buf2),fd_write),
711  fd_set_str(buf3,sizeof(buf3),fd_except));
712 }
713 
714 int main (int argc, char **argv)
715 {
716  BOOL use_8254 = TRUE;
717  BOOL use_isr = FALSE;
718  BOOL debug = FALSE;
719  double sel_wait = 0.5;
720  int sel_size = 1;
721  int ch;
722 
723  while ((ch = getopt(argc, argv, "s:w:hid?")) != EOF)
724  switch (ch)
725  {
726  case 'h':
727  use_8254 = FALSE;
728  break;
729 
730  case 'i':
731  init_timer_isr();
732  use_isr = TRUE;
733  break;
734 
735  case 's':
736  sel_size = atoi (optarg);
737  break;
738 
739  case 'd':
740  dbug_init();
741  debug = TRUE;
742  break;
743 
744  case 'w':
745  sel_wait = atof (optarg);
746  break;
747 
748  case '?':
749  default:
750  usage (argv[0]);
751  break;
752  }
753 
754  if (sel_size <= 0 || sel_size > MAX_SOCKETS)
755  {
756  printf ("Illegal select-size %d. Range 0 - %d\n", sel_size, MAX_SOCKETS);
757  return (-1);
758  }
759 
760  sock_init();
761 
762  printf ("select-wait %.3f sec, select-size %d, debug %d, ",
763  sel_wait, sel_size, debug);
764 
765 #if defined(MSDOS)
766  printf ("has_8254 %d, uses_int8 %d\n", has_8254, use_isr);
767  hires_timer (use_8254);
768 #endif
769 
770  puts ("Press 'q' to quit");
771 
772  while (1)
773  {
774  fd_set read [NUM_SOCK_FDSETS];
775  struct timeval tv;
776  uclock_t start, diff;
777 
778  tv.tv_sec = (time_t)sel_wait;
779  tv.tv_usec = 1000000UL * (sel_wait - (double)tv.tv_sec);
780  start = uclock();
781  memset (read, 0, sizeof(read));
782  FD_SET (STDIN_FILENO, &read[0]);
783 
784  if (select_s (sel_size, read, NULL, NULL, &tv) < 0)
785  {
786  perror ("select");
787  break;
788  }
789 
790  diff = uclock() - start;
791  if (debug)
792  SOCK_DEBUGF ((", diff: %.6fs", (double)diff/(double)UCLOCKS_PER_SEC));
793 
794  fputc ('.', stderr);
795  usleep (100000UL);
796 
797  if (FD_ISSET(0,&read[0]))
798  {
799  int ch = getch();
800  fputc (ch, stderr);
801  if (ch == 'q')
802  break;
803  }
804  }
805  return (0);
806 }
807 #endif /* TEST_PROG */
Definition: wtypes.h:197
int W32_CALL select_s(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
The select_s() function.
Definition: select.c:112
Definition: socket.h:137
static struct timeval sel_min_block
The smallest time for not yielding or calling tcp_tick().
Definition: select.c:68
static int exc_select(int s, Socket *socket)
Definition: select.c:624
Definition: if.h:84
Socket * _socklist_find(int s)
Returns a pointer to the Socket structure associated with socket 's'.
Definition: socket.c:1534
BOOL _sock_dos_fd(int s)
_sock_dos_fd - Return TRUE if `s' is a valid DOS/Win32 handle.
Definition: socket.c:222
Definition: wtime.h:38
BOOL has_8254
Do we have a working 8254 timer chip?
Definition: timer.c:56
void _sock_crit_start(void)
Start a critical region.
Definition: socket.c:1296
int W32_CALL watt_kbhit(void)
A less CPU hogging kbhit().
Definition: misc.c:900
void _sock_crit_stop(void)
Mark the end of a critical region.
Definition: socket.c:1306
int hires_timer(int on)
Control use of high-resolution timer.
Definition: timer.c:377
Definition: wtime.h:87
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
int main(int argc, char **argv)
Definition: echo.c:223
UINT state
tcp connection state
Definition: wattcp.h:622