Yesterday, I talked about the state machine macro I used, but forgot to show the actual macro. If anybody wants to see it, email me.
pt
Oh yes indeed!
Brian C.
p.s. I was aware of the meet last night, but was hit late in the day with some urgent work and had to bail out.
From: Paul Tarvydas [mailto:tarvydas@visualframeworksinc.com] Sent: Wednesday, April 08, 2009 3:21 PM To: toronto-lisp@common-lisp.net Subject: [toronto-lisp] state machine macro
Yesterday, I talked about the state machine macro I used, but forgot to show the actual macro. If anybody wants to see it, email me.
pt
On Wednesday 08 April 2009 3:22:49 pm Brian Connoy wrote:
Oh yes indeed!
Brian C.
p.s. I was aware of the meet last night, but was hit late in the day with some urgent work and had to bail out.
From: Paul Tarvydas [mailto:tarvydas@visualframeworksinc.com] Sent: Wednesday, April 08, 2009 3:21 PM To: toronto-lisp@common-lisp.net Subject: [toronto-lisp] state machine macro
Yesterday, I talked about the state machine macro I used, but forgot to show the actual macro. If anybody wants to see it, email me.
pt
Brian
Sorry for the delay. Here it is. Feel free to ask questions.
pt
Hi Paul,
On Wed, Apr 08, 2009 at 03:21:16PM -0400 or thereabouts, Paul Tarvydas wrote:
Yesterday, I talked about the state machine macro I used, but forgot to show the actual macro. If anybody wants to see it, email me.
Thanks for showing us your approach to state machines. I found it really interesting and seeing some use cases and the expansion was enough for me to mostly figure out how your macro works (I think).
In my webserver program Antiweb I have a different approach to state machines. A state machine is a closure which you can send messages to by funcalling it. It will return a new closure which represents the new state of the state machine.
Here is the macro:
(defmacro fsm (name &rest body) (unless (symbolp name) (error "fsm needs symbol for name")) `(let (,name) (declare (ignorable ,name)) (setq ,name (lambda () ,@body))))
And here is how to use it in your light switch use case:
* (fsm on (format t "Turning OFF~%") (fsm off (format t "Turning ON~%") on))
#<Interpreted Function "FSM ON" {5812CF11}>
Now we can invoke it a few times:
* (funcall *) Turning OFF #<Interpreted Function "FSM ON" {5812D7A9}>
* (funcall *) Turning ON #<Interpreted Function "FSM ON" {5812CF11}>
* (funcall *) Turning OFF #<Interpreted Function "FSM ON" {5812E809}>
Notice that the default on state is the same closure (address 5812CF11) but that the off state is newly consed every time.
In Antiweb I use this macro for managing the state of connections. For example, a connection will be in the state "waiting for HTTP headers" until it receives the terminator "\r\n\r\n" after which it will go into the "reading HTTP body" state if it was a POST request. Once the HTTP body is read, it will go back to the "waiting for HTTP headers" state to support HTTP/1.1 persistent connections.
You can download Antiweb and read our extensive manual here:
Here is list of some Antiweb features if anyone is interested:
* Uses either the kqueue() or epoll() stateful event APIs in level-triggered mode * 10,000 inactive keepalive connections consume about 3M of userspace memory * Connection sockets are transferred between processes with sendmsg() for privilege-separated vhosts and SMP/multi-core * Files are mmap()ed to avoid copying file data to userspace * Vectored IO (aka scatter-gather IO) used everywhere * Vhosts can be chroot()ed into separate roots * Compromised vhosts can't intercept log messages created by other vhosts or steal connections destined to other vhosts * Every Antiweb process is separately exec()ed (not fork()ed) so each has its own unique memory randomisation offsets (on systems that do this) * Write direction of socket is shutdown() when closing connection (required for HTTP/1.1 persistent connections) * Native IPv6 support * Conditional CGI/1.1 compliance * CGI processes can be restricted with rlimits * Directory listings * Download resuming * Entity tags * Javascript and CSS content is minimised, gzip encoded, cached to the filesystem and served as static content * Apache-like regexp-based rewrite module * Memcached-like memory cache module * BerkeleyDB integration
Regards,
Doug