I have completed the port of my network server from C to Common LISP. As
you may recall, I started with CLISP (because I was familiar with it and
because I liked the implementation). After running into a few road-blocks,
I decided to port it to CMUCL as a tool for comparison. (My experience with
CMUCL in the past was not very pleasant.)
I can now make the following generalizations about CLISP/CMUCL from the
standpoint of a single-threaded TCP-based network server:
1. Sockets. Both implementations (via their FFI) can provide reasonable
bindings to sockets. Definitely avoid socket streams, though. For my
TELNET server I needed access to: socket, bind, listen, accept, send, recv,
close, select, fcntl, setsckopt and getsockopt. All but the send/recv and
select interface could be handled with more or less equal facility in CLISP
and CMUCL. select() would have been more natural in CLISP, except that it
doesn't allow you to create a heap-resident foreign-pointer. If it had, I
would have allocated 3 fd-set objects on the heap and re-used them over and
over. CMUCL doesn't handle this any better, though. I have to convert
bignums into fd-sets for each select() call. CMUCL wins on send/recv. The
ability to create SAPs from data arrays is a big win for CMUCL. If
possible, CLISP's FFI should be enhanced to provide them IMO.
2. Inrerrupts. CMUCL's interrupt handling is definitely superior. By
stealing the SIGALRM handler and defining it as: (lambda () (incf *ticks*)),
it become very easy even in a single-thread to interleave time processing
with select() processing.
3. I have not played with CMUCL threads. Since my C design was
single-threaded already, and I was hoping to use CLISP as my implementation,
I decided to keep it single-threaded. However, now that I have it running
under CMUCL, I may decide to use MySQL (as opposed to flat files) for my
data storage. A multi-threaded environment makes this more palatable (for
real-time response reasons).
1. CLISPs FFI is quite good. It could improve with heap allocated foreign
object types and CMUCL's SAPs are a clear win.
2. Being able to attach LISP code to a SIGALRM proved extremely handy, not
only as a way to keep track of time in general, but as a way to cause
select() to terminate as time events occur.
3. Threads are not necessary, but they're a nice convenience.
Sadly, I think I have made the transition to CMUCL for this application.