;; low-level socket use ;; simple http-server, ruby/httpd model with queue (use gauche.threads) (use gauche.net) (define (make-synchronised-queue) (let ((mutex (make-mutex)) (available-cv (make-condition-variable)) (head ()) (tail ())) (define (empty?) (null? head)) (define (enqueue item) (mutex-lock! mutex) (let ((new-pair (cons item ()))) (cond ((empty?) (set! head new-pair) (set! tail new-pair)) (else (set-cdr! tail new-pair) (set! tail new-pair)))) (format #t "(enqueue l=~d)\n" (length head)) (condition-variable-broadcast! available-cv) (mutex-unlock! mutex)) (define (dequeue) (mutex-lock! mutex) (cond ((empty?) (mutex-unlock! mutex available-cv) (dequeue)) (else (let1 result (car head) (set! head (cdr head)) (format #t "(dequeue l=~d)\n" (length head)) (mutex-unlock! mutex) result)))) ;; dispatcher (lambda args (apply (case (car args) ((enqueue push) enqueue) ((dequeue pop) dequeue) ((empty?) empty?)) (cdr args))))) (define (parallel-execute . args) "each arg is a thunk, to be run in a separate thread" (let ((threads ())) (dolist (thunk args) (push! threads (thread-start! (make-thread thunk)))) (map thread-join! threads))) (define-macro (forever . body) `(do () (#f) ,@body)) (define server (car (make-server-sockets "localhost" 1234 :reuse-addr? #t))) (define requests (make-synchronised-queue)) (define (listener) (set-signal-handler! SIGINT (lambda (sig) (print "for to die! " sig) (socket-close server))) (forever (print "listener: doing just that") (let ((client (socket-accept server))) (print "listener: accepted " client) (requests 'push client)))) (define (handler) (forever (let ((client (requests 'pop))) (print "handler: doing " client) (format (socket-output-port client) "echo: ~s\n" (read-line (socket-input-port client :buffered? #f))) (print "handler: done") (socket-close client)))) (parallel-execute listener) (handler)