]> git.eshelyaron.com Git - emacs.git/commitdiff
Prepare process.c for threads by not having global select masks.
authorTom Tromey <tromey@redhat.com>
Wed, 15 Aug 2012 19:17:37 +0000 (13:17 -0600)
committerTom Tromey <tromey@redhat.com>
Wed, 15 Aug 2012 19:17:37 +0000 (13:17 -0600)
The next step is to make it so selects can choose fds by thread.

src/process.c

index 2a61b6da777ac3b06b6ba10904b44d5c38ac1289..0d3355512b8e2024e945c5ed91e8ffd01af59eb3 100644 (file)
@@ -267,29 +267,7 @@ static void create_pty (Lisp_Object);
 static Lisp_Object get_process (register Lisp_Object name);
 static void exec_sentinel (Lisp_Object proc, Lisp_Object reason);
 
-/* Mask of bits indicating the descriptors that we wait for input on.  */
-
-static SELECT_TYPE input_wait_mask;
-
-/* Mask that excludes keyboard input descriptor(s).  */
-
-static SELECT_TYPE non_keyboard_wait_mask;
-
-/* Mask that excludes process input descriptor(s).  */
-
-static SELECT_TYPE non_process_wait_mask;
-
-/* Mask for selecting for write.  */
-
-static SELECT_TYPE write_mask;
-
 #ifdef NON_BLOCKING_CONNECT
-/* Mask of bits indicating the descriptors that we wait for connect to
-   complete on.  Once they complete, they are removed from this mask
-   and added to the input_wait_mask and non_keyboard_wait_mask.  */
-
-static SELECT_TYPE connect_wait_mask;
-
 /* Number of bits set in connect_wait_mask.  */
 static int num_pending_connects;
 #endif /* NON_BLOCKING_CONNECT */
@@ -336,13 +314,27 @@ static int pty_max_bytes;
 
 \f
 
+enum fd_bits
+{
+  /* Read from file descriptor.  */
+  FOR_READ = 1,
+  /* Write to file descriptor.  */
+  FOR_WRITE = 2,
+  /* This descriptor refers to a keyboard.  Only valid if FOR_READ is
+     set.  */
+  KEYBOARD_FD = 4,
+  /* This descriptor refers to a process.  */
+  PROCESS_FD = 8,
+  /* A non-blocking connect.  Only valid if FOR_WRITE is set.  */
+  NON_BLOCKING_CONNECT_FD = 16
+};
+
 static struct fd_callback_data
 {
   fd_callback func;
   void *data;
-#define FOR_READ  1
-#define FOR_WRITE 2
-  int condition; /* mask of the defines above.  */
+  /* Flags from enum fd_bits.  */
+  int flags;
 } fd_callback_info[MAXDESC];
 
 
@@ -357,7 +349,23 @@ add_read_fd (int fd, fd_callback func, void *data)
 
   fd_callback_info[fd].func = func;
   fd_callback_info[fd].data = data;
-  fd_callback_info[fd].condition |= FOR_READ;
+}
+
+void
+add_non_keyboard_read_fd (int fd)
+{
+  eassert (fd >= 0 && fd < MAXDESC);
+  eassert (fd_callback_info[fd].func == NULL);
+  fd_callback_info[fd].flags |= FOR_READ;
+  if (fd > max_input_desc)
+    max_input_desc = fd;
+}
+
+void
+add_process_read_fd (int fd)
+{
+  add_non_keyboard_read_fd (fd);
+  fd_callback_info[fd].flags |= PROCESS_FD;
 }
 
 /* Stop monitoring file descriptor FD for when read is possible.  */
@@ -368,8 +376,7 @@ delete_read_fd (int fd)
   eassert (fd < MAXDESC);
   delete_keyboard_wait_descriptor (fd);
 
