OSDN Git Service

* fhandler.h (fhandler_tty_slave): Declare new methods.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / select.cc
index d3c607a..1823cd1 100644 (file)
@@ -1,6 +1,6 @@
 /* select.cc
 
-   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
 
    Written by Christopher Faylor of Cygnus Solutions
    cgf@cygnus.com
@@ -20,17 +20,26 @@ details. */
 #define  __INSIDE_CYGWIN_NET__
 #define Win32_Winsock
 
+#include "winsup.h"
 #include <errno.h>
 #include <sys/socket.h>
 #include <stdlib.h>
 #include <sys/time.h>
 
-#include "winsup.h"
+#include <wingdi.h>
+#include <winuser.h>
 #include <netdb.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <winsock.h>
 #include "select.h"
+#include "cygerrno.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "sync.h"
+#include "sigproc.h"
+#include "perthread.h"
+#include "tty.h"
 
 /*
  * All these defines below should be in sys/types.h
@@ -69,7 +78,7 @@ typedef long fd_mask;
 #define UNIX_FD_ZERO(p, n) \
   bzero ((caddr_t)(p), sizeof_fd_set ((n)))
 
-#define allocfd_set(n) ((fd_set *) alloca (sizeof_fd_set (n)))
+#define allocfd_set(n) ((fd_set *) memset (alloca (sizeof_fd_set (n)), 0, sizeof_fd_set (n)))
 #define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n));
 
 /* Make a fhandler_foo::ready_for_ready method.
@@ -83,7 +92,7 @@ fhandler_##what::ready_for_read (int fd, DWORD howlong, int ignra) \
   me.fd = fd; \
   (void) select_read (&me); \
   while (!peek_##what (&me, ignra) && howlong == INFINITE) \
-    if (fd >= 0 && dtable.not_open (fd)) \
+    if (fd >= 0 && fdtab.not_open (fd)) \
       break; \
     else if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0) \
       break; \
@@ -92,7 +101,7 @@ fhandler_##what::ready_for_read (int fd, DWORD howlong, int ignra) \
 
 #define set_handle_or_return_if_not_open(h, s) \
   h = (s)->fh->get_handle (); \
-  if (dtable.not_open ((s)->fd)) \
+  if (fdtab.not_open ((s)->fd)) \
     { \
       (s)->saw_error = TRUE; \
       set_errno (EBADF); \
@@ -103,14 +112,14 @@ fhandler_##what::ready_for_read (int fd, DWORD howlong, int ignra) \
  */
 extern "C"
 int
-cygwin_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
-                    struct timeval *to)
+cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+              struct timeval *to)
 {
   select_stuff sel;
-  fd_set *dummy_readfds = allocfd_set (n);
-  fd_set *dummy_writefds = allocfd_set (n);
-  fd_set *dummy_exceptfds = allocfd_set (n);
-  sigframe thisframe (mainthread, 0);
+  fd_set *dummy_readfds = allocfd_set (maxfds);
+  fd_set *dummy_writefds = allocfd_set (maxfds);
+  fd_set *dummy_exceptfds = allocfd_set (maxfds);
+  sigframe thisframe (mainthread);
 
 #if 0
   if (n > FD_SETSIZE)
@@ -120,25 +129,16 @@ cygwin_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
     }
 #endif
 
-  select_printf ("%d, %p, %p, %p, %p", n, readfds, writefds, exceptfds, to);
+  select_printf ("%d, %p, %p, %p, %p", maxfds, readfds, writefds, exceptfds, to);
 
   if (!readfds)
-    {
-      UNIX_FD_ZERO (dummy_readfds, n);
-      readfds = dummy_readfds;
-    }
+    readfds = dummy_readfds;
   if (!writefds)
-    {
-      UNIX_FD_ZERO (dummy_writefds, n);
-      writefds = dummy_writefds;
-    }
+    writefds = dummy_writefds;
   if (!exceptfds)
-    {
-      UNIX_FD_ZERO (dummy_exceptfds, n);
-      exceptfds = dummy_exceptfds;
-    }
+    exceptfds = dummy_exceptfds;
 
-  for (int i = 0; i < n; i++)
+  for (int i = 0; i < maxfds; i++)
     if (!sel.test_and_set (i, readfds, writefds, exceptfds))
       {
        select_printf ("aborting due to test_and_set error");
@@ -169,18 +169,20 @@ cygwin_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
       return 0;
     }
 
