ffi/unsafe/alloc: allow #f as an "allocator"

Allowing #f as an allocator avoids problems composing `allocator` with
foreign-function lookup where failure is anticipated and implemented
as #f. For example, `g_settings_new` in the "gui-lib" package's
"mred/private/wx/gtk/gsettings.rkt" can be #f if the libgio libray is
too old, in which case there won't be an attempt to use
`g_settings_new`.
This commit is contained in:
Matthew Flatt 2019-08-10 07:23:54 -06:00
parent 19fad3f8d9
commit 001abc5b55
3 changed files with 38 additions and 25 deletions

View File

@ -9,7 +9,7 @@
ensuring that values allocated through foreign functions are reliably ensuring that values allocated through foreign functions are reliably
deallocated.} deallocated.}
@defproc[((allocator [dealloc (any/c . -> . any)]) [alloc procedure?]) procedure?]{ @defproc[((allocator [dealloc (any/c . -> . any)]) [alloc (or/c procedure? #f)]) (or/c procedure? #f)]{
Produces an @deftech{allocator} procedure that behaves like Produces an @deftech{allocator} procedure that behaves like
@racket[alloc], but each result @racket[_v] of the @tech{allocator}, @racket[alloc], but each result @racket[_v] of the @tech{allocator},
@ -17,6 +17,8 @@ if not @racket[#f], is given a finalizer that calls @racket[dealloc]
on @racket[_v]---unless the call has been canceled by applying a on @racket[_v]---unless the call has been canceled by applying a
@tech{deallocator} (produced by @racket[deallocator]) to @racket[_v]. @tech{deallocator} (produced by @racket[deallocator]) to @racket[_v].
Any existing @racket[dealloc] registered for @racket[_v] is canceled. Any existing @racket[dealloc] registered for @racket[_v] is canceled.
If and only if @racket[alloc] is @racket[#f], @racket[((allocator
alloc) dealloc)] produces @racket[#f].
The resulting @tech{allocator} calls @racket[alloc] in @tech{atomic The resulting @tech{allocator} calls @racket[alloc] in @tech{atomic
mode} (see @racket[call-as-atomic]). The result from @racket[alloc] is mode} (see @racket[call-as-atomic]). The result from @racket[alloc] is
@ -44,7 +46,9 @@ a new deallocation action that will run earlier.
@history[#:changed "7.0.0.4" @elem{Added atomic mode for @racket[dealloc] @history[#:changed "7.0.0.4" @elem{Added atomic mode for @racket[dealloc]
and changed non-main place exits to call and changed non-main place exits to call
all remaining @racket[dealloc]s.}]} all remaining @racket[dealloc]s.}
#:changed "7.4.0.4" @elem{Produce @racket[#f] when @racket[alloc]
is @racket[#f].}]}
@deftogether[( @deftogether[(
@defproc[((deallocator [get-arg (list? . -> . any/c) car]) [dealloc procedure?]) @defproc[((deallocator [get-arg (list? . -> . any/c) car]) [dealloc procedure?])

View File

@ -5,6 +5,7 @@
(require ffi/unsafe (require ffi/unsafe
ffi/unsafe/cvector ffi/unsafe/cvector
ffi/unsafe/alloc
ffi/unsafe/define ffi/unsafe/define
ffi/unsafe/define/conventions ffi/unsafe/define/conventions
ffi/vector ffi/vector
@ -1302,6 +1303,11 @@
;; ---------------------------------------- ;; ----------------------------------------
(test #t procedure? ((allocator void) void))
(test #f (allocator void) #f)
;; ----------------------------------------
;; Check `void/reference-sink` ;; Check `void/reference-sink`
(let* ([sym (gensym)] (let* ([sym (gensym)]
[wb (make-weak-box sym)]) [wb (make-weak-box sym)])

View File

@ -61,6 +61,9 @@
(define ((allocator d) proc) (define ((allocator d) proc)
(check-arity-includes-1 'allocator d) (check-arity-includes-1 'allocator d)
(cond
[(not proc) #f]
[else
(rename (rename
(let-values ([(_ allowed-kws) (procedure-keywords proc)]) (let-values ([(_ allowed-kws) (procedure-keywords proc)])
(define (register v) (define (register v)
@ -82,7 +85,7 @@
(call-as-atomic (call-as-atomic
(lambda () (lambda ()
(register (keyword-apply proc kws kw-args rest))))))])) (register (keyword-apply proc kws kw-args rest))))))]))
proc)) proc)]))
(define ((deallocator [get-arg car]) proc) (define ((deallocator [get-arg car]) proc)
(check-arity-includes-1 'deallocator get-arg "(-> list/c any/c)") (check-arity-includes-1 'deallocator get-arg "(-> list/c any/c)")