improved the setup for the front-end method so that
printing to stdout and stderr is safe and to better document the issues
This commit is contained in:
parent
8e94ce49e4
commit
e3c26a2aa4
|
@ -1312,7 +1312,7 @@ TODO
|
||||||
(let ([run-on-user-thread (lambda (t)
|
(let ([run-on-user-thread (lambda (t)
|
||||||
(queue-user/wait
|
(queue-user/wait
|
||||||
(λ ()
|
(λ ()
|
||||||
(with-handlers ((exn? (λ (x) (printf "~s\n" (exn-message x)))))
|
(with-handlers ((exn? (λ (x) (oprintf "~s\n" (exn-message x)))))
|
||||||
(t)))))])
|
(t)))))])
|
||||||
run-on-user-thread))
|
run-on-user-thread))
|
||||||
|
|
||||||
|
@ -1653,10 +1653,39 @@ TODO
|
||||||
(let ([lang (drracket:language-configuration:language-settings-language user-language-settings)]
|
(let ([lang (drracket:language-configuration:language-settings-language user-language-settings)]
|
||||||
[drr-evtspace (current-eventspace)]
|
[drr-evtspace (current-eventspace)]
|
||||||
[s (make-semaphore 0)])
|
[s (make-semaphore 0)])
|
||||||
|
|
||||||
|
(define-values (sp-err-other-end sp-err) (make-pipe))
|
||||||
|
(define-values (sp-out-other-end sp-out) (make-pipe))
|
||||||
|
(define io-chan (make-channel))
|
||||||
|
|
||||||
|
;; collect the IO to replay later
|
||||||
|
(thread
|
||||||
|
(λ ()
|
||||||
|
(let loop ([ports (list sp-err-other-end sp-out-other-end)]
|
||||||
|
[io '()])
|
||||||
|
(cond
|
||||||
|
[(null? ports) (channel-put io-chan io)]
|
||||||
|
[else
|
||||||
|
(apply sync
|
||||||
|
(map (λ (port) (handle-evt
|
||||||
|
port
|
||||||
|
(λ (_)
|
||||||
|
(define byte (read-byte port))
|
||||||
|
(if (eof-object? byte)
|
||||||
|
(loop (remq port ports) io)
|
||||||
|
(loop ports (cons (cons port byte)
|
||||||
|
io))))))
|
||||||
|
ports))]))))
|
||||||
|
|
||||||
(run-in-evaluation-thread
|
(run-in-evaluation-thread
|
||||||
(λ ()
|
(λ ()
|
||||||
(let/ec k
|
(let/ec k
|
||||||
(parameterize ([error-escape-handler (λ () (k (void)))])
|
;; we set the io ports here to ones that just collect the data
|
||||||
|
;; since we're blocking the eventspace handler thread (and thus IO to
|
||||||
|
;; the user's ports can deadlock)
|
||||||
|
(parameterize ([error-escape-handler (λ () (k (void)))]
|
||||||
|
[current-output-port sp-out]
|
||||||
|
[current-error-port sp-err])
|
||||||
(cond
|
(cond
|
||||||
;; this is for backwards compatibility; drracket used to
|
;; this is for backwards compatibility; drracket used to
|
||||||
;; expect this method to be a thunk (but that was a bad decision)
|
;; expect this method to be a thunk (but that was a bad decision)
|
||||||
|
@ -1667,7 +1696,21 @@ TODO
|
||||||
;; this is the backwards compatible case.
|
;; this is the backwards compatible case.
|
||||||
(send lang first-opened)])))
|
(send lang first-opened)])))
|
||||||
(semaphore-post s)))
|
(semaphore-post s)))
|
||||||
(semaphore-wait s))
|
|
||||||
|
;; wait for the first-opened method to finish up
|
||||||
|
(semaphore-wait s)
|
||||||
|
|
||||||
|
;; close the output ports to get the above thread to terminate
|
||||||
|
(close-output-port sp-err)
|
||||||
|
(close-output-port sp-out)
|
||||||
|
|
||||||
|
;; duplicate it over to the user's ports, now that there is
|
||||||
|
;; no danger of deadlock
|
||||||
|
(for ([i (in-list (reverse (channel-get io-chan)))])
|
||||||
|
(write-byte (cdr i)
|
||||||
|
(if (eq? (car i) sp-err-other-end)
|
||||||
|
(get-err-port)
|
||||||
|
(get-out-port)))))
|
||||||
|
|
||||||
(send context enable-evaluation)
|
(send context enable-evaluation)
|
||||||
(end-edit-sequence)
|
(end-edit-sequence)
|
||||||
|
|
|
@ -440,7 +440,7 @@ This method is the same as
|
||||||
}
|
}
|
||||||
|
|
||||||
@defmethod[(on-execute [settings settings]
|
@defmethod[(on-execute [settings settings]
|
||||||
[run-in-user-thread ((-> void) -> void)])
|
[run-on-user-thread ((-> void) -> void)])
|
||||||
vod]{
|
vod]{
|
||||||
This method is the same as
|
This method is the same as
|
||||||
@method[drracket:language:language<%> on-execute].
|
@method[drracket:language:language<%> on-execute].
|
||||||
|
@ -628,7 +628,7 @@ default settings obtained via
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@defmethod*[([(first-opened [settings settings]) void?])]{
|
@defmethod[(first-opened [settings settings]) void?]{
|
||||||
|
|
||||||
This method is called after the language is initialized, but
|
This method is called after the language is initialized, but
|
||||||
no program has yet been run. It is called from the user's
|
no program has yet been run. It is called from the user's
|
||||||
|
@ -637,8 +637,8 @@ eventspace's main thread.
|
||||||
See also
|
See also
|
||||||
@method[drracket:rep:text% initialize-console].
|
@method[drracket:rep:text% initialize-console].
|
||||||
|
|
||||||
Calling this method should not raise an exception (or otherwise
|
Calling this method should not escape.
|
||||||
try to escape). DrRacket calls this method in a @racket[parameterize]
|
DrRacket calls this method in a @racket[parameterize]
|
||||||
where the @racket[error-escape-handler] is set to an escaping
|
where the @racket[error-escape-handler] is set to an escaping
|
||||||
continuation that continues initializing the interactions window.
|
continuation that continues initializing the interactions window.
|
||||||
Thus, raising an exception will report the error in the user's
|
Thus, raising an exception will report the error in the user's
|
||||||
|
@ -646,7 +646,14 @@ interactions window as if this were a bug in the user's program.
|
||||||
Escaping in any other way, however, can cause DrRacket to fail
|
Escaping in any other way, however, can cause DrRacket to fail
|
||||||
to start up.
|
to start up.
|
||||||
|
|
||||||
Contrary to the method contract space, DrRacket will also invoke this
|
Also, IO system will deadlock if the @racket[first-opened] method
|
||||||
|
does IO on the user's IO ports, so the calling context of
|
||||||
|
@racket[first-opened] sets the @racket[current-output-port] and
|
||||||
|
@racket[current-error-port] to ports that just collect all of the
|
||||||
|
IO that happened and then replay it later in the initialization of the
|
||||||
|
user's program.
|
||||||
|
|
||||||
|
Contrary to the method contract spec, DrRacket will also invoke this
|
||||||
method if it has zero arguments, passing nothing; the zero argument
|
method if it has zero arguments, passing nothing; the zero argument
|
||||||
version is for backwards compatibility and is not recommended.
|
version is for backwards compatibility and is not recommended.
|
||||||
|
|
||||||
|
@ -932,7 +939,7 @@ the settings for this language.
|
||||||
}
|
}
|
||||||
|
|
||||||
@defmethod[(on-execute [settings settings]
|
@defmethod[(on-execute [settings settings]
|
||||||
[run-in-user-thread ((-> any) -> any)])
|
[run-on-user-thread ((-> any) -> any)])
|
||||||
any]{
|
any]{
|
||||||
The @scheme[on-execute] method is called on DrRacket's
|
The @scheme[on-execute] method is called on DrRacket's
|
||||||
eventspace's main thread before any evaluation happens
|
eventspace's main thread before any evaluation happens
|
||||||
|
@ -1015,13 +1022,16 @@ that error message into the definitions window.}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
The @scheme[run-in-user-thread] arguments accepts thunks and
|
The @scheme[run-on-user-thread] arguments accepts thunks and
|
||||||
runs them on the user's eventspace's main thread. These
|
runs them on the user's eventspace's main thread.
|
||||||
thunks must not raise an exceptions (or DrRacket itself will
|
The output ports are not yet
|
||||||
get stuck). In addition, the output ports are not yet
|
|
||||||
functioning, so print outs should be directed to the
|
functioning, so print outs should be directed to the
|
||||||
original DrRacket output port, if necessary.
|
original DrRacket output port, if necessary.
|
||||||
|
|
||||||
|
This thunk is wrapped in a @racket[with-handlers] that
|
||||||
|
catches all exceptions matching @racket[exn:fail?] and
|
||||||
|
then prints out the exception message to the original
|
||||||
|
output port of the DrRacket process.
|
||||||
}
|
}
|
||||||
|
|
||||||
@defmethod[(order-manuals [manuals (listof bytes?)])
|
@defmethod[(order-manuals [manuals (listof bytes?)])
|
||||||
|
|
|
@ -111,7 +111,9 @@ The @scheme[complete-program?] argument determines if the
|
||||||
how it finishes).
|
how it finishes).
|
||||||
}
|
}
|
||||||
|
|
||||||
@defmethod[#:mode augment (on-execute [run-on-user-thread (-> any)]) any]{
|
@defmethod[(on-execute [run-on-user-thread (-> any)]) any]{
|
||||||
|
|
||||||
|
Use @scheme[run-on-user-thread] to initialize the user's parameters, etc.
|
||||||
|
|
||||||
Called from the DrRacket thread after the language's
|
Called from the DrRacket thread after the language's
|
||||||
@method[drracket:language:language<%> on-execute]
|
@method[drracket:language:language<%> on-execute]
|
||||||
|
@ -119,7 +121,11 @@ The @scheme[complete-program?] argument determines if the
|
||||||
special values have been setup (the ones registered
|
special values have been setup (the ones registered
|
||||||
via @scheme[drracket:language:add-snip-value]).
|
via @scheme[drracket:language:add-snip-value]).
|
||||||
|
|
||||||
Use @scheme[run-on-user-thread] to initialize the user's parameters, etc.
|
Do not print to @racket[current-output-port] or @racket[current-error-port]
|
||||||
|
during the dynamic extent of the thunk passed to @racket[run-on-user-thread] becuase
|
||||||
|
this can deadlock. IO is still, in general, fine, but the @racket[current-error-port]
|
||||||
|
and @racket[current-output-port] are set to the user's ports that print
|
||||||
|
into the interactions window and are not in a good state during those calls.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user