Is there any way for dynamic-wind to know about the context of the continuation 
being jumped to in order to skip doing useless work?

To explain I mean and why I want such a thing, I have written some code that 
uses semaphores as mutexes, and most of my code acquires the mutex using 
call-with-semaphore. However, some functions need to do slightly more than what 
call-with-semaphore allows, because a sub-computation may also temporarily 
release the mutex, then re-acquire it when the sub-computation returns. To make 
that more concrete, here’s some code that does just that, using a 
call-with-semaphore/release function that I’ve written:

(call-with-semaphore/release mutex
  (lambda (call-with-released)
    (do-something-with-the-mutex-locked!)
    (call-with-released
     (lambda ()
       (do-something-with-the-mutex-unlocked!)))
    (do-some-more-with-the-mutex-locked!)))

The call-with-semaphore procedure provided by racket/base installs a 
continuation barrier on every call, but I would like to be able to capture a 
continuation inside the inner portion, within the call-with-released thunk, so 
I’ve implemented call-with-semaphore/release using two uses of dynamic-wind: 
one to lock the mutex on entrance and unlock it on exit, and another to do 
precisely the inverse for around the code for which the mutex is released.

The problem with that is if I have code like

(call-with-semaphore/release mutex
  (lambda (call-with-released)
    (call-with-released
     (lambda ()
       (call/cc
        (lambda (k)
          (stash-continuation-and-abort! k)))))))

then when the continuation k is invoked from outside the dynamic extent of the 
call-with-semaphore/release application, the continuation will not start 
executing until it can acquire the mutex, even though it will release the mutex 
as soon as it acquires it. This is very wasteful, since it creates a lot of 
unnecessary contention for the mutex.

I guess one way I could avoid this would be to make every call to 
call-with-semaphore/release install a fresh prompt, then make 
call-with-released capture the current continuation, abort to that prompt, 
execute the inner thunk in the outer context without the lock acquired, and 
finally apply the captured continuation to the result. This would mean the 
above example would end up effectively doing something like this:

(let ([tag (make-continuation-prompt-tag)])
  (call-with-continuation-prompt
   tag
   (lambda ()
     (call-with-semaphore mutex
       (lambda ()
         (call/comp
          (lambda (reacquire-k)
            (abort-current-continuation
             tag
             (lambda ()
               (call-with-values
                (lambda ()
                  (call/cc
                   (lambda (k)
                     (stash-continuation-and-abort! k))))
                reacquire-k))))
          tag))))
   (lambda (thunk) (thunk))))

…which sure is wordy, but the real problem is that any continuation marks or 
prompts installed by the thunk passed to call-with-semaphore/release before 
calling call-with-released would get dropped. I’ve tried to come up with a way 
to avoid the needless re-locking outlined above without suffering from that 
problem, but I haven’t come up with any solutions, not even by bringing mutable 
state into the picture. Is it possible?

Thanks,
Alexis

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/BCB3DDF0-95B1-49EB-9FDA-8C3B6FC045DE%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to