📄 process.c
字号:
/* Read and dispose of subprocess output while waiting for timeout to elapse and/or keyboard input to be available. time_limit is the timeout in seconds, or zero for no limit. -1 means gobble data available immediately but don't wait for any. read_kbd is 1 to return when input is available. -1 means caller will actually read the input. A pointer to a struct Lisp_Process means wait until something arrives from that process. do_display means redisplay should be done to show subprocess output that arrives. */wait_reading_process_input (time_limit, read_kbd, do_display) int time_limit, read_kbd, do_display;{ register int channel, nfds, m; SELECT_TYPE Available; SELECT_TYPE Exception; int xerrno; Lisp_Object proc;#ifdef HAVE_TIMEVAL struct timeval timeout, end_time, garbage;#else long timeout, end_time, temp;#endif /* not HAVE_TIMEVAL */ SELECT_TYPE Atemp; int wait_channel = 0; struct Lisp_Process *wait_proc = 0; extern kbd_count; /* Detect when read_kbd is really the address of a Lisp_Process. */ if (read_kbd > 10 || read_kbd < -1) { wait_proc = (struct Lisp_Process *) read_kbd; wait_channel = XFASTINT (wait_proc->infd); read_kbd = 0; } waiting_for_user_input_p = read_kbd; /* Since we may need to wait several times, compute the absolute time to return at. */ if (time_limit) {#ifdef HAVE_TIMEVAL gettimeofday (&end_time, &garbage); end_time.tv_sec += time_limit;#else /* not HAVE_TIMEVAL */ time (&end_time); end_time += time_limit;#endif /* not HAVE_TIMEVAL */ }#if 0 /* Select emulator claims to preserve alarms. And there are many ways to get out of this function by longjmp. */ /* Turn off periodic alarms (in case they are in use) because the select emulator uses alarms. */ stop_polling ();#endif while (1) { /* If calling from keyboard input, do not quit since we want to return C-g as an input character. Otherwise, do pending quit if requested. */ if (read_kbd >= 0) {#if 0 /* This is the same condition tested by QUIT. We need to resume polling if we are going to quit. */ if (!NULL (Vquit_flag) && NULL (Vinhibit_quit)) { start_polling (); QUIT; }#endif QUIT; } /* If status of something has changed, and no input is available, notify the user of the change right away */ if (update_tick != process_tick && do_display) { Atemp = input_wait_mask;#ifdef HAVE_TIMEVAL timeout.tv_sec=0; timeout.tv_usec=0;#else /* not HAVE_TIMEVAL */ timeout = 0;#endif /* not HAVE_TIMEVAL */ if (select (MAXDESC, &Atemp, 0, 0, &timeout) <= 0) status_notify (); } /* Don't wait for output from a non-running process. */ if (wait_proc != 0 && !NULL (wait_proc->raw_status_low)) update_status (wait_proc); if (wait_proc != 0 && ! EQ (wait_proc->status, Qrun)) break; if (fix_screen_hook) (*fix_screen_hook) (); /* Compute time from now till when time limit is up */ /* Exit if already run out */ if (time_limit == -1) { /* -1 specified for timeout means gobble output available now but don't wait at all. */#ifdef HAVE_TIMEVAL timeout.tv_sec = 0; timeout.tv_usec = 0;#else timeout = 0;#endif /* not HAVE_TIMEVAL */ } else if (time_limit) {#ifdef HAVE_TIMEVAL gettimeofday (&timeout, &garbage); timeout.tv_sec = end_time.tv_sec - timeout.tv_sec; timeout.tv_usec = end_time.tv_usec - timeout.tv_usec; if (timeout.tv_usec < 0) timeout.tv_usec += 1000000, timeout.tv_sec--; if (timeout.tv_sec < 0) break;#else /* not HAVE_TIMEVAL */ time (&temp); timeout = end_time - temp; if (timeout < 0) break;#endif /* not HAVE_TIMEVAL */ } else {#ifdef HAVE_TIMEVAL /* If no real timeout, loop sleeping with a big timeout so that input interrupt can wake us up by zeroing it */ timeout.tv_sec = 100; timeout.tv_usec = 0;#else /* not HAVE_TIMEVAL */ timeout = 100000; /* 100000 recognized by the select emulator */#endif /* not HAVE_TIMEVAL */ } /* Cause quitting and alarm signals to take immediate action, and cause input available signals to zero out timeout */ if (read_kbd < 0) set_waiting_for_input (&timeout); /* Wait till there is something to do */ Available = Exception = input_wait_mask; if (!read_kbd) FD_CLR (0, &Available); if (read_kbd && kbd_count) nfds = 0; else#ifdef IBMRTAIX nfds = select (MAXDESC, &Available, 0, 0, &timeout);#else#ifdef HPUX nfds = select (MAXDESC, &Available, 0, 0, &timeout);#else nfds = select (MAXDESC, &Available, 0, &Exception, &timeout);#endif#endif xerrno = errno; if (fix_screen_hook) (*fix_screen_hook) (); /* Make C-g and alarm signals set flags again */ clear_waiting_for_input (); /* If we woke up due to SIGWINCH, actually change size now. */ do_pending_window_change (); if (time_limit && nfds == 0) /* timeout elapsed */ break; if (nfds < 0) { if (xerrno == EINTR) FD_ZERO (&Available);#ifdef ALLIANT /* This happens for no known reason on ALLIANT. I am guessing that this is the right response. -- RMS. */ else if (xerrno == EFAULT) FD_ZERO (&Available);#endif else if (xerrno == EBADF)#ifdef AIX /* AIX will return EBADF on a call to select involving a ptc if the associated pts isn't open. Since this will only happen just as a child is dying, just ignore the situation -- SIGCHLD will come along quite quickly, and after cleanup the ptc will no longer be checked, so this error will stop recurring. */ FD_ZERO (&Available); /* Cannot depend on values returned. */#else /* not AIX */ abort ();#endif /* not AIX */ else error("select error: %s", sys_errlist[xerrno]); }#ifdef sun else if (nfds > 0 && FD_ISSET (0, &Available) && interrupt_input) /* System sometimes fails to deliver SIGIO. */ kill (getpid (), SIGIO);#endif /* Check for keyboard input */ /* If there is any, return immediately to give it higher priority than subprocesses */ if (read_kbd && detect_input_pending ()) break;#ifdef vipc /* Check for connection from other process */ if (FD_ISSET (comm_server, &Available)) { FD_CLR (comm_server, &Available); create_commchan (); }#endif vipc /* Check for data from a process or a command channel */ for (channel = 3; channel < MAXDESC; channel++) { if (FD_ISSET (channel, &Available)) { int nread; FD_CLR (channel, &Available); /* If waiting for this channel, arrange to return as soon as no more input to be processed. No more waiting. */ if (wait_channel == channel) { wait_channel = 0; time_limit = -1; } proc = chan_process[channel]; if (NULL (proc)) continue;#ifdef vipc /* It's a command channel */ if (!NULL (XPROCESS (proc)->command_channel_p)) { ProcessCommChan (channel, proc); if (NULL (XPROCESS (proc)->command_channel_p)) { /* It has ceased to be a command channel! */ int bytes_available; if (ioctl (channel, FIONREAD, &bytes_available) < 0) bytes_available = 0; if (bytes_available) FD_SET (channel, &Available); } continue; }#endif vipc /* Read data from the process, starting with our buffered-ahead character if we have one. */ nread = read_process_output (proc, channel); if (nread > 0) { /* Since read_process_output can run a filter, which can call accept-process-output, don't try to read from any other processes before doing the select again. */ FD_ZERO (&Available); if (do_display) redisplay_preserve_echo_area (); }#ifdef EWOULDBLOCK else if (nread == -1 && errno == EWOULDBLOCK) ;#else#ifdef O_NONBLOCK else if (nread == -1 && errno == EAGAIN) ;#else#ifdef O_NDELAY else if (nread == -1 && errno == EAGAIN) ; /* Note that we cannot distinguish between no input available now and a closed pipe. With luck, a closed pipe will be accompanied by subprocess termination and SIGCHLD. */ else if (nread == 0) ;#endif /* O_NDELAY */#endif /* O_NONBLOCK */#endif /* EWOULDBLOCK */#ifdef HAVE_PTYS /* On some OSs with ptys, when the process on one end of a pty exits, the other end gets an error reading with errno = EIO instead of getting an EOF (0 bytes read). Therefore, if we get an error reading and errno = EIO, just continue, because the child process has exited and should clean itself up soon (e.g. when we get a SIGCHLD). */ else if (nread == -1 && errno == EIO) ;#endif /* HAVE_PTYS *//* If we can detect process termination, don't consider the process gone just because its pipe is closed. */#ifdef SIGCHLD else if (nread == 0) ;#endif else { /* Preserve status of processes already terminated. */ XSETINT (XPROCESS (proc)->tick, ++process_tick); deactivate_process (proc); if (!NULL (XPROCESS (proc)->raw_status_low)) update_status (XPROCESS (proc)); if (EQ (XPROCESS (proc)->status, Qrun)) XPROCESS (proc)->status = Fcons (Qexit, Fcons (make_number (256), Qnil)); } } } /* end for */ } /* end while */#if 0 /* Resume periodic signals to poll for input, if necessary. */ start_polling ();#endif}/* Actually call the filter. This gets the information via variables because internal_condition_case won't pass arguments. */Lisp_Objectrun_filter (){ return call2 (this_filter, filter_process, filter_string);}/* Read pending output from the process channel, starting with our buffered-ahead character if we have one. Yield number of characters read. This function reads at most 1024 characters. If you want to read all available subprocess output, you must call it repeatedly until it returns zero. */read_process_output (proc, channel) Lisp_Object proc; register int channel;{ register int nchars; char chars[1024]; register Lisp_Object outstream; register struct buffer *old = current_buffer; register struct Lisp_Process *p = XPROCESS (proc); register int opoint; if (proc_buffered_char[channel] < 0) nchars = read (channel, chars, sizeof chars); else { chars[0] = proc_buffered_char[channel]; proc_buffered_char[channel] = -1; nchars = read (channel, chars + 1, sizeof chars - 1); if (nchars < 0) nchars = 1; else nchars = nchars + 1; } if (nchars <= 0) return nchars; outstream = p->filter; if (!NULL (outstream)) { int count = specpdl_ptr - specpdl; specbind (Qinhibit_quit, Qt); this_filter = outstream; filter_process = proc; filter_string = make_string (chars, nchars); call2 (this_filter, filter_process, filter_string); /* internal_condition_case (run_filter, Qerror, Fidentity); */ unbind_to (count); return nchars; } /* If no filter, write into buffer if it isn't dead. */ if (!NULL (p->buffer) && !NULL (XBUFFER (p->buffer)->name)) { Lisp_Object tem; Fset_buffer (p->buffer); opoint = point; /* Insert new output into buffer at the current end-of-output marker, thus preserving logical ordering of input and output. */ if (XMARKER (p->mark)->buffer) SET_PT (marker_position (p->mark)); else SET_PT (ZV); if (point <= opoint) opoint += nchars; tem = current_buffer->read_only; current_buffer->read_only = Qnil; insert (chars, nchars); current_buffer->read_only = tem; Fset_marker (p->mark, make_number (point), p->buffer); update_mode_lines++; SET_PT (opoint); set_buffer_internal (old); } return nchars;}DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, Swaiting_for_user_input_p, 0, 0, 0, "Returns non-NIL if emacs is waiting for input from the user.\n\This is intended for use by asynchronous process output filters and sentinels.") (){ return ((waiting_for_user_input_p) ? Qt : Qnil);}/* Sending data to subprocess */jmp_buf send_process_frame;send_process_trap (){#ifdef BSD4_1 sigrelse (SIGPIPE); sigrelse (SIGALRM);#endif /* BSD4_1 */ longjmp (send_process_frame, 1);}send_process (proc, buf, len) Lisp_Object proc; char *buf; int len;{ /* Don't use register vars; longjmp can lose them. */ int rv; unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data; if (!NULL (XPROCESS (proc)->raw_status_low)) update_status (XPROCESS (proc)); if (! EQ (XPROCESS (proc)->status, Qrun)) error ("Process %s not running", procname); if (!setjmp (send_process_frame)) while (len > 0) { signal (SIGPIPE, send_process_trap); rv = write (XFASTINT (XPROCESS (proc)->outfd), buf, len); signal (SIGPIPE, SIG_DFL); if (rv < 0) {#ifdef EWOULDBLOCK if (errno == EWOULDBLOCK) { /* It would be nice to accept process output here, but that is difficult. For example, it could garbage what we are sending if that is from a buffer. */ immediate_quit = 1; QUIT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -