Redo the forking-without-the-threads fix in a way not involving
command levels (as there *are* no command levels for things like scsh -c): There's now a new asynchronous event, similar to SPAWN, called NARROW. It spawns off a new scheduler with just one thread (which runs the thunk provided as an argument to NARROW) and blocks the current one until the narrowed scheduler finishes. For this to work, two schedulers need to be in place: the root scheduler which performs the housekeeping, and another one inside that which is the one the program uses---otherwise it's the root scheduler that's blocked, and that means no housekeeping gets done. This is trivially the case for interactive mode, as the command-levels all have their own schedulers, but we also need to make sure scsh's entry point fires up its own initial scheduler.
This commit is contained in:
parent
2a302178e6
commit
1d35626709
|
@ -355,6 +355,11 @@
|
|||
((spawned)
|
||||
(spawn-on-command-level level (car args) (cadr args))
|
||||
#t)
|
||||
((narrowed)
|
||||
(handle-narrow-event command-quantum
|
||||
(command-level-dynamic-env level)
|
||||
args)
|
||||
#t)
|
||||
((runnable)
|
||||
(let* ((thread (car args))
|
||||
(level (thread-data thread)))
|
||||
|
|
|
@ -553,7 +553,7 @@
|
|||
(export thread?
|
||||
thread-name thread-uid ;for debugging
|
||||
|
||||
spawn
|
||||
spawn narrow
|
||||
relinquish-timeslice
|
||||
sleep
|
||||
terminate-current-thread))
|
||||
|
@ -601,6 +601,7 @@
|
|||
(export run-threads
|
||||
run-threads-with-housekeeper
|
||||
round-robin-event-handler
|
||||
handle-narrow-event
|
||||
|
||||
make-counter ; for thread counts
|
||||
counter-value
|
||||
|
|
|
@ -256,7 +256,8 @@
|
|||
(files (rts thread) (rts sleep)))
|
||||
|
||||
(define-structure scheduler scheduler-interface
|
||||
(open scheme-level-1 threads threads-internal enumerated enum-case
|
||||
(open scheme-level-1 threads threads-internal locks
|
||||
enumerated enum-case
|
||||
debug-messages
|
||||
signals) ;error
|
||||
(files (rts scheduler)))
|
||||
|
|
|
@ -101,6 +101,8 @@
|
|||
(make-thread (car event-data)
|
||||
dynamic-env
|
||||
(cadr event-data))))
|
||||
((narrowed)
|
||||
(handle-narrow-event quantum dynamic-env event-data))
|
||||
((no-event)
|
||||
(values))
|
||||
(else
|
||||
|
@ -126,6 +128,34 @@
|
|||
|
||||
thread-event-handler)
|
||||
|
||||
(define (handle-narrow-event quantum dynamic-env event-data)
|
||||
(let ((thread (current-thread))
|
||||
(lock (make-lock)))
|
||||
(obtain-lock lock)
|
||||
(spawn
|
||||
(lambda ()
|
||||
(let ((runnable (make-thread-queue))
|
||||
(thread (make-thread (car event-data)
|
||||
dynamic-env
|
||||
(cadr event-data)))
|
||||
(thread-count (make-counter)))
|
||||
|
||||
(enqueue-thread! runnable thread)
|
||||
(increment-counter! thread-count)
|
||||
|
||||
(run-threads
|
||||
(round-robin-event-handler runnable quantum dynamic-env thread-count
|
||||
(lambda args #f)
|
||||
(lambda (thread token args) ; upcall handler
|
||||
(propogate-upcall thread token args))
|
||||
(lambda ()
|
||||
(if (positive? (counter-value thread-count))
|
||||
(wait)
|
||||
#f))))
|
||||
(release-lock lock)))
|
||||
'narrowed-scheduler)
|
||||
(obtain-lock lock)))
|
||||
|
||||
; Simple counting cell
|
||||
|
||||
(define (make-counter)
|
||||
|
|
|
@ -226,6 +226,7 @@
|
|||
;; asynchronous events
|
||||
runnable ; <thread> <args> <thread> is now runnable
|
||||
spawned ; <thunk> <id> ... spawn <thunk> as a new thread
|
||||
narrowed ; <thunk> <id> ... narrow to <thunk> as a new thread
|
||||
interrupt ; <type> . <stuff> an interrupt has occured
|
||||
deadlock ; no one can run
|
||||
|
||||
|
@ -586,6 +587,12 @@
|
|||
thunk
|
||||
(if (null? id) #f (car id))))
|
||||
|
||||
(define (narrow thunk . id)
|
||||
(schedule-event (thread-scheduler (current-thread))
|
||||
(enum event-type narrowed)
|
||||
thunk
|
||||
(if (null? id) #f (car id))))
|
||||
|
||||
; Enqueue a RUNNABLE for THREAD's scheduler.
|
||||
|
||||
(define (make-ready thread . args)
|
||||
|
|
|
@ -283,12 +283,15 @@
|
|||
usual-resumer ; usual-resumer
|
||||
environments ; with-interaction-environment
|
||||
fluids-internal ; JMG: get-dynamic-env
|
||||
threads threads-internal scheduler
|
||||
structure-refs
|
||||
scsh-utilities
|
||||
interrupts
|
||||
low-interrupt
|
||||
sigevents
|
||||
primitives
|
||||
scheme)
|
||||
(access threads-internal)
|
||||
(files startup))
|
||||
|
||||
(define-structure scsh-top-package (export parse-switches-and-execute
|
||||
|
|
|
@ -922,23 +922,23 @@
|
|||
|
||||
(define (fork-1 clear-interactive? . rest)
|
||||
(let-optionals rest ((maybe-thunk #f)
|
||||
(no-new-command-level? #f))
|
||||
(dont-narrow? #f))
|
||||
(really-fork clear-interactive?
|
||||
(not no-new-command-level?)
|
||||
(not dont-narrow?)
|
||||
maybe-thunk)))
|
||||
|
||||
(define (really-fork clear-interactive? new-command-level? maybe-thunk)
|
||||
(define (really-fork clear-interactive? narrow? maybe-thunk)
|
||||
(with-env-aligned* ; not neccessary here but doing it on exec
|
||||
; genereates no cache in the parent
|
||||
(lambda ()
|
||||
(let ((proc #f)
|
||||
(maybe-push
|
||||
(if new-command-level?
|
||||
(maybe-narrow
|
||||
(if narrow?
|
||||
(lambda (thunk)
|
||||
(push-command-level (preserve-thread-fluids thunk)
|
||||
'forking))
|
||||
(narrow (preserve-thread-fluids thunk)
|
||||
'forking))
|
||||
(lambda (thunk) (thunk)))))
|
||||
(maybe-push
|
||||
(maybe-narrow
|
||||
(lambda ()
|
||||
;; There was an atomicity problem/race condition -- if a child
|
||||
;; process died after it was forked, but before the scsh fork
|
||||
|
@ -958,17 +958,12 @@
|
|||
(if (and (session-started?) clear-interactive?)
|
||||
(set-batch-mode?! #t)) ; Children are non-interactive.
|
||||
(if maybe-thunk
|
||||
(call-terminally maybe-thunk)
|
||||
(if new-command-level?
|
||||
(proceed-with-command-level
|
||||
(cadr (command-levels))))))
|
||||
(call-terminally maybe-thunk)))
|
||||
;; Parent
|
||||
(begin
|
||||
(set! proc (new-child-proc pid))
|
||||
(lambda ()
|
||||
(if new-command-level?
|
||||
(proceed-with-command-level
|
||||
(cadr (command-levels)))))))))))))
|
||||
(values))))))))))
|
||||
proc))))
|
||||
|
||||
(define (exit . maybe-status)
|
||||
|
|
|
@ -171,11 +171,11 @@
|
|||
(set-interrupt-handler
|
||||
i
|
||||
#t))))
|
||||
(let ((scheduler-initial-thread (current-thread)))
|
||||
(if (not (eq? (thread-name scheduler-initial-thread)
|
||||
'scheduler-initial-thread))
|
||||
(error "sighandler did not find scheduler-initial-thread, but"
|
||||
scheduler-initial-thread))
|
||||
(let ((scsh-initial-thread (current-thread)))
|
||||
(if (not (eq? (thread-name scsh-initial-thread)
|
||||
'scsh-initial-thread))
|
||||
(error "sighandler did not find scsh-initial-thread, but"
|
||||
scsh-initial-thread))
|
||||
|
||||
;; Note: this will prevent any other system to work, since it pushes
|
||||
;; a new command level !
|
||||
|
@ -183,7 +183,7 @@
|
|||
(set-interrupt-handler interrupt/keyboard
|
||||
(lambda stuff
|
||||
((structure-ref threads-internal schedule-event)
|
||||
scheduler-initial-thread
|
||||
scsh-initial-thread
|
||||
(enum
|
||||
(structure-ref threads-internal event-type)
|
||||
interrupt)
|
||||
|
|
|
@ -67,18 +67,40 @@
|
|||
|
||||
|
||||
(define (scsh-stand-alone-resumer start)
|
||||
(usual-resumer ;sets up exceptions, interrupts, and current input & output
|
||||
(lambda (args) ; VM gives us our args, but not our program.
|
||||
(usual-resumer ; sets up exceptions, interrupts,
|
||||
; and current input & output
|
||||
(lambda (args) ; VM gives us our args, but not our program.
|
||||
(init-fdports!)
|
||||
(call-with-current-continuation
|
||||
(lambda (halt)
|
||||
(set! %vm-prog-args (cons "scsh" args)) ; WRONG -- use image.
|
||||
(set-command-line-args! %vm-prog-args)
|
||||
(with-handler
|
||||
(simple-condition-handler halt (current-error-port))
|
||||
(lambda ()
|
||||
(let ((exit-val (start (command-line))))
|
||||
(if (integer? exit-val) exit-val 0))))))))) ; work around bug.
|
||||
(lambda (halt)
|
||||
(set! %vm-prog-args (cons "scsh" args)) ; WRONG -- use image.
|
||||
(set-command-line-args! %vm-prog-args)
|
||||
(with-handler
|
||||
(simple-condition-handler halt (current-error-port))
|
||||
(lambda ()
|
||||
(let ((dynamic-env (get-dynamic-env))
|
||||
(*result* 4711))
|
||||
(let ((runnable (make-thread-queue))
|
||||
(thread (make-thread (lambda ()
|
||||
(set! *result*
|
||||
(start (command-line))))
|
||||
dynamic-env
|
||||
'scsh-initial-thread))
|
||||
(thread-count (make-counter)))
|
||||
|
||||
(enqueue-thread! runnable thread)
|
||||
(increment-counter! thread-count)
|
||||
|
||||
(run-threads
|
||||
(round-robin-event-handler runnable 200 dynamic-env thread-count
|
||||
(lambda args #f)
|
||||
(lambda (thread token args) ; upcall handler
|
||||
(propogate-upcall thread token args))
|
||||
(lambda ()
|
||||
(if (positive? (counter-value thread-count))
|
||||
((structure-ref threads-internal wait))
|
||||
#f))))
|
||||
(if (integer? *result*) *result* 0)))))))))) ; work around bug.
|
||||
|
||||
(define %vm-prog-args #f)
|
||||
|
Loading…
Reference in New Issue