Next: , Up: iklib guardians   [Index]


6.42.1 Usage examples for guardians

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: , Up: iklib guardians   [Index]