1 ;; maxima-server.lisp -- create simultaneous, independent Maxima sessions via POSIX fork
3 ;; Copyright 2007 by Robert Dodier.
4 ;; I release this file under the terms of
5 ;; the GNU General Public License.
7 ;; The function SERVER-RUN implements a simple Unix server:
8 ;; listen, accept, fork.
10 ;; Actually fork is called twice and child exits immediately,
11 ;; so the grandchild process cannot become a zombie.
13 ;; This code only works for SBCL. It might work with some modification
14 ;; for other Lisps which have POSIX functions.
16 ;; This code is experimental and if it causes all kinds of errors,
17 ;; that's to be expected.
24 ;; (%i1) load ("./maxima-server.lisp");
25 ;; (%i2) :lisp (server-run)
26 ;; JUST BEFORE SOCKET-ACCEPT ...
27 ;; (etc etc log messages here)
31 ;; $ telnet localhost 1042
32 ;; Trying 127.0.0.1...
33 ;; Connected to localhost.
34 ;; Escape character is '^]'.
36 ;; (%i2) build_info ();
38 ;; Maxima version: 5.12.0cvs
39 ;; Maxima build date: 9:5 5/12/2007
40 ;; host type: i686-pc-linux-gnu
41 ;; lisp-implementation-type: SBCL
42 ;; lisp-implementation-version: 1.0
50 (defvar listening-socket
(make-instance 'sb-bsd-sockets
:inet-socket
:type
:stream
:protocol
:tcp
))
51 (sb-bsd-sockets:socket-bind listening-socket
(sb-bsd-sockets:make-inet-address
"127.0.0.1") 1042)
52 (sb-bsd-sockets:socket-listen listening-socket
5)
56 (format t
"JUST BEFORE SOCKET-ACCEPT ...~%")
57 (multiple-value-bind (working-socket peer-address
) (sb-bsd-sockets:socket-accept listening-socket
)
58 (format t
"ACCEPTED CLIENT; PEER-ADDRESS = ~S~%WORKING-SOCKET = ~S~%" peer-address working-socket
)
60 ; Conventional Unix hackery here:
61 ; fork twice and immediate exit first child process,
62 ; so that grandchild is eventually inherited by init process;
63 ; thus grandchild doesn't become a zombie.
65 (let ((child-pid (sb-posix:fork
)))
67 (let ((grandchild-pid (sb-posix:fork
)))
68 (if (eql grandchild-pid
0)
70 ; Grandchild process: I execute the Maxima session here.
72 ((working-stream (sb-bsd-sockets:socket-make-stream working-socket
:input t
:output t
))
73 (*standard-input
* working-stream
)
74 (*standard-output
* working-stream
))
75 (handler-case (cl-user::run
)
77 (format t
"SERVER-RUN RETURNED; GRANDCHILD NOW QUITS~%")
78 (sb-bsd-sockets:socket-close working-socket
)
81 ; Child process: I exit immediately.
82 (format t
"CHILD: IMMEDIATE EXIT; GRANDCHILD PID = ~S~%" grandchild-pid
)
83 (sb-bsd-sockets:socket-close working-socket
)
86 (format t
"PARENT: WAIT FOR CHILD; CHILD PID = ~S~%" child-pid
)
87 (sb-bsd-sockets:socket-close working-socket
)
88 (sb-posix:waitpid child-pid
0)))))))