[racket] instantiating multiple sandboxes with gui's

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Sat Apr 5 14:33:54 EDT 2014

thread cells are subject to GC and that's fine. The real issue is that I
might write a program that does (effectively) this:

 > (let l()(l))

and then I'm stuck.

Robby


On Sat, Apr 5, 2014 at 1:15 PM, Greg Hendershott
<greghendershott at gmail.com>wrote:

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

Posted on the users mailing list.