[Openmcl-devel] *multiprocessing-socket-io* and implications

Ralf Stoye stoye at stoye.com
Mon Oct 29 06:10:27 PDT 2007

In August 2005 there was a discussion about ccl::*multiprocessing- 
After some tests i saw a performance benefit and better stability (no  
need to handle eagain errors) from setting it to nil, but there is an  
unlovely side-effect:
If you kill a process blocked by ccl:accept-connection the socket  
stays open until the next connection arrives and after that, we have  
an orphaned connection in state "CLOSE_WAIT" (seen with netstat). I  
noticed the problem by using some http-server packages: Since they  
kill their listening processes, none of them is able to stop and  
restart the service when ccl::*multiprocessing-socket-io* is nil,  
since the port is "already in use".
I got around this by modifying the "wait" clause in ccl::socket- 
accept to resemble the behavior of the T clause (change socket  
options to include #$O_NONBLOCK
before calling with-eagain... ) but i am not sure if this is the  
"right" way to solve the problem.

Maybe someone can comment on this.
(i can post some code for testing if needed)

;; my modified socket-accept:
(defun socket-accept (fd wait socket)
   (flet ((_accept (fd async)
	   (let ((res (c_accept fd (%null-ptr) (%null-ptr))))
	     (declare (fixnum res))
	     ;; See the inscrutable note under ERROR HANDLING in
	     ;; man accept(2). This is my best guess at what they mean...
	     (if (and async (< res 0)
		      (or (eql res (- #$ENETDOWN))
			  (eql res (- #+linux-target #$EPROTO
				      #+(or darwin-target freebsd-target) #$EPROTOTYPE))
			  (eql res (- #$ENOPROTOOPT))
			  (eql res (- #$EHOSTDOWN))
			  (eql res (- #+linux-target #$ENONET
				      #+(or darwin-target freebsd-target) #$ENETDOWN))
			  (eql res (- #$EHOSTUNREACH))
			  (eql res (- #$EOPNOTSUPP))
			  (eql res (- #$ENETUNREACH))))
	       (- #$EAGAIN)
     (cond (wait
	   (let ((old (socket-call socket "fcntl" (fd-get-flags fd))))
		    (socket-call socket "fcntl" (fd-set-flags fd (logior old # 
		    (with-eagain fd :input
		      (_accept fd t)))
		(socket-call socket "fcntl" (fd-set-flags fd old)))))
	    (_accept fd t))
	    (let ((old (socket-call socket "fcntl" (fd-get-flags fd))))
		    (socket-call socket "fcntl" (fd-set-flags fd (logior old # 
		    (_accept fd t))
		(socket-call socket "fcntl" (fd-set-flags fd old))))))))

Ralf Stoye

More information about the Openmcl-devel mailing list