-  /* If one of the selected fds is "always ready" just poll everything and return
-     the result.  There is no need to wait. */
-  if (sel.always_ready || ms == 0)
-    {
-      UNIX_FD_ZERO (readfds, n);
-      UNIX_FD_ZERO (writefds, n);
-      UNIX_FD_ZERO (exceptfds, n);
-      return sel.poll (readfds, writefds, exceptfds);
-    }
+  /* Allocate some fd_set structures using the number of fds as a guide. */
+  fd_set *r = allocfd_set (maxfds);
+  fd_set *w = allocfd_set (maxfds);
+  fd_set *e = allocfd_set (maxfds);
 
-  /* Wait for an fd to come alive */
-  return sel.wait (readfds, writefds, exceptfds, ms);
+  if (sel.always_ready || ms == 0)
+    /* Don't bother waiting. */;
+  else if (sel.wait (r, w, e, ms))
+    return -1; /* some kind of error */
+
+  copyfd_set (readfds, r, maxfds);
+  copyfd_set (writefds, w, maxfds);
+  copyfd_set (exceptfds, e, maxfds);
+  return sel.poll (readfds, writefds, exceptfds);
 }
 
 /* Cleanup */
@@ -209,11 +211,11 @@ select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds,
                            fd_set *exceptfds)
 {
   select_record *s = NULL;
-  if (UNIX_FD_ISSET (i, readfds) && (s = dtable.select_read (i, s)) == NULL)
+  if (UNIX_FD_ISSET (i, readfds) && (s = fdtab.select_read (i, s)) == NULL)
     return 0; /* error */
-  if (UNIX_FD_ISSET (i, writefds) && (s = dtable.select_write (i, s)) == NULL)
+  if (UNIX_FD_ISSET (i, writefds) && (s = fdtab.select_write (i, s)) == NULL)
     return 0; /* error */
-  if (UNIX_FD_ISSET (i, exceptfds) && (s = dtable.select_except (i, s)) == NULL)
+  if (UNIX_FD_ISSET (i, exceptfds) && (s = fdtab.select_except (i, s)) == NULL)
     return 0; /* error */
   if (s == NULL)
     return 1; /* nothing to do */
@@ -256,6 +258,11 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
      counting the number of active fds. */
   while ((s = s->next))
     {
+      if (m > MAXIMUM_WAIT_OBJECTS)
+       {
+         set_errno (EINVAL);
+         return -1;
+       }
       if (!s->startup (s, this))
        {
          __seterrno ();
@@ -271,17 +278,9 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
       continue;
     }
 
-  int n = m - 1;
   DWORD start_time = GetTickCount ();  /* Record the current time for later use. */
 
-  /* Allocate some fd_set structures using the number of fds as a guide. */
-  fd_set *r = allocfd_set (n);
-  fd_set *w = allocfd_set (n);
-  fd_set *e = allocfd_set (n);
-  UNIX_FD_ZERO (r, n);
-  UNIX_FD_ZERO (w, n);
-  UNIX_FD_ZERO (e, n);
-  debug_printf ("n %d, ms %u", n, ms);
+  debug_printf ("m %d, ms %u", m, ms);
   for (;;)
     {
       if (!windows_used)
@@ -311,7 +310,7 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
        if (s->saw_error)
          return -1;            /* Somebody detected an error */
        else if ((((wait_ret >= m && s->windows_handle) || s->h == w4[wait_ret])) &&
-           s->verify (s, r, w, e))
+           s->verify (s, readfds, writefds, exceptfds))
          gotone = TRUE;
 
       select_printf ("gotone %d", gotone);
@@ -337,11 +336,8 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
     }
 
 out:
-  copyfd_set (readfds, r, n);
-  copyfd_set (writefds, w, n);
-  copyfd_set (exceptfds, e, n);
-
-  return poll (readfds, writefds, exceptfds);
+  select_printf ("returning 0");
+  return 0;
 }
 
 static int
@@ -416,18 +412,29 @@ peek_pipe (select_record *s, int ignra)
          gotone = 1;
          goto out;
        }
-      if (fh->bg_check (SIGTTIN) <= 0)
+      if (fh->bg_check (SIGTTIN) <= bg_eof)
        {
          gotone = s->read_ready = 1;
          goto out;
        }
 
-      if (!ignra && fh->get_device () != FH_PTYM && fh->get_device () != FH_TTYM &&
-         fh->get_readahead_valid ())
+      switch (fh->get_device ())
        {
-         select_printf ("readahead");
-         gotone = s->read_ready = 1;
-         goto out;
+       case FH_PTYM:
+       case FH_TTYM:
+         if (((fhandler_pty_master *)fh)->need_nl)
+           {
+             gotone = s->read_ready = 1;
+             goto out;
+           }
+         break;
+       default:
+         if (!ignra && fh->get_readahead_valid ())
+           {
+             select_printf ("readahead");
+             gotone = s->read_ready = 1;
+             goto out;
+           }
        }
     }
 
@@ -595,7 +602,7 @@ fhandler_pipe::select_except (select_record *s)
 static int
 peek_console (select_record *me, int ignra)
 {
-  extern const char * get_nonascii_key (INPUT_RECORD& input_rec);
+  extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *);
   fhandler_console *fh = (fhandler_console *)me->fh;
 
   if (!me->read_selected)
@@ -616,10 +623,11 @@ peek_console (select_record *me, int ignra)
   INPUT_RECORD irec;
   DWORD events_read;
   HANDLE h;
+  char tmpbuf[17];
   set_handle_or_return_if_not_open (h, me);
 
   for (;;)
-    if (fh->bg_check (SIGTTIN) <= 0)
+    if (fh->bg_check (SIGTTIN) <= bg_eof)
       return me->read_ready = 1;
     else if (!PeekConsoleInput (h, &irec, 1, &events_read) || !events_read)
       break;
@@ -627,8 +635,15 @@ peek_console (select_record *me, int ignra)
       {
        if (irec.EventType == WINDOW_BUFFER_SIZE_EVENT)
          kill_pgrp (fh->tc->getpgid (), SIGWINCH);
+       else if (irec.EventType == MOUSE_EVENT &&
+                (irec.Event.MouseEvent.dwEventFlags == 0 ||
+                 irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
+         {
+           if (fh->mouse_aware ())
+             return me->read_ready = 1;
+         }
        else if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown == TRUE &&
-                (irec.Event.KeyEvent.uChar.AsciiChar || get_nonascii_key (irec)))
+                (irec.Event.KeyEvent.uChar.AsciiChar || get_nonascii_key (irec, tmpbuf)))
          return me->read_ready = 1;
 
        /* Read and discard the event */
@@ -658,6 +673,7 @@ fhandler_console::select_read (select_record *s)
       s->startup = no_startup;
       s->poll = poll_console;
       s->verify = poll_console;
+      set_cursor_maybe ();
     }
 
   s->h = get_handle ();
@@ -674,6 +690,7 @@ fhandler_console::select_write (select_record *s)
       s->startup = no_startup;
       s->poll = poll_console;
       s->verify = no_verify;
+      set_cursor_maybe ();
     }
 
   s->write_selected = TRUE;
@@ -690,6 +707,7 @@ fhandler_console::select_except (select_record *s)
       s->startup = no_startup;
       s->poll = poll_console;
       s->verify = no_verify;
+      set_cursor_maybe ();
     }
 
   s->except_selected = TRUE;
@@ -725,6 +743,53 @@ fhandler_tty_common::select_except (select_record *s)
   return ((fhandler_pipe *)this)->fhandler_pipe::select_except (s);
 }
 
+static int
+verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
+          fd_set *exceptfds)
+{
+  if (WaitForSingleObject (me->h, 0) == WAIT_OBJECT_0)
+    me->read_ready = 1;
+  return set_bits (me, readfds, writefds, exceptfds);
+}
+
+select_record *
+fhandler_tty_slave::select_read (select_record *s)
+{
+  if (!s)
+    s = new select_record;
+  s->h = input_available_event;
+  s->startup = no_startup;
+  s->poll = poll_pipe;
+  s->verify = verify_tty_slave;
+  s->read_selected = TRUE;
+  s->cleanup = NULL;
+  return s;
+}
+
+int
+fhandler_tty_slave::ready_for_read (int fd, DWORD howlong, int ignra)
+{
+  HANDLE w4[2];
+  if (!ignra && get_readahead_valid ())
+    {
+      select_printf ("readahead");
+      return 1;
+    }
+  w4[0] = signal_arrived;
+  w4[1] = input_available_event;
+  switch (WaitForMultipleObjects (2, w4, FALSE, howlong))
+    {
+    case WAIT_OBJECT_0 + 1:
+      return 1;
+    case WAIT_FAILED:
+      select_printf ( "wait failed %E" );
+    case WAIT_OBJECT_0:
+    case WAIT_TIMEOUT:
+    default:
+      return 0;
+    }
+}
+
 select_record *
 fhandler_dev_null::select_read (select_record *s)
 {
@@ -842,10 +907,10 @@ peek_serial (select_record *s, int)
     {
     case WAIT_OBJECT_0:
       if (!ClearCommError (h, &ev, &st))
-        {
-          debug_printf ("ClearCommError");
-          goto err;
-        }
+       {
+         debug_printf ("ClearCommError");
+         goto err;
+       }
       else if (!st.cbInQue)
        Sleep (to);
       else