#lang scheme
(require scheme/sandbox)
(define timeout/c (and/c integer? positive?))
(define memory-limit/c (and/c integer? positive?))
(define sandbox-result/c (or/c exn? (listof any/c)))
(define eval-expression/c any/c)
(define memory-accounting?
(custodian-memory-accounting-available?))
(provide exn:fail:cpu-resource? exn:fail:cpu-resource-resource)
(define-struct (exn:fail:cpu-resource exn:fail) (resource))
(provide/contract
(call-with-limits/cpu-time
(timeout/c (-> any) . -> . any)))
(define (call-with-limits/cpu-time sec thunk)
(let ([ch (make-channel)]
[p current-preserved-thread-cell-values])
(let* ([start-cpu-time (current-process-milliseconds)]
[end-cpu-time (+ start-cpu-time (* 1000 sec))]
[work
(thread (lambda ()
(channel-put ch
(with-handlers ([void (lambda (e)
(list (p) raise e))])
(call-with-values thunk
(lambda vs (list* (p) values vs)))))))]
[watch (thread
(λ ()
(channel-put
ch (let loop ([wait-sec
(quotient
(- end-cpu-time (current-process-milliseconds))
1000)])
(sync/timeout wait-sec work)
(if (>= (current-process-milliseconds) end-cpu-time)
'time
(loop (quotient
(- end-cpu-time (current-process-milliseconds))
1000)))))))]
[r (channel-get ch)])
(kill-thread watch)
(if (list? r)
(begin (p (car r)) (apply (cadr r) (cddr r)))
(raise (make-exn:fail:cpu-resource "out of cpu time"
(current-continuation-marks)
r))))))
(provide evaluate/limits/cpu-time)
(define (evaluate/limits/cpu-time evaluator memory-limit cpu-time-limit expr)
(parameterize ([sandbox-eval-limits `(#f ,memory-limit)])
(call-with-limits/cpu-time
cpu-time-limit
(λ () (evaluator expr)))))
(provide sandbox-execution)
(define-struct (exn:sandbox:unknown exn:fail) (value))
(define (sandbox-execution timeout memory-limit language requires body to-evaluate)
(with-handlers ([exn? (λ (exn) exn)]
[(λ (x) #t)
(λ (v)
(make-exn:sandbox:unknown
v "not a subclass of exn:fail"
(current-continuation-marks)))])
(call-with-values
(λ ()
(parameterize ([sandbox-eval-limits `(,timeout ,memory-limit)])
(let ([evaluator (make-evaluator language requires body)])
(evaluator to-evaluate))))
(λ results results))))