From 2a96208cb00220f963e723ae0530492c5c70df27 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 11 Feb 2010 13:30:32 +0000 Subject: OTP-8335 Even more NIF features --- erts/emulator/beam/beam_bif_load.c | 31 +- erts/emulator/beam/beam_emu.c | 4 +- erts/emulator/beam/binary.c | 18 +- erts/emulator/beam/erl_binary.h | 21 +- erts/emulator/beam/erl_driver.h | 33 +- erts/emulator/beam/erl_drv_nif.h | 48 ++ erts/emulator/beam/erl_init.c | 1 + erts/emulator/beam/erl_nif.c | 805 ++++++++++++++++++++++++++++----- erts/emulator/beam/erl_nif.h | 42 +- erts/emulator/beam/erl_nif_api_funcs.h | 151 ++++++- erts/emulator/beam/external.c | 9 +- erts/emulator/beam/global.h | 25 +- erts/emulator/beam/io.c | 12 +- erts/emulator/beam/module.c | 18 +- erts/emulator/beam/module.h | 19 +- erts/emulator/beam/utils.c | 20 +- 16 files changed, 1032 insertions(+), 225 deletions(-) create mode 100644 erts/emulator/beam/erl_drv_nif.h (limited to 'erts/emulator/beam') diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index d3a1ed4e7d..b1feec7074 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ @@ -642,21 +642,9 @@ purge_module(int module) /* * Unload any NIF library */ - if (modp->old_nif.handle != NULL) { - if (modp->old_nif.entry->unload != NULL) { - ErlNifEnv env; - env.nif_data = modp->old_nif.data; - env.proc = NULL; /* BUGBUG: unlink can not access calling process */ - env.hp = NULL; - env.hp_end = NULL; - env.heap_frag_sz = 0; - env.fpe_was_unmasked = erts_block_fpe(); - modp->old_nif.entry->unload(NULL, modp->old_nif.data); - erts_unblock_fpe(env.fpe_was_unmasked); - } - erts_sys_ddll_close(modp->old_nif.handle); - modp->old_nif.handle = NULL; - modp->old_nif.entry = NULL; + if (modp->old_nif != NULL) { + erts_unload_nif(modp->old_nif); + modp->old_nif = NULL; } /* @@ -732,8 +720,7 @@ delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) modp->code = NULL; modp->code_length = 0; modp->catches = BEAM_CATCHES_NIL; - modp->nif.handle = NULL; - modp->nif.entry = NULL; + modp->nif = NULL; } diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 13757b7d1c..2f7f48193d 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -2973,7 +2973,7 @@ void process_main(void) * I[-1]: Arity * I[0]: &&call_nif * I[1]: Function pointer to NIF function - * I[2]: priv_data pointer + * I[2]: Pointer to erl_module_nif */ BifFunction vbf; @@ -2989,7 +2989,7 @@ void process_main(void) typedef Eterm NifF(struct enif_environment_t*, int argc, Eterm argv[]); NifF* fp = vbf = (NifF*) I[1]; struct enif_environment_t env; - erts_pre_nif(&env, c_p, (void*)I[2]); + erts_pre_nif(&env, c_p, (struct erl_module_nif*)I[2]); reg[0] = r(0); tmp_arg1 = (*fp)(&env, tmp_arg2, reg); erts_post_nif(&env); diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index 49bc0d6457..08c64610a2 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ @@ -180,7 +180,7 @@ erts_realloc_binary(Eterm bin, size_t size) } byte* -erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr) +erts_get_aligned_binary_bytes_extra(Eterm bin, byte** base_ptr, unsigned extra) { byte* bytes; Eterm* real_bin; @@ -208,10 +208,10 @@ erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr) bytes = (byte *)(&(((ErlHeapBin *) real_bin)->data)) + offs; } if (bit_offs) { - byte* buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, byte_size); - - erts_copy_bits(bytes, bit_offs, 1, buf, 0, 1, byte_size*8); + byte* buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, byte_size + extra); *base_ptr = buf; + buf += extra; + erts_copy_bits(bytes, bit_offs, 1, buf, 0, 1, byte_size*8); bytes = buf; } return bytes; diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h index f8ecdde997..21d4e3fdfd 100644 --- a/erts/emulator/beam/erl_binary.h +++ b/erts/emulator/beam/erl_binary.h @@ -150,7 +150,7 @@ do { \ void erts_init_binary(void); -byte* erts_get_aligned_binary_bytes(Eterm, byte**); +byte* erts_get_aligned_binary_bytes_extra(Eterm, byte**, unsigned extra); #if defined(__i386__) || !defined(__GNUC__) /* @@ -166,6 +166,7 @@ byte* erts_get_aligned_binary_bytes(Eterm, byte**); #define ERTS_CHK_BIN_ALIGNMENT(B) \ do { ASSERT(!(B) || (((Uint) &((Binary *)(B))->orig_bytes[0]) & ERTS_BIN_ALIGNMENT_MASK) == ((Uint) 0)) } while(0) +ERTS_GLB_INLINE byte* erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr); ERTS_GLB_INLINE void erts_free_aligned_binary_bytes(byte* buf); ERTS_GLB_INLINE Binary *erts_bin_drv_alloc_fnf(Uint size); ERTS_GLB_INLINE Binary *erts_bin_drv_alloc(Uint size); @@ -178,6 +179,14 @@ ERTS_GLB_INLINE Binary *erts_create_magic_binary(Uint size, #if ERTS_GLB_INLINE_INCL_FUNC_DEF +#include /* offsetof */ + +ERTS_GLB_INLINE byte* +erts_get_aligned_binary_bytes(Eterm bin, byte** base_ptr) +{ + return erts_get_aligned_binary_bytes_extra(bin, base_ptr, 0); +} + ERTS_GLB_INLINE void erts_free_aligned_binary_bytes(byte* buf) { @@ -189,7 +198,7 @@ erts_free_aligned_binary_bytes(byte* buf) ERTS_GLB_INLINE Binary * erts_bin_drv_alloc_fnf(Uint size) { - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); void *res; res = erts_alloc_fnf(ERTS_ALC_T_DRV_BINARY, bsize); ERTS_CHK_BIN_ALIGNMENT(res); @@ -199,7 +208,7 @@ erts_bin_drv_alloc_fnf(Uint size) ERTS_GLB_INLINE Binary * erts_bin_drv_alloc(Uint size) { - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); void *res; res = erts_alloc(ERTS_ALC_T_DRV_BINARY, bsize); ERTS_CHK_BIN_ALIGNMENT(res); @@ -210,7 +219,7 @@ erts_bin_drv_alloc(Uint size) ERTS_GLB_INLINE Binary * erts_bin_nrml_alloc(Uint size) { - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); void *res; res = erts_alloc(ERTS_ALC_T_BINARY, bsize); ERTS_CHK_BIN_ALIGNMENT(res); @@ -221,7 +230,7 @@ ERTS_GLB_INLINE Binary * erts_bin_realloc_fnf(Binary *bp, Uint size) { Binary *nbp; - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0); if (bp->flags & BIN_FLAG_DRV) nbp = erts_realloc_fnf(ERTS_ALC_T_DRV_BINARY, (void *) bp, bsize); @@ -235,7 +244,7 @@ ERTS_GLB_INLINE Binary * erts_bin_realloc(Binary *bp, Uint size) { Binary *nbp; - Uint bsize = sizeof(Binary) - 1 + size; + Uint bsize = ERTS_SIZEOF_Binary(size); ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0); if (bp->flags & BIN_FLAG_DRV) nbp = erts_realloc_fnf(ERTS_ALC_T_DRV_BINARY, (void *) bp, bsize); diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index cdb584b282..489e74d960 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ @@ -65,6 +65,8 @@ # error SIZEOF_LONG_LONG mismatch #endif +#include "erl_drv_nif.h" + #include #if defined(VXWORKS) @@ -116,7 +118,7 @@ typedef struct { #define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed) #define ERL_DRV_EXTENDED_MAJOR_VERSION 1 -#define ERL_DRV_EXTENDED_MINOR_VERSION 4 +#define ERL_DRV_EXTENDED_MINOR_VERSION 5 /* * The emulator will refuse to load a driver with different major @@ -195,22 +197,6 @@ typedef struct { unsigned char data[sizeof(void *)*4]; } ErlDrvMonitor; - -/* - * System info - */ - -typedef struct { - int driver_major_version; - int driver_minor_version; - char *erts_version; - char *otp_release; - int thread_support; - int smp_support; - int async_threads; - int scheduler_threads; -} ErlDrvSysInfo; - typedef struct { unsigned long megasecs; unsigned long secs; @@ -255,9 +241,6 @@ typedef struct ErlDrvCond_ ErlDrvCond; typedef struct ErlDrvRWLock_ ErlDrvRWLock; typedef int ErlDrvTSDKey; -typedef struct { - int suggested_stack_size; -} ErlDrvThreadOpts; /* * diff --git a/erts/emulator/beam/erl_drv_nif.h b/erts/emulator/beam/erl_drv_nif.h new file mode 100644 index 0000000000..ea013a49a3 --- /dev/null +++ b/erts/emulator/beam/erl_drv_nif.h @@ -0,0 +1,48 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Common structures for both erl_driver.h and erl_nif.h + */ + +#ifndef __ERL_DRV_NIF_H__ +#define __ERL_DRV_NIF_H__ + +typedef struct { + int driver_major_version; + int driver_minor_version; + char *erts_version; + char *otp_release; + int thread_support; + int smp_support; + int async_threads; + int scheduler_threads; + int nif_major_version; + int nif_minor_version; +} ErlDrvSysInfo; + +typedef struct { + int suggested_stack_size; +} ErlDrvThreadOpts; + +#endif /* __ERL_DRV_NIF_H__ */ + + + + diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 17cf3b9597..e97ab328cd 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -296,6 +296,7 @@ erl_init(void) erl_sys_init_final(); #endif packet_parser_init(); + erl_nif_init(); } static void diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 2cb93112ae..585a6c1fdf 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2009-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ /* Erlang Native InterFace @@ -34,9 +34,26 @@ #include "beam_bp.h" #include +#include /* offsetof */ + + +/* Information about a loaded nif library. + * Each successful call to erlang:load_nif will allocate an instance of + * erl_module_nif. Two calls opening the same library will thus have the same + * 'handle'. + */ +struct erl_module_nif { + void* priv_data; + void* handle; /* "dlopen" */ + struct enif_entry_t* entry; + erts_refc_t rt_cnt; /* number of resource types */ + erts_refc_t rt_dtor_cnt; /* number of resource types with destructors */ + int is_orphan; /* if erlang module has been purged */ +}; + #define MIN_HEAP_FRAG_SZ 200 -static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need); +static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp); static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need) { @@ -45,43 +62,88 @@ static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need) if (env->hp <= env->hp_end) { return hp; } - env->hp = hp; - return alloc_heap_heavy(env,need); + return alloc_heap_heavy(env, need, hp); } -static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need) -{ - Eterm* hp; - - if (env->heap_frag_sz == 0) { +static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp) +{ + unsigned frag_sz; + env->hp = hp; + if (env->heap_frag == NULL) { ASSERT(HEAP_LIMIT(env->proc) == env->hp_end); HEAP_TOP(env->proc) = env->hp; - env->heap_frag_sz = need + MIN_HEAP_FRAG_SZ; } else { HRelease(env->proc, env->hp_end, env->hp); - env->heap_frag_sz *= 2; } - hp = erts_heap_alloc(env->proc, env->heap_frag_sz); + frag_sz = need + MIN_HEAP_FRAG_SZ; + hp = erts_heap_alloc(env->proc, frag_sz); env->hp = hp + need; - env->hp_end = hp + env->heap_frag_sz; + env->hp_end = hp + frag_sz; + env->heap_frag = MBUF(env->proc); return hp; } -void erts_pre_nif(ErlNifEnv* env, Process* p, void* nif_data) +void erts_pre_nif(ErlNifEnv* env, Process* p, struct erl_module_nif* mod_nif) { - env->nif_data = nif_data; + env->mod_nif = mod_nif; env->proc = p; env->hp = HEAP_TOP(p); env->hp_end = HEAP_LIMIT(p); - env->heap_frag_sz = 0; + env->heap_frag = NULL; + env->fpe_was_unmasked = erts_block_fpe(); + env->tmp_obj_list = NULL; +} + +static void pre_nif_noproc(ErlNifEnv* env, struct erl_module_nif* mod_nif) +{ + env->mod_nif = mod_nif; + env->proc = NULL; + env->hp = NULL; + env->hp_end = NULL; + env->heap_frag = NULL; env->fpe_was_unmasked = erts_block_fpe(); + env->tmp_obj_list = NULL; +} + +static ERTS_INLINE void free_tmp_objs(ErlNifEnv* env) +{ + while (env->tmp_obj_list != NULL) { + struct enif_tmp_obj_t* free_me = env->tmp_obj_list; + env->tmp_obj_list = free_me->next; + free_me->dtor(free_me); + } } void erts_post_nif(ErlNifEnv* env) { erts_unblock_fpe(env->fpe_was_unmasked); - if (env->heap_frag_sz == 0) { + if (env->heap_frag == NULL) { + ASSERT(env->hp_end == HEAP_LIMIT(env->proc)); + ASSERT(env->hp >= HEAP_TOP(env->proc)); + ASSERT(env->hp <= HEAP_LIMIT(env->proc)); + HEAP_TOP(env->proc) = env->hp; + } + else { + ASSERT(env->hp_end != HEAP_LIMIT(env->proc)); + ASSERT(env->hp_end - env->hp <= env->heap_frag->size); + HRelease(env->proc, env->hp_end, env->hp); + } + free_tmp_objs(env); +} + +static void post_nif_noproc(ErlNifEnv* env) +{ + erts_unblock_fpe(env->fpe_was_unmasked); + free_tmp_objs(env); +} + + +/* Flush out our cached heap pointers to allow an ordinary HAlloc +*/ +static void enable_halloc(ErlNifEnv* env) +{ + if (env->heap_frag == NULL) { ASSERT(env->hp_end == HEAP_LIMIT(env->proc)); ASSERT(env->hp >= HEAP_TOP(env->proc)); ASSERT(env->hp <= HEAP_LIMIT(env->proc)); @@ -89,14 +151,35 @@ void erts_post_nif(ErlNifEnv* env) } else { ASSERT(env->hp_end != HEAP_LIMIT(env->proc)); - ASSERT(env->hp_end - env->hp <= env->heap_frag_sz); + ASSERT(env->hp_end - env->hp <= env->heap_frag->size); HRelease(env->proc, env->hp_end, env->hp); } } -void* enif_get_data(ErlNifEnv* env) +/* Restore cached heap pointers +*/ +static void disable_halloc(ErlNifEnv* env) { - return env->nif_data; + if (env->heap_frag == NULL) { + ASSERT(env->hp_end == HEAP_LIMIT(env->proc)); + ASSERT(env->hp <= HEAP_TOP(env->proc)); + ASSERT(env->hp <= HEAP_LIMIT(env->proc)); + env->hp = HEAP_TOP(env->proc); + } + else { + ASSERT(env->hp_end != HEAP_LIMIT(env->proc)); + ASSERT(env->hp_end - env->hp <= env->heap_frag->size); + env->heap_frag = MBUF(env->proc); + ASSERT(env->heap_frag != NULL); + env->hp = env->heap_frag->mem + env->heap_frag->used_size; + env->hp_end = env->heap_frag->mem + env->heap_frag->size; + } +} + + +void* enif_priv_data(ErlNifEnv* env) +{ + return env->mod_nif->priv_data; } void* enif_alloc(ErlNifEnv* env, size_t size) @@ -104,6 +187,11 @@ void* enif_alloc(ErlNifEnv* env, size_t size) return erts_alloc_fnf(ERTS_ALC_T_NIF, (Uint) size); } +void* enif_realloc(ErlNifEnv* env, void* ptr, size_t size) +{ + return erts_realloc_fnf(ERTS_ALC_T_NIF, ptr, size); +} + void enif_free(ErlNifEnv* env, void* ptr) { erts_free(ERTS_ALC_T_NIF, ptr); @@ -119,25 +207,94 @@ int enif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term) return is_binary(term) && (binary_bitsize(term) % 8 == 0); } +int enif_is_empty_list(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_nil(term); +} + +int enif_is_fun(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_fun(term); +} + +int enif_is_pid(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_pid(term); +} + +int enif_is_port(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_port(term); +} + int enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term) { return is_ref(term); } +static void aligned_binary_dtor(struct enif_tmp_obj_t* obj) +{ + erts_free_aligned_binary_bytes((byte*)obj); +} int enif_inspect_binary(ErlNifEnv* env, Eterm bin_term, ErlNifBinary* bin) { - bin->tmp_alloc = NULL; - bin->data = erts_get_aligned_binary_bytes(bin_term, &bin->tmp_alloc); + union { + struct enif_tmp_obj_t* tmp; + byte* raw_ptr; + }u; + u.tmp = NULL; + bin->data = erts_get_aligned_binary_bytes_extra(bin_term, &u.raw_ptr, + sizeof(struct enif_tmp_obj_t)); if (bin->data == NULL) { return 0; } + if (u.tmp != NULL) { + u.tmp->next = env->tmp_obj_list; + u.tmp->dtor = &aligned_binary_dtor; + env->tmp_obj_list = u.tmp; + } bin->bin_term = bin_term; bin->size = binary_size(bin_term); bin->ref_bin = NULL; return 1; } +static void tmp_alloc_dtor(struct enif_tmp_obj_t* obj) +{ + erts_free(ERTS_ALC_T_TMP, obj); +} + +int enif_inspect_iolist_as_binary(ErlNifEnv* env, Eterm term, ErlNifBinary* bin) +{ + struct enif_tmp_obj_t* tobj; + int sz; + if (is_binary(term)) { + return enif_inspect_binary(env,term,bin); + } + if (is_nil(term)) { + bin->data = (unsigned char*) &bin->data; /* dummy non-NULL */ + bin->size = 0; + bin->bin_term = THE_NON_VALUE; + bin->ref_bin = NULL; + return 1; + } + if ((sz = io_list_len(term)) < 0) { + return 0; + } + + tobj = erts_alloc(ERTS_ALC_T_TMP, sz + sizeof(struct enif_tmp_obj_t)); + tobj->next = env->tmp_obj_list; + tobj->dtor = &tmp_alloc_dtor; + env->tmp_obj_list = tobj; + + bin->data = (unsigned char*) &tobj[1]; + bin->size = sz; + bin->bin_term = THE_NON_VALUE; + bin->ref_bin = NULL; + io_list_to_buf(term, (char*) bin->data, sz); + return 1; +} int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin) { @@ -154,46 +311,48 @@ int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin) bin->size = size; bin->data = (unsigned char*) refbin->orig_bytes; bin->bin_term = THE_NON_VALUE; - bin->tmp_alloc = NULL; bin->ref_bin = refbin; return 1; } int enif_realloc_binary(ErlNifEnv* env, ErlNifBinary* bin, unsigned size) { - Binary* oldbin; - Binary* newbin; - ASSERT(bin->ref_bin != NULL); - - oldbin = (Binary*) bin->ref_bin; - newbin = (Binary *) erts_bin_realloc_fnf(oldbin, size); - if (!newbin) { - return 0; - } - newbin->orig_size = size; - bin->ref_bin = newbin; - bin->data = (unsigned char*) newbin->orig_bytes; - bin->size = size; + if (bin->ref_bin != NULL) { + Binary* oldbin; + Binary* newbin; + + oldbin = (Binary*) bin->ref_bin; + newbin = (Binary *) erts_bin_realloc_fnf(oldbin, size); + if (!newbin) { + return 0; + } + newbin->orig_size = size; + bin->ref_bin = newbin; + bin->data = (unsigned char*) newbin->orig_bytes; + bin->size = size; + } + else { + unsigned char* old_data = bin->data; + unsigned cpy_sz = (size < bin->size ? size : bin->size); + enif_alloc_binary(env, size, bin); + sys_memcpy(bin->data, old_data, cpy_sz); + } return 1; } void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin) { - if (bin->ref_bin == NULL) { - erts_free_aligned_binary_bytes(bin->tmp_alloc); - } - else { + if (bin->ref_bin != NULL) { Binary* refbin = bin->ref_bin; - ASSERT(bin->tmp_alloc == NULL); ASSERT(bin->bin_term == THE_NON_VALUE); if (erts_refc_dectest(&refbin->refc, 0) == 0) { erts_bin_free(refbin); } } #ifdef DEBUG + bin->data = NULL; bin->bin_term = THE_NON_VALUE; - bin->tmp_alloc = NULL; bin->ref_bin = NULL; #endif } @@ -208,7 +367,7 @@ int enif_compare(ErlNifEnv* env, Eterm lhs, Eterm rhs) return cmp(lhs,rhs); } -int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, Eterm** array) +int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, const Eterm** array) { Eterm* ptr; if (is_not_tuple(tpl)) { @@ -220,16 +379,47 @@ int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, Eterm** array) return 1; } +int enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char* buf, unsigned len, + ErlNifCharEncoding encoding) +{ + Eterm* listptr; + int n = 0; + + ASSERT(encoding == ERL_NIF_LATIN1); + if (len < 1) { + return 0; + } + while (is_not_nil(list)) { + if (is_not_list(list)) { + buf[n] = '\0'; + return 0; + } + listptr = list_val(list); + + if (!is_byte(*listptr)) { + buf[n] = '\0'; + return 0; + } + buf[n++] = unsigned_val(*listptr); + if (n >= len) { + buf[n-1] = '\0'; /* truncate */ + return -len; + } + list = CDR(listptr); + } + buf[n] = '\0'; + return n + 1; +} + Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin) { - if (bin->ref_bin == NULL) { - erts_free_aligned_binary_bytes(bin->tmp_alloc); + if (bin->bin_term != THE_NON_VALUE) { return bin->bin_term; } - else { + else if (bin->ref_bin != NULL) { Binary* bptr = bin->ref_bin; ProcBin* pb; - ASSERT(bin->tmp_alloc == NULL); + Eterm bin_term; /* !! Copy-paste from new_binary() !! */ pb = (ProcBin *) alloc_heap(env, PROC_BIN_SIZE); @@ -242,15 +432,67 @@ Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin) pb->flags = 0; MSO(env->proc).overhead += pb->size / sizeof(Eterm); - return make_binary(pb); + bin_term = make_binary(pb); + if (erts_refc_read(&bptr->refc, 1) == 1) { + /* Total ownership transfer */ + bin->ref_bin = NULL; + bin->bin_term = bin_term; + } + return bin_term; + } + else { + enable_halloc(env); + bin->bin_term = new_binary(env->proc, bin->data, bin->size); + disable_halloc(env); + return bin->bin_term; } } +Eterm enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, + unsigned pos, unsigned size) +{ + ErlSubBin* sb; + Eterm orig; + Uint offset, bit_offset, bit_size; + unsigned src_size; + + ASSERT(is_binary(bin_term)); + src_size = binary_size(bin_term); + ASSERT(pos <= src_size); + ASSERT(size <= src_size); + ASSERT(pos + size <= src_size); + sb = (ErlSubBin*) alloc_heap(env, ERL_SUB_BIN_SIZE); + ERTS_GET_REAL_BIN(bin_term, orig, offset, bit_offset, bit_size); + sb->thing_word = HEADER_SUB_BIN; + sb->size = size; + sb->offs = offset + pos; + sb->orig = orig; + sb->bitoffs = bit_offset; + sb->bitsize = 0; + sb->is_writable = 0; + return make_binary(sb); +} + + Eterm enif_make_badarg(ErlNifEnv* env) { BIF_ERROR(env->proc, BADARG); } +int enif_get_atom(ErlNifEnv* env, Eterm atom, char* buf, unsigned len) +{ + Atom* ap; + if (is_not_atom(atom)) { + return 0; + } + ap = atom_tab(atom_val(atom)); + if (ap->len+1 > len) { + return 0; + } + sys_memcpy(buf, ap->name, ap->len); + buf[ap->len] = '\0'; + return ap->len + 1; +} int enif_get_int(ErlNifEnv* env, Eterm term, int* ip) { @@ -268,6 +510,29 @@ int enif_get_int(ErlNifEnv* env, Eterm term, int* ip) #endif } +int enif_get_uint(ErlNifEnv* env, Eterm term, unsigned* ip) +{ +#if SIZEOF_INT == SIZEOF_VOID_P + return term_to_Uint(term, (Uint*)ip); +#elif SIZEOF_LONG == SIZEOF_VOID_P + Uint i; + if (!term_to_Uint(term, &i) || i > UINT_MAX) { + return 0; + } + *ip = (unsigned) i; + return 1; +#endif +} + +int enif_get_long(ErlNifEnv* env, Eterm term, long* ip) +{ +#if SIZEOF_LONG == SIZEOF_VOID_P + return term_to_Sint(term, ip); +#else +# error Unknown long word size +#endif +} + int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip) { #if SIZEOF_LONG == SIZEOF_VOID_P @@ -307,18 +572,26 @@ ERL_NIF_TERM enif_make_int(ErlNifEnv* env, int i) #endif } -ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i) +ERL_NIF_TERM enif_make_uint(ErlNifEnv* env, unsigned i) { -#if SIZEOF_LONG == SIZEOF_VOID_P - Eterm* hp; - Uint sz = 0; - erts_bld_uint(NULL, &sz, i); - hp = alloc_heap(env,sz); - return erts_bld_uint(&hp, NULL, i); -#else +#if SIZEOF_INT == SIZEOF_VOID_P + return IS_USMALL(0,i) ? make_small(i) : uint_to_big(i,alloc_heap(env,2)); +#elif SIZEOF_LONG == SIZEOF_VOID_P + return make_small(i); +#endif +} + +ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i) +{ +#if SIZEOF_LONG != SIZEOF_VOID_P # error Unknown long word size #endif + return IS_SSMALL(i) ? make_small(i) : small_to_big(i, alloc_heap(env,2)); +} +ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i) +{ + return IS_USMALL(0,i) ? make_small(i) : uint_to_big(i,alloc_heap(env,2)); } ERL_NIF_TERM enif_make_double(ErlNifEnv* env, double d) @@ -355,6 +628,19 @@ ERL_NIF_TERM enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...) return ret; } +ERL_NIF_TERM enif_make_tuple_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], unsigned cnt) +{ + Eterm* hp = alloc_heap(env,cnt+1); + Eterm ret = make_tuple(hp); + const Eterm* src = arr; + + *hp++ = make_arityval(cnt); + while (cnt--) { + *hp++ = *src++; + } + return ret; +} + ERL_NIF_TERM enif_make_list_cell(ErlNifEnv* env, Eterm car, Eterm cdr) { Eterm* hp = alloc_heap(env,2); @@ -384,10 +670,29 @@ ERL_NIF_TERM enif_make_list(ErlNifEnv* env, unsigned cnt, ...) return ret; } -ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string) +ERL_NIF_TERM enif_make_list_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], unsigned cnt) +{ + Eterm* hp = alloc_heap(env,cnt*2); + Eterm ret = make_list(hp); + Eterm* last = &ret; + const Eterm* src = arr; + + while (cnt--) { + *last = make_list(hp); + *hp = *src++; + last = ++hp; + ++hp; + } + *last = NIL; + return ret; +} + +ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string, + ErlNifCharEncoding encoding) { Sint n = sys_strlen(string); Eterm* hp = alloc_heap(env,n*2); + ASSERT(encoding == ERL_NIF_LATIN1); return erts_bld_string_n(&hp,NULL,string,n); } @@ -397,32 +702,265 @@ ERL_NIF_TERM enif_make_ref(ErlNifEnv* env) return erts_make_ref_in_buffer(hp); } -#if 0 /* To be continued... */ -typedef struct enif_handle_type_t +void enif_system_info(ErlNifSysInfo *sip, size_t si_size) { - struct enif_handle_type_t* next; - struct enif_handle_type_t* prev; - const char* name; - void (*dtor)(void* obj); - erts_smp_atomic_t ref_cnt; /* num of handles of this type */ -}ErlNifHandleType; + driver_system_info(sip, si_size); +} -ErlNifHandleType* -enif_create_handle_type(ErlNifEnv* env, const char* type_name, - void (*dtor)(void *)) + +ErlNifMutex* enif_mutex_create(char *name) { return erl_drv_mutex_create(name); } +void enif_mutex_destroy(ErlNifMutex *mtx) { erl_drv_mutex_destroy(mtx); } +int enif_mutex_trylock(ErlNifMutex *mtx) { return erl_drv_mutex_trylock(mtx); } +void enif_mutex_lock(ErlNifMutex *mtx) { erl_drv_mutex_lock(mtx); } +void enif_mutex_unlock(ErlNifMutex *mtx) { erl_drv_mutex_unlock(mtx); } +ErlNifCond* enif_cond_create(char *name) { return erl_drv_cond_create(name); } +void enif_cond_destroy(ErlNifCond *cnd) { erl_drv_cond_destroy(cnd); } +void enif_cond_signal(ErlNifCond *cnd) { erl_drv_cond_signal(cnd); } +void enif_cond_broadcast(ErlNifCond *cnd) { erl_drv_cond_broadcast(cnd); } +void enif_cond_wait(ErlNifCond *cnd, ErlNifMutex *mtx) { erl_drv_cond_wait(cnd,mtx); } +ErlNifRWLock* enif_rwlock_create(char *name) { return erl_drv_rwlock_create(name); } +void enif_rwlock_destroy(ErlNifRWLock *rwlck) { erl_drv_rwlock_destroy(rwlck); } +int enif_rwlock_tryrlock(ErlNifRWLock *rwlck) { return erl_drv_rwlock_tryrlock(rwlck); } +void enif_rwlock_rlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_rlock(rwlck); } +void enif_rwlock_runlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_runlock(rwlck); } +int enif_rwlock_tryrwlock(ErlNifRWLock *rwlck) { return erl_drv_rwlock_tryrwlock(rwlck); } +void enif_rwlock_rwlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_rwlock(rwlck); } +void enif_rwlock_rwunlock(ErlNifRWLock *rwlck) { erl_drv_rwlock_rwunlock(rwlck); } +int enif_tsd_key_create(char *name, ErlNifTSDKey *key) { return erl_drv_tsd_key_create(name,key); } +void enif_tsd_key_destroy(ErlNifTSDKey key) { erl_drv_tsd_key_destroy(key); } +void enif_tsd_set(ErlNifTSDKey key, void *data) { erl_drv_tsd_set(key,data); } +void* enif_tsd_get(ErlNifTSDKey key) { return erl_drv_tsd_get(key); } +ErlNifThreadOpts* enif_thread_opts_create(char *name) { return (ErlNifThreadOpts*) erl_drv_thread_opts_create(name); } +void enif_thread_opts_destroy(ErlNifThreadOpts *opts) { erl_drv_thread_opts_destroy((ErlDrvThreadOpts*)opts); } +int enif_thread_create(char *name, ErlNifTid *tid, void* (*func)(void *), + void *args, ErlNifThreadOpts *opts) { + return erl_drv_thread_create(name,tid,func,args,(ErlDrvThreadOpts*)opts); +} +ErlNifTid enif_thread_self(void) { return erl_drv_thread_self(); } +int enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2) { return erl_drv_equal_tids(tid1,tid2); } +void enif_thread_exit(void *resp) { erl_drv_thread_exit(resp); } +int enif_thread_join(ErlNifTid tid, void **respp) { return erl_drv_thread_join(tid,respp); } + +int enif_fprintf(void* filep, const char* format, ...) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = erts_vfprintf((FILE*)filep, format, arglist); + va_end(arglist); + return ret; +} + +/*********************************************************** + ** Memory managed (GC'ed) "resource" objects ** + ***********************************************************/ + + +struct enif_resource_type_t { + struct enif_resource_type_t* next; /* list of all resource types */ + struct enif_resource_type_t* prev; + struct erl_module_nif* owner; /* that created this type and thus implements the destructor*/ + ErlNifResourceDtor* dtor; /* user destructor function */ + erts_refc_t refc; /* num of resources of this type (HOTSPOT warning) + +1 for active erl_module_nif */ + char name[1]; +}; + +/* dummy node in circular list */ +struct enif_resource_type_t resource_type_list; + +typedef struct enif_resource_t +{ + struct enif_resource_type_t* type; +#ifdef DEBUG + erts_refc_t nif_refc; +#endif + char data[1]; +}ErlNifResource; + +#define SIZEOF_ErlNifResource(SIZE) (offsetof(ErlNifResource,data) + (SIZE)) +#define DATA_TO_RESOURCE(PTR) ((ErlNifResource*)((char*)(PTR) - offsetof(ErlNifResource,data))) +static ErlNifResourceType* find_resource_type(const char* name) +{ + ErlNifResourceType* type; + for (type = resource_type_list.next; + type != &resource_type_list; + type = type->next) { + + if (sys_strcmp(type->name, name) == 0) { + return type; + } + } + return NULL; +} + +#define in_area(ptr,start,nbytes) \ + ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + + +static void close_lib(struct erl_module_nif* lib) +{ + ASSERT(lib != NULL); + ASSERT(lib->handle != NULL); + ASSERT(erts_refc_read(&lib->rt_dtor_cnt,0) == 0); + + if (lib->entry != NULL && lib->entry->unload != NULL) { + ErlNifEnv env; + pre_nif_noproc(&env, lib); + lib->entry->unload(&env, lib->priv_data); + post_nif_noproc(&env); + } + erts_sys_ddll_close(lib->handle); + lib->handle = NULL; } -ERL_NIF_TERM enif_make_handle(ErlNifEnv* env, ErlNifHandleType* htype, void* obj) +static void steal_resource_type(ErlNifResourceType* type) { + struct erl_module_nif* lib = type->owner; + + if (type->dtor != NULL + && erts_refc_dectest(&lib->rt_dtor_cnt, 0) == 0 + && lib->is_orphan) { + /* last type with destructor gone, close orphan lib */ + close_lib(lib); + } + if (erts_refc_dectest(&lib->rt_cnt, 0) == 0 + && lib->is_orphan) { + erts_free(ERTS_ALC_T_NIF, lib); + } } -int enif_get_handle(ErlNifEnv* env, ERL_NIF_TERM term, void** objp) +ErlNifResourceType* +enif_open_resource_type(ErlNifEnv* env, const char* type_name, + ErlNifResourceDtor* dtor, + enum ErlNifResourceFlags flags, + enum ErlNifResourceFlags* tried) { + ErlNifResourceType* type = find_resource_type(type_name); + enum ErlNifResourceFlags op = flags; + ASSERT(erts_smp_is_system_blocked(0)); + if (type == NULL) { + if (flags & ERL_NIF_RT_CREATE) { + type = erts_alloc(ERTS_ALC_T_NIF, + sizeof(struct enif_resource_type_t) + + sys_strlen(type_name)); + type->dtor = dtor; + sys_strcpy(type->name, type_name); + erts_refc_init(&type->refc, 1); + type->owner = env->mod_nif; + type->prev = &resource_type_list; + type->next = resource_type_list.next; + type->next->prev = type; + type->prev->next = type; + op = ERL_NIF_RT_CREATE; + } + } + else { + if (flags & ERL_NIF_RT_TAKEOVER) { + steal_resource_type(type); + op = ERL_NIF_RT_TAKEOVER; + } + else { + type = NULL; + } + } + if (type != NULL) { + type->owner = env->mod_nif; + type->dtor = dtor; + if (type->dtor != NULL) { + erts_refc_inc(&type->owner->rt_dtor_cnt, 1); + } + erts_refc_inc(&type->owner->rt_cnt, 1); + } + if (tried != NULL) { + *tried = op; + } + return type; +} + +static void nif_resource_dtor(Binary* bin) +{ + ErlNifResource* resource = (ErlNifResource*) ERTS_MAGIC_BIN_DATA(bin); + ErlNifResourceType* type = resource->type; + ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == &nif_resource_dtor); + + if (type->dtor != NULL) { + ErlNifEnv env; + pre_nif_noproc(&env, type->owner); + type->dtor(&env,resource->data); + post_nif_noproc(&env); + } + if (erts_refc_dectest(&type->refc, 0) == 0) { + ASSERT(type->next == NULL); + ASSERT(type->owner != NULL); + ASSERT(type->owner->is_orphan); + steal_resource_type(type); + erts_free(ERTS_ALC_T_NIF, type); + } } + +void* enif_alloc_resource(ErlNifEnv* env, ErlNifResourceType* type, unsigned size) +{ + Binary* bin = erts_create_magic_binary(SIZEOF_ErlNifResource(size), &nif_resource_dtor); + ErlNifResource* resource = ERTS_MAGIC_BIN_DATA(bin); + resource->type = type; + erts_refc_inc(&bin->refc, 1); +#ifdef DEBUG + erts_refc_init(&resource->nif_refc, 1); +#endif + erts_refc_inc(&resource->type->refc, 2); + return resource->data; +} + +void enif_release_resource(ErlNifEnv* env, void* obj) +{ + ErlNifResource* resource = DATA_TO_RESOURCE(obj); + ErtsBinary* bin = ERTS_MAGIC_BIN_FROM_DATA(resource); + + ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == &nif_resource_dtor); +#ifdef DEBUG + erts_refc_dec(&resource->nif_refc, 0); #endif + if (erts_refc_dectest(&bin->binary.refc, 0) == 0) { + erts_bin_free(&bin->binary); + } +} + +ERL_NIF_TERM enif_make_resource(ErlNifEnv* env, void* obj) +{ + ErlNifResource* resource = DATA_TO_RESOURCE(obj); + ErtsBinary* bin = ERTS_MAGIC_BIN_FROM_DATA(resource); + Eterm* hp = alloc_heap(env,PROC_BIN_SIZE); + return erts_mk_magic_binary_term(&hp, &MSO(env->proc), &bin->binary); +} + +int enif_get_resource(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifResourceType* type, + void** objp) +{ + Binary* mbin; + ErlNifResource* resource; + if (!ERTS_TERM_IS_MAGIC_BINARY(term)) { + return 0; + } + mbin = ((ProcBin*) binary_val(term))->val; + resource = (ErlNifResource*) ERTS_MAGIC_BIN_DATA(mbin); + if (ERTS_MAGIC_BIN_DESTRUCTOR(mbin) != &nif_resource_dtor + || resource->type != type) { + return 0; + } + *objp = resource->data; + return 1; +} + +unsigned enif_sizeof_resource(ErlNifEnv* env, void* obj) +{ + ErlNifResource* resource = DATA_TO_RESOURCE(obj); + Binary* bin = &ERTS_MAGIC_BIN_FROM_DATA(resource)->binary; + return ERTS_MAGIC_BIN_DATA_SIZE(bin) - offsetof(ErlNifResource,data); +} /*************************************************************************** ** load_nif/2 ** @@ -445,10 +983,7 @@ static Uint** get_func_pp(Eterm* mod_code, Eterm f_atom, unsigned arity) return NULL; } -#define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) - -static void refresh_cached_nif_data(Eterm* mod_code, +/*static void refresh_cached_nif_data(Eterm* mod_code, struct erl_module_nif* mod_nif) { int i; @@ -459,9 +994,9 @@ static void refresh_cached_nif_data(Eterm* mod_code, erts_atom_get(func->name, sys_strlen(func->name), &f_atom); code_ptr = *get_func_pp(mod_code, f_atom, func->arity); - code_ptr[5+2] = (Uint) mod_nif->data; + code_ptr[5+2] = (Uint) mod_nif->priv_data; } -} +}*/ static Eterm mkatom(const char *str) { @@ -567,6 +1102,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT; Eterm ret = am_ok; int veto; + struct erl_module_nif* lib = NULL; len = intlist_to_buf(BIF_ARG_1, lib_name, sizeof(lib_name)-1); if (len < 1) { @@ -652,16 +1188,27 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) /* Call load, reload or upgrade: */ - if (mod->nif.handle != NULL) { /* Reload */ + + + lib = erts_alloc(ERTS_ALC_T_NIF, sizeof(struct erl_module_nif)); + lib->handle = handle; + lib->entry = entry; + erts_refc_init(&lib->rt_cnt, 0); + erts_refc_init(&lib->rt_dtor_cnt, 0); + lib->is_orphan = 0; + env.mod_nif = lib; + if (mod->nif != NULL) { /* Reload */ int k; - ASSERT(mod->nif.entry != NULL); + lib->priv_data = mod->nif->priv_data; + + ASSERT(mod->nif->entry != NULL); if (entry->reload == NULL) { ret = load_nif_error(BIF_P,reload,"Reload not supported by this NIF library."); goto error; } /* Check that no NIF is removed */ - for (k=0; k < mod->nif.entry->num_of_funcs; k++) { - ErlNifFunc* old_func = &mod->nif.entry->funcs[k]; + for (k=0; k < mod->nif->entry->num_of_funcs; k++) { + ErlNifFunc* old_func = &mod->nif->entry->funcs[k]; for (i=0; i < entry->num_of_funcs; i++) { if (old_func->arity == entry->funcs[i].arity && sys_strcmp(old_func->name, entry->funcs[i].name) == 0) { @@ -675,37 +1222,39 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) goto error; } } - erts_pre_nif(&env, BIF_P, mod->nif.data); - veto = entry->reload(&env, &env.nif_data, BIF_ARG_2); + erts_pre_nif(&env, BIF_P, lib); + veto = entry->reload(&env, &lib->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful."); } else { - erts_sys_ddll_close(mod->nif.handle); + mod->nif->entry = NULL; /* to prevent 'unload' callback */ + erts_unload_nif(mod->nif); } } else { - if (mod->old_nif.handle != NULL) { /* Upgrade */ - void* prev_old_data = mod->old_nif.data; + lib->priv_data = NULL; + if (mod->old_nif != NULL) { /* Upgrade */ + void* prev_old_data = mod->old_nif->priv_data; if (entry->upgrade == NULL) { ret = load_nif_error(BIF_P, upgrade, "Upgrade not supported by this NIF library."); goto error; } - erts_pre_nif(&env, BIF_P, NULL); - veto = entry->upgrade(&env, &env.nif_data, &mod->old_nif.data, BIF_ARG_2); + erts_pre_nif(&env, BIF_P, lib); + veto = entry->upgrade(&env, &lib->priv_data, &mod->old_nif->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { - mod->old_nif.data = prev_old_data; + mod->old_nif->priv_data = prev_old_data; ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful."); } - else if (mod->old_nif.data != prev_old_data) { - refresh_cached_nif_data(mod->old_code, &mod->old_nif); - } + /*else if (mod->old_nif->priv_data != prev_old_data) { + refresh_cached_nif_data(mod->old_code, mod->old_nif); + }*/ } else if (entry->load != NULL) { /* Initial load */ - erts_pre_nif(&env, BIF_P, NULL); - veto = entry->load(&env, &env.nif_data, BIF_ARG_2); + erts_pre_nif(&env, BIF_P, lib); + veto = entry->load(&env, &lib->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { ret = load_nif_error(BIF_P, "load", "Library load-call unsuccessful."); @@ -716,9 +1265,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) /* ** Everything ok, patch the beam code with op_call_nif */ - mod->nif.data = env.nif_data; - mod->nif.handle = handle; - mod->nif.entry = entry; + mod->nif = lib; for (i=0; i < entry->num_of_funcs; i++) { Uint* code_ptr; @@ -727,17 +1274,21 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) if (code_ptr[1] == 0) { code_ptr[5+0] = (Uint) BeamOp(op_call_nif); - } else { /* Function traced, patch the original instruction word */ + } + else { /* Function traced, patch the original instruction word */ BpData* bp = (BpData*) code_ptr[1]; bp->orig_instr = (Uint) BeamOp(op_call_nif); } code_ptr[5+1] = (Uint) entry->funcs[i].fptr; - code_ptr[5+2] = (Uint) mod->nif.data; + code_ptr[5+2] = (Uint) lib; } } else { error: ASSERT(ret != am_ok); + if (lib != NULL) { + erts_free(ERTS_ALC_T_NIF, lib); + } if (handle != NULL) { erts_sys_ddll_close(handle); } @@ -749,3 +1300,53 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) BIF_RET(ret); } + +void +erts_unload_nif(struct erl_module_nif* lib) +{ + ErlNifResourceType* rt; + ErlNifResourceType* next; + ASSERT(erts_smp_is_system_blocked(0)); + ASSERT(lib != NULL); + ASSERT(!lib->is_orphan); + for (rt = resource_type_list.next; + rt != &resource_type_list; + rt = next) { + + next = rt->next; + if (rt->owner == lib) { + rt->next->prev = rt->prev; + rt->prev->next = rt->next; + rt->next = NULL; + rt->prev = NULL; + if (erts_refc_dectest(&rt->refc, 0) == 0) { + if (rt->dtor != NULL) { + erts_refc_dec(&lib->rt_dtor_cnt, 0); + } + erts_refc_dec(&lib->rt_cnt, 0); + erts_free(ERTS_ALC_T_NIF, rt); + } + } + } + if (erts_refc_read(&lib->rt_dtor_cnt, 0) == 0) { + close_lib(lib); + if (erts_refc_read(&lib->rt_cnt, 0) == 0) { + erts_free(ERTS_ALC_T_NIF, lib); + return; + } + } + else { + ASSERT(erts_refc_read(&lib->rt_cnt, 1) > 0); + } + lib->is_orphan = 1; +} + +void erl_nif_init() +{ + resource_type_list.next = &resource_type_list; + resource_type_list.prev = &resource_type_list; + resource_type_list.dtor = NULL; + resource_type_list.owner = NULL; + resource_type_list.name[0] = '\0'; +} + diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index e5e6d65c0e..1ccf00293e 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -1,25 +1,30 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2009-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ /* Include file for writers of Native Implemented Functions. */ +#ifndef __ERL_NIF_H__ +#define __ERL_NIF_H__ + +#include "erl_drv_nif.h" + /* Version history: ** 0.1: R13B03 ** 1.0: R13B04 @@ -63,11 +68,32 @@ typedef struct /* Internals (avert your eyes) */ ERL_NIF_TERM bin_term; - unsigned char* tmp_alloc; void* ref_bin; - }ErlNifBinary; +typedef struct enif_resource_type_t ErlNifResourceType; +typedef void ErlNifResourceDtor(ErlNifEnv*, void*); +enum ErlNifResourceFlags +{ + ERL_NIF_RT_CREATE = 1, + ERL_NIF_RT_TAKEOVER = 2 +}; + +typedef enum +{ + ERL_NIF_LATIN1 = 1 +}ErlNifCharEncoding; + +typedef ErlDrvSysInfo ErlNifSysInfo; + +typedef struct ErlDrvTid_ *ErlNifTid; +typedef struct ErlDrvMutex_ ErlNifMutex; +typedef struct ErlDrvCond_ ErlNifCond; +typedef struct ErlDrvRWLock_ ErlNifRWLock; +typedef int ErlNifTSDKey; + +typedef ErlDrvThreadOpts ErlNifThreadOpts; + #if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) # define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS typedef struct { @@ -124,3 +150,5 @@ ERL_NIF_INIT_DECL(NAME) \ return &entry; \ } +#endif /* __ERL_NIF_H__ */ + diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index 7556806ce4..ec07a976b2 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2009-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ @@ -22,7 +22,7 @@ #endif #ifdef ERL_NIF_API_FUNC_DECL -ERL_NIF_API_FUNC_DECL(void*,enif_get_data,(ErlNifEnv*)); +ERL_NIF_API_FUNC_DECL(void*,enif_priv_data,(ErlNifEnv*)); ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(ErlNifEnv*, size_t size)); ERL_NIF_API_FUNC_DECL(void,enif_free,(ErlNifEnv*, void* ptr)); ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term)); @@ -36,7 +36,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_get_int,(ErlNifEnv*, ERL_NIF_TERM term, int* ip)) ERL_NIF_API_FUNC_DECL(int,enif_get_ulong,(ErlNifEnv*, ERL_NIF_TERM term, unsigned long* ip)); ERL_NIF_API_FUNC_DECL(int,enif_get_double,(ErlNifEnv*, ERL_NIF_TERM term, double* dp)); ERL_NIF_API_FUNC_DECL(int,enif_get_list_cell,(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM* head, ERL_NIF_TERM* tail)); -ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, ERL_NIF_TERM** array)); +ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, const ERL_NIF_TERM** array)); ERL_NIF_API_FUNC_DECL(int,enif_is_identical,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)); ERL_NIF_API_FUNC_DECL(int,enif_compare,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin)); @@ -49,15 +49,69 @@ ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* n ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple,(ErlNifEnv* env, unsigned cnt, ...)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list,(ErlNifEnv* env, unsigned cnt, ...)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_TERM car, ERL_NIF_TERM cdr)); -ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string, ErlNifCharEncoding)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env)); + +ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_mutex_destroy,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(int,enif_mutex_trylock,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(void,enif_mutex_lock,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(void,enif_mutex_unlock,(ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_destroy,(ErlNifCond *cnd)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_signal,(ErlNifCond *cnd)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_broadcast,(ErlNifCond *cnd)); +ERL_NIF_API_FUNC_DECL(void,enif_cond_wait,(ErlNifCond *cnd, ErlNifMutex *mtx)); +ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_destroy,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_runlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrwlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rwunlock,(ErlNifRWLock *rwlck)); +ERL_NIF_API_FUNC_DECL(int,enif_tsd_key_create,(char *name, ErlNifTSDKey *key)); +ERL_NIF_API_FUNC_DECL(void,enif_tsd_key_destroy,(ErlNifTSDKey key)); +ERL_NIF_API_FUNC_DECL(void,enif_tsd_set,(ErlNifTSDKey key, void *data)); +ERL_NIF_API_FUNC_DECL(void*,enif_tsd_get,(ErlNifTSDKey key)); +ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name)); +ERL_NIF_API_FUNC_DECL(void,enif_thread_opts_destroy,(ErlNifThreadOpts *opts)); +ERL_NIF_API_FUNC_DECL(int,enif_thread_create,(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts)); +ERL_NIF_API_FUNC_DECL(ErlNifTid,enif_thread_self,(void)); +ERL_NIF_API_FUNC_DECL(int,enif_equal_tids,(ErlNifTid tid1, ErlNifTid tid2)); +ERL_NIF_API_FUNC_DECL(void,enif_thread_exit,(void *resp)); +ERL_NIF_API_FUNC_DECL(int,enif_thread_join,(ErlNifTid, void **respp)); + +ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(ErlNifEnv*, void* ptr, size_t size)); +ERL_NIF_API_FUNC_DECL(void,enif_system_info,(ErlNifSysInfo *sip, size_t si_size)); +ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(void/* FILE* */ *filep, const char *format, ...)); +ERL_NIF_API_FUNC_DECL(int,enif_inspect_iolist_as_binary,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifBinary* bin)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_sub_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, unsigned pos, unsigned size)); +ERL_NIF_API_FUNC_DECL(int,enif_get_string,(ErlNifEnv*, ERL_NIF_TERM list, char* buf, unsigned len, ErlNifCharEncoding)); +ERL_NIF_API_FUNC_DECL(int,enif_get_atom,(ErlNifEnv*, ERL_NIF_TERM atom, char* buf, unsigned len)); +ERL_NIF_API_FUNC_DECL(int,enif_is_fun,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_is_pid,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_is_port,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_get_uint,(ErlNifEnv*, ERL_NIF_TERM term, unsigned* ip)); +ERL_NIF_API_FUNC_DECL(int,enif_get_long,(ErlNifEnv*, ERL_NIF_TERM term, long* ip)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint,(ErlNifEnv*, unsigned i)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_long,(ErlNifEnv*, long i)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt)); +ERL_NIF_API_FUNC_DECL(int,enif_is_empty_list,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(ErlNifResourceType*,enif_open_resource_type,(ErlNifEnv*, const char* type_name, void (*dtor)(ErlNifEnv*,void *), enum ErlNifResourceFlags flags, enum ErlNifResourceFlags* tried)); +ERL_NIF_API_FUNC_DECL(void*,enif_alloc_resource,(ErlNifEnv*, ErlNifResourceType* type, unsigned size)); +ERL_NIF_API_FUNC_DECL(void,enif_release_resource,(ErlNifEnv*, void* obj)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource,(ErlNifEnv*, void* obj)); +ERL_NIF_API_FUNC_DECL(int,enif_get_resource,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp)); +ERL_NIF_API_FUNC_DECL(unsigned,enif_sizeof_resource,(ErlNifEnv*, void* obj)); /* ** Add last to keep compatibility on Windows!!! */ #endif #ifdef ERL_NIF_API_FUNC_MACRO -# define enif_get_data ERL_NIF_API_FUNC_MACRO(enif_get_data) +# define enif_priv_data ERL_NIF_API_FUNC_MACRO(enif_priv_data) # define enif_alloc ERL_NIF_API_FUNC_MACRO(enif_alloc) # define enif_free ERL_NIF_API_FUNC_MACRO(enif_free) # define enif_is_atom ERL_NIF_API_FUNC_MACRO(enif_is_atom) @@ -88,5 +142,84 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env)); # define enif_make_string ERL_NIF_API_FUNC_MACRO(enif_make_string) # define enif_make_ref ERL_NIF_API_FUNC_MACRO(enif_make_ref) +# define enif_mutex_create ERL_NIF_API_FUNC_MACRO(enif_mutex_create) +# define enif_mutex_destroy ERL_NIF_API_FUNC_MACRO(enif_mutex_destroy) +# define enif_mutex_trylock ERL_NIF_API_FUNC_MACRO(enif_mutex_trylock) +# define enif_mutex_lock ERL_NIF_API_FUNC_MACRO(enif_mutex_lock) +# define enif_mutex_unlock ERL_NIF_API_FUNC_MACRO(enif_mutex_unlock) +# define enif_cond_create ERL_NIF_API_FUNC_MACRO(enif_cond_create) +# define enif_cond_destroy ERL_NIF_API_FUNC_MACRO(enif_cond_destroy) +# define enif_cond_signal ERL_NIF_API_FUNC_MACRO(enif_cond_signal) +# define enif_cond_broadcast ERL_NIF_API_FUNC_MACRO(enif_cond_broadcast) +# define enif_cond_wait ERL_NIF_API_FUNC_MACRO(enif_cond_wait) +# define enif_rwlock_create ERL_NIF_API_FUNC_MACRO(enif_rwlock_create) +# define enif_rwlock_destroy ERL_NIF_API_FUNC_MACRO(enif_rwlock_destroy) +# define enif_rwlock_tryrlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrlock) +# define enif_rwlock_rlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rlock) +# define enif_rwlock_runlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_runlock) +# define enif_rwlock_tryrwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_tryrwlock) +# define enif_rwlock_rwlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwlock) +# define enif_rwlock_rwunlock ERL_NIF_API_FUNC_MACRO(enif_rwlock_rwunlock) +# define enif_tsd_key_create ERL_NIF_API_FUNC_MACRO(enif_tsd_key_create) +# define enif_tsd_key_destroy ERL_NIF_API_FUNC_MACRO(enif_tsd_key_destroy) +# define enif_tsd_set ERL_NIF_API_FUNC_MACRO(enif_tsd_set) +# define enif_tsd_get ERL_NIF_API_FUNC_MACRO(enif_tsd_get) +# define enif_thread_opts_create ERL_NIF_API_FUNC_MACRO(enif_thread_opts_create) +# define enif_thread_opts_destroy ERL_NIF_API_FUNC_MACRO(enif_thread_opts_destroy) +# define enif_thread_create ERL_NIF_API_FUNC_MACRO(enif_thread_create) +# define enif_thread_self ERL_NIF_API_FUNC_MACRO(enif_thread_self) +# define enif_equal_tids ERL_NIF_API_FUNC_MACRO(enif_equal_tids) +# define enif_thread_exit ERL_NIF_API_FUNC_MACRO(enif_thread_exit) +# define enif_thread_join ERL_NIF_API_FUNC_MACRO(enif_thread_join) + +# define enif_realloc ERL_NIF_API_FUNC_MACRO(enif_realloc) +# define enif_system_info ERL_NIF_API_FUNC_MACRO(enif_system_info) +# define enif_fprintf ERL_NIF_API_FUNC_MACRO(enif_fprintf) +# define enif_inspect_iolist_as_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_iolist_as_binary) +# define enif_make_sub_binary ERL_NIF_API_FUNC_MACRO(enif_make_sub_binary) +# define enif_get_string ERL_NIF_API_FUNC_MACRO(enif_get_string) +# define enif_get_atom ERL_NIF_API_FUNC_MACRO(enif_get_atom) +# define enif_is_fun ERL_NIF_API_FUNC_MACRO(enif_is_fun) +# define enif_is_pid ERL_NIF_API_FUNC_MACRO(enif_is_pid) +# define enif_is_port ERL_NIF_API_FUNC_MACRO(enif_is_port) +# define enif_get_uint ERL_NIF_API_FUNC_MACRO(enif_get_uint) +# define enif_get_long ERL_NIF_API_FUNC_MACRO(enif_get_long) +# define enif_make_uint ERL_NIF_API_FUNC_MACRO(enif_make_uint) +# define enif_make_long ERL_NIF_API_FUNC_MACRO(enif_make_long) +# define enif_make_tuple_from_array ERL_NIF_API_FUNC_MACRO(enif_make_tuple_from_array) +# define enif_make_list_from_array ERL_NIF_API_FUNC_MACRO(enif_make_list_from_array) +# define enif_is_empty_list ERL_NIF_API_FUNC_MACRO(enif_is_empty_list) +# define enif_open_resource_type ERL_NIF_API_FUNC_MACRO(enif_open_resource_type) +# define enif_alloc_resource ERL_NIF_API_FUNC_MACRO(enif_alloc_resource) +# define enif_release_resource ERL_NIF_API_FUNC_MACRO(enif_release_resource) +# define enif_make_resource ERL_NIF_API_FUNC_MACRO(enif_make_resource) +# define enif_get_resource ERL_NIF_API_FUNC_MACRO(enif_get_resource) +# define enif_sizeof_resource ERL_NIF_API_FUNC_MACRO(enif_sizeof_resource) + +#endif + +#ifndef enif_make_list1 +# define enif_make_list1(ENV,E1) enif_make_list(ENV,1,E1) +# define enif_make_list2(ENV,E1,E2) enif_make_list(ENV,2,E1,E2) +# define enif_make_list3(ENV,E1,E2,E3) enif_make_list(ENV,3,E1,E2,E3) +# define enif_make_list4(ENV,E1,E2,E3,E4) enif_make_list(ENV,4,E1,E2,E3,E4) +# define enif_make_list5(ENV,E1,E2,E3,E4,E5) enif_make_list(ENV,5,E1,E2,E3,E4,E5) +# define enif_make_list6(ENV,E1,E2,E3,E4,E5,E6) enif_make_list(ENV,6,E1,E2,E3,E4,E5,E6) +# define enif_make_list7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_list(ENV,7,E1,E2,E3,E4,E5,E6,E7) +# define enif_make_list8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_list(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8) +# define enif_make_list9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_list(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9) +# define enif_make_tuple1(ENV,E1) enif_make_tuple(ENV,1,E1) +# define enif_make_tuple2(ENV,E1,E2) enif_make_tuple(ENV,2,E1,E2) +# define enif_make_tuple3(ENV,E1,E2,E3) enif_make_tuple(ENV,3,E1,E2,E3) +# define enif_make_tuple4(ENV,E1,E2,E3,E4) enif_make_tuple(ENV,4,E1,E2,E3,E4) +# define enif_make_tuple5(ENV,E1,E2,E3,E4,E5) enif_make_tuple(ENV,5,E1,E2,E3,E4,E5) +# define enif_make_tuple6(ENV,E1,E2,E3,E4,E5,E6) enif_make_tuple(ENV,6,E1,E2,E3,E4,E5,E6) +# define enif_make_tuple7(ENV,E1,E2,E3,E4,E5,E6,E7) enif_make_tuple(ENV,7,E1,E2,E3,E4,E5,E6,E7) +# define enif_make_tuple8(ENV,E1,E2,E3,E4,E5,E6,E7,E8) enif_make_tuple(ENV,8,E1,E2,E3,E4,E5,E6,E7,E8) +# define enif_make_tuple9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_tuple(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9) +#endif + +#ifndef enif_get_data +# define enif_get_data enif_priv_data /* deprecated */ #endif diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index b011d4c0de..099eddd195 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -1027,11 +1027,12 @@ static uLongf binary2term_uncomp_size(byte* data, Sint size) err = inflateInit(&stream); if (err == Z_OK) { - while ((err = inflate(&stream, Z_NO_FLUSH)) == Z_OK) { - uncomp_size += chunk_size - stream.avail_out; + do { stream.next_out = tmp_buf; - stream.avail_out = chunk_size; - } + stream.avail_out = chunk_size; + err = inflate(&stream, Z_NO_FLUSH); + uncomp_size += chunk_size - stream.avail_out; + }while (err == Z_OK); inflateEnd(&stream); } erts_free(ERTS_ALC_T_TMP, tmp_buf); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 8def007c63..cab249a53f 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -76,19 +76,29 @@ typedef struct line_buf { /* Buffer used in line oriented I/O */ The rest is the overflow buffer. */ } LineBuf; +/* Temporary object header, auto-deallocated when NIF returns. */ +struct enif_tmp_obj_t { + struct enif_tmp_obj_t* next; + void (*dtor)(struct enif_tmp_obj_t*); + /*char data[];*/ +}; struct enif_environment_t /* ErlNifEnv */ { - void* nif_data; + struct erl_module_nif* mod_nif; Process* proc; Eterm* hp; Eterm* hp_end; - unsigned heap_frag_sz; + ErlHeapFragment* heap_frag; int fpe_was_unmasked; + struct enif_tmp_obj_t* tmp_obj_list; }; -extern void erts_pre_nif(struct enif_environment_t*, Process*, void* nif_data); +extern void erts_pre_nif(struct enif_environment_t*, Process*, + struct erl_module_nif*); extern void erts_post_nif(struct enif_environment_t* env); extern Eterm erts_nif_taints(Process* p); -extern void erts_print_nif_taints(int to, void* to_arg); +extern void erts_print_nif_taints(int to, void* to_arg); +void erts_unload_nif(struct erl_module_nif* nif); +extern void erl_nif_init(void); /* * Port Specific Data. @@ -403,6 +413,9 @@ typedef struct binary { char orig_bytes[1]; /* to be continued */ } Binary; +#define ERTS_SIZEOF_Binary(Sz) \ + (offsetof(Binary,orig_bytes) + (Sz)) + typedef struct { ERTS_INTERNAL_BINARY_FIELDS long orig_size; @@ -435,7 +448,9 @@ typedef union { #define ERTS_MAGIC_BIN_ORIG_SIZE(Sz) \ (sizeof(void (*)(Binary *)) + (Sz)) #define ERTS_MAGIC_BIN_SIZE(Sz) \ - (sizeof(ErtsMagicBinary) - 1 + (Sz)) + (offsetof(ErtsMagicBinary,magic_bin_data) + (Sz)) +#define ERTS_MAGIC_BIN_FROM_DATA(DATA) \ + ((ErtsBinary*)((char*)(DATA) - offsetof(ErtsMagicBinary,magic_bin_data))) #define Binary2ErlDrvBinary(B) (&((ErtsBinary *) (B))->driver.binary) #define ErlDrvBinary2Binary(D) ((Binary *) \ diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index c5de180cb2..ad0b909b2a 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -31,6 +31,7 @@ /* must be included BEFORE global.h (since it includes erl_driver.h) */ #include "erl_sys_driver.h" +#include "erl_nif.h" #include "erl_vm.h" #include "global.h" @@ -1078,7 +1079,7 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) } cbin = driver_alloc_binary(csize); if (!cbin) - erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, sizeof(Binary) + csize); + erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, ERTS_SIZEOF_Binary(csize)); /* Element 0 is for driver usage to add header block */ ivp[0].iov_base = NULL; @@ -4473,7 +4474,14 @@ driver_system_info(ErlDrvSysInfo *sip, size_t si_size) sip->async_threads = erts_async_max_threads; sip->scheduler_threads = erts_no_schedulers; } - + /* + * 'nif_minor_version' is the last field in the third version + * (driver version 1.5, NIF version 1.0) + */ + if (si_size >= ERL_DRV_SYS_INFO_SIZE(nif_minor_version)) { + sip->nif_major_version = ERL_NIF_MAJOR_VERSION; + sip->nif_minor_version = ERL_NIF_MINOR_VERSION; + } } diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index 57a43c89f4..91e4ccce70 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ @@ -66,12 +66,8 @@ static Module* module_alloc(Module* tmpl) obj->code_length = 0; obj->old_code_length = 0; obj->slot.index = -1; - obj->nif.handle = NULL; - obj->old_nif.handle = NULL; - obj->nif.entry = NULL; - obj->old_nif.entry = NULL; - obj->nif.data = NULL; - obj->old_nif.data = NULL; + obj->nif = NULL; + obj->old_nif = NULL; return obj; } diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 314be8e2ee..87d13b3607 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ @@ -24,11 +24,6 @@ #include "index.h" #endif -struct erl_module_nif { - void* handle; - struct enif_entry_t* entry; - void* data; -}; typedef struct erl_module { IndexSlot slot; /* Must be located at top of struct! */ @@ -39,8 +34,8 @@ typedef struct erl_module { int code_length; /* Length of loaded code in bytes. */ int old_code_length; /* Length of old loaded code in bytes */ unsigned catches, old_catches; - struct erl_module_nif nif; - struct erl_module_nif old_nif; + struct erl_module_nif* nif; + struct erl_module_nif* old_nif; } Module; Module* erts_get_module(Eterm mod); diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 687e6fa67b..31efddc0f2 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -124,26 +124,28 @@ erts_heap_alloc(Process* p, Uint need) #endif /* FORCE_HEAP_FRAGS */ n = need; + bp = MBUF(p); + if (bp != NULL && need <= (bp->size - bp->used_size)) { + Eterm* ret = bp->mem + bp->used_size; + bp->used_size += need; + return ret; + } #ifdef DEBUG n++; #endif bp = (ErlHeapFragment*) ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP_FRAG, ERTS_HEAP_FRAG_SIZE(n)); -#ifdef DEBUG - n--; -#endif - -#if defined(DEBUG) - for (i = 0; i <= n; i++) { - bp->mem[i] = ERTS_HOLE_MARKER; - } -#elif defined(CHECK_FOR_HOLES) +#if defined(DEBUG) || defined(CHECK_FOR_HOLES) for (i = 0; i < n; i++) { bp->mem[i] = ERTS_HOLE_MARKER; } #endif +#ifdef DEBUG + n--; +#endif + /* * When we have created a heap fragment, we are no longer allowed * to store anything more on the heap. -- cgit v1.2.3