X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/a9989764a4d54bf58381d5c3902e575bdf314245..acf20901186d76a6d5db0008fba8d1afa48c5671:/src/process.c diff --git a/src/process.c b/src/process.c index e5546488aa..b3271d3a2e 100644 --- a/src/process.c +++ b/src/process.c @@ -1,14 +1,14 @@ /* Asynchronous subprocess control for GNU Emacs. Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, - 1996, 1998, 1999, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + 1996, 1998, 1999, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 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 @@ -43,26 +41,23 @@ Boston, MA 02110-1301, USA. */ #ifdef HAVE_INTTYPES_H #include #endif +#ifdef STDC_HEADERS +#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 +68,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 +75,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 +90,6 @@ Boston, MA 02110-1301, USA. */ #endif #endif -#ifdef IRIS -#include /* for "minor" */ -#endif /* not IRIS */ - #ifdef HAVE_SYS_WAIT #include #endif @@ -150,14 +123,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 +146,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, Qtime, Qctime; #ifdef HAVE_SOCKETS -#define NETCONN_P(p) (CONSP (XPROCESS (p)->childp)) -#define NETCONN1_P(p) (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 +179,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 +202,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 +248,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 +391,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 +406,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 +526,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 +547,6 @@ allocate_pty () # else fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0); # endif -# endif /* not IRIS */ } #endif /* no PTY_OPEN */ @@ -594,16 +557,16 @@ allocate_pty () #ifdef PTY_TTY_NAME_SPRINTF PTY_TTY_NAME_SPRINTF #else - sprintf (pty_name, "/dev/tty%c%x", c, i); + sprintf (pty_name, "/dev/tty%c%x", c, i); #endif /* no PTY_TTY_NAME_SPRINTF */ 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 +596,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; @@ -688,10 +652,7 @@ setup_process_coding_systems (process) = (struct coding_system *) xmalloc (sizeof (struct coding_system)); coding_system = p->decode_coding_system; if (! NILP (p->filter)) - { - if (!p->filter_multibyte) - coding_system = raw_text_coding_system (coding_system); - } + ; else if (BUFFERP (p->buffer)) { if (NILP (XBUFFER (p->buffer)->enable_multibyte_characters)) @@ -808,7 +769,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; @@ -885,7 +846,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; @@ -943,7 +904,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; { @@ -975,7 +937,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; @@ -1042,7 +1004,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); @@ -1050,7 +1013,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; @@ -1081,7 +1044,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; } @@ -1186,11 +1149,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; { @@ -1206,11 +1171,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); } @@ -1250,6 +1218,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, @@ -1349,7 +1330,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; @@ -1417,7 +1398,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; @@ -1435,14 +1416,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); @@ -1453,6 +1429,10 @@ list_processes_1 (query_only) else Fprinc (symbol, Qnil); } + else if (SERIALCONN1_P (p)) + { + write_string ("running", -1); + } else Fprinc (symbol, Qnil); @@ -1500,7 +1480,7 @@ list_processes_1 (query_only) insert_string (tembuf); } else if (NETCONN1_P (p)) - { + { /* For a local socket, there is no host name, so display service instead. */ Lisp_Object host = Fplist_get (p->childp, QChost); @@ -1516,7 +1496,23 @@ list_processes_1 (query_only) (DATAGRAM_CHAN_P (p->infd) ? "datagram" : "stream"), (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; @@ -1585,12 +1581,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 (); @@ -1614,9 +1605,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)); @@ -1640,11 +1634,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 @@ -1705,28 +1698,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. @@ -1778,7 +1749,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; @@ -1837,7 +1807,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; @@ -1847,6 +1816,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; @@ -1902,14 +1874,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); @@ -1927,7 +1891,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 */ @@ -1981,9 +1963,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 */ @@ -1992,7 +1971,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 */ @@ -2109,9 +2087,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? */ @@ -2127,10 +2102,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 */ @@ -2156,9 +2127,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 */ @@ -2166,7 +2134,6 @@ create_process (process, new_argv, current_dir) signal (SIGCHLD, sigchld); #endif #endif /* ordinary USG */ -#endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ @@ -2178,6 +2145,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 */ @@ -2231,6 +2201,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. @@ -2248,9 +2232,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 */ @@ -2262,7 +2243,6 @@ create_process (process, new_argv, current_dir) kill (getpid (), SIGCHLD); #endif #endif /* ordinary USG */ -#endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ @@ -2270,7 +2250,6 @@ create_process (process, new_argv, current_dir) if (pid < 0) report_file_error ("Doing vfork", Qnil); } -#endif /* not VMS */ #ifdef HAVE_SOCKETS @@ -2288,6 +2267,12 @@ conv_sockaddr_to_lisp (sa, len) unsigned char *cp; register struct Lisp_Vector *p; + /* Workaround for a bug in getsockname on BSD: Names bound to + sockets in the UNIX domain are inaccessible; getsockname returns + a zero length name. */ + if (len < OFFSETOF (struct sockaddr, sa_family) + sizeof (sa->sa_family)) + return build_string (""); + switch (sa->sa_family) { case AF_INET: @@ -2297,14 +2282,14 @@ conv_sockaddr_to_lisp (sa, len) address = Fmake_vector (make_number (len), Qnil); p = XVECTOR (address); p->contents[--len] = make_number (ntohs (sin->sin_port)); - cp = (unsigned char *)&sin->sin_addr; + cp = (unsigned char *) &sin->sin_addr; break; } #ifdef AF_INET6 case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; - uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr; + uint16_t *ip6 = (uint16_t *) &sin6->sin6_addr; len = sizeof (sin6->sin6_addr)/2 + 1; address = Fmake_vector (make_number (len), Qnil); p = XVECTOR (address); @@ -2325,11 +2310,11 @@ conv_sockaddr_to_lisp (sa, len) } #endif default: - len -= sizeof (sa->sa_family); + len -= OFFSETOF (struct sockaddr, sa_family) + sizeof (sa->sa_family); address = Fcons (make_number (sa->sa_family), Fmake_vector (make_number (len), Qnil)); p = XVECTOR (XCDR (address)); - cp = (unsigned char *) sa + sizeof (sa->sa_family); + cp = (unsigned char *) &sa->sa_family + sizeof (sa->sa_family); break; } @@ -2675,18 +2660,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 @@ -2916,7 +3190,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; @@ -2946,32 +3220,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; @@ -3095,7 +3343,7 @@ usage: (make-network-process &rest ARGS) */) #ifdef HAVE_GAI_STRERROR error ("%s/%s %s", SDATA (host), portstring, gai_strerror(ret)); #else - error ("%s/%s getaddrinfo error %d", SDATA (host), portstring, ret); + error ("%s/%s getaddrinfo error %d", SDATA (host), portstring, ret); #endif immediate_quit = 0; @@ -3153,9 +3401,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, @@ -3171,28 +3419,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; @@ -3238,7 +3464,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]); @@ -3404,8 +3630,6 @@ usage: (make-network-process &rest ARGS) */) report_file_error ("make client process failed", contact); } -#endif /* not TERM */ - inch = s; outch = s; @@ -3427,14 +3651,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; @@ -3847,19 +4068,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; @@ -3928,10 +4139,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. @@ -3947,6 +4159,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)) @@ -3960,19 +4184,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; } @@ -4089,7 +4300,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; } @@ -4149,6 +4360,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; @@ -4322,16 +4534,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) { @@ -4343,8 +4545,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. */ @@ -4386,13 +4593,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 (); @@ -4440,8 +4649,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 @@ -4449,15 +4661,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); @@ -4480,7 +4683,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, } /* Don't wait for output from a non-running process. Just - read whatever data has already been received. */ + read whatever data has already been received. */ if (wait_proc && wait_proc->raw_status_new) update_status (wait_proc); if (wait_proc @@ -4500,19 +4703,22 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, if (nread == 0) break; - if (0 < nread) - total_nread += nread; + if (0 < nread) + { + total_nread += nread; + got_some_input = 1; + } #ifdef EIO else if (nread == -1 && EIO == errno) - break; + break; #endif #ifdef EAGAIN else if (nread == -1 && EAGAIN == errno) - break; + break; #endif #ifdef EWOULDBLOCK else if (nread == -1 && EWOULDBLOCK == errno) - break; + break; #endif } if (total_nread > 0 && do_display) @@ -4606,8 +4812,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 @@ -4633,15 +4843,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 @@ -4667,19 +4868,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. */ @@ -4834,7 +5022,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 */ @@ -4862,7 +5050,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 @@ -4895,7 +5083,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display, #ifdef GNU_LINUX /* getsockopt(,,SO_ERROR,,) is said to hang on some systems. - So only use it on systems where it is known to work. */ + So only use it on systems where it is known to work. */ { int xlen = sizeof(xerrno); if (getsockopt(channel, SOL_SOCKET, SO_ERROR, &xerrno, &xlen)) @@ -4953,14 +5141,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; } @@ -5011,37 +5191,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. */ @@ -5098,7 +5247,6 @@ read_process_output (proc, channel) else nbytes = nbytes + 1; } -#endif /* not VMS */ p->decoding_carryover = 0; @@ -5191,11 +5339,6 @@ read_process_output (proc, channel) coding->carryover_bytes); p->decoding_carryover = coding->carryover_bytes; } - /* 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 (SBYTES (text) > 0) internal_condition_case_1 (read_process_output_call, Fcons (outstream, @@ -5226,9 +5369,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; } @@ -5351,9 +5491,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; } @@ -5375,10 +5512,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); } @@ -5409,10 +5542,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)) @@ -5493,14 +5622,6 @@ send_process (proc, buf, len, 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) @@ -5529,7 +5650,7 @@ send_process (proc, buf, len, object) if (p->pty_flag) { /* Starting this at zero is always correct when not the first - iteration because the previous iteration ended by sending C-d. + iteration because the previous iteration ended by sending C-d. It may not be correct for the first iteration if a partial line was sent in a separate send_process call. If that proves worth handling, we need to save linepos @@ -5656,29 +5777,22 @@ 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; @@ -5746,7 +5860,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) { @@ -5776,7 +5890,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) @@ -5819,7 +5933,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) @@ -5840,7 +5954,7 @@ process_send_signal (process, signo, current_group, nomsg) by sending an input character to it. */ /* TERMIOS is the latest and bestest, and seems most likely to - work. If the system has it, use it. */ + work. If the system has it, use it. */ #ifdef HAVE_TERMIOS struct termios t; cc_t *sig_char = NULL; @@ -5929,7 +6043,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 */ @@ -5982,20 +6096,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; } @@ -6068,12 +6170,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; @@ -6099,12 +6202,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; @@ -6115,6 +6219,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; @@ -6177,7 +6288,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)) @@ -6300,7 +6411,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; { @@ -6325,11 +6438,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; @@ -6339,7 +6457,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. */ @@ -6364,7 +6482,6 @@ text to PROCESS after you call this function. */) XPROCESS (proc)->outfd = new_outfd; } -#endif /* VMS */ return process; } @@ -6383,7 +6500,7 @@ kill_buffer_processes (buffer) 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); @@ -6428,15 +6545,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 @@ -6445,7 +6557,7 @@ sigchld_handler (signo) #endif /* no WUNTRACED */ /* Keep trying to get a status until we get a definitive result. */ do - { + { errno = 0; pid = wait3 (&w, WNOHANG | WUNTRACED, 0); } @@ -6460,10 +6572,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; @@ -6492,7 +6600,7 @@ sigchld_handler (signo) { proc = XCDR (XCAR (tail)); p = XPROCESS (proc); - if (EQ (p->childp, Qt) && p->pid == pid) + if (EQ (p->type, Qreal) && p->pid == pid) break; p = 0; } @@ -6512,12 +6620,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. */ @@ -6548,7 +6654,7 @@ sigchld_handler (signo) if (WIFEXITED (w)) synch_process_retcode = WRETCODE (w); else if (WIFSIGNALED (w)) - synch_process_termsig = WTERMSIG (w); + synch_process_termsig = WTERMSIG (w); /* Tell wait_reading_process_output that it needs to wake up and look around. */ @@ -6566,7 +6672,7 @@ sigchld_handler (signo) to use up all the processes that have something to tell us. */ #if (defined WINDOWSNT \ || (defined USG && !defined GNU_LINUX \ - && !(defined HPUX && defined WNOHANG))) + && !(defined HPUX && defined WNOHANG))) #if defined (USG) && ! defined (POSIX_SIGNALS) signal (signo, sigchld_handler); #endif @@ -6714,7 +6820,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); @@ -6856,7 +6963,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; @@ -6869,11 +6977,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); } @@ -6960,6 +7069,78 @@ keyboard_bit_set (mask) return 0; } +/* Enumeration of and access to system processes a-la ps(1). */ + +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 list_system_processes (); +} + +DEFUN ("system-process-attributes", Fsystem_process_attributes, + Ssystem_process_attributes, 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 + time -- sum of utime and stime, 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) + ctime -- sum of cutime and cstime, in the (HIGH LOW USEC) format + 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 system_process_attributes (pid); +} + void init_process () { @@ -7035,7 +7216,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 @@ -7046,7 +7227,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) @@ -7099,6 +7280,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"); @@ -7131,8 +7345,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); @@ -7142,6 +7354,69 @@ 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); + Qtime = intern ("time"); + staticpro (&Qtime); + Qcutime = intern ("cutime"); + staticpro (&Qcutime); + Qcstime = intern ("cstime"); + staticpro (&Qcstime); + Qctime = intern ("ctime"); + staticpro (&Qctime); + 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. */); @@ -7198,6 +7473,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); @@ -7227,11 +7506,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_attributes); } @@ -7239,6 +7520,12 @@ 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" @@ -7252,7 +7539,12 @@ extern int frame_garbaged; extern EMACS_TIME timer_check (); extern int timers_run; -Lisp_Object QCtype; +Lisp_Object QCtype, QCname; + +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, Qtime, Qctime; /* As described above, except assuming that there are no subprocesses: @@ -7430,7 +7722,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); @@ -7514,6 +7806,76 @@ 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 list_system_processes (); +} + +DEFUN ("system-process-attributes", Fsystem_process_attributes, + Ssystem_process_attributes, 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 + time -- sum of utime and stime, 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) + ctime -- sum of cutime and cstime, in the (HIGH LOW USEC) format + 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 system_process_attributes (pid); +} + void init_process () { @@ -7524,9 +7886,79 @@ syms_of_process () { QCtype = intern (":type"); staticpro (&QCtype); + QCname = intern (":name"); + staticpro (&QCname); + QCtype = intern (":type"); + staticpro (&QCtype); + QCname = intern (":name"); + staticpro (&QCname); + 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); + Qtime = intern ("time"); + staticpro (&Qtime); + Qcutime = intern ("cutime"); + staticpro (&Qcutime); + Qcstime = intern ("cstime"); + staticpro (&Qcstime); + Qctime = intern ("ctime"); + staticpro (&Qctime); + 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); defsubr (&Sget_buffer_process); defsubr (&Sprocess_inherit_coding_system_flag); + defsubr (&Slist_system_processes); + defsubr (&Ssystem_process_attributes); }