2.5 Foreign Pointers
A pointer object encapsulates a memory address and a potentially empty sequence of symbolic tags. A pointer object may refer to an address that under the control of Racket’s memory manager and garbage collection, or it may refer to an address is managed externally.
The base type for pointers is ptr_t (aliased as void_t*), and new pointer types can be created via define-ffi2-type with either an existing pointer type, a struct_t type, a union_t type, or an a array_t type.
A pointer’s tags enable sanity checking that the right kind of pointer is provided to an operation. If an operation expects a pointer with a certain sequence of tags, it accepts a pointer with additional tags added to the end, so additional tags form a pointer subtype. A ptr_t representation has no tags, which means that a C conversion to Racket via ptr_t is not accepted by any context that expects some tag, whereas a pointer with any tags is accepted as a ptr_t representation to translate to C. Whether a pointer object represents an address managed by Racket’s garbage collector is independent of its tags.
procedure
v : any/c
procedure
(ptr_t/gcable? v) → boolean?
v : any/c
procedure
v : any/c
procedure
(void_t*/gcable? v) → boolean?
v : any/c
syntax
(ffi2-malloc maybe-mode maybe-type n-expr maybe-bytes maybe-as-type)
maybe-mode =
| #:gcable | #:gcable-traced | #:gcable-immobile | #:gcable-traced-immobile | #:manual maybe-type =
| type maybe-bytes =
| #:bytes maybe-as-type =
| #:as as-type
The amount of allocated memory depends on n-expr. If no type is provided as maybe-type, or if maybe-bytes is #:bytes, then the allocated memory spans as many bytes as the value of n-expr. Otherwise, the allocated memory’s size is the result of (* n-expr (ffi2-sizeof maybe-type)).
If maybe-as is specified, then the result is cast to as-type in the sense of ffi2-cast. Otherwise, the result is a pointer object encapsulating the address of allocated memory. If maybe-type is a struct_t, union_t, or size array_t type (and maybe-as is not specified), the result is a pointer object using the representation of maybe-type. Otherwise, the result is a pointer object using the representation of void_t*.
By default, allocation uses #:gcable mode, but a maybe-mode specification can pick any of the supported modes:
#:gcable: Allocates uninitialized memory in Racket’s garbage-collected space, i.e., GCable memory. The allocated memory becomes eligible for garbage collection when it is not referenced by any reachable pointer object or traced allocated memory. Even before collection, the memory manager may relocate the object, but garbage collection or relocation cannot happen with a foreign-procedure call is active.
#:gcable-immobile: Like #:gcable, but the allocated memory will not be relocated by a different address by the memory manager as long as it is not collected.
#:gcable-traced: Like #:gcable, but the allocated memory is traced, meaning that it can itself contain references to other memory that is allocated using #:gcable variants. In particular, references from traced memory are updated by the memory manager if it moves the referenced objects. Traced memory can also contain references to non-GCable memory, but beware of the possibility that Racket’s garbage collector takes over an an address range that was formerly under external control but deallocated.
#:gcable-traced-immobile: Like #:gcable-traced, but the allocated memory will not be relocated by a different address by the memory manager as long as it is not collected (but it can contain references to mobile objects).
#:manual: Allocates outside of Racket’s garbage-collected space. The allocated memory is never relocated by the garbage collection, and it must be freed explicitly with ffi2-free.
syntax
(ffi2-ref ptr-expr type maybe-offset)
maybe-offset =
| offset-expr | offset-expr #:bytes
If offset-expr is followed by #:bytes, it the result of offset-expr is used as an offset to add to the address represented by the result of ptr-expr. If #:bytes is not present, that offset is multiplied by (ffi2-sizeof type).
syntax
(ffi2-set! ptr-expr type maybe-offset val-expr)
maybe-offset = (code:bank) | offset-expr | offset-expr #:bytes
When maybe-offset is not empty, it specifies an address offset in the same way as for ffi2-ref.
syntax
(ffi2-cast expr option ...)
option = #:from from-type | #:to to-type | #:offset maybe-type n-expr maybe-type =
| type
If the #:offset option is provided, the resulting pointer is shifted to represent an address that is n bytes later, where n is the result of n-expr multiplied by (ffi2-sizeof maybe-type) or by 1 if maybe-type is empty. An #:offset option cannot be provided for casting between scalar types.
procedure
(ffi2-memcpy dest src len [ #:dest-offset dest-offset #:src-offset src-offset]) → void? dest : ptr_t? src : ptr_t? len : exact-nonnegative-integer? dest-offset : exact-integer? = 0 src-offset : exact-integer? = 0
procedure
(ffi2-memmove dest src len [ #:dest-offset dest-offset #:src-offset src-offset]) → void? dest : ptr_t? src : ptr_t? len : exact-nonnegative-integer? dest-offset : exact-integer? = 0 src-offset : exact-integer? = 0
procedure
(ffi2-memset dest byte len [ #:dest-offset dest-offset]) → void? dest : ptr_t? byte : byte_t? len : exact-nonnegative-integer? dest-offset : exact-integer? = 0
The ffi2-memcpy function sets len bytes at the address represented by (ffi2-add dest dest-offset) so that each byte’s value is byte.
procedure
(ffi2-malloc-manual-box v) → ptr_t?
v : any/c
procedure
(ffi2-free-manual-box p) → void?
p : ptr_t?
procedure
(ffi2-manual-box-ref p) → any/c
p : ptr_t?
procedure
(ffi2-manual-box-set! p v) → void
p : ptr_t? v : any/c
procedure
ptr : ptr_t?
procedure
(uintptr_t->ptr_t int) → ptr_t?
int : exact-nonnegative-integer?
Beware that the integer form of an address managed by Racket’s garbage collector can become immediately invalid, unless an object at the address was allocated as immobile.