-  fd_callback_info[fd].condition &= ~FOR_READ;
-  if (fd_callback_info[fd].condition == 0)
+  if (fd_callback_info[fd].flags == 0)
     {
       fd_callback_info[fd].func = 0;
       fd_callback_info[fd].data = 0;
@@ -383,13 +390,24 @@ void
 add_write_fd (int fd, fd_callback func, void *data)
 {
   eassert (fd < MAXDESC);
-  FD_SET (fd, &write_mask);
   if (fd > max_input_desc)
     max_input_desc = fd;
 
   fd_callback_info[fd].func = func;
   fd_callback_info[fd].data = data;
-  fd_callback_info[fd].condition |= FOR_WRITE;
+  fd_callback_info[fd].flags |= FOR_WRITE;
+}
+
+void
+add_non_blocking_write_fd (int fd)
+{
+  eassert (fd >= 0 && fd < MAXDESC);
+  eassert (fd_callback_info[fd].func == NULL);
+
+  fd_callback_info[fd].flags |= FOR_WRITE | NON_BLOCKING_CONNECT_FD;
+  if (fd > max_input_desc)
+    max_input_desc = fd;
+  ++num_pending_connects;
 }
 
 /* Stop monitoring file descriptor FD for when write is possible.  */
@@ -400,24 +418,87 @@ delete_write_fd (int fd)
   int lim = max_input_desc;
 
   eassert (fd < MAXDESC);
-  FD_CLR (fd, &write_mask);
-  fd_callback_info[fd].condition &= ~FOR_WRITE;
-  if (fd_callback_info[fd].condition == 0)
+  if ((fd_callback_info[fd].flags & NON_BLOCKING_CONNECT_FD) != 0)
+    {
+      if (--num_pending_connects < 0)
+       abort ();
+    }
+  fd_callback_info[fd].flags &= ~(FOR_WRITE | NON_BLOCKING_CONNECT_FD);
+  if (fd_callback_info[fd].flags == 0)
     {
       fd_callback_info[fd].func = 0;
       fd_callback_info[fd].data = 0;
 
       if (fd == max_input_desc)
-        for (fd = lim; fd >= 0; fd--)
-          if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
-            {
-              max_input_desc = fd;
-              break;
-            }
+       {
+         for (fd = max_input_desc; fd >= 0; --fd)
+           {
+             if (fd_callback_info[fd].flags != 0)
+               {
+                 max_input_desc = fd;
+                 break;
+               }
+           }
+       }
+    }
+}
+
+static void
+compute_input_wait_mask (SELECT_TYPE *mask)
+{
+  int fd;
 
+  FD_ZERO (mask);
+  for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
+    {
+      if ((fd_callback_info[fd].flags & FOR_READ) != 0)
+       FD_SET (fd, mask);
     }
 }
 
+static void
+compute_non_process_wait_mask (SELECT_TYPE *mask)
+{
+  int fd;
+
+  FD_ZERO (mask);
+  for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
+    {
+      if ((fd_callback_info[fd].flags & FOR_READ) != 0
+         && (fd_callback_info[fd].flags & PROCESS_FD) == 0)
+       FD_SET (fd, mask);
+    }
+}
+
+static void
+compute_non_keyboard_wait_mask (SELECT_TYPE *mask)
+{
+  int fd;
+
+  FD_ZERO (mask);
+  for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
+    {
+      if ((fd_callback_info[fd].flags & FOR_READ) != 0
+         && (fd_callback_info[fd].flags & KEYBOARD_FD) == 0)
+       FD_SET (fd, mask);
+    }
+}
+
+static void
+compute_write_mask (SELECT_TYPE *mask)
+{
+  int fd;
+
+  FD_ZERO (mask);
+  for (fd = 0; fd < max (max_process_desc, max_input_desc); ++fd)
+    {
+      if ((fd_callback_info[fd].flags & FOR_WRITE) != 0)
+       FD_SET (fd, mask);
+    }
+}
+
+
+
 \f
 /* Compute the Lisp form of the process status, p->status, from
    the numeric status that was returned by `wait'.  */
