leif
2017-5-6 14:41:48

@mflatt Hmm…so apparently when I run raco setup, the callback I give to scheme_add_managed_close_on_exit never gets called.


leif
2017-5-6 14:41:56

(When I run the program directly though it does.


leif
2017-5-6 14:41:58

)


leif
2017-5-6 14:42:09

fahree
2017-5-6 20:10:23

I want a macro that expands to something different at toplevel than when nested. So I use a (for-syntax (define slide-function (make-parameter #’toplevel-slide))) but it says that syntax is invalid.


fahree
2017-5-6 20:17:35

(require (for-syntax syntax/parse)) and tweaks it until it hopefully works



fahree
2017-5-6 20:27:28

thanks


fahree
2017-5-6 20:28:21

unhappily, I don’t exactly want syntax, since I’m passing slide as a first-class function and defining wrappers around it and don’t want to syntaxify everything.


fahree
2017-5-6 20:29:06

let me think… I want some parameter for the “current context”, and slide will have to side-effect that context


georges-duperon
2017-5-6 20:51:10

@fahree : just to be clear, is this what you want? #lang racket (slide blah) ;; top-level version (map slide '(1 2 3)) ;; not the top-level version(let () (slide blah)) ;; not the top-level version (slide blah) ;; top-level version again


georges-duperon
2017-5-6 20:54:08

@fahree or do you want something like this? #lang racket (define myslide (slide blah)) myslide ;; acts as the top-level version (side 'wrapper myslide) ;; myslide acts as the non-top-level version, the wrapper is a top-level one though


mflatt
2017-5-6 21:02:43

leif: I imagine you know that the registration is commented out in the committed version, so that’s not it. But you’re registering a Racket closure as a callback with scheme_add_managed_close_on_exit, and nothing retains that closure from the GC’s perspective. So probably you’re seeing a crash when the custodian is shut down and tries to invoke the callback (but the callback is GCed). One easy fix is to pass the closure as both the third and fourth argument to scheme_add_managed_close_on_exit.


mflatt
2017-5-6 21:03:36

You probably also want to deregister the process global when the counter goes to 0, in case init is later – that is, not in a nested mode


mflatt
2017-5-6 21:05:22

Also, beware that you have race conditions all over; the reason scheme_register_process_global returns a value, for example, is to implement a kind of compare-and-swap, so don’t ignore the result.


mflatt
2017-5-6 21:08:02

You need to make the counter increments and decrements atomic somehow… I don’t immediately see or remember something exported from Racket to do that, though


leif
2017-5-6 21:14:38

Ya, I eventually gave up and commented it out the close(), the commit I originally sent didn’t have it commented out.


leif
2017-5-6 21:16:09

leif
2017-5-6 21:16:33

Also good idea, I didn’t realize the GC would collect the closure there. Thanks for pointing that out to me.


mflatt
2017-5-6 21:17:23

@leif No on ffi/unsafe/atomic; see the first paragraph of that section


leif
2017-5-6 21:20:15

@mflatt OH, okay. So I need something that is atomic with places, okay.


leif
2017-5-6 21:20:33

Also, you say to deregister the process global, but the docs seem to only have a register function.


mflatt
2017-5-6 21:23:05

Yes, I take that back; don’t deregister, but instead re-init if the counter is 0


leif
2017-5-6 21:23:22

Ah, okay, that makes sense.


leif
2017-5-6 21:23:24

Thanks.


leif
2017-5-6 21:23:58

Alright, I just need to find something automic….its currently looking like I’ll have to use FFI locks.


mflatt
2017-5-6 21:24:26

mflatt
2017-5-6 21:25:00

That’s completely a hack, since it relies on many implementation details of Racket, but it should work


mflatt
2017-5-6 21:26:27

The key is that box-cas! is implemented with a compare-and-swap at the processor level


leif
2017-5-6 21:27:19

Yup. Also wow….I never thought of making something in GCed memory and memcopy-ing it.


mflatt
2017-5-6 21:27:42

Good - never do that :slightly_smiling_face:


leif
2017-5-6 21:27:43

Seems very dangerous, but I suppose it can work with this implementation


mflatt
2017-5-6 21:27:49

Right


leif
2017-5-6 21:29:47

This won’t work though for: (let ([x (scheme_register_process_global counter-key #f)]) (cond [x x] [else


leif
2017-5-6 21:30:02

(Which is trying to see if a counter has been created before trying to allocate one.)


mflatt
2017-5-6 21:30:26

True, you may end up creating a counter that doesn’t get used


leif
2017-5-6 21:31:03

True. I guess I could allocate the counter, try to install it, and then if I already had one installed, free the new counter.


leif
2017-5-6 21:31:18

The install is then automic and so a race there is okay.


mflatt
2017-5-6 21:31:38

Well, freeing memory that has been cast to _racket is dangerous, so I don’t have a good suggestion


leif
2017-5-6 21:35:19

True, but I don’t see where I would be free-ing memory cast to _racket


mflatt
2017-5-6 21:36:01

The counter is cast to _racket


leif
2017-5-6 21:36:33

Oh…derp, in the example you copied, okay.


leif
2017-5-6 21:36:37

Thinking…


mflatt
2017-5-6 21:37:12

There’s also a problem with discovering that the count is 0 and deciding to call init, versus discovering that the counter is 1 and knowing that init has been called; you really want some signaling mechanism instead


leif
2017-5-6 21:37:35

Okay, you say that scheme_register_process_global operates automically, is that correct?


mflatt
2017-5-6 21:37:59

Yes


mflatt
2017-5-6 21:39:00

Probably it works to use the FFI to get mzrt_sema_create, etc., as defined in “mzrt.h”


leif
2017-5-6 21:39:20

hmm…worth a shot, I’ll give that a try.


mflatt
2017-5-6 21:39:40

Those are not explicitly made public, but I’m pretty sure they’ll be accessible on all platforms – except on builds that don’t have places, in which case you don’t need them


leif
2017-5-6 21:42:26

Ha, fair.


leif
2017-5-6 21:43:08

Is there any documentation for them, otherwise I will just assume they’re like traditional semaphores.


leif
2017-5-6 21:45:14

Meh, looks like they’re just regular semaphores, I’ll give it a shot, thanks.


leif
2017-5-6 22:05:24

@mflatt So, it does look like I will have to use the semaphores as a mutex rather than just storing the counter in there.


leif
2017-5-6 22:06:28

Because there is no way to get the current counter except for wait. Is that correct?


mflatt
2017-5-6 22:13:55

Correct


fahree
2017-5-6 22:36:24

@georges-duperon what I wanted is that a toplevel slides calls register-slide, but a nested slide calls section.


fahree
2017-5-6 22:36:41

not sure what’s the best way to do it, though


fahree
2017-5-6 22:36:59

especially since what’s “toplevel” or not seems pretty dynamic to me.


georges-duperon
2017-5-6 22:39:25

@fahree I see a few ways to do this: either you interpret top-level statically, as in “not syntactically nested inside another slide”, or you interpret it dynamically, as “not during the execution of another (slide …) form”.


fahree
2017-5-6 22:39:58

let’s say dynamically


georges-duperon
2017-5-6 22:39:59

@fahree In the first case, I’d use syntax-parameterize, in the second parameterize.


georges-duperon
2017-5-6 22:43:52

@fahree A third option: consider the values which get implicitly printed when evaluating a module, e.g. #lang racket 'printed (let () 'not-printed 'not-printed 'printed) 'printed This behaviour comes from #%module-begin, which wraps every expression with code that prints its result. You could devise a custom #%module-begin which instead of always printing, does (let ([v the-expression]) (if (is-a-section? v) (register-slide v) (print v)))


georges-duperon
2017-5-6 22:50:00

For the second option (based on parameterize), here’s a skeleton: (define slide-top-level? (make-parameter #t)) (define (myslide-f title body) (if (slide-top-level?) (parameterize ([slide-top-level? #f]) (slide title (body))) (section title (body)))) (define-syntax-rule (myslide title . body) (myslide-f title (λ () . body))) (myslide title (myslide nested-section-1 "body1") (myslide nested-section-2 "body1"))


georges-duperon
2017-5-6 22:53:04

@fahree beware that with the second option, if you do (define tmp-variable (slide …)) directly within the module, the slide will be considered top-level, so you would have to write instead (define (make-the-slide) (slide …)). The third option is a bit more difficult, because it involves always producing sections, and turning a section back into a slide (i’m not sure if it’s possible/easy with slideshow, or if some of the information is hidden away and hard to get back).


fahree
2017-5-7 02:45:40

Thanks. I used a parameter + a simple syntax-rule to delay evaluation.


fahree
2017-5-7 02:46:43

(If anyone is curious about the result, it’s at https://github.com/fare/better-stories/blob/master/fare-lambdaconf2017.rkt )


georges-duperon
2017-5-7 03:07:15

@fahree Pas mal :slightly_smiling_face: