Initial implementation of new select-registry mechanism. This simply
authorChris Hanson <org/chris-hanson/cph>
Sat, 29 Mar 2003 05:35:55 +0000 (05:35 +0000)
committerChris Hanson <org/chris-hanson/cph>
Sat, 29 Mar 2003 05:35:55 +0000 (05:35 +0000)
recreates the old behavior with the new interface.

v7/src/microcode/ntio.c
v7/src/microcode/ntio.h
v7/src/microcode/ntsock.c

index 0b4b7fc25d02d2fea1dea3e856626958ff8c0f01..feda337901ba84d1d48f90fc9c42e222605a27b3 100644 (file)
@@ -1,8 +1,8 @@
 /* -*-C-*-
 
-$Id: ntio.c,v 1.27 2003/02/14 18:48:12 cph Exp $
+$Id: ntio.c,v 1.28 2003/03/29 05:35:49 cph Exp $
 
-Copyright 1992-2001 Massachusetts Institute of Technology
+Copyright 1993,1997,1998,2000,2001,2003 Massachusetts Institute of Technology
 
 This file is part of MIT/GNU Scheme.
 
@@ -27,6 +27,7 @@ USA.
 #include "prims.h"
 #include "nt.h"
 #include "ntio.h"
+#include "ntgui.h"
 #include "osterm.h"
 #include "osfile.h"
 #include "outf.h"
@@ -49,6 +50,12 @@ channel_class_t * NT_channel_class_named_pipe;
 
 static Tchannel channel_allocate (void);
 static long cooked_channel_write (Tchannel, const void *, unsigned long) ;
+static int wait_on_multiple_objects (struct select_registry_s *);
+static int test_multiple_objects (struct select_registry_s *);
+static int wait_on_single_object (Tchannel, unsigned int);
+static int test_single_object (Tchannel, unsigned int);
+static unsigned int test_single_object_1 (Tchannel, unsigned int);
+static int test_for_pending_event (void);
 \f
 #ifndef NT_DEFAULT_CHANNEL_TABLE_SIZE
 #define NT_DEFAULT_CHANNEL_TABLE_SIZE 1024
@@ -248,8 +255,7 @@ generic_channel_write (Tchannel channel, const void * buffer,
 static long
 generic_channel_n_read (Tchannel channel)
 {
-  /* This means "unknown".  */
-  return (-2);
+  return (CHANNEL_N_READ_UNKNOWN);
 }
 
 static void
@@ -320,7 +326,7 @@ screen_channel_n_read (Tchannel channel)
   /* This is incorrect.  However, it's a pain to do the right thing.
      Furthermore, NT_channel_n_read is only used by "select", and for
      that particular case, this is the correct value.  */
-  return (-1);
+  return (CHANNEL_N_READ_WOULD_BLOCK);
 }
 
 static void
@@ -395,8 +401,7 @@ pipe_channel_n_read (Tchannel channel)
   fprintf (trace_file, "pipe_channel_n_read: n=%d\n", n);
   fflush (trace_file);
 #endif
-  /* Zero bytes available means "read would block", so return -1.  */
-  return ((n == 0) ? (-1) : n);
+  return ((n == 0) ? CHANNEL_N_READ_WOULD_BLOCK : n);
 }
 
 static void
@@ -683,3 +688,261 @@ NT_initialize_channels (void)
   initialize_channel_class_anonymous_pipe ();
   initialize_channel_class_named_pipe ();
 }
