<div dir="ltr">thread cells are subject to GC and that's fine. The real issue is that I might write a program that does (effectively) this:<div><br></div><div> > (let l()(l))</div><div><br></div><div>and then I'm stuck.<br>
<div><br></div><div>Robby</div></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Apr 5, 2014 at 1:15 PM, Greg Hendershott <span dir="ltr"><<a href="mailto:greghendershott@gmail.com" target="_blank">greghendershott@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Oh wait. There could be per-thread "resources". Such as thread cells?<br>
That's why it really ought to be a fresh thread?<br>
<br>
On Sat, Apr 5, 2014 at 1:58 PM, Greg Hendershott<br>
<div class="HOEnZb"><div class="h5"><<a href="mailto:greghendershott@gmail.com">greghendershott@gmail.com</a>> wrote:<br>
>> re grokking extra thread: No no, that's not what I'm saying. I'm saying that<br>
>> if you don't create the extra thread, then the custodian's protection is<br>
>> circumvented. The thread you get started on is not under the auspices of the<br>
>> custodian you created, so that thread doesn't get shutdown when you shutdown<br>
>> the custodian. This means that the user's program won't be completely reset<br>
>> unless you set up the extra thread.<br>
><br>
> Right but the REPL uses the default thread to run the user's program.<br>
> I don't need or want _that_ thread to be shutdown. I do want any<br>
> _additional_ threads (and ports etc.) to be shutdown. I thought<br>
> setting current-custodian means, from that point on, these things will<br>
> be under the custodian. So for instance:<br>
><br>
> (define t0 (current-thread)) ;; from `main`<br>
> (define user-cust (make-custodian (current-custodian))<br>
> (current-custodian user-cust)<br>
> ;; resources<br>
> (define t1 (thread ...))<br>
> (define es (make-eventspace ...))<br>
> (define ip (open-input-port ...))<br>
> (custodian-shutdown-all user-cust)<br>
> ;; ^ releases t1, es, ip -- but _not_ t0<br>
><br>
> Assuming that last comment is correct (?), that seems fine. Everything<br>
> about the user program has been released, except for REPL's main<br>
> thread that was simply running the user program for awhile. So that's<br>
> fine. No?<br>
><br>
> On Sat, Apr 5, 2014 at 10:02 AM, Robby Findler<br>
> <<a href="mailto:robby@eecs.northwestern.edu">robby@eecs.northwestern.edu</a>> wrote:<br>
>> re grokking extra thread: No no, that's not what I'm saying. I'm saying that<br>
>> if you don't create the extra thread, then the custodian's protection is<br>
>> circumvented. The thread you get started on is not under the auspices of the<br>
>> custodian you created, so that thread doesn't get shutdown when you shutdown<br>
>> the custodian. This means that the user's program won't be completely reset<br>
>> unless you set up the extra thread.<br>
>><br>
>> As for the question of whether or not to create an eventspace (to use its<br>
>> thread) or to call 'thread' directly, I think that you're going to have to<br>
>> rely on someone external to tell you that. I guess it would be possible look<br>
>> at the program's require graph and see if it requires racket/gui/base, but<br>
>> that is work the user might wish you didn't do and it is foiled by some<br>
>> programs that will dynamic-require it. Probably the best thing is to have an<br>
>> emacs-level variable that determines if you create that first thread via an<br>
>> eventspace or not.<br>
>><br>
>> Robby<br>
>><br>
>><br>
>><br>
>><br>
>> On Sat, Apr 5, 2014 at 8:25 AM, Greg Hendershott <<a href="mailto:greghendershott@gmail.com">greghendershott@gmail.com</a>><br>
>> wrote:<br>
>>><br>
>>> Thank you Robby. I've spent some time thinking about your response,<br>
>>> trying to make use of it, and even looking at some<br>
>>> mred/private/common/wx code.<br>
>>><br>
>>> First, I don't grok the need for an extra thread. This is for an Emacs<br>
>>> mode REPL. It's quite similar to Racket's xrepl, which doesn't use an<br>
>>> extra thread. Although I could create one if necessary, I think it<br>
>>> would complicate things when I have a more basic issue regarding<br>
>>> `main-eventspace`, custodians, and how/when racket/gui/base gets<br>
>>> loaded:<br>
>>><br>
>>> As an Emacs mode (unlike DrRacket, which is a GUI that needs<br>
>>> racket/gui/base itself), I don't want to statically `require`<br>
>>> racket/gui/base, because I don't want it loaded until/unless it's<br>
>>> actually needed by a user program. (Otherwise, e.g. on OS X, running a<br>
>>> non-GUI program, you would get a weird windowless menu bar, and it<br>
>>> steals the focus from Emacs.) So the way that racket/gui/base _first_<br>
>>> gets required, is via the dynamic-require of the first user program<br>
>>> that happens to require it. As a result the `main-eventspace` state in<br>
>>> mred/private/wx/common/queue.rkt (IIUC) is associated with<br>
>>> `user-cust`, not `orig-cust`. As a result, custodian-shutdown-all<br>
>>> blows that away. And I don't know how to recreate it correctly.<br>
>>> Symptom: Subsequent runs of a user program like `(require plot) (plot<br>
>>> __)`, result in windows that sit there un-drawn and/or unresponsive to<br>
>>> mouse input.<br>
>>><br>
>>><br>
>>> Seems like it could be solved on either "end":<br>
>>><br>
>>> 1. Somehow try to manage the load process so that the first-ever load<br>
>>> of racket/gui/base gets its stuff on orig-cust but the user's stuff on<br>
>>> user-cust.<br>
>>><br>
>>> 2. Somehow re-initialize the main eventspace sufficiently.<br>
>>><br>
>>> Although 2 seems more plausible and less kludgy, I can't work out how<br>
>>> to do it either way.<br>
>>><br>
>>><br>
>>> Some code snippets that might be more understandable than prose:<br>
>>><br>
>>> ;; (or/c #f path?) -> any<br>
>>> (define (run path-str)<br>
>>> (define-values (mod load-dir) (path-string->mod-path&load-dir path-str))<br>
>>><br>
>>> ;; Use custodian to release resources.<br>
>>> ;;<br>
>>> ;; The problem here is that this seems to be "too thorough" -- it<br>
>>> ;; boinks `main-eventspace` in mred/private/queue.rkt. Why? How<br>
>>> ;; racket/gui/base first got loaded was at end of this function,<br>
>>> ;; in the dynamic-require of whatever user module first happened to<br>
>>> ;; use racket/gui/base. (We don't want to load racket/gui/base<br>
>>> ;; in the Emacs mode until/unless it's actually needed). Therefore<br>
>>> ;; `main-eventspace` is created on `user-cust`, and gets blown away<br>
>>> ;; here. Ideally, instead `main-eventspace` would be managed by<br>
>>> ;; `orig-cust`, and everything else about the user program would be<br>
>>> ;; on `user-cust`. But how to do that??<br>
>>> (custodian-shutdown-all user-cust)<br>
>>> ;; New custodian<br>
>>> (set! user-cust (make-custodian orig-cust))<br>
>>> (current-custodian user-cust)<br>
>>><br>
>>> ;; Save the current namespace. Save whether it uses racket/gui/base.<br>
>>> (define orig-ns (current-namespace))<br>
>>> (define had-gui? (module-declared? 'racket/gui/base))<br>
>>> ;; Fresh, clear racket/base namespace.<br>
>>> (current-namespace (make-base-namespace))<br>
>>><br>
>>> (when had-gui?<br>
>>> (displayln "had-gui? #t")<br>
>>> ;; If racket/gui/base module was instantiated in orig-ns, attach<br>
>>> ;; and require it into the new namespace, and _before_ requiring<br>
>>> ;; the new module. Avoids "cannot instantiate `racket/gui/base' a<br>
>>> ;; second time in the same process" problem.<br>
>>> (namespace-attach-module orig-ns 'racket/gui/base)<br>
>>> (namespace-require 'racket/gui/base)<br>
>>><br>
>>> ;; Also need to create an eventspace. FIXME: Not working with<br>
>>> ;; plot.rkt example. custodian-shutdown-all seems to have borked<br>
>>> ;; the original main eventspace state, and our newly-created one<br>
>>> ;; ain't good enough.<br>
>>> (define (gdr sym)<br>
>>> (dynamic-require 'racket/gui/base sym))<br>
>>> (define current-eventspace (gdr 'current-eventspace))<br>
>>> (define make-eventspace (gdr 'make-eventspace))<br>
>>> (current-eventspace (make-eventspace)))<br>
>>><br>
>>> ;; Load the user module, if any<br>
>>> (when mod<br>
>>> (parameterize ([current-load-relative-directory load-dir])<br>
>>> (dynamic-require mod 0)<br>
>>> (current-namespace (module->namespace mod))))<br>
>>> (current-prompt-read (make-prompt-read mod)))<br>
>>><br>
>>> Example GUI user program:<br>
>>><br>
>>> #lang racket<br>
>>> (require plot math)<br>
>>> (plot-new-window? #t)<br>
>>> (plot (function sin (- pi) pi #:label "y = sin(x)"))<br>
>>><br>
>>><br>
>>><br>
>>> On Thu, Apr 3, 2014 at 5:49 PM, Robby Findler<br>
>>> <<a href="mailto:robby@eecs.northwestern.edu">robby@eecs.northwestern.edu</a>> wrote:<br>
>>> > I think the main missing thing is that the thread you're requiriing the<br>
>>> > user's program on should be under the control of the custodian. In other<br>
>>> > words, you'll want to create a new eventspace (under the new custodian)<br>
>>> > and<br>
>>> > queue a callback over to it to require the user's program.<br>
>>> ><br>
>>> > Robby<br>
>>> ><br>
>>> ><br>
>>> > On Thu, Apr 3, 2014 at 4:26 PM, Greg Hendershott<br>
>>> > <<a href="mailto:greghendershott@gmail.com">greghendershott@gmail.com</a>><br>
>>> > wrote:<br>
>>> >><br>
>>> >> So the background for Spencer's question was a problem with my Emacs<br>
>>> >> racket-mode when using racket/gui/base.<br>
>>> >><br>
>>> >> There's a long-ish bug report comment thread. If you want to read it,<br>
>>> >> at all, you might want to skip to the last few comments, here:<br>
>>> >><br>
>>> >><br>
>>> >><br>
>>> >> <a href="https://github.com/greghendershott/racket-mode/issues/26#issuecomment-39494285" target="_blank">https://github.com/greghendershott/racket-mode/issues/26#issuecomment-39494285</a><br>
>>> >><br>
>>> >> Or the TL;DR: I probably don't need racket/sandbox at all. I probably<br>
>>> >> just need a new namespace and a custodian -- in order to do a<br>
>>> >> DrRacket-style "reset the REPL to the source file".<br>
>>> >><br>
>>> >> Matthew and Robby I know you're both incredibly busy, but if either of<br>
>>> >> you had a chance to look at this code, I'd be grateful. Although part<br>
>>> >> of me hopes you'll say "perfect!", the older/wiser part of me hopes<br>
>>> >> you'll point out X Y and Z problems I don't yet realize I have. It's<br>
>>> >> just these 30 lines of code here:<br>
>>> >><br>
>>> >><br>
>>> >><br>
>>> >> <a href="https://github.com/greghendershott/racket-mode/blob/experimental/sandbox.rkt#L30-L66" target="_blank">https://github.com/greghendershott/racket-mode/blob/experimental/sandbox.rkt#L30-L66</a><br>
>>> >><br>
>>> >> On Sun, Mar 23, 2014 at 8:35 PM, Robby Findler<br>
>>> >> <<a href="mailto:robby@eecs.northwestern.edu">robby@eecs.northwestern.edu</a>> wrote:<br>
>>> >> > It is safe, however, to share the racket/gui/base that you get with<br>
>>> >> > the<br>
>>> >> > one<br>
>>> >> > in the sandbox.<br>
>>> >> ><br>
>>> >> > Robby<br>
>>> >> ><br>
>>> >> ><br>
>>> >> > On Sun, Mar 23, 2014 at 7:25 PM, Matthew Flatt <<a href="mailto:mflatt@cs.utah.edu">mflatt@cs.utah.edu</a>><br>
>>> >> > wrote:<br>
>>> >> >><br>
>>> >> >> Yes, this is a limitation of `racket/gui/base`. On initialization,<br>
>>> >> >> the<br>
>>> >> >> library must register in various non-composable ways with an<br>
>>> >> >> underlying<br>
>>> >> >> GUI toolkit (callbacks, Objective-C classes, Win32 classes, etc.),<br>
>>> >> >> and<br>
>>> >> >> so `racket/gui/base` cannot be instantiated multiple times.<br>
>>> >> >><br>
>>> >> >> At Sun, 23 Mar 2014 20:12:43 -0400, Spencer Florence wrote:<br>
>>> >> >> > I'm attempting to launch multiple evaluators which require<br>
>>> >> >> > `racket/gui`,<br>
>>> >> >> > however I get the error:<br>
>>> >> >> ><br>
>>> >> >> > cannot instantiate `racket/gui/base` a second time in the same<br>
>>> >> >> > process<br>
>>> >> >> ><br>
>>> >> >> > Is `racket/gui/base` maintaining some kind of state thats escaping<br>
>>> >> >> > the<br>
>>> >> >> > sandbox?<br>
>>> >> >> ><br>
>>> >> >> ><br>
>>> >> >> ><br>
>>> >> >> ><br>
>>> >> >> ><br>
>>> >> >> > Example of the problem:<br>
>>> >> >> ><br>
>>> >> >> > #lang racket/base<br>
>>> >> >> > (require racket/sandbox)<br>
>>> >> >> ><br>
>>> >> >> > (call-with-trusted-sandbox-configuration<br>
>>> >> >> > (lambda ()<br>
>>> >> >> > (define (make)<br>
>>> >> >> > (make-evaluator 'racket/base<br>
>>> >> >> > #:requires '(racket/gui/base)))<br>
>>> >> >> ><br>
>>> >> >> > (make)<br>
>>> >> >> > (make)))<br>
>>> >> >> > ____________________<br>
>>> >> >> > Racket Users list:<br>
>>> >> >> > <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
>>> >> >> ____________________<br>
>>> >> >> Racket Users list:<br>
>>> >> >> <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
>>> >> ><br>
>>> >> ><br>
>>> >> ><br>
>>> >> > ____________________<br>
>>> >> > Racket Users list:<br>
>>> >> > <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
>>> >> ><br>
>>> ><br>
>>> ><br>
>><br>
>><br>
</div></div></blockquote></div><br></div>