File: maxima-server.lisp

package info (click to toggle)
maxima 5.47.0-9
  • links: PTS
  • area: main
  • in suites: forky
  • size: 193,104 kB
  • sloc: lisp: 434,678; fortran: 14,665; tcl: 10,990; sh: 4,577; makefile: 2,763; ansic: 447; java: 328; python: 262; perl: 201; xml: 60; awk: 28; sed: 15; javascript: 2
file content (89 lines) | stat: -rw-r--r-- 3,165 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
;; maxima-server.lisp -- create simultaneous, independent Maxima sessions via POSIX fork
;;
;; Copyright 2007 by Robert Dodier.
;; I release this file under the terms of
;; the GNU General Public License.
;;
;; The function SERVER-RUN implements a simple Unix server:
;; listen, accept, fork.
;;
;; Actually fork is called twice and child exits immediately,
;; so the grandchild process cannot become a zombie.
;;
;; This code only works for SBCL. It might work with some modification
;; for other Lisps which have POSIX functions.
;;
;; This code is experimental and if it causes all kinds of errors,
;; that's to be expected.
;;
;; Example:
;;
;; Server:
;;
;; $ maxima
;; (%i1) load ("./maxima-server.lisp");
;; (%i2) :lisp (server-run)
;; JUST BEFORE SOCKET-ACCEPT ...
;; (etc etc log messages here)
;;
;; Client:
;;
;; $ telnet localhost 1042
;; Trying 127.0.0.1...
;; Connected to localhost.
;; Escape character is '^]'.
;; Maxima restarted.
;; (%i2) build_info ();
;; 
;; Maxima version: 5.12.0cvs
;; Maxima build date: 9:5 5/12/2007
;; host type: i686-pc-linux-gnu
;; lisp-implementation-type: SBCL
;; lisp-implementation-version: 1.0
;; 
;; (%o2) 
;; (%i3) ^]
;; telnet> quit
;; Connection closed.


(defvar listening-socket (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))
(sb-bsd-sockets:socket-bind listening-socket (sb-bsd-sockets:make-inet-address "127.0.0.1") 1042)
(sb-bsd-sockets:socket-listen listening-socket 5)

(defun server-run ()
  (loop do
    (format t "JUST BEFORE SOCKET-ACCEPT ...~%")
    (multiple-value-bind (working-socket peer-address) (sb-bsd-sockets:socket-accept listening-socket)
      (format t "ACCEPTED CLIENT; PEER-ADDRESS = ~S~%WORKING-SOCKET = ~S~%" peer-address working-socket)
  
      ; Conventional Unix hackery here:
      ; fork twice and immediate exit first child process,
      ; so that grandchild is eventually inherited by init process;
      ; thus grandchild doesn't become a zombie.
  
      (let ((child-pid (sb-posix:fork)))
        (if (eql child-pid 0)
          (let ((grandchild-pid (sb-posix:fork)))
            (if (eql grandchild-pid 0)
              (progn
                ; Grandchild process: I execute the Maxima session here.
                (let*
                  ((working-stream (sb-bsd-sockets:socket-make-stream working-socket :input t :output t))
                   (*standard-input* working-stream)
                   (*standard-output* working-stream))
                  (handler-case (cl-user::run)
                    (error nil t)))
                (format t "SERVER-RUN RETURNED; GRANDCHILD NOW QUITS~%")
                (sb-bsd-sockets:socket-close working-socket)
                (sb-ext:quit))
              (progn
                ; Child process: I exit immediately.
                (format t "CHILD: IMMEDIATE EXIT; GRANDCHILD PID = ~S~%" grandchild-pid)
                (sb-bsd-sockets:socket-close working-socket)
                (sb-ext:quit))))
          (progn
            (format t "PARENT: WAIT FOR CHILD; CHILD PID = ~S~%" child-pid)
            (sb-bsd-sockets:socket-close working-socket)
            (sb-posix:waitpid child-pid 0)))))))