+\f
+struct select_registry_s
+{
+  unsigned int n_channels;
+  unsigned int length;
+  Tchannel * channels;
+  unsigned int * qmodes;
+  unsigned int * rmodes;
+};
+
+select_registry_t
+OS_allocate_select_registry (void)
+{
+  struct select_registry_s * r
+    = (OS_malloc (sizeof (struct select_registry_s)));
+  (r -> n_channels) = 0;
+  (r -> length) = 16;
+  (r -> channels) = (OS_malloc ((sizeof (Tchannel)) * (r -> length)));
+  (r -> qmodes) = (OS_malloc ((sizeof (unsigned int)) * (r -> length)));
+  (r -> rmodes) = (OS_malloc ((sizeof (unsigned int)) * (r -> length)));
+  return (r);
+}
+
+void
+OS_deallocate_select_registry (select_registry_t registry)
+{
+  struct select_registry_s * r = registry;
+  OS_free (r -> rmodes);
+  OS_free (r -> qmodes);
+  OS_free (r -> channels);
+  OS_free (r);
+}
+
+void
+OS_add_to_select_registry (select_registry_t registry, int fd,
+                          unsigned int mode)
+{
+  struct select_registry_s * r = registry;
+  Tchannel channel = fd;
+  unsigned int i = 0;
+
+  while (i < (r -> n_channels))
+    {
+      if (((r -> channels) [i]) == channel)
+       {
+         ((r -> qmodes) [i]) |= mode;
+         return;
+       }
+      i += 1;
+    }
+  if (i == (r -> length))
+    {
+      (r -> length) *= 2;
+      (r -> channels) = (OS_realloc ((r -> channels), (r -> length)));
+      (r -> qmodes) = (OS_realloc ((r -> qmodes), (r -> length)));
+      (r -> rmodes) = (OS_realloc ((r -> rmodes), (r -> length)));
+    }
+  ((r -> channels) [i]) = channel;
+  ((r -> qmodes) [i]) = mode;
+  (r -> n_channels) += 1;
+}
+\f
+void
+OS_remove_from_select_registry (select_registry_t registry, int fd,
+                               unsigned int mode)
+{
+  struct select_registry_s * r = registry;
+  Tchannel channel = fd;
+  unsigned int i = 0;
+
+  while (1)
+    {
+      if (i == (r -> n_channels))
+       return;
+      if (((r -> channels) [i]) == channel)
+       {
+         ((r -> qmodes) [i]) &=~ mode;
+         if (((r -> qmodes) [i]) == 0)
+           break;
+         else
+           return;
+       }
+      i += 1;
+    }
+  while (i < (r -> n_channels))
+    {
+      ((r -> channels) [i]) = ((r -> channels) [(i + 1)]);
+      ((r -> qmodes) [i]) = ((r -> qmodes) [(i + 1)]);
+      i += 1;
+    }
+  (r -> n_channels) -= 1;
+
+  if (((r -> length) > 16) && ((r -> n_channels) < ((r -> length) / 2)))
+    {
+      (r -> length) /= 2;
+      (r -> channels) = (OS_realloc ((r -> channels), (r -> length)));
+      (r -> qmodes) = (OS_realloc ((r -> qmodes), (r -> length)));
+      (r -> rmodes) = (OS_realloc ((r -> rmodes), (r -> length)));
+    }
+}
+
+unsigned int
+OS_select_registry_length (select_registry_t registry)
+{
+  struct select_registry_s * r = registry;
+  return (r -> n_channels);
+}
+
+void
+OS_select_registry_result (select_registry_t registry, unsigned int index,
+                          int * fd_r, unsigned int * mode_r)
+{
+  struct select_registry_s * r = registry;
+  (*fd_r) = ((r -> channels) [index]);
+  (*mode_r) = ((r -> rmodes) [index]);
+}
+\f
+int
+OS_test_select_registry (select_registry_t registry, int blockp)
+{
+  struct select_registry_s * r = registry;
+  if (win32_trace_level > 1)
+    {
+      fprintf (win32_trace_file, "OS_test_select_registry: ");
+      fprintf (win32_trace_file, "n_channels=%d blockp=%d\n",
+              (r -> n_channels), blockp);
+      fflush (win32_trace_file);
+    }
+  {
+    int result
+      = (blockp
+        ? (wait_on_multiple_objects (r))
+        : (test_multiple_objects (r)));
+    if (win32_trace_level > 1)
+      {
+       fprintf (win32_trace_file, "OS_test_select_registry: ");
+       fprintf (win32_trace_file, "result=%d\n", result);
+       fflush (win32_trace_file);
+      }
+    return (result);
+  }
+}
+
+static int
+wait_on_multiple_objects (struct select_registry_s * r)
+{
+  while (1)
+    {
+      {
+       int result = (test_multiple_objects (r));
+       if (result != 0)
+         return (result);
+      }
+      /* Block waiting for a message to arrive.  The asynchronous
+        interrupt thread guarantees that a message will arrive in a
+        reasonable amount of time.  */
+      if ((MsgWaitForMultipleObjects (0, 0, FALSE, INFINITE, QS_ALLINPUT))
+         == WAIT_FAILED)
+       NT_error_api_call
+         ((GetLastError ()), apicall_MsgWaitForMultipleObjects);
+    }
+}
+
+static int
+test_multiple_objects (struct select_registry_s * r)
+{
+  unsigned int i;
+  unsigned int j;
+
+  j = 0;
+  for (i = 0; (i < (r -> n_channels)); i += 1)
+    {
+      ((r -> rmodes) [i])
+       = (test_single_object_1 (((r -> channels) [i]),
+                                ((r -> qmodes) [i])));
+      if (((r -> rmodes) [i]) != 0)
+       j += 1;
+    }
+  return
+    ((j > 0)
+     ? j
+     : (pending_interrupts_p ())
+     ? SELECT_INTERRUPT
+     : (OS_process_any_status_change ())
+     ? SELECT_PROCESS_STATUS_CHANGE
+     : 0);
+}
+\f
+int
+OS_test_select_descriptor (int fd, int blockp, unsigned int qmode)
+{
+  Tchannel channel = fd;
+  return
+    (blockp
+     ? (wait_on_single_object (channel, qmode))
+     : (test_single_object (channel, qmode)));
+}
+
+static int
+wait_on_single_object (Tchannel channel, unsigned int qmode)
+{
+  while (1)
+    {
+      int result = (test_single_object (channel, qmode));
+      if (result != 0)
+       return (result);
+
+      /* Block waiting for a message to arrive.  The asynchronous
+        interrupt thread guarantees that a message will arrive in a
+        reasonable amount of time.  */
+      if ((MsgWaitForMultipleObjects (0, 0, FALSE, INFINITE, QS_ALLINPUT))
+         == WAIT_FAILED)
+       NT_error_api_call
+         ((GetLastError ()), apicall_MsgWaitForMultipleObjects);
+    }
+}
+
+static int
+test_single_object (Tchannel channel, unsigned int qmode)
+{
+  unsigned int rmode = (test_single_object_1 (channel, qmode));
+  return
+    ((rmode > 0)
+     ? rmode
+     : (pending_interrupts_p ())
+     ? SELECT_INTERRUPT
+     : (OS_process_any_status_change ())
+     ? SELECT_PROCESS_STATUS_CHANGE
+     : 0);
+}
+  
+
+static unsigned int
+test_single_object_1 (Tchannel channel, unsigned int qmode)
+{
+  unsigned int rmode = (qmode & SELECT_MODE_WRITE);
+  if (((qmode & SELECT_MODE_READ) != 0)
+      && ((channel == (OS_tty_input_channel ()))
+         ? ((Screen_pending_events_p ()) || (test_for_pending_event ()))
+         : ((NT_channel_n_read (channel)) > 0)))
+    rmode |= SELECT_MODE_READ;
+  return (rmode);
+}
+
+static int
+test_for_pending_event (void)
+{
+  while (1)
+    {
+      MSG m;
+      int mp = (PeekMessage ((&m), 0, 0, 0, PM_NOREMOVE));
+      if (!mp)
+       return (0);
+      if ((m . message) != WM_SCHEME_INTERRUPT)
+       return (1);
+      PeekMessage ((&m), 0, 0, 0, PM_REMOVE);
+    }
+}
index e5581130c985d6686787f57c898c4a1d3abfcecd..f294962e3e7ed7fe4618caae9867f4d6464b195d 100644 (file)
@@ -1,8 +1,8 @@
 /* -*-C-*-
 
-$Id: ntio.h,v 1.13 2003/02/14 18:28:20 cph Exp $
+$Id: ntio.h,v 1.14 2003/03/29 05:35:52 cph Exp $
 
-Copyright (c) 1992-1999 Massachusetts Institute of Technology
+Copyright 1993,1994,1997,2003 Massachusetts Institute of Technology
 
 This file is part of MIT/GNU Scheme.
 
@@ -48,6 +48,9 @@ typedef struct _channel_class_t
 #define CHANNEL_CLASS_OP_CLOSE(class) ((class) -> op_close)
 #define CHANNEL_CLASS_OP_N_READ(class) ((class) -> op_n_read)
 
+#define CHANNEL_N_READ_UNKNOWN (-2)
+#define CHANNEL_N_READ_WOULD_BLOCK (-1)
+
 struct channel
 {
   channel_class_t * class;
index 1744fbb2879ae6df6e62a66402ed1d09fe046229..6d93fa4e4cdf313373141a3030f0f00fa44129bd 100644 (file)
@@ -1,8 +1,8 @@
 /* -*-C-*-
 
-$Id: ntsock.c,v 1.15 2003/02/14 18:28:21 cph Exp $
+$Id: ntsock.c,v 1.16 2003/03/29 05:35:55 cph Exp $
 
-Copyright (c) 1997-2002 Massachusetts Institute of Technology
+Copyright 1997,1998,1999,2001,2002,2003 Massachusetts Institute of Technology
 
 This file is part of MIT/GNU Scheme.
 
@@ -295,8 +295,7 @@ socket_channel_n_read (Tchannel channel)
 {
   unsigned long n;
   VOID_SOCKET_CALL (ioctlsocket, ((CHANNEL_SOCKET (channel)), FIONREAD, (&n)));
-  /* Zero bytes available means "read would block", so return -1.  */
-  return ((n == 0) ? (-1) : n);
+  return ((n == 0) ? CHANNEL_N_READ_WOULD_BLOCK : n);
 }
 
 static long