From: ilya
Subject: tiny web server
Date: 
Message-ID: <newscache$7yg47h$ouk$1@lnews.actcom.co.il>
Hi.
I'm a lisp newbie.
Just wanna hear your critics.
It should be more about [mis]understanding lisp concepts
and less about specific issues.

By the way - where the zombies come from when using "/top" ?


---8<---
#!/usr/local/bin/clisp

(setq do-shutdown nil)

(defun start-html-response (sock)
         (format sock "HTTP/0.9 200 Okay~%")
         (format sock "Expires: Thu, 01 Dec 1994 16:00:00 GMT~%")
         (format sock "Pragma: no-cache~%")
         (format sock "Content-type: text/html~%~%")
         (format sock "Current time is : ~A<br>~%" (current-time nil)))

(defun err-not-found (sock url)
         (format sock "HTTP/0.9 404~%")
         (format sock "Content-type: text/html~%~%")
         (format sock "URL : ~A not found on this server~%" url))

(defun cut-url (line)
         (let (
                 (p1 (position #\Space line))
                 (p2 (position #\Space line :from-end t)))
                         (if (and p1 p2)
                                 (subseq line (1+ p1) p2)
                                 "-")))

(defun handle-request (sock line)
         (let ((url (cut-url line)))
                 (format t "Url: ~A~%" url)
                 (cond
                         ((equal url "/")
                                 (start-html-response sock)
                                 (format sock "Hallo<br>"))
                         ((equal url "/shutdown")
                                 (start-html-response sock)
                                 (format sock "Going down ...<br>")
                                 ;(shell "logger _httpd will shut down 
the system")
                                 (setq do-shutdown t))
                         ((equal url "/top")
                                 (start-html-response sock)
                                 ;(format sock "<head><META 
http-equiv='Refresh' content='2'></head>")
                                 (format sock "<pre>")
                                 (do*
                                         ((pipe (make-pipe-input-stream 
"top -b"))
                                                 (str (read-line pipe nil)))
                                         ((not str) (close pipe) nil)
                                         (format sock "~A~%" str)
                                         (setq str (read-line pipe nil)))
                                 (format sock "</pre>"))
                         (t (err-not-found sock url)))))

(format t "HTTPD.CL started~%")
(let ((serv (socket-server 80)))
         (loop
                 (let ((sock (socket-accept serv)))
                         (format t "Socket accepted~%")
                         ;(shell "logger _httpd started")
                         (let ((line1 (read-line sock)))
                                 (format t ">~A~%" line1)
                                 ;(shell "logger _httpd handling request")
                                 (handle-request sock line1)
                                 ;(shell "logger _httpd finished handling")
                                 (force-output sock)
                                 (close sock)
                                 (if do-shutdown (shell "halt")))))))

(format t "Done~%")
---8<---

-- 
(lisp-newbie-p ilya) => t

From: Sam Steingold
Subject: Re: tiny web server
Date: 
Message-ID: <m3vg1wgkbi.fsf@loiso.podval.org>
> * In message <······················@lnews.actcom.co.il>
> * On the subject of "tiny web server"
> * Sent on Sat, 14 Dec 2002 20:35:19 +0200
> * Honorable ilya <············@example.com> writes:
>
> By the way - where the zombies come from when using "/top" ?

<http://www.podval.org/~sds/zombie.html>

> #!/usr/local/bin/clisp
> 
> (setq do-shutdown nil)
> 
> (defun start-html-response (sock)
>          (format sock "HTTP/0.9 200 Okay~%")
>          (format sock "Expires: Thu, 01 Dec 1994 16:00:00 GMT~%")
>          (format sock "Pragma: no-cache~%")
>          (format sock "Content-type: text/html~%~%")
>          (format sock "Current time is : ~A<br>~%" (current-time nil)))
> 
> (defun err-not-found (sock url)
>          (format sock "HTTP/0.9 404~%")
>          (format sock "Content-type: text/html~%~%")
>          (format sock "URL : ~A not found on this server~%" url))
> 
> (defun cut-url (line)
>          (let (
>                  (p1 (position #\Space line))
>                  (p2 (position #\Space line :from-end t)))
>                          (if (and p1 p2)
>                                  (subseq line (1+ p1) p2)
>                                  "-")))
> 
> (defun handle-request (sock line)
>          (let ((url (cut-url line)))
>                  (format t "Url: ~A~%" url)
>                  (cond
>                          ((equal url "/")
>                                  (start-html-response sock)
>                                  (format sock "Hallo<br>"))
>                          ((equal url "/shutdown")
>                                  (start-html-response sock)
>                                  (format sock "Going down ...<br>")
>                                  ;(shell "logger _httpd will shut down
>                                   the system")
>                                  (setq do-shutdown t))
>                          ((equal url "/top")
>                                  (start-html-response sock)
>                                  ;(format sock "<head><META
>                                   http-equiv='Refresh'
>                                   content='2'></head>")
>                                  (format sock "<pre>")
>                                  (do*
>                                          ((pipe (make-pipe-input-stream
>                                          "top -b"))

"top -b" runs until it is killed.
who is supposed to kill it?
(close pipe) would, but it is unreachable: read-line will always return
a string.

>                                                  (str (read-line pipe nil)))
>                                          ((not str) (close pipe) nil)
>                                          (format sock "~A~%" str)
>                                          (setq str (read-line pipe nil)))
>                                  (format sock "</pre>"))
>                          (t (err-not-found sock url)))))
> 
> (format t "HTTPD.CL started~%")
> (let ((serv (socket-server 80)))
>          (loop
>                  (let ((sock (socket-accept serv)))

don't forget to pass the :EXTERNAL-FORMAT argument
(see *http-encoding* in CLISP/src/inspect.lisp)
At the very least use :EXTERNAL-FORMAT :DOS - then "~%" will send CR/LF
required by the HTTP protocol, not just LF.

>                          (format t "Socket accepted~%")
>                          ;(shell "logger _httpd started")
>                          (let ((line1 (read-line sock)))
>                                  (format t ">~A~%" line1)
>                                  ;(shell "logger _httpd handling request")
>                                  (handle-request sock line1)
>                                  ;(shell "logger _httpd finished handling")
>                                  (force-output sock)
>                                  (close sock)

You do not need to FORCE-OUTPUT is you are going to CLOSE the socket
right away

>                                  (if do-shutdown (shell "halt")))))))
> 
> (format t "Done~%")
> 

far too much indentation.
Emacs indents Lisp code quite well - use it!

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
The program isn't debugged until the last user is dead.
From: ilya
Subject: Re: tiny web server
Date: 
Message-ID: <newscache$rh367h$rj3$1@lnews.actcom.co.il>
Sam Steingold wrote:
>>* In message <······················@lnews.actcom.co.il>
>>* On the subject of "tiny web server"
>>* Sent on Sat, 14 Dec 2002 20:35:19 +0200
>>* Honorable ilya <············@example.com> writes:
>>
>>By the way - where the zombies come from when using "/top" ?
> 
> 
> <http://www.podval.org/~sds/zombie.html>
Great text , thanks.
> 
>>#!/usr/local/bin/clisp
>>
>>(setq do-shutdown nil)
>>
>>(defun start-html-response (sock)
>>         (format sock "HTTP/0.9 200 Okay~%")
>>         (format sock "Expires: Thu, 01 Dec 1994 16:00:00 GMT~%")
>>         (format sock "Pragma: no-cache~%")
>>         (format sock "Content-type: text/html~%~%")
>>         (format sock "Current time is : ~A<br>~%" (current-time nil)))
>>
>>(defun err-not-found (sock url)
>>         (format sock "HTTP/0.9 404~%")
>>         (format sock "Content-type: text/html~%~%")
>>         (format sock "URL : ~A not found on this server~%" url))
>>
>>(defun cut-url (line)
[snip]
>>
>>(defun handle-request (sock line)
>>         (let ((url (cut-url line)))
>>                 (format t "Url: ~A~%" url)
>>                 (cond
[snip]
>>                         ((equal url "/top")
>>                                 (start-html-response sock)
>>                                 ;(format sock "<head><META
>>                                  http-equiv='Refresh'
>>                                  content='2'></head>")
>>                                 (format sock "<pre>")
>>                                 (do*
>>                                         ((pipe (make-pipe-input-stream
>>                                         "top -b"))
> 
> 
> "top -b" runs until it is killed.
> who is supposed to kill it?
> (close pipe) would, but it is unreachable: read-line will always return
> a string.
It seems that you are right , it's not reached,
so I suppose read-line doesn't return NIL
unlike in this session :
[28]> (read-line pipe nil)
"  205 root       2    0    76K    4K sleep     0:00  0.00%  0.00% 
<inetd>" ;
NIL
[29]> (read-line pipe nil)
"" ;
NIL
[30]> (read-line pipe nil)
NIL ;
T
[31]>
Why?
I'm really missing here something ...

> 
> 
>>                                                 (str (read-line pipe nil)))
>>                                         ((not str) (close pipe) nil)
>>                                         (format sock "~A~%" str)
>>                                         (setq str (read-line pipe nil)))
>>                                 (format sock "</pre>"))
>>                         (t (err-not-found sock url)))))
>>
>>(format t "HTTPD.CL started~%")
>>(let ((serv (socket-server 80)))
>>         (loop
>>                 (let ((sock (socket-accept serv)))
> 
> 
> don't forget to pass the :EXTERNAL-FORMAT argument
> (see *http-encoding* in CLISP/src/inspect.lisp)
> At the very least use :EXTERNAL-FORMAT :DOS - then "~%" will send CR/LF
> required by the HTTP protocol, not just LF.
> 
Ok, thanks , I'll do that later because it /seems to/ work
even with LF alone and I've got zombies to handle :)
> 
>>                         (format t "Socket accepted~%")
>>                         ;(shell "logger _httpd started")
>>                         (let ((line1 (read-line sock)))
>>                                 (format t ">~A~%" line1)
>>                                 ;(shell "logger _httpd handling request")
>>                                 (handle-request sock line1)
>>                                 ;(shell "logger _httpd finished handling")
>>                                 (force-output sock)
>>                                 (close sock)
> 
> 
> You do not need to FORCE-OUTPUT is you are going to CLOSE the socket
> right away
Okay.
> 
> 
>>                                 (if do-shutdown (shell "halt")))))))
>>
>>(format t "Done~%")
>>
> 
> 
> far too much indentation.
> Emacs indents Lisp code quite well - use it!
I'm to deep in VIM ...
The code looks much better with tabstop=4.
Are there any logical problems whith my indentation?

-- 
(lisp-newbie-p ilya) => t
From: Larry Clapp
Subject: Re: tiny web server
Date: 
Message-ID: <nnkita.spi.ln@127.0.0.1>
In article <······················@lnews.actcom.co.il>, ilya wrote:
> Sam Steingold wrote:
>> far too much indentation.
>> Emacs indents Lisp code quite well - use it!
> I'm to deep in VIM ...
> The code looks much better with tabstop=4.

Vim does decent Lisp indentation, too.  See ":help lisp".

These may help, too:

    Lisp with Vim: http://lisp-p.org/htdocs/15-vim/index.html
	An article I wrote with some (hopefully :) helpful tips on writing
	Lisp with Vim.
    VILisp: http://vim.sourceforge.net/script.php?script_id=221
	A set of Vim functions for interacting with a Lisp process.  VILisp
	works (mostly) with CLisp ("clisp"?) under Linux.  (I targeted it at
	CMU CL.)

I'd've mailed this, but you don't list a valid email address.

-- Larry



-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----==  Over 80,000 Newsgroups - 16 Different Servers! =-----
From: ilya
Subject: Re: tiny web server
Date: 
Message-ID: <newscache$lhj67h$re4$1@lnews.actcom.co.il>
Larry Clapp wrote:
[snipped a lot, less traffic the better ?]
>     Lisp with Vim: http://lisp-p.org/htdocs/15-vim/index.html
>     VILisp: http://vim.sourceforge.net/script.php?script_id=221
> I'd've mailed this, but you don't list a valid email address.
Thanks for the information, i'll check thise out.
I'm too afraid of spam to provide my email address.


-- 
(lisp-newbie-p ilya) => t
From: Peter De Wachter
Subject: Re: tiny web server
Date: 
Message-ID: <slrnavph2m.6lq.pdewacht@arrakis.home>
In artikel <······················@lnews.actcom.co.il> schreef ilya:
> I'm to deep in VIM ...
> The code looks much better with tabstop=4.

try :set lisp autoindent showmatch
From: Sam Steingold
Subject: Re: tiny web server
Date: 
Message-ID: <m3lm2rf4x0.fsf@loiso.podval.org>
> * In message <······················@lnews.actcom.co.il>
> * On the subject of "Re: tiny web server"
> * Sent on Sun, 15 Dec 2002 17:39:42 +0200
> * Honorable ilya <············@example.com> writes:
>
> > "top -b" runs until it is killed.
> > who is supposed to kill it?
> > (close pipe) would, but it is unreachable: read-line will always return
> > a string.
> It seems that you are right , it's not reached,
> so I suppose read-line doesn't return NIL
> unlike in this session :
> [28]> (read-line pipe nil)
> "  205 root       2    0    76K    4K sleep     0:00  0.00%  0.00%
> <inetd>" ;
> NIL
> [29]> (read-line pipe nil)
> "" ;
> NIL
> [30]> (read-line pipe nil)
> NIL ;
> T
> [31]>
> Why?
> I'm really missing here something ...

here you get NIL because the pipe command has finished and read(2) on
the pipe returned EOF.
since top /b never finishes, read(2) never returns EOF, and READ-LINE
never returns NIL.

> > far too much indentation.
> > Emacs indents Lisp code quite well - use it!
> I'm to deep in VIM ...
> The code looks much better with tabstop=4.
> Are there any logical problems whith my indentation?

Many lispers use indentation to understand the logical structure of the
code.  We do not count parentheses.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Never succeed from the first try - if you do, nobody will think it was hard.
From: ilya
Subject: Re: tiny web server
Date: 
Message-ID: <newscache$f6j67h$8e4$1@lnews.actcom.co.il>
Sam Steingold wrote:
>>* In message <······················@lnews.actcom.co.il>
>>* On the subject of "Re: tiny web server"
>>* Sent on Sun, 15 Dec 2002 17:39:42 +0200
>>* Honorable ilya <············@example.com> writes:
>>
>>
>>>"top -b" runs until it is killed.
>>>who is supposed to kill it?
>>>(close pipe) would, but it is unreachable: read-line will always return
>>>a string.
>>
>>It seems that you are right , it's not reached,
>>so I suppose read-line doesn't return NIL
>>unlike in this session :
>>[28]> (read-line pipe nil)
>>"  205 root       2    0    76K    4K sleep     0:00  0.00%  0.00%
>><inetd>" ;
>>NIL
>>[29]> (read-line pipe nil)
>>"" ;
>>NIL
>>[30]> (read-line pipe nil)
>>NIL ;
>>T
>>[31]>
>>Why?
>>I'm really missing here something ...
> 
> 
> here you get NIL because the pipe command has finished and read(2) on
> the pipe returned EOF.
> since top /b never finishes, read(2) never returns EOF, and READ-LINE
Sorry , it's incorrect.
The "top -b" lists all the "top" processes once and quits.
(close pipe) gets executed, we were both wrong (i've tested).
We have a zombie here that we should wait() for.
How can i call the system function?
> never returns NIL.
> 
> 
>>>far too much indentation.
>>>Emacs indents Lisp code quite well - use it!
>>
>>I'm to deep in VIM ...
>>The code looks much better with tabstop=4.
>>Are there any logical problems whith my indentation?
> 
> 
> Many lispers use indentation to understand the logical structure of the
> code.  We do not count parentheses.

Obvious.
By my question i meant whether there are anomalities in the indentation,
such that lispers that don't count parentheses would be confused.
(Not considering that tab here happens to be 8 spaces)

-- 
(lisp-newbie-p ilya) => t
From: Sam Steingold
Subject: Re: tiny web server
Date: 
Message-ID: <m3wumaeh7c.fsf@loiso.podval.org>
> * In message <······················@lnews.actcom.co.il>
> * On the subject of "Re: tiny web server"
> * Sent on Sun, 15 Dec 2002 23:18:38 +0200
> * Honorable ilya <············@example.com> writes:
>
> Sam Steingold wrote:
> > since top /b never finishes, read(2) never returns EOF, and READ-LINE
> Sorry , it's incorrect.
> The "top -b" lists all the "top" processes once and quits.

it does not quit for me. linux man page says:

       b    Batch mode. Useful for sending output from top to  other  programs
            or  to  a  file.   In  this mode, top will not accept command line
            input.  It  runs  until  it  produces  the  number  of  iterations
            requested  with the n option or until killed. Output is plain text
            suitable for display on a dumb terminal.

> (close pipe) gets executed, we were both wrong (i've tested).
> We have a zombie here that we should wait() for.
> How can i call the system function?

I think closing the pipe fd is enough (note that CLISP does not use
popen(3) on linux, it uses pipe/execl).
(and a simple experiment shows that the pipe process goes away when the
pipe stream is CLOSEd).

> By my question i meant whether there are anomalities in the indentation,
> such that lispers that don't count parentheses would be confused.

not confused. rather the indentation does not offer as much information
as it could (especially the DO* form).

your indentation:

(defun handle-request (sock line)
         (let ((url (cut-url line)))
                 (format t "Url: ~A~%" url)
                 (cond
                         ((equal url "/")
                                 (start-html-response sock)
                                 (format sock "Hallo<br>"))
                         ((equal url "/shutdown")
                                 (start-html-response sock)
                                 (format sock "Going down ...<br>")
                                 ;(shell "logger _httpd will shut down
                                  the system")
                                 (setq do-shutdown t))
                         ((equal url "/top")
                                 (start-html-response sock)
                                 ;(format sock "<head><META
                                  http-equiv='Refresh'
                                  content='2'></head>")
                                 (format sock "<pre>")
                                 (do*
                                         ((pipe (make-pipe-input-stream
                                         "top -b"))
                                                 (str (read-line pipe nil)))
                                         ((not str) (close pipe) nil)
                                         (format sock "~A~%" str)
                                         (setq str (read-line pipe nil)))
                                 (format sock "</pre>"))
                         (t (err-not-found sock url)))))

Emacs:

(defun handle-request (sock line)
  (let ((url (cut-url line)))
    (format t "Url: ~A~%" url)
    (cond ((equal url "/")
           (start-html-response sock)
           (format sock "Hallo<br>"))
          ((equal url "/shutdown")
           (start-html-response sock)
           (format sock "Going down ...<br>")
           ;; (shell "logger _httpd will shut down the system")
           (setq do-shutdown t))
          ((equal url "/top")
           (start-html-response sock)
           ;; (format sock "<head><META http-equiv='Refresh' content='2'></head>")
           (format sock "<pre>")
           (do* ((pipe (make-pipe-input-stream "top -b"))
                 (str (read-line pipe nil)))
                ((not str) (close pipe) nil)
             (format sock "~A~%" str)
             (setq str (read-line pipe nil)))
           (format sock "</pre>"))
          (t (err-not-found sock url)))))

> (Not considering that tab here happens to be 8 spaces)

I think that the TAB character should better be avoided and the exact
number of spaces inserted instead.  But, as with the above, this is
just my personal preference.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Between grand theft and a legal fee, there only stands a law degree.
From: ilya
Subject: Re: tiny web server
Date: 
Message-ID: <newscache$tj777h$fy5$1@lnews.actcom.co.il>
Sam Steingold wrote:
>>* In message <······················@lnews.actcom.co.il>
>>* On the subject of "Re: tiny web server"
>>* Sent on Sun, 15 Dec 2002 23:18:38 +0200
>>* Honorable ilya <············@example.com> writes:
>>
>>Sam Steingold wrote:
>>
>>>since top /b never finishes, read(2) never returns EOF, and READ-LINE
>>
>>Sorry , it's incorrect.
>>The "top -b" lists all the "top" processes once and quits.
> 
> 
> it does not quit for me. linux man page says:
> 
>        b    Batch mode. Useful for sending output from top to  other  programs
>             or  to  a  file.   In  this mode, top will not accept command line
>             input.  It  runs  until  it  produces  the  number  of  iterations
>             requested  with the n option or until killed. Output is plain text
>             suitable for display on a dumb terminal.
> 
I'm really sorry that i haven't provided you the necessary information.
It's NetBSD box. "top -b" works there as i described (once).

(Strangely, the man doesn't say that)
        -b     Use "batch" mode.  In this mode, all input from the
               terminal is ignored.  Interrupt characters (such as
               ^C and ^\) still  have  an  effect.   This  is  the
               default  on  a dumb terminal, or when the output is
               not a terminal.

> 
>>(close pipe) gets executed, we were both wrong (i've tested).
>>We have a zombie here that we should wait() for.
>>How can i call the system function?
> 
> 
> I think closing the pipe fd is enough (note that CLISP does not use
> popen(3) on linux, it uses pipe/execl).
The process is already zombie by the time it gets SIGPIPE (or something 
like this) ...
> (and a simple experiment shows that the pipe process goes away when the
> pipe stream is CLOSEd).
Should be correct for non-zombies.
> 
> 
>>By my question i meant whether there are anomalities in the indentation,
>>such that lispers that don't count parentheses would be confused.
> 
> 
> not confused. rather the indentation does not offer as much information
> as it could (especially the DO* form).
I guess it's about the exit clause not indented otherwise than forms. 
You are definitely right here.
> 
> your indentation:
> 
> (defun handle-request (sock line)
>          (let ((url (cut-url line)))
>                  (format t "Url: ~A~%" url)
>                  (cond
>                          ((equal url "/")
>                                  (start-html-response sock)
>                                  (format sock "Hallo<br>"))
>                          ((equal url "/shutdown")
>                                  (start-html-response sock)
>                                  (format sock "Going down ...<br>")
>                                  ;(shell "logger _httpd will shut down
>                                   the system")
>                                  (setq do-shutdown t))
>                          ((equal url "/top")
>                                  (start-html-response sock)
>                                  ;(format sock "<head><META
>                                   http-equiv='Refresh'
>                                   content='2'></head>")
>                                  (format sock "<pre>")
>                                  (do*
>                                          ((pipe (make-pipe-input-stream
>                                          "top -b"))
>                                                  (str (read-line pipe nil)))
>                                          ((not str) (close pipe) nil)
>                                          (format sock "~A~%" str)
>                                          (setq str (read-line pipe nil)))
>                                  (format sock "</pre>"))
>                          (t (err-not-found sock url)))))
> 
> Emacs:
> 
> (defun handle-request (sock line)
>   (let ((url (cut-url line)))
>     (format t "Url: ~A~%" url)
>     (cond ((equal url "/")
>            (start-html-response sock)
>            (format sock "Hallo<br>"))
>           ((equal url "/shutdown")
>            (start-html-response sock)
>            (format sock "Going down ...<br>")
>            ;; (shell "logger _httpd will shut down the system")
>            (setq do-shutdown t))
>           ((equal url "/top")
>            (start-html-response sock)
>            ;; (format sock "<head><META http-equiv='Refresh' content='2'></head>")
>            (format sock "<pre>")
>            (do* ((pipe (make-pipe-input-stream "top -b"))
>                  (str (read-line pipe nil)))
>                 ((not str) (close pipe) nil)
>              (format sock "~A~%" str)
>              (setq str (read-line pipe nil)))
>            (format sock "</pre>"))
>           (t (err-not-found sock url)))))
> 
> 
>>(Not considering that tab here happens to be 8 spaces)
> 
> 
> I think that the TAB character should better be avoided and the exact
> number of spaces inserted instead.  But, as with the above, this is
> just my personal preference.

That's what VI does for lisp mode : spaces instead of tabs, and i don't 
like that. I think tabs should be used to enable different people use 
tabstop sizes they like...

-- 
(lisp-newbie-p ilya) => t
From: Sam Steingold
Subject: Re: tiny web server
Date: 
Message-ID: <m3znr6gets.fsf@loiso.podval.org>
> * In message <······················@lnews.actcom.co.il>
> * On the subject of "Re: tiny web server"
> * Sent on Mon, 16 Dec 2002 08:05:05 +0200
> * Honorable ilya <············@example.com> writes:
>
> Sam Steingold wrote:
> >>>since top /b never finishes, read(2) never returns EOF, and READ-LINE
> >>The "top -b" lists all the "top" processes once and quits.
> > it does not quit for me. linux man page says:
> >        b    Batch mode. Useful for sending output from top to  other programs
> >             or  to  a  file.   In  this mode, top will not accept command line
> >             input.  It  runs  until  it  produces  the  number  of  iterations
> >             requested  with the n option or until killed. Output is plain text
> >             suitable for display on a dumb terminal.
> > 
> I'm really sorry that i haven't provided you the necessary information.
> It's NetBSD box. "top -b" works there as i described (once).
> 
> (Strangely, the man doesn't say that)
>         -b     Use "batch" mode.  In this mode, all input from the
>                terminal is ignored.  Interrupt characters (such as
>                ^C and ^\) still  have  an  effect.   This  is  the
>                default  on  a dumb terminal, or when the output is
>                not a terminal.

it does not say that it quits after listing the processes once.
indeed it would be strange if it did for in that case 'top -b' would be
no different than 'ps'.
(OTOH, now 'top -b' is no different than 'while ps; do sleep 5; done')

could you please experiment with a less controversial program?
E.g., does 
        (close (make-pipe-input-stream "ls"))
create a zombie?

> >>(close pipe) gets executed, we were both wrong (i've tested).
> >>We have a zombie here that we should wait() for.
> >>How can i call the system function?
> > I think closing the pipe fd is enough (note that CLISP does not use
> > popen(3) on linux, it uses pipe/execl).
> The process is already zombie by the time it gets SIGPIPE (or something
> like this) ...

I thought that processes do not become zombies on their own - without
being killed.

> > (and a simple experiment shows that the pipe process goes away when the
> > pipe stream is CLOSEd).
> Should be correct for non-zombies.

so when does your `top' process become a zombie?

> >            (do* ((pipe (make-pipe-input-stream "top -b"))
> >                  (str (read-line pipe nil)))
> >                 ((not str) (close pipe) nil)
> >              (format sock "~A~%" str)
> >              (setq str (read-line pipe nil)))
> > 
> >>(Not considering that tab here happens to be 8 spaces)
> > I think that the TAB character should better be avoided and the exact
> > number of spaces inserted instead.  But, as with the above, this is
> > just my personal preference.
> 
> That's what VI does for lisp mode : spaces instead of tabs, and i
> don't like that. I think tabs should be used to enable different
> people use tabstop sizes they like...

if you look at the DO* example above, you will see that the indentation
difference between the second and the third line is 1.
this means that _I_ (and IMNSHO many other lispers who subscribe to the
CLTL/CLHS indentation style) would have to set the "tabstop size" to
_1_ to achieve this level of granularity, i.e., there will be no
difference between #\Tab and #\Space for us.

PS when I said above that not using TAB was just my personal preference,
   I meant that I do not use TAB even in C/Java where many people do,
   while I doubt that many lispers use TABs

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Even Windows doesn't suck, when you use Common Lisp
From: ilya
Subject: Re: tiny web server
Date: 
Message-ID: <newscache$g6287h$617$1@lnews.actcom.co.il>
Sam Steingold wrote:
[snip]
>>>>The "top -b" lists all the "top" processes once and quits.
> it does not say that it quits after listing the processes once.
but it does (tested from shell)
> indeed it would be strange if it did for in that case 'top -b' would be
> no different than 'ps'.
> (OTOH, now 'top -b' is no different than 'while ps; do sleep 5; done')
> 
> could you please experiment with a less controversial program?
> E.g., does 
>         (close (make-pipe-input-stream "ls"))
> create a zombie?

It shouldn't but it does (if consider this as "does") :

[10]> (dotimes (i 20) (close (make-pipe-input-stream "ls")))
NIL
[11]> (shell "top -b")
load averages:  0.07,  0.08,  0.08    18:53:00
37 processes:  16 sleeping, 20 zombie, 1 on processor
<and a second later>
[12]> (shell "top -b")
load averages:  0.07,  0.08,  0.08    18:53:03
17 processes:  16 sleeping, 1 on processor

They died by their own ...

> I thought that processes do not become zombies on their own - without
> being killed.
AFAIK they do when they are fork() childs of the parent and they finish
their job. The parent should wait() , till than - the child is zombie.
>>>(and a simple experiment shows that the pipe process goes away when the
>>>pipe stream is CLOSEd).
>>
>>Should be correct for non-zombies.
> 
> 
> so when does your `top' process become a zombie?
When it's done.
That means just after i get last text line and before
i get nil from (read-line).
> 
> 
>>>           (do* ((pipe (make-pipe-input-stream "top -b"))
>>>                 (str (read-line pipe nil)))
>>>                ((not str) (close pipe) nil)
>>>             (format sock "~A~%" str)
>>>             (setq str (read-line pipe nil)))

-- 
(lisp-newbie-p ilya) => t
From: Sam Steingold
Subject: Re: tiny web server
Date: 
Message-ID: <m3of7lhiwb.fsf@loiso.podval.org>
> * In message <······················@lnews.actcom.co.il>
> * On the subject of "Re: tiny web server"
> * Sent on Mon, 16 Dec 2002 19:06:40 +0200
> * Honorable ilya <············@example.com> writes:
>
> Sam Steingold wrote:
> > E.g., does         (close (make-pipe-input-stream "ls"))
> > create a zombie?
> 
> It shouldn't but it does (if consider this as "does") :
> 
> [10]> (dotimes (i 20) (close (make-pipe-input-stream "ls")))
> NIL
> [11]> (shell "top -b")
> load averages:  0.07,  0.08,  0.08    18:53:00
> 37 processes:  16 sleeping, 20 zombie, 1 on processor
> <and a second later>
> [12]> (shell "top -b")
> load averages:  0.07,  0.08,  0.08    18:53:03
> 17 processes:  16 sleeping, 1 on processor
> 
> They died by their own ...

a zombie that dies on its own is no zombie :-)
why worry about it?

CLISP DTRT but before that takes effect, you notice that your processes
had been zombies for a while.
I think this can be called a "race condition".

At any rate, this appears to be an OS problem, not a CLISP one, and a
very minor problem at that.  Why bother?

PS.  You are one of only two NetBSD CLISP user I know.
     Can I ask you to build a CLISP NetBSD binary package?
     Please contact me by e-mail.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
The early bird may get the worm, but the second mouse gets the cheese.
From: Raymond Wiker
Subject: Re: tiny web server
Date: 
Message-ID: <861y4hbpq5.fsf@raw.grenland.fast.no>
Sam Steingold <···@gnu.org> writes:

> a zombie that dies on its own is no zombie :-)
> why worry about it?

        In Un*x systems, dead processes are "reaped" by their parent
process. If the parent process has already terminated at that point,
the child process becomes a zombie. In some (all?) Un*x systems they
are eventually handed to "init" process.

        Anyway, whether a process dies on its own or is killed has no
bearing on whether or not it becomes a zombie.

-- 
Raymond Wiker                        Mail:  ·············@fast.no
Senior Software Engineer             Web:   http://www.fast.no/
Fast Search & Transfer ASA           Phone: +47 23 01 11 60
P.O. Box 1677 Vika                   Fax:   +47 35 54 87 99
NO-0120 Oslo, NORWAY                 Mob:   +47 48 01 11 60

Try FAST Search: http://alltheweb.com/
From: Daniel Barlow
Subject: Re: tiny web server
Date: 
Message-ID: <87adj5r2xj.fsf@noetbook.telent.net>
Raymond Wiker <·············@fast.no> writes:

>         In Un*x systems, dead processes are "reaped" by their parent
> process. If the parent process has already terminated at that point,
> the child process becomes a zombie. In some (all?) Un*x systems they
> are eventually handed to "init" process.
>
>         Anyway, whether a process dies on its own or is killed has no
> bearing on whether or not it becomes a zombie.

Nor, for that matter, does whether its parent is dead.  The child will
be a zombie until the parent executes wait() or waitpid() or a related
function.  

In this example the child exits immediately, while the parent sleeps
to give it a chance to finish, then runs ps(1) to show the relevant
processes -

:; perl -e '$a=fork(); if($a==0) { printf "child pid $$\n"; exit(0); } else { sleep(2); system("ps $$ $a");  }'
child pid 31632
  PID TTY      STAT   TIME COMMAND
31631 pts/6    S      0:00 perl -e $a=fork(); if($a==0) { printf "child pid $$\
31632 pts/6    Z      0:00 [perl <defunct>]

               ^ "the zombie walks" [1]


-dan

[1] http://www.ornl.gov/cts/archives/mailing-lists/tru64-unix-managers/1996/03/msg00586.html

-- 

   http://www.cliki.net/ - Link farm for free CL-on-Unix resources 
From: Tim Bradshaw
Subject: Re: tiny web server
Date: 
Message-ID: <ey3fzsw676j.fsf@cley.com>
* Daniel Barlow wrote:

> Nor, for that matter, does whether its parent is dead.  The child will
> be a zombie until the parent executes wait() or waitpid() or a related
> function.  

To be annoying, it is a zombie until whoever is currently its parent
waits for it.  If the parent is dead, this will be that process's
parent, and so on, until eventually you reach init, which does little
else other than sit & wait for processes to die (well: it also manages
runlevel changes on most (?) systems, which is another pretty major
task).

Someone once told me that, simply by looking at the terminology of
Unix you could infer that the people who originally wrote it did not
have children, because no one with children would ever invent this
terminology of parents waiting for their children to die and `reaping'
them...

--t
From: Harald Hanche-Olsen
Subject: Re: tiny web server
Date: 
Message-ID: <pco8yyo1d7q.fsf@thoth.math.ntnu.no>
+ Tim Bradshaw <···@cley.com>:

| * Daniel Barlow wrote:
| 
| > Nor, for that matter, does whether its parent is dead.  The child
| > will be a zombie until the parent executes wait() or waitpid() or
| > a related function.
| 
| To be annoying, it is a zombie until whoever is currently its parent
| waits for it.  If the parent is dead, this will be that process's
| parent, and so on, until eventually you reach init, which does
| little else other than sit & wait for processes to die

I want to be annoying too.  On every unix system where I investigated,
when a process dies, its children are inherited directly by init.  For
example, on FreeBSD, _exit(2):

  � The parent process-ID of all of the calling process's existing child
    processes are set to 1; the initialization process (see the
    DEFINITIONS section of intro(2)) inherits each of these processes.

Of course, as you say init is pretty good at what it does, so a zombie
with init for a parent will not remain a zombie for very long.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?
From: Tim Bradshaw
Subject: Re: tiny web server
Date: 
Message-ID: <ey3u1hc44n1.fsf@cley.com>
* Harald Hanche-Olsen wrote:

> I want to be annoying too.  On every unix system where I investigated,
> when a process dies, its children are inherited directly by init.  For
> example, on FreeBSD, _exit(2):

Yes, this obviously has to be true, I was confused!

--tim
From: Raymond Wiker
Subject: Re: tiny web server
Date: 
Message-ID: <86wum7aedb.fsf@raw.grenland.fast.no>
Harald Hanche-Olsen <······@math.ntnu.no> writes:

> + Tim Bradshaw <···@cley.com>:
> 
> | * Daniel Barlow wrote:
> | 
> | > Nor, for that matter, does whether its parent is dead.  The child
> | > will be a zombie until the parent executes wait() or waitpid() or
> | > a related function.
> | 
> | To be annoying, it is a zombie until whoever is currently its parent
> | waits for it.  If the parent is dead, this will be that process's
> | parent, and so on, until eventually you reach init, which does
> | little else other than sit & wait for processes to die
> 
> I want to be annoying too.  On every unix system where I investigated,
> when a process dies, its children are inherited directly by init.  For
> example, on FreeBSD, _exit(2):

        I'm *reasonably* sure that this was not true for certain SunOS
versions. The reason for that is that I wrote a small package for
monitoring critical servers at a previous employers; this package was
written in Perl but could call out to external
programs. Unfortunately, I had left out code to reap the
sub-processes, so the process table filled up and some of the servers
went gaga.

-- 
Raymond Wiker                        Mail:  ·············@fast.no
Senior Software Engineer             Web:   http://www.fast.no/
Fast Search & Transfer ASA           Phone: +47 23 01 11 60
P.O. Box 1677 Vika                   Fax:   +47 35 54 87 99
NO-0120 Oslo, NORWAY                 Mob:   +47 48 01 11 60

Try FAST Search: http://alltheweb.com/
From: Alexander Kjeldaas
Subject: Re: tiny web server
Date: 
Message-ID: <atplol$379$1@news.broadnet.no>
Harald Hanche-Olsen wrote:

> + Tim Bradshaw <···@cley.com>:
> 
> | * Daniel Barlow wrote:
> | 
> | > Nor, for that matter, does whether its parent is dead.  The child
> | > will be a zombie until the parent executes wait() or waitpid() or
> | > a related function.
> | 
> | To be annoying, it is a zombie until whoever is currently its parent
> | waits for it.  If the parent is dead, this will be that process's
> | parent, and so on, until eventually you reach init, which does
> | little else other than sit & wait for processes to die
> 
> I want to be annoying too.  On every unix system where I investigated,
> when a process dies, its children are inherited directly by init.  For
> example, on FreeBSD, _exit(2):
> 
>   � The parent process-ID of all of the calling process's existing child
>     processes are set to 1; the initialization process (see the
>     DEFINITIONS section of intro(2)) inherits each of these processes.
> 
> Of course, as you say init is pretty good at what it does, so a zombie
> with init for a parent will not remain a zombie for very long.
> 

Which is why the lazy programmer's trick to avoid zombies is to do a double
fork where the first forked child process immediately exits after forking a
second child.

astor
From: Sam Steingold
Subject: Re: tiny web server
Date: 
Message-ID: <m3r8cgehgs.fsf@loiso.podval.org>
> * In message <······················@lnews.actcom.co.il>
> * On the subject of "Re: tiny web server"
> * Sent on Tue, 17 Dec 2002 15:59:24 +0200
> * Honorable ilya <············@example.com> writes:
>
> Daniel Barlow wrote:
> [snip]
> > Nor, for that matter, does whether its parent is dead.  The child will
> > be a zombie until the parent executes wait() or waitpid() or a related
> > function.
> That's exactly the question.
> How do i call wait() from CLisp (On NetBSD) ?

CLISP already does it for you - see <src/spvw_sigcld.d>:

# Our general policy with child processes - in particular child processes
# to which we are connected through pipes - is not to wait for them, but
# instead do what init(1) would do in case our process terminates before
# the child: perform a non-blocking waitpid() and ignore the child's
# termination status.


-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
main(a){printf(a,34,a="main(a){printf(a,34,a=%c%s%c,34);}",34);}
From: Scott Schwartz
Subject: Re: tiny web server
Date: 
Message-ID: <8gy96oa5er.fsf@galapagos.cse.psu.edu>
Sam Steingold <···@gnu.org> writes:
> CLISP already does it for you - see <src/spvw_sigcld.d>:

You are using SIGCLD, which is obsolete.  The posix signal is SIGCHLD.

Moreover, you set SIGC*LD to SIG_IGN which is undefined in POSIX.

> # Our general policy with child processes - in particular child processes
> # to which we are connected through pipes - is not to wait for them, but
> # instead do what init(1) would do in case our process terminates before
> # the child: perform a non-blocking waitpid() and ignore the child's
> # termination status.

That seems very broken to me.  Unix programs expect to be able, *need
to be able*, to return exit status to their callers.  Why are you
throwing it away?