Subject: Re: Handling errors in standard output statements with openmcl
From: rpw3@rpw3.org (Rob Warnock)
Date: Tue, 06 Dec 2005 07:10:19 -0600
Newsgroups: comp.lang.lisp
Message-ID: <VoGdneERIrMmEAjeRVn-pQ@speakeasy.net>
Kirk Job Sluder  <kirk-nospam@jobsluder.net> wrote:
+---------------
| ... if I pipe the output into less, and then quit less midway
| through the file.  The program hangs, then gives me:
| 
| Unhandled exception 11 at 0x410be24, context->regs at #xbff9eee8
| Write operation to unmapped address 0x75ff8
...
| I know that what is happening when I quit less, OpenMCL still tries to 
| write to an output buffer.  My question is (after a modest amount of 
| searching) primarily for future reference.  How can I make this output 
| function "safe" so that if *standard-input* closes, the script exits 
| gracefully.
+---------------

I had exactly the same problem when writing a CMUCL-based web
application server, when the browser user hit "Stop" or "Back"
or "Close" before a large request has been completely sent.
Under Unix/Linux, this causes a SIGPIPE signal to be sent to
the CMUCL process, which I tried to catch using CMUCL's signal-
handling code... which is unfortunately not completely reliable.

But Dan Barlow [thanks, Dan!!] pointed out a much simpler way:
Simply set the Lisp process to *ignore* SIGPIPE, and then you'll
get ordinary system call errors (with EPIPE) from any writes after
the pipe [or socket] is closed. In CMUCL, you can do that this way:

    ;;; Somewhere in your init code:
    (defvar *old-sigpipe-handler* (system:enable-interrupt :sigpipe :ignore))

Then wrap the following around your outputting code:

    (handler-case
	(send-output stream)		; the main work
      (error (condition)
	(cond
	  ((eql unix:unix-errno unix:EPIPE)
	   ;; Log it locally if you want to & can, then...
	   (ignore-errors (close stream :abort t)))
	  ;; <== Maybe insert other error cases here.
	  (t			; catch-all
	   ;; Log it locally if you want to & can, then...
           ;; If the stream is still open, try to print the error
           ;; onto the output stream, too.
           (when (open-stream-p stream)
             (ignore-errors     ; But might EPIPE here, too, so protect.
               (progn
                 (format stream "Internal server error!~%~a~%" condition)
                 (finish-output stream)  ; Either of these might EPIPE,
                 (close stream))))))))   ;  which is why the IGNORE-ERRORS.

As I said, this works fine for CMUCL. You'll need to find out how
to do the same SIGPIPE ignoring in OpenMCL, and also translate the
other UNIX package code above appropriately...


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607