📄 process.c
字号:
/* Asynchronous subprocess control for GNU Emacs. Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.This file is part of GNU Emacs.GNU Emacs is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Emacs; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <signal.h>#include "config.h"#ifdef subprocesses/* The entire file is within this conditional */#include <stdio.h>#include <errno.h>#include <setjmp.h>#include <sys/types.h> /* some typedefs are used in sys/file.h */#include <sys/file.h>#include <sys/stat.h>#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */#include <sys/socket.h>#include <netdb.h>#include <netinet/in.h>#endif /* HAVE_SOCKETS */#if defined(BSD) || defined(STRIDE)#include <sys/ioctl.h>#if !defined (O_NDELAY) && defined (HAVE_PTYS)#include <fcntl.h>#endif /* HAVE_PTYS and no O_NDELAY */#endif /* BSD or STRIDE */#ifdef USG#include <termio.h>#include <fcntl.h>#endif /* USG */#ifdef NEED_BSDTTY#include <sys/bsdtty.h>#endif#ifdef HPUX#undef TIOCGPGRP#endif#ifdef IRIS#include <sys/sysmacros.h> /* for "minor" */#include <sys/time.h>#else#ifdef UNIPLUS#include <sys/time.h>#else /* not IRIS, not UNIPLUS */#ifdef HAVE_TIMEVAL/* _h_BSDTYPES is checked because on ISC unix, socket.h includes both time.h and sys/time.h, and the latter file is protected from repeated inclusion. */#if defined(USG) && !defined(AIX) && !defined(_h_BSDTYPES) && !defined(USG_SYS_TIME)#include <time.h>#else /* AIX or USG_SYS_TIME, or not USG */#include <sys/time.h>#endif /* AIX or USG_SYS_TIME, or not USG */#endif /* HAVE_TIMEVAL */#endif /* not UNIPLUS */#endif /* not IRIS */#if defined (HPUX) && defined (HAVE_PTYS)#include <sys/ptyio.h>#endif #ifdef AIX#include <sys/pty.h>#include <unistd.h>#endif /* AIX */#ifdef SYSV_PTYS#include <sys/tty.h>#include <sys/pty.h>#endif#undef NULL#include "lisp.h"#include "window.h"#include "buffer.h"#include "process.h"#include "termhooks.h"#include "termopts.h"#include "commands.h"Lisp_Object Qrun, Qstop, Qsignal, Qexit, Qopen, Qclosed;/* a process object is a network connection when its childp field is neither Qt nor Qnil but is instead a string (name of foreign host we are connected to + name of port we are connected to) */#ifdef HAVE_SOCKETS#define NETCONN_P(p) (XGCTYPE (XPROCESS (p)->childp) == Lisp_String)#else#define NETCONN_P(p) 0#endif /* HAVE_SOCKETS *//* Define SIGCHLD as an alias for SIGCLD. There are many conditionals testing SIGCHLD. */#if !defined (SIGCHLD) && defined (SIGCLD)#define SIGCHLD SIGCLD#endif /* SIGCLD *//* Define the structure that the wait system call stores. On many systems, there is a structure defined for this. But on vanilla-ish USG systems there is not. */#ifndef WAITTYPE#if !defined (BSD) && !defined (UNIPLUS) && !defined (STRIDE) && !(defined (HPUX) && !defined (NOMULTIPLEJOBS)) && !defined (HAVE_WAIT_HEADER)#define WAITTYPE int#define WIFSTOPPED(w) ((w&0377) == 0177)#define WIFSIGNALED(w) ((w&0377) != 0177 && (w&~0377) == 0)#define WIFEXITED(w) ((w&0377) == 0)#define WRETCODE(w) (w >> 8)#define WSTOPSIG(w) (w >> 8)#define WTERMSIG(w) (w & 0377)#ifndef WCOREDUMP#define WCOREDUMP(w) ((w&0200) != 0)#endif#else#ifdef BSD4_1#include <wait.h>#else#include <sys/wait.h>#endif /* not BSD 4.1 */#define WAITTYPE union wait#ifndef WRETCODE#define WRETCODE(w) w.w_retcode#endif#ifndef WCOREDUMP#define WCOREDUMP(w) w.w_coredump#endif#ifdef HPUX/* HPUX version 7 has broken definitions of these. */#undef WTERMSIG#undef WSTOPSIG#undef WIFSTOPPED#undef WIFSIGNALED#undef WIFEXITED#endif#ifndef WTERMSIG#define WTERMSIG(w) w.w_termsig#endif#ifndef WSTOPSIG#define WSTOPSIG(w) w.w_stopsig#endif#ifndef WIFSTOPPED#define WIFSTOPPED(w) (WTERMSIG (w) == 0177)#endif#ifndef WIFSIGNALED#define WIFSIGNALED(w) (WTERMSIG (w) != 0177 && (WSTOPSIG (w)) == 0)#endif#ifndef WIFEXITED#define WIFEXITED(w) (WTERMSIG (w) == 0)#endif#endif /* BSD or UNIPLUS or STRIDE */#endif /* no WAITTYPE */#ifndef BSD4_4extern errno;extern sys_nerr;extern char *sys_errlist[];#endif#ifndef BSD4_1#ifndef BSD4_4extern char *sys_siglist[];#endif#elsechar *sys_siglist[] = { "bum signal!!", "hangup", "interrupt", "quit", "illegal instruction", "trace trap", "iot instruction", "emt instruction", "floating point exception", "kill", "bus error", "segmentation violation", "bad argument to system call", "write on a pipe with no one to read it", "alarm clock", "software termination signal from kill", "status signal", "sendable stop signal not from tty", "stop signal from tty", "continue a stopped process", "child status has changed", "background read attempted from control tty", "background write attempted from control tty", "input record available at control tty", "exceeded CPU time limit", "exceeded file size limit" };#endif#ifdef vipc#include "vipc.h"extern int comm_server;extern int net_listen_address;#endif /* vipc *//* t means use pty, nil means use a pipe, maybe other values to come. */Lisp_Object Vprocess_connection_type;#ifdef SKTPAIR#ifndef HAVE_SOCKETS#include <sys/socket.h>#endif#endif /* SKTPAIR *//* Number of events of change of status of a process. */int process_tick;/* Number of events for which the user or sentinel has been notified. */int update_tick;int delete_exited_processes;#ifdef FD_SET/* We could get this from param.h, but better not to depend on finding that. And better not to risk that it might define other symbols used in this file. */#define MAXDESC 64#define SELECT_TYPE fd_set#else /* no FD_SET */#define MAXDESC 32#define SELECT_TYPE int/* Define the macros to access a single-int bitmap of descriptors. */#define FD_SET(n, p) (*(p) |= (1 << (n)))#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))#define FD_ISSET(n, p) (*(p) & (1 << (n)))#define FD_ZERO(p) (*(p) = 0)#endif /* no FD_SET *//* Mask of bits indicating the descriptors that we wait for input on */SELECT_TYPE input_wait_mask;/* Indexed by descriptor, gives the process (if any) for that descriptor */Lisp_Object chan_process[MAXDESC];/* Alist of elements (NAME . PROCESS) */Lisp_Object Vprocess_alist;Lisp_Object Qprocessp;Lisp_Object get_process ();/* Buffered-ahead input char from process, indexed by channel. -1 means empty (no char is buffered). Used on sys V where the only way to tell if there is any output from the process is to read at least one char. Always -1 on systems that support FIONREAD. */int proc_buffered_char[MAXDESC];/* These variables hold the filter about to be run, and its args, between read_process_output and run_filter. Also used in exec_sentinel for sentinels. */Lisp_Object this_filter;Lisp_Object filter_process, filter_string;/* Compute the Lisp form of the process status, p->status, from the numeric status that was returned by `wait'. */update_status (p) struct Lisp_Process *p;{ union { int i; WAITTYPE wt; } u; u.i = XFASTINT (p->raw_status_low) + (XFASTINT (p->raw_status_high) << 16); p->status = status_convert (u.wt); p->raw_status_low = Qnil; p->raw_status_high = Qnil;}/* Convert a process status word in Unix format to the list that we use internally. */Lisp_Objectstatus_convert (w) WAITTYPE w;{ if (WIFSTOPPED (w)) return Fcons (Qstop, Fcons (make_number (WSTOPSIG (w)), Qnil)); else if (WIFEXITED (w)) return Fcons (Qexit, Fcons (make_number (WRETCODE (w)), WCOREDUMP (w) ? Qt : Qnil)); else if (WIFSIGNALED (w)) return Fcons (Qsignal, Fcons (make_number (WTERMSIG (w)), WCOREDUMP (w) ? Qt : Qnil)); else return Qrun;}/* Given a status-list, extract the three pieces of information and store them individually through the three pointers. */voiddecode_status (l, symbol, code, coredump) Lisp_Object l; Lisp_Object *symbol; int *code; int *coredump;{ Lisp_Object tem; if (XTYPE (l) == Lisp_Symbol) { *symbol = l; *code = 0; *coredump = 0; } else { *symbol = XCONS (l)->car; tem = XCONS (l)->cdr; *code = XFASTINT (XCONS (tem)->car); tem = XFASTINT (XCONS (tem)->cdr); *coredump = !NULL (tem); }}/* Return a string describing a process status list. */Lisp_Object status_message (status) Lisp_Object status;{ Lisp_Object symbol; int code, coredump; Lisp_Object string, string2; decode_status (status, &symbol, &code, &coredump); if (EQ (symbol, Qsignal) || EQ (symbol, Qstop)) { string = build_string (code < NSIG ? sys_siglist[code] : "unknown"); string2 = build_string (coredump ? " (core dumped)\n" : "\n"); XSTRING (string)->data[0] = DOWNCASE (XSTRING (string)->data[0]); return concat2 (string, string2); } else if (EQ (symbol, Qexit)) { if (code == 0) return build_string ("finished\n"); string = Fint_to_string (make_number (code)); string2 = build_string (coredump ? " (core dumped)\n" : "\n"); return concat2 (build_string ("exited abnormally with code "), concat2 (string, string2)); } else return Fcopy_sequence (Fsymbol_name (symbol));}#ifdef HAVE_PTYS/* Open an available pty, returning a file descriptor. Return -1 on failure. The file name of the terminal corresponding to the pty is left in the variable pty_name. */char pty_name[24];intallocate_pty (){ struct stat stb; register c, i; int fd;#ifdef PTY_ITERATION PTY_ITERATION#else for (c = FIRST_PTY_LETTER; c <= 'z'; c++) for (i = 0; i < 16; i++)#endif {#ifdef PTY_NAME_SPRINTF PTY_NAME_SPRINTF#else#ifdef HPUX sprintf (pty_name, "/dev/ptym/pty%c%x", c, i);#else#ifdef RTU sprintf (pty_name, "/dev/pty%x", i);#else sprintf (pty_name, "/dev/pty%c%x", c, i);#endif /* not RTU */#endif /* not HPUX */#endif /* no PTY_NAME_SPRINTF */#ifndef IRIS if (stat (pty_name, &stb) < 0) return -1;#ifdef O_NONBLOCK fd = open (pty_name, O_RDWR | O_NONBLOCK, 0);#else fd = open (pty_name, O_RDWR | O_NDELAY, 0);#endif#else /* Unusual IRIS code */ fd = open ("/dev/ptc", O_RDWR | O_NDELAY, 0); if (fd < 0) return -1; if (fstat (fd, &stb) < 0) return -1;#endif /* IRIS */ if (fd >= 0) { /* check to make certain that both sides are available this avoids a nasty yet stupid bug in rlogins */#ifdef PTY_TTY_NAME_SPRINTF PTY_TTY_NAME_SPRINTF#else /* In version 19, make these special cases use the macro above. */#ifdef HPUX sprintf (pty_name, "/dev/pty/tty%c%x", c, i);#else#ifdef RTU sprintf (pty_name, "/dev/ttyp%x", i);#else#ifdef IRIS sprintf (pty_name, "/dev/ttyq%d", minor (stb.st_rdev));#else sprintf (pty_name, "/dev/tty%c%x", c, i);#endif /* not IRIS */#endif /* not RTU */#endif /* not HPUX */#endif /* no PTY_TTY_NAME_SPRINTF */#ifndef UNIPLUS if (access (pty_name, 6) != 0) { close (fd);#ifndef IRIS continue;#else return -1;#endif /* IRIS */ }#endif /* not UNIPLUS */ setup_pty (fd); return fd; } } return -1;}#endif /* HAVE_PTYS */Lisp_Objectmake_process (name) Lisp_Object name;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -