From: Ari Johnson
Subject: Socket Programming
Date: 
Message-ID: <zNfoc.112192$Jy3.183@fed1read03>
Howdy, all.  I'm working up an application to help myself become 
conversant in Lisp and CLOS, and I've run into a minor snag... 
Basically, I want the program to sit idle unless there is input waiting, 
a new connection has been made, an old connection has been closed, or it 
is time to do something (say, once per second).  It is interactive, so 
it can't just sit for a whole second when there is input waiting.

Connections will be made via TCP sockets.  I am using CLISP since it has 
the easiest-to-use socket facilities from what I can tell.  I have this 
part of it working, but the problem is I don't know how a Lisper would 
make it sleep under the conditions above.

How I've done the same thing in C is with select(2), giving as its input 
FD set each currently-open socket plus the FD for the listen(2) socket. 
  Giving select(2) a 1-second timeout or no timeout and using alarm(2) 
and a signal handler accomplishes what I want.

I can't see how to do this in CLISP, as there doesn't seem to be an 
operator that will wait on the right conditions.  Is there a portable 
socket library that does this better (avoiding my having to do any FFI 
coding), or a way to do it within the confines of CLISP?

Thanks.

Ari

From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcv65b2yorx.fsf@famine.OCF.Berkeley.EDU>
Ari Johnson <·····@hotmail.com> writes:

> Howdy, all.  I'm working up an application to help myself become 
> conversant in Lisp and CLOS, and I've run into a minor snag... 
> Basically, I want the program to sit idle unless there is input waiting, 
> a new connection has been made, an old connection has been closed, or it 
> is time to do something (say, once per second).  It is interactive, so 
> it can't just sit for a whole second when there is input waiting.

This is a great match for CMUCL's and SBCL's serve-event facility.
You can check out the docs here:

  http://www.pmsf.de/pub/cmucl/doc/cmu-user/serve-event.html

> Connections will be made via TCP sockets.  I am using CLISP since it has 
> the easiest-to-use socket facilities from what I can tell.  I have this 
> part of it working, but the problem is I don't know how a Lisper would 
> make it sleep under the conditions above.

I'm not sure with CLISP.  BTW, since you know C, SBCL has plain old
BSD sockets in the sb-bsd-sockets contrib module.  I find that the
easiest interface (y'know, since I already know it).

> How I've done the same thing in C is with select(2), giving as its input 
> FD set each currently-open socket plus the FD for the listen(2) socket. 
>   Giving select(2) a 1-second timeout or no timeout and using alarm(2) 
> and a signal handler accomplishes what I want.

I would do this using serve-event by setting up handlers for the FDs I
care about, then calling serve-event with a 1-second timeout.

Maybe a CLISP hacker can give you an answer for their neck of the
woods.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Andreas Yankopolus
Subject: Re: Socket Programming
Date: 
Message-ID: <m23c6534kq.fsf@stubb.local>
Ari,

The CLISP information notes
(http://clisp.sourceforge.net/impnotes.html) have a section on sockets
that should prove helpful. The analog to select() in CLISP is
socket:socket-status
(http://clisp.sourceforge.net/impnotes.html#so-status). I believe that
CLISP is TCP-only at this point (no UDP).

Cheers,

Andreas
From: Ari Johnson
Subject: Re: Socket Programming
Date: 
Message-ID: <RKzoc.124590$Jy3.24581@fed1read03>
Andreas Yankopolus wrote:
> The CLISP information notes
> (http://clisp.sourceforge.net/impnotes.html) have a section on sockets
> that should prove helpful. The analog to select() in CLISP is
> socket:socket-status
> (http://clisp.sourceforge.net/impnotes.html#so-status). I believe that
> CLISP is TCP-only at this point (no UDP).

Alright, I managed to pay attention to the fact that socket-status can 
include the socket-server in its list, which is a good thing, but now 
I'm wondering if there's a way to have it tell me how much time actually 
elapsed or, equivalently, how much of the timeout was left.  I want the 
non-network events to occur exactly once per second.  I could use the 
system timer or threads for this, but I don't know if there's a 
portable-between-Lisps way to do either of those any more than there is 
to do sockets in the first place.
From: Svein Ove Aas
Subject: Re: Socket Programming
Date: 
Message-ID: <gmUoc.1391$RL3.31965@news2.e.nsc.no>
Ari Johnson wrote:

> Andreas Yankopolus wrote:
>> The CLISP information notes
>> (http://clisp.sourceforge.net/impnotes.html) have a section on sockets
>> that should prove helpful. The analog to select() in CLISP is
>> socket:socket-status
>> (http://clisp.sourceforge.net/impnotes.html#so-status). I believe that
>> CLISP is TCP-only at this point (no UDP).
> 
> Alright, I managed to pay attention to the fact that socket-status can
> include the socket-server in its list, which is a good thing, but now
> I'm wondering if there's a way to have it tell me how much time actually
> elapsed or, equivalently, how much of the timeout was left.  I want the
> non-network events to occur exactly once per second.  I could use the
> system timer or threads for this, but I don't know if there's a
> portable-between-Lisps way to do either of those any more than there is
> to do sockets in the first place.

CLHS: get-current-real-time, perhaps?

Depends on what resolution you need.
From: Svein Ove Aas
Subject: Re: Socket Programming
Date: 
Message-ID: <4npoc.969$RL3.26920@news2.e.nsc.no>
Thomas F. Burdick wrote:

> I would do this using serve-event by setting up handlers for the FDs I
> care about, then calling serve-event with a 1-second timeout.

Having never used serve-event, would you say that it's approximately
equivalent to select?
From: =?iso-2022-jp-2?b?TmlscyBHGy5BG052c2NoZQ==?=
Subject: Re: Socket Programming
Date: 
Message-ID: <ly4qqlagp8.fsf@cartan.de>
Svein Ove Aas <··············@brage.info> writes:

> Thomas F. Burdick wrote:
> 
> > I would do this using serve-event by setting up handlers for the FDs I
> > care about, then calling serve-event with a 1-second timeout.
> 
> Having never used serve-event, would you say that it's approximately
> equivalent to select?

Well, decide for yourself:

http://www.pmsf.de/pub/cmucl/doc/cmu-user/serve-event.html#toc225

Frankly, I would prefer to do such a thing with threads.  Have a
thread waiting for TCP connections and nothing else, that will create
another thread for every client connecting to your program, and have
yet another thread waiting for other forms of input (and nothing
else).  Blocking reads all over the place.  Unfortunately, I don't
know if CLISP supports threads...

Regards,
-- 
Nils G.ANvsche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvy8nxxo6o.fsf@famine.OCF.Berkeley.EDU>
> Svein Ove Aas <··············@brage.info> writes:
> 
> > Thomas F. Burdick wrote:
> > 
> > > I would do this using serve-event by setting up handlers for the FDs I
> > > care about, then calling serve-event with a 1-second timeout.
> >
> > Having never used serve-event, would you say that it's approximately
> > equivalent to select?

Imagine if `select' had been done right.  It uses select down in its
guts, but it's a much better interface (for one thing, it's
declarative, since you associate handlers with things).  But yes, just
as FORMAT is kind of like printf, SERVE-EVENT is kind of like select :-)

···@cartan.de (=?iso-2022-jp-2?b?TmlscyBHGy5BG052c2NoZQ==?=) writes:

> Frankly, I would prefer to do such a thing with threads.  Have a
> thread waiting for TCP connections and nothing else, that will create
> another thread for every client connecting to your program, and have
> yet another thread waiting for other forms of input (and nothing
> else).  Blocking reads all over the place.  Unfortunately, I don't
> know if CLISP supports threads...

That sounds easier or simpler to you?!?!

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Steven E. Harris
Subject: Re: Socket Programming
Date: 
Message-ID: <q67fza5ch3f.fsf@L75001820.us.ray.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> It uses select down in its guts, but it's a much better interface
> (for one thing, it's declarative, since you associate handlers with
> things).

Can serve-event dispatch timer expiry? I looked at the documentation
today, but found nothing sounding like "timer" or "timeout" as a
possible event to fire.

By way of analogy, serve-event sounds like the ACE library's Reactor
framework�, which includes, in addition to file descriptor and socket
dispatching, things such as timer expiry, queue readiness transitions,
and arbitrary user-to-handler notifications.


Footnotes: 
� http://www.dre.vanderbilt.edu/Doxygen/Current/html/ace/classACE__Reactor.html
  http://www.cs.wustl.edu/~schmidt/ACE-papers.html#reactor
  http://www.cs.wustl.edu/~schmidt/PDF/reactor-rules.pdf

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvn04dxfo3.fsf@famine.OCF.Berkeley.EDU>
"Steven E. Harris" <········@raytheon.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > It uses select down in its guts, but it's a much better interface
> > (for one thing, it's declarative, since you associate handlers with
> > things).
> 
> Can serve-event dispatch timer expiry? I looked at the documentation
> today, but found nothing sounding like "timer" or "timeout" as a
> possible event to fire.

Nope, it only lets you setup handlers for Unix FDs and X11 events.
That said, I don't think it would be too hard to add time events to
it, using an interval timer and a pipe.  I haven't had a need to yet,
though.

> By way of analogy, serve-event sounds like the ACE library's Reactor
> framework�, which includes, in addition to file descriptor and socket
> dispatching, things such as timer expiry, queue readiness transitions,
> and arbitrary user-to-handler notifications.

Yeah, that's a better comparison than plain `select'.  The problem
with these analogies, though, is that the Lisp solution tends to be
elegant, where lesser languages are painful.  The other difference is
that SERVE-EVENT is built into CMUCL and SBCL, which means all the
standard Lisp I/O functions play nicely with it.  Just glancing at the
Reactor docs, it looks like they give you ACE_HANDLEs for I/O, which
I'd imagine play nicely with their event loop.  However, if I run some
godaweful query on Postgres, I'm going to be blocked reading from the
socket; or, I'd have to use an ACE-specific socket facility.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Aleksandr Skobelev
Subject: Re: Socket Programming
Date: 
Message-ID: <m11xlo603f.fsf@askomac.add.com>
"Steven E. Harris" <········@raytheon.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > It uses select down in its guts, but it's a much better interface
> > (for one thing, it's declarative, since you associate handlers with
> > things).
> 
> Can serve-event dispatch timer expiry? I looked at the documentation
> today, but found nothing sounding like "timer" or "timeout" as a
> possible event to fire.
> 

[...]


Some time ago, when I was playing with CLM, I added serve-timer facility
to CMUCL's serve-event. So, I could post that code here if somebody interested
in it. 
From: Rob Warnock
Subject: Re: Socket Programming
Date: 
Message-ID: <cZidnWrCFK5sujndRVn-jA@speakeasy.net>
Aleksandr Skobelev  <····@envion.spb.ru> wrote:
+---------------
| Some time ago, when I was playing with CLM, I added serve-timer facility
| to CMUCL's serve-event. So, I could post that code here if somebody
| interested in it. 
+---------------

Yes, please!


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Aleksandr Skobelev
Subject: Re: Socket Programming
Date: 
Message-ID: <m13c635r7m.fsf@askomac.add.com>
--=-=-=

····@rpw3.org (Rob Warnock) writes:

> Aleksandr Skobelev  <····@envion.spb.ru> wrote:
> +---------------
> | Some time ago, when I was playing with CLM, I added serve-timer facility
> | to CMUCL's serve-event. So, I could post that code here if somebody
> | interested in it. 
> +---------------
> 
> Yes, please!
> 

Below are the attached files serve-event.patch and serve-timer.lisp. 
The first contains a patch for serve-event.lisp file from code directory
in the CMUCL's source tree. The second is realization of the facility.

Just load serve-timer.lisp and then serve-event.lisp patched with
serve-event.patch. Be ware that serve-timer.lisp file has to be loaded
before the patched serve-event.lisp file. 

The patch just adds calls to the ext::adjust-timeout and
ext::serve-timers functions from serve-timer.lisp into the
sub-serve-event function.

It seems to me that this code is working :), but I wrote it a more then year
ago and didn't use it only for writing simple code snippet from CLM
manual.

So, any comments/patches are welcome.




--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment; filename=serve-event.patch

--- serve-event.lisp	Fri May 14 12:14:58 2004
+++ serve-event-patched.lisp	Wed May 12 13:54:20 2004
@@ -5,7 +5,7 @@
@@ -471,6 +470,9 @@
       (setf to-usec *max-event-to-usec*)
       (setf call-polling-fn t))
 
+    (multiple-value-bind (ts tu) (ext::adjust-timeout to-sec to-usec)
+      (setf to-sec ts to-usec tu))
+    
     ;; Next, wait for something to happen.
     (alien:with-alien ((read-fds (alien:struct unix:fd-set))
 		       (write-fds (alien:struct unix:fd-set)))
@@ -484,6 +486,7 @@
 	
 	  ;; Now see what it was (if anything)
 	  (cond (value
+                  (ext::serve-timers)
 		 (cond ((zerop value)
 			;; Timed out.
 			(when call-polling-fn

--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=serve-timer.lisp

(in-package "EXT")

(export '(add-timer remove-timer start-timer stop-timer set-interval))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(eval-when (:compile-toplevel :load-toplevel :execute)
  #+(and)
  (defun declare-opt (&rest decls)
    `(declare (optimize (speed 3) (space 0) (debug 1) (safety 0))
      ,@decls))
  
  #-(and)
  (defun declare-opt (&rest decls)
    `(declare (optimize (speed 0) (space 0) (debug 3) (safety 3))
      ,@decls))
  
  ) ;;eval-when


;; (declaim (start-block add-timer remove-timer
;;                       start-timer stop-timer set-interval
;;                       serve-timers adjust-timeout))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(declaim (inline get-time))
(defun get-time ()
  (declare (values (signed-byte 32) (signed-byte 32)))
  (multiple-value-bind (e s u) (unix:unix-gettimeofday)
    (declare (ignore e))
    (values s u)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(declaim (inline time-norm))
(defun time-norm (sec usec)
  #.(declare-opt '(type integer sec usec)
                 '(values (signed-byte 32) (mod 1000000)))
  (unless (<= 0 usec 999999)
    (multiple-value-bind (s u) (floor usec 1000000)
      (setf sec (+ sec s) usec u)))
  (if (< sec 0)
    (values 0 0)
    (if (< #x7fffffff sec)
      (values #x7fffffff  usec)
      (values sec  usec))))

          
(declaim (inline time+))
(defun time+ (v1-sec v1-usec v2-sec v2-usec)
  #.(declare-opt '(type (signed-byte 32) v1-sec v2-sec)
                 '(type (mod 1000000) v1-usec v2-usec)
                 '(values (signed-byte 32) (mod 1000000)))
  
    (time-norm (+ v1-sec v2-sec) (+ v1-usec v2-usec)))


(declaim (inline time-))
(defun time- (v1-sec v1-usec v2-sec v2-usec)
  #.(declare-opt '(type (signed-byte 32) v1-sec v2-sec)
                 '(type (mod 1000000) v1-usec v2-usec)
                 '(values (unsigned-byte 32) (mod 1000000)))
  
    (time-norm (- v1-sec v2-sec) (- v1-usec v2-usec)))
  

(declaim (inline time<))
(defun time< (v1-sec v1-usec v2-sec v2-usec)
  #.(declare-opt '(type (signed-byte 32) v1-sec v2-sec)
                 '(type (mod 1000000) v1-usec v2-usec)
                 '(values boolean))
  (or (< v1-sec v2-sec)
      (and (= v1-sec v2-sec) (< v1-usec v2-usec))))



(declaim (inline interval-norm))
(defun interval-norm (interval-ms)
  #.(declare-opt '(type integer interval-ms)
                 '(values (signed-byte 32) (mod 1000000)))
  (multiple-value-bind (s m) (floor interval-ms 1000)
    (time-norm s (* m 1000))))


;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (defparameter *log* "/tmp/serve-timer.log")

;; (defun printlog (fmt &rest args)
;;   (with-open-file (log *log* :direction ':output :if-exists ':append
;;                        :if-does-not-exist ':create)
    
;;     (multiple-value-bind (e s u) (unix:unix-gettimeofday)
;;       (declare (ignore e))
;;       (multiple-value-bind (sc mn hr)
;;           (decode-universal-time (+ 2208988800 s))
;;         (apply #'format log
;;                (concatenate 'string "~&<~2,'0D:~2,'0D:~2,'0D.~3,'0D> " fmt "~%")
;;                hr mn sc (truncate u 1000) 
;;                args)))
;;     (force-output log)))
                       

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar *next-id* 0)
(defparameter *timers* nil
  "The plist of all timers.")

(defparameter *active-timers* nil
  "The list of active timers that will be handled by SERVE-TIMERS.
The elements in this list are represented as (TIMER-ID SEC USEC) list, where
SEC and USEC is an absolute time as UNIX:UNIX-GETTIMEOFDAY gives it,
when the timer procedure has to be run.")

(defparameter *current-timer* nil
  "Set to a current timer during the timer handling")


(defstruct (timer);; (:print-function print-timer))
  (id (incf *next-id*) :type (unsigned-byte 32))
  (isec  0 :type (signed-byte 32))
  (iusec 0 :type (signed-byte 32))
  (once-p   nil :type boolean)
  (active-p nil :type boolean)
  (remove-p nil :type boolean)
  handler
  data)


(defun print-timer (timer stream level)
  (declare (ignore level))
  (print-unreadable-object
      (timer stream :type t :identity t)
    (format stream "ID: ~D INTERVAL: ~D.~3,'0D HANDLER: ~S"
            (timer-id timer)
            (timer-isec timer)
            (truncate (timer-iusec timer) 1000)
            (timer-handler timer))))


(declaim (inline %get-timer))
(defun %get-timer (id)
  (getf *timers* id))

(declaim (inline %set-timer))
(defun %set-timer (timer)
  (setf (getf *timers* (timer-id timer)) timer)
  (timer-id timer))
    
(declaim (inline %del-timer))
(defun %del-timer (id)
  (remf *timers* id))
    
           
(declaim (inline %activate-timers))
(defun %activate-timer (timer sec usec)
  #.(declare-opt)
  (let ((tm (list (timer-id timer) sec usec)))
    (flet ((tm< (l r)
             (time< (cadr l) (caddr l) (cadr r) (caddr r))))
      
      (setf *active-timers* (merge 'list *active-timers* (list tm) #'tm<)
            (timer-active-p timer) t))))


(declaim (inline %desactivate-timers))
(defun %disactivate-timer (timer)
  #.(declare-opt)
  (setf (timer-active-p timer) nil
        *active-timers* (delete (timer-id timer) *active-timers* :key #'car)))


    
                        
(defun add-timer (interval-ms
                  handler client-data
                  &key (active t) (once nil) (remove nil))
  #.(declare-opt)
  (check-type interval-ms (integer 0 *) "a positive integer")
  (multiple-value-bind (ns nu) (get-time)
    (multiple-value-bind (is iu) (interval-norm interval-ms)
      (multiple-value-bind (sc us) (time+ ns nu is iu)
        
        (let* ((tm (make-timer :isec is :iusec iu
                               :once-p once
                               :remove-p remove
                               :handler handler
                               :data client-data)))
          (%set-timer tm)
          (when active (%activate-timer tm sc us))
          (timer-id tm))))))

  
(defun remove-timer (timer-id)
  #.(declare-opt)
  (let ((tm (%get-timer timer-id)))
    (when tm
      (%disactivate-timer tm)
      (%del-timer timer-id))))

(defun stop-timer (timer-id)
  #.(declare-opt)
  (let ((tm (%get-timer timer-id)))
    (when tm
      (%disactivate-timer tm)
      (when (timer-remove-p tm) (%del-timer timer-id)))))


;;How to start / stop a timer from a handler?  
(defun start-timer (timer-id &optional (interval-ms))
  #.(declare-opt)
  (check-type interval-ms (or nil (integer 0 *)) "a NIL or positive integer")

  (let ((tm (%get-timer timer-id)))
    (when tm
      (when (timer-active-p tm)
        (cerror "Stop timer #~D" "Starting activated timer #~D"
                timer-id)
        (stop-timer timer-id))
      
      (multiple-value-bind (ns nu) (get-time)
        (when interval-ms
          (multiple-value-bind (is iu) (interval-norm interval-ms)
            (setf (timer-isec tm) is (timer-iusec tm) iu)))
        
        (multiple-value-bind (sc us)
            (time+ ns nu (timer-isec tm) (timer-iusec tm))
          (%activate-timer tm sc us)))
      timer-id)))


(defun  set-timer-interval (timer-id interval-ms)
  #.(declare-opt)
  (check-type interval-ms integer)
  (let ((tm (%get-timer timer-id)))
    (when tm
      (multiple-value-bind (is iu) (interval-norm interval-ms)
        (setf (timer-isec tm) is (timer-iusec tm) iu))
      timer-id)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun adjust-timeout (to-sec to-usec)
  (let ((ti (car *active-timers*)))
    (if (and ti (not *current-timer*)) ;;to prevent recursive timers handling
      (multiple-value-bind (ns nu) (get-time)
        (multiple-value-bind (ds du) (time- (cadr ti) (caddr ti) ns nu)
          (if (time< ds du to-sec to-usec)
            (values ds du)
            (values to-sec to-usec))))
      
      (values to-sec to-usec))))
  
 
(defun  serve-timers ()
  (let ((ti (car *active-timers*)))
    (when (and ti (not *current-timer*)) ;;to prevent recursive timers handling
      (let ((tid (car ti))
            (tsc (cadr ti))
            (tus (caddr ti)))
           
        (multiple-value-bind (ns nu) (get-time)
          ;;(printlog "(serve-timers)")
          (when (time< ns nu tsc tus) (return-from serve-timers)))

        (setf *active-timers* (cdr *active-timers*))
        (let ((tm (%get-timer tid)))
          (when (and tm (timer-active-p tm))

            (if (timer-once-p tm)
              (setf (timer-active-p tm) nil) 
              
              (multiple-value-bind (ts-next tu-next)
                  (time+ tsc tus (timer-isec tm) (timer-iusec tm))
                (%activate-timer tm ts-next tu-next)))
              
            (ext:letf ((*current-timer* tm))
              (handler-bind
                ((error
                  #'(lambda (c)
                      (%disactivate-timer tm)
                      (error c))))
                ;;(printlog "(serve-timers): will call handler for ~S" tm)
                (funcall (timer-handler tm) tid (timer-data tm))
                (when (and (not (timer-active-p tm)) (timer-remove-p tm))
                  (%del-timer tid))))
            ))))))

;; (declaim (end-block))

--=-=-=--
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87n04d0zoj.fsf@david-steuber.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> ···@cartan.de (=?iso-2022-jp-2?b?TmlscyBHGy5BG052c2NoZQ==?=) writes:
> 
> > Frankly, I would prefer to do such a thing with threads.  Have a
> > thread waiting for TCP connections and nothing else, that will create
> > another thread for every client connecting to your program, and have
> > yet another thread waiting for other forms of input (and nothing
> > else).  Blocking reads all over the place.  Unfortunately, I don't
> > know if CLISP supports threads...
> 
> That sounds easier or simpler to you?!?!

He is not the only one.  A decent threading model means you don't have
to manualy hop around input streams to see if something is waiting for
you.  The overall application is simpler.  The portion of the code
that actualy deals with the input has to wait for it anyway.  So just
do a blocking read to get the input, then do a blocking write to send
the output.  From the point of view of that section of code, only one
thing is going on: read, eval, print. :-)

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvisf1x82t.fsf@famine.OCF.Berkeley.EDU>
David Steuber <·····@david-steuber.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > ···@cartan.de (=?iso-2022-jp-2?b?TmlscyBHGy5BG052c2NoZQ==?=) writes:
> > 
> > > Frankly, I would prefer to do such a thing with threads.  Have a
> > > thread waiting for TCP connections and nothing else, that will create
> > > another thread for every client connecting to your program, and have
> > > yet another thread waiting for other forms of input (and nothing
> > > else).  Blocking reads all over the place.  Unfortunately, I don't
> > > know if CLISP supports threads...
> > 
> > That sounds easier or simpler to you?!?!
> 
> He is not the only one.  A decent threading model means you don't have
> to manualy hop around input streams to see if something is waiting for
> you.  The overall application is simpler.

Of course it is: you just compared "a decent threading model" with a
piss-poor event server.  I'm not saying threads are no use, but using
them simply to get nonblocking I/O seems overkill to me.

> The portion of the code that actualy deals with the input has to
> wait for it anyway.  So just do a blocking read to get the input,
> then do a blocking write to send the output.  From the point of view
> of that section of code, only one thing is going on: read, eval,
> print. :-)

With a decent event server, you setup handlers on the inputs your
application is interested in.  Those handlers use the system's normal
I/O facilities.  All the I/O simplicity you get from threads, with
very little of the hair.

To give you an idea, you might write a serve-event server like this:

  (defvar *db-connections* ())

  (defun get-db-connection ()
    (or (pop *db-connections*)
        (connect-to-database ...)))

  (defun done-with-connection (db)
    (push db *db-connections*))

  (defvar *server-socket* ...)

  (defun serve-connection (fd)
    (declare (ignore fd))
    (let* ((socket (socket-accept *server-socket*))
           (client (socket-make-stream socket :input t :output t))
           (db (get-db-connection)))
      ... normal I/O here, read-line and such ...
      (done-with-connection db)
      (close client)
      (socket-close socket)))

  (socket-bind ...)
  (socket-listen ...)
  (add-fd-handler (socket-file-descriptor *server-socket*)
                  :input #'serve-connection)

  ;; You probably don't need this, because the repl calls it
  ;; (loop (serve-event))

Notice how, unlike after reading a `select' example, you're not
doubled over with pain right now.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <871xloo5v0.fsf@david-steuber.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Of course it is: you just compared "a decent threading model" with a
> piss-poor event server.  I'm not saying threads are no use, but using
> them simply to get nonblocking I/O seems overkill to me.

[Nice example snipped]

> Notice how, unlike after reading a `select' example, you're not
> doubled over with pain right now.

Heh.  I'm used to languages that suck.  I had no idea Lisp had this.

If all I wanted was just nonblocking I/O, I think I would go with what
you have just demonstrated.  My reason for wanting threads is to deal
with concurrent requests
-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Alex Tibbles
Subject: Re: Socket Programming
Date: 
Message-ID: <40a38633$0$6327$65c69314@mercury.nildram.net>
"Thomas F. Burdick" <···@famine.OCF.Berkeley.EDU> wrote in message
····················@famine.OCF.Berkeley.EDU...
> To give you an idea, you might write a serve-event server like this:
>
>   (defvar *db-connections* ())
>
>   (defun get-db-connection ()
>     (or (pop *db-connections*)
>         (connect-to-database ...)))
>
>   (defun done-with-connection (db)
>     (push db *db-connections*))
>
>   (defvar *server-socket* ...)
>
>   (defun serve-connection (fd)
>     (declare (ignore fd))
could you explain (to the clueless) why you use this declaration?

[...function body...]

[.. etcetera...]

> Notice how, unlike after reading a `select' example, you're not
> doubled over with pain right now.
nice

alex
From: Nils Gösche
Subject: Re: Socket Programming
Date: 
Message-ID: <87zn8c7znc.fsf@darkstar.cartan.de>
"Alex Tibbles" <············@yahoo.co.uk> writes:

> "Thomas F. Burdick" <···@famine.OCF.Berkeley.EDU> wrote in message
> ····················@famine.OCF.Berkeley.EDU...
> >   (defun serve-connection (fd)
> >     (declare (ignore fd))

> could you explain (to the clueless) why you use this declaration?

With the IGNORE declaration, you tell the compiler that you're not
going to use the variable FD, and it will thank you by not printing an
unused-variable warning at compile time.  Note that you'll have to
keep your promise.  In generated code (notably in macros), you
sometimes don't know in advance if a certain variable will be used or
not (or you're too lazy to find out).  In these cases, you'll use
IGNORABLE instead.

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Luke Gorrie
Subject: Re: Socket Programming
Date: 
Message-ID: <lhbrksz9tg.fsf@dodo.bluetail.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

>   (defun serve-connection (fd)
>     (declare (ignore fd))
>     (let* ((socket (socket-accept *server-socket*))
>            (client (socket-make-stream socket :input t :output t))
>            (db (get-db-connection)))
>       ... normal I/O here, read-line and such ...
>       (done-with-connection db)
>       (close client)
>       (socket-close socket)))

[...]

> Notice how, unlike after reading a `select' example, you're not
> doubled over with pain right now.

Well, not yet. :-)

There are heavy constraints on the "normal I/O here, read-line and
such" code. If your SERVE-EVENT handler makes a blocking call to
READ-LINE then Lisp will freeze until a whole line has been read. If
the guy on the other end of the socket has a slow connection, or has
fallen off the internet, or is deliberately withholding the data, then
this could take several minutes to time-out. It's not very robust.

I believe you can set your file descriptors non-blocking and then
would-be blocking operations will implicitly call SERVE-EVENT to
dispatch other requests while waiting for the data. However, writing
concurrent programs with blocking operations via a recursive
event-loop is a very hairy business (ask any Elisp hacker).

It's a good experience to write a few programs like this in Erlang,
just to see how simple and easy it can be.

P.S. I'm aware of two popular styles of concurrent programming in
Lisp: SERVE-EVENT-style and pthreads-like multithreading. Are there
some other interesting styles in the Lisp literature?

Cheers,
Luke
From: Raymond Wiker
Subject: Re: Socket Programming
Date: 
Message-ID: <86zn8co0so.fsf@raw.grenland.fast.no>
Luke Gorrie <····@bluetail.com> writes:

> P.S. I'm aware of two popular styles of concurrent programming in
> Lisp: SERVE-EVENT-style and pthreads-like multithreading. Are there
> some other interesting styles in the Lisp literature?

        This one, for example:

        http://www.hulver.com/scoop/story/2004/3/11/154543/749

        I *think* this is closer to Erlang and Occam style; it's
certainly an improvement on pthreads style :-)

-- 
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: Luke Gorrie
Subject: Re: Socket Programming
Date: 
Message-ID: <lhhdudk45s.fsf@dodo.bluetail.com>
Raymond Wiker <·············@fast.no> writes:

>         This one, for example:
>
>         http://www.hulver.com/scoop/story/2004/3/11/154543/749
>
>         I *think* this is closer to Erlang and Occam style; it's
> certainly an improvement on pthreads style :-)

I've read that article, I think it's pretty stylish programming.

As I understand it, PLT Scheme used the design from Concurrent ML,
which is a lot like Hoare's CSP [*]. It's quite similar to Erlang in
using explicit protocols to communicate and synchronize rather than
shared state and mutexes.

You could use threads to program similarly in Common Lisp too. I'm not
sure how to get the same overall feel, but if it's possible it would
be a great thing.

One challenge seems to be isolating threads from implicit interactions
through shared variables and data structures, so that you don't have
to do "thread-safety audits" of all your code. In Erlang this isn't a
problem because the non-concurrent code is essentially purely
functional; I don't know about in PLT.

Another is making threads themselves cheap enough that you needn't
hestitate to create hundreds of them. Otherwise you'll end up falling
back to SERVE-EVENT in the end, anyway. We must avoid having to do
"stack-depth audits" too, of course :-)

An interesting problem!

Cheers,
Luke

[*]: Communicating Sequential Processes, C.A.R. Hoare
     http://www.usingcsp.com/
     (They have the whole book in PDF. Good reading!)
From: Kenny Tilton
Subject: Back In the Day [was Re: Socket Programming]
Date: 
Message-ID: <f06747e2.0406030744.6a476ca6@posting.google.com>
Luke Gorrie <····@bluetail.com> wrote in message news:<··············@dodo.bluetail.com>...
> [*]: Communicating Sequential Processes, C.A.R. Hoare
>      http://www.usingcsp.com/
>      (They have the whole book in PDF. Good reading!)

Just stumbled onto that again while studying up for Cells/CSP, was
"excited" to spot:

"3. The proposed implementations are unusual in that they use a very
simple
purely functional subset of the well-known programming language LISP.
This will afford additional excitement to those who have access to a
LISP
implementation on which to exercise and demonstrate their designs."

Well-known! In 1985, of course. :)

kenny
From: Nils Gösche
Subject: Re: Socket Programming
Date: 
Message-ID: <87u0yk7zho.fsf@darkstar.cartan.de>
Luke Gorrie <····@bluetail.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Notice how, unlike after reading a `select' example, you're not
> > doubled over with pain right now.
> 
> Well, not yet. :-)
> 
> There are heavy constraints on the "normal I/O here, read-line and
> such" code. If your SERVE-EVENT handler makes a blocking call to
> READ-LINE then Lisp will freeze until a whole line has been read.

That would make the SERVE-EVENT thing unusable (IMHO); however, in an
earlier posting, Thomas told me that if an I/O call blocks, Lisp will
schedule and make event-handling for other fd's possible, much like
what happens with normal threads.  Which is correct?

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvad0bxwn1.fsf@famine.OCF.Berkeley.EDU>
···@cartan.de (Nils G�sche) writes:

> Luke Gorrie <····@bluetail.com> writes:
> 
> > ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> > 
> > > Notice how, unlike after reading a `select' example, you're not
> > > doubled over with pain right now.
> > 
> > Well, not yet. :-)
> > 
> > There are heavy constraints on the "normal I/O here, read-line and
> > such" code. If your SERVE-EVENT handler makes a blocking call to
> > READ-LINE then Lisp will freeze until a whole line has been read.
> 
> That would make the SERVE-EVENT thing unusable (IMHO); however, in an
> earlier posting, Thomas told me that if an I/O call blocks, Lisp will
> schedule and make event-handling for other fd's possible, much like
> what happens with normal threads.  Which is correct?

What I described iis what *should* happen.  Maybe Luke ran into the
read-sequence bug I just noticed, and thought it was the correct
behavior.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvd657xwpe.fsf@famine.OCF.Berkeley.EDU>
Luke Gorrie <····@bluetail.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> >   (defun serve-connection (fd)
> >     (declare (ignore fd))
> >     (let* ((socket (socket-accept *server-socket*))
> >            (client (socket-make-stream socket :input t :output t))
> >            (db (get-db-connection)))
> >       ... normal I/O here, read-line and such ...
> >       (done-with-connection db)
> >       (close client)
> >       (socket-close socket)))
> 
> [...]
> 
> > Notice how, unlike after reading a `select' example, you're not
> > doubled over with pain right now.
> 
> Well, not yet. :-)
> 
> There are heavy constraints on the "normal I/O here, read-line and
> such" code. If your SERVE-EVENT handler makes a blocking call to
> READ-LINE then Lisp will freeze until a whole line has been read. If
> the guy on the other end of the socket has a slow connection, or has
> fallen off the internet, or is deliberately withholding the data, then
> this could take several minutes to time-out. It's not very robust.

With stream buffering, this shouldn't be a problem.  However, having
just done a quick check, it looks like read-sequence has a bug here.
The stream interface *should* take care of this for you, though, bugs
not withstanding.

> I believe you can set your file descriptors non-blocking and then
> would-be blocking operations will implicitly call SERVE-EVENT to
> dispatch other requests while waiting for the data. However, writing
> concurrent programs with blocking operations via a recursive
> event-loop is a very hairy business (ask any Elisp hacker).

As an Elisp hacker, I agree; as a CL hacker, I haven't had a problem.
I think it's proper closures that make the difference, but I'm not
sure.  I've found fewer gotchas than in multithreaded programming.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Aurélien Campéas
Subject: Re: Socket Programming
Date: 
Message-ID: <pan.2004.05.30.17.06.38.372502@wanadoo.fr>
Le Thu, 13 May 2004 16:22:03 +0200, Luke Gorrie a �crit�:

> 
> P.S. I'm aware of two popular styles of concurrent programming in
> Lisp: SERVE-EVENT-style and pthreads-like multithreading. Are there
> some other interesting styles in the Lisp literature?
> 
> Cheers,
> Luke

In http://library.readscheme.org/page9.html, see


Extension of Scheme for Parallel and Concurrent Programming

also

Futures and Multi-Lisp

FYI.
Aur�lien.
From: Antony Sequeira
Subject: Re: Socket Programming
Date: 
Message-ID: <0NNoc.48040$zT.18636@newssvr29.news.prodigy.com>
Thomas F. Burdick wrote:
> 
> To give you an idea, you might write a serve-event server like this:
> 
>   (defvar *db-connections* ())
> 
>   (defun get-db-connection ()
>     (or (pop *db-connections*)
>         (connect-to-database ...)))
> 
>   (defun done-with-connection (db)
>     (push db *db-connections*))
> 
>   (defvar *server-socket* ...)
> 
>   (defun serve-connection (fd)
>     (declare (ignore fd))
>     (let* ((socket (socket-accept *server-socket*))
>            (client (socket-make-stream socket :input t :output t))
>            (db (get-db-connection)))
>       ... normal I/O here, read-line and such ...
>       (done-with-connection db)
>       (close client)
>       (socket-close socket)))
> 
>   (socket-bind ...)
>   (socket-listen ...)
>   (add-fd-handler (socket-file-descriptor *server-socket*)
>                   :input #'serve-connection)
> 
>   ;; You probably don't need this, because the repl calls it
>   ;; (loop (serve-event))
> 
> Notice how, unlike after reading a `select' example, you're not
> doubled over with pain right now.
> 
A few questions about the code above-
1. Is it possible to pass a bit more context into the serve-connection 
call, other than just the fd. For example , some sort of call context 
object. I guess a workaround is to have a hash table that maps a fd to 
whatever context I need, or can serve-connection be a closure per fd ?
2. Do you have code that lets you use this in implementations that do 
not have things like add-fd-handler

I want to confess up front that I am a newbie, I have been doing a lot 
of reading on Lisp, but not enough coding :(
Thanks for the code above.
-Antony
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcv7jvfxvvk.fsf@famine.OCF.Berkeley.EDU>
Antony Sequeira <·············@hotmail.com> writes:

> A few questions about the code above-
> 1. Is it possible to pass a bit more context into the serve-connection 
> call, other than just the fd. For example , some sort of call context 
> object. I guess a workaround is to have a hash table that maps a fd to 
> whatever context I need, or can serve-connection be a closure per fd ?

SERVE-EVENT calls your handler, and passes the FD.  You were on the
right path with the closure idea, though.  If you want more context,
you do it like:

  (add-fd-handler fd <direction>
                  (lambda (fd) (my-handler fd context more-context)))

> 2. Do you have code that lets you use this in implementations that do 
> not have things like add-fd-handler

I feel like Frankie Beverly:

  * the joy of SERVE-EVENT is that it's built into CMUCL and SBCL, and
    they use it themselves (eg, for the repl)

  * the pain, it's only in SBCL and CMUCL

  * the sunshine, because it's built into the implementation at a
    fairly low level, the basic CL I/O functions work hand-in-hand
    with it.

  * the rain, if you write a portable version, you won't get that
    low-level integration.

> I want to confess up front that I am a newbie, I have been doing a lot 
> of reading on Lisp, but not enough coding :(
> Thanks for the code above.

No problem.  I highly recommend writing a real program in CL, though,
it's really fun, more so than most languages (PostScript and Smalltalk
are the only ones that I know that are fun like CL).  If you like
servery stuff on Unix, SBCL or CMUCL are great; if you have a Mac, MCL
was distractingly fun to play with.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m37jvgvxcb.fsf@javamonkey.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> David Steuber <·····@david-steuber.com> writes:
>
>> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
>> 
>> > ···@cartan.de (=?iso-2022-jp-2?b?TmlscyBHGy5BG052c2NoZQ==?=) writes:
>> > 
>> > > Frankly, I would prefer to do such a thing with threads.  Have a
>> > > thread waiting for TCP connections and nothing else, that will create
>> > > another thread for every client connecting to your program, and have
>> > > yet another thread waiting for other forms of input (and nothing
>> > > else).  Blocking reads all over the place.  Unfortunately, I don't
>> > > know if CLISP supports threads...
>> > 
>> > That sounds easier or simpler to you?!?!
>> 
>> He is not the only one.  A decent threading model means you don't have
>> to manualy hop around input streams to see if something is waiting for
>> you.  The overall application is simpler.
>
> Of course it is: you just compared "a decent threading model" with a
> piss-poor event server.  I'm not saying threads are no use, but using
> them simply to get nonblocking I/O seems overkill to me.
>
>> The portion of the code that actualy deals with the input has to
>> wait for it anyway.  So just do a blocking read to get the input,
>> then do a blocking write to send the output.  From the point of view
>> of that section of code, only one thing is going on: read, eval,
>> print. :-)
>
> With a decent event server, you setup handlers on the inputs your
> application is interested in.  Those handlers use the system's normal
> I/O facilities.  All the I/O simplicity you get from threads, with
> very little of the hair.
>
> To give you an idea, you might write a serve-event server like this:
>
>   (defvar *db-connections* ())
>
>   (defun get-db-connection ()
>     (or (pop *db-connections*)
>         (connect-to-database ...)))
>
>   (defun done-with-connection (db)
>     (push db *db-connections*))
>
>   (defvar *server-socket* ...)
>
>   (defun serve-connection (fd)
>     (declare (ignore fd))
>     (let* ((socket (socket-accept *server-socket*))
>            (client (socket-make-stream socket :input t :output t))
>            (db (get-db-connection)))
>       ... normal I/O here, read-line and such ...
>       (done-with-connection db)
>       (close client)
>       (socket-close socket)))
>
>   (socket-bind ...)
>   (socket-listen ...)
>   (add-fd-handler (socket-file-descriptor *server-socket*)
>                   :input #'serve-connection)
>
>   ;; You probably don't need this, because the repl calls it
>   ;; (loop (serve-event))
>
> Notice how, unlike after reading a `select' example, you're not
> doubled over with pain right now.

So I want to make sure I understand what happens under the covers
here--each time a new cliet connects the SERVE-EVENT mechanism notices
that there's stuff to do with *SERVER-SOCKET* and calls
SERVE-CONNECTION to deal with it. Within that call you make
potentially blocking I/O calls such as to the database, etc. What
happens if another connection comes in before the first call to
SERVE-CONNECTION returns?

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcv4qqjxva2.fsf@famine.OCF.Berkeley.EDU>
Peter Seibel <·····@javamonkey.com> writes:

> So I want to make sure I understand what happens under the covers
> here--each time a new cliet connects the SERVE-EVENT mechanism notices
> that there's stuff to do with *SERVER-SOCKET* and calls
> SERVE-CONNECTION to deal with it.

Yep.

> Within that call you make potentially blocking I/O calls such as to
> the database, etc. What happens if another connection comes in
> before the first call to SERVE-CONNECTION returns?

It calls SERVE-CONNECTION.  If you're dealing with connections from
the open internet, you want to have a counter that your handler checks
before accepting a client, to keep a maximum number on the number of
connections you're serving, so you have a base case for your
recursion.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m37jvevhby.fsf@javamonkey.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> So I want to make sure I understand what happens under the covers
>> here--each time a new cliet connects the SERVE-EVENT mechanism notices
>> that there's stuff to do with *SERVER-SOCKET* and calls
>> SERVE-CONNECTION to deal with it.
>
> Yep.
>
>> Within that call you make potentially blocking I/O calls such as to
>> the database, etc. What happens if another connection comes in
>> before the first call to SERVE-CONNECTION returns?
>
> It calls SERVE-CONNECTION.  If you're dealing with connections from
> the open internet, you want to have a counter that your handler checks
> before accepting a client, to keep a maximum number on the number of
> connections you're serving, so you have a base case for your
> recursion.

So doesn't that mean that within SERVE-CONNECTION I still have to take
care of synchronizing access to shared data (such as the database
connection pool)? I.e. I'm still running a multi-threaded app It just
happens that I'm not spinning up the threads. Also does this imply a
thread-per-connection under the covers. Because that's not a great way
to write a scalable server.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87brkqcrql.fsf@david-steuber.com>
Peter Seibel <·····@javamonkey.com> writes:

> So doesn't that mean that within SERVE-CONNECTION I still have to take
> care of synchronizing access to shared data (such as the database
> connection pool)? I.e. I'm still running a multi-threaded app It just
> happens that I'm not spinning up the threads. Also does this imply a
> thread-per-connection under the covers. Because that's not a great way
> to write a scalable server.

I'm really glad this thread exists.  When I was working on my own
flavor of a mod_lisp Lisp side (currently on back burner), I was going
with the idea of a thread per connection model on the theory that
Apache would be configured so that it placed a limit on the total
number of threads spawned.

Now I suspect that is a naive idea.  The Lisp image could be running
on some big iron just like a database (like Oracle) and accepting
connections from a number of Apache servers which are themselves
behind a firewall that does load balancing ala local director.

Also threads are really most useful when you have a CPU to back up
each thread.  Otherwise, the threads are just an illusion.

Unfortunately, serve-connection is not in the CLHS or CLtL2.  Can I
find this documented somewhere?  I hope to use it under SBCL.  I also
hope that it can be used in combination with threads if that doesn't
make things too hairy.  That is, have an app server run a thread per
processor (or just go with a user configured number of threads) and
use serve-connection and family to multiplex connection requests.

So another question is, is it safe to mutex shared data
(sb-thread:with-mutex (foo) ...) within a serve-connection model?

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Luke Gorrie
Subject: Re: Socket Programming
Date: 
Message-ID: <lhk6zemwhn.fsf@dodo.bluetail.com>
Peter Seibel <·····@javamonkey.com> writes:

> Also does this imply a thread-per-connection under the
> covers. Because that's not a great way to write a scalable server.

Under the covers it's a recursive event-loop, i.e. if an operation
would block then it recursively calls the select()-loop to dispatch
some other event in the meantime. Actually, these recursive calls to
SERVE-EVENT are similar to what you and I have discussed in the
context of recursive-edits during SLIME network requests.

To clarify my thoughts a bit I have written a couple of small programs
that demonstrate some things one might want to be careful of when
using SERVE-EVENT. I posted the source to Ingvar Mattsson's new
`small-cl-src' mailing list, which is for sourcecode only and serves
as an outlet for random CL hacks (like gnu.emacs.sources).

The mailing list is here:
  http://www.hexapodia.net:8080/mailman/listinfo/small-cl-src

My serve-event example is on the web here:
  http://www.bluetail.com/~luke/misc/lisp/serve-event-tricky.lisp

Or there's a PDF version of the example program here instead:
  http://www.bluetail.com/~luke/misc/lisp/serve-event-tricky.pdf

(The PDF is autogenerated from a little program that I intend to post
to gnu.emacs.sources this weekend.)

P.S., either CMUCL has changed between 18e and the May snapshot (which
I'm using now) or I mischaracterised it before when I said that only
FDs set to non-blocking would recurse into SERVE-EVENT on operations
that would block. It seems to happen always.

Cheers,
Luke

P.S., I dig SERVE-EVENT and don't mean to knock it :-)
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvhduhwny9.fsf@famine.OCF.Berkeley.EDU>
Luke Gorrie <····@bluetail.com> writes:

> To clarify my thoughts a bit I have written a couple of small programs
> that demonstrate some things one might want to be careful of when
> using SERVE-EVENT.

Nice!  That's a good summary of the pitfalls of using SERVE-EVENT.  I
had to figure this kind of stuff out mostly on my own; maybe we can
save the next generation of Lispers a little time and pain.  If I have
time this weekend, maybe I'll put together an example of how to avoid
those pitfalls, to make a style guide for using SERVE-EVENT to write
servers.

Oh, one thing you forgot was dynamic bindings.  Anyone following the
advice in your conclusion ("be aware of what's on the stack") will
figure it out, but if a handler binds a global variable, then calls
SERVE-EVENT, any handler that runs under it will get its binding, not
the global binding.

> I posted the source to Ingvar Mattsson's new
> `small-cl-src' mailing list, which is for sourcecode only and serves
> as an outlet for random CL hacks (like gnu.emacs.sources).

( Cool, I didn't know about this. )

> P.S., either CMUCL has changed between 18e and the May snapshot (which
> I'm using now) or I mischaracterised it before when I said that only
> FDs set to non-blocking would recurse into SERVE-EVENT on operations
> that would block. It seems to happen always.

It's not a function of the FD, it's a function of the stream you make
out of it.  If you use full buffering (the default), this should
always happen.  However, if you turn buffering off, it will block;
which can be useful on occasion.

> P.S., I dig SERVE-EVENT and don't mean to knock it :-)

I think this discussion is good.  Threads, Unix processes, and event
loops all have their place.  It would be a shame for people coming to
Lisp to miss one of the perfectly good options.

It's my preferred style for writing small, local servers.  For stuff
that goes on the big, bad internet, I'm split between SERVE-EVENT
(with care), and preforking (like old-style Apache).

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Edi Weitz
Subject: Re: Socket Programming
Date: 
Message-ID: <m33c618s16.fsf@ella.agharta.de>
On 15 May 2004 11:21:50 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

> It's my preferred style for writing small, local servers.  For stuff
> that goes on the big, bad internet, I'm split between SERVE-EVENT
> (with care), and preforking (like old-style Apache).

Does that mean you really fork like in [1]? Could you be so nice to
post a small example demonstrating this technique?

Thanks,
Edi.

[1] <http://cl-cookbook.sourceforge.net/os.html#fork-cmucl>
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcv8yfsx2ul.fsf@famine.OCF.Berkeley.EDU>
Edi Weitz <···@agharta.de> writes:

> On 15 May 2004 11:21:50 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
> 
> > It's my preferred style for writing small, local servers.  For stuff
> > that goes on the big, bad internet, I'm split between SERVE-EVENT
> > (with care), and preforking (like old-style Apache).
> 
> Does that mean you really fork like in [1]?

Sure.  I came to Lisp from programming Unix servers, and until OpenMCL
0.14 came out, I didn't have access to a Lisp with native threads
(shoulda bought SCL while I could afford it).

> Could you be so nice to post a small example demonstrating this
> technique?

Lisp, C, it looks pretty much the same, it's mostly a Unix IPC
problem.  What do you mean not everyone had the same road to Lisp as I
did?  /Who/ did a survey?  Hey, Kenny did a survey about your moms!

Er, I mean -- sure, no problem.  Not tonight, tho.  I'll try to code
up an example or two showing how to do this, and post it here.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Edi Weitz
Subject: Re: Socket Programming
Date: 
Message-ID: <m3vfiwzplc.fsf@ella.agharta.de>
On 16 May 2004 00:12:18 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

> Sure.  I came to Lisp from programming Unix servers, and until
> OpenMCL 0.14 came out, I didn't have access to a Lisp with native
> threads (shoulda bought SCL while I could afford it).

Yeah, me too. The trial version I had looked really very promising but
now it's far far away from the budget of the projects I'm working
on... :(

>> Could you be so nice to post a small example demonstrating this
>> technique?
>
> Lisp, C, it looks pretty much the same, it's mostly a Unix IPC
> problem.  What do you mean not everyone had the same road to Lisp as
> I did?  /Who/ did a survey?  Hey, Kenny did a survey about your
> moms!

:)

> Er, I mean -- sure, no problem.  Not tonight, tho.  I'll try to code
> up an example or two showing how to do this, and post it here.

Thanks. I'm more or less aware on how Apache does it (and could look
at their source if I needed to) but I'd nevertheless like to see how
you do it with Lisp (CMUCL, I suppose) because I might miss some of
the fine points otherwise.

I could also (with your permission) add these examples to the CL
cookbook.

Cheers,
Edi.
From: Thomas F. Burdick
Subject: Preforking servers (was: Socket Programming)
Date: 
Message-ID: <xcvy8n3djqe.fsf_-_@famine.OCF.Berkeley.EDU>
Real Life got in the way and delayed the prefork examples I promised,
but here they are.  Well, here's Part I, a simple example.  I'll
follow up with a more realistic example later, with code partially
culled from production sources.

This was written using SBCL on Mac OS X, but it should work on any
BSD-ish system.  Porting it to CMUCL shouldn't be hard.  You need to
compile these files before you load them, because they're written
in a top-down manner.

The example server itself is here:
http://www.cathouse.bofh.se/pipermail/small-cl-src/2004-June/000012.html

It depends on the following patch, which adds fork, wait, and waitpid
to sb-posix (the patch is against SBCL-0.8.8):
http://www.cathouse.bofh.se/pipermail/small-cl-src/2004-June/000011.html

Here's a simple client you can use to poke at the server:
http://www.cathouse.bofh.se/pipermail/small-cl-src/2004-June/000013.html


Edi Weitz <···@agharta.de> writes:

> Thanks. I'm more or less aware on how Apache does it (and could look
> at their source if I needed to) but I'd nevertheless like to see how
> you do it with Lisp (CMUCL, I suppose) because I might miss some of
> the fine points otherwise.
> 
> I could also (with your permission) add these examples to the CL
> cookbook.

That's a good idea, go ahead.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Luke Gorrie
Subject: Re: Socket Programming
Date: 
Message-ID: <lhu0yfncfx.fsf@dodo.bluetail.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Edi Weitz <···@agharta.de> writes:
>
>> On 15 May 2004 11:21:50 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
>> 
>> > It's my preferred style for writing small, local servers.  For stuff
>> > that goes on the big, bad internet, I'm split between SERVE-EVENT
>> > (with care), and preforking (like old-style Apache).
>> 
>> Does that mean you really fork like in [1]?

[...]

>> Could you be so nice to post a small example demonstrating this
>> technique?
>
> Lisp, C, it looks pretty much the same, it's mostly a Unix IPC
> problem.  What do you mean not everyone had the same road to Lisp as I
> did?  /Who/ did a survey?  Hey, Kenny did a survey about your moms!

I would be very interested in this example too! I've been looking for
ways to write concurrent programs in Lisp more in the style of IPC
than multithreading, and Unix/Linux processes seem like a really
interesting potential foundation nowadays.

-Luke
From: Luke Gorrie
Subject: Re: Socket Programming
Date: 
Message-ID: <lhy8nrncpt.fsf@dodo.bluetail.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> If I have time this weekend, maybe I'll put together an example of
> how to avoid those pitfalls, to make a style guide for using
> SERVE-EVENT to write servers.

That would be cool.

Here's a trick I often use in Emacs Lisp -- I wonder if other people
"HaveThisPattern" too.

The main trouble with my example server was that it did blocking I/O
by calling `READ' on a "buffered" stream, causing the event-loop to be
called recursively. If you don't recurse into the event loop (and
don't block) then you don't have those problems.

The server could be made non-blocking by making the stream
unbuffered. That way `READ' will return immediately -- either with its
result or, if the request is incomplete, with an `EOF-ERROR'. If we
get an EOF-ERROR we just save the input we have so far and return to
SERVE-EVENT. When we get called again with new data we append it to
the old and try again -- and so on until we have enough data to
complete the READ. This way nobody gets blocked.

There are some issues with that approach, but no serious ones that I
can think of. It seems like a useful "design pattern" for when you
don't have a suitable coroutine mechanism.

> Oh, one thing you forgot was dynamic bindings.  Anyone following the
> advice in your conclusion ("be aware of what's on the stack") will
> figure it out, but if a handler binds a global variable, then calls
> SERVE-EVENT, any handler that runs under it will get its binding, not
> the global binding.

Good point. I wonder how to neatly represent that in the example
program.

> I think this discussion is good.  Threads, Unix processes, and event
> loops all have their place.  It would be a shame for people coming to
> Lisp to miss one of the perfectly good options.
>
> It's my preferred style for writing small, local servers.  For stuff
> that goes on the big, bad internet, I'm split between SERVE-EVENT
> (with care), and preforking (like old-style Apache).

For the big, bad internet (day job) I'm a big Erlang fan. If you're
bored on some rainy afternoon you might enjoy reading a bit of
"Concurrent Programming in Erlang" [*]. It really nails
internet-server type of programming.

[*]: http://www.erlang.org/download/erlang-book-part1.pdf

Cheers,
Luke
From: Steven E. Harris
Subject: Re: Socket Programming
Date: 
Message-ID: <q67vfiv8275.fsf@L75001820.us.ray.com>
Luke Gorrie <····@bluetail.com> writes:

> The server could be made non-blocking by making the stream
> unbuffered. That way `READ' will return immediately -- either with
> its result or, if the request is incomplete, with an `EOF-ERROR'. If
> we get an EOF-ERROR we just save the input we have so far and return
> to SERVE-EVENT. When we get called again with new data we append it
> to the old and try again -- and so on until we have enough data to
> complete the READ. This way nobody gets blocked.

How would you know when to finally give up trying to read? What if the
socket has already been closed, but you haven't read enough yet to be
satisfied? Would you just keep on trying to read despite the repeated
EOF-ERRORs? Would some other event inform you that the socket had been
closed?

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvwu37ujzl.fsf@famine.OCF.Berkeley.EDU>
Luke Gorrie <····@bluetail.com> writes:

> Here's a trick I often use in Emacs Lisp -- I wonder if other people
> "HaveThisPattern" too.

Nope, I wrote a CPS transformer for elisp.  It's a bad idea, though,
you just end out blowing the stack a lot ... you'd think that adding
tail-call elimination would be the answer, but, uh, how do you do that
in a dynamic-binding Lisp?  This NonBlockingPattern sounds like a
better idea.

> The main trouble with my example server was that it did blocking I/O
> by calling `READ' on a "buffered" stream, causing the event-loop to be
> called recursively. If you don't recurse into the event loop (and
> don't block) then you don't have those problems.
> 
> The server could be made non-blocking by making the stream
> unbuffered. That way `READ' will return immediately -- either with its
> result or, if the request is incomplete, with an `EOF-ERROR'.

I think you'd also have to set the FD to be non-blocking, and handle
EAGAIN errors; otherwise, the I/O will just block for real.

> If we
> get an EOF-ERROR we just save the input we have so far and return to
> SERVE-EVENT. When we get called again with new data we append it to
> the old and try again -- and so on until we have enough data to
> complete the READ. This way nobody gets blocked.
> 
> There are some issues with that approach, but no serious ones that I
> can think of. It seems like a useful "design pattern" for when you
> don't have a suitable coroutine mechanism.

It does sound good.  It would also let you use an event server on a
Lisp that doesn't have one built in.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Joe Marshall
Subject: Re: Socket Programming
Date: 
Message-ID: <r7tfeynn.fsf@ccs.neu.edu>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Luke Gorrie <····@bluetail.com> writes:
>
>> Here's a trick I often use in Emacs Lisp -- I wonder if other people
>> "HaveThisPattern" too.
>
> Nope, I wrote a CPS transformer for elisp.  It's a bad idea, though,
> you just end out blowing the stack a lot ... you'd think that adding
> tail-call elimination would be the answer, but, uh, how do you do that
> in a dynamic-binding Lisp?  

You have to collect the `buried bindings'.  See 
   http://home.pipeline.com/~hbaker1/BuriedStale.html
and
   http://www.accesscom.com/~darius/writings/dynatail.html
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m3isetsmz9.fsf@javamonkey.com>
Luke Gorrie <····@bluetail.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> Also does this imply a thread-per-connection under the
>> covers. Because that's not a great way to write a scalable server.
>
> Under the covers it's a recursive event-loop, i.e. if an operation
> would block then it recursively calls the select()-loop to dispatch
> some other event in the meantime. Actually, these recursive calls to
> SERVE-EVENT are similar to what you and I have discussed in the
> context of recursive-edits during SLIME network requests.

Okay. So it's like cooperative multithreading with the "yield" built
into all the potentially blocking operations? (Roughly speaking.) So
that seems somewhat suboptimal in a language where dynamic context
(e.g. dynamically bound variables, condition handlers, and restarts)
are important. As in, I'd rather have the separate "tasks" running in
their own dynamic context that unwinds after each task completes.

I get that in the absence of threads this is a reasonable way to
actually get work done but it seems a bit kludgy in the sense that
there's this weird interaction between things that should be separate.
(The bad thing I'm imagining is that in one set of code I bind a
condition handler and it ends up handling a condition for some other
bit of code that happened to be interleaved on the call stack thanks
to the recursive event loop. Or am I missing something.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Daniel Barlow
Subject: Re: Socket Programming
Date: 
Message-ID: <87smdx1vy4.fsf@noetbook.telent.net>
Peter Seibel <·····@javamonkey.com> writes:

> Okay. So it's like cooperative multithreading with the "yield" built
> into all the potentially blocking operations? (Roughly speaking.) So
> that seems somewhat suboptimal in a language where dynamic context
> (e.g. dynamically bound variables, condition handlers, and restarts)
> are important. As in, I'd rather have the separate "tasks" running in
> their own dynamic context that unwinds after each task completes.

That corresponds with my understanding, yes.  And, yes, it gives me
the creeps too. 


-dan

-- 
"please make sure that the person is your friend before you confirm"
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcv1xlfvziy.fsf@famine.OCF.Berkeley.EDU>
Peter Seibel <·····@javamonkey.com> writes:

> Luke Gorrie <····@bluetail.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> Also does this imply a thread-per-connection under the
> >> covers. Because that's not a great way to write a scalable server.
> >
> > Under the covers it's a recursive event-loop, i.e. if an operation
> > would block then it recursively calls the select()-loop to dispatch
> > some other event in the meantime. Actually, these recursive calls to
> > SERVE-EVENT are similar to what you and I have discussed in the
> > context of recursive-edits during SLIME network requests.
> 
> Okay. So it's like cooperative multithreading with the "yield" built
> into all the potentially blocking operations? (Roughly speaking.)

Kind of, but really, thinking of an event server in terms of being a
crappy thread implementation is going to make it seem really bad; it's
a way to allow multiple Lisp applications to handle incoming events
within a single thread of control.

> So that seems somewhat suboptimal in a language where dynamic
> context (e.g. dynamically bound variables, condition handlers, and
> restarts) are important. As in, I'd rather have the separate "tasks"
> running in their own dynamic context that unwinds after each task
> completes.

Well, if you're using it as the central mechanism of a single
application, you have to put thought into what's happening on the
stack.  The more functional/declarative your code is, the less you
notice SERVE-EVENT.  If you're using it to allow multiple different
applications to run in the same Lisp image, it's much less
problematic; at least, assuming your dynamic variables are in your own
package, and you're defining your own condition types and handling
them.  Libraries can be more problematic.

> I get that in the absence of threads this is a reasonable way to
> actually get work done but it seems a bit kludgy in the sense that
> there's this weird interaction between things that should be separate.
> (The bad thing I'm imagining is that in one set of code I bind a
> condition handler and it ends up handling a condition for some other
> bit of code that happened to be interleaved on the call stack thanks
> to the recursive event loop. Or am I missing something.

If two applications are using the same library, yeah, this can happen.
And I agree with Dan Barlow, it's creepy.  It's not a replacement for
threads.

If you're designing your own application that uses SERVE-EVENT to run
all by itself, this shouldn't be a problem.  You want to distinguish
between conditions that apply to the application as a whole, and
conditions that are internal to a handler.  In the latter case, you
include enough context in the condition that you can tell if its yours
or not.  Something like:

  (handler-bind ((borked (lambda (c)
                           (when (eql (borked-request c) my-request)
                             (abort-request (borked-request c))))))
    ...)

It is definately a different type of Lisp programming.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Eric Marsden
Subject: Re: Socket Programming
Date: 
Message-ID: <wzizn7u55ed.fsf@melbourne.laas.fr>
[reacting a bit late to this interesting thread]  

>>>>> "lg" == Luke Gorrie <····@bluetail.com> writes:
  
  lg> To clarify my thoughts a bit I have written a couple of small programs
  lg> that demonstrate some things one might want to be careful of when
  lg> using SERVE-EVENT.

  lg> My serve-event example is on the web here:
  lg> http://www.bluetail.com/~luke/misc/lisp/serve-event-tricky.lisp

  your DELAY example is a great illustration of a potential pitfall in
  SERVE-EVENT programming, that arises from its reentrant nature. As
  you state, the only way for a server that uses SERVE-EVENT in this
  way to protect itself from a malicious client is to use timeouts.
  Fortunately, CMUCL makes this easy. Inside SERVER-HANDLE-CONNECTION,
  add a line like

      (setf (lisp::fd-stream-timeout stream) 1)

  then be prepared to abort the current connection upon a
  LISP::IO-TIMEOUT condition. This bounds the delay that can be caused
  by a misbehaving client. 


  However, it's better (though more complicated) completely to avoid
  reentry of SERVE-EVENT. Request I/O should be separated from request
  processing, with I/O being handled in the fd-handlers and processing
  being handled in the main server loop. Instead of calling standard
  CL I/O functions such as READ-LINE from the fd-handler (since they
  may block and cause reentry of SERVE-EVENT), call system-dependent
  I/O routines that do non-blocking input. CMUCL has a function called
  SYS:READ-N-BYTES that can do this, or one can call UNIX-READ and
  friends directly. 
  

  lg> P.S., either CMUCL has changed between 18e and the May snapshot (which
  lg> I'm using now) or I mischaracterised it before when I said that only
  lg> FDs set to non-blocking would recurse into SERVE-EVENT on operations
  lg> that would block. It seems to happen always.

  I think it's done that for quite a while, but with CVS offline I
  can't check. 
  
-- 
Eric Marsden                          <URL:http://www.laas.fr/~emarsden/>
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87d64pon5r.fsf@david-steuber.com>
Eric Marsden <········@laas.fr> writes:

> [reacting a bit late to this interesting thread]  

I've actually been thinking about this recently.  Inside the last hour
in fact.  Just to recap, there are two basic models I would consider
using for a TCP service:

* Single threaded application that multiplexes concurrent connections
  and uses non-blocking io.
* Multi threaded application that uses one thread per connection
  request and blocking io.

Some requests may be served within millisecond time scale.  Others may
take a few seconds.  Hopefully no requests take longer than that
because people on the other end of the line get impatient for an
answer very quickly.

If the host machine is a multi-cpu box and you have native threads,
then you can take advantage of the hardware with the second approach.
On a single cpu system, preemptive thread switching introduces some
overhead.  In either case, I would expect the application logic to
have similar complexity.  However, I personally am more familiar with
mult-threaded programming techniques from other languages than I am
with the multiplexing approach (select in Perl & C).

I would tend to favor the multi-threaded approach for that reason even
on a single cpu system (in the hope that I can upgrade to a multi cpu
system in the future).  Is there a noticable performance downside to
this in terms of maximum requests per second I can handle on a given
piece of hardware?

Just to keep this on topic, I would be using SBCL.  It only supports
native threads on x86 at present.  I haven't measured it's thread
creation overhead yet, but I plan to Real Soon Now(tm).

One thing that would be nice to do with a multi threaded approach is
in the main thread that accepts socket connections and spawns new
threads to handle them is have a mechanism for sleeping for some
fractions of a second to act as a throttle in the event of the
slashdot effect or a plain old DoS attack.

In C, sleep takes an int in seconds of time.  The best I can think to
do is keep some rolling counter of number of connections accepted in
the past second and sleep for a second or two if the number exceeds
some threshold value.  The counter would have to be checked and
adjusted with each accept.

A DoS attack would still work, but the system won't fall down.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m3pt8polan.fsf@javamonkey.com>
David Steuber <·····@david-steuber.com> writes:

> Eric Marsden <········@laas.fr> writes:
>
>> [reacting a bit late to this interesting thread]  
>
> I've actually been thinking about this recently. Inside the last
> hour in fact. Just to recap, there are two basic models I would
> consider using for a TCP service:
>
> * Single threaded application that multiplexes concurrent connections
>   and uses non-blocking io.
> * Multi threaded application that uses one thread per connection
>   request and blocking io.

[snip]

> I would tend to favor the multi-threaded approach for that reason even
> on a single cpu system (in the hope that I can upgrade to a multi cpu
> system in the future).  Is there a noticable performance downside to
> this in terms of maximum requests per second I can handle on a given
> piece of hardware?

So the thread-per-connection approach does not work well if you want
to write highly scalable services simply because most threading
systems are not designed to handle tens of thousands of threads. (I.e.
threads are just too heavyweight.) Google for the C10K problem for
more info.

On the other hand, just using non-blocking i/o doesn't solve the
problem either because a typical scenario is you have 10,000 open
sockets from different clients and you need to find the one that at
this moment has data for you to read and process. If you had a
non-blocking READ-BYTE or whatever, you could loop over all your
sockets calling READ-BYTE and as long as there are bytes to read
process them, otherwise move on to the next socket. However even a
non-blocking call isn't instantaneous. So you'll spend a bunch of time
reading from sockets just to determine that there's nothing to read.
All of which adds latency to the sockets that actually do have data
for you to read.

What you really want is asynchronous i/o. Which you can simulate
fairly well with a much smaller number of threads than a
thread-per-connection model as long as you have some kind of
select/poll mechanism. (Or you can use non-blocking i/o with a
dedicated thread and some clever hueristics to try and minimize the
time you spend checking connections that are unlikely to have data to
process. However all such heurestics seem to add latency in certain
situations.)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Antony Sequeira
Subject: Re: Socket Programming
Date: 
Message-ID: <14rtc.73582$0j6.64012@newssvr25.news.prodigy.com>
Peter Seibel wrote:
> 
> On the other hand, just using non-blocking i/o doesn't solve the
> problem either because a typical scenario is you have 10,000 open
> sockets from different clients and you need to find the one that at
> this moment has data for you to read and process. If you had a
> non-blocking READ-BYTE or whatever, you could loop over all your
> sockets calling READ-BYTE and as long as there are bytes to read
> process them, otherwise move on to the next socket. However even a
> non-blocking call isn't instantaneous. So you'll spend a bunch of time
> reading from sockets just to determine that there's nothing to read.
> All of which adds latency to the sockets that actually do have data
> for you to read.
In a multi-tiered architecture, only the client facing servers have to 
deal with the large number tcp connections issue, rest of the servers 
have to deal with large number of transactions only (unless you have 
botched up your server-server communications design).
Just a thought.

-Antony
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m3k6yxo104.fsf@javamonkey.com>
Antony Sequeira <·············@hotmail.com> writes:

> Peter Seibel wrote:
>> On the other hand, just using non-blocking i/o doesn't solve the
>> problem either because a typical scenario is you have 10,000 open
>> sockets from different clients and you need to find the one that at
>> this moment has data for you to read and process. If you had a
>> non-blocking READ-BYTE or whatever, you could loop over all your
>> sockets calling READ-BYTE and as long as there are bytes to read
>> process them, otherwise move on to the next socket. However even a
>> non-blocking call isn't instantaneous. So you'll spend a bunch of time
>> reading from sockets just to determine that there's nothing to read.
>> All of which adds latency to the sockets that actually do have data
>> for you to read.

> In a multi-tiered architecture, only the client facing servers have to
> deal with the large number tcp connections issue, rest of the servers
> have to deal with large number of transactions only (unless you have
> botched up your server-server communications design).
> Just a thought.

That's true. But it's in those client facing servers that the
thread-per-connection breaks down.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Dominique Boucher
Subject: Re: Socket Programming
Date: 
Message-ID: <8165ah5t6z.fsf@Forman.nuecho.ad>
Peter Seibel <·····@javamonkey.com> writes:

> So the thread-per-connection approach does not work well if you want
> to write highly scalable services simply because most threading
> systems are not designed to handle tens of thousands of threads. (I.e.
> threads are just too heavyweight.) Google for the C10K problem for
> more info.

I know it's Scheme, not Common Lisp, but Gambit-C 4.0, a Scheme system
that compiles to C code, can handle up to 1.35M threads (yeah, 1.35
million) with 2Gigabytes of RAM. (Compare this with Red Hat's NPTL
which can handle at most 0.38M threads.)  Threads are REALLY cheap
(thread creation takes 2.5 microseconds on a 2.8 GHz Xeon).

A web server implemented in Scheme at Purdue University (for a math
introductory course) is used by about 2000 simultaneous users and the
machine load never exceeds 20%.

For more information, see Marc Feeley's talk at the Montreal
Scheme/Lisp User Group:

http://www.iro.umontreal.ca/~boucherd/mslug/meetings/20040519/mslug1.pdf.gz


Dominique Boucher
From: Luke Gorrie
Subject: Re: Socket Programming
Date: 
Message-ID: <lhk6yx9j8q.fsf@dodo.bluetail.com>
Dominique Boucher <·················@nuecho.com> writes:

> A web server implemented in Scheme at Purdue University (for a math
> introductory course) is used by about 2000 simultaneous users and the
> machine load never exceeds 20%.

Good point. As far as I know "how to write nice and scalable
concurrent programs" is a solved-problem. People do it all the time
with no fuss at all.

Not everyone though. The "C10K Problem" page makes me want to cry. So
many trees, so little forest.

Cheers,
Luke
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87n03sk835.fsf@david-steuber.com>
Luke Gorrie <····@bluetail.com> writes:

> Dominique Boucher <·················@nuecho.com> writes:
> 
> > A web server implemented in Scheme at Purdue University (for a math
> > introductory course) is used by about 2000 simultaneous users and the
> > machine load never exceeds 20%.
> 
> Good point. As far as I know "how to write nice and scalable
> concurrent programs" is a solved-problem. People do it all the time
> with no fuss at all.
> 
> Not everyone though. The "C10K Problem" page makes me want to cry. So
> many trees, so little forest.

I just did a google search and found this:

  http://www.kegel.com/c10k.html

I haven't had a chance to read it yet.

I would be ecstatic if my webserver could dole out 100 requests per
second of Lisp generated content.  That is nowhere near 10 000
concurrent connections.  It is also far below the peak demand my
server has ever seen.

The box is currently a 566Mhz Celeron with 384MB RAM and 40GB disk.
It's on a T1, so I don't think the 100bt NIC makes much of a
difference.  I've also barely touched swap.

My real concern is thread creation overhead.  If it doesn't take a
significant part of the time to create a thread to handle the requests
over a connection, then I'm not going to worry about it.  I know there
are limits on the number of stacks and other sundry details.  If it
comes down to it, I can add more hardware.  I would presumably have a
money making business if I had an average server load of 100 requests
per second :-)

Of course you have to be able to deal with the peaks gracefully.  For
any given hardware and software setup, there is presumably a magic
number of open connections where you don't want to accept any more or
it will actually start to take longer to fulfill requests.

Bottom line, if thread creation is cheap enough, it is much simpler to
just create and dispose of threads on demand.  Heck, in the old days
of CGI, an entire process would be spawned (fork + exec) to handle a
single request.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m3smdkl92v.fsf@javamonkey.com>
Luke Gorrie <····@bluetail.com> writes:

> Dominique Boucher <·················@nuecho.com> writes:
>
>> A web server implemented in Scheme at Purdue University (for a math
>> introductory course) is used by about 2000 simultaneous users and the
>> machine load never exceeds 20%.
>
> Good point. As far as I know "how to write nice and scalable
> concurrent programs" is a solved-problem. People do it all the time
> with no fuss at all.
>
> Not everyone though. The "C10K Problem" page makes me want to cry.
> So many trees, so little forest.

So now I'm curious, how would *you* write a server that should handle
10,000-100,000 concurrently connected (but mostly idle) clients. Bonus
points for a solution that can be deployed on stock general purpose
hardware (i.e. a box I can buy from Dell) and better yet on a
"mainstream" OS. But if either of those two requirements is the
barrier to doing it "with no fuss at all" feel free to disregard them.

As I understand it the point of the C10K page is that at the OS
level--at least in mainstream OS's--there's no good solution to the
problem of keeping track of which of 10,000 (let alone 100,000)
connections may have data to deal with. Unless I'm misunderstanding
them there's little that better languages or ways of thinking about
writing concurrent software can do to fix *that* particular problem.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87r7t4l050.fsf@david-steuber.com>
Peter Seibel <·····@javamonkey.com> writes:

> As I understand it the point of the C10K page is that at the OS
> level--at least in mainstream OS's--there's no good solution to the
> problem of keeping track of which of 10,000 (let alone 100,000)
> connections may have data to deal with. Unless I'm misunderstanding
> them there's little that better languages or ways of thinking about
> writing concurrent software can do to fix *that* particular problem.

I don't think you need to worry about the 100,000 simultaneous
connection problem.  IPv4 supports only 2^16 ports.  Even if a process
could get 100,000 file descriptors, there would be no way for one
machine to have that many open IP connections.  This is actually a
major reason for the HTTP protocol vs FTP where a typical session is
much longer.  IP connections are a very limited resource.

What I got from the C10K page was that the primary problem with one
thread per connection was running out of stack space.  If incomming
data causes ALL the threads to wake up and then the ones that should
be idle to go back to sleep (thundering herd), then that would be a
real problem as well.  If you can say ahead of time what the maximum
stack space you will need is, you should have a way to tell the OS not
to give you more than that.

However, either way you cut it, time slicing has to be done
somewhere.  Polling is expensive because you are querying descriptors
that are not ready.  The other two methods that were mentioned in the
article seem like reasonable fixes, but you would still have to do
some sort of processing on idle connections.

Proper 1:1 threading should work nicely.  The ideal case (see sig) is
that data comes in on the ether and the kernel knows exactly which
thread to wake up to read it.  If the kernel can handle that detail,
then things are much easier for developers in userland.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Johannes Groedem
Subject: Re: Socket Programming
Date: 
Message-ID: <lzfz9jmlrk.fsf@unity.copyleft.no>
* David Steuber <·····@david-steuber.com>:

> I don't think you need to worry about the 100,000 simultaneous
> connection problem.  IPv4 supports only 2^16 ports.  Even if a
> process could get 100,000 file descriptors, there would be no way
> for one machine to have that many open IP connections.

Having 100,000 simultaneous _outgoing_ connections from one IP-address
isn't what's interesting here, but rather being able to accept 100,000
simultaneous connections from different hosts.  Anyway, for that, you
only need one port per service, such as port 80 for HTTP.  A
TCP-connection is, conceptually (simplified), a (dest-address,
dest-port, source-address, source-port)-tuple, so you can figure out
for yourself how many connections you can theoretically handle given a
fixed (dest-address, dest-port)-pair.  (It's a lot more than 100,000.)

Also, IP doesn't have ports, IP-endpoints are IP-addresses, while
TCP-endpoints are IP-addresses combined with ports.  (Or some other
kind of network layer-addresses, I don't know if TCP is being used
over something else than IPv4/6.)

> However, either way you cut it, time slicing has to be done
> somewhere.  Polling is expensive because you are querying
> descriptors that are not ready.  The other two methods that were
> mentioned in the article seem like reasonable fixes, but you would
> still have to do some sort of processing on idle connections.

Why?  You would just tell the OS to notify you when there is data
available on a connection, and no processing needs to be done for that
connection until data is actually available for it.

-- 
Johannes Gr�dem <OpenPGP: 5055654C>
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m3y8n9bjxc.fsf@javamonkey.com>
David Steuber <·····@david-steuber.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> As I understand it the point of the C10K page is that at the OS
>> level--at least in mainstream OS's--there's no good solution to the
>> problem of keeping track of which of 10,000 (let alone 100,000)
>> connections may have data to deal with. Unless I'm misunderstanding
>> them there's little that better languages or ways of thinking about
>> writing concurrent software can do to fix *that* particular problem.
>
> I don't think you need to worry about the 100,000 simultaneous
> connection problem.  IPv4 supports only 2^16 ports.  Even if a process
> could get 100,000 file descriptors, there would be no way for one
> machine to have that many open IP connections.  This is actually a
> major reason for the HTTP protocol vs FTP where a typical session is
> much longer.  IP connections are a very limited resource.

That doesn't matter to the server. Every connection to a server is to
the same port anyway (typically). It's the client IP-address/port that
makes the connection unique. So while it's true that I can only have
(expt 2 16) connections from a single client IP address, I can have
many, many connections from many, many clients.

> What I got from the C10K page was that the primary problem with one
> thread per connection was running out of stack space.  If incomming
> data causes ALL the threads to wake up and then the ones that should
> be idle to go back to sleep (thundering herd), then that would be a
> real problem as well.  If you can say ahead of time what the maximum
> stack space you will need is, you should have a way to tell the OS not
> to give you more than that.
>
> However, either way you cut it, time slicing has to be done
> somewhere.  Polling is expensive because you are querying descriptors
> that are not ready.  The other two methods that were mentioned in the
> article seem like reasonable fixes, but you would still have to do
> some sort of processing on idle connections.

Why? The kernel knows when packets arive on the wire as it is
responsible for decoding them.

> Proper 1:1 threading should work nicely.  The ideal case (see sig) is
> that data comes in on the ether and the kernel knows exactly which
> thread to wake up to read it.  If the kernel can handle that detail,
> then things are much easier for developers in userland.

Yes. That's called asynchronous i/o. When you issue the i/o call, you
pass along a callback that should be run when the i/o completes. So if
I do a read on a socket, I pass along the code that I want to run when
there is actually data to read. Nothing happens until some data shows
up for that connection.

Which the kernel *does* know since somewhere down in the TCP stack in
decoded the incoming packet and figured out which connection it
belongs to, etc. Of coures I'd also like to keep a thread-like notion
of dynamic context so my special variables, condition handlers, and
restarts are still in place.

(Where is that guy who was writing a TCP stack in Common Lisp? Maybe
he could implement something like this for sockets anyway.)

Actually the question of what the Ultimate Right Thing is is
interesting to me. I seet it as perhaps analogous to an argument I
used to have on a regular basis with one of the other developers at my
last gig: whether a general purpose garbage collector had to *in
principle* less efficient (in computer resources) than manually
managing memory. I had two arguments in favor of GC. The "weak"
argument was that while it might be possible to actually manage memory
more efficiently without GC (by taking advantage of
application-specific knowledge of memory usage patterns) that in
practice it would be so much harder to outperform a good GC
implementation that the programmer using GC would have way more time
to improve the overall efficiency of their program through better
design that it would always outperform a program written using manual
memory management. My "strong" argument was that memory management is
actually complex enough (e.g. you have to consider locality issues,
etc.) that ultimately a good GC implementation would do better on any
reasonably complex application than a human could. (I.e. the same
reason I want my compiler to allocate registers for me.)

So back to threads, there's part of me that would like to believe that
ultimately general purpose threading systems will be so good that the
path to the most efficient program simply will be to spin up as many
threads as you want and let the threading system take care of it.
Analogues to my weak and strong arguments for GC can be made. But I
don't belive that current threading systems have achieved that goal
yet. Not being an OS or virtual machine researcher, I'm not sure what
the open questions are or how near a solution we are. Thus I'm hoping
Luke--who claimed writing super-scalable software is a solved
problem--will answer my other post.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87isec7j3l.fsf@david-steuber.com>
Peter Seibel <·····@javamonkey.com> writes:

> David Steuber <·····@david-steuber.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> As I understand it the point of the C10K page is that at the OS
> >> level--at least in mainstream OS's--there's no good solution to the
> >> problem of keeping track of which of 10,000 (let alone 100,000)
> >> connections may have data to deal with. Unless I'm misunderstanding
> >> them there's little that better languages or ways of thinking about
> >> writing concurrent software can do to fix *that* particular problem.
> >
> > I don't think you need to worry about the 100,000 simultaneous
> > connection problem.  IPv4 supports only 2^16 ports.  Even if a process
> > could get 100,000 file descriptors, there would be no way for one
> > machine to have that many open IP connections.  This is actually a
> > major reason for the HTTP protocol vs FTP where a typical session is
> > much longer.  IP connections are a very limited resource.
> 
> That doesn't matter to the server. Every connection to a server is to
> the same port anyway (typically). It's the client IP-address/port that
> makes the connection unique. So while it's true that I can only have
> (expt 2 16) connections from a single client IP address, I can have
> many, many connections from many, many clients.

Another poster also corrected my misconceptions about sockets.  The
reason I thought there was a limit on server connections was the way I
thought accept worked.  I don't recall how I got this idea, but I
thought that when a connection to port 80 was accepted, a seperate
port was used for the transaction so that the server could continue to
listen on port 80.

I'm perfectly happy to be wrong on that account.  It means I can
settle for cheaper hardware :-)

> > What I got from the C10K page was that the primary problem with one
> > thread per connection was running out of stack space.  If incomming
> > data causes ALL the threads to wake up and then the ones that should
> > be idle to go back to sleep (thundering herd), then that would be a
> > real problem as well.  If you can say ahead of time what the maximum
> > stack space you will need is, you should have a way to tell the OS not
> > to give you more than that.
> >
> > However, either way you cut it, time slicing has to be done
> > somewhere.  Polling is expensive because you are querying descriptors
> > that are not ready.  The other two methods that were mentioned in the
> > article seem like reasonable fixes, but you would still have to do
> > some sort of processing on idle connections.
> 
> Why? The kernel knows when packets arive on the wire as it is
> responsible for decoding them.

I'm talking about polling buy the user code.  It's kinda like the kids
in the back seat asking, "are we there yet?"

Something driven by an event from the kernel will obviously work
better because it just sits passively until kicked.

> > Proper 1:1 threading should work nicely.  The ideal case (see sig) is
> > that data comes in on the ether and the kernel knows exactly which
> > thread to wake up to read it.  If the kernel can handle that detail,
> > then things are much easier for developers in userland.
> 
> Yes. That's called asynchronous i/o. When you issue the i/o call, you
> pass along a callback that should be run when the i/o completes. So if
> I do a read on a socket, I pass along the code that I want to run when
> there is actually data to read. Nothing happens until some data shows
> up for that connection.
> 
> Which the kernel *does* know since somewhere down in the TCP stack in
> decoded the incoming packet and figured out which connection it
> belongs to, etc. Of coures I'd also like to keep a thread-like notion
> of dynamic context so my special variables, condition handlers, and
> restarts are still in place.

Ok, asynchronous i/o sounds good from an event driven perspective.
Using a call back sounds very hairy.

When I did programming for Win16, it was all event driven.  Each event
was fetched in a message loop.  The Win16 API call getMessage (or
something like that, it's been a while and I suck with remembering
names) would block until a message came in.  (There was also a
peekMessage call that would return immediatly, so you could do
background processing without setting up a timer).

The only problem with that model was there was no concurrency.  If you
took ten seconds to process a message, that was ten seconds that the
entire system was frozen.  Win32 improved things somewhat to making it
so that only your application was frozen unless you kicked of a thread
to handle the event so that you could go back to your event loop as
quickly as possible.

> Actually the question of what the Ultimate Right Thing is is
> interesting to me. I seet it as perhaps analogous to an argument I
> used to have on a regular basis with one of the other developers at my
> last gig: whether a general purpose garbage collector had to *in
> principle* less efficient (in computer resources) than manually
> managing memory. I had two arguments in favor of GC. The "weak"
> argument was that while it might be possible to actually manage memory
> more efficiently without GC (by taking advantage of
> application-specific knowledge of memory usage patterns) that in
> practice it would be so much harder to outperform a good GC
> implementation that the programmer using GC would have way more time
> to improve the overall efficiency of their program through better
> design that it would always outperform a program written using manual
> memory management. My "strong" argument was that memory management is
> actually complex enough (e.g. you have to consider locality issues,
> etc.) that ultimately a good GC implementation would do better on any
> reasonably complex application than a human could. (I.e. the same
> reason I want my compiler to allocate registers for me.)

In the general case I agree with you here.  There are some things the
compiler should be able to figure out (or the runtime) so that consing
and gc are as cheap as possible.  Lisp and the various functional
languages should do very well with this because information on memory
usage is available to the system.  Perhaps more than there is
available to the programmer.  I'm a little less concinved with Java,
but then it could just be that I've been using an immature product.

One thing in Lisp that interests me is dynamic-extent.  When you
rebind a special varaible in a let, you know at compile time that you
have dynamic-extent and may be able to use the stack for allocation
just like C automatic variables.  That means no allocation at all.
You don't get much faster than that.  I'm not sure what happens when
you try to close over a special variable that has been
dynamicly-bound.  I would expect the specialness to mean that you
refer to the previous value of the variable when you leave the lexical
scope of the binding.  I'll have to reread that bit in the CLHS.

Other lexicals established by let should also effectivly have
dynamic-extent.  If they are closed over or returned from the let,
then you know they have indefinite extent.  But if that does not
happen, and this should be known at compile time, then stack
allocation can be used again.

I may be wrong on the details and would be happy for corrections.
Bottom line is that the compiler should be able to do a very good job
of managing memory for you.  It should even be able to tell when you
have a large chunk of static memory that you treat as read only or
just do in place modifications to.

> So back to threads, there's part of me that would like to believe that
> ultimately general purpose threading systems will be so good that the
> path to the most efficient program simply will be to spin up as many
> threads as you want and let the threading system take care of it.
> Analogues to my weak and strong arguments for GC can be made. But I
> don't belive that current threading systems have achieved that goal
> yet. Not being an OS or virtual machine researcher, I'm not sure what
> the open questions are or how near a solution we are. Thus I'm hoping
> Luke--who claimed writing super-scalable software is a solved
> problem--will answer my other post.

The only problems I see have to do with allocating a stack for the
thread and dealing with shared memory.  The stacks can eat up your
virtual address space very quickly.  The only way I can think to deal
with that is to not use overly large stacks.  If you have good memory
management, you can put the big objects (even if they are short lived)
on the heap so that stack space doesn't need to grow in some unbounded
way.  I don't know all the gotchas that are there.  Running out of
stack space is not a good thing though.

Shared memory is much easier to deal with.  Fast mutexes seem to be
the answer there.  I'm sure there are other tricks as well.  Rebinding
a special in a let should give you a thread local storage of sorts.  A
functional programming style will reduce the need for shared memory.
In anycase, serialization is something to avoid where possible because
that defeats the whole point of having threads.

What I like about threads is that I can, for the most part, treat each
thread like a batch process.  I find cooperative multi-tasking to be
much more painful than having a preemptive system in place.  I've been
down the cooperative road in the past with C and C++.  I hate that
road.

Perhaps if everyone said to hell with runtime efficiency, it's easier
to program with 1:1 threads, the OS support will develop and mature to
support that style so that the hardware can be properly utilized.

It sounds a lot like threading and automatic memory management go hand
in hand.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Karl A. Krueger
Subject: Re: Socket Programming
Date: 
Message-ID: <c9fsic$skv$1@baldur.whoi.edu>
David Steuber <·····@david-steuber.com> wrote:
> I don't recall how I got this idea, but I thought that when a
> connection to port 80 was accepted, a seperate port was used for the
> transaction so that the server could continue to listen on port 80.

Here's how I got the same wrong idea at first, which may or may not be
the same thing.  When a connection to port 80 is accepted, a separate
-socket- is used for the transaction, so the server can continue to
listen on the -server socket-.

(You don't listen on a port; you listen on a socket which is bound to a
port.  Your -host- is seen to pick up connections on a port, which we
sometimes call "listening on a port", but that's a misnomer.)

-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: Antony Sequeira
Subject: Re: Socket Programming
Date: 
Message-ID: <1U3vc.3349$gy4.2612@newssvr27.news.prodigy.com>
Karl A. Krueger wrote:
> David Steuber <·····@david-steuber.com> wrote:
> 
>>I don't recall how I got this idea, but I thought that when a
>>connection to port 80 was accepted, a seperate port was used for the
>>transaction so that the server could continue to listen on port 80.
> 
> 
> Here's how I got the same wrong idea at first, which may or may not be
> the same thing.  When a connection to port 80 is accepted, a separate
> -socket- is used for the transaction, so the server can continue to
> listen on the -server socket-.
> 
> (You don't listen on a port; you listen on a socket which is bound to a
> port.  Your -host- is seen to pick up connections on a port, which we
> sometimes call "listening on a port", but that's a misnomer.)
> 
and the data from two different clients is sent to the appropriate 
server socket based on the originating (client) IP and port ?

-Antony
From: Christopher C. Stacy
Subject: Re: Socket Programming
Date: 
Message-ID: <uk6yr3ydh.fsf@news.dtpq.com>
>>>>> On Tue, 01 Jun 2004 18:27:09 GMT, Antony Sequeira ("Antony") writes:

 Antony> Karl A. Krueger wrote:
 >> David Steuber <·····@david-steuber.com> wrote:
 >> 
 >>> I don't recall how I got this idea, but I thought that when a
 >>> connection to port 80 was accepted, a seperate port was used for the
 >>> transaction so that the server could continue to listen on port 80.
 >> Here's how I got the same wrong idea at first, which may or may not
 >> be
 >> the same thing.  When a connection to port 80 is accepted, a separate
 >> -socket- is used for the transaction, so the server can continue to
 >> listen on the -server socket-.
 >> (You don't listen on a port; you listen on a socket which is bound
 >> to a
 >> port.  Your -host- is seen to pick up connections on a port, which we
 >> sometimes call "listening on a port", but that's a misnomer.)
 >> 
 Antony> and the data from two different clients is sent to the appropriate
 Antony> server socket based on the originating (client) IP and port ?

Each of the two ends of a TCP connection are defined by a 
tuple of: local-host, local-port, foreign-host, foreign-port.
(You need to read a basic tutorial on networking.)
From: Antony Sequeira
Subject: Re: Socket Programming
Date: 
Message-ID: <PP4vc.3371$495.765@newssvr27.news.prodigy.com>
Christopher C. Stacy wrote:

>>>>>>On Tue, 01 Jun 2004 18:27:09 GMT, Antony Sequeira ("Antony") writes:
> 
> 
>  Antony> Karl A. Krueger wrote:
>  >> David Steuber <·····@david-steuber.com> wrote:
>  >> 
>  >>> I don't recall how I got this idea, but I thought that when a
>  >>> connection to port 80 was accepted, a seperate port was used for the
>  >>> transaction so that the server could continue to listen on port 80.
>  >> Here's how I got the same wrong idea at first, which may or may not
>  >> be
>  >> the same thing.  When a connection to port 80 is accepted, a separate
>  >> -socket- is used for the transaction, so the server can continue to
>  >> listen on the -server socket-.
>  >> (You don't listen on a port; you listen on a socket which is bound
>  >> to a
>  >> port.  Your -host- is seen to pick up connections on a port, which we
>  >> sometimes call "listening on a port", but that's a misnomer.)
>  >> 
>  Antony> and the data from two different clients is sent to the appropriate
>  Antony> server socket based on the originating (client) IP and port ?
> 
> Each of the two ends of a TCP connection are defined by a 
> tuple of: local-host, local-port, foreign-host, foreign-port.
> (You need to read a basic tutorial on networking.)
You can add me to the list of people who got the same confusion as the 
above two people regarding the relation between sockets and the TCP 
ports. I get the feeling that something is lacking in the reading material.
Also see
http://java.sun.com/docs/books/tutorial/networking/sockets/definition.html
where it says
"If everything goes well, the server accepts the connection. Upon 
acceptance, the server gets a new socket bound to a *different port*. It 
needs a new socket (and consequently a different port number) so that it 
can continue to listen to the original socket for connection requests 
while tending to the needs of the connected client."

I am sure they are wrong, but you see where people like me are confused.
Or is it possible that you are wrong (I doubt it)?
-Antony
From: Peter Seibel
Subject: Re: Socket Programming
Date: 
Message-ID: <m365aa9as4.fsf@javamonkey.com>
Antony Sequeira <·············@hotmail.com> writes:

> Also see
> http://java.sun.com/docs/books/tutorial/networking/sockets/definition.html
> where it says "If everything goes well, the server accepts the
> connection. Upon acceptance, the server gets a new socket bound to a
> *different port*. It needs a new socket (and consequently a
> different port number) so that it can continue to listen to the
> original socket for connection requests while tending to the needs
> of the connected client."
>
> I am sure they are wrong, but you see where people like me are
> confused. Or is it possible that you are wrong (I doubt it)?

They're wrong. Or I am. But I'm not. ;-)

You could test their assertion easily enough by writing a bit of code
that opens a ServerSocket on some port then prints the value returned
by getLocalPort() on the socket returned by accept() and see if it
isn't in fact the same as the port you specified (and which would be
retuned by getLocalPort() on the ServerSocket itself.) E.g.

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class ProveSunWrong {

  public static void main (String[] argv) throws IOException {
    ServerSocket ss = new ServerSocket(9876);
    System.out.println("ServerSocket local port: " + ss.getLocalPort());
    Socket s = ss.accept();
    System.out.println("Accepted Socket local port: " + s.getLocalPort());
  }

}

class ProveSunWrongClient {

  public static void main (String[] argv) throws IOException {
    Socket s = new Socket("localhost", 9876);
    System.out.println("Client Socket local port: " + s.getLocalPort());
  }

}

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Antony Sequeira
Subject: Re: Socket Programming
Date: 
Message-ID: <il8vc.3437$_a7.500@newssvr27.news.prodigy.com>
Peter Seibel wrote:

> Antony Sequeira <·············@hotmail.com> writes:
> 
> 
>>Also see
>>http://java.sun.com/docs/books/tutorial/networking/sockets/definition.html
>>where it says "If everything goes well, the server accepts the
>>connection. Upon acceptance, the server gets a new socket bound to a
>>*different port*. It needs a new socket (and consequently a
>>different port number) so that it can continue to listen to the
>>original socket for connection requests while tending to the needs
>>of the connected client."
>>
>>I am sure they are wrong, but you see where people like me are
>>confused. Or is it possible that you are wrong (I doubt it)?
> 
> 
> They're wrong. Or I am. But I'm not. ;-)
> 
> You could test their assertion easily enough by writing a bit of code
> that opens a ServerSocket on some port then prints the value returned
> by getLocalPort() on the socket returned by accept() and see if it
> isn't in fact the same as the port you specified (and which would be
> retuned by getLocalPort() on the ServerSocket itself.) E.g.
> 
>...removed code..
> 
> -Peter
> 
Thank you.

I improved it a bit just to convince myself.
File XX.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class XX {

     public static void main (String[] argv) throws IOException {
         ServerSocket ss = new ServerSocket(9876);
         System.out.println("ServerSocket local port: " + 
ss.getLocalPort());
         while (true) {
             Socket s = ss.accept();
             System.out.println("Accepted Socket" + s + "  local port: " 
+ s.getLocalPort());
         }
     }

}

File YY.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class  YY {

     public static void main (String[] argv) throws IOException {
         for (int i =0; i < 65000; i++) {
             Socket s = new Socket("localhost", 9876);
             System.out.println("Client Socket attempt " + i + " local 
port: " + s.getLocalPort());
         }
     }

}


The serialized print of the socket obtained by 'ss.accept()'
looks something like
    Socket[addr=/127.0.0.1,port=2126,localport=9876]
    Socket[addr=/127.0.0.1,port=2128,localport=9876]

I guess this is the socket port versus TCP port confusion that
Harald Hanche-Olsen was referring to.

(Interestingly the app fails with "Exception java.net.BindException: 
Address already in use", long before making 65000 connections on W2K 
that has 1GB ram)

I am pretty sure the above tutrial is not the beginning of the story, 
the author in turn must have gotten this from somewhere else (just like 
me and the others who posted) because I have had this mis-conception 
long before I learned Java.
Thanks,
-Antony
P.S.: I am sorry about posting java code to c.l.l, but I feel I am 
likely to be more enlightened here than in c.l.j. My ultimate goal is to 
learn how to deal with n/w in Lisp.
From: Antony Sequeira
Subject: Re: Socket Programming
Date: 
Message-ID: <fO8vc.3451$Ln7.1594@newssvr27.news.prodigy.com>
Antony Sequeira wrote:

> 
> The serialized print of the socket obtained by 'ss.accept()'
> looks something like
>    Socket[addr=/127.0.0.1,port=2126,localport=9876]
>    Socket[addr=/127.0.0.1,port=2128,localport=9876]
> 
> I guess this is the socket port versus TCP port confusion that
> Harald Hanche-Olsen was referring to.
> 
Bad guess :(, the 'port' refers to the port number on the remote host to 
which the socket is connected.
-Antony
From: Rob Warnock
Subject: Re: Socket Programming
Date: 
Message-ID: <4OKdnf2DAuxaOCDdRVn-uA@speakeasy.net>
Antony Sequeira  <·············@hotmail.com> wrote:
+---------------
| Antony Sequeira wrote:
| > The serialized print of the socket obtained by 'ss.accept()'
| > looks something like
| >    Socket[addr=/127.0.0.1,port=2126,localport=9876]
| >    Socket[addr=/127.0.0.1,port=2128,localport=9876]
| > 
| > I guess this is the socket port versus TCP port confusion that
| > Harald Hanche-Olsen was referring to.
| > 
| Bad guess :(, the 'port' refers to the port number on the remote host to 
| which the socket is connected.
+---------------

Correct: A TCP[1] connection is defined by a quadruple: {Local address,
Local port, Remote address, Remote port}. If *any* element of that
quadruple is different, you have a different connection. Therefore
*many* TCP connections may have the same Local address/Local port
values...


-Rob

[1] More generally, many (most?) IP/TCP/UDP/xxx-over-IP protocol stacks
    (at least the connection-oriented ones and others that use "ports")
    have some notion of a Protocol Control Block (PCB), which is identified
    when receiving a packet by a quintuple: {Local address, Local port,
    Remote port, Remote address, IP-protocol-type} [where IP-protocol-type
    is TCP (6), UDP (17), or any of the other protocol numbers found in
    "/etc/protocols" (at least on Unix systems). To a rough approximation,
    PCBs are one-to-one with sockets.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Harald Hanche-Olsen
Subject: Re: Socket Programming
Date: 
Message-ID: <pcoisebklzg.fsf@shuttle.math.ntnu.no>
+ Antony Sequeira <·············@hotmail.com>:

| Also see
| http://java.sun.com/docs/books/tutorial/networking/sockets/definition.html
| where it says
| "If everything goes well, the server accepts the connection. Upon
| acceptance, the server gets a new socket bound to a *different
| port*. It needs a new socket (and consequently a different port
| number) so that it can continue to listen to the original socket for
| connection requests while tending to the needs of the connected
| client."
| 
| I am sure they are wrong, but you see where people like me are confused.
| Or is it possible that you are wrong (I doubt it)?

Here are some lines from the output of sockstat on the (FreeBSD)
machine on which I write this:

USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
hanche   chatter    10382 0  tcp4   10.0.0.2:9898         10.0.0.1:1031
hanche   chatter    10382 1  tcp4   10.0.0.2:9898         10.0.0.1:1031
hanche   tcpserver  10381 3  tcp4   10.0.0.2:9898         *:*

As you can see, the original tcpserver is happily listening on port
9898 and IP address 10.0.0.2 while another processes is communicating
using the same port number and address.

Now the word "socket" is used in slightly different ways in RFC 793,
which defines TCP, and on Unix, which may be the cause of some
confusion.  According to RFC 793,

    To allow for many processes within a single Host to use TCP
    communication facilities simultaneously, the TCP provides a set of
    addresses or ports within each host.  Concatenated with the network
    and host addresses from the internet communication layer, this forms
    a socket.  A pair of sockets uniquely identifies each connection.
    That is, a socket may be simultaneously used in multiple
    connections.

But the man page for accept(2) on FreeBSD says

     The accept() system call extracts the first connection request on
     the queue of pending connections, creates a new socket [sic] with
     the same properties as s, and allocates a new file descriptor for
     the socket.

So according to Unix, a socket is a data structure whose properties
include those of an RFC 793 socket (an IP address and a port number),
but several of these data structures can specify the same local socket
(in the RFC 793 sense).

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- Debating gives most of us much more psychological satisfaction
  than thinking does: but it deprives us of whatever chance there is
  of getting closer to the truth.  -- C.P. Snow
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87ekoymwiz.fsf@david-steuber.com>
"Karl A. Krueger" <········@example.edu> writes:

> David Steuber <·····@david-steuber.com> wrote:
> > I don't recall how I got this idea, but I thought that when a
> > connection to port 80 was accepted, a seperate port was used for the
> > transaction so that the server could continue to listen on port 80.
> 
> Here's how I got the same wrong idea at first, which may or may not be
> the same thing.  When a connection to port 80 is accepted, a separate
> -socket- is used for the transaction, so the server can continue to
> listen on the -server socket-.
> 
> (You don't listen on a port; you listen on a socket which is bound to a
> port.  Your -host- is seen to pick up connections on a port, which we
> sometimes call "listening on a port", but that's a misnomer.)

That is almost certainly where I got the idea.  In Java terms,
accepting a connection from a ServerSocket gives you a Socket.  IIRC.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Rob Warnock
Subject: Re: Socket Programming
Date: 
Message-ID: <rKCdnW5S8cpYfibdRVn-iQ@speakeasy.net>
David Steuber  <·····@david-steuber.com> wrote:
+---------------
| Peter Seibel <·····@javamonkey.com> writes:
| > That doesn't matter to the server. Every connection to a server is to
| > the same port anyway (typically). It's the client IP-address/port that
| > makes the connection unique. So while it's true that I can only have
| > (expt 2 16) connections from a single client IP address, I can have
| > many, many connections from many, many clients.
| 
| Another poster also corrected my misconceptions about sockets.  The
| reason I thought there was a limit on server connections was the way I
| thought accept worked.  I don't recall how I got this idea...
+---------------

Did you even play with the Xerox XNS protocol stack (or the Novell
Netware stack, which used a lightly-hacked version of XNS)? XNS's
Sequenced Packet Protocol worked the way you thought IP/TCP did:
"Well-known sockets" were only used to receive connection requests,
which contained a connection-request ID. The actual response was
from a different, random server socket, which replied with the given
connection-request ID (so the client knew which connection request
the reply was for). And, yes, socket numbers were only 16 bits, so
the ~65K connection limit applied [since the whole point of the reply
protocol was to make it possible to demultiplex received packets
based on destination socket number *only*!].

As Peter says, though, IP/TCP doesn't work that way...


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Tim Bradshaw
Subject: Re: Socket Programming
Date: 
Message-ID: <fbc0f5d1.0406011100.3df07226@posting.google.com>
David Steuber <·····@david-steuber.com> wrote in message news:<··············@david-steuber.com>...
> Peter Seibel <·····@javamonkey.com> writes:

> I don't think you need to worry about the 100,000 simultaneous
> connection problem.  IPv4 supports only 2^16 ports.  Even if a process
> could get 100,000 file descriptors, there would be no way for one
> machine to have that many open IP connections.  This is actually a
> major reason for the HTTP protocol vs FTP where a typical session is
> much longer.  IP connections are a very limited resource.
> 

There can be multiple connections open to a port.  The requirement is
that the tuple (source port, source IP, dest port, dest IP) is unique
(see below).  For something like an active web server there could be
very many active connections.

Example:

$ netstat -n | fgrep :22
tcp        0      0 127.0.0.1:22            127.0.0.1:55814        
ESTABLISHED
tcp        0      0 192.168.11.143:60240    10.168.72.110:22       
ESTABLISHED
tcp        0      0 127.0.0.1:55814         127.0.0.1:22           
ESTABLISHED
tcp        0      0 127.0.0.1:55805         127.0.0.1:22           
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.34.142:1223    
ESTABLISHED
tcp        0      0 127.0.0.1:22            127.0.0.1:55805        
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.34.151:49458   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.34.151:47398   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.34.151:49667   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.34.151:49021   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.11.116:34691   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.34.151:42401   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.11.116:52380   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.35.152:4773    
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.11.116:36304   
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.35.152:3294    
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.35.152:3293    
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.35.152:3292    
ESTABLISHED
tcp        0      0 192.168.11.143:22       192.168.35.152:3291    
ESTABLISHED
From: Ingvar
Subject: Re: Socket Programming
Date: 
Message-ID: <m2pt8j32w9.fsf@head.cathouse.bofh.se>
David Steuber <·····@david-steuber.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
> 
> > As I understand it the point of the C10K page is that at the OS
> > level--at least in mainstream OS's--there's no good solution to the
> > problem of keeping track of which of 10,000 (let alone 100,000)
> > connections may have data to deal with. Unless I'm misunderstanding
> > them there's little that better languages or ways of thinking about
> > writing concurrent software can do to fix *that* particular problem.
> 
> I don't think you need to worry about the 100,000 simultaneous
> connection problem.  IPv4 supports only 2^16 ports.  Even if a process
> could get 100,000 file descriptors, there would be no way for one
> machine to have that many open IP connections.  This is actually a
> major reason for the HTTP protocol vs FTP where a typical session is
> much longer.  IP connections are a very limited resource.

Each TCP session is identified by a quadruple:
   <src IP, src port, dst IP, dst port>

As long as your 100k sessions are from 2 machines or more, you can
(theoretically) accomodate that many sessions ( make it to be about
1.5 machines, so I'll say 2 to be on the safe side).

As for HTTP/FTP, I'd say that the main problem is taht FTP is an
inherently messy protocol. Works well, but can't do "exciting" things
like name-based virtual servers.

Likewise, there's a reason why there's a keep-alive "multiple requests
in one TCP sessions" mechanism in HTTP/1.1 and taht's because opening
a TCP session is a relatively expensive operation (besides, multiple
requests from a single client to a single server is "wasteful" of the
precious TCP resources).

//Ingvar
-- 
When C++ is your hammer, everything looks like a thumb
	Latest seen from Steven M. Haflich, in c.l.l
From: Scott A Crosby
Subject: Re: Socket Programming
Date: 
Message-ID: <oydy8n8w84i.fsf@bert.cs.rice.edu>
On Fri, 28 May 2004 18:07:19 GMT, Peter Seibel <·····@javamonkey.com> writes:

> As I understand it the point of the C10K page is that at the OS
> level--at least in mainstream OS's--there's no good solution to the
> problem of keeping track of which of 10,000 (let alone 100,000)
> connections may have data to deal with. Unless I'm misunderstanding
> them there's little that better languages or ways of thinking about
> writing concurrent software can do to fix *that* particular problem.

I think the problem is an API-level problem. The kernel knows when a
packet arrives to a socket, and a socket now has data to read. AFAIK,
The problem is that until recently there wasn't really a good scalable
way to get this information across the syscall interface. What I read
in the c10k page was that there are new [not yet standardized] ways to
now get this information out of the system.

When using select or poll, there may be libc/kernel limitations on the
maximum number of file descriptors in any request. Worse, passing
10,000 fd's to the kernel is going to take O(n) time just to assemble
the list, then O(n) time for the kernel to check all of the fd's for
data, and again O(n) time for the program to check the result.

The approaches on the c10k are API enhancements where the program
informs the kernel that it wants notification of read/write ability on
a fd, the kernel then asyncroniously queues up only the fd's that
change, the program then queries the kernel for the queue without
having to scan the inactive fd's.

According to results on http://lse.sourceforge.net/epoll/index.html
this at least in theory can scale to huge numbers of open fd's.  A
program running with 16000 open pipes implementing a token-passing
microbenchmark was able to deal with 300k token-passes per second. A
poll-based microbenchmark was at least a hundred times worse.

Scott
From: Ray Dillinger
Subject: Re: Socket Programming
Date: 
Message-ID: <WvFAc.17608$Fo4.227866@typhoon.sonic.net>
David Steuber wrote:
> Eric Marsden <········@laas.fr> writes:
> 
> 
>>[reacting a bit late to this interesting thread]  
> 
> 
> I've actually been thinking about this recently.  Inside the last hour
> in fact.  Just to recap, there are two basic models I would consider
> using for a TCP service:
> 
> * Single threaded application that multiplexes concurrent connections
>   and uses non-blocking io.
> * Multi threaded application that uses one thread per connection
>   request and blocking io.
> 

These both have problems.  a single-threaded application that
multiplexes concurrent connections and uses non-blocking I/O
escapes thread overhead, but as the number of connections
increases, it spends a lot of time servicing threads for
which there is no input.

What I really want in this circumstance is in two parts:  first,
an interrupt service routine that takes incoming bytes and
puts them on a single input queue along with their connection
number, and second, a single-threaded application that reads
and processes that queue of incoming bytes + connection number.

But the interrupt service routine means replacing some stuff
that's normally in the TCP stack, so...  it's difficult.  You
usually have to be root to make this work.

				Bear
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvk6zdwox5.fsf@famine.OCF.Berkeley.EDU>
Peter Seibel <·····@javamonkey.com> writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> So I want to make sure I understand what happens under the covers
> >> here--each time a new cliet connects the SERVE-EVENT mechanism notices
> >> that there's stuff to do with *SERVER-SOCKET* and calls
> >> SERVE-CONNECTION to deal with it.
> >
> > Yep.
> >
> >> Within that call you make potentially blocking I/O calls such as to
> >> the database, etc. What happens if another connection comes in
> >> before the first call to SERVE-CONNECTION returns?
> >
> > It calls SERVE-CONNECTION.  If you're dealing with connections from
> > the open internet, you want to have a counter that your handler checks
> > before accepting a client, to keep a maximum number on the number of
> > connections you're serving, so you have a base case for your
> > recursion.
> 
> So doesn't that mean that within SERVE-CONNECTION I still have to take
> care of synchronizing access to shared data (such as the database
> connection pool)? I.e. I'm still running a multi-threaded app It just
> happens that I'm not spinning up the threads.

You do have to synchronize access to shared resources.  However, the
only time another handle gets a chance to run is when you do I/O and
it blocks, or when you call SERVE-EVENT.  This makes synchronization a
lot easier; eg, you have to worry about individual db connections, but
not access to the pool itself, unless you do something crazy like find
the index of the connection you want to use, do some I/O, then try to
remove it from the pool.

> Also does this imply a thread-per-connection under the
> covers. Because that's not a great way to write a scalable server.

Nope, it's a facility from the days before most Unixes had threads.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Nils Gösche
Subject: Re: Socket Programming
Date: 
Message-ID: <871xlpb67c.fsf@darkstar.cartan.de>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> ···@cartan.de (=?iso-2022-jp-2?b?TmlscyBHGy5BG052c2NoZQ==?=) writes:
> 
> > Frankly, I would prefer to do such a thing with threads.  Have a
> > thread waiting for TCP connections and nothing else, that will create
> > another thread for every client connecting to your program, and have
> > yet another thread waiting for other forms of input (and nothing
> > else).  Blocking reads all over the place.  Unfortunately, I don't
> > know if CLISP supports threads...
> 
> That sounds easier or simpler to you?!?!

Actually, yes :) I do the select thing with non-blocking I/O all the
time when I write C code.  When writing Lisp, however, I prefer to use
threads.  As most Lisps do their own thread scheduling, there is a
select somewhere in the heart of the thing, too, of course.  So, you
could view threads as an abstraction over select, too :-)  How do you
do non-blocking I/O in Lisp, anyway?

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Thomas F. Burdick
Subject: Re: Socket Programming
Date: 
Message-ID: <xcvpt99xg8k.fsf@famine.OCF.Berkeley.EDU>
···@cartan.de (Nils G�sche) writes:

> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > ···@cartan.de (=?iso-2022-jp-2?b?TmlscyBHGy5BG052c2NoZQ==?=) writes:
> > 
> > > Frankly, I would prefer to do such a thing with threads.  Have a
> > > thread waiting for TCP connections and nothing else, that will create
> > > another thread for every client connecting to your program, and have
> > > yet another thread waiting for other forms of input (and nothing
> > > else).  Blocking reads all over the place.  Unfortunately, I don't
> > > know if CLISP supports threads...
> > 
> > That sounds easier or simpler to you?!?!
> 
> Actually, yes :) I do the select thing with non-blocking I/O all the
> time when I write C code.

You do remember that SERVE-EVENT is a Lisp facility, not a C one, right? ;)

> When writing Lisp, however, I prefer to use
> threads.  As most Lisps do their own thread scheduling, there is a
> select somewhere in the heart of the thing, too, of course.  So, you
> could view threads as an abstraction over select, too :-)  How do you
> do non-blocking I/O in Lisp, anyway?

I let SERVE-EVENT take care of it.  I setup handlers on the FDs I care
about, then enter the SERVE-EVENT loop.  When I do I/O, I use the
stream interface, which DTRT with SERVE-EVENT; when I/O blocks, other
event handlers have a chance to run.

You do still have concurrency issues to contend with, of course.  If
some handler is using the database connection, you don't want another
one to use the same connection; but that's nothing new.  Unlike with
threads, you don't need to bother with locks, because everything
between I/O calls is atomic.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Nils Gösche
Subject: Re: Socket Programming
Date: 
Message-ID: <87r7tolh99.fsf@darkstar.cartan.de>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> ···@cartan.de (Nils G�sche) writes:
> 
> > Actually, yes :) I do the select thing with non-blocking I/O all
> > the time when I write C code.
> 
> You do remember that SERVE-EVENT is a Lisp facility, not a C one,
> right? ;)

Yes, yes ;-)

> > When writing Lisp, however, I prefer to use threads.  As most
> > Lisps do their own thread scheduling, there is a select somewhere
> > in the heart of the thing, too, of course.  So, you could view
> > threads as an abstraction over select, too :-) How do you do
> > non-blocking I/O in Lisp, anyway?
> 
> I let SERVE-EVENT take care of it.  I setup handlers on the FDs I
> care about, then enter the SERVE-EVENT loop.  When I do I/O, I use
> the stream interface, which DTRT with SERVE-EVENT; when I/O blocks,
> other event handlers have a chance to run.

Aaah, this is the part I missed.  Ok, it /does/ look like a nice
mechanism, then.  Something I'll probably use whenever I don't have
any threads available :->

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Peter Herth
Subject: Re: Socket Programming
Date: 
Message-ID: <c7vc1u$clu$1@newsreader2.netcologne.de>
Nils G????? wrote:

> Well, decide for yourself:
> 
> http://www.pmsf.de/pub/cmucl/doc/cmu-user/serve-event.html#toc225
> 
> Frankly, I would prefer to do such a thing with threads.  Have a
> thread waiting for TCP connections and nothing else, that will create
> another thread for every client connecting to your program, and have
> yet another thread waiting for other forms of input (and nothing
> else).  Blocking reads all over the place.  Unfortunately, I don't
> know if CLISP supports threads...

It very depends on what you want to do. If you plan to process the
data recieved via a socket more or less in parallel (like a web server),
threads might be a good idea. However, if the only reason to use threads
is to get non-blocking IO, I think they are really bad and select-style
approaches are much better. Threads on many systems involve quite some
overhead, so much that for example Java introduced select style IO in
the never VM versions, in spite of having thread support in the language.
The reason is, if you want to handle many (hundreds) of socket connections,
the threads' stack space allone can eat up your heap. Furthermore, you have
to synchronize the data recieved by the threads with your main program
logic. (By the way: which would be the Common Lisp aequivalent to the
Java "synchronized" ?)

Peter
From: David Steuber
Subject: Re: Socket Programming
Date: 
Message-ID: <87oeosnu0t.fsf@david-steuber.com>
Peter Herth <·····@netcologne.de> writes:

> Nils G????? wrote:
> 
> > Well, decide for yourself:
> > 
> > http://www.pmsf.de/pub/cmucl/doc/cmu-user/serve-event.html#toc225
> > 
> > Frankly, I would prefer to do such a thing with threads.  Have a
> > thread waiting for TCP connections and nothing else, that will create
> > another thread for every client connecting to your program, and have
> > yet another thread waiting for other forms of input (and nothing
> > else).  Blocking reads all over the place.  Unfortunately, I don't
> > know if CLISP supports threads...
> 
> It very depends on what you want to do. If you plan to process the
> data recieved via a socket more or less in parallel (like a web server),
> threads might be a good idea. However, if the only reason to use threads
> is to get non-blocking IO, I think they are really bad and select-style
> approaches are much better. Threads on many systems involve quite some
> overhead, so much that for example Java introduced select style IO in
> the never VM versions, in spite of having thread support in the language.
> The reason is, if you want to handle many (hundreds) of socket connections,
> the threads' stack space allone can eat up your heap. Furthermore, you have
> to synchronize the data recieved by the threads with your main program
> logic. (By the way: which would be the Common Lisp aequivalent to the
> Java "synchronized" ?)

sb-thread has mutexes.  For "synchronized" you can use a mutex that
was created for the object (say a hashtable) that needs to be
synchronized by wrapping the access in something like:

(sb-thread:with-mutex (mutex) ...)

You bring up a very good point about stack space.  But on a
multiprocessor machine, native threads let you use all the CPUs.  I
guess the other way to do that would be to run a process per CPU.
After all, only one thread (or process) per CPU can actually be
getting CPU time.  If the address space allows it, I would think that
multiple threads in a single process space would be easier.  With
multiple processes, you need some way to share information across
process boundries.

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Peter Herth
Subject: Re: Socket Programming
Date: 
Message-ID: <c80je3$qno$1@newsreader2.netcologne.de>
David Steuber wrote:

> sb-thread has mutexes.  For "synchronized" you can use a mutex that
> was created for the object (say a hashtable) that needs to be
> synchronized by wrapping the access in something like:
> 
> (sb-thread:with-mutex (mutex) ...)

Thank you, that was what I looked for.
 
> You bring up a very good point about stack space.  But on a
> multiprocessor machine, native threads let you use all the CPUs.  I
> guess the other way to do that would be to run a process per CPU.
> After all, only one thread (or process) per CPU can actually be
> getting CPU time.  If the address space allows it, I would think that
> multiple threads in a single process space would be easier.  With
> multiple processes, you need some way to share information across
> process boundries.

Of course, if you want to do things in parallel, threads are the way 
to go. But as this whole thread started - if you only want to do IO
on multiple sockets, select should be the optimal solution. Like for
example a multi-user game engine, where input from all connections 
is collected and then all this input is processed in the main game loop.
Here multithreading really would make things more difficult. 

Peter
From: Nils Gösche
Subject: Re: Socket Programming
Date: 
Message-ID: <87pt987z2q.fsf@darkstar.cartan.de>
Peter Herth <·····@netcologne.de> writes:

> Of course, if you want to do things in parallel, threads are the way
> to go. But as this whole thread started - if you only want to do IO
> on multiple sockets, select should be the optimal solution. Like for
> example a multi-user game engine, where input from all connections
> is collected and then all this input is processed in the main game
> loop.  Here multithreading really would make things more difficult.

Are you really so sure about this?  Again, I use the select/event
approach in C all the time, and the other one in Lisp all the time,
too.  I really know both, and the thread approach seems a lot easier
to me.  OTOH, I also have a feeling that threads (and their
concurrency issues) are somehow easier to handle in Lisp than in C,
but I must admit that I have absolutely no idea, why.

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Alain Picard
Subject: Re: Socket Programming
Date: 
Message-ID: <873c63kjpr.fsf@memetrics.com>
···@cartan.de (Nils G�sche) writes:

> OTOH, I also have a feeling that threads (and their
> concurrency issues) are somehow easier to handle in Lisp than in C,
> but I must admit that I have absolutely no idea, why.

It's mostly because of how naturally you can encapsulate thread-specific
resources in special variables, I think.
From: Nils Gösche
Subject: Re: Socket Programming
Date: 
Message-ID: <87hduj9b04.fsf@darkstar.cartan.de>
Alain Picard <············@memetrics.com> writes:

> ···@cartan.de (Nils G�sche) writes:
> 
> > OTOH, I also have a feeling that threads (and their concurrency
> > issues) are somehow easier to handle in Lisp than in C, but I must
> > admit that I have absolutely no idea, why.
> 
> It's mostly because of how naturally you can encapsulate
> thread-specific resources in special variables, I think.

Good point; I definitely use this a lot.  It might very well be the
cause for my impression.

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x7E4651AD
From: Peter Herth
Subject: Re: Socket Programming
Date: 
Message-ID: <c821jt$k9r$1@newsreader2.netcologne.de>
Nils G�sche wrote:

> Are you really so sure about this?  Again, I use the select/event
> approach in C all the time, and the other one in Lisp all the time,
> too.  I really know both, and the thread approach seems a lot easier
> to me.  OTOH, I also have a feeling that threads (and their
> concurrency issues) are somehow easier to handle in Lisp than in C,
> but I must admit that I have absolutely no idea, why.

I have no extensive experience doing it with Lisp, though I tried
both approaches with CMUCL and was happier using the select style
approach. I have some experience from Java as of using the thread-style
approach in Dawn (http://dawn.netcologne.de, a multi player MUD) since
Java did not offer an alternative back then. But once I get around, 
I will definitely try the new select based IO system. In Dawn, threads 
are solely used to get IO non-blocking and this carries a heavy overhead 
if you start having 30 or more threads just for this task. Especially
since the main game loop is by purpose a single thread as you want
the game events happen synchronized to each other.
Toying around, I ported some parts of Dawn to CL and for this kind
of application, the select based approch worked nicely with CMUCL.
The mainloop looks like:
(loop
  (sys:serve-all-events 0) ;; reads any possible input from players
  do 1 round of game logic handling...
  write buffered output to all players ...
  (sleep 0.25))
which is very "natural" for the task at hand. In the input file handlers
for the single sockets, I do not use read-line but rather unix-read which
works like the C read function - read nonblocking up to a specified number
of bytes. 

Peter

-- 
pet project: http://dawn.netcologne.de
homepage:    http://www.peter-herth.de
lisp stuff:  http://www.peter-herth.de/lisp.html
From: Johannes Groedem
Subject: Re: Socket Programming
Date: 
Message-ID: <lz4qqlekaz.fsf@unity.copyleft.no>
* Ari Johnson <·····@hotmail.com>:

> I can't see how to do this in CLISP, as there doesn't seem to be an
> operator that will wait on the right conditions.  Is there a
> portable socket library that does this better (avoiding my having to
> do any FFI coding), or a way to do it within the confines of CLISP?

Can't you use #'socket:socket-status?

http://clisp.sourceforge.net/impnotes/socket.html

-- 
Johannes Gr�dem <OpenPGP: 5055654C>
From: Ari Johnson
Subject: Re: Socket Programming
Date: 
Message-ID: <VWroc.119763$Jy3.39999@fed1read03>
Johannes Groedem wrote:

> * Ari Johnson <·····@hotmail.com>:
> 
> 
>>I can't see how to do this in CLISP, as there doesn't seem to be an
>>operator that will wait on the right conditions.  Is there a
>>portable socket library that does this better (avoiding my having to
>>do any FFI coding), or a way to do it within the confines of CLISP?
> 
> 
> Can't you use #'socket:socket-status?
> 
> http://clisp.sourceforge.net/impnotes/socket.html
> 

Ah!  I was using an inferior browser at work and entirely missed "...or 
whether a connection is available on a SOCKET:SOCKET-SERVER".  I was 
operating under the impression that socket:socket-status would only 
operate on the socket-streams.  I'll experiment with that later to do, 
and try again to get it to work right when I want it to destructively 
modify a list as it claims to.

Thanks.