Skip to content

Commit

Permalink
Create term_from_resource API
Browse files Browse the repository at this point in the history
This is equivalent to `enif_make_resource` but without allocation, so callers
can handle allocation failures. `enif_make_resource` is a thin wrapper around
it.

Signed-off-by: Paul Guyot <pguyot@kallisys.net>
  • Loading branch information
pguyot committed Jun 24, 2023
1 parent bbded72 commit e84347f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 17 deletions.
19 changes: 2 additions & 17 deletions src/libAtomVM/resources.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,10 @@ int enif_release_resource(void *resource)
return true;
}

static inline term resource_to_term(struct RefcBinary *refc, Heap *heap)
{
term *boxed_value = memory_heap_alloc(heap, TERM_BOXED_REFC_BINARY_SIZE);
boxed_value[0] = ((TERM_BOXED_REFC_BINARY_SIZE - 1) << 6) | TERM_BOXED_REFC_BINARY;
boxed_value[1] = (term) 0; // binary size, this is pre ERTS 9.0 (OTP-20.0) behavior
boxed_value[2] = (term) RefcNoFlags;
term ret = ((term) boxed_value) | TERM_BOXED_VALUE_TAG;
boxed_value[3] = (term) refc;
// Increment ref count and add the resource to the mso list
refc_binary_increment_refcount(refc);
heap->root->mso_list = term_list_init_prepend(boxed_value + 4, ret, heap->root->mso_list);
return ret;
}

ERL_NIF_TERM enif_make_resource(ErlNifEnv *env, void *obj)
{
struct RefcBinary *refc = refc_binary_from_data(obj);
if (UNLIKELY(memory_erl_nif_env_ensure_free(env, TERM_BOXED_REFC_BINARY_SIZE) != MEMORY_GC_OK)) {
if (UNLIKELY(memory_erl_nif_env_ensure_free(env, TERM_BOXED_RESOURCE_SIZE) != MEMORY_GC_OK)) {
AVM_ABORT();
}
return resource_to_term(refc, &env->heap);
return term_from_resource(obj, &env->heap);
}
27 changes: 27 additions & 0 deletions src/libAtomVM/term.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ extern "C" {
#define TERM_BOXED_REFC_BINARY_SIZE 6
#define TERM_BOXED_BIN_MATCH_STATE_SIZE 4
#define TERM_BOXED_SUB_BINARY_SIZE 4
#define TERM_BOXED_RESOURCE_SIZE TERM_BOXED_REFC_BINARY_SIZE
#if TERM_BYTES == 8
#define REFC_BINARY_MIN 64
#define SUB_BINARY_MIN 16
Expand Down Expand Up @@ -1664,6 +1665,32 @@ static inline term term_get_sub_binary_ref(term t)
return boxed_value[3];
}

/**
* @brief Create a resource on the heap.
* @details This function creats a resource (obtained from `enif_alloc_resource`)
* on the heap which must have `TERM_BOXED_RESOURCE_SIZE` free terms.
*
* @param resource resource obtained from `enif_alloc_resource`
* @param heap the heap to allocate the resource in
* @return a term pointing to the resource
*/
static inline term term_from_resource(void *resource, Heap *heap)
{
// Resources are currently refc binaries with a size of 0 but may be
// references in the future.
struct RefcBinary *refc = refc_binary_from_data(resource);
term *boxed_value = memory_heap_alloc(heap, TERM_BOXED_REFC_BINARY_SIZE);
boxed_value[0] = ((TERM_BOXED_REFC_BINARY_SIZE - 1) << 6) | TERM_BOXED_REFC_BINARY;
boxed_value[1] = (term) 0; // binary size, this is pre ERTS 9.0 (OTP-20.0) behavior
boxed_value[2] = (term) RefcNoFlags;
term ret = ((term) boxed_value) | TERM_BOXED_VALUE_TAG;
boxed_value[3] = (term) refc;
// Increment ref count and add the resource to the mso list
refc_binary_increment_refcount(refc);
heap->root->mso_list = term_list_init_prepend(boxed_value + 4, ret, heap->root->mso_list);
return ret;
}

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit e84347f

Please sign in to comment.