Shadowing special variables in threaded handlers

Chun Tian binghe.lisp at gmail.com
Thu Dec 30 14:41:37 UTC 2021


Hi Duncan,

you can try the following modified version of your CREATE-SERVER function:

(defun create-server ()
  (usocket:socket-server "0.0.0.0" 1965
                         (let ((string *foo*))
                           (lambda (stream) (write string :stream stream)))
                         ()
                         :multi-threading t
                         :element-type 'character
                         :in-new-thread t))

The difference here is that now (lambda (stream) ...) is a closure which will contain a local version of *foo* at the time when (create-server) is called.  This kind of uses of lambda functions is like a cheap object with a member variable.

Hope this helps,

Chun Tian

> On Dec 30, 2021, at 03:56, Duncan Bayne <duncan at bayne.id.au> wrote:
> 
> Hi,
> 
> I'm trying to write some end to end tests for the germinal library,
> which uses usockets.
> 
> What I'm trying, and failing, to do is to shadow special variables in my
> tests so that test-specific configuration is scoped just to the tests in
> question.
> 
> This (tidied up) REPL session with a simple repro case using just
> usocket and usocket-server should give a sense of what I'm trying to
> achieve:
> 
> CL-USER> (ql:quickload '(:usocket :usocket-server))
> (:USOCKET :USOCKET-SERVER)
> CL-USER> (defvar *foo* "original value")
> *FOO*
> CL-USER> (defun create-server ()
>           (usocket:socket-server "0.0.0.0" 1965
>                                  (lambda (stream) (write *foo* :stream stream))
>                                  ()
>                                  :multi-threading t
>                                  :element-type 'character
>                                  :in-new-thread t))
> CREATE-SERVER
> CL-USER> (let ((*foo* "shadowed value")) (create-server))
> #<SB-THREAD:THREAD "USOCKET Server" RUNNING {10043A6933}>
> #<USOCKET:STREAM-SERVER-USOCKET {10043A67D3}>
> 
> So what I'm hoping for here is for the socket server to return "shadowed
> value" when a connection is opened; of course that doesn't happen,
> because the handler runs in a new thread which is bereft of the let
> context:
> 
> $ telnet localhost 1965
> Trying 127.0.0.1...
> Connected to localhost.
> Escape character is '^]'.
> "original value"
> 
> I'd appreciate any assistance here ... I'm somewhat new to Common Lisp
> with only a little commercial experience in it beyond hobbyist work.
> 
> I don't know whether there's a "Lisp trick" I should be using to ensure
> the right context for the handler thread, or whether I need to refactor
> the library in question to not rely on special variables in the handler
> ...
> 
> --
> Duncan Bayne
> +61 420 817 082 | https://duncan.bayne.id.au/
> 
> I usually check my mail every 24 - 48 hours.  If there's something
> urgent going on, please send me an SMS or call me.
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Message signed with OpenPGP
URL: <https://mailman.common-lisp.net/pipermail/usocket-devel/attachments/20211230/ac0570cf/attachment.sig>


More information about the usocket-devel mailing list