Next: iklib guardians api, Up: iklib guardians [Index]
Let’s say that we use the Vicare FFI to handle some memory
block (ffi for details on the FFI); memory blocks allocated
with malloc
are not released by the Vicare garbage
collector: we have to explicitly apply free
to the pointer value
referencing them.
If we use the blocks synchronously with the evaluation of forms, we do
(assuming we do not use continuations, so this use of
dynamic-wind
is fine):
(import (vicare) (vicare ffi)) (define (do-something-with . args) (display args) (newline)) (let ((p #f) (size 4096)) (dynamic-wind (lambda () (set! p (malloc size)) (unless p (error #f "memory allocation"))) (lambda () (do-something-with p)) (lambda () (free p))))
and we can define a syntax for it:
(import (vicare) (vicare ffi)) (define (do-something-with . args) (display args) (newline)) (define-syntax with-block (syntax-rules () ((_ ?pointer ?size ?body ...) (let ((?pointer #f)) (dynamic-wind (lambda () (set! ?pointer (malloc ?size)) (unless ?pointer (error #f "memory allocation"))) (lambda () ?body ...) (lambda () (free ?pointer))))))) (with-block p 2048 (do-something-with p)) (with-block p 4096 (do-something-with p)) (with-block p 8192 (do-something-with p))
If we need the block in an event driven program: we will probably need to use it asynchronously with the evaluation of forms. For example, we store the pointer value that references a block in a thunk (a closure that takes no arguments):
(import (vicare) (vicare ffi)) (define *event-source* '()) (define (enqueue-event event) (set! *event-source* (reverse (cons event (reverse *event-source*))))) (define (pop-event) (if (null? *event-source*) #f (let ((event (car *event-source*))) (set! *event-source* (cdr *event-source*)) event))) ;; Usage: (define (do-something-with . args) (display args) (newline)) (let ((p (malloc 4096))) (unless p (error #f "memory allocation")) (enqueue-event (lambda () (do-something-with p))) (enqueue-event (lambda () (do-something-with 123))) (enqueue-event (lambda () (do-something-with p)))) (do ((event (pop-event) (pop-event))) ((not event)) (event))
once the thunks have been evaluated, the pointer value is garbage
collected, but the allocated memory block becomes leaked memory. We
need a way to be notified of the pointer value garbage collection, so
that we can apply free
to it; this is the job for guardians.
The following script shows the usage of a guardian to free a memory block:
(import (vicare) (vicare ffi)) (define g (make-guardian)) (let ((a (malloc (expt 2 20)))) (unless p (error #f "memory allocation")) (g a) (printf "value ~s~%" a)) (printf "value from guardian ~s~%" (g)) ;; This triggers a garbage collection. (collect) (let ((p (g))) (printf "value from guardian ~s~%" p) (free p))
In an event driven program what we have to do is to register the pointer into the guardian, and then periodically enqueue as event a call to the guardian:
(import (vicare) (vicare ffi)) ;; Event source handling. (define *event-source* '()) (define (enqueue-event event) (set! *event-source* (reverse (cons event (reverse *event-source*))))) (define (pop-event) (if (null? *event-source*) #f (let ((event (car *event-source*))) (set! *event-source* (cdr *event-source*)) event))) ;; Block guardian. (define block-guardian (make-guardian)) (define (run-block-guardian) (do ((p (block-guardian) (block-guardian))) ((not p)) (printf "collecting ~s~%" p) (free p))) ;; Application follows. (define (do-something-with . args) (display args) (newline)) (let ((p (malloc (expt 2 20)))) (unless p (error #f "memory allocation")) (block-guardian p) (enqueue-event (lambda () (do-something-with p))) (enqueue-event (lambda () (do-something-with 123))) (enqueue-event (lambda () (do-something-with p))) (enqueue-event (lambda () (do-something-with 456)))) (do ((event (pop-event) (pop-event)) (i 1 (+ i 1))) ((= i 20)) (when event (event)) (when (= 0 (modulo i 10)) (collect) (enqueue-event run-block-guardian)))
Next: iklib guardians api, Up: iklib guardians [Index]