cs: avoid thread misuse during GC
A collection can only invoke certain callabcks (e.g., for DrRacket's GC icon) when the collection is performed in the main thread. Also, delay posting GC logging events to receivers that cannot work at interrupt time.
This commit is contained in:
parent
6b56156d55
commit
efd601cb51
|
@ -416,18 +416,20 @@
|
||||||
(and (not minor?)
|
(and (not minor?)
|
||||||
(log-level? root-logger 'debug 'GC:major)))
|
(log-level? root-logger 'debug 'GC:major)))
|
||||||
(let ([delta (- pre-allocated post-allocated)])
|
(let ([delta (- pre-allocated post-allocated)])
|
||||||
(log-message root-logger 'debug (if debug-GC? 'GC 'GC:major)
|
(log-message* root-logger 'debug (if debug-GC? 'GC 'GC:major)
|
||||||
(chez:format "GC: 0:~a~a @ ~a(~a); free ~a(~a) ~ams @ ~a"
|
(chez:format "GC: 0:~a~a @ ~a(~a); free ~a(~a) ~ams @ ~a"
|
||||||
(if minor? "min" "MAJ") gen
|
(if minor? "min" "MAJ") gen
|
||||||
(K "" pre-allocated) (K "+" (- pre-allocated+overhead pre-allocated))
|
(K "" pre-allocated) (K "+" (- pre-allocated+overhead pre-allocated))
|
||||||
(K "" delta) (K "+" (- (- pre-allocated+overhead post-allocated+overhead)
|
(K "" delta) (K "+" (- (- pre-allocated+overhead post-allocated+overhead)
|
||||||
delta))
|
delta))
|
||||||
(- post-cpu-time pre-cpu-time) pre-cpu-time)
|
(- post-cpu-time pre-cpu-time) pre-cpu-time)
|
||||||
(make-gc-info (if minor? 'minor 'major) pre-allocated pre-allocated+overhead 0
|
(make-gc-info (if minor? 'minor 'major) pre-allocated pre-allocated+overhead 0
|
||||||
post-allocated post-allocated+overhead
|
post-allocated post-allocated+overhead
|
||||||
pre-cpu-time post-cpu-time
|
pre-cpu-time post-cpu-time
|
||||||
pre-time post-time)
|
pre-time post-time)
|
||||||
#f)))))))))
|
#f
|
||||||
|
;; in interrupt:
|
||||||
|
#t)))))))))
|
||||||
(seq
|
(seq
|
||||||
(|#%app| exit-handler
|
(|#%app| exit-handler
|
||||||
(let ([orig (|#%app| exit-handler)]
|
(let ([orig (|#%app| exit-handler)]
|
||||||
|
|
|
@ -599,7 +599,7 @@
|
||||||
set-ffi-get-lib-and-obj! ; not exported to Racket
|
set-ffi-get-lib-and-obj! ; not exported to Racket
|
||||||
poll-async-callbacks ; not exported to Racket
|
poll-async-callbacks ; not exported to Racket
|
||||||
set-async-callback-poll-wakeup! ; not exported to Racket
|
set-async-callback-poll-wakeup! ; not exported to Racket
|
||||||
set-foreign-eval! ; not exported to racket
|
set-foreign-eval! ; not exported to Racket
|
||||||
|
|
||||||
unsafe-unbox
|
unsafe-unbox
|
||||||
unsafe-unbox*
|
unsafe-unbox*
|
||||||
|
|
|
@ -307,28 +307,32 @@
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
||||||
;; List of (cons <pre> <post>)
|
;; List of (cons <pre> <post>), currently suported
|
||||||
|
;; only in the original host thread of the original place
|
||||||
(define collect-callbacks '())
|
(define collect-callbacks '())
|
||||||
|
|
||||||
(define (unsafe-add-collect-callbacks pre post)
|
(define (unsafe-add-collect-callbacks pre post)
|
||||||
(let ([p (cons pre post)])
|
(when (in-original-host-thread?)
|
||||||
(with-interrupts-disabled
|
(let ([p (cons pre post)])
|
||||||
(set! collect-callbacks (cons p collect-callbacks)))
|
(with-interrupts-disabled
|
||||||
p))
|
(set! collect-callbacks (cons p collect-callbacks)))
|
||||||
|
p)))
|
||||||
|
|
||||||
(define (unsafe-remove-collect-callbacks p)
|
(define (unsafe-remove-collect-callbacks p)
|
||||||
(with-interrupts-disabled
|
(when (in-original-host-thread?)
|
||||||
(set! collect-callbacks (#%remq p collect-callbacks))))
|
(with-interrupts-disabled
|
||||||
|
(set! collect-callbacks (#%remq p collect-callbacks)))))
|
||||||
|
|
||||||
(define (run-collect-callbacks sel)
|
(define (run-collect-callbacks sel)
|
||||||
(let loop ([l collect-callbacks])
|
(when (in-original-host-thread?)
|
||||||
(unless (null? l)
|
(let loop ([l collect-callbacks])
|
||||||
(let ([v (sel (car l))])
|
(unless (null? l)
|
||||||
(let loop ([i 0] [save #f])
|
(let ([v (sel (car l))])
|
||||||
(unless (fx= i (#%vector-length v))
|
(let loop ([i 0] [save #f])
|
||||||
(loop (fx+ i 1)
|
(unless (fx= i (#%vector-length v))
|
||||||
(run-one-collect-callback (#%vector-ref v i) save sel))))
|
(loop (fx+ i 1)
|
||||||
(loop (cdr l))))))
|
(run-one-collect-callback (#%vector-ref v i) save sel))))
|
||||||
|
(loop (cdr l)))))))
|
||||||
|
|
||||||
(define-syntax (osapi-foreign-procedure stx)
|
(define-syntax (osapi-foreign-procedure stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
(set-place-registers! place-registers)
|
(set-place-registers! place-registers)
|
||||||
(thunk)))))
|
(thunk)))))
|
||||||
(define pthread? thread?)
|
(define pthread? thread?)
|
||||||
|
(define in-original-host-thread?
|
||||||
|
(let ([initial-thread-id (get-thread-id)])
|
||||||
|
(lambda ()
|
||||||
|
(eqv? (get-thread-id) initial-thread-id))))
|
||||||
;; make-condition
|
;; make-condition
|
||||||
;; condition-wait
|
;; condition-wait
|
||||||
;; condition-signal
|
;; condition-signal
|
||||||
|
@ -20,6 +24,7 @@
|
||||||
(define make-pthread-parameter #%make-parameter)
|
(define make-pthread-parameter #%make-parameter)
|
||||||
(define (fork-pthread) (void))
|
(define (fork-pthread) (void))
|
||||||
(define (pthread?) #f)
|
(define (pthread?) #f)
|
||||||
|
(define (in-original-host-thread?) #t)
|
||||||
(define (make-condition) (void))
|
(define (make-condition) (void))
|
||||||
(define (condition-wait c m) (void))
|
(define (condition-wait c m) (void))
|
||||||
(define (condition-signal c) (void))
|
(define (condition-signal c) (void))
|
||||||
|
|
|
@ -132,5 +132,6 @@
|
||||||
'unsafe-custodian-unregister unsafe-custodian-unregister
|
'unsafe-custodian-unregister unsafe-custodian-unregister
|
||||||
'thread-push-kill-callback! thread-push-kill-callback!
|
'thread-push-kill-callback! thread-push-kill-callback!
|
||||||
'thread-pop-kill-callback! thread-pop-kill-callback!
|
'thread-pop-kill-callback! thread-pop-kill-callback!
|
||||||
|
'unsafe-add-pre-poll-callback! (lambda (proc) (void))
|
||||||
'set-get-subprocesses-time! void
|
'set-get-subprocesses-time! void
|
||||||
'prop:place-message prop:place-message))
|
'prop:place-message prop:place-message))
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
unsafe-custodian-unregister
|
unsafe-custodian-unregister
|
||||||
thread-push-kill-callback!
|
thread-push-kill-callback!
|
||||||
thread-pop-kill-callback!
|
thread-pop-kill-callback!
|
||||||
|
unsafe-add-pre-poll-callback!
|
||||||
set-get-subprocesses-time!)
|
set-get-subprocesses-time!)
|
||||||
|
|
||||||
(define start-atomic unsafe-start-atomic)
|
(define start-atomic unsafe-start-atomic)
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
log-max-level
|
log-max-level
|
||||||
log-all-levels
|
log-all-levels
|
||||||
log-level-evt
|
log-level-evt
|
||||||
log-message ; ok to call in host-Scheme interrupt handler
|
log-message
|
||||||
|
log-message* ; ok to call in host-Scheme interrupt handler
|
||||||
log-receiver?
|
log-receiver?
|
||||||
make-log-receiver
|
make-log-receiver
|
||||||
add-stderr-log-receiver!
|
add-stderr-log-receiver!
|
||||||
|
@ -80,8 +81,6 @@
|
||||||
s])))
|
s])))
|
||||||
(semaphore-peek-evt s))
|
(semaphore-peek-evt s))
|
||||||
|
|
||||||
;; Can be called in any host Scheme thread and in interrupt handler,
|
|
||||||
;; like `log-level?`:
|
|
||||||
(define/who log-message
|
(define/who log-message
|
||||||
;; Complex dispatch based on number and whether third is a string:
|
;; Complex dispatch based on number and whether third is a string:
|
||||||
(case-lambda
|
(case-lambda
|
||||||
|
@ -102,13 +101,16 @@
|
||||||
[(logger level topic message data prefix?)
|
[(logger level topic message data prefix?)
|
||||||
(do-log-message who logger level topic message data prefix?)]))
|
(do-log-message who logger level topic message data prefix?)]))
|
||||||
|
|
||||||
;; Can be called in any host Scheme thread and in interrupt handler,
|
|
||||||
;; like `log-level?`:
|
|
||||||
(define (do-log-message who logger level topic message data prefix?)
|
(define (do-log-message who logger level topic message data prefix?)
|
||||||
(check who logger? logger)
|
(check who logger? logger)
|
||||||
(check-level who level)
|
(check-level who level)
|
||||||
(check who #:or-false symbol? topic)
|
(check who #:or-false symbol? topic)
|
||||||
(check who string? message)
|
(check who string? message)
|
||||||
|
(log-message* logger level topic message data prefix? #f))
|
||||||
|
|
||||||
|
;; Can be called in any host Scheme thread and in interrupt handler,
|
||||||
|
;; like `log-level?`:
|
||||||
|
(define (log-message* logger level topic message data prefix? in-interrupt?)
|
||||||
(define msg #f)
|
(define msg #f)
|
||||||
(atomically/no-interrupts/no-wind
|
(atomically/no-interrupts/no-wind
|
||||||
(when ((logger-max-wanted-level logger) . level>=? . level)
|
(when ((logger-max-wanted-level logger) . level>=? . level)
|
||||||
|
@ -126,7 +128,7 @@
|
||||||
message))
|
message))
|
||||||
data
|
data
|
||||||
topic)))
|
topic)))
|
||||||
(log-receiver-send! r msg)))
|
(log-receiver-send! r msg in-interrupt?)))
|
||||||
(let ([parent (logger-parent logger)])
|
(let ([parent (logger-parent logger)])
|
||||||
(when (and parent
|
(when (and parent
|
||||||
((filters-level-for-topic (logger-propagate-filters logger) topic) . level>=? . level))
|
((filters-level-for-topic (logger-propagate-filters logger) topic) . level>=? . level))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
(require "../common/check.rkt"
|
(require "../common/check.rkt"
|
||||||
"../../common/queue.rkt"
|
"../../common/queue.rkt"
|
||||||
"../host/thread.rkt"
|
"../host/thread.rkt"
|
||||||
|
"../host/pthread.rkt"
|
||||||
"../host/rktio.rkt"
|
"../host/rktio.rkt"
|
||||||
"../string/convert.rkt"
|
"../string/convert.rkt"
|
||||||
"level.rkt"
|
"level.rkt"
|
||||||
|
@ -27,48 +28,44 @@
|
||||||
#:property
|
#:property
|
||||||
prop:receiver-send
|
prop:receiver-send
|
||||||
(lambda (lr msg)
|
(lambda (lr msg)
|
||||||
;; called in atomic mode and possibly in host interrupt handler,
|
;; called in atomic mode
|
||||||
;; so anything we touch here should only be modified with
|
(define b (queue-remove! (queue-log-receiver-waiters lr)))
|
||||||
;; interrupts disabled
|
(cond
|
||||||
(atomically/no-interrupts/no-wind
|
[b
|
||||||
(define b (queue-remove! (queue-log-receiver-waiters lr)))
|
(decrement-receiever-waiters! lr)
|
||||||
(cond
|
(define select! (unbox b))
|
||||||
[b
|
(set-box! b msg)
|
||||||
(decrement-receiever-waiters! lr)
|
(select!)]
|
||||||
(define select! (unbox b))
|
[else
|
||||||
(set-box! b msg)
|
(queue-add! (queue-log-receiver-msgs lr) msg)]))
|
||||||
(select!)]
|
|
||||||
[else
|
|
||||||
(queue-add! (queue-log-receiver-msgs lr) msg)])))
|
|
||||||
#:property
|
#:property
|
||||||
prop:evt
|
prop:evt
|
||||||
(poller (lambda (lr ctx)
|
(poller (lambda (lr ctx)
|
||||||
(define msg (atomically/no-interrupts/no-wind (queue-remove! (queue-log-receiver-msgs lr))))
|
(define msg (queue-remove! (queue-log-receiver-msgs lr)))
|
||||||
(cond
|
(cond
|
||||||
[msg
|
[msg
|
||||||
(values (list msg) #f)]
|
(values (list msg) #f)]
|
||||||
[else
|
[else
|
||||||
(define b (box (poll-ctx-select-proc ctx)))
|
(define b (box (poll-ctx-select-proc ctx)))
|
||||||
(define n (atomically/no-interrupts/no-wind
|
(define n (begin
|
||||||
(increment-receiever-waiters! lr)
|
(increment-receiever-waiters! lr)
|
||||||
(queue-add! (queue-log-receiver-waiters lr) b)))
|
(queue-add! (queue-log-receiver-waiters lr) b)))
|
||||||
(values #f (control-state-evt
|
(values #f (control-state-evt
|
||||||
(wrap-evt async-evt (lambda (e) (unbox b)))
|
(wrap-evt async-evt (lambda (e) (unbox b)))
|
||||||
(lambda () (atomically/no-interrupts/no-wind
|
(lambda ()
|
||||||
(queue-remove-node! (queue-log-receiver-waiters lr) n)
|
(queue-remove-node! (queue-log-receiver-waiters lr) n)
|
||||||
(decrement-receiever-waiters! lr)))
|
(decrement-receiever-waiters! lr))
|
||||||
void
|
void
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(atomically/no-interrupts/no-wind
|
(define msg (queue-remove! (queue-log-receiver-msgs lr)))
|
||||||
(define msg (queue-remove! (queue-log-receiver-msgs lr)))
|
(cond
|
||||||
(cond
|
[msg
|
||||||
[msg
|
(set-box! b msg)
|
||||||
(set-box! b msg)
|
(values msg #t)]
|
||||||
(values msg #t)]
|
[else
|
||||||
[else
|
(increment-receiever-waiters! lr)
|
||||||
(increment-receiever-waiters! lr)
|
(set! n (queue-add! (queue-log-receiver-waiters lr) b))
|
||||||
(set! n (queue-add! (queue-log-receiver-waiters lr) b))
|
(values #f #f)]))))]))))
|
||||||
(values #f #f)])))))]))))
|
|
||||||
|
|
||||||
(define/who (make-log-receiver logger level . args)
|
(define/who (make-log-receiver logger level . args)
|
||||||
(check who logger? logger)
|
(check who logger? logger)
|
||||||
|
@ -152,5 +149,11 @@
|
||||||
(set-logger-level-sema! logger #f))))
|
(set-logger-level-sema! logger #f))))
|
||||||
|
|
||||||
;; Called in atomic mode and with interrupts disabled
|
;; Called in atomic mode and with interrupts disabled
|
||||||
(define (log-receiver-send! r msg)
|
(define (log-receiver-send! r msg in-interrupt?)
|
||||||
((receiver-send-ref r) r msg))
|
(if (or (not in-interrupt?)
|
||||||
|
;; We can run stdio loggers in atomic/interrupt mode:
|
||||||
|
(stdio-log-receiver? r))
|
||||||
|
((receiver-send-ref r) r msg)
|
||||||
|
;; Record any any other message for posting later:
|
||||||
|
(unsafe-add-pre-poll-callback! (lambda ()
|
||||||
|
((receiver-send-ref r) r msg)))))
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
"thread.rkt"
|
"thread.rkt"
|
||||||
"unsafe.rkt"
|
"unsafe.rkt"
|
||||||
"time.rkt"
|
"time.rkt"
|
||||||
"place-message.rkt")
|
"place-message.rkt"
|
||||||
|
"pre-poll.rkt")
|
||||||
|
|
||||||
;; Unsafe scheduler-cooperation functions are made available to
|
;; Unsafe scheduler-cooperation functions are made available to
|
||||||
;; clients through a `#%thread` primitive linklet instance:
|
;; clients through a `#%thread` primitive linklet instance:
|
||||||
|
@ -65,5 +66,6 @@
|
||||||
'unsafe-custodian-unregister unsafe-custodian-unregister
|
'unsafe-custodian-unregister unsafe-custodian-unregister
|
||||||
'thread-push-kill-callback! thread-push-kill-callback!
|
'thread-push-kill-callback! thread-push-kill-callback!
|
||||||
'thread-pop-kill-callback! thread-pop-kill-callback!
|
'thread-pop-kill-callback! thread-pop-kill-callback!
|
||||||
|
'unsafe-add-pre-poll-callback! unsafe-add-pre-poll-callback!
|
||||||
'set-get-subprocesses-time! set-get-subprocesses-time!
|
'set-get-subprocesses-time! set-get-subprocesses-time!
|
||||||
'prop:place-message prop:place-message))
|
'prop:place-message prop:place-message))
|
||||||
|
|
|
@ -95,6 +95,7 @@
|
||||||
(start-atomic)
|
(start-atomic)
|
||||||
(define-values (parent-in parent-out parent-err child-in-fd child-out-fd child-err-fd)
|
(define-values (parent-in parent-out parent-err child-in-fd child-out-fd child-err-fd)
|
||||||
(make-place-ports+fds in out err))
|
(make-place-ports+fds in out err))
|
||||||
|
(host:mutex-acquire lock)
|
||||||
;; Start the new place
|
;; Start the new place
|
||||||
(host:fork-place
|
(host:fork-place
|
||||||
(lambda ()
|
(lambda ()
|
||||||
|
@ -136,7 +137,6 @@
|
||||||
(wakeup-waiting pl))
|
(wakeup-waiting pl))
|
||||||
(hash-clear! done-waiting)))
|
(hash-clear! done-waiting)))
|
||||||
;; Wait for the place to start, then return the place object
|
;; Wait for the place to start, then return the place object
|
||||||
(host:mutex-acquire lock)
|
|
||||||
(host:condition-wait started lock)
|
(host:condition-wait started lock)
|
||||||
(host:mutex-release lock)
|
(host:mutex-release lock)
|
||||||
(end-atomic)
|
(end-atomic)
|
||||||
|
|
26
racket/src/thread/pre-poll.rkt
Normal file
26
racket/src/thread/pre-poll.rkt
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#lang racket/base
|
||||||
|
(require "atomic.rkt"
|
||||||
|
"host.rkt")
|
||||||
|
|
||||||
|
(provide unsafe-add-pre-poll-callback!
|
||||||
|
call-pre-poll-external-callbacks)
|
||||||
|
|
||||||
|
(define pre-poll-callbacks null)
|
||||||
|
|
||||||
|
;; called in atomic mode in an arbitrary host thread, but
|
||||||
|
;; with all other host threads paused; the given procedure
|
||||||
|
;; will be called in atomic mode, possibly in the schduler
|
||||||
|
(define (unsafe-add-pre-poll-callback! proc)
|
||||||
|
(set! pre-poll-callbacks (cons proc pre-poll-callbacks)))
|
||||||
|
|
||||||
|
;; in atomic mode
|
||||||
|
(define (call-pre-poll-external-callbacks)
|
||||||
|
(unless (null? pre-poll-callbacks)
|
||||||
|
;; disable interrupts to avoid a case with `unsafe-add-pre-poll-callback!`
|
||||||
|
(host:disable-interrupts)
|
||||||
|
(define l pre-poll-callbacks)
|
||||||
|
(set! pre-poll-callbacks null)
|
||||||
|
(host:enable-interrupts)
|
||||||
|
;; Call the callbacks
|
||||||
|
(for ([cb (in-list (reverse l))])
|
||||||
|
(cb))))
|
|
@ -12,7 +12,8 @@
|
||||||
"exit.rkt"
|
"exit.rkt"
|
||||||
"future.rkt"
|
"future.rkt"
|
||||||
"custodian.rkt"
|
"custodian.rkt"
|
||||||
(submod "custodian.rkt" scheduling))
|
(submod "custodian.rkt" scheduling)
|
||||||
|
"pre-poll.rkt")
|
||||||
|
|
||||||
;; Many scheduler details are implemented in "thread.rkt", but this
|
;; Many scheduler details are implemented in "thread.rkt", but this
|
||||||
;; module handles the thread selection, thread swapping, and
|
;; module handles the thread selection, thread swapping, and
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
pending-callbacks))
|
pending-callbacks))
|
||||||
(host:poll-will-executors)
|
(host:poll-will-executors)
|
||||||
(check-external-events 'fast)
|
(check-external-events 'fast)
|
||||||
|
(call-pre-poll-external-callbacks)
|
||||||
(check-place-activity)
|
(check-place-activity)
|
||||||
(when (and (null? callbacks)
|
(when (and (null? callbacks)
|
||||||
(all-threads-poll-done?)
|
(all-threads-poll-done?)
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
"atomic.rkt"
|
"atomic.rkt"
|
||||||
"parameter.rkt"
|
"parameter.rkt"
|
||||||
"waiter.rkt"
|
"waiter.rkt"
|
||||||
"evt.rkt")
|
"evt.rkt"
|
||||||
|
"pre-poll.rkt")
|
||||||
|
|
||||||
(provide make-semaphore
|
(provide make-semaphore
|
||||||
semaphore?
|
semaphore?
|
||||||
|
@ -93,6 +94,7 @@
|
||||||
(define/who (semaphore-try-wait? s)
|
(define/who (semaphore-try-wait? s)
|
||||||
(check who semaphore? s)
|
(check who semaphore? s)
|
||||||
(atomically
|
(atomically
|
||||||
|
(call-pre-poll-external-callbacks)
|
||||||
(define c (semaphore-count s))
|
(define c (semaphore-count s))
|
||||||
(cond
|
(cond
|
||||||
[(positive? c)
|
[(positive? c)
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
"thread.rkt"
|
"thread.rkt"
|
||||||
(only-in (submod "thread.rkt" scheduling)
|
(only-in (submod "thread.rkt" scheduling)
|
||||||
thread-descheduled?)
|
thread-descheduled?)
|
||||||
"schedule-info.rkt")
|
"schedule-info.rkt"
|
||||||
|
"pre-poll.rkt")
|
||||||
|
|
||||||
(provide sync
|
(provide sync
|
||||||
sync/timeout
|
sync/timeout
|
||||||
|
@ -96,6 +97,7 @@
|
||||||
(cond
|
(cond
|
||||||
[(or (and (real? timeout) (zero? timeout))
|
[(or (and (real? timeout) (zero? timeout))
|
||||||
(procedure? timeout))
|
(procedure? timeout))
|
||||||
|
(atomically (call-pre-poll-external-callbacks))
|
||||||
(let poll-loop ()
|
(let poll-loop ()
|
||||||
(sync-poll s #:fail-k (lambda (sched-info polled-all?)
|
(sync-poll s #:fail-k (lambda (sched-info polled-all?)
|
||||||
(cond
|
(cond
|
||||||
|
|
Loading…
Reference in New Issue
Block a user