@@ -961,17 +1042,11 @@ The string argument is normally a multibyte string, except:
   if (p->infd >= 0)
     {
       if (EQ (filter, Qt) && !EQ (p->status, Qlisten))
-       {
-         FD_CLR (p->infd, &input_wait_mask);
-         FD_CLR (p->infd, &non_keyboard_wait_mask);
-       }
+       delete_read_fd (p->infd);
       else if (EQ (p->filter, Qt)
               /* Network or serial process not stopped:  */
               && !EQ (p->command, Qt))
-       {
-         FD_SET (p->infd, &input_wait_mask);
-         FD_SET (p->infd, &non_keyboard_wait_mask);
-       }
+       delete_read_fd (p->infd);
     }
 
   PSET (p, filter, filter);
@@ -1650,10 +1725,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 #endif /* HAVE_WORKING_VFORK */
   pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
 
-  FD_SET (inchannel, &input_wait_mask);
-  FD_SET (inchannel, &non_keyboard_wait_mask);
-  if (inchannel > max_process_desc)
-    max_process_desc = inchannel;
+  add_non_keyboard_read_fd (inchannel);
 
   /* Until we store the proper pid, enable sigchld_handler
      to recognize an unknown pid as standing for this process.
@@ -1968,10 +2040,7 @@ create_pty (Lisp_Object process)
   PSET (XPROCESS (process), status, Qrun);
   setup_process_coding_systems (process);
 
-  FD_SET (inchannel, &input_wait_mask);
-  FD_SET (inchannel, &non_keyboard_wait_mask);
-  if (inchannel > max_process_desc)
-    max_process_desc = inchannel;
+  add_non_keyboard_read_fd (inchannel);
 
   XPROCESS (process)->pid = -2;
 #ifdef HAVE_PTYS
@@ -2616,10 +2685,7 @@ usage:  (make-serial-process &rest ARGS)  */)
   p->pty_flag = 0;
 
   if (!EQ (p->command, Qt))
-    {
-      FD_SET (fd, &input_wait_mask);
-      FD_SET (fd, &non_keyboard_wait_mask);
-    }
+    add_non_keyboard_read_fd (fd);
 
   if (BUFFERP (buffer))
     {
@@ -3431,12 +3497,8 @@ usage: (make-network-process &rest ARGS)  */)
         in that case, we still need to signal this like a non-blocking
         connection.  */
       PSET (p, status, Qconnect);
-      if (!FD_ISSET (inch, &connect_wait_mask))
-       {
-         FD_SET (inch, &connect_wait_mask);
-         FD_SET (inch, &write_mask);
-         num_pending_connects++;
-       }
+      if ((fd_callback_info[inch].flags & NON_BLOCKING_CONNECT_FD) == 0)
+       add_non_blocking_write_fd (inch);
     }
   else
 #endif
@@ -3444,10 +3506,7 @@ usage: (make-network-process &rest ARGS)  */)
        still listen for incoming connects unless it is stopped.  */
     if ((!EQ (p->filter, Qt) && !EQ (p->command, Qt))
        || (EQ (p->status, Qlisten) && NILP (p->command)))
-      {
-       FD_SET (inch, &input_wait_mask);
-       FD_SET (inch, &non_keyboard_wait_mask);
-      }
+      add_non_keyboard_read_fd (inch);
 
   if (inch > max_process_desc)
     max_process_desc = inch;
@@ -3892,16 +3951,10 @@ deactivate_process (Lisp_Object proc)
        }
 #endif
       chan_process[inchannel] = Qnil;
-      FD_CLR (inchannel, &input_wait_mask);
-      FD_CLR (inchannel, &non_keyboard_wait_mask);
+      delete_read_fd (inchannel);
 #ifdef NON_BLOCKING_CONNECT
-      if (FD_ISSET (inchannel, &connect_wait_mask))
-       {
-         FD_CLR (inchannel, &connect_wait_mask);
-         FD_CLR (inchannel, &write_mask);
-         if (--num_pending_connects < 0)
-           abort ();
-       }
+      if ((fd_callback_info[inchannel].flags & NON_BLOCKING_CONNECT_FD) != 0)
+       delete_write_fd (inchannel);
 #endif
       if (inchannel == max_process_desc)
        {
@@ -4165,13 +4218,7 @@ server_accept_connection (Lisp_Object server, int channel)
 
   /* Client processes for accepted connections are not stopped initially.  */
   if (!EQ (p->filter, Qt))
-    {
-      FD_SET (s, &input_wait_mask);
-      FD_SET (s, &non_keyboard_wait_mask);
-    }
-
-  if (s > max_process_desc)
-    max_process_desc = s;
+    add_non_keyboard_read_fd (s);
 
   /* Setup coding system for new process based on server process.
      This seems to be the proper thing to do, as the coding system
@@ -4433,8 +4480,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
           if (kbd_on_hold_p ())
             FD_ZERO (&Atemp);
           else
-            Atemp = input_wait_mask;
-         Ctemp = write_mask;
+            compute_input_wait_mask (&Atemp);
+         compute_write_mask (&Ctemp);
 
          timeout = make_emacs_time (0, 0);
          if ((pselect (max (max_process_desc, max_input_desc) + 1,
@@ -4512,17 +4559,17 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
        }
       else if (!NILP (wait_for_cell))
        {
-         Available = non_process_wait_mask;
+         compute_non_process_wait_mask (&Available);
          check_delay = 0;
          check_write = 0;
        }
       else
        {
          if (! read_kbd)
-           Available = non_keyboard_wait_mask;
+           compute_non_keyboard_wait_mask (&Available);
          else
-           Available = input_wait_mask;
-          Writeok = write_mask;
+           compute_input_wait_mask (&Available);
+         compute_write_mask (&Writeok);
 #ifdef SELECT_CANT_DO_WRITE_MASK
           check_write = 0;
 #else
@@ -4790,19 +4837,19 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
           struct fd_callback_data *d = &fd_callback_info[channel];
           if (FD_ISSET (channel, &Available)
               && d->func != 0
-              && (d->condition & FOR_READ) != 0)
+              && (d->flags & FOR_READ) != 0)
             d->func (channel, d->data, 1);
           if (FD_ISSET (channel, &Writeok)
               && d->func != 0
-              && (d->condition & FOR_WRITE) != 0)
+              && (d->flags & FOR_WRITE) != 0)
             d->func (channel, d->data, 0);
           }
 
       for (channel = 0; channel <= max_process_desc; channel++)
        {
          if (FD_ISSET (channel, &Available)
-             && FD_ISSET (channel, &non_keyboard_wait_mask)
-              && !FD_ISSET (channel, &non_process_wait_mask))
+             && ((fd_callback_info[channel].flags & (KEYBOARD_FD | PROCESS_FD))
+                 == PROCESS_FD))
            {
              int nread;
 
@@ -4880,8 +4927,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 
                  /* Clear the descriptor now, so we only raise the
                     signal once.  */
-                 FD_CLR (channel, &input_wait_mask);
-                 FD_CLR (channel, &non_keyboard_wait_mask);
+                 delete_read_fd (channel);
 
                  if (p->pid == -2)
                    {
@@ -4915,14 +4961,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
            }
 #ifdef NON_BLOCKING_CONNECT
          if (FD_ISSET (channel, &Writeok)
-             && FD_ISSET (channel, &connect_wait_mask))
+             && (fd_callback_info[channel].flags
+                 & NON_BLOCKING_CONNECT_FD) != 0)
            {
              struct Lisp_Process *p;
 
-             FD_CLR (channel, &connect_wait_mask);
-              FD_CLR (channel, &write_mask);
-             if (--num_pending_connects < 0)
-               abort ();
+             delete_write_fd (channel);
 
              proc = chan_process[channel];
              if (NILP (proc))
@@ -4970,10 +5014,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                     from the process before calling the sentinel.  */
                  exec_sentinel (proc, build_string ("open\n"));
                  if (!EQ (p->filter, Qt) && !EQ (p->command, Qt))
-                   {
-                     FD_SET (p->infd, &input_wait_mask);
-                     FD_SET (p->infd, &non_keyboard_wait_mask);
-                   }
+                   delete_read_fd (p->infd);
                }
            }
 #endif /* NON_BLOCKING_CONNECT */
@@ -6014,10 +6055,7 @@ traffic.  */)
       p = XPROCESS (process);
       if (NILP (p->command)
          && p->infd >= 0)
-       {
-         FD_CLR (p->infd, &input_wait_mask);
-         FD_CLR (p->infd, &non_keyboard_wait_mask);
-       }
+       delete_read_fd (p->infd);
       PSET (p, command, Qt);
       return process;
     }
@@ -6045,8 +6083,7 @@ traffic.  */)
          && p->infd >= 0
          && (!EQ (p->filter, Qt) || EQ (p->status, Qlisten)))
        {
-         FD_SET (p->infd, &input_wait_mask);
-         FD_SET (p->infd, &non_keyboard_wait_mask);
+         add_non_keyboard_read_fd (p->infd);
 #ifdef WINDOWSNT
          if (fd_info[ p->infd ].flags & FILE_SERIAL)
            PurgeComm (fd_info[ p->infd ].hnd, PURGE_RXABORT | PURGE_RXCLEAR);
@@ -6419,10 +6456,7 @@ sigchld_handler (int signo)
 
          /* We use clear_desc_flag to avoid a compiler bug in Microsoft C.  */
          if (clear_desc_flag)
-           {
-             FD_CLR (p->infd, &input_wait_mask);
-             FD_CLR (p->infd, &non_keyboard_wait_mask);
-           }
+           delete_read_fd (p->infd);
 
          /* Tell wait_reading_process_output that it needs to wake up and
             look around.  */
@@ -6796,8 +6830,8 @@ keyboard_bit_set (fd_set *mask)
   int fd;
 
   for (fd = 0; fd <= max_input_desc; fd++)
-    if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask)
-       && !FD_ISSET (fd, &non_keyboard_wait_mask))
+    if (FD_ISSET (fd, mask)
+       && ((fd_callback_info[fd].flags & KEYBOARD_FD) != 0))
       return 1;
 
   return 0;
@@ -7042,8 +7076,8 @@ void
 add_keyboard_wait_descriptor (int desc)
 {
 #ifdef subprocesses /* actually means "not MSDOS" */
-  FD_SET (desc, &input_wait_mask);
-  FD_SET (desc, &non_process_wait_mask);
+  eassert (desc >= 0 && desc < MAXDESC);
+  fd_callback_info[desc].flags |= FOR_READ | KEYBOARD_FD;
   if (desc > max_input_desc)
     max_input_desc = desc;
 #endif
@@ -7058,13 +7092,19 @@ delete_keyboard_wait_descriptor (int desc)
   int fd;
   int lim = max_input_desc;
 
-  FD_CLR (desc, &input_wait_mask);
-  FD_CLR (desc, &non_process_wait_mask);
+  fd_callback_info[desc].flags &= ~(FOR_READ | KEYBOARD_FD | PROCESS_FD);
 
   if (desc == max_input_desc)
-    for (fd = 0; fd < lim; fd++)
-      if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
-        max_input_desc = fd;
+    {
+      for (fd = max_input_desc; fd >= 0; --fd)
+       {
+         if (fd_callback_info[desc].flags != 0)
+           {
+             max_input_desc = fd;
+             break;
+           }
+       }
+    }
 #endif
 }
 
@@ -7320,15 +7360,10 @@ init_process_emacs (void)
     signal (SIGCHLD, sigchld_handler);
 #endif
 
-  FD_ZERO (&input_wait_mask);
-  FD_ZERO (&non_keyboard_wait_mask);
-  FD_ZERO (&non_process_wait_mask);
-  FD_ZERO (&write_mask);
   max_process_desc = 0;
   memset (fd_callback_info, 0, sizeof (fd_callback_info));
 
 #ifdef NON_BLOCKING_CONNECT
-  FD_ZERO (&connect_wait_mask);
   num_pending_connects = 0;
 #endif