diff src/process.c @ 263:727739f917cb r20-5b30

Import from CVS: tag r20-5b30
author cvs
date Mon, 13 Aug 2007 10:24:41 +0200
parents 11cf20601dec
children 966663fcf606
line wrap: on
line diff
--- a/src/process.c	Mon Aug 13 10:23:52 2007 +0200
+++ b/src/process.c	Mon Aug 13 10:24:41 2007 +0200
@@ -21,11 +21,13 @@
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* Synched up with: Mule 2.0, FSF 19.30. */
-
 /* This file has been Mule-ized except for `start-process-internal',
    `open-network-stream-internal' and `open-multicast-group-internal'. */
 
+/* This file has been split into process.c and process-unix.c by
+   Kirill M. Katsnelson <kkm@kis.ru>, so please bash him and not
+   the original author(s) */
+
 #include <config.h>
 
 #if !defined (NO_SUBPROCESSES)
@@ -38,25 +40,30 @@
 #include "commands.h"
 #include "events.h"
 #include "frame.h"
+#include "hash.h"
 #include "insdel.h"
 #include "lstream.h"
 #include "opaque.h"
 #include "process.h"
+#include "procimpl.h"
 #include "sysdep.h"
 #include "window.h"
 #ifdef FILE_CODING
 #include "file-coding.h"
 #endif
 
-#include <setjmp.h>
 #include "sysfile.h"
 #include "sysproc.h"
 #include "systime.h"
 #include "syssignal.h" /* Always include before systty.h */
-
 #include "systty.h"
 #include "syswait.h"
 
+Lisp_Object Qprocessp;
+
+/* Process methods */
+struct process_methods the_process_methods;
+
 /* a process object is a network connection when its pid field a cons
    (name of name of port we are connected to . foreign host name) */
 
@@ -64,6 +71,8 @@
 Lisp_Object Qrun, Qstop; /* Qexit from eval.c, Qsignal from data.c. */
 /* Qrun => Qopen, Qexit => Qclosed for "network connection" processes */
 Lisp_Object Qopen, Qclosed;
+/* Protocol families */
+Lisp_Object Qtcpip;
 
 #ifdef HAVE_MULTICAST
 Lisp_Object Qmulticast; /* Will be used for occasional warnings */
@@ -71,20 +80,16 @@
 
 /* t means use pty, nil means use a pipe,
    maybe other values to come.  */
-static Lisp_Object Vprocess_connection_type;
+Lisp_Object Vprocess_connection_type;
 
 #ifdef PROCESS_IO_BLOCKING
 /* List of port numbers or port names to set a blocking I/O mode.
    Nil means set a non-blocking I/O mode [default]. */
-static Lisp_Object network_stream_blocking_port_list;
+Lisp_Object network_stream_blocking_port_list;
 #endif  /* PROCESS_IO_BLOCKING */
 
-/* FSFmacs says:
-
-   These next two vars are non-static since sysdep.c uses them in the
-   emulation of `select'.  */
 /* Number of events of change of status of a process.  */
-static volatile int process_tick;
+volatile int process_tick;
 
 /* Number of events for which the user or sentinel has been notified.  */
 static int update_tick;
@@ -92,114 +97,14 @@
 /* Nonzero means delete a process right away if it exits.  */
 int delete_exited_processes;
 
-/* Indexed by descriptor, gives the process (if any) for that descriptor */
-Lisp_Object descriptor_to_process[MAXDESC];
+/* Hashtable which maps USIDs as returned by create_stream_pair_cb to
+   process objects. Processes are not GC-protected through this! */
+c_hashtable usid_to_process;
 
 /* List of process objects. */
 Lisp_Object Vprocess_list;
 
-Lisp_Object Qprocessp;
-
-/* Buffered-ahead input char from process, indexed by channel.
-   -1 means empty (no char is buffered).
-   Used on sys V where the only way to tell if there is any
-   output from the process is to read at least one char.
-   Always -1 on systems that support FIONREAD.  */
-
-#if 0 /* FSFmacs */
-/* FSFmacs says:
-   Don't make static; need to access externally.  */
-static int proc_buffered_char[MAXDESC];
-#endif
-
-#ifdef HAVE_PTYS
-/* The file name of the pty opened by allocate_pty.  */
-
-static char pty_name[24];
-#endif
-
 
-/************************************************************************/
-/*                        the process Lisp object                       */
-/************************************************************************/
-
-/*
- * Structure records pertinent information about open channels.
- * There is one channel associated with each process.
- */
-
-struct Lisp_Process
-{
-  struct lcrecord_header header;
-  /* Name of this process */
-  Lisp_Object name;
-  /* List of command arguments that this process was run with */
-  Lisp_Object command;
-  /* (funcall FILTER PROC STRING)  (if FILTER is non-nil)
-     to dispose of a bunch of chars from the process all at once */
-  Lisp_Object filter;
-  /* (funcall SENTINEL PROCESS) when process state changes */
-  Lisp_Object sentinel;
-  /* Buffer that output is going to */
-  Lisp_Object buffer;
-  /* Marker set to end of last buffer-inserted output from this process */
-  Lisp_Object mark;
-  /* Lisp_Int of subprocess' PID, or a cons of
-     service/host if this is really a network connection */
-  Lisp_Object pid;
-  /* Non-0 if this is really a ToolTalk channel. */
-  int connected_via_filedesc_p;
-#if 0 /* FSFmacs */
-  /* Perhaps it's cleaner this way, but FSFmacs
-     provides no way of retrieving this value, so I'll
-     leave this info with PID. */
-  /* Non-nil if this is really a child process */
-  Lisp_Object childp;
-#endif
-
-  /* Symbol indicating status of process.
-     This may be a symbol: run, stop, exit, signal */
-  Lisp_Object status_symbol;
-
-
-  /* Exit code if process has terminated,
-     signal which stopped/interrupted process
-     or 0 if process is running */
-  int exit_code;
-  /* Number of this process */
-  /* Non-false if process has exited and "dumped core" on its way down */
-  char core_dumped;
-  /* Descriptor by which we read from this process.  -1 for dead process */
-  int infd;
-  /* Descriptor by which we write to this process. -1 for dead process */
-  int outfd;
-  /* Descriptor for the tty which this process is using.
-     -1 if we didn't record it (on some systems, there's no need).  */
-  int subtty;
-  /* Name of subprocess terminal. */
-  Lisp_Object tty_name;
-  /* Non-false if communicating through a pty.  */
-  char pty_flag;
-  /* This next field is only actually used #ifdef ENERGIZE */
-  /* if this flag is not NIL, then filter will do the read on the
-     channel, rather than having a call to make_string.
-     This only works if the filter is a subr. */
-  char filter_does_read;
-  /* Non-nil means kill silently if Emacs is exited.  */
-  char kill_without_query;
-  char selected;
-  /* Event-count of last event in which this process changed status.  */
-  volatile int tick;
-  /* Event-count of last such event reported.  */
-  int update_tick;
-  /* streams used in input and output */
-  Lisp_Object instream;
-  Lisp_Object outstream;
-  /* The actual filedesc stream used for output; may be different
-     than OUTSTREAM under Mule */
-  Lisp_Object filedesc_stream;
-};
-
 static Lisp_Object mark_process (Lisp_Object, void (*) (Lisp_Object));
 static void print_process (Lisp_Object, Lisp_Object, int);
 static void finalize_process (void *, int);
@@ -211,6 +116,7 @@
 mark_process (Lisp_Object obj, void (*markobj) (Lisp_Object))
 {
   struct Lisp_Process *proc = XPROCESS (obj);
+  MAYBE_PROCMETH (mark_process_data, (proc, markobj));
   ((markobj) (proc->name));
   ((markobj) (proc->command));
   ((markobj) (proc->filter));
@@ -218,10 +124,12 @@
   ((markobj) (proc->buffer));
   ((markobj) (proc->mark));
   ((markobj) (proc->pid));
-  ((markobj) (proc->tty_name));
-  ((markobj) (proc->instream));
-  ((markobj) (proc->outstream));
-  ((markobj) (proc->filedesc_stream));
+  ((markobj) (proc->pipe_instream));
+  ((markobj) (proc->pipe_outstream));
+#ifdef FILE_CODING
+  ((markobj) (proc->coding_instream));
+  ((markobj) (proc->coding_outstream));
+#endif
   return proc->status_symbol;
 }
 
@@ -248,6 +156,7 @@
       print_internal (proc->pid, printcharfun, 1);
       write_c_string (" state:", printcharfun);
       print_internal (proc->status_symbol, printcharfun, 1);
+      MAYBE_PROCMETH (print_process_data, (proc, printcharfun));
       write_c_string (">", printcharfun);
     }
 }
@@ -259,15 +168,22 @@
 static void
 finalize_process (void *header, int for_disksave)
 {
-  if (for_disksave) return; /* hmm, what would this do anyway? */
   /* #### this probably needs to be tied into the tty event loop */
   /* #### when there is one */
+  struct Lisp_Process *p = (struct Lisp_Process *) header;
 #ifdef HAVE_WINDOW_SYSTEM
-  {
-    struct Lisp_Process *p = (struct Lisp_Process *) header;
-    debug_process_finalization (p);
-  }
+  if (!for_disksave)
+    {
+      debug_process_finalization (p);
+    }
 #endif /* HAVE_WINDOW_SYSTEM */
+
+  if (p->process_data)
+    {
+      MAYBE_PROCMETH (finalize_process_data, (p, for_disksave));
+      if (!for_disksave)
+	xfree (p->process_data);
+    }
 }
 
 
@@ -275,78 +191,35 @@
 /*                       basic process accessors                        */
 /************************************************************************/
 
-static SIGTYPE
-close_safely_handler (int signo)
-{
-  EMACS_REESTABLISH_SIGNAL (signo, close_safely_handler);
-  SIGRETURN;
-}
-
-static void
-close_safely (int fd)
-{
-  stop_interrupts ();
-  signal (SIGALRM, close_safely_handler);
-  alarm (1);
-  close (fd);
-  alarm (0);
-  start_interrupts ();
-}
-
-static void
-close_descriptor_pair (int in, int out)
+/* Under FILE_CODING, this function returns low-level streams, connected
+   directrly to the child process, rather than en/decoding FILE_CODING
+   streams */
+void
+get_process_streams (struct Lisp_Process *p,
+		     Lisp_Object *instr, Lisp_Object *outstr)
 {
-  if (in >= 0)
-    close (in);
-  if (out != in && out >= 0)
-    close (out);
-}
-
-/* Close all descriptors currently in use for communication
-   with subprocess.  This is used in a newly-forked subprocess
-   to get rid of irrelevant descriptors.  */
-
-void
-close_process_descs (void)
-{
-#ifndef WINDOWSNT
-  int i;
-  for (i = 0; i < MAXDESC; i++)
-    {
-      Lisp_Object process;
-      process = descriptor_to_process[i];
-      if (!NILP (process))
-	{
-	  close_descriptor_pair (XPROCESS (process)->infd,
-				 XPROCESS (process)->outfd);
-	}
-    }
-#endif
-}
-
-void
-get_process_file_descriptors (struct Lisp_Process *p, int *infd,
-			      int *outfd)
-{
-  if (! p) abort ();
-  /* the cast of MAXDESC is needed for some versions of Linux */
-  assert (p->infd  >= -1 && p->infd  < ((int) (MAXDESC)));
-  assert (p->outfd >= -1 && p->outfd < ((int) (MAXDESC)));
-  *infd = p->infd;
-  *outfd = p->outfd;
+  assert (p);
+  assert (NILP (p->pipe_instream) || LSTREAMP(p->pipe_instream));
+  assert (NILP (p->pipe_outstream) || LSTREAMP(p->pipe_outstream));
+  *instr = p->pipe_instream;
+  *outstr = p->pipe_outstream;
 }
 
 struct Lisp_Process *
-get_process_from_input_descriptor (int infd)
+get_process_from_usid (USID usid)
 {
-  Lisp_Object proc;
+  CONST void *vval;
+
+  assert (usid != USID_ERROR && usid != USID_DONTHASH);
 
-  if ((infd  < 0) || (infd  >= ((int) (MAXDESC)))) abort ();
-  proc = descriptor_to_process[infd];
-  if (NILP (proc))
+  if (gethash ((CONST void*)usid, usid_to_process, &vval))
+    {
+      Lisp_Object proc;
+      CVOID_TO_LISP (proc, vval);
+      return XPROCESS (proc);
+    }
+  else
     return 0;
-  else
-    return XPROCESS (proc);
 }
 
 int
@@ -361,6 +234,12 @@
   p->selected = !!selected_p;
 }
 
+int
+connected_via_filedesc_p (struct Lisp_Process *p)
+{
+  return MAYBE_INT_PROCMETH (tooltalk_connection_p, (p));
+}
+
 #ifdef HAVE_SOCKETS
 int
 network_connection_p (Lisp_Object process)
@@ -369,12 +248,6 @@
 }
 #endif
 
-int
-connected_via_filedesc_p (struct Lisp_Process *p)
-{
-  return p->connected_via_filedesc_p;
-}
-
 DEFUN ("processp", Fprocessp, 1, 1, 0, /*
 Return t if OBJECT is a process.
 */
@@ -483,7 +356,9 @@
     }
   else
     {
-      /* fsf:  CHECK_PROCESS (obj, 0); */
+      /* #### This was commented out. Although, simple
+	 (kill-process 7 "qqq") resulted in a falat error. - kkm */
+      CHECK_PROCESS (obj);
       proc = obj;
     }
   return proc;
@@ -535,7 +410,7 @@
 /*                          creating a process                          */
 /************************************************************************/
 
-static Lisp_Object
+Lisp_Object
 make_process_internal (Lisp_Object name)
 {
   Lisp_Object val, name1;
@@ -564,21 +439,22 @@
   p->mark = Fmake_marker ();
   p->pid = Qnil;
   p->status_symbol = Qrun;
-  p->connected_via_filedesc_p = 0;
   p->exit_code = 0;
   p->core_dumped = 0;
-  p->infd   = -1;
-  p->outfd  = -1;
-  p->subtty = -1;
-  p->tty_name = Qnil;
-  p->pty_flag = 0;
   p->filter_does_read = 0;
   p->kill_without_query = 0;
   p->selected = 0;
   p->tick = 0;
   p->update_tick = 0;
-  p->instream  = Qnil;
-  p->outstream = Qnil;
+  p->pipe_instream  = Qnil;
+  p->pipe_outstream = Qnil;
+#ifdef FILE_CODING
+  p->coding_instream  = Qnil;
+  p->coding_outstream = Qnil;
+#endif
+
+  p->process_data = 0;
+  MAYBE_PROCMETH (alloc_process_data, (p));
 
   XSETPROCESS (val, p);
 
@@ -586,506 +462,55 @@
   return val;
 }
 
-#ifdef HAVE_PTYS
-
-/* Open an available pty, returning a file descriptor.
-   Return -1 on failure.
-   The file name of the terminal corresponding to the pty
-   is left in the variable pty_name.  */
-
-static int
-allocate_pty (void)
+void
+init_process_io_handles (struct Lisp_Process *p, void* in, void* out, int flags)
 {
-  struct stat stb;
-  int c, i;
-  int fd;
-
-  /* Some systems name their pseudoterminals so that there are gaps in
-     the usual sequence - for example, on HP9000/S700 systems, there
-     are no pseudoterminals with names ending in 'f'.  So we wait for
-     three failures in a row before deciding that we've reached the
-     end of the ptys.  */
-  int failed_count = 0;
-
-#ifdef PTY_ITERATION
-  PTY_ITERATION
-#else
-  for (c = FIRST_PTY_LETTER; c <= 'z'; c++)
-    for (i = 0; i < 16; i++)
-#endif
-      {
-#ifdef PTY_NAME_SPRINTF
-	PTY_NAME_SPRINTF
-#else
-	sprintf (pty_name, "/dev/pty%c%x", c, i);
-#endif /* no PTY_NAME_SPRINTF */
-
-#ifdef PTY_OPEN
-	PTY_OPEN;
-#else /* no PTY_OPEN */
-#ifdef IRIS
-	/* Unusual IRIS code */
- 	*ptyv = open ("/dev/ptc", O_RDWR | O_NDELAY | OPEN_BINARY, 0);
- 	if (fd < 0)
- 	  return -1;
-	if (fstat (fd, &stb) < 0)
-	  return -1;
-#else /* not IRIS */
-	if (stat (pty_name, &stb) < 0)
-	  {
-	    failed_count++;
-	    if (failed_count >= 3)
-	      return -1;
-	  }
-	else
-	  failed_count = 0;
-#ifdef O_NONBLOCK
-	fd = open (pty_name, O_RDWR | O_NONBLOCK | OPEN_BINARY, 0);
-#else
-	fd = open (pty_name, O_RDWR | O_NDELAY | OPEN_BINARY, 0);
-#endif
-#endif /* not IRIS */
-#endif /* no PTY_OPEN */
-
-	if (fd >= 0)
-	  {
-	    /* check to make certain that both sides are available
-	       this avoids a nasty yet stupid bug in rlogins */
-#ifdef PTY_TTY_NAME_SPRINTF
-	    PTY_TTY_NAME_SPRINTF
-#else
-            sprintf (pty_name, "/dev/tty%c%x", c, i);
-#endif /* no PTY_TTY_NAME_SPRINTF */
-#ifndef UNIPLUS
-	    if (access (pty_name, 6) != 0)
-	      {
-		close (fd);
-#if !defined(IRIS) && !defined(__sgi)
-		continue;
-#else
-		return -1;
-#endif /* IRIS */
-	      }
-#endif /* not UNIPLUS */
-	    setup_pty (fd);
-	    return fd;
-	  }
-      }
-  return -1;
-}
-#endif /* HAVE_PTYS */
-
-static int
-create_bidirectional_pipe (int *inchannel, int *outchannel,
-			   volatile int *forkin, volatile int *forkout)
-{
-  int sv[2];
+  USID usid = event_stream_create_stream_pair (in, out,
+					       &p->pipe_instream, &p->pipe_outstream,
+					       flags);
 
-#ifdef SKTPAIR
-  if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
-    return -1;
-  *outchannel = *inchannel = sv[0];
-  *forkout = *forkin = sv[1];
-#else /* not SKTPAIR */
-  int temp;
-  temp = pipe (sv);
-  if (temp < 0) return -1;
-  *inchannel = sv[0];
-  *forkout = sv[1];
-  temp = pipe (sv);
-  if (temp < 0) return -1;
-  *outchannel = sv[1];
-  *forkin = sv[0];
-#endif /* not SKTPAIR */
-  return 0;
-}
-
-
-static Bufbyte
-get_eof_char (struct Lisp_Process *p)
-{
-  /* Figure out the eof character for the outfd of the given process.
-   * The following code is similar to that in process_send_signal, and
-   * should probably be merged with that code somehow. */
-
-  CONST Bufbyte ctrl_d = (Bufbyte) '\004';
-
-  if (!isatty (p->outfd))
-    return ctrl_d;
-#ifdef HAVE_TERMIOS
-  {
-    struct termios t;
-    tcgetattr (p->outfd, &t);
-#if 0
-    /* What is the following line designed to do??? -mrb */
-    if (strlen ((CONST char *) t.c_cc) < (unsigned int) (VEOF + 1))
-      return ctrl_d;
-    else
-      return (Bufbyte) t.c_cc[VEOF];
-#endif
-    return t.c_cc[VEOF] == CDISABLE ? ctrl_d : (Bufbyte) t.c_cc[VEOF];
-  }
-#else /* ! HAVE_TERMIOS */
-  /* On Berkeley descendants, the following IOCTL's retrieve the
-    current control characters.  */
-#if defined (TIOCGETC)
-  {
-    struct tchars c;
-    ioctl (p->outfd, TIOCGETC, &c);
-    return (Bufbyte) c.t_eofc;
-  }
-#else /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
-  /* On SYSV descendants, the TCGETA ioctl retrieves the current control
-     characters.  */
-#ifdef TCGETA
-  {
-    struct termio t;
-    ioctl (p->outfd, TCGETA, &t);
-    if (strlen ((CONST char *) t.c_cc) < (unsigned int) (VINTR + 1))
-      return ctrl_d;
-    else
-      return (Bufbyte) t.c_cc[VINTR];
-  }
-#else /* ! defined (TCGETA) */
-  /* Rather than complain, we'll just guess ^D, which is what
-   * earlier emacsen always used. */
-  return ctrl_d;
-#endif /* ! defined (TCGETA) */
-#endif /* ! defined (TIOCGETC) */
-#endif /* ! defined (HAVE_TERMIOS) */
-}
-
-static int
-get_pty_max_bytes (struct Lisp_Process *p)
-{
-  int pty_max_bytes;
-
-#if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON)
-  pty_max_bytes = fpathconf (p->outfd, _PC_MAX_CANON);
-  if (pty_max_bytes < 0)
-    pty_max_bytes = 250;
-#else
-  pty_max_bytes = 250;
-#endif
-  /* Deduct one, to leave space for the eof.  */
-  pty_max_bytes--;
-
-  return pty_max_bytes;
-}
-
-static void
-init_process_fds (struct Lisp_Process *p, int in, int out)
-{
-  p->infd = in;
-  p->outfd = out;
-  p->instream = make_filedesc_input_stream (in, 0, -1, 0);
-  p->outstream = make_filedesc_output_stream (out, 0, -1,
-					      LSTR_BLOCKED_OK
-					      | (p->pty_flag ?
-						 LSTR_PTY_FLUSHING : 0));
-  p->filedesc_stream = p->outstream;
-  if (p->pty_flag)
+  if (usid == USID_ERROR)
+    report_file_error ("Setting up communication with subprocess", Qnil);
+  
+  if (usid != USID_DONTHASH)
     {
-      Bufbyte eof_char = get_eof_char (p);
-      int pty_max_bytes = get_pty_max_bytes (p);
-      filedesc_stream_set_pty_flushing (XLSTREAM (p->outstream),
-					pty_max_bytes, eof_char);
+      Lisp_Object proc = Qnil;
+      XSETPROCESS (proc, p);
+      puthash ((CONST void*)usid, LISP_TO_VOID (proc), usid_to_process);
     }
 
-#ifdef FILE_CODING
+  MAYBE_PROCMETH (init_process_io_handles, (p, in, out, flags));
 
-  p->instream = make_decoding_input_stream
-    (XLSTREAM (p->instream),
+#ifdef FILE_CODING
+  p->coding_instream = make_decoding_input_stream
+    (XLSTREAM (p->pipe_instream),
      Fget_coding_system (Vcoding_system_for_read));
-  Lstream_set_character_mode (XLSTREAM (p->instream));
-  p->outstream = make_encoding_output_stream
-    (XLSTREAM (p->outstream),
+  Lstream_set_character_mode (XLSTREAM (p->coding_instream));
+  p->coding_outstream = make_encoding_output_stream
+    (XLSTREAM (p->pipe_outstream),
      Fget_coding_system (Vcoding_system_for_write));
   /* CODE_CNTL (&out_state[outchannel]) |= CC_END; !!####
      What's going on here? */
-#endif
+#endif /* FILE_CODING */
 }
 
 static void
 create_process (Lisp_Object process,
                 char **new_argv, CONST char *current_dir)
 {
-  /* This function rewritten by wing@666.com. */
-
-  int pid, inchannel, outchannel;
-  /* Use volatile to protect variables from being clobbered by longjmp.  */
-  volatile int forkin, forkout;
-  volatile int pty_flag = 0;
-  char **env;
   struct Lisp_Process *p = XPROCESS (process);
-
-  env = environ;
-
-  inchannel = outchannel = forkin = forkout = -1;
-
-#ifdef HAVE_PTYS
-  if (!NILP (Vprocess_connection_type))
-    {
-      /* find a new pty, open the master side, return the opened
-	 file handle, and store the name of the corresponding slave
-	 side in global variable pty_name. */
-      outchannel = inchannel = allocate_pty ();
-    }
+  int pid;
 
-  if (inchannel >= 0)
-    {
-      /* You're "supposed" to now open the slave in the child.
-	 On some systems, we can open it here; this allows for
-	 better error checking. */
-#if !defined(USG)
-      /* On USG systems it does not work to open the pty's tty here
-	       and then close and reopen it in the child.  */
-#ifdef O_NOCTTY
-      /* Don't let this terminal become our controlling terminal
-	 (in case we don't have one).  */
-      forkout = forkin = open (pty_name, O_RDWR | O_NOCTTY | OPEN_BINARY, 0);
-#else
-      forkout = forkin = open (pty_name, O_RDWR | OPEN_BINARY, 0);
-#endif
-      if (forkin < 0)
-	goto io_failure;
-#endif /* not USG */
-      p->pty_flag = pty_flag = 1;
-    }
-  else
-#endif /* HAVE_PTYS */
-    if (create_bidirectional_pipe (&inchannel, &outchannel,
-				   &forkin, &forkout) < 0)
-      goto io_failure;
-
-#if 0
-  /* Replaced by close_process_descs */
-  set_exclusive_use (inchannel);
-  set_exclusive_use (outchannel);
-#endif
-
-  set_descriptor_non_blocking (inchannel);
-
-  /* Record this as an active process, with its channels.
-     As a result, child_setup will close Emacs's side of the pipes.  */
-  descriptor_to_process[inchannel] = process;
-  init_process_fds (p, inchannel, outchannel);
-  /* Record the tty descriptor used in the subprocess.  */
-  p->subtty = forkin;
+  /* *_create_process may change status_symbol, if the process
+     is a kind of "fire-and-forget" (no I/O, unwaitable) */
   p->status_symbol = Qrun;
   p->exit_code = 0;
 
-  {
-#if !defined(__CYGWIN32__)
-    /* child_setup must clobber environ on systems with true vfork.
-       Protect it from permanent change.  */
-    char **save_environ = environ;
-#endif
-
-#ifdef EMACS_BTL
-    /* when performance monitoring is on, turn it off before the vfork(),
-       as the child has no handler for the signal -- when back in the
-       parent process, turn it back on if it was really on when you "turned
-       it off" */
-    int logging_on = cadillac_stop_logging ();	/* #### rename me */
-#endif
-
-#ifndef WINDOWSNT
-    pid = fork ();
-    if (pid == 0)
-#endif /* not WINDOWSNT */
-      {
-	/**** Now we're in the child process ****/
-	int xforkin = forkin;
-	int xforkout = forkout;
-
-	if (!pty_flag)
-	  EMACS_SEPARATE_PROCESS_GROUP ();
-#ifdef HAVE_PTYS
-	else
-	  {
-	    /* Disconnect the current controlling terminal, pursuant to
-	       making the pty be the controlling terminal of the process.
-	       Also put us in our own process group. */
-
-	    disconnect_controlling_terminal ();
-
-	    /* Open the pty connection and make the pty's terminal
-	       our controlling terminal.
-
-	       On systems with TIOCSCTTY, we just use it to set
-	       the controlling terminal.  On other systems, the
-	       first TTY we open becomes the controlling terminal.
-	       So, we end up with four possibilities:
-
-	       (1) on USG and TIOCSCTTY systems, we open the pty
-	           and use TIOCSCTTY.
-	       (2) on other USG systems, we just open the pty.
-	       (3) on non-USG systems with TIOCSCTTY, we
-	           just use TIOCSCTTY. (On non-USG systems, we
-		   already opened the pty in the parent process.)
-	       (4) on non-USG systems without TIOCSCTTY, we
-	           close the pty and reopen it.
-
-	       This would be cleaner if we didn't open the pty
-	       in the parent process, but doing it that way
-	       makes it possible to trap error conditions.
-	       It's harder to convey an error from the child
-	       process, and I don't feel like messing with
-	       this now. */
-
-	    /* There was some weirdo, probably wrong,
-	       conditionalization on RTU and UNIPLUS here.
-	       I deleted it.  So sue me. */
-
-	    /* SunOS has TIOCSCTTY but the close/open method
-	       also works. */
-
-#  if defined (USG) || !defined (TIOCSCTTY)
-	    /* Now close the pty (if we had it open) and reopen it.
-	       This makes the pty the controlling terminal of the
-	       subprocess.  */
-	    /* I wonder if close (open (pty_name, ...)) would work?  */
-	    if (xforkin >= 0)
-	      close (xforkin);
-	    xforkout = xforkin = open (pty_name, O_RDWR | OPEN_BINARY, 0);
-	    if (xforkin < 0)
-	      {
-		write (1, "Couldn't open the pty terminal ", 31);
-		write (1, pty_name, strlen (pty_name));
-		write (1, "\n", 1);
-		_exit (1);
-	      }
-#  endif /* USG or not TIOCSCTTY */
-
-	    /* Miscellaneous setup required for some systems.
-               Must be done before using tc* functions on xforkin.
-               This guarantees that isatty(xforkin) is true. */
-
-# ifdef SETUP_SLAVE_PTY
-	    SETUP_SLAVE_PTY;
-# endif /* SETUP_SLAVE_PTY */
-
-#  ifdef TIOCSCTTY
-	    /* We ignore the return value
-	       because faith@cs.unc.edu says that is necessary on Linux.  */
-            assert (isatty (xforkin));
-	    ioctl (xforkin, TIOCSCTTY, 0);
-#  endif /* TIOCSCTTY */
-
-	    /* Change the line discipline. */
-
-# if defined (HAVE_TERMIOS) && defined (LDISC1)
-	    {
-	      struct termios t;
-              assert (isatty (xforkin));
-	      tcgetattr (xforkin, &t);
-	      t.c_lflag = LDISC1;
-	      if (tcsetattr (xforkin, TCSANOW, &t) < 0)
-		perror ("create_process/tcsetattr LDISC1 failed\n");
-	    }
-# elif defined (NTTYDISC) && defined (TIOCSETD)
-	    {
-	      /* Use new line discipline.  TIOCSETD is accepted and
-                 ignored on Sys5.4 systems with ttcompat. */
-	      int ldisc = NTTYDISC;
-              assert (isatty (xforkin));
-	      ioctl (xforkin, TIOCSETD, &ldisc);
-	    }
-# endif /* TIOCSETD & NTTYDISC */
-
-	    /* Make our process group be the foreground group
-	       of our new controlling terminal. */
-
-	    {
-	      int piddly = EMACS_GET_PROCESS_GROUP ();
-	      EMACS_SET_TTY_PROCESS_GROUP (xforkin, &piddly);
-	    }
-
-# ifdef AIX
-	    /* On AIX, we've disabled SIGHUP above once we start a
-	       child on a pty.  Now reenable it in the child, so it
-	       will die when we want it to.  */
-	    signal (SIGHUP, SIG_DFL);
-# endif /* AIX */
-	  }
-#endif /* HAVE_PTYS */
-
-	signal (SIGINT, SIG_DFL);
-	signal (SIGQUIT, SIG_DFL);
-
-#if !defined(MSDOS) && !defined(WINDOWSNT)
-	if (pty_flag)
-	  {
-	    /* Set up the terminal characteristics of the pty. */
-	    child_setup_tty (xforkout);
-	  }
-
-#ifdef WINDOWSNT
-	pid = child_setup (xforkin, xforkout, xforkout,
-			   new_argv, current_dir);
-#else  /* not WINDOWSNT */
-	child_setup (xforkin, xforkout, xforkout, new_argv, current_dir);
-#endif /* not WINDOWSNT */
-#endif /* not MSDOS */
-      }
-#ifdef EMACS_BTL
-    else if (logging_on)
-      cadillac_start_logging ();	/* #### rename me */
-#endif
-
-#if !defined(__CYGWIN32__)
-    environ = save_environ;
-#endif
-  }
-
-  if (pid < 0)
-    {
-      close_descriptor_pair (forkin, forkout);
-      report_file_error ("Doing fork", Qnil);
-    }
+  pid = PROCMETH (create_process, (p, new_argv, current_dir));
 
   p->pid = make_int (pid);
-  /* #### dmoore - why is this commented out, otherwise we leave
-     subtty = forkin, but then we close forkin just below. */
-  /* p->subtty = -1; */
-
-#ifdef WINDOWSNT
-  register_child (pid, inchannel);
-#endif /* WINDOWSNT */
-
-  /* If the subfork execv fails, and it exits,
-     this close hangs.  I don't know why.
-     So have an interrupt jar it loose.  */
-  if (forkin >= 0)
-    close_safely (forkin);
-  if (forkin != forkout && forkout >= 0)
-    close (forkout);
-
-#ifdef HAVE_PTYS
-  if (pty_flag)
-    XPROCESS (process)->tty_name = build_string (pty_name);
-  else
-#endif
-    XPROCESS (process)->tty_name = Qnil;
-
-  /* Notice that SIGCHLD was not blocked. (This is not possible on
-     some systems.) No biggie if SIGCHLD occurs right around the
-     time that this call happens, because SIGCHLD() does not actually
-     deselect the process (that doesn't occur until the next time
-     we're waiting for an event, when status_notify() is called). */
-  event_stream_select_process (XPROCESS (process));
-
-  return;
-
-io_failure:
-  {
-    int temp = errno;
-    close_descriptor_pair (forkin, forkout);
-    close_descriptor_pair (inchannel, outchannel);
-    errno = temp;
-    report_file_error ("Opening pty or pipe", Qnil);
-  }
+  if (!NILP(p->pipe_instream))
+    event_stream_select_process (p);
 }
 
 /* This function is the unwind_protect form for Fstart_process_internal.  If
@@ -1217,117 +642,27 @@
 }
 
 
-/* connect to an existing file descriptor.  This is very similar to
-   open-network-stream except that it assumes that the connection has
-   already been initialized.  It is currently used for ToolTalk
-   communication. */
-
-/* This function used to be visible on the Lisp level, but there is no
-   real point in doing that.  Here is the doc string:
-
-  "Connect to an existing file descriptor.\n\
-Returns a subprocess-object to represent the connection.\n\
-Input and output work as for subprocesses; `delete-process' closes it.\n\
-Args are NAME BUFFER INFD OUTFD.\n\
-NAME is name for process.  It is modified if necessary to make it unique.\n\
-BUFFER is the buffer (or buffer-name) to associate with the process.\n\
- Process output goes at end of that buffer, unless you specify\n\
- an output stream or filter function to handle the output.\n\
- BUFFER may be also nil, meaning that this process is not associated\n\
- with any buffer\n\
-INFD and OUTFD specify the file descriptors to use for input and\n\
- output, respectively."
-*/
-
-Lisp_Object
-connect_to_file_descriptor (Lisp_Object name, Lisp_Object buffer,
-			    Lisp_Object infd, Lisp_Object outfd)
-{
-  /* This function can GC */
-  Lisp_Object proc;
-  int inch;
-
-  CHECK_STRING (name);
-  CHECK_INT (infd);
-  CHECK_INT (outfd);
-
-  inch = XINT (infd);
-  if (!NILP (descriptor_to_process[inch]))
-    error ("There is already a process connected to fd %d", inch);
-  if (!NILP (buffer))
-    buffer = Fget_buffer_create (buffer);
-  proc = make_process_internal (name);
-
-  descriptor_to_process[inch] = proc;
-
-  XPROCESS (proc)->pid = Fcons (infd, name);
-  XPROCESS (proc)->buffer = buffer;
-  init_process_fds (XPROCESS (proc), inch, XINT (outfd));
-  XPROCESS (proc)->connected_via_filedesc_p = 1;
-
-  event_stream_select_process (XPROCESS (proc));
-
-  return proc;
-}
-
-
 #ifdef HAVE_SOCKETS
 
-static int
-get_internet_address (Lisp_Object host, struct sockaddr_in *address,
-		      Error_behavior errb)
-{
-  struct hostent *host_info_ptr = NULL;
-#ifdef TRY_AGAIN
-  int count = 0;
-#endif
 
-  memset (address, 0, sizeof (*address));
+/* #### The network support is fairly synthetical. What we actually
+   need is a single function, which supports all datagram, stream and
+   packet stream connections, arbitrary protocol families should they
+   be supported by the target system, multicast groups, in both data
+   and control rooted/nonrooted flavors, service quality etc whatever
+   is supported by the underlying network.
 
-  while (1)
-    {
-#ifdef TRY_AGAIN
-      if (count++ > 10) break;
-#ifndef BROKEN_CYGWIN
-      h_errno = 0; 
-#endif
-#endif
-      /* Some systems can't handle SIGIO/SIGALARM in gethostbyname. */
-      slow_down_interrupts ();
-      host_info_ptr = gethostbyname ((char *) XSTRING_DATA (host));
-      speed_up_interrupts ();
-#ifdef TRY_AGAIN
-      if (! (host_info_ptr == 0 && h_errno == TRY_AGAIN))
-#endif
-	break;
-      Fsleep_for (make_int (1));
-    }
-  if (host_info_ptr)
-    {
-      address->sin_family = host_info_ptr->h_addrtype;
-      memcpy (&address->sin_addr, host_info_ptr->h_addr, host_info_ptr->h_length);
-    }
-  else
-    {
-      IN_ADDR numeric_addr;
-      /* Attempt to interpret host as numeric inet address */
-      numeric_addr = inet_addr ((char *) XSTRING_DATA (host));
-      if (NUMERIC_ADDR_ERROR)
-	{
-	  maybe_error (Qprocess, errb,
-		       "Unknown host \"%s\"", XSTRING_DATA (host));
-	  return 0;
-	}
+   It must accept a property list describing the connection. The current
+   functions must then go to lisp and provide a suitable list for the
+   generalized connection function.
 
-      /* There was some broken code here that called strlen() here
-	 on (char *) &numeric_addr and even sometimes accessed
-	 uninitialized data. */
-      address->sin_family = AF_INET;
-      * (IN_ADDR *) &address->sin_addr = numeric_addr;
-    }
+   Both UNIX ans Win32 support BSD sockets, and there are many extensions
+   availalble (Sockets 2 spec). 
 
-  return 1;
-}
+   A todo is define a consistent set of properties abstracting a
+   network connection.   -kkm
+*/
+
 
 /* open a TCP network connection to a given HOST/SERVICE.  Treated
    exactly like a normal process when reading and writing.  Only
@@ -1335,7 +670,7 @@
    connection has no PID; you cannot signal it.  All you can do is
    deactivate and close it via delete-process */
 
-DEFUN ("open-network-stream-internal", Fopen_network_stream_internal, 4, 4, 0, /*
+DEFUN ("open-network-stream-internal", Fopen_network_stream_internal, 4, 5, 0, /*
 Open a TCP connection for a service to a host.
 Returns a subprocess-object to represent the connection.
 Input and output work as for subprocesses; `delete-process' closes it.
@@ -1349,186 +684,48 @@
 Third arg is name of the host to connect to, or its IP address.
 Fourth arg SERVICE is name of the service desired, or an integer
  specifying a port number to connect to.
+Fifth argument FAMILY is a protocol family. When omitted, 'tcp/ip
+(Internet protocol family TCP/IP) is assumed.
 */
-       (name, buffer, host, service))
+       (name, buffer, host, service, family))
 {
   /* !!#### This function has not been Mule-ized */
   /* This function can GC */
-  Lisp_Object proc;
-  struct sockaddr_in address;
-  int s, outch, inch;
-  volatile int port;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-  volatile int retry = 0;
-  int retval;
+  Lisp_Object proc = Qnil;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, ngcpro1;
+  void *inch, *outch;
 
-  GCPRO4 (name, buffer, host, service);
+  GCPRO5 (name, buffer, host, service, family);
   CHECK_STRING (name);
-  CHECK_STRING (host);
-  if (INTP (service))
-    port = htons ((unsigned short) XINT (service));
-  else
-    {
-      struct servent *svc_info;
-      CHECK_STRING (service);
-      svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp");
-      if (svc_info == 0)
-#ifdef WIN32
-	error ("Unknown service \"%s\" (%d)",
-	       XSTRING_DATA (service), WSAGetLastError ());
-#else
-	error ("Unknown service \"%s\"", XSTRING_DATA (service));
-#endif
-      port = svc_info->s_port;
-    }
-
-  get_internet_address (host, &address, ERROR_ME);
-  address.sin_port = port;
-
-  s = socket (address.sin_family, SOCK_STREAM, 0);
-  if (s < 0)
-    report_file_error ("error creating socket", list1 (name));
-
-  /* Turn off interrupts here -- see comments below.  There used to
-     be code which called bind_polling_period() to slow the polling
-     period down rather than turn it off, but that seems rather
-     bogus to me.  Best thing here is to use a non-blocking connect
-     or something, to check for QUIT. */
-
-  /* Comments that are not quite valid: */
-
-  /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
-     when connect is interrupted.  So let's not let it get interrupted.
-     Note we do not turn off polling, because polling is only used
-     when not interrupt_input, and thus not normally used on the systems
-     which have this bug.  On systems which use polling, there's no way
-     to quit if polling is turned off.  */
-
-  /* Slow down polling.  Some kernels have a bug which causes retrying
-     connect to fail after a connect.  */
-
-  slow_down_interrupts ();
 
- loop:
-
-  /* A system call interrupted with a SIGALRM or SIGIO comes back
-     here, with can_break_system_calls reset to 0. */
-  SETJMP (break_system_call_jump);
-  if (QUITP)
-    {
-      speed_up_interrupts ();
-      REALLY_QUIT;
-      /* In case something really weird happens ... */
-      slow_down_interrupts ();
-    }
+  if (NILP(family))
+    family = Qtcpip;
+  else
+    CHECK_SYMBOL (family);
 
-  /* Break out of connect with a signal (it isn't otherwise possible).
-     Thus you don't get screwed with a hung network. */
-  can_break_system_calls = 1;
-  retval = connect (s, (struct sockaddr *) &address, sizeof (address));
-  can_break_system_calls = 0;
-  if (retval == -1 && errno != EISCONN)
-    {
-      int xerrno = errno;
-      if (errno == EINTR)
-	goto loop;
-      if (errno == EADDRINUSE && retry < 20)
-	{
-	  /* A delay here is needed on some FreeBSD systems,
-	     and it is harmless, since this retrying takes time anyway
-	     and should be infrequent.
-             `sleep-for' allowed for quitting this loop with interrupts
-             slowed down so it can't be used here.  Async timers should
-             already be disabled at this point so we can use `sleep'. */
-          sleep (1);
-	  retry++;
-	  goto loop;
-	}
-
-      close (s);
-
-      speed_up_interrupts ();
-
-      errno = xerrno;
-      report_file_error ("connection failed", list2 (host, name));
-    }
-
-  speed_up_interrupts ();
-
-  inch = s;
-  outch = dup (s);
-  if (outch < 0)
-    {
-      close (s); /* this used to be leaked; from Kyle Jones */
-      report_file_error ("error duplicating socket", list1 (name));
-    }
-
+  /* Since this code is inside HAVE_SOCKETS, existence of
+     open_network_stream is mandatory */
+  PROCMETH (open_network_stream, (name, host, service, family,
+				  &inch, &outch));
+  
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer);
   proc = make_process_internal (name);
