tiemann@mcc-pp.UUCP (Michael Tiemann) (08/14/86)
So we *know* we're talking the same language, here's some simple gnuemacs lisp code: (defun setup-process (a &rest b) (interactive) (setq cat (eval (cons 'start-process (append (list a a a) b)))) ) (defun send-process-region () (interactive) (send-region cat (point) (mark)) ) (defun cat () (interactive) (setup-process "cat") (switch-to-buffer "cat") ) (defun x-cat () (interactive) (kill-buffer "cat") ) (global-set-key "\e$" 'send-process-region) Here's the problem: we set up at "cat" process (copy input to output), find a big file, set point and mark to be 1000 characters apart, and they repeatedly type "ESC-$" . On our SUN-3 about the 4th "ESC-4" the error message "writing to process: operation would block, cat" pops up. If we continue to type "ESC-$", the error sometimes comes up, and sometimes does not. On our VAX 11/750 "running" (walking) BDS 4.2, there is no error message, but the gnuemacs shows up as Idle in ps -ux. (A few ^G's wake it into abortion-land). Clues? Look in process.c for the error-causing routine (send_process_1). The problem gets worse: if I want to send a 10k region, not even one call will go through. The code looks easy, so either (1) I understand nothing about pipes. (2) The authors of GNU understand nothing about pipes (3) Our friends at Berkely understands nothing about pipes. And its not "cat"'s fault: I wrote a program that just says "hello" and then proceedes to read (and only read) the keyboard. Same result. It seems to me that if I want to write a zillion bytes to a pipe, and somebody else wants to read it, that the OS should wake and sleep us until those zillion bytes have zipped through the pipe. If this is an incorrect interpretation, please tell me how to pretend this is happening. Michael "God I wish I had shared memory" Tiemann
ehj@mordor.ARPA (Eric H Jensen) (08/14/86)
In article <1508@mcc-pp.UUCP> tiemann@mcc-pp.UUCP (Michael Tiemann) writes: >On our SUN-3 about the 4th "ESC-4" the error message "writing to process: >operation would block, cat" pops up. If we continue to type "ESC-$", >the error sometimes comes up, and sometimes does not. On our VAX >11/750 "running" (walking) BDS 4.2, there is no error message, but the >gnuemacs shows up as Idle in ps -ux. (A few ^G's wake it into >abortion-land). I believe I had a similar problem to yours (GNUemacs 17.49). The cause is that emacs does an ioctl instructing unix that writes to the pipe should not block (which, I believe, is for most purposes is the right thing). After thinking about it and consulting with our local unix guru I came up with the following changes (hope this helps): *** process.c.orig Thu May 29 17:04:36 1986 --- process.c Wed Jun 4 14:15:20 1986 *************** *** 166,171 **** --- 166,174 ---- Always -1 on systems that support FIONREAD. */ int proc_buffered_char[MAXDESC]; + + Lisp_Object Vwait_no_block; + #ifdef HAVE_PTYS *************** *** 1201,1206 **** --- 1204,1217 ---- { /* Don't use register vars; longjmp can lose them. */ int rv; + int fd; + + #ifdef HAVE_TIMEVAL + struct timeval sd; + int usec; + int sv; + #endif /* HAVE_TIMEVAL */ + unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data; if ((XFASTINT (XPROCESS (proc)->flags) & PROC_STATUS) != RUNNING) *************** *** 1211,1217 **** if (!setjmp (send_process_frame)) while (len > 0) { ! rv = write (XFASTINT (XPROCESS (proc)->outfd), buf, len); if (rv < 0) break; buf += rv; --- 1222,1239 ---- if (!setjmp (send_process_frame)) while (len > 0) { ! fd = XFASTINT (XPROCESS (proc)->outfd); ! ! #ifdef HAVE_TIMEVAL ! if (XTYPE (Vwait_no_block) == Lisp_Int) ! sd.tv_usec = XUINT (Vwait_no_block); ! else sd.tv_usec = 0; ! sd.tv_sec = 0; ! usec = 1 << fd; ! sv = select (fd + 1, 0,&usec, 0, &sd); ! #endif /* HAVE_TIMEVAL */ ! ! rv = write (fd, buf, len); if (rv < 0) break; buf += rv; *************** *** 1694,1699 **** --- 1716,1729 ---- staticpro (&Qprocessp); staticpro (&Vprocess_alist); + + DefLispVar ("wait-no-block", &Vwait_no_block, + "*If integer, unsigned value indicates number of microseconds \n\ + for select to wait before writing to a subprocess. This mechanism \n\ + is provided because Emacs refuses to block on writes to subprocesses.\n\ + A non-integer value is equivalent to 0. The default value is 50000."); + + Vwait_no_block = XFASTINT(50000); DefBoolVar ("delete-exited-processes", &delete_exited_processes, "*Non-nil means delete processes immediately when they exit.\n\ -- eric h. jensen (S1 Project @ Lawrence Livermore National Laboratory) Phone: (415) 423-0229 USMail: LLNL, P.O. Box 5503, L-276, Livermore, Ca., 94550 ARPA: ehj@angband UUCP: ...!decvax!decwrl!mordor!angband!ehj
wesommer@mit-trillian.MIT.EDU (William Sommerfeld) (08/15/86)
Read the manual page for pipe(2) (this is BSD 4.3, but it hasn't changed much). The pipe system call creates an I/O mechanism called a pipe. The file descriptors returned can be used in read and write operations. When the pipe is written using the descriptor fildes[1] up to 4096 bytes of data are buffered before the writing process is suspended. A read using the descriptor fildes[0] will pick up the data. BUGS Should more than 4096 bytes be necessary in any pipe among a loop of processes, deadlock will occur. In article <1508@mcc-pp.UUCP> tiemann@mcc-pp.UUCP writes: > >Here's the problem: we set up at "cat" process (copy input to output), >find a big file, set point and mark to be 1000 characters apart, and >they repeatedly type "ESC-$" . > >On our SUN-3 about the 4th "ESC-4" the error message "writing to process: >operation would block, cat" pops up. If we continue to type "ESC-$", >the error sometimes comes up, and sometimes does not. On our VAX >11/750 "running" (walking) BDS 4.2, there is no error message, but the >gnuemacs shows up as Idle in ps -ux. (A few ^G's wake it into >abortion-land). It looks like you're jamming more than the maximum buffer size into the pipe. Since all "cat" does is whip your input back out at you, and Emacs hasn't had a chance to read it yet, when both buffers get jammed, you lose and have to break out. It is possible that the SUN kernel detects this deadlock situation and returns an EWOULDBLOCK ("Operation would block") error code. >It seems to me that if I want to write a zillion bytes to a pipe, and >somebody else wants to read it, that the OS should wake and sleep us >until those zillion bytes have zipped through the pipe. If this is an >incorrect interpretation, please tell me how to pretend this is >happening. Not if the kernel limits your buffer space; otherwise, runaway processes could chew up all your memory. The problem is not that you're shipping a lot through the pipe, it is that you're shipping a lot through, it's being sent right back to you, and you have no way to read it because you're writing right now. A possible fix (BSD dependant) would be to select non-blocking I/O, maintain a queue of input for each file descriptor, and then ship things over in 1K or 2K chunks, and drop back into a select loop when the operation blocks. Bill Sommerfeld ARPA: wesommer@athena.mit.edu UUCP: ...!mit-eddie!wesommer