X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/68e7476278a3dc4bd13dab63cc23bc0e671e5525..fedc6ab5551a4f4a80c8c1add8095d0415e034e9:/src/process.c diff --git a/src/process.c b/src/process.c index c7ca36a847..5084bc8d15 100644 --- a/src/process.c +++ b/src/process.c @@ -5,10 +5,10 @@ This file is part of GNU Emacs. -GNU Emacs is free software; you can redistribute it and/or modify +GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,9 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +along with GNU Emacs. If not, see . */ #include @@ -35,6 +33,8 @@ Boston, MA 02110-1301, USA. */ #ifdef subprocesses #include +#include +#include #include #include #include /* some typedefs are used in sys/file.h */ @@ -43,26 +43,25 @@ Boston, MA 02110-1301, USA. */ #ifdef HAVE_INTTYPES_H #include #endif + +#ifdef HAVE_PWD_H +#include +#include +#endif + #ifdef HAVE_UNISTD_H #include #endif - -#if defined(WINDOWSNT) || defined(UNIX98_PTYS) -#include #include -#endif /* not WINDOWSNT */ #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */ #include #include #include #include -#ifdef NEED_NET_ERRNO_H -#include -#endif /* NEED_NET_ERRNO_H */ /* Are local (unix) sockets supported? */ -#if defined (HAVE_SYS_UN_H) && !defined (NO_SOCKETS_IN_FILE_SYSTEM) +#if defined (HAVE_SYS_UN_H) #if !defined (AF_LOCAL) && defined (AF_UNIX) #define AF_LOCAL AF_UNIX #endif @@ -73,20 +72,6 @@ Boston, MA 02110-1301, USA. */ #endif #endif /* HAVE_SOCKETS */ -/* TERM is a poor-man's SLIP, used on GNU/Linux. */ -#ifdef TERM -#include -#endif - -/* On some systems, inet_addr returns a 'struct in_addr'. */ -#ifdef HAVE_BROKEN_INET_ADDR -#define IN_ADDR struct in_addr -#define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1) -#else -#define IN_ADDR unsigned long -#define NUMERIC_ADDR_ERROR (numeric_addr == -1) -#endif - #if defined(BSD_SYSTEM) #include #if !defined (O_NDELAY) && defined (HAVE_PTYS) && !defined(USG5) @@ -94,10 +79,6 @@ Boston, MA 02110-1301, USA. */ #endif /* HAVE_PTYS and no O_NDELAY */ #endif /* BSD_SYSTEM */ -#ifdef BROKEN_O_NONBLOCK -#undef O_NONBLOCK -#endif /* BROKEN_O_NONBLOCK */ - #ifdef NEED_BSDTTY #include #endif @@ -113,10 +94,6 @@ Boston, MA 02110-1301, USA. */ #endif #endif -#ifdef IRIS -#include /* for "minor" */ -#endif /* not IRIS */ - #ifdef HAVE_SYS_WAIT #include #endif @@ -133,7 +110,7 @@ Boston, MA 02110-1301, USA. */ #include "window.h" #include "buffer.h" -#include "charset.h" +#include "character.h" #include "coding.h" #include "process.h" #include "frame.h" @@ -150,14 +127,17 @@ Lisp_Object Qprocessp; Lisp_Object Qrun, Qstop, Qsignal; Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten; Lisp_Object Qlocal, Qipv4, Qdatagram; +Lisp_Object Qreal, Qnetwork, Qserial; #ifdef AF_INET6 Lisp_Object Qipv6; #endif +Lisp_Object QCport, QCspeed, QCprocess; +Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven; +Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary; Lisp_Object QCname, QCbuffer, QChost, QCservice, QCtype; Lisp_Object QClocal, QCremote, QCcoding; Lisp_Object QCserver, QCnowait, QCnoquery, QCstop; Lisp_Object QCsentinel, QClog, QCoptions, QCplist; -Lisp_Object QCfilter_multibyte; Lisp_Object Qlast_nonmenu_event; /* QCfamily is declared and initialized in xfaces.c, QCfilter in keyboard.c. */ @@ -170,23 +150,25 @@ extern Lisp_Object QCfamily; /* QCfilter is defined in keyboard.c. */ extern Lisp_Object QCfilter; -/* a process object is a network connection when its childp field is neither - Qt nor Qnil but is instead a property list (KEY VAL ...). */ +Lisp_Object Qeuid, Qegid, Qcomm, Qstate, Qppid, Qpgrp, Qsess, Qttname, Qtpgid; +Lisp_Object Qminflt, Qmajflt, Qcminflt, Qcmajflt, Qutime, Qstime, Qcstime; +Lisp_Object Qcutime, Qpri, Qnice, Qthcount, Qstart, Qvsize, Qrss, Qargs; +Lisp_Object Quser, Qgroup, Qetime, Qpcpu, Qpmem; #ifdef HAVE_SOCKETS -#define NETCONN_P(p) (GC_CONSP (XPROCESS (p)->childp)) -#define NETCONN1_P(p) (GC_CONSP ((p)->childp)) +#define NETCONN_P(p) (EQ (XPROCESS (p)->type, Qnetwork)) +#define NETCONN1_P(p) (EQ ((p)->type, Qnetwork)) +#define SERIALCONN_P(p) (EQ (XPROCESS (p)->type, Qserial)) +#define SERIALCONN1_P(p) (EQ ((p)->type, Qserial)) #else #define NETCONN_P(p) 0 #define NETCONN1_P(p) 0 +#define SERIALCONN_P(p) 0 +#define SERIALCONN1_P(p) 0 #endif /* HAVE_SOCKETS */ /* Define first descriptor number available for subprocesses. */ -#ifdef VMS -#define FIRST_PROC_DESC 1 -#else /* Not VMS */ #define FIRST_PROC_DESC 3 -#endif /* Define SIGCHLD as an alias for SIGCLD. There are many conditionals testing SIGCHLD. */ @@ -201,12 +183,20 @@ extern Lisp_Object QCfilter; extern char *get_operating_system_release (); +/* Serial processes require termios or Windows. */ +#if defined (HAVE_TERMIOS) || defined (WINDOWSNT) +#define HAVE_SERIAL +#endif + +#ifdef HAVE_SERIAL +/* From sysdep.c or w32.c */ +extern int serial_open (char *port); +extern void serial_configure (struct Lisp_Process *p, Lisp_Object contact); +#endif + #ifndef USE_CRT_DLL extern int errno; #endif -#ifdef VMS -extern char *sys_errlist[]; -#endif #ifndef HAVE_H_ERRNO extern int h_errno; @@ -216,12 +206,6 @@ extern int h_errno; maybe other values to come. */ static Lisp_Object Vprocess_connection_type; -#ifdef SKTPAIR -#ifndef HAVE_SOCKETS -#include -#endif -#endif /* SKTPAIR */ - /* 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. */ @@ -268,11 +252,6 @@ int update_tick; #endif /* DATAGRAM_SOCKETS */ #endif /* BROKEN_DATAGRAM_SOCKETS */ -#ifdef TERM -#undef NON_BLOCKING_CONNECT -#undef DATAGRAM_SOCKETS -#endif - #if !defined (ADAPTIVE_READ_BUFFERING) && !defined (NO_ADAPTIVE_READ_BUFFERING) #ifdef EMACS_HAS_USECS #define ADAPTIVE_READ_BUFFERING @@ -416,16 +395,14 @@ static char pty_name[24]; /* Compute the Lisp form of the process status, p->status, from the numeric status that was returned by `wait'. */ -static Lisp_Object status_convert (); +static Lisp_Object status_convert (int); static void update_status (p) struct Lisp_Process *p; { - union { int i; WAITTYPE wt; } u; eassert (p->raw_status_new); - u.i = p->raw_status; - p->status = status_convert (u.wt); + p->status = status_convert (p->raw_status); p->raw_status_new = 0; } @@ -433,8 +410,7 @@ update_status (p) the list that we use internally. */ static Lisp_Object -status_convert (w) - WAITTYPE w; +status_convert (int w) { if (WIFSTOPPED (w)) return Fcons (Qstop, Fcons (make_number (WSTOPSIG (w)), Qnil)); @@ -554,14 +530,6 @@ allocate_pty () PTY_OPEN; #else /* no PTY_OPEN */ { -# ifdef IRIS - /* Unusual IRIS code */ - *ptyv = emacs_open ("/dev/ptc", O_RDWR | O_NDELAY, 0); - if (fd < 0) - return -1; - if (fstat (fd, &stb) < 0) - return -1; -# else /* not IRIS */ { /* 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 @@ -583,7 +551,6 @@ allocate_pty () # else fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0); # endif -# endif /* not IRIS */ } #endif /* no PTY_OPEN */ @@ -599,11 +566,11 @@ allocate_pty () if (access (pty_name, 6) != 0) { emacs_close (fd); -# if !defined(IRIS) && !defined(__sgi) +# ifndef __sgi continue; # else return -1; -# endif /* IRIS */ +# endif /* __sgi */ } setup_pty (fd); return fd; @@ -633,6 +600,7 @@ make_process (name) p->raw_status_new = 0; p->status = Qrun; p->mark = Fmake_marker (); + p->kill_without_query = 0; #ifdef ADAPTIVE_READ_BUFFERING p->adaptive_read_buffering = 0; @@ -678,6 +646,7 @@ setup_process_coding_systems (process) struct Lisp_Process *p = XPROCESS (process); int inch = p->infd; int outch = p->outfd; + Lisp_Object coding_system; if (inch < 0 || outch < 0) return; @@ -685,26 +654,21 @@ setup_process_coding_systems (process) if (!proc_decode_coding_system[inch]) proc_decode_coding_system[inch] = (struct coding_system *) xmalloc (sizeof (struct coding_system)); - setup_coding_system (p->decode_coding_system, - proc_decode_coding_system[inch]); + coding_system = p->decode_coding_system; if (! NILP (p->filter)) - { - if (!p->filter_multibyte) - setup_raw_text_coding_system (proc_decode_coding_system[inch]); - } + ; else if (BUFFERP (p->buffer)) { if (NILP (XBUFFER (p->buffer)->enable_multibyte_characters)) - setup_raw_text_coding_system (proc_decode_coding_system[inch]); + coding_system = raw_text_coding_system (coding_system); } + setup_coding_system (coding_system, proc_decode_coding_system[inch]); if (!proc_encode_coding_system[outch]) proc_encode_coding_system[outch] = (struct coding_system *) xmalloc (sizeof (struct coding_system)); setup_coding_system (p->encode_coding_system, proc_encode_coding_system[outch]); - if (proc_encode_coding_system[outch]->eol_type == CODING_EOL_UNDECIDED) - proc_encode_coding_system[outch]->eol_type = system_eol_type; } DEFUN ("processp", Fprocessp, Sprocessp, 1, 1, 0, @@ -809,7 +773,7 @@ nil, indicating the current buffer's process. */) p = XPROCESS (process); p->raw_status_new = 0; - if (NETCONN1_P (p)) + if (NETCONN1_P (p) || SERIALCONN1_P (p)) { p->status = Fcons (Qexit, Fcons (make_number (0), Qnil)); p->tick = ++process_tick; @@ -886,7 +850,7 @@ nil, indicating the current buffer's process. */) status = p->status; if (CONSP (status)) status = XCAR (status); - if (NETCONN1_P (p)) + if (NETCONN1_P (p) || SERIALCONN1_P (p)) { if (EQ (status, Qexit)) status = Qclosed; @@ -944,7 +908,8 @@ DEFUN ("process-command", Fprocess_command, Sprocess_command, 1, 1, 0, doc: /* Return the command that was executed to start PROCESS. This is a list of strings, the first string being the program executed and the rest of the strings being the arguments given to it. -For a non-child channel, this is nil. */) +For a network or serial process, this is nil (process is running) or t +\(process is stopped). */) (process) register Lisp_Object process; { @@ -976,7 +941,7 @@ DEFUN ("set-process-buffer", Fset_process_buffer, Sset_process_buffer, CHECK_BUFFER (buffer); p = XPROCESS (process); p->buffer = buffer; - if (NETCONN1_P (p)) + if (NETCONN1_P (p) || SERIALCONN1_P (p)) p->childp = Fplist_put (p->childp, QCbuffer, buffer); setup_process_coding_systems (process); return buffer; @@ -1043,7 +1008,8 @@ The string argument is normally a multibyte string, except: FD_CLR (p->infd, &non_keyboard_wait_mask); } else if (EQ (p->filter, Qt) - && !EQ (p->command, Qt)) /* Network process not stopped. */ + /* 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); @@ -1051,7 +1017,7 @@ The string argument is normally a multibyte string, except: } p->filter = filter; - if (NETCONN1_P (p)) + if (NETCONN1_P (p) || SERIALCONN1_P (p)) p->childp = Fplist_put (p->childp, QCfilter, filter); setup_process_coding_systems (process); return filter; @@ -1082,7 +1048,7 @@ It gets two arguments: the process, and a string describing the change. */) p = XPROCESS (process); p->sentinel = sentinel; - if (NETCONN1_P (p)) + if (NETCONN1_P (p) || SERIALCONN1_P (p)) p->childp = Fplist_put (p->childp, QCsentinel, sentinel); return sentinel; } @@ -1187,11 +1153,13 @@ Lisp_Object Fprocess_datagram_address (); DEFUN ("process-contact", Fprocess_contact, Sprocess_contact, 1, 2, 0, doc: /* Return the contact info of PROCESS; t for a real child. -For a net connection, the value depends on the optional KEY arg. -If KEY is nil, value is a cons cell of the form (HOST SERVICE), -if KEY is t, the complete contact information for the connection is -returned, else the specific value for the keyword KEY is returned. -See `make-network-process' for a list of keywords. */) +For a network or serial connection, the value depends on the optional +KEY arg. If KEY is nil, value is a cons cell of the form (HOST +SERVICE) for a network connection or (PORT SPEED) for a serial +connection. If KEY is t, the complete contact information for the +connection is returned, else the specific value for the keyword KEY is +returned. See `make-network-process' or `make-serial-process' for a +list of keywords. */) (process, key) register Lisp_Object process, key; { @@ -1207,11 +1175,14 @@ See `make-network-process' for a list of keywords. */) Fprocess_datagram_address (process)); #endif - if (!NETCONN_P (process) || EQ (key, Qt)) + if ((!NETCONN_P (process) && !SERIALCONN_P (process)) || EQ (key, Qt)) return contact; - if (NILP (key)) + if (NILP (key) && NETCONN_P (process)) return Fcons (Fplist_get (contact, QChost), Fcons (Fplist_get (contact, QCservice), Qnil)); + if (NILP (key) && SERIALCONN_P (process)) + return Fcons (Fplist_get (contact, QCport), + Fcons (Fplist_get (contact, QCspeed), Qnil)); return Fplist_get (contact, key); } @@ -1251,6 +1222,19 @@ a socket connection. */) } #endif +DEFUN ("process-type", Fprocess_type, Sprocess_type, 1, 1, 0, + doc: /* Return the connection type of PROCESS. +The value is either the symbol `real', `network', or `serial'. +PROCESS may be a process, a buffer, the name of a process or buffer, or +nil, indicating the current buffer's process. */) + (process) + Lisp_Object process; +{ + Lisp_Object proc; + proc = get_process (process); + return XPROCESS (proc)->type; +} + #ifdef HAVE_SOCKETS DEFUN ("format-network-address", Fformat_network_address, Sformat_network_address, 1, 2, 0, @@ -1350,7 +1334,7 @@ list_processes_1 (query_only) proc = Fcdr (XCAR (tail)); p = XPROCESS (proc); - if (NILP (p->childp)) + if (NILP (p->type)) continue; if (!NILP (query_only) && p->kill_without_query) continue; @@ -1418,7 +1402,7 @@ list_processes_1 (query_only) proc = Fcdr (XCAR (tail)); p = XPROCESS (proc); - if (NILP (p->childp)) + if (NILP (p->type)) continue; if (!NILP (query_only) && p->kill_without_query) continue; @@ -1436,14 +1420,9 @@ list_processes_1 (query_only) { Lisp_Object tem; tem = Fcar (Fcdr (p->status)); -#ifdef VMS - if (XINT (tem) < NSIG) - write_string (sys_errlist [XINT (tem)], -1); - else -#endif - Fprinc (symbol, Qnil); + Fprinc (symbol, Qnil); } - else if (NETCONN1_P (p)) + else if (NETCONN1_P (p) || SERIALCONN1_P (p)) { if (EQ (symbol, Qexit)) write_string ("closed", -1); @@ -1454,6 +1433,10 @@ list_processes_1 (query_only) else Fprinc (symbol, Qnil); } + else if (SERIALCONN1_P (p)) + { + write_string ("running", -1); + } else Fprinc (symbol, Qnil); @@ -1518,6 +1501,22 @@ list_processes_1 (query_only) (STRINGP (host) ? (char *)SDATA (host) : "?")); insert_string (tembuf); } + else if (SERIALCONN1_P (p)) + { + Lisp_Object port = Fplist_get (p->childp, QCport); + Lisp_Object speed = Fplist_get (p->childp, QCspeed); + insert_string ("(serial port "); + if (STRINGP (port)) + insert_string (SDATA (port)); + else + insert_string ("?"); + if (INTEGERP (speed)) + { + sprintf (tembuf, " at %d b/s", XINT (speed)); + insert_string (tembuf); + } + insert_string (")\n"); + } else { tem = p->command; @@ -1586,12 +1585,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) register Lisp_Object *args; { Lisp_Object buffer, name, program, proc, current_dir, tem; -#ifdef VMS - register unsigned char *new_argv; - int len; -#else register unsigned char **new_argv; -#endif register int i; int count = SPECPDL_INDEX (); @@ -1615,9 +1609,12 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) GCPRO2 (buffer, current_dir); - current_dir - = expand_and_dir_to_file (Funhandled_file_name_directory (current_dir), - Qnil); + current_dir = Funhandled_file_name_directory (current_dir); + if (NILP (current_dir)) + /* If the file name handler says that current_dir is unreachable, use + a sensible default. */ + current_dir = build_string ("~/"); + current_dir = expand_and_dir_to_file (current_dir, Qnil); if (NILP (Ffile_accessible_directory_p (current_dir))) report_file_error ("Setting current directory", Fcons (current_buffer->directory, Qnil)); @@ -1641,11 +1638,10 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) XPROCESS (proc)->childp = Qt; XPROCESS (proc)->plist = Qnil; + XPROCESS (proc)->type = Qreal; XPROCESS (proc)->buffer = buffer; XPROCESS (proc)->sentinel = Qnil; XPROCESS (proc)->filter = Qnil; - XPROCESS (proc)->filter_multibyte - = !NILP (buffer_defaults.enable_multibyte_characters); XPROCESS (proc)->command = Flist (nargs - 2, args + 2); #ifdef ADAPTIVE_READ_BUFFERING @@ -1706,28 +1702,6 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) XPROCESS (proc)->encode_coding_system = val; } -#ifdef VMS - /* Make a one member argv with all args concatenated - together separated by a blank. */ - len = SBYTES (program) + 2; - for (i = 3; i < nargs; i++) - { - tem = args[i]; - CHECK_STRING (tem); - len += SBYTES (tem) + 1; /* count the blank */ - } - new_argv = (unsigned char *) alloca (len); - strcpy (new_argv, SDATA (program)); - for (i = 3; i < nargs; i++) - { - tem = args[i]; - CHECK_STRING (tem); - strcat (new_argv, " "); - strcat (new_argv, SDATA (tem)); - } - /* Need to add code here to check for program existence on VMS */ - -#else /* not VMS */ new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *)); /* If program file name is not absolute, search our path for it. @@ -1779,7 +1753,6 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) new_argv[i - 2] = SDATA (tem); } new_argv[i - 2] = 0; -#endif /* not VMS */ XPROCESS (proc)->decoding_buf = make_uninit_string (0); XPROCESS (proc)->decoding_carryover = 0; @@ -1838,7 +1811,6 @@ create_process_sigchld () #endif #endif -#ifndef VMS /* VMS version of this function is in vmsproc.c. */ void create_process (process, new_argv, current_dir) Lisp_Object process; @@ -1848,6 +1820,9 @@ create_process (process, new_argv, current_dir) int inchannel, outchannel; pid_t pid; int sv[2]; +#if !defined (WINDOWSNT) && defined (FD_CLOEXEC) + int wait_child_setup[2]; +#endif #ifdef POSIX_SIGNALS sigset_t procmask; sigset_t blocked; @@ -1903,14 +1878,6 @@ create_process (process, new_argv, current_dir) } else #endif /* HAVE_PTYS */ -#ifdef SKTPAIR - { - if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0) - report_file_error ("Opening socketpair", Qnil); - outchannel = inchannel = sv[0]; - forkout = forkin = sv[1]; - } -#else /* not SKTPAIR */ { int tem; tem = pipe (sv); @@ -1928,7 +1895,25 @@ create_process (process, new_argv, current_dir) outchannel = sv[1]; forkin = sv[0]; } -#endif /* not SKTPAIR */ + +#if !defined (WINDOWSNT) && defined (FD_CLOEXEC) + { + int tem; + + tem = pipe (wait_child_setup); + if (tem < 0) + report_file_error ("Creating pipe", Qnil); + tem = fcntl (wait_child_setup[1], F_GETFD, 0); + if (tem >= 0) + tem = fcntl (wait_child_setup[1], F_SETFD, tem | FD_CLOEXEC); + if (tem < 0) + { + emacs_close (wait_child_setup[0]); + emacs_close (wait_child_setup[1]); + report_file_error ("Setting file descriptor flags", Qnil); + } + } +#endif #if 0 /* Replaced by close_process_descs */ @@ -1982,9 +1967,6 @@ create_process (process, new_argv, current_dir) sigprocmask (SIG_BLOCK, &blocked, &procmask); #else /* !POSIX_SIGNALS */ #ifdef SIGCHLD -#ifdef BSD4_1 - sighold (SIGCHLD); -#else /* not BSD4_1 */ #if defined (BSD_SYSTEM) || defined (HPUX) sigsetmask (sigmask (SIGCHLD)); #else /* ordinary USG */ @@ -1993,7 +1975,6 @@ create_process (process, new_argv, current_dir) sigchld = signal (SIGCHLD, create_process_sigchld); #endif #endif /* ordinary USG */ -#endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ @@ -2110,9 +2091,6 @@ create_process (process, new_argv, current_dir) This makes the pty the controlling terminal of the subprocess. */ if (pty_flag) { -#ifdef SET_CHILD_PTY_PGRP - int pgrp = getpid (); -#endif /* I wonder if emacs_close (emacs_open (pty_name, ...)) would work? */ @@ -2128,10 +2106,6 @@ create_process (process, new_argv, current_dir) _exit (1); } -#ifdef SET_CHILD_PTY_PGRP - ioctl (xforkin, TIOCSPGRP, &pgrp); - ioctl (xforkout, TIOCSPGRP, &pgrp); -#endif } #endif /* not DONT_REOPEN_PTY */ @@ -2157,9 +2131,6 @@ create_process (process, new_argv, current_dir) sigprocmask (SIG_SETMASK, &procmask, 0); #else /* !POSIX_SIGNALS */ #ifdef SIGCHLD -#ifdef BSD4_1 - sigrelse (SIGCHLD); -#else /* not BSD4_1 */ #if defined (BSD_SYSTEM) || defined (HPUX) sigsetmask (SIGEMPTYMASK); #else /* ordinary USG */ @@ -2167,7 +2138,6 @@ create_process (process, new_argv, current_dir) signal (SIGCHLD, sigchld); #endif #endif /* ordinary USG */ -#endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ @@ -2179,6 +2149,9 @@ create_process (process, new_argv, current_dir) pid = child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir); #else /* not WINDOWSNT */ +#ifdef FD_CLOEXEC + emacs_close (wait_child_setup[0]); +#endif child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir); #endif /* not WINDOWSNT */ @@ -2232,6 +2205,20 @@ create_process (process, new_argv, current_dir) else #endif XPROCESS (process)->tty_name = Qnil; + +#if !defined (WINDOWSNT) && defined (FD_CLOEXEC) + /* Wait for child_setup to complete in case that vfork is + actually defined as fork. The descriptor wait_child_setup[1] + of a pipe is closed at the child side either by close-on-exec + on successful execvp or the _exit call in child_setup. */ + { + char dummy; + + emacs_close (wait_child_setup[1]); + emacs_read (wait_child_setup[0], &dummy, 1); + emacs_close (wait_child_setup[0]); + } +#endif } /* Restore the signal state whether vfork succeeded or not. @@ -2249,9 +2236,6 @@ create_process (process, new_argv, current_dir) sigprocmask (SIG_SETMASK, &procmask, 0); #else /* !POSIX_SIGNALS */ #ifdef SIGCHLD -#ifdef BSD4_1 - sigrelse (SIGCHLD); -#else /* not BSD4_1 */ #if defined (BSD_SYSTEM) || defined (HPUX) sigsetmask (SIGEMPTYMASK); #else /* ordinary USG */ @@ -2263,7 +2247,6 @@ create_process (process, new_argv, current_dir) kill (getpid (), SIGCHLD); #endif #endif /* ordinary USG */ -#endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ @@ -2271,7 +2254,6 @@ create_process (process, new_argv, current_dir) if (pid < 0) report_file_error ("Doing vfork", Qnil); } -#endif /* not VMS */ #ifdef HAVE_SOCKETS @@ -2676,18 +2658,307 @@ OPTION is not a supported option, return nil instead; otherwise return t. */) } -/* A version of request_sigio suitable for a record_unwind_protect. */ +#ifdef HAVE_SERIAL +DEFUN ("serial-process-configure", + Fserial_process_configure, + Sserial_process_configure, + 0, MANY, 0, + doc: /* Configure speed, bytesize, etc. of a serial process. -#ifdef __ultrix__ -static Lisp_Object -unwind_request_sigio (dummy) - Lisp_Object dummy; +Arguments are specified as keyword/argument pairs. Attributes that +are not given are re-initialized from the process's current +configuration (available via the function `process-contact') or set to +reasonable default values. The following arguments are defined: + +:process PROCESS +:name NAME +:buffer BUFFER +:port PORT +-- Any of these arguments can be given to identify the process that is +to be configured. If none of these arguments is given, the current +buffer's process is used. + +:speed SPEED -- SPEED is the speed of the serial port in bits per +second, also called baud rate. Any value can be given for SPEED, but +most serial ports work only at a few defined values between 1200 and +115200, with 9600 being the most common value. If SPEED is nil, the +serial port is not configured any further, i.e., all other arguments +are ignored. This may be useful for special serial ports such as +Bluetooth-to-serial converters which can only be configured through AT +commands. A value of nil for SPEED can be used only when passed +through `make-serial-process' or `serial-term'. + +:bytesize BYTESIZE -- BYTESIZE is the number of bits per byte, which +can be 7 or 8. If BYTESIZE is not given or nil, a value of 8 is used. + +:parity PARITY -- PARITY can be nil (don't use parity), the symbol +`odd' (use odd parity), or the symbol `even' (use even parity). If +PARITY is not given, no parity is used. + +:stopbits STOPBITS -- STOPBITS is the number of stopbits used to +terminate a byte transmission. STOPBITS can be 1 or 2. If STOPBITS +is not given or nil, 1 stopbit is used. + +:flowcontrol FLOWCONTROL -- FLOWCONTROL determines the type of +flowcontrol to be used, which is either nil (don't use flowcontrol), +the symbol `hw' (use RTS/CTS hardware flowcontrol), or the symbol `sw' +\(use XON/XOFF software flowcontrol). If FLOWCONTROL is not given, no +flowcontrol is used. + +`serial-process-configure' is called by `make-serial-process' for the +initial configuration of the serial port. + +Examples: + +\(serial-process-configure :process "/dev/ttyS0" :speed 1200) + +\(serial-process-configure + :buffer "COM1" :stopbits 1 :parity 'odd :flowcontrol 'hw) + +\(serial-process-configure :port "\\\\.\\COM13" :bytesize 7) + +usage: (serial-process-configure &rest ARGS) */) + (nargs, args) + int nargs; + Lisp_Object *args; +{ + struct Lisp_Process *p; + Lisp_Object contact = Qnil; + Lisp_Object proc = Qnil; + struct gcpro gcpro1; + + contact = Flist (nargs, args); + GCPRO1 (contact); + + proc = Fplist_get (contact, QCprocess); + if (NILP (proc)) + proc = Fplist_get (contact, QCname); + if (NILP (proc)) + proc = Fplist_get (contact, QCbuffer); + if (NILP (proc)) + proc = Fplist_get (contact, QCport); + proc = get_process (proc); + p = XPROCESS (proc); + if (!EQ (p->type, Qserial)) + error ("Not a serial process"); + + if (NILP (Fplist_get (p->childp, QCspeed))) + { + UNGCPRO; + return Qnil; + } + + serial_configure (p, contact); + + UNGCPRO; + return Qnil; +} + +/* Used by make-serial-process to recover from errors. */ +Lisp_Object make_serial_process_unwind (Lisp_Object proc) { - if (interrupt_input) - request_sigio (); + if (!PROCESSP (proc)) + abort (); + remove_process (proc); return Qnil; } -#endif + +DEFUN ("make-serial-process", Fmake_serial_process, Smake_serial_process, + 0, MANY, 0, + doc: /* Create and return a serial port process. + +In Emacs, serial port connections are represented by process objects, +so input and output work as for subprocesses, and `delete-process' +closes a serial port connection. However, a serial process has no +process id, it cannot be signaled, and the status codes are different +from normal processes. + +`make-serial-process' creates a process and a buffer, on which you +probably want to use `process-send-string'. Try \\[serial-term] for +an interactive terminal. See below for examples. + +Arguments are specified as keyword/argument pairs. The following +arguments are defined: + +:port PORT -- (mandatory) PORT is the path or name of the serial port. +For example, this could be "/dev/ttyS0" on Unix. On Windows, this +could be "COM1", or "\\\\.\\COM10" for ports higher than COM9 (double +the backslashes in strings). + +:speed SPEED -- (mandatory) is handled by `serial-process-configure', +which is called by `make-serial-process'. + +:name NAME -- NAME is the name of the process. If NAME is not given, +the value of PORT is used. + +:buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate +with the process. Process output goes at the end of that buffer, +unless you specify an output stream or filter function to handle the +output. If BUFFER is not given, the value of NAME is used. + +:coding CODING -- If CODING is a symbol, it specifies the coding +system used for both reading and writing for this process. If CODING +is a cons (DECODING . ENCODING), DECODING is used for reading, and +ENCODING is used for writing. + +:noquery BOOL -- When exiting Emacs, query the user if BOOL is nil and +the process is running. If BOOL is not given, query before exiting. + +:stop BOOL -- Start process in the `stopped' state if BOOL is non-nil. +In the stopped state, a serial process does not accept incoming data, +but you can send outgoing data. The stopped state is cleared by +`continue-process' and set by `stop-process'. + +:filter FILTER -- Install FILTER as the process filter. + +:sentinel SENTINEL -- Install SENTINEL as the process sentinel. + +:plist PLIST -- Install PLIST as the initial plist of the process. + +:speed +:bytesize +:parity +:stopbits +:flowcontrol +-- These arguments are handled by `serial-process-configure', which is +called by `make-serial-process'. + +The original argument list, possibly modified by later configuration, +is available via the function `process-contact'. + +Examples: + +\(make-serial-process :port "/dev/ttyS0" :speed 9600) + +\(make-serial-process :port "COM1" :speed 115200 :stopbits 2) + +\(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity 'odd) + +\(make-serial-process :port "/dev/tty.BlueConsole-SPP-1" :speed nil) + +usage: (make-serial-process &rest ARGS) */) + (nargs, args) + int nargs; + Lisp_Object *args; +{ + int fd = -1; + Lisp_Object proc, contact, port; + struct Lisp_Process *p; + struct gcpro gcpro1; + Lisp_Object name, buffer; + Lisp_Object tem, val; + int specpdl_count = -1; + + if (nargs == 0) + return Qnil; + + contact = Flist (nargs, args); + GCPRO1 (contact); + + port = Fplist_get (contact, QCport); + if (NILP (port)) + error ("No port specified"); + CHECK_STRING (port); + + if (NILP (Fplist_member (contact, QCspeed))) + error (":speed not specified"); + if (!NILP (Fplist_get (contact, QCspeed))) + CHECK_NUMBER (Fplist_get (contact, QCspeed)); + + name = Fplist_get (contact, QCname); + if (NILP (name)) + name = port; + CHECK_STRING (name); + proc = make_process (name); + specpdl_count = SPECPDL_INDEX (); + record_unwind_protect (make_serial_process_unwind, proc); + p = XPROCESS (proc); + + fd = serial_open ((char*) SDATA (port)); + p->infd = fd; + p->outfd = fd; + if (fd > max_process_desc) + max_process_desc = fd; + chan_process[fd] = proc; + + buffer = Fplist_get (contact, QCbuffer); + if (NILP (buffer)) + buffer = name; + buffer = Fget_buffer_create (buffer); + p->buffer = buffer; + + p->childp = contact; + p->plist = Fcopy_sequence (Fplist_get (contact, QCplist)); + p->type = Qserial; + p->sentinel = Fplist_get (contact, QCsentinel); + p->filter = Fplist_get (contact, QCfilter); + p->log = Qnil; + if (tem = Fplist_get (contact, QCnoquery), !NILP (tem)) + p->kill_without_query = 1; + if (tem = Fplist_get (contact, QCstop), !NILP (tem)) + p->command = Qt; + p->pty_flag = 0; + + if (!EQ (p->command, Qt)) + { + FD_SET (fd, &input_wait_mask); + FD_SET (fd, &non_keyboard_wait_mask); + } + + if (BUFFERP (buffer)) + { + set_marker_both (p->mark, buffer, + BUF_ZV (XBUFFER (buffer)), + BUF_ZV_BYTE (XBUFFER (buffer))); + } + + tem = Fplist_member (contact, QCcoding); + if (!NILP (tem) && (!CONSP (tem) || !CONSP (XCDR (tem)))) + tem = Qnil; + + val = Qnil; + if (!NILP (tem)) + { + val = XCAR (XCDR (tem)); + if (CONSP (val)) + val = XCAR (val); + } + else if (!NILP (Vcoding_system_for_read)) + val = Vcoding_system_for_read; + else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters)) + || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters))) + val = Qnil; + p->decode_coding_system = val; + + val = Qnil; + if (!NILP (tem)) + { + val = XCAR (XCDR (tem)); + if (CONSP (val)) + val = XCDR (val); + } + else if (!NILP (Vcoding_system_for_write)) + val = Vcoding_system_for_write; + else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters)) + || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters))) + val = Qnil; + p->encode_coding_system = val; + + setup_process_coding_systems (proc); + p->decoding_buf = make_uninit_string (0); + p->decoding_carryover = 0; + p->encoding_buf = make_uninit_string (0); + p->inherit_coding_system_flag + = !(!NILP (tem) || NILP (buffer) || !inherit_process_coding_system); + + Fserial_process_configure(nargs, args); + + specpdl_ptr = specpdl + specpdl_count; + + UNGCPRO; + return proc; +} +#endif /* HAVE_SERIAL */ /* Create a network stream/datagram client/server process. Treated exactly like a normal process when reading and writing. Primary @@ -2917,7 +3188,7 @@ usage: (make-network-process &rest ARGS) */) { /* Don't support network sockets when non-blocking mode is not available, since a blocked Emacs is not useful. */ -#if defined(TERM) || (!defined(O_NONBLOCK) && !defined(O_NDELAY)) +#if !defined(O_NONBLOCK) && !defined(O_NDELAY) error ("Network servers not supported"); #else is_server = 1; @@ -2947,32 +3218,6 @@ usage: (make-network-process &rest ARGS) */) CHECK_STRING (name); -#ifdef TERM - /* Let's handle TERM before things get complicated ... */ - host = Fplist_get (contact, QChost); - CHECK_STRING (host); - - service = Fplist_get (contact, QCservice); - if (INTEGERP (service)) - port = htons ((unsigned short) XINT (service)); - else - { - struct servent *svc_info; - CHECK_STRING (service); - svc_info = getservbyname (SDATA (service), "tcp"); - if (svc_info == 0) - error ("Unknown service: %s", SDATA (service)); - port = svc_info->s_port; - } - - s = connect_server (0); - if (s < 0) - report_file_error ("error creating socket", Fcons (name, Qnil)); - send_command (s, C_PORT, 0, "%s:%d", SDATA (host), ntohs (port)); - send_command (s, C_DUMB, 1, 0); - -#else /* not TERM */ - /* Initialize addrinfo structure in case we don't use getaddrinfo. */ ai.ai_socktype = socktype; ai.ai_protocol = 0; @@ -3154,9 +3399,9 @@ usage: (make-network-process &rest ARGS) */) else /* Attempt to interpret host as numeric inet address */ { - IN_ADDR numeric_addr; + unsigned long numeric_addr; numeric_addr = inet_addr ((char *) SDATA (host)); - if (NUMERIC_ADDR_ERROR) + if (numeric_addr == -1) error ("Unknown host \"%s\"", SDATA (host)); bcopy ((char *)&numeric_addr, (char *) &address_in.sin_addr, @@ -3172,28 +3417,6 @@ usage: (make-network-process &rest ARGS) */) open_socket: -#ifdef __ultrix__ - /* Previously this was compiled unconditionally, but that seems - unnecessary on modern systems, and `unrequest_sigio' was a noop - under X anyway. --lorentey */ - /* 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. */ - if (interrupt_input - && !is_server && socktype == SOCK_STREAM) - { - /* Comment from KFS: The original open-network-stream code - didn't unwind protect this, but it seems like the proper - thing to do. In any case, I don't see how it could harm to - do this -- and it makes cleanup (using unbind_to) easier. */ - record_unwind_protect (unwind_request_sigio, Qnil); - unrequest_sigio (); - } -#endif - /* Do this in case we never enter the for-loop below. */ count1 = SPECPDL_INDEX (); s = -1; @@ -3239,7 +3462,7 @@ usage: (make-network-process &rest ARGS) */) /* Parse network options in the arg list. We simply ignore anything which isn't a known option (including other keywords). - An error is signalled if setting a known option fails. */ + An error is signaled if setting a known option fails. */ for (optn = optbits = 0; optn < nargs-1; optn += 2) optbits |= set_socket_option (s, args[optn], args[optn+1]); @@ -3405,8 +3628,6 @@ usage: (make-network-process &rest ARGS) */) report_file_error ("make client process failed", contact); } -#endif /* not TERM */ - inch = s; outch = s; @@ -3428,14 +3649,11 @@ usage: (make-network-process &rest ARGS) */) p->childp = contact; p->plist = Fcopy_sequence (Fplist_get (contact, QCplist)); + p->type = Qnetwork; p->buffer = buffer; p->sentinel = sentinel; p->filter = filter; - p->filter_multibyte = !NILP (buffer_defaults.enable_multibyte_characters); - /* Override the above only if :filter-multibyte is specified. */ - if (! NILP (Fplist_member (contact, QCfilter_multibyte))) - p->filter_multibyte = !NILP (Fplist_get (contact, QCfilter_multibyte)); p->log = Fplist_get (contact, QClog); if (tem = Fplist_get (contact, QCnoquery), !NILP (tem)) p->kill_without_query = 1; @@ -3848,19 +4066,9 @@ deactivate_process (proc) { /* Beware SIGCHLD hereabouts. */ flush_pending_output (inchannel); -#ifdef VMS - { - VMS_PROC_STUFF *get_vms_process_pointer (), *vs; - sys$dassgn (outchannel); - vs = get_vms_process_pointer (p->pid); - if (vs) - give_back_vms_process_stuff (vs); - } -#else emacs_close (inchannel); if (outchannel >= 0 && outchannel != inchannel) emacs_close (outchannel); -#endif p->infd = -1; p->outfd = -1; @@ -3929,10 +4137,11 @@ It is read into the process' buffers or given to their filter functions. Non-nil arg PROCESS means do not return until some output has been received from PROCESS. -Non-nil second arg SECONDS and third arg MILLISEC are number of -seconds and milliseconds to wait; return after that much time whether -or not there is input. If SECONDS is a floating point number, +Non-nil second arg SECONDS and third arg MILLISEC are number of seconds +and milliseconds to wait; return after that much time whether or not +there is any subprocess output. If SECONDS is a floating point number, it specifies a fractional number of seconds to wait. +The MILLISEC argument is obsolete and should be avoided. If optional fourth arg JUST-THIS-ONE is non-nil, only accept output from PROCESS, suspending reading output from other processes. @@ -3948,6 +4157,18 @@ Return non-nil if we received any output before the timeout expired. */) else just_this_one = Qnil; + if (!NILP (millisec)) + { /* Obsolete calling convention using integers rather than floats. */ + CHECK_NUMBER (millisec); + if (NILP (seconds)) + seconds = make_float (XINT (millisec) / 1000.0); + else + { + CHECK_NUMBER (seconds); + seconds = make_float (XINT (millisec) / 1000.0 + XINT (seconds)); + } + } + if (!NILP (seconds)) { if (INTEGERP (seconds)) @@ -3961,19 +4182,6 @@ Return non-nil if we received any output before the timeout expired. */) else wrong_type_argument (Qnumberp, seconds); - if (INTEGERP (millisec)) - { - int carry; - usecs += XINT (millisec) * 1000; - carry = usecs / 1000000; - secs += carry; - if ((usecs -= carry * 1000000) < 0) - { - secs--; - usecs += 1000000; - } - } - if (secs < 0 || (secs == 0 && usecs == 0)) secs = -1, usecs = 0; } @@ -4090,7 +4298,7 @@ server_accept_connection (server, channel) #endif default: caller = Fnumber_to_string (make_number (connect_counter)); - caller = concat3 (build_string (" <*"), caller, build_string ("*>")); + caller = concat3 (build_string (" <"), caller, build_string (">")); break; } @@ -4150,6 +4358,7 @@ server_accept_connection (server, channel) p->childp = contact; p->plist = Fcopy_sequence (ps->plist); + p->type = Qnetwork; p->buffer = buffer; p->sentinel = ps->sentinel; @@ -4323,16 +4532,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, EMACS_SET_SECS_USECS (timeout, time_limit, microsecs); EMACS_ADD_TIME (end_time, end_time, timeout); } -#ifdef POLL_INTERRUPTED_SYS_CALL - /* AlainF 5-Jul-1996 - HP-UX 10.10 seem to have problems with signals coming in - Causes "poll: interrupted system call" messages when Emacs is run - in an X window - Turn off periodic alarms (in case they are in use), - and then turn off any other atimers. */ - stop_polling (); - turn_on_atimers (0); -#endif /* POLL_INTERRUPTED_SYS_CALL */ while (1) { @@ -4344,8 +4543,13 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, if (read_kbd >= 0) QUIT; #ifdef SYNC_INPUT - else if (interrupt_input_pending) - handle_async_input (); + else + { + if (interrupt_input_pending) + handle_async_input (); + if (pending_atimers) + do_pending_atimers (); + } #endif /* Exit now if the cell we're waiting for became non-nil. */ @@ -4387,13 +4591,15 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, { int old_timers_run = timers_run; struct buffer *old_buffer = current_buffer; + Lisp_Object old_window = selected_window; timer_delay = timer_check (1); /* If a timer has run, this might have changed buffers an alike. Make read_key_sequence aware of that. */ if (timers_run != old_timers_run - && old_buffer != current_buffer + && (old_buffer != current_buffer + || !EQ (old_window, selected_window)) && waiting_for_user_input_p == -1) record_asynch_buffer_change (); @@ -4441,8 +4647,11 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, /* If status of something has changed, and no input is available, notify the user of the change right away. After this explicit check, we'll let the SIGCHLD handler zap - timeout to get our attention. */ - if (update_tick != process_tick && do_display) + timeout to get our attention. When Emacs is run + interactively, only do this with a nonzero DO_DISPLAY + argument, because status_notify triggers redisplay. */ + if (update_tick != process_tick + && (do_display || noninteractive)) { SELECT_TYPE Atemp; #ifdef NON_BLOCKING_CONNECT @@ -4450,15 +4659,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, #endif Atemp = input_wait_mask; -#if 0 - /* On Mac OS X 10.0, the SELECT system call always says input is - present (for reading) at stdin, even when none is. This - causes the call to SELECT below to return 1 and - status_notify not to be called. As a result output of - subprocesses are incorrectly discarded. - */ - FD_CLR (0, &Atemp); -#endif IF_NON_BLOCKING_CONNECT (Ctemp = connect_wait_mask); EMACS_SET_SECS_USECS (timeout, 0, 0); @@ -4502,7 +4702,10 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, break; if (0 < nread) - total_nread += nread; + { + total_nread += nread; + got_some_input = 1; + } #ifdef EIO else if (nread == -1 && EIO == errno) break; @@ -4607,8 +4810,12 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, process_output_skip = 0; } #endif - - nfds = select (max (max (max_process_desc, max_keyboard_desc), +#ifdef HAVE_NS + nfds = ns_select +#else + nfds = select +#endif + (max (max (max_process_desc, max_keyboard_desc), max_gpm_desc) + 1, &Available, #ifdef NON_BLOCKING_CONNECT @@ -4634,15 +4841,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, { if (xerrno == EINTR) no_avail = 1; -#ifdef ultrix - /* Ultrix select seems to return ENOMEM when it is - interrupted. Treat it just like EINTR. Bleah. Note - that we want to test for the "ultrix" CPP symbol, not - "__ultrix__"; the latter is only defined under GCC, but - not by DEC's bundled CC. -JimB */ - else if (xerrno == ENOMEM) - no_avail = 1; -#endif else if (xerrno == EBADF) { #ifdef AIX @@ -4668,19 +4866,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, IF_NON_BLOCKING_CONNECT (check_connect = 0); } -#if defined(sun) && !defined(USG5_4) - if (nfds > 0 && keyboard_bit_set (&Available) - && interrupt_input) - /* System sometimes fails to deliver SIGIO. - - David J. Mackenzie says that Emacs doesn't compile under - Solaris if this code is enabled, thus the USG5_4 in the CPP - conditional. "I haven't noticed any ill effects so far. - If you find a Solaris expert somewhere, they might know - better." */ - kill (getpid (), SIGIO); -#endif - #if 0 /* When polling is used, interrupt_input is 0, so get_input_pending should read the input. So this should not be needed. */ @@ -4835,7 +5020,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, available now and a closed pipe. With luck, a closed pipe will be accompanied by subprocess termination and SIGCHLD. */ - else if (nread == 0 && !NETCONN_P (proc)) + else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc)) ; #endif /* O_NDELAY */ #endif /* O_NONBLOCK */ @@ -4863,7 +5048,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, /* If we can detect process termination, don't consider the process gone just because its pipe is closed. */ #ifdef SIGCHLD - else if (nread == 0 && !NETCONN_P (proc)) + else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc)) ; #endif else @@ -4954,14 +5139,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, clear_input_pending (); QUIT; } -#ifdef POLL_INTERRUPTED_SYS_CALL - /* AlainF 5-Jul-1996 - HP-UX 10.10 seems to have problems with signals coming in - Causes "poll: interrupted system call" messages when Emacs is run - in an X window - Turn periodic alarms back on */ - start_polling (); -#endif /* POLL_INTERRUPTED_SYS_CALL */ return got_some_input; } @@ -5012,37 +5189,6 @@ read_process_output (proc, channel) int carryover = p->decoding_carryover; int readmax = 4096; -#ifdef VMS - VMS_PROC_STUFF *vs, *get_vms_process_pointer(); - - vs = get_vms_process_pointer (p->pid); - if (vs) - { - if (!vs->iosb[0]) - return (0); /* Really weird if it does this */ - if (!(vs->iosb[0] & 1)) - return -1; /* I/O error */ - } - else - error ("Could not get VMS process pointer"); - chars = vs->inputBuffer; - nbytes = clean_vms_buffer (chars, vs->iosb[1]); - if (nbytes <= 0) - { - start_vms_process_read (vs); /* Crank up the next read on the process */ - return 1; /* Nothing worth printing, say we got 1 */ - } - if (carryover > 0) - { - /* The data carried over in the previous decoding (which are at - the tail of decoding buffer) should be prepended to the new - data read to decode all together. */ - chars = (char *) alloca (nbytes + carryover); - bcopy (SDATA (p->decoding_buf), buf, carryover); - bcopy (vs->inputBuffer, chars + carryover, nbytes); - } -#else /* not VMS */ - chars = (char *) alloca (carryover + readmax); if (carryover) /* See the comment above. */ @@ -5099,7 +5245,6 @@ read_process_output (proc, channel) else nbytes = nbytes + 1; } -#endif /* not VMS */ p->decoding_carryover = 0; @@ -5155,13 +5300,13 @@ read_process_output (proc, channel) save the match data in a special nonrecursive fashion. */ running_asynch_code = 1; - text = decode_coding_string (make_unibyte_string (chars, nbytes), - coding, 0); - Vlast_coding_system_used = coding->symbol; + decode_coding_c_string (coding, chars, nbytes, Qt); + text = coding->dst_object; + Vlast_coding_system_used = CODING_ID_NAME (coding->id); /* A new coding system might be found. */ - if (!EQ (p->decode_coding_system, coding->symbol)) + if (!EQ (p->decode_coding_system, Vlast_coding_system_used)) { - p->decode_coding_system = coding->symbol; + p->decode_coding_system = Vlast_coding_system_used; /* Don't call setup_coding_system for proc_decode_coding_system[channel] here. It is done in @@ -5177,30 +5322,21 @@ read_process_output (proc, channel) if (NILP (p->encode_coding_system) && proc_encode_coding_system[p->outfd]) { - p->encode_coding_system = coding->symbol; - setup_coding_system (coding->symbol, + p->encode_coding_system + = coding_inherit_eol_type (Vlast_coding_system_used, Qnil); + setup_coding_system (p->encode_coding_system, proc_encode_coding_system[p->outfd]); - if (proc_encode_coding_system[p->outfd]->eol_type - == CODING_EOL_UNDECIDED) - proc_encode_coding_system[p->outfd]->eol_type - = system_eol_type; } } - carryover = nbytes - coding->consumed; - if (carryover < 0) - abort (); - - if (SCHARS (p->decoding_buf) < carryover) - p->decoding_buf = make_uninit_string (carryover); - bcopy (chars + coding->consumed, SDATA (p->decoding_buf), - carryover); - p->decoding_carryover = carryover; - /* Adjust the multibyteness of TEXT to that of the filter. */ - if (!p->filter_multibyte != !STRING_MULTIBYTE (text)) - text = (STRING_MULTIBYTE (text) - ? Fstring_as_unibyte (text) - : Fstring_to_multibyte (text)); + if (coding->carryover_bytes > 0) + { + if (SCHARS (p->decoding_buf) < coding->carryover_bytes) + p->decoding_buf = make_uninit_string (coding->carryover_bytes); + bcopy (coding->carryover, SDATA (p->decoding_buf), + coding->carryover_bytes); + p->decoding_carryover = coding->carryover_bytes; + } if (SBYTES (text) > 0) internal_condition_case_1 (read_process_output_call, Fcons (outstream, @@ -5231,9 +5367,6 @@ read_process_output (proc, channel) if (waiting_for_user_input_p == -1) record_asynch_buffer_change (); -#ifdef VMS - start_vms_process_read (vs); -#endif unbind_to (count, Qnil); return nbytes; } @@ -5280,36 +5413,31 @@ read_process_output (proc, channel) if (! (BEGV <= PT && PT <= ZV)) Fwiden (); - text = decode_coding_string (make_unibyte_string (chars, nbytes), - coding, 0); - Vlast_coding_system_used = coding->symbol; + decode_coding_c_string (coding, chars, nbytes, Qt); + text = coding->dst_object; + Vlast_coding_system_used = CODING_ID_NAME (coding->id); /* A new coding system might be found. See the comment in the similar code in the previous `if' block. */ - if (!EQ (p->decode_coding_system, coding->symbol)) + if (!EQ (p->decode_coding_system, Vlast_coding_system_used)) { - p->decode_coding_system = coding->symbol; + p->decode_coding_system = Vlast_coding_system_used; if (NILP (p->encode_coding_system) && proc_encode_coding_system[p->outfd]) { - p->encode_coding_system = coding->symbol; - setup_coding_system (coding->symbol, + p->encode_coding_system + = coding_inherit_eol_type (Vlast_coding_system_used, Qnil); + setup_coding_system (p->encode_coding_system, proc_encode_coding_system[p->outfd]); - if (proc_encode_coding_system[p->outfd]->eol_type - == CODING_EOL_UNDECIDED) - proc_encode_coding_system[p->outfd]->eol_type - = system_eol_type; } } - carryover = nbytes - coding->consumed; - if (carryover < 0) - abort (); - - if (SCHARS (p->decoding_buf) < carryover) - p->decoding_buf = make_uninit_string (carryover); - bcopy (chars + coding->consumed, SDATA (p->decoding_buf), - carryover); - p->decoding_carryover = carryover; - + if (coding->carryover_bytes > 0) + { + if (SCHARS (p->decoding_buf) < coding->carryover_bytes) + p->decoding_buf = make_uninit_string (coding->carryover_bytes); + bcopy (coding->carryover, SDATA (p->decoding_buf), + coding->carryover_bytes); + p->decoding_carryover = coding->carryover_bytes; + } /* Adjust the multibyteness of TEXT to that of the buffer. */ if (NILP (current_buffer->enable_multibyte_characters) != ! STRING_MULTIBYTE (text)) @@ -5361,9 +5489,6 @@ read_process_output (proc, channel) SET_PT_BOTH (opoint, opoint_byte); set_buffer_internal (old); } -#ifdef VMS - start_vms_process_read (vs); -#endif return nbytes; } @@ -5385,10 +5510,6 @@ SIGTYPE send_process_trap () { SIGNAL_THREAD_CHECK (SIGPIPE); -#ifdef BSD4_1 - sigrelse (SIGPIPE); - sigrelse (SIGALRM); -#endif /* BSD4_1 */ sigunblock (sigmask (SIGPIPE)); longjmp (send_process_frame, 1); } @@ -5419,10 +5540,6 @@ send_process (proc, buf, len, object) GCPRO1 (object); -#ifdef VMS - VMS_PROC_STUFF *vs, *get_vms_process_pointer(); -#endif /* VMS */ - if (p->raw_status_new) update_status (p); if (! EQ (p->status, Qrun)) @@ -5431,24 +5548,19 @@ send_process (proc, buf, len, object) error ("Output file descriptor of %s is closed", SDATA (p->name)); coding = proc_encode_coding_system[p->outfd]; - Vlast_coding_system_used = coding->symbol; + Vlast_coding_system_used = CODING_ID_NAME (coding->id); if ((STRINGP (object) && STRING_MULTIBYTE (object)) || (BUFFERP (object) && !NILP (XBUFFER (object)->enable_multibyte_characters)) || EQ (object, Qt)) { - if (!EQ (coding->symbol, p->encode_coding_system)) + if (!EQ (Vlast_coding_system_used, p->encode_coding_system)) /* The coding system for encoding was changed to raw-text because we sent a unibyte text previously. Now we are sending a multibyte text, thus we must encode it by the original coding system specified for the current process. */ setup_coding_system (p->encode_coding_system, coding); - if (coding->eol_type == CODING_EOL_UNDECIDED) - coding->eol_type = system_eol_type; - /* src_multibyte should be set to 1 _after_ a call to - setup_coding_system, since it resets src_multibyte to - zero. */ coding->src_multibyte = 1; } else @@ -5456,70 +5568,58 @@ send_process (proc, buf, len, object) /* For sending a unibyte text, character code conversion should not take place but EOL conversion should. So, setup raw-text or one of the subsidiary if we have not yet done it. */ - if (coding->type != coding_type_raw_text) + if (CODING_REQUIRE_ENCODING (coding)) { if (CODING_REQUIRE_FLUSHING (coding)) { /* But, before changing the coding, we must flush out data. */ coding->mode |= CODING_MODE_LAST_BLOCK; send_process (proc, "", 0, Qt); + coding->mode &= CODING_MODE_LAST_BLOCK; } + setup_coding_system (raw_text_coding_system + (Vlast_coding_system_used), + coding); coding->src_multibyte = 0; - setup_raw_text_coding_system (coding); } } coding->dst_multibyte = 0; if (CODING_REQUIRE_ENCODING (coding)) { - int require = encoding_buffer_size (coding, len); - int from_byte = -1, from = -1, to = -1; - + coding->dst_object = Qt; if (BUFFERP (object)) { - from_byte = BUF_PTR_BYTE_POS (XBUFFER (object), buf); - from = buf_bytepos_to_charpos (XBUFFER (object), from_byte); - to = buf_bytepos_to_charpos (XBUFFER (object), from_byte + len); + int from_byte, from, to; + int save_pt, save_pt_byte; + struct buffer *cur = current_buffer; + + set_buffer_internal (XBUFFER (object)); + save_pt = PT, save_pt_byte = PT_BYTE; + + from_byte = PTR_BYTE_POS (buf); + from = BYTE_TO_CHAR (from_byte); + to = BYTE_TO_CHAR (from_byte + len); + TEMP_SET_PT_BOTH (from, from_byte); + encode_coding_object (coding, object, from, from_byte, + to, from_byte + len, Qt); + TEMP_SET_PT_BOTH (save_pt, save_pt_byte); + set_buffer_internal (cur); } else if (STRINGP (object)) { - from_byte = buf - SDATA (object); - from = string_byte_to_char (object, from_byte); - to = string_byte_to_char (object, from_byte + len); + encode_coding_string (coding, object, 1); } - - if (coding->composing != COMPOSITION_DISABLED) + else { - if (from_byte >= 0) - coding_save_composition (coding, from, to, object); - else - coding->composing = COMPOSITION_DISABLED; + coding->dst_object = make_unibyte_string (buf, len); + coding->produced = len; } - if (SBYTES (p->encoding_buf) < require) - p->encoding_buf = make_uninit_string (require); - - if (from_byte >= 0) - buf = (BUFFERP (object) - ? BUF_BYTE_ADDRESS (XBUFFER (object), from_byte) - : SDATA (object) + from_byte); - - object = p->encoding_buf; - encode_coding (coding, (char *) buf, SDATA (object), - len, SBYTES (object)); - coding_free_composition_data (coding); len = coding->produced; - buf = SDATA (object); + buf = SDATA (coding->dst_object); } -#ifdef VMS - vs = get_vms_process_pointer (p->pid); - if (vs == 0) - error ("Could not find this process: %x", p->pid); - else if (write_to_vms_process (vs, buf, len)) - ; -#else /* not VMS */ - if (pty_max_bytes == 0) { #if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON) @@ -5675,119 +5775,27 @@ send_process (proc, buf, len, object) this -= rv; } - /* If we sent just part of the string, put in an EOF + /* If we sent just part of the string, put in an EOF (C-d) to force it through, before we send the rest. */ if (len > 0) Fprocess_send_eof (proc); } } -#endif /* not VMS */ else { signal (SIGPIPE, old_sigpipe); -#ifndef VMS proc = process_sent_to; p = XPROCESS (proc); -#endif p->raw_status_new = 0; p->status = Fcons (Qexit, Fcons (make_number (256), Qnil)); p->tick = ++process_tick; deactivate_process (proc); -#ifdef VMS - error ("Error writing to process %s; closed it", SDATA (p->name)); -#else error ("SIGPIPE raised on process %s; closed it", SDATA (p->name)); -#endif } UNGCPRO; } -static Lisp_Object -send_process_object_unwind (buf) - Lisp_Object buf; -{ - Lisp_Object tembuf; - - if (XBUFFER (buf) == current_buffer) - return Qnil; - tembuf = Fcurrent_buffer (); - Fset_buffer (buf); - Fkill_buffer (tembuf); - return Qnil; -} - -/* Send current contents of region between START and END to PROC. - If START is a string, send it instead. - This function can evaluate Lisp code and can garbage collect. */ - -static void -send_process_object (proc, start, end) - Lisp_Object proc, start, end; -{ - int count = SPECPDL_INDEX (); - Lisp_Object object = STRINGP (start) ? start : Fcurrent_buffer (); - struct buffer *given_buffer = current_buffer; - unsigned char *buf; - int len; - - record_unwind_protect (send_process_object_unwind, Fcurrent_buffer ()); - - if (STRINGP (object) ? STRING_MULTIBYTE (object) - : ! NILP (XBUFFER (object)->enable_multibyte_characters)) - { - struct Lisp_Process *p = XPROCESS (proc); - struct coding_system *coding; - - if (p->raw_status_new) - update_status (p); - if (! EQ (p->status, Qrun)) - error ("Process %s not running", SDATA (p->name)); - if (p->outfd < 0) - error ("Output file descriptor of %s is closed", SDATA (p->name)); - - coding = proc_encode_coding_system[p->outfd]; - if (! EQ (coding->symbol, p->encode_coding_system)) - /* The coding system for encoding was changed to raw-text - because we sent a unibyte text previously. Now we are - sending a multibyte text, thus we must encode it by the - original coding system specified for the current process. */ - setup_coding_system (p->encode_coding_system, coding); - if (! NILP (coding->pre_write_conversion)) - { - struct gcpro gcpro1, gcpro2; - - GCPRO2 (proc, object); - call2 (coding->pre_write_conversion, start, end); - UNGCPRO; - if (given_buffer != current_buffer) - { - start = make_number (BEGV), end = make_number (ZV); - object = Fcurrent_buffer (); - } - } - } - - if (BUFFERP (object)) - { - EMACS_INT start_byte; - - if (XINT (start) < GPT && XINT (end) > GPT) - move_gap (XINT (end)); - start_byte = CHAR_TO_BYTE (XINT (start)); - buf = BYTE_POS_ADDR (start_byte); - len = CHAR_TO_BYTE (XINT (end)) - start_byte; - } - else - { - buf = SDATA (object); - len = SBYTES (object); - } - send_process (proc, buf, len, object); - - unbind_to (count, Qnil); -} - DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region, 3, 3, 0, doc: /* Send current contents of region as input to PROCESS. @@ -5801,10 +5809,19 @@ Output from processes can arrive in between bunches. */) Lisp_Object process, start, end; { Lisp_Object proc; + int start1, end1; proc = get_process (process); validate_region (&start, &end); - send_process_object (proc, start, end); + + if (XINT (start) < GPT && XINT (end) > GPT) + move_gap (XINT (start)); + + start1 = CHAR_TO_BYTE (XINT (start)); + end1 = CHAR_TO_BYTE (XINT (end)); + send_process (proc, BYTE_POS_ADDR (start1), end1 - start1, + Fcurrent_buffer ()); + return Qnil; } @@ -5822,7 +5839,8 @@ Output from processes can arrive in between bunches. */) Lisp_Object proc; CHECK_STRING (string); proc = get_process (process); - send_process_object (proc, string, Qnil); + send_process (proc, SDATA (string), + SBYTES (string), string); return Qnil; } @@ -5840,7 +5858,7 @@ emacs_get_tty_pgrp (p) int fd; /* Some OS:es (Solaris 8/9) does not allow TIOCGPGRP from the master side. Try the slave side. */ - fd = emacs_open (XSTRING (p->tty_name)->data, O_RDONLY, 0); + fd = emacs_open (SDATA (p->tty_name), O_RDONLY, 0); if (fd != -1) { @@ -5870,7 +5888,7 @@ return t unconditionally. */) proc = get_process (process); p = XPROCESS (proc); - if (!EQ (p->childp, Qt)) + if (!EQ (p->type, Qreal)) error ("Process %s is not a subprocess", SDATA (p->name)); if (p->infd < 0) @@ -5913,7 +5931,7 @@ process_send_signal (process, signo, current_group, nomsg) proc = get_process (process); p = XPROCESS (proc); - if (!EQ (p->childp, Qt)) + if (!EQ (p->type, Qreal)) error ("Process %s is not a subprocess", SDATA (p->name)); if (p->infd < 0) @@ -6023,7 +6041,7 @@ process_send_signal (process, signo, current_group, nomsg) you'd better be using one of the alternatives above! */ #endif /* ! defined (TCGETA) */ #endif /* ! defined (TIOCGLTC) && defined (TIOCGETC) */ - /* In this case, the code above should alway returns. */ + /* In this case, the code above should alway return. */ abort (); #endif /* ! defined HAVE_TERMIOS */ @@ -6076,20 +6094,8 @@ process_send_signal (process, signo, current_group, nomsg) break; #endif /* ! defined (SIGCONT) */ case SIGINT: -#ifdef VMS - send_process (proc, "\003", 1, Qnil); /* ^C */ - goto whoosh; -#endif case SIGQUIT: -#ifdef VMS - send_process (proc, "\031", 1, Qnil); /* ^Y */ - goto whoosh; -#endif case SIGKILL: -#ifdef VMS - sys$forcex (&(p->pid), 0, 1); - whoosh: -#endif flush_pending_output (p->infd); break; } @@ -6162,12 +6168,13 @@ See function `interrupt-process' for more details on usage. */) DEFUN ("stop-process", Fstop_process, Sstop_process, 0, 2, 0, doc: /* Stop process PROCESS. May be process or name of one. See function `interrupt-process' for more details on usage. -If PROCESS is a network process, inhibit handling of incoming traffic. */) +If PROCESS is a network or serial process, inhibit handling of incoming +traffic. */) (process, current_group) Lisp_Object process, current_group; { #ifdef HAVE_SOCKETS - if (PROCESSP (process) && NETCONN_P (process)) + if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process))) { struct Lisp_Process *p; @@ -6193,12 +6200,13 @@ If PROCESS is a network process, inhibit handling of incoming traffic. */) DEFUN ("continue-process", Fcontinue_process, Scontinue_process, 0, 2, 0, doc: /* Continue process PROCESS. May be process or name of one. See function `interrupt-process' for more details on usage. -If PROCESS is a network process, resume handling of incoming traffic. */) +If PROCESS is a network or serial process, resume handling of incoming +traffic. */) (process, current_group) Lisp_Object process, current_group; { #ifdef HAVE_SOCKETS - if (PROCESSP (process) && NETCONN_P (process)) + if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process))) { struct Lisp_Process *p; @@ -6209,6 +6217,13 @@ If PROCESS is a network process, resume handling of incoming traffic. */) { FD_SET (p->infd, &input_wait_mask); FD_SET (p->infd, &non_keyboard_wait_mask); +#ifdef WINDOWSNT + if (fd_info[ p->infd ].flags & FILE_SERIAL) + PurgeComm (fd_info[ p->infd ].hnd, PURGE_RXABORT | PURGE_RXCLEAR); +#endif +#ifdef HAVE_TERMIOS + tcflush (p->infd, TCIFLUSH); +#endif } p->command = Qnil; return process; @@ -6271,7 +6286,7 @@ SIGCODE may be an integer, or a symbol whose name is a signal name. */) got_it: #define parse_signal(NAME, VALUE) \ - else if (!xstricmp (name, NAME)) \ + else if (!xstrcasecmp (name, NAME)) \ XSETINT (sigcode, VALUE) if (INTEGERP (sigcode)) @@ -6394,7 +6409,9 @@ PROCESS may be a process, a buffer, the name of a process or buffer, or nil, indicating the current buffer's process. If PROCESS is a network connection, or is a process communicating through a pipe (as opposed to a pty), then you cannot send any more -text to PROCESS after you call this function. */) +text to PROCESS after you call this function. +If PROCESS is a serial process, wait until all output written to the +process has been transmitted to the serial port. */) (process) Lisp_Object process; { @@ -6419,11 +6436,16 @@ text to PROCESS after you call this function. */) send_process (proc, "", 0, Qnil); } -#ifdef VMS - send_process (proc, "\032", 1, Qnil); /* ^z */ -#else if (XPROCESS (proc)->pty_flag) send_process (proc, "\004", 1, Qnil); + else if (EQ (XPROCESS (proc)->type, Qserial)) + { +#ifdef HAVE_TERMIOS + if (tcdrain (XPROCESS (proc)->outfd) != 0) + error ("tcdrain() failed: %s", emacs_strerror (errno)); +#endif + /* Do nothing on Windows because writes are blocking. */ + } else { int old_outfd, new_outfd; @@ -6433,7 +6455,7 @@ text to PROCESS after you call this function. */) for communication with the subprocess, call shutdown to cause EOF. (In some old system, shutdown to socketpair doesn't work. Then we just can't win.) */ - if (XPROCESS (proc)->pid == 0 + if (EQ (XPROCESS (proc)->type, Qnetwork) || XPROCESS (proc)->outfd == XPROCESS (proc)->infd) shutdown (XPROCESS (proc)->outfd, 1); /* In case of socketpair, outfd == infd, so don't close it. */ @@ -6458,7 +6480,6 @@ text to PROCESS after you call this function. */) XPROCESS (proc)->outfd = new_outfd; } -#endif /* VMS */ return process; } @@ -6471,13 +6492,13 @@ kill_buffer_processes (buffer) { Lisp_Object tail, proc; - for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCDR (tail)) + for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) { proc = XCDR (XCAR (tail)); - if (GC_PROCESSP (proc) + if (PROCESSP (proc) && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer))) { - if (NETCONN_P (proc)) + if (NETCONN_P (proc) || SERIALCONN_P (proc)) Fdelete_process (proc); else if (XPROCESS (proc)->infd >= 0) process_send_signal (proc, SIGHUP, Qnil, 1); @@ -6522,15 +6543,10 @@ sigchld_handler (signo) SIGNAL_THREAD_CHECK (signo); -#ifdef BSD4_1 - extern int sigheld; - sigheld |= sigbit (SIGCHLD); -#endif - while (1) { pid_t pid; - WAITTYPE w; + int w; Lisp_Object tail; #ifdef WNOHANG @@ -6554,10 +6570,6 @@ sigchld_handler (signo) must reestablish each time */ #if defined (USG) && !defined (POSIX_SIGNALS) signal (signo, sigchld_handler); /* WARNING - must come after wait3() */ -#endif -#ifdef BSD4_1 - sigheld &= ~sigbit (SIGCHLD); - sigrelse (SIGCHLD); #endif errno = old_errno; return; @@ -6569,11 +6581,11 @@ sigchld_handler (signo) /* Find the process that signaled us, and record its status. */ /* The process can have been deleted by Fdelete_process. */ - for (tail = deleted_pid_list; GC_CONSP (tail); tail = XCDR (tail)) + for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) { Lisp_Object xpid = XCAR (tail); - if ((GC_INTEGERP (xpid) && pid == (pid_t) XINT (xpid)) - || (GC_FLOATP (xpid) && pid == (pid_t) XFLOAT_DATA (xpid))) + if ((INTEGERP (xpid) && pid == (pid_t) XINT (xpid)) + || (FLOATP (xpid) && pid == (pid_t) XFLOAT_DATA (xpid))) { XSETCAR (tail, Qnil); goto sigchld_end_of_loop; @@ -6582,11 +6594,11 @@ sigchld_handler (signo) /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */ p = 0; - for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCDR (tail)) + for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) { proc = XCDR (XCAR (tail)); p = XPROCESS (proc); - if (GC_EQ (p->childp, Qt) && p->pid == pid) + if (EQ (p->type, Qreal) && p->pid == pid) break; p = 0; } @@ -6594,7 +6606,7 @@ sigchld_handler (signo) /* Look for an asynchronous process whose pid hasn't been filled in yet. */ if (p == 0) - for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCDR (tail)) + for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) { proc = XCDR (XCAR (tail)); p = XPROCESS (proc); @@ -6606,12 +6618,10 @@ sigchld_handler (signo) /* Change the status of the process that was found. */ if (p != 0) { - union { int i; WAITTYPE wt; } u; int clear_desc_flag = 0; p->tick = ++process_tick; - u.wt = w; - p->raw_status = u.i; + p->raw_status = w; p->raw_status_new = 1; /* If process has terminated, stop waiting for its output. */ @@ -6808,7 +6818,8 @@ status_notify (deleting_process) while (! EQ (p->filter, Qt) && ! EQ (p->status, Qconnect) && ! EQ (p->status, Qlisten) - && ! EQ (p->command, Qt) /* Network process not stopped. */ + /* Network or serial process not stopped: */ + && ! EQ (p->command, Qt) && p->infd >= 0 && p != deleting_process && read_process_output (proc, p->infd) > 0); @@ -6917,7 +6928,7 @@ encode subprocess input. */) error ("Output file descriptor of %s closed", SDATA (p->name)); Fcheck_coding_system (decoding); Fcheck_coding_system (encoding); - + encoding = coding_inherit_eol_type (encoding, Qnil); p->decode_coding_system = decoding; p->encode_coding_system = encoding; setup_process_coding_systems (process); @@ -6950,7 +6961,8 @@ suppressed. */) CHECK_PROCESS (process); p = XPROCESS (process); - p->filter_multibyte = !NILP (flag); + if (NILP (flag)) + p->decode_coding_system = raw_text_coding_system (p->decode_coding_system); setup_process_coding_systems (process); return Qnil; @@ -6963,11 +6975,12 @@ DEFUN ("process-filter-multibyte-p", Fprocess_filter_multibyte_p, Lisp_Object process; { register struct Lisp_Process *p; + struct coding_system *coding; CHECK_PROCESS (process); p = XPROCESS (process); - - return (p->filter_multibyte ? Qt : Qnil); + coding = proc_decode_coding_system[p->infd]; + return (CODING_FOR_UNIBYTE (coding) ? Qnil : Qt); } @@ -7054,6 +7067,500 @@ keyboard_bit_set (mask) return 0; } +/* Enumeration of and access to system processes a-la ps(1). */ + +#if HAVE_PROCFS + +/* Process enumeration and access via /proc. */ + +static Lisp_Object +procfs_list_system_processes () +{ + Lisp_Object procdir, match, proclist, next; + struct gcpro gcpro1, gcpro2; + register Lisp_Object tail; + + GCPRO2 (procdir, match); + /* For every process on the system, there's a directory in the + "/proc" pseudo-directory whose name is the numeric ID of that + process. */ + procdir = build_string ("/proc"); + match = build_string ("[0-9]+"); + proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil); + + /* `proclist' gives process IDs as strings. Destructively convert + each string into a number. */ + for (tail = proclist; CONSP (tail); tail = next) + { + next = XCDR (tail); + XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil)); + } + UNGCPRO; + + /* directory_files_internal returns the files in reverse order; undo + that. */ + proclist = Fnreverse (proclist); + return proclist; +} + +static void +time_from_jiffies (unsigned long long tval, long hz, + time_t *sec, unsigned *usec) +{ + unsigned long long ullsec; + + *sec = tval / hz; + ullsec = *sec; + tval -= ullsec * hz; + /* Careful: if HZ > 1 million, then integer division by it yields zero. */ + if (hz <= 1000000) + *usec = tval * 1000000 / hz; + else + *usec = tval / (hz / 1000000); +} + +static Lisp_Object +ltime_from_jiffies (unsigned long long tval, long hz) +{ + time_t sec; + unsigned usec; + + time_from_jiffies (tval, hz, &sec, &usec); + + return list3 (make_number ((sec >> 16) & 0xffff), + make_number (sec & 0xffff), + make_number (usec)); +} + +static void +get_up_time (time_t *sec, unsigned *usec) +{ + FILE *fup; + + *sec = *usec = 0; + + BLOCK_INPUT; + fup = fopen ("/proc/uptime", "r"); + + if (fup) + { + double uptime, idletime; + + /* The numbers in /proc/uptime use C-locale decimal point, but + we already set ourselves to the C locale (see `fixup_locale' + in emacs.c). */ + if (2 <= fscanf (fup, "%lf %lf", &uptime, &idletime)) + { + *sec = uptime; + *usec = (uptime - *sec) * 1000000; + } + fclose (fup); + } + UNBLOCK_INPUT; +} + +#define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff) +#define MINOR(d) (((unsigned)(d) & 0xff) | (((unsigned)(d) & 0xfff00000) >> 12)) + +static Lisp_Object +procfs_ttyname (rdev) +{ + FILE *fdev = NULL; + char name[PATH_MAX]; + + BLOCK_INPUT; + fdev = fopen ("/proc/tty/drivers", "r"); + + if (fdev) + { + unsigned major; + unsigned long minor_beg, minor_end; + char minor[25]; /* 2 32-bit numbers + dash */ + char *endp; + + while (!feof (fdev) && !ferror (fdev)) + { + if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) + && major == MAJOR (rdev)) + { + minor_beg = strtoul (minor, &endp, 0); + if (*endp == '\0') + minor_end = minor_beg; + else if (*endp == '-') + minor_end = strtoul (endp + 1, &endp, 0); + else + continue; + + if (MINOR (rdev) >= minor_beg && MINOR (rdev) <= minor_end) + { + sprintf (name + strlen (name), "%lu", MINOR (rdev)); + break; + } + } + } + fclose (fdev); + } + UNBLOCK_INPUT; + return build_string (name); +} + +static unsigned long +procfs_get_total_memory (void) +{ + FILE *fmem = NULL; + unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */ + + BLOCK_INPUT; + fmem = fopen ("/proc/meminfo", "r"); + + if (fmem) + { + unsigned long entry_value; + char entry_name[20]; /* the longest I saw is 13+1 */ + + while (!feof (fmem) && !ferror (fmem)) + { + if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value) + && strcmp (entry_name, "MemTotal:") == 0) + { + retval = entry_value; + break; + } + } + fclose (fmem); + } + UNBLOCK_INPUT; + return retval; +} + +static Lisp_Object +procfs_system_process_attributes (pid) + Lisp_Object pid; +{ + char procfn[PATH_MAX], fn[PATH_MAX]; + struct stat st; + struct passwd *pw; + struct group *gr; + long clocks_per_sec; + char *procfn_end; + char procbuf[1025], *p, *q; + int fd; + ssize_t nread; + const char *cmd = NULL; + char *cmdline = NULL; + size_t cmdsize = 0, cmdline_size; + unsigned char c; + int proc_id, ppid, uid, gid, pgrp, sess, tty, tpgid, thcount; + unsigned long long utime, stime, cutime, cstime, start; + long priority, nice, rss; + unsigned long minflt, majflt, cminflt, cmajflt, vsize; + time_t sec; + unsigned usec; + EMACS_TIME tnow, tstart, tboot, telapsed,ttotal; + double pcpu, pmem; + Lisp_Object attrs = Qnil; + Lisp_Object cmd_str, decoded_cmd, tem; + struct gcpro gcpro1, gcpro2; + EMACS_INT uid_eint, gid_eint; + + CHECK_NUMBER_OR_FLOAT (pid); + proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid); + sprintf (procfn, "/proc/%lu", proc_id); + if (stat (procfn, &st) < 0) + return attrs; + + GCPRO2 (attrs, decoded_cmd); + + /* euid egid */ + uid = st.st_uid; + /* Use of EMACS_INT stops GCC whining about limited range of data type. */ + uid_eint = uid; + attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid_eint)), attrs); + BLOCK_INPUT; + pw = getpwuid (uid); + UNBLOCK_INPUT; + if (pw) + attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs); + + gid = st.st_gid; + gid_eint = gid; + attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid_eint)), attrs); + BLOCK_INPUT; + gr = getgrgid (gid); + UNBLOCK_INPUT; + if (gr) + attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); + + strcpy (fn, procfn); + procfn_end = fn + strlen (fn); + strcpy (procfn_end, "/stat"); + fd = emacs_open (fn, O_RDONLY, 0); + if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof(procbuf) - 1)) > 0) + { + procbuf[nread] = '\0'; + p = procbuf; + + p = strchr (p, '('); + if (p != NULL) + { + q = strrchr (p + 1, ')'); + /* comm */ + if (q != NULL) + { + cmd = p + 1; + cmdsize = q - cmd; + } + } + else + q = NULL; + if (cmd == NULL) + { + cmd = "???"; + cmdsize = 3; + } + /* Command name is encoded in locale-coding-system; decode it. */ + cmd_str = make_unibyte_string (cmd, cmdsize); + decoded_cmd = code_convert_string_norecord (cmd_str, + Vlocale_coding_system, 0); + attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); + + if (q) + { + EMACS_INT ppid_eint, pgrp_eint, sess_eint, tpgid_eint, thcount_eint; + p = q + 2; + /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt utime stime cutime cstime priority nice thcount . start vsize rss */ + sscanf (p, "%c %d %d %d %d %d %*u %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld", + &c, &ppid, &pgrp, &sess, &tty, &tpgid, + &minflt, &cminflt, &majflt, &cmajflt, + &utime, &stime, &cutime, &cstime, + &priority, &nice, &thcount, &start, &vsize, &rss); + { + char state_str[2]; + + state_str[0] = c; + state_str[1] = '\0'; + tem = build_string (state_str); + attrs = Fcons (Fcons (Qstate, tem), attrs); + } + /* Stops GCC whining about limited range of data type. */ + ppid_eint = ppid; + pgrp_eint = pgrp; + sess_eint = sess; + tpgid_eint = tpgid; + thcount_eint = thcount; + attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid_eint)), attrs); + attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp_eint)), attrs); + attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess_eint)), attrs); + attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs); + attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid_eint)), attrs); + attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (minflt)), attrs); + attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (majflt)), attrs); + attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), attrs); + attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), attrs); + clocks_per_sec = sysconf (_SC_CLK_TCK); + if (clocks_per_sec < 0) + clocks_per_sec = 100; + attrs = Fcons (Fcons (Qutime, + ltime_from_jiffies (utime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qstime, + ltime_from_jiffies (stime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qcutime, + ltime_from_jiffies (cutime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qcstime, + ltime_from_jiffies (cstime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qpri, make_number (priority)), attrs); + attrs = Fcons (Fcons (Qnice, make_number (nice)), attrs); + attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs); + EMACS_GET_TIME (tnow); + get_up_time (&sec, &usec); + EMACS_SET_SECS (telapsed, sec); + EMACS_SET_USECS (telapsed, usec); + EMACS_SUB_TIME (tboot, tnow, telapsed); + time_from_jiffies (start, clocks_per_sec, &sec, &usec); + EMACS_SET_SECS (tstart, sec); + EMACS_SET_USECS (tstart, usec); + EMACS_ADD_TIME (tstart, tboot, tstart); + attrs = Fcons (Fcons (Qstart, + list3 (make_number + ((EMACS_SECS (tstart) >> 16) & 0xffff), + make_number + (EMACS_SECS (tstart) & 0xffff), + make_number + (EMACS_USECS (tstart)))), + attrs); + attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs); + attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs); + EMACS_SUB_TIME (telapsed, tnow, tstart); + attrs = Fcons (Fcons (Qetime, + list3 (make_number + ((EMACS_SECS (telapsed) >> 16) & 0xffff), + make_number + (EMACS_SECS (telapsed) & 0xffff), + make_number + (EMACS_USECS (telapsed)))), + attrs); + time_from_jiffies (utime + stime, clocks_per_sec, &sec, &usec); + pcpu = (sec + usec / 1000000.0) / (EMACS_SECS (telapsed) + EMACS_USECS (telapsed) / 1000000.0); + if (pcpu > 1.0) + pcpu = 1.0; + attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); + pmem = 4.0 * 100 * rss / procfs_get_total_memory (); + if (pmem > 100) + pmem = 100; + attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs); + } + } + if (fd >= 0) + emacs_close (fd); + + /* args */ + strcpy (procfn_end, "/cmdline"); + fd = emacs_open (fn, O_RDONLY, 0); + if (fd >= 0) + { + for (cmdline_size = 0; emacs_read (fd, &c, 1) == 1; cmdline_size++) + { + if (isspace (c) || c == '\\') + cmdline_size++; /* for later quoting, see below */ + } + if (cmdline_size) + { + cmdline = xmalloc (cmdline_size + 1); + lseek (fd, 0L, SEEK_SET); + cmdline[0] = '\0'; + if ((nread = read (fd, cmdline, cmdline_size)) >= 0) + cmdline[nread++] = '\0'; + else + { + /* Assigning zero to `nread' makes us skip the following + two loops, assign zero to cmdline_size, and enter the + following `if' clause that handles unknown command + lines. */ + nread = 0; + } + /* We don't want trailing null characters. */ + for (p = cmdline + nread - 1; p > cmdline && !*p; p--) + nread--; + for (p = cmdline; p < cmdline + nread; p++) + { + /* Escape-quote whitespace and backslashes. */ + if (isspace (*p) || *p == '\\') + { + memmove (p + 1, p, nread - (p - cmdline)); + nread++; + *p++ = '\\'; + } + else if (*p == '\0') + *p = ' '; + } + cmdline_size = nread; + } + if (!cmdline_size) + { + if (!cmd) + cmd = "???"; + if (!cmdsize) + cmdsize = strlen (cmd); + cmdline_size = cmdsize + 2; + cmdline = xmalloc (cmdline_size + 1); + strcpy (cmdline, "["); + strcat (strncat (cmdline, cmd, cmdsize), "]"); + } + emacs_close (fd); + /* Command line is encoded in locale-coding-system; decode it. */ + cmd_str = make_unibyte_string (cmdline, cmdline_size); + decoded_cmd = code_convert_string_norecord (cmd_str, + Vlocale_coding_system, 0); + xfree (cmdline); + attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); + } + + UNGCPRO; + return attrs; +} + +#endif /* !HAVE_PROCFS */ + +DEFUN ("list-system-processes", Flist_system_processes, Slist_system_processes, + 0, 0, 0, + doc: /* Return a list of numerical process IDs of all running processes. +If this functionality is unsupported, return nil. + +See `system-process-attributes' for getting attributes of a process +given its ID. */) + () +{ +#ifdef LISTPROC + return LISTPROC (); +#else + return Qnil; +#endif +} + +DEFUN ("system-process-attributes", Fsystem_process_attributes, + Ssystem_process_attributeses, 1, 1, 0, + doc: /* Return attributes of the process given by its PID, a number. + +Value is an alist where each element is a cons cell of the form + + \(KEY . VALUE) + +If this functionality is unsupported, the value is nil. + +See `list-system-processes' for getting a list of all process IDs. + +The KEYs of the attributes that this function may return are listed +below, together with the type of the associated VALUE (in parentheses). +Not all platforms support all of these attributes; unsupported +attributes will not appear in the returned alist. +Unless explicitly indicated otherwise, numbers can have either +integer or floating point values. + + euid -- Effective user User ID of the process (number) + user -- User name corresponding to euid (string) + egid -- Effective user Group ID of the process (number) + group -- Group name corresponding to egid (string) + comm -- Command name (executable name only) (string) + state -- Process state code, such as "S", "R", or "T" (string) + ppid -- Parent process ID (number) + pgrp -- Process group ID (number) + sess -- Session ID, i.e. process ID of session leader (number) + ttname -- Controlling tty name (string) + tpgid -- ID of foreground process group on the process's tty (number) + minflt -- number of minor page faults (number) + majflt -- number of major page faults (number) + cminflt -- cumulative number of minor page faults (number) + cmajflt -- cumulative number of major page faults (number) + utime -- user time used by the process, in the (HIGH LOW USEC) format + stime -- system time used by the process, in the (HIGH LOW USEC) format + cutime -- user time used by the process and its children, (HIGH LOW USEC) + cstime -- system time used by the process and its children, (HIGH LOW USEC) + pri -- priority of the process (number) + nice -- nice value of the process (number) + thcount -- process thread count (number) + start -- time the process started, in the (HIGH LOW USEC) format + vsize -- virtual memory size of the process in KB's (number) + rss -- resident set size of the process in KB's (number) + etime -- elapsed time the process is running, in (HIGH LOW USEC) format + pcpu -- percents of CPU time used by the process (floating-point number) + pmem -- percents of total physical memory used by process's resident set + (floating-point number) + args -- command line which invoked the process (string). */) + (pid) + + Lisp_Object pid; +{ +#ifdef PROCATTR + return PROCATTR (pid); +#else + return Qnil; +#endif +} + void init_process () { @@ -7129,7 +7636,7 @@ init_process () #ifdef HAVE_GETSOCKNAME ADD_SUBFEATURE (QCservice, Qt); #endif -#if !defined(TERM) && (defined(O_NONBLOCK) || defined(O_NDELAY)) +#if defined(O_NONBLOCK) || defined(O_NDELAY) ADD_SUBFEATURE (QCserver, Qt); #endif @@ -7140,7 +7647,7 @@ init_process () } #endif /* HAVE_SOCKETS */ -#if defined (DARWIN) || defined (MAC_OSX) +#if defined (DARWIN_OS) /* PTYs are broken on Darwin < 6, but are sometimes useful for interactive processes. As such, we only change the default value. */ if (initialized) @@ -7193,6 +7700,39 @@ syms_of_process () Qdatagram = intern ("datagram"); staticpro (&Qdatagram); + QCport = intern (":port"); + staticpro (&QCport); + QCspeed = intern (":speed"); + staticpro (&QCspeed); + QCprocess = intern (":process"); + staticpro (&QCprocess); + + QCbytesize = intern (":bytesize"); + staticpro (&QCbytesize); + QCstopbits = intern (":stopbits"); + staticpro (&QCstopbits); + QCparity = intern (":parity"); + staticpro (&QCparity); + Qodd = intern ("odd"); + staticpro (&Qodd); + Qeven = intern ("even"); + staticpro (&Qeven); + QCflowcontrol = intern (":flowcontrol"); + staticpro (&QCflowcontrol); + Qhw = intern ("hw"); + staticpro (&Qhw); + Qsw = intern ("sw"); + staticpro (&Qsw); + QCsummary = intern (":summary"); + staticpro (&QCsummary); + + Qreal = intern ("real"); + staticpro (&Qreal); + Qnetwork = intern ("network"); + staticpro (&Qnetwork); + Qserial = intern ("serial"); + staticpro (&Qserial); + QCname = intern (":name"); staticpro (&QCname); QCbuffer = intern (":buffer"); @@ -7225,8 +7765,6 @@ syms_of_process () staticpro (&QCoptions); QCplist = intern (":plist"); staticpro (&QCplist); - QCfilter_multibyte = intern (":filter-multibyte"); - staticpro (&QCfilter_multibyte); Qlast_nonmenu_event = intern ("last-nonmenu-event"); staticpro (&Qlast_nonmenu_event); @@ -7236,6 +7774,65 @@ syms_of_process () staticpro (&deleted_pid_list); #endif + Qeuid = intern ("euid"); + staticpro (&Qeuid); + Qegid = intern ("egid"); + staticpro (&Qegid); + Quser = intern ("user"); + staticpro (&Quser); + Qgroup = intern ("group"); + staticpro (&Qgroup); + Qcomm = intern ("comm"); + staticpro (&Qcomm); + Qstate = intern ("state"); + staticpro (&Qstate); + Qppid = intern ("ppid"); + staticpro (&Qppid); + Qpgrp = intern ("pgrp"); + staticpro (&Qpgrp); + Qsess = intern ("sess"); + staticpro (&Qsess); + Qttname = intern ("ttname"); + staticpro (&Qttname); + Qtpgid = intern ("tpgid"); + staticpro (&Qtpgid); + Qminflt = intern ("minflt"); + staticpro (&Qminflt); + Qmajflt = intern ("majflt"); + staticpro (&Qmajflt); + Qcminflt = intern ("cminflt"); + staticpro (&Qcminflt); + Qcmajflt = intern ("cmajflt"); + staticpro (&Qcmajflt); + Qutime = intern ("utime"); + staticpro (&Qutime); + Qstime = intern ("stime"); + staticpro (&Qstime); + Qcutime = intern ("cutime"); + staticpro (&Qcutime); + Qcstime = intern ("cstime"); + staticpro (&Qcstime); + Qpri = intern ("pri"); + staticpro (&Qpri); + Qnice = intern ("nice"); + staticpro (&Qnice); + Qthcount = intern ("thcount"); + staticpro (&Qthcount); + Qstart = intern ("start"); + staticpro (&Qstart); + Qvsize = intern ("vsize"); + staticpro (&Qvsize); + Qrss = intern ("rss"); + staticpro (&Qrss); + Qetime = intern ("etime"); + staticpro (&Qetime); + Qpcpu = intern ("pcpu"); + staticpro (&Qpcpu); + Qpmem = intern ("pmem"); + staticpro (&Qpmem); + Qargs = intern ("args"); + staticpro (&Qargs); + DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes, doc: /* *Non-nil means delete processes immediately when they exit. A value of nil means don't delete them until `list-processes' is run. */); @@ -7292,6 +7889,10 @@ The variable takes effect when `start-process' is called. */); defsubr (&Slist_processes); defsubr (&Sprocess_list); defsubr (&Sstart_process); +#ifdef HAVE_SERIAL + defsubr (&Sserial_process_configure); + defsubr (&Smake_serial_process); +#endif /* HAVE_SERIAL */ #ifdef HAVE_SOCKETS defsubr (&Sset_network_process_option); defsubr (&Smake_network_process); @@ -7321,11 +7922,13 @@ The variable takes effect when `start-process' is called. */); defsubr (&Sprocess_send_eof); defsubr (&Ssignal_process); defsubr (&Swaiting_for_user_input_p); -/* defsubr (&Sprocess_connection); */ + defsubr (&Sprocess_type); defsubr (&Sset_process_coding_system); defsubr (&Sprocess_coding_system); defsubr (&Sset_process_filter_multibyte); defsubr (&Sprocess_filter_multibyte_p); + defsubr (&Slist_system_processes); + defsubr (&Ssystem_process_attributeses); } @@ -7333,10 +7936,16 @@ The variable takes effect when `start-process' is called. */); #include #include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif #include "lisp.h" #include "systime.h" -#include "charset.h" +#include "character.h" #include "coding.h" #include "termopts.h" #include "sysselect.h" @@ -7346,7 +7955,7 @@ extern int frame_garbaged; extern EMACS_TIME timer_check (); extern int timers_run; -Lisp_Object QCtype; +Lisp_Object QCtype, QCname; /* As described above, except assuming that there are no subprocesses: @@ -7524,7 +8133,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, else error ("select error: %s", emacs_strerror (xerrno)); } -#ifdef sun +#ifdef SOLARIS2 else if (nfds > 0 && (waitchannels & 1) && interrupt_input) /* System sometimes fails to deliver SIGIO. */ kill (getpid (), SIGIO); @@ -7608,6 +8217,74 @@ kill_buffer_processes (buffer) { } +DEFUN ("list-system-processes", Flist_system_processes, Slist_system_processes, + 0, 0, 0, + doc: /* Return a list of numerical process IDs of all running processes. +If this functionality is unsupported, return nil. + +See `system-process-attributes' for getting attributes of a process +given its ID. */) + () +{ + return Qnil; +} + +DEFUN ("system-process-attributes", Fsystem_process_attributes, + Ssystem_process_attributeses, 1, 1, 0, + doc: /* Return attributes of the process given by its PID, a number. + +Value is an alist where each element is a cons cell of the form + + \(KEY . VALUE) + +If this functionality is unsupported, the value is nil. + +See `list-system-processes' for getting a list of all process IDs. + +The KEYs of the attributes that this function may return are listed +below, together with the type of the associated VALUE (in parentheses). +Not all platforms support all of these attributes; unsupported +attributes will not appear in the returned alist. +Unless explicitly indicated otherwise, numbers can have either +integer or floating point values. + + euid -- Effective user User ID of the process (number) + user -- User name corresponding to euid (string) + egid -- Effective user Group ID of the process (number) + group -- Group name corresponding to egid (string) + comm -- Command name (executable name only) (string) + state -- Process state code, such as "S", "R", or "T" (string) + ppid -- Parent process ID (number) + pgrp -- Process group ID (number) + sess -- Session ID, i.e. process ID of session leader (number) + ttname -- Controlling tty name (string) + tpgid -- ID of foreground process group on the process's tty (number) + minflt -- number of minor page faults (number) + majflt -- number of major page faults (number) + cminflt -- cumulative number of minor page faults (number) + cmajflt -- cumulative number of major page faults (number) + utime -- user time used by the process, in the (HIGH LOW USEC) format + stime -- system time used by the process, in the (HIGH LOW USEC) format + cutime -- user time used by the process and its children, (HIGH LOW USEC) + cstime -- system time used by the process and its children, (HIGH LOW USEC) + pri -- priority of the process (number) + nice -- nice value of the process (number) + thcount -- process thread count (number) + start -- time the process started, in the (HIGH LOW USEC) format + vsize -- virtual memory size of the process in KB's (number) + rss -- resident set size of the process in KB's (number) + etime -- elapsed time the process is running, in (HIGH LOW USEC) format + pcpu -- percents of CPU time used by the process (floating-point number) + pmem -- percents of total physical memory used by process's resident set + (floating-point number) + args -- command line which invoked the process (string). */) + (pid) + + Lisp_Object pid; +{ + return Qnil; +} + void init_process () { @@ -7618,9 +8295,13 @@ syms_of_process () { QCtype = intern (":type"); staticpro (&QCtype); + QCname = intern (":name"); + staticpro (&QCname); defsubr (&Sget_buffer_process); defsubr (&Sprocess_inherit_coding_system_flag); + defsubr (&Slist_system_processes); + defsubr (&Ssystem_process_attributeses); }