-
-  descriptor_to_process[inch] = proc;
-
-#ifdef PROCESS_IO_BLOCKING
-  {
-    Lisp_Object tail;
-
-    for (tail = network_stream_blocking_port_list; CONSP (tail); tail = XCDR (tail))
-      {
-	Lisp_Object tail_port = XCAR (tail);
-
-	if (STRINGP (tail_port))
-	  {
-	    struct servent *svc_info;
-	    CHECK_STRING (tail_port);
-	    svc_info = getservbyname ((char *) XSTRING_DATA (tail_port), "tcp");
-	    if ((svc_info != 0) && (svc_info->s_port == port))
-		break;
-	    else
-	      continue;
-	  }
-	else if ((INTP (tail_port)) && (htons ((unsigned short) XINT (tail_port)) == port))
-	  break;
-      }
-
-    if (!CONSP (tail))
-      {
-#endif	/* PROCESS_IO_BLOCKING */
-  set_descriptor_non_blocking (inch);
-#ifdef PROCESS_IO_BLOCKING
-      }
-    }
-#endif	/* PROCESS_IO_BLOCKING */
+  NGCPRO1 (proc);
 
   XPROCESS (proc)->pid = Fcons (service, host);
   XPROCESS (proc)->buffer = buffer;
-  init_process_fds (XPROCESS (proc), inch, outch);
-  XPROCESS (proc)->connected_via_filedesc_p = 0;
+  init_process_io_handles (XPROCESS (proc), (void*)inch, (void*)outch, 0);
 
   event_stream_select_process (XPROCESS (proc));
 
   UNGCPRO;
+  NUNGCPRO;
   return proc;
 }
 
 #ifdef HAVE_MULTICAST
-/* Didier Verna <verna@inf.enst.fr> Nov. 28 1997.
 
-   This function is similar to open-network-stream-internal, but provides a
-   mean to open an UDP multicast connection instead of a TCP one. Like in the
-   TCP case, the multicast connection will be seen as a sub-process,
-
-   Some notes:
-   - Normaly, we should use sendto and recvfrom with non connected
-   sockets. The current code doesn't allow us to do this. In the future, it
-   would be a good idea to extend the process data structure in order to deal
-   properly with the different types network connections.
-   - For the same reason, when leaving a multicast group, it is better to make
-   a setsockopt - IP_DROP_MEMBERSHIP before closing the descriptors.
-   Unfortunately, this can't be done here because delete_process doesn't know
-   about the kind of connection we have. However, this is not such an
-   important issue.
-*/
 DEFUN ("open-multicast-group-internal", Fopen_multicast_group_internal, 5, 5, 0, /*
 Open a multicast connection on the specified dest/port/ttl.
 Returns a subprocess-object to represent the connection.
@@ -1549,138 +746,16 @@
 {
   /* !!#### This function has not been Mule-ized */
   /* This function can GC */
-  Lisp_Object proc;
-  struct ip_mreq imr;
-  struct sockaddr_in sa;
-  struct protoent *udp;
-  int ws, rs;
-  int theport;
-  unsigned char thettl;
-  int one = 1; /* For REUSEADDR */
-  int ret;
-  volatile int retry = 0;
+  Lisp_Object proc = Qnil;
   struct gcpro gcpro1;
-  
-  CHECK_STRING (name);
-  CHECK_STRING (dest);
-  
-  CHECK_NATNUM (port);
-  theport = htons ((unsigned short) XINT (port));
-  
-  CHECK_NATNUM (ttl);
-  thettl = (unsigned char) XINT (ttl);
-  
-  if ((udp = getprotobyname ("udp")) == NULL)
-    error ("No info available for UDP protocol");
-  
-  /* Init the sockets. Yes, I need 2 sockets. I couldn't duplicate one. */
-  if ((rs = socket (PF_INET, SOCK_DGRAM, udp->p_proto)) < 0)
-    report_file_error ("error creating socket", list1(name));
-  if ((ws = socket (PF_INET, SOCK_DGRAM, udp->p_proto)) < 0)
-    {
-      close (rs);
-      report_file_error ("error creating socket", list1(name));
-    }
-  
-  /* This will be used for both sockets */
-  bzero(&sa, sizeof(sa));
-  sa.sin_family = AF_INET; 
-  sa.sin_port = theport;
-  sa.sin_addr.s_addr = htonl (inet_addr ((char *) XSTRING_DATA (dest)));
+  void *inch, *outch;
 
-  /* Socket configuration for reading ------------------------ */
-  
-  /* Multiple connections from the same machine. This must be done before
-     bind. If it fails, it shouldn't be fatal. The only consequence is that
-     people won't be able to connect twice from the same machine. */
-  if (setsockopt (rs, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one))
-      < 0)
-    warn_when_safe (Qmulticast, Qwarning, "Cannot reuse socket address");
-  
-  /* bind socket name */
-  if (bind (rs, (struct sockaddr *)&sa, sizeof(sa)))
-    {
-      close (rs);
-      close (ws);
-      report_file_error ("error binding socket", list2(name, port));
-    }
-  
-  /* join multicast group */
-  imr.imr_multiaddr.s_addr = htonl (inet_addr ((char *) XSTRING_DATA (dest)));
-  imr.imr_interface.s_addr = htonl (INADDR_ANY);
-  if (setsockopt (rs, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-		 (char *) &imr, sizeof (struct ip_mreq)) < 0)
-    {
-      close (ws);
-      close (rs);
-      report_file_error ("error adding membership", list2(name, dest));
-    }
-  
-  /* Socket configuration for writing ----------------------- */
-  
-  /* Normaly, there's no 'connect' in multicast, since we use preferentialy
-     'sendto' and 'recvfrom'. However, in order to handle this connection in
-     the process-like way it is done for TCP, we must be able to use 'write'
-     instead of 'sendto'. Consequently, we 'connect' this socket. */
-  
-  /* See open-network-stream-internal for comments on this part of the code */
-  slow_down_interrupts ();
-  
- loop:
-  
-  /* A system call interrupted with a SIGALRM or SIGIO comes back
-     here, with can_break_system_calls reset to 0. */
-  SETJMP (break_system_call_jump);
-  if (QUITP)
-    {
-      speed_up_interrupts ();
-      REALLY_QUIT;
-      /* In case something really weird happens ... */
-      slow_down_interrupts ();
-    }
-  
-  /* Break out of connect with a signal (it isn't otherwise possible).
-     Thus you don't get screwed with a hung network. */
-  can_break_system_calls = 1;
-  ret = connect (ws, (struct sockaddr *) &sa, sizeof (sa));
-  can_break_system_calls = 0;
-  if (ret == -1 && errno != EISCONN)
-    {
-      int xerrno = errno;
-      
-      if (errno == EINTR)
-	goto loop;
-      if (errno == EADDRINUSE && retry < 20)
-	{ 
-	  /* A delay here is needed on some FreeBSD systems,
-	     and it is harmless, since this retrying takes time anyway
-	     and should be infrequent.
-	     `sleep-for' allowed for quitting this loop with interrupts
-	     slowed down so it can't be used here.  Async timers should
-	     already be disabled at this point so we can use `sleep'. */
-	  sleep (1);
-	  retry++;
-	  goto loop;
-	}
-    
-      close (rs);
-      close (ws);
-      speed_up_interrupts ();
-      
-      errno = xerrno;
-      report_file_error ("error connecting socket", list2(name, port));
-    }
-  
-  speed_up_interrupts ();
-  
-  /* scope */
-  if (setsockopt (ws, IPPROTO_IP, IP_MULTICAST_TTL, 
-		  (char *) &thettl, sizeof (thettl)) < 0)
-    {
-      close (rs);
-      close (ws);
-      report_file_error ("error setting ttl", list2(name, ttl));
-    }
+  CHECK_STRING (name);
+
+  /* Since this code is inside HAVE_MULTICAST, existence of
+     open_network_stream is mandatory */
+  PROCMETH (open_multicast_group, (name, dest, port, ttl,
+				   &inch, &outch));
   
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer);
@@ -1688,46 +763,9 @@
   proc = make_process_internal (name);
   GCPRO1 (proc);
 
-  descriptor_to_process[rs] = proc;
-  
-#ifdef PROCESS_IO_BLOCKING
-  {
-    Lisp_Object tail;
-    
-    for (tail = network_stream_blocking_port_list; 
-	 CONSP (tail); tail = XCDR (tail))
-      {
-	Lisp_Object tail_port = XCAR (tail);
-	
-	if (STRINGP (tail_port))
-	  {
-	    struct servent *svc_info;
-	    
-	    svc_info = 
-	      getservbyname ((char *) XSTRING_DATA (tail_port), "udp");
-	    if ((svc_info != 0) && (svc_info->s_port == theport))
-	      break;
-	    else
-	      continue;
-	  }
-	else if ((INTP (tail_port)) && 
-		 (htons ((unsigned short) XINT (tail_port)) == theport))
-	  break;
-      }
-    
-    if (!CONSP (tail))
-      {
-#endif	/* PROCESS_IO_BLOCKING */
-	set_descriptor_non_blocking (rs);
-#ifdef PROCESS_IO_BLOCKING
-      }
-  }
-#endif	/* PROCESS_IO_BLOCKING */
-  
   XPROCESS (proc)->pid = Fcons (port, dest);
   XPROCESS (proc)->buffer = buffer;
-  init_process_fds (XPROCESS (proc), rs, ws);
-  XPROCESS (proc)->connected_via_filedesc_p = 0;
+  init_process_io_handles (XPROCESS (proc), (void*)inch, (void*)outch, 0);
   
   event_stream_select_process (XPROCESS (proc));
   
@@ -1741,21 +779,7 @@
 Lisp_Object
 canonicalize_host_name (Lisp_Object host)
 {
-#ifdef HAVE_SOCKETS
-  /* #### for HAVE_TERM, you probably have to do something else. */
-  struct sockaddr_in address;
-
-  if (!get_internet_address (host, &address, ERROR_ME_NOT))
-    return host;
-
-  if (address.sin_family == AF_INET)
-    return build_string (inet_ntoa (address.sin_addr));
-  else
-    /* #### any clue what to do here? */
-    return host;
-#else
-  return host;
-#endif
+  return PROCMETH_OR_GIVEN (canonicalize_host_name, (host), host);
 }
 
 
@@ -1767,11 +791,9 @@
   CHECK_PROCESS (proc);
   CHECK_NATNUM (height);
   CHECK_NATNUM (width);
-  if (set_window_size (XPROCESS (proc)->infd, XINT (height), XINT (width))
-      <= 0)
-    return Qnil;
-  else
-    return Qt;
+  return
+    MAYBE_INT_PROCMETH (set_window_size, (XPROCESS (proc), XINT (height), XINT (width))) <= 0
+    ? Qnil : Qt;
 }
 
 
@@ -1779,11 +801,6 @@
 /*                              Process I/O                             */
 /************************************************************************/
 
-/*  (Faccept_process_output is now in event-stream.c) */
-
-/* Some FSFmacs error handlers here.  We handle this
-   in call2_trapping_errors(). */
-
 /* Read pending output from the process channel,
    starting with our buffered-ahead character if we have one.
    Yield number of characters read.
@@ -1809,7 +826,7 @@
      Really, the loop in execute_internal_event() should check itself
      for a process-filter change, like in status_notify(); but the
      struct Lisp_Process is not exported outside of this file. */
-  if (p->infd < 0)
+  if (NILP(p->pipe_instream))
     return -1; /* already closed */
 
   if (!NILP (p->filter) && (p->filter_does_read))
@@ -1827,32 +844,7 @@
       return XINT (filter_result);
     }
 
-#if 0 /* FSFmacs */
-  /* #### equivalent code from FSFmacs.  Would need some porting
-     for Windows NT. */
-  if (proc_buffered_char[channel] < 0)
-#ifdef WINDOWSNT
-    nchars = read_child_output (channel, chars, sizeof (chars));
-#else
-    nchars = read (channel, chars, sizeof chars);
-#endif
-  else
-    {
-      chars[0] = proc_buffered_char[channel];
-      proc_buffered_char[channel] = -1;
-#ifdef WINDOWSNT
-      nchars = read_child_output (channel, chars + 1, sizeof (chars) - 1);
-#else
-      nchars = read (channel, chars + 1, sizeof chars - 1);
-#endif
-      if (nchars < 0)
-	nchars = 1;
-      else
-	nchars = nchars + 1;
-    }
-#endif /* FSFmacs */
-
-  nbytes = Lstream_read (XLSTREAM (p->instream), chars, sizeof (chars));
+  nbytes = Lstream_read (XLSTREAM (DATA_INSTREAM(p)), chars, sizeof (chars));
   if (nbytes <= 0) return nbytes;
 
   nchars = bytecount_to_charcount (chars, nbytes);
@@ -1956,19 +948,9 @@
     }
   return nchars;
 }
-
+
 /* Sending data to subprocess */
 
-static JMP_BUF send_process_frame;
-
-static SIGTYPE
-send_process_trap (int signum)
-{
-  EMACS_REESTABLISH_SIGNAL (signum, send_process_trap);
-  EMACS_UNBLOCK_SIGNAL (signum);
-  LONGJMP (send_process_frame, 1);
-}
-
 /* send some data to process PROC.  If NONRELOCATABLE is non-NULL, it
    specifies the address of the data.  Otherwise, the data comes from the
    object RELOCATABLE (either a string or a buffer).  START and LEN
@@ -1977,27 +959,18 @@
    Note that START and LEN are in Bufpos's if RELOCATABLE is a buffer,
    and in Bytecounts otherwise. */
 
-static void
-send_process (volatile Lisp_Object proc,
+void
+send_process (Lisp_Object proc,
               Lisp_Object relocatable, CONST Bufbyte *nonrelocatable,
               int start, int len)
 {
   /* This function can GC */
-  /* Use volatile to protect variables from being clobbered by longjmp.  */
   struct gcpro gcpro1, gcpro2;
-  SIGTYPE (*volatile old_sigpipe) (int) = 0;
   Lisp_Object lstream = Qnil;
-  volatile struct Lisp_Process *p = XPROCESS (proc);
-#if defined (NO_UNION_TYPE) /* || !defined (__GNUC__) GCC bug only??? */
-  /* #### ugh! There must be a better solution. */
-  Lisp_Object defeat_volatile_kludge = (Lisp_Object) proc;
-#else
-  Lisp_Object defeat_volatile_kludge = proc;
-#endif
 
-  GCPRO2 (defeat_volatile_kludge, lstream);
+  GCPRO2 (proc, lstream);
 
-  if (p->outfd < 0)
+  if (NILP (DATA_OUTSTREAM (XPROCESS (proc))))
     signal_simple_error ("Process not open for writing", proc);
 
   if (nonrelocatable)
@@ -2009,63 +982,8 @@
   else
     lstream = make_lisp_string_input_stream (relocatable, start, len);
 
-  if (!SETJMP (send_process_frame))
-    {
-      /* use a reasonable-sized buffer (somewhere around the size of the
-	 stream buffer) so as to avoid inundating the stream with blocked
-	 data. */
-      Bufbyte chunkbuf[512];
-      Bytecount chunklen;
-
-      while (1)
-	{
-	  int writeret;
+  PROCMETH (send_process, (proc, XLSTREAM (lstream)));
 
-	  chunklen = Lstream_read (XLSTREAM (lstream), chunkbuf, 512);
-	  if (chunklen <= 0)
-	    break; /* perhaps should abort() if < 0?
-		      This should never happen. */
-	  old_sigpipe =
-	    (SIGTYPE (*) (int)) signal (SIGPIPE, send_process_trap);
-	  /* Lstream_write() will never successfully write less than
-	     the amount sent in.  In the worst case, it just buffers
-	     the unwritten data. */
-	  writeret = Lstream_write (XLSTREAM (p->outstream), chunkbuf,
-				    chunklen);
-	  signal (SIGPIPE, old_sigpipe);
-	  if (writeret < 0)
-	    /* This is a real error.  Blocking errors are handled
-	       specially inside of the filedesc stream. */
-	    report_file_error ("writing to process",
-			       list1 (proc));
-	  while (filedesc_stream_was_blocked (XLSTREAM (p->filedesc_stream)))
-	    {
-	      /* Buffer is full.  Wait, accepting input;
-		 that may allow the program
-		 to finish doing output and read more.  */
-	      Faccept_process_output (Qnil, make_int (1), Qnil);
-	      old_sigpipe =
-		(SIGTYPE (*) (int)) signal (SIGPIPE, send_process_trap);
-	      Lstream_flush (XLSTREAM (p->filedesc_stream));
-	      signal (SIGPIPE, old_sigpipe);
-	    }
-	}
-    }
-  else
-    { /* We got here from a longjmp() from the SIGPIPE handler */
-      signal (SIGPIPE, old_sigpipe);
-      p->status_symbol = Qexit;
-      p->exit_code = 256; /* #### SIGPIPE ??? */
-      p->core_dumped = 0;
-      p->tick++;
-      process_tick++;
-      deactivate_process (proc);
-      error ("SIGPIPE raised on process %s; closed it",
-	     XSTRING_DATA (p->name));
-    }
-  old_sigpipe = (SIGTYPE (*) (int)) signal (SIGPIPE, send_process_trap);
-  Lstream_flush (XLSTREAM (p->outstream));
-  signal (SIGPIPE, old_sigpipe);
   UNGCPRO;
   Lstream_delete (XLSTREAM (lstream));
 }
@@ -2078,7 +996,7 @@
        (proc))
 {
   CHECK_PROCESS (proc);
-  return XPROCESS (proc)->tty_name;
+  return MAYBE_LISP_PROCMETH (get_tty_name, (XPROCESS (proc)));
 }
 
 DEFUN ("set-process-buffer", Fset_process_buffer, 2, 2, 0, /*
@@ -2206,7 +1124,7 @@
        (process))
 {
   process = get_process (process);
-  return decoding_stream_coding_system (XLSTREAM ( XPROCESS (process)->instream) );
+  return decoding_stream_coding_system (XLSTREAM (XPROCESS (process)->coding_instream) );
 }
 
 DEFUN ("process-output-coding-system", Fprocess_output_coding_system, 1, 1, 0, /*
@@ -2215,7 +1133,7 @@
        (process))
 {
   process = get_process (process);
-  return encoding_stream_coding_system (XLSTREAM (XPROCESS (process)->outstream));
+  return encoding_stream_coding_system (XLSTREAM (XPROCESS (process)->coding_outstream));
 }
 
 DEFUN ("process-coding-system", Fprocess_coding_system, 1, 1, 0, /*
@@ -2225,9 +1143,9 @@
 {
   process = get_process (process);
   return Fcons (decoding_stream_coding_system
-		(XLSTREAM (XPROCESS (process)->instream)),
+		(XLSTREAM (XPROCESS (process)->coding_instream)),
 		encoding_stream_coding_system
-		(XLSTREAM (XPROCESS (process)->outstream)));
+		(XLSTREAM (XPROCESS (process)->coding_outstream)));
 }
 
 DEFUN ("set-process-input-coding-system",
@@ -2238,7 +1156,7 @@
 {
   codesys = Fget_coding_system (codesys);
   process = get_process (process);
-  set_decoding_stream_coding_system ( XLSTREAM ( XPROCESS (process)->instream ), codesys);
+  set_decoding_stream_coding_system ( XLSTREAM ( XPROCESS (process)->coding_instream ), codesys);
   return Qnil;
 }
 
@@ -2251,7 +1169,7 @@
   codesys = Fget_coding_system (codesys);
   process = get_process (process);
   set_encoding_stream_coding_system
-    ( XLSTREAM ( XPROCESS (process)->outstream), codesys);
+    ( XLSTREAM ( XPROCESS (process)->coding_outstream), codesys);
   return Qnil;
 }
 
@@ -2270,16 +1188,12 @@
   return Qnil;
 }
 
-#endif
-
+#endif /* FILE_CODING */
 
 /************************************************************************/
 /*                             process status                           */
 /************************************************************************/
 
-/* Some FSFmacs error handlers here.  We handle this
-   in call2_trapping_errors(). */
-
 static Lisp_Object
 exec_sentinel_unwind (Lisp_Object datum)
 {
@@ -2348,40 +1262,6 @@
   return (CONST char *) GETTEXT ("unknown signal");
 }
 
-/* Compute the Lisp form of the process status from
-   the numeric status that was returned by `wait'.  */
-
-static void
-update_status_from_wait_code (struct Lisp_Process *p, int *w_fmh)
-{
-  /* C compiler lossage when attempting to pass w directly */
-  int w = *w_fmh;
-
-  if (WIFSTOPPED (w))
-    {
-      p->status_symbol = Qstop;
-      p->exit_code = WSTOPSIG (w);
-      p->core_dumped = 0;
-    }
-  else if (WIFEXITED (w))
-    {
-      p->status_symbol = Qexit;
-      p->exit_code = WEXITSTATUS (w);
-      p->core_dumped = 0;
-    }
-  else if (WIFSIGNALED (w))
-    {
-      p->status_symbol = Qsignal;
-      p->exit_code = WTERMSIG (w);
-      p->core_dumped = WCOREDUMP (w);
-    }
-  else
-    {
-      p->status_symbol = Qrun;
-      p->exit_code = 0;
-    }
-}
-
 void
 update_process_status (Lisp_Object p,
 		       Lisp_Object status_symbol,
@@ -2395,212 +1275,6 @@
   XPROCESS (p)->core_dumped = core_dumped;
 }
 
-#ifdef SIGCHLD
-
-#define MAX_EXITED_PROCESSES 1000
-static volatile pid_t exited_processes[MAX_EXITED_PROCESSES];
-static volatile int exited_processes_status[MAX_EXITED_PROCESSES];
-static volatile int exited_processes_index;
-
-static volatile int sigchld_happened;
-
-/* For any processes that have changed status and are recorded
-   and such, update the corresponding struct Lisp_Process.
-   We separate this from record_exited_processes() so that
-   we never have to call this function from within a signal
-   handler.  We block SIGCHLD in case record_exited_processes()
-   is called from a signal handler. */
-
-static void
-reap_exited_processes (void)
-{
-  int i;
-  struct Lisp_Process *p;
-
-  if (exited_processes_index <= 0)
-    {
-      return;
-    }
-
-#ifdef  EMACS_BLOCK_SIGNAL
-  EMACS_BLOCK_SIGNAL (SIGCHLD);
-#endif
-  for (i = 0; i < exited_processes_index; i++)
-    {
-      int pid = exited_processes[i];
-      int w = exited_processes_status[i];
-
-      /* Find the process that signaled us, and record its status.  */
-
-      p = 0;
-      {
-        Lisp_Object tail;
-	LIST_LOOP (tail, Vprocess_list)
-	  {
-	    Lisp_Object proc = XCAR (tail);
-	    p = XPROCESS (proc);
-	    if (INTP (p->pid) && XINT (p->pid) == pid)
-	      break;
-	    p = 0;
-	  }
-      }
-
-      if (p)
-	{
-	  /* Change the status of the process that was found.  */
-	  p->tick++;
-	  process_tick++;
-	  update_status_from_wait_code (p, &w);
-
-          /* If process has terminated, stop waiting for its output.  */
-	  if (WIFSIGNALED (w) || WIFEXITED (w))
-	    {
-	      if (p->infd >= 0)
-		{
-		  /* We can't just call event_stream->unselect_process_cb (p)
-		     here, because that calls XtRemoveInput, which is not
-		     necessarily reentrant, so we can't call this at interrupt
-		     level.
-		   */
-		}
-	    }
-	}
-      else
-	{
-          /* There was no asynchronous process found for that id.  Check
-	     if we have a synchronous process. Only set sync process status
-	     if there is one, so we work OK with the waitpid() call in
-	     wait_for_termination(). */
-	  if (synch_process_alive != 0)
-	    { /* Set the global sync process status variables. */
-	      synch_process_alive = 0;
-
-	      /* Report the status of the synchronous process.  */
-	      if (WIFEXITED (w))
-		synch_process_retcode = WEXITSTATUS (w);
-	      else if (WIFSIGNALED (w))
-		synch_process_death = signal_name (WTERMSIG (w));
-	    }
-        }
-    }
-
-  exited_processes_index = 0;
-
-  EMACS_UNBLOCK_SIGNAL (SIGCHLD);
-}
-
-/* On receipt of a signal that a child status has changed,
- loop asking about children with changed statuses until
- the system says there are no more.  All we do is record
- the processes and wait status.
-
- This function could be called from within the SIGCHLD
- handler, so it must be completely reentrant.  When
- not called from a SIGCHLD handler, BLOCK_SIGCHLD should
- be non-zero so that SIGCHLD is blocked while this
- function is running. (This is necessary so avoid
- race conditions with the SIGCHLD_HAPPENED flag). */
-
-static void
-record_exited_processes (int block_sigchld)
-{
-  if (!sigchld_happened)
-    {
-      return;
-    }
-
-#ifdef EMACS_BLOCK_SIGNAL
-  if (block_sigchld)
-    EMACS_BLOCK_SIGNAL (SIGCHLD);
-#endif
-
-  while (sigchld_happened)
-    {
-      int pid;
-      int w;
-
-      /* Keep trying to get a status until we get a definitive result.  */
-      do
-	{
-	  errno = 0;
-#ifdef WNOHANG
-#  ifndef WUNTRACED
-#    define WUNTRACED 0
-#  endif /* not WUNTRACED */
-#  ifdef HAVE_WAITPID
-	  pid = waitpid ((pid_t) -1, &w, WNOHANG | WUNTRACED);
-#  else
-	  pid = wait3 (&w, WNOHANG | WUNTRACED, 0);
-#  endif
-#else /* not WNOHANG */
-	  pid = wait (&w);
-#endif /* not WNOHANG */
-	}
-      while (pid <= 0 && errno == EINTR);
-
-      if (pid <= 0)
-	break;
-
-      if (exited_processes_index < MAX_EXITED_PROCESSES)
-	{
-	  exited_processes[exited_processes_index] = pid;
-	  exited_processes_status[exited_processes_index] = w;
-	  exited_processes_index++;
-	}
-
-      /* On systems with WNOHANG, we just ignore the number
-	 of times that SIGCHLD was signalled, and keep looping
-	 until there are no more processes to wait on.  If we
-	 don't have WNOHANG, we have to rely on the count in
-	 SIGCHLD_HAPPENED. */
-#ifndef WNOHANG
-      sigchld_happened--;
-#endif /* not WNOHANG */
-    }
-
-  sigchld_happened = 0;
-
-  if (block_sigchld)
-    EMACS_UNBLOCK_SIGNAL (SIGCHLD);
-}
-
-/** USG WARNING:  Although it is not obvious from the documentation
- in signal(2), on a USG system the SIGCLD handler MUST NOT call
- signal() before executing at least one wait(), otherwise the handler
- will be called again, resulting in an infinite loop.  The relevant
- portion of the documentation reads "SIGCLD signals will be queued
- and the signal-catching function will be continually reentered until
- the queue is empty".  Invoking signal() causes the kernel to reexamine
- the SIGCLD queue.   Fred Fish, UniSoft Systems Inc.
-
- (Note that now this only applies in SYS V Release 2 and before.
- On SYS V Release 3, we use sigset() to set the signal handler for
- the first time, and so we don't have to reestablish the signal handler
- in the handler below.  On SYS V Release 4, we don't get this weirdo
- behavior when we use sigaction(), which we do use.) */
-
-static SIGTYPE
-sigchld_handler (int signo)
-{
-#ifdef OBNOXIOUS_SYSV_SIGCLD_BEHAVIOR
-  int old_errno = errno;
-
-  sigchld_happened++;
-  record_exited_processes (0);
-  errno = old_errno;
-#else
-  sigchld_happened++;
-#endif
-#ifdef HAVE_UNIXOID_EVENT_LOOP
-  signal_fake_event ();
-#endif
-  /* WARNING - must come after wait3() for USG systems */
-  EMACS_REESTABLISH_SIGNAL (signo, sigchld_handler);
-  SIGRETURN;
-}
-
-#endif /* SIGCHLD */
-
 /* Return a string describing a process status list.  */
 
 static Lisp_Object
@@ -2649,6 +1323,7 @@
   process_tick++;
 }
 
+
 /* Report all recent events of a change in process status
    (either run the sentinel or output a message).
    This is done while Emacs is waiting for keyboard input.  */
@@ -2671,12 +1346,7 @@
      stuff in -- it can't hurt.) */
   int temp_process_tick;
 
-#ifdef SIGCHLD
-#ifndef OBNOXIOUS_SYSV_SIGCLD_BEHAVIOR
-  record_exited_processes (1);
-#endif
-  reap_exited_processes ();
-#endif
+  MAYBE_PROCMETH (reap_exited_processes, ());
 
   temp_process_tick = process_tick;
 
@@ -2696,26 +1366,12 @@
       /* p->tick is also volatile.  Same thing as above applies. */
       int this_process_tick;
 
-#ifdef HAVE_WAITPID
       /* #### extra check for terminated processes, in case a SIGCHLD
 	 got missed (this seems to happen sometimes, I'm not sure why).
        */
-      {
-	int w;
-#ifdef SIGCHLD
-	EMACS_BLOCK_SIGNAL (SIGCHLD);
-#endif
-	if (INTP (p->pid) &&
-	    waitpid (XINT (p->pid), &w, WNOHANG) == XINT (p->pid))
-	  {
-	    p->tick++;
-	    update_status_from_wait_code (p, &w);
-	  }
-#ifdef SIGCHLD
-	EMACS_UNBLOCK_SIGNAL (SIGCHLD);
-#endif
-      }
-#endif
+      if (INTP (p->pid))
+	MAYBE_PROCMETH (update_status_if_terminated, (p));
+
       this_process_tick = p->tick;
       if (this_process_tick != p->update_tick)
 	{
@@ -2851,83 +1507,7 @@
 }
 
 
-#ifdef SIGNALS_VIA_CHARACTERS
-/* Get signal character to send to process if SIGNALS_VIA_CHARACTERS */
 
-static int
-process_signal_char (int tty_fd, int signo)
-{
-  /* If it's not a tty, pray that these default values work */
-  if (!isatty(tty_fd)) {
-#define CNTL(ch) (037 & (ch))
-    switch (signo)
-      {
-      case SIGINT:  return CNTL('C');
-      case SIGQUIT: return CNTL('\\');
-#ifdef SIGTSTP
-      case SIGTSTP: return CNTL('Z');
-#endif
-      }
-  }
-
-#ifdef HAVE_TERMIOS
-  /* TERMIOS is the latest and bestest, and seems most likely to work.
-     If the system has it, use it. */
-  {
-    struct termios t;
-    tcgetattr (tty_fd, &t);
-    switch (signo)
-      {
-      case SIGINT:  return t.c_cc[VINTR];
-      case SIGQUIT: return t.c_cc[VQUIT];
-#  if defined (VSWTCH) && !defined (PREFER_VSUSP)
-      case SIGTSTP: return t.c_cc[VSWTCH];
-#  else
-      case SIGTSTP: return t.c_cc[VSUSP];
-#  endif
-      }
-  }
-
-# elif defined (TIOCGLTC) && defined (TIOCGETC) /* not HAVE_TERMIOS */
-  {
-    /* On Berkeley descendants, the following IOCTL's retrieve the
-       current control characters.  */
-    struct tchars c;
-    struct ltchars lc;
-    switch (signo)
-      {
-      case SIGINT:  ioctl (tty_fd, TIOCGETC, &c);  return c.t_intrc;
-      case SIGQUIT: ioctl (tty_fd, TIOCGETC, &c);  return c.t_quitc;
-#  ifdef SIGTSTP
-      case SIGTSTP: ioctl (tty_fd, TIOCGLTC, &lc); return lc.t_suspc;
-#  endif /* SIGTSTP */
-      }
-  }
-
-# elif defined (TCGETA) /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
-  {
-    /* On SYSV descendants, the TCGETA ioctl retrieves the current
-       control characters.  */
-    struct termio t;
-    ioctl (tty_fd, TCGETA, &t);
-    switch (signo) {
-    case SIGINT:  return t.c_cc[VINTR];
-    case SIGQUIT: return t.c_cc[VQUIT];
-#  ifdef SIGTSTP
-    case SIGTSTP: return t.c_cc[VSWTCH];
-#  endif /* SIGTSTP */
-    }
-  }
-# else /* ! defined (TCGETA) */
-#error ERROR! Using SIGNALS_VIA_CHARACTERS, but not HAVE_TERMIOS || (TIOCGLTC && TIOCGETC) || TCGETA
-  /* If your system configuration files define SIGNALS_VIA_CHARACTERS,
-     you'd better be using one of the alternatives above!  */
-# endif /* ! defined (TCGETA) */
-  return '\0';
-}
-#endif /* SIGNALS_VIA_CHARACTERS */
-
-
 /* send a signal number SIGNO to PROCESS.
    CURRENT_GROUP means send to the process group that currently owns
    the terminal being used to communicate with PROCESS.
@@ -2940,111 +1520,20 @@
    their uid, for which killpg would return an EPERM error.  */
 
 static void
-process_send_signal (Lisp_Object process0, int signo,
+process_send_signal (Lisp_Object process, int signo,
                      int current_group, int nomsg)
 {
   /* This function can GC */
-  Lisp_Object proc = get_process (process0);
-  struct Lisp_Process *p = XPROCESS (proc);
-  int gid;
-  int no_pgrp = 0;
+  Lisp_Object proc = get_process (process);
 
   if (network_connection_p (proc))
     error ("Network connection %s is not a subprocess",
-	   XSTRING_DATA (p->name));
-  if (p->infd < 0)
+	   XSTRING_DATA (XPROCESS(proc)->name));
+  if (!PROCESS_LIVE_P (proc))
     error ("Process %s is not active",
-	   XSTRING_DATA (p->name));
-
-  if (!p->pty_flag)
-    current_group = 0;
-
-  /* If we are using pgrps, get a pgrp number and make it negative.  */
-  if (current_group)
-    {
-#ifdef SIGNALS_VIA_CHARACTERS
-      /* If possible, send signals to the entire pgrp
-	 by sending an input character to it.  */
-      {
-        char sigchar = process_signal_char(p->subtty, signo);
-        if (sigchar) {
-          send_process (proc, Qnil, (Bufbyte *) &sigchar, 0, 1);
-          return;
-        }
-      }
-#endif /* ! defined (SIGNALS_VIA_CHARACTERS) */
-
-#ifdef TIOCGPGRP
-      /* Get the pgrp using the tty itself, if we have that.
-	 Otherwise, use the pty to get the pgrp.
-	 On pfa systems, saka@pfu.fujitsu.co.JP writes:
-	 "TIOCGPGRP symbol defined in sys/ioctl.h at E50.
-	 But, TIOCGPGRP does not work on E50 ;-P works fine on E60"
-	 His patch indicates that if TIOCGPGRP returns an error, then
-	 we should just assume that p->pid is also the process group id.  */
-      {
-	int err;
-
-        err = ioctl ( (p->subtty != -1 ? p->subtty : p->infd), TIOCGPGRP, &gid);
+	   XSTRING_DATA (XPROCESS(proc)->name));
 
-#ifdef pfa
-	if (err == -1)
-	  gid = - XINT (p->pid);
-#endif /* ! defined (pfa) */
-      }
-      if (gid == -1)
-	no_pgrp = 1;
-      else
-	gid = - gid;
-#else /* ! defined (TIOCGPGRP ) */
-      /* Can't select pgrps on this system, so we know that
-	 the child itself heads the pgrp.  */
-      gid = - XINT (p->pid);
-#endif /* ! defined (TIOCGPGRP ) */
-    }
-  else
-    gid = - XINT (p->pid);
-
-  switch (signo)
-    {
-#ifdef SIGCONT
-    case SIGCONT:
-      p->status_symbol = Qrun;
-      p->exit_code = 0;
-      p->tick++;
-      process_tick++;
-      if (!nomsg)
-	status_notify ();
-      break;
-#endif /* ! defined (SIGCONT) */
-    case SIGINT:
-    case SIGQUIT:
-    case SIGKILL:
-      flush_pending_output (p->infd);
-      break;
-    }
-
-  /* If we don't have process groups, send the signal to the immediate
-     subprocess.  That isn't really right, but it's better than any
-     obvious alternative.  */
-  if (no_pgrp)
-    {
-      kill (XINT (p->pid), signo);
-      return;
-    }
-
-  /* gid may be a pid, or minus a pgrp's number */
-#ifdef TIOCSIGSEND
-  if (current_group)
-    ioctl (p->infd, TIOCSIGSEND, signo);
-  else
-    {
-      gid = - XINT (p->pid);
-      kill (gid, signo);
-    }
-#else /* ! defined (TIOCSIGSEND) */
-  EMACS_KILLPG (-gid, signo);
-#endif /* ! defined (TIOCSIGSEND) */
+  MAYBE_PROCMETH (kill_child_process, (proc, signo, current_group, nomsg));
 }
 
 DEFUN ("interrupt-process", Finterrupt_process, 0, 2, 0, /*
@@ -3070,8 +1559,7 @@
        (process, current_group))
 {
   /* This function can GC */
-  process_send_signal (process, SIGKILL, !NILP (current_group),
-		       0);
+  process_send_signal (process, SIGKILL, !NILP (current_group), 0);
   return process;
 }
 
@@ -3082,8 +1570,7 @@
        (process, current_group))
 {
   /* This function can GC */
-  process_send_signal (process, SIGQUIT, !NILP (current_group),
-		       0);
+  process_send_signal (process, SIGQUIT, !NILP (current_group), 0);
   return process;
 }
 
@@ -3094,11 +1581,10 @@
        (process, current_group))
 {
   /* This function can GC */
-#ifndef SIGTSTP
-  error ("no SIGTSTP support");
+#ifdef SIGTSTP
+  process_send_signal (process, SIGTSTP, !NILP (current_group), 0);
 #else
-  process_send_signal (process, SIGTSTP, !NILP (current_group),
-		       0);
+  error ("stop-process: Not supported on this system");
 #endif
   return process;
 }
@@ -3111,10 +1597,9 @@
 {
   /* This function can GC */
 #ifdef SIGCONT
-    process_send_signal (process, SIGCONT, !NILP (current_group),
-			 0);
+  process_send_signal (process, SIGCONT, !NILP (current_group), 0);
 #else
-    error ("no SIGCONT support");
+  error ("continue-process: Not supported on this system");
 #endif
   return process;
 }
@@ -3240,7 +1725,8 @@
 
 #undef handle_signal
 
-  return make_int (kill (XINT (pid), XINT (sigcode)));
+  return make_int (PROCMETH_OR_GIVEN (kill_process_by_pid,
+				      (XINT (pid), XINT (sigcode)), -1));
 }
 
 DEFUN ("process-send-eof", Fprocess_send_eof, 0, 1, 0, /*
@@ -3262,24 +1748,14 @@
   if (! EQ (XPROCESS (proc)->status_symbol, Qrun))
     error ("Process %s not running", XSTRING_DATA (XPROCESS (proc)->name));
 
-  if (XPROCESS (proc)->pty_flag)
+  if (!MAYBE_INT_PROCMETH (process_send_eof, (proc)))
     {
-      /* #### get_eof_char simply doesn't return the correct character
-         here.  Maybe it is needed to determine the right eof
-         character in init_process_fds but here it simply screws
-         things up. */
-#if 0
-      Bufbyte eof_char = get_eof_char (XPROCESS (proc));
-      send_process (proc, Qnil, &eof_char, 0, 1);
-#else
-      send_process (proc, Qnil, (CONST Bufbyte *) "\004", 0, 1);
+      event_stream_delete_stream_pair (Qnil, XPROCESS (proc)->pipe_outstream);
+      XPROCESS (proc)->pipe_outstream = Qnil;
+#ifdef FILE_CODING
+      XPROCESS (proc)->coding_outstream = Qnil;
 #endif
     }
-  else
-    {
-      close (XPROCESS (proc)->outfd);
-      XPROCESS (proc)->outfd = open (NULL_DEVICE, O_WRONLY | OPEN_BINARY, 0);
-    }
 
   return process;
 }
@@ -3292,42 +1768,36 @@
 void
 deactivate_process (Lisp_Object proc)
 {
-  int inchannel, outchannel;
   struct Lisp_Process *p = XPROCESS (proc);
-  SIGTYPE (*old_sigpipe) (int) = 0;
-
-  inchannel = p->infd;
-  outchannel = p->outfd;
+  USID usid;
 
-  /* closing the outstream could result in SIGPIPE, so ignore it. */
-  old_sigpipe =
-    (SIGTYPE (*) (int)) signal (SIGPIPE, SIG_IGN);
-  if (!NILP (p->instream))
-    Lstream_close (XLSTREAM (p->instream));
-  if (!NILP (p->outstream))
-    Lstream_close (XLSTREAM (p->outstream));
-  signal (SIGPIPE, old_sigpipe);
+  /* It's possible that we got as far in the process-creation
+     process as creating the descriptors but didn't get so
+     far as selecting the process for input.  In this
+     case, p->pid is nil: p->pid is set at the same time that
+     the process is selected for input. */
+  /* #### The comment does not look correct. event_stream_unselect_process
+     is guarded by process->selected, so this is not a problem. - kkm*/
+  /* Must call this before setting the streams to nil */
+  event_stream_unselect_process (p);
 
-  if (inchannel >= 0)
-    {
-      /* Beware SIGCHLD hereabouts. */
-      flush_pending_output (inchannel);
-      close_descriptor_pair (inchannel, outchannel);
-      if (!NILP (p->pid))
-	{
-	  /* It's possible that we got as far in the process-creation
-	     process as creating the descriptors but didn't get so
-	     far as selecting the process for input.  In this
-	     case, p->pid is nil: p->pid is set at the same time that
-	     the process is selected for input. */
-	  /* Must call this before setting the file descriptors to 0 */
-	  event_stream_unselect_process (p);
-	}
+  /* Provide minimal implementation for deactivate_process
+     if there's no process-specific one */
+  if (HAS_PROCMETH_P (deactivate_process))
+    usid = PROCMETH (deactivate_process, (p));
+  else
+    usid = event_stream_delete_stream_pair (p->pipe_instream,
+					    p->pipe_outstream);
 
-      p->infd  = -1;
-      p->outfd = -1;
-      descriptor_to_process[inchannel] = Qnil;
-    }
+  if (usid != USID_DONTHASH)
+    remhash ((CONST void*)usid, usid_to_process);
+
+  p->pipe_instream = Qnil;
+  p->pipe_outstream = Qnil;
+#ifdef FILE_CODING
+  p->coding_instream = Qnil;
+  p->coding_outstream = Qnil;
+#endif
 }
 
 static void
@@ -3357,7 +1827,7 @@
       p->tick++;
       process_tick++;
     }
-  else if (p->infd >= 0)
+  else if (!NILP(p->pipe_instream))
     {
       Fkill_process (proc, Qnil);
       /* Do this now, since remove_process will make sigchld_handler do nothing.  */
@@ -3389,30 +1859,12 @@
 	{
 	  if (network_connection_p (proc))
 	    Fdelete_process (proc);
-	  else if (XPROCESS (proc)->infd >= 0)
+	  else if (!NILP (XPROCESS (proc)->pipe_instream))
 	    process_send_signal (proc, SIGHUP, 0, 1);
 	}
     }
 }
 
-#if 0 /* Unused */
-int
-count_active_processes (void)
-{
-  Lisp_Object tail;
-  int count = 0;
-
-  for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail))
-    {
-      Lisp_Object status = XPROCESS (XCAR (tail))->status_symbol;
-      if ((EQ (status, Qrun) || EQ (status, Qstop)))
-	count++;
-    }
-
-  return count;
-}
-#endif /* Unused */
-
 DEFUN ("process-kill-without-query", Fprocess_kill_without_query, 1, 2, 0, /*
 Say no query needed if PROCESS is running when Emacs is exited.
 Optional second argument if non-nil says to require a query.
@@ -3443,23 +1895,10 @@
 void
 init_xemacs_process (void)
 {
-  int i;
-
-#ifdef SIGCHLD
-# ifndef CANNOT_DUMP
-  if (! noninteractive || initialized)
-# endif
-    signal (SIGCHLD, sigchld_handler);
-#endif /* SIGCHLD */
+  MAYBE_PROCMETH (init_process, ());
 
   Vprocess_list = Qnil;
-  for (i = 0; i < MAXDESC; i++)
-    {
-      descriptor_to_process[i] = Qnil;
-#if 0 /* FSFmacs */
-      proc_buffered_char[i] = -1;
-#endif
-    }
+  usid_to_process = make_hashtable (32);
 }
 
 #if 0
@@ -3488,6 +1927,8 @@
   defsymbol (&Qopen, "open");
   defsymbol (&Qclosed, "closed");
 
+  defsymbol (&Qtcpip, "tcp/ip");
+
 #ifdef HAVE_MULTICAST
   defsymbol(&Qmulticast, "multicast"); /* Used for occasional warnings */
 #endif
@@ -3537,7 +1978,7 @@
   DEFSUBR (Fset_process_output_coding_system);
   DEFSUBR (Fprocess_coding_system);
   DEFSUBR (Fset_process_coding_system);
-#endif
+#endif /* FILE_CODING */
 }
 
 void