aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2010-06-03 12:41:28 +0000
committerErlang/OTP <[email protected]>2010-06-03 12:41:28 +0000
commit8335159b919cc330e1c529464b6bbf89edbbe0a0 (patch)
tree7616c514cd3c809de4674cb146fd432afb2e85a7 /erts/emulator
parent95ee37bc47ae9ff6eb26b7364f7ec953f894fc46 (diff)
downloadotp-8335159b919cc330e1c529464b6bbf89edbbe0a0.tar.gz
otp-8335159b919cc330e1c529464b6bbf89edbbe0a0.tar.bz2
otp-8335159b919cc330e1c529464b6bbf89edbbe0a0.zip
OTP-8555 Send message from NIF
New NIF features: Send messages from a NIF, or from thread created by NIF, to any local process (enif_send) Store terms between NIF calls (enif_alloc_env, enif_make_copy) Create binary terms with user defined memory management (enif_make_resource_binary)
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/break.c2
-rw-r--r--erts/emulator/beam/copy.c130
-rw-r--r--erts/emulator/beam/erl_bif_info.c6
-rw-r--r--erts/emulator/beam/erl_bif_port.c4
-rw-r--r--erts/emulator/beam/erl_bif_timer.c2
-rw-r--r--erts/emulator/beam/erl_db_util.c17
-rw-r--r--erts/emulator/beam/erl_debug.c6
-rw-r--r--erts/emulator/beam/erl_gc.c101
-rw-r--r--erts/emulator/beam/erl_gc.h39
-rw-r--r--erts/emulator/beam/erl_message.c133
-rw-r--r--erts/emulator/beam/erl_message.h19
-rw-r--r--erts/emulator/beam/erl_nif.c332
-rw-r--r--erts/emulator/beam/erl_nif.h38
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h58
-rw-r--r--erts/emulator/beam/erl_process.c19
-rw-r--r--erts/emulator/beam/erl_process.h2
-rw-r--r--erts/emulator/beam/erl_vm.h1
-rw-r--r--erts/emulator/beam/global.h3
-rw-r--r--erts/emulator/beam/utils.c5
-rw-r--r--erts/emulator/hipe/hipe_gc.c18
-rw-r--r--erts/emulator/test/nif_SUITE.erl225
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c646
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c80
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.h12
24 files changed, 1492 insertions, 406 deletions
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 5cb1481a3a..857cb177c8 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -258,12 +258,10 @@ print_process_info(int to, void *to_arg, Process *p)
}
{
- long s = 0;
int frags = 0;
ErlHeapFragment *m = p->mbuf;
while (m != NULL) {
frags++;
- s += m->size;
m = m->next;
}
erts_print(to, to_arg, "Number of heap fragments: %d\n", frags);
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index 0a5050b1fe..521a1b1788 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.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%
*/
@@ -37,6 +37,8 @@ MA_STACK_DECLARE(dst);
MA_STACK_DECLARE(offset);
#endif
+static void move_one_frag(Eterm** hpp, Eterm* src, Uint src_sz, ErlOffHeap*);
+
void
init_copy(void)
{
@@ -86,7 +88,7 @@ size_object(Eterm obj)
obj = *ptr++;
if (!IS_CONST(obj)) {
ESTACK_PUSH(s, obj);
- }
+ }
obj = *ptr;
break;
case TAG_PRIMARY_BOXED:
@@ -99,7 +101,7 @@ size_object(Eterm obj)
arity = header_arity(hdr);
sum += arity + 1;
if (arity == 0) { /* Empty tuple -- unusual. */
- goto size_common;
+ goto pop_next;
}
while (arity-- > 1) {
obj = *++ptr;
@@ -115,7 +117,6 @@ size_object(Eterm obj)
ErlFunThing* funp = (ErlFunThing *) bptr;
unsigned eterms = 1 /* creator */ + funp->num_free;
unsigned sz = thing_arityval(hdr);
-
sum += 1 /* header */ + sz + eterms;
bptr += 1 /* header */ + sz;
while (eterms-- > 1) {
@@ -151,7 +152,7 @@ size_object(Eterm obj)
} else {
sum += heap_bin_size(binary_size(obj)+extra_bytes);
}
- goto size_common;
+ goto pop_next;
}
break;
case BIN_MATCHSTATE_SUBTAG:
@@ -159,18 +160,12 @@ size_object(Eterm obj)
"size_object: matchstate term not allowed");
default:
sum += thing_arityval(hdr) + 1;
- /* Fall through */
- size_common:
- if (ESTACK_ISEMPTY(s)) {
- DESTROY_ESTACK(s);
- return sum;
- }
- obj = ESTACK_POP(s);
- break;
+ goto pop_next;
}
}
break;
case TAG_PRIMARY_IMMED1:
+ pop_next:
if (ESTACK_ISEMPTY(s)) {
DESTROY_ESTACK(s);
return sum;
@@ -979,3 +974,104 @@ copy_shallow(Eterm* ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
*hpp = hp;
return make_tuple(ptr + offs);
}
+
+/* Move all terms in heap fragments into heap. The terms must be guaranteed to
+ * be contained within the fragments. The source terms are destructed with
+ * move markers.
+ * Typically used to copy a multi-fragmented message (from NIF).
+ */
+void move_multi_frags(Eterm** hpp, ErlOffHeap* off_heap, ErlHeapFragment* first,
+ Eterm* refs, unsigned nrefs)
+{
+ ErlHeapFragment* bp;
+ Eterm* hp_start = *hpp;
+ Eterm* hp_end;
+ Eterm* hp;
+ unsigned i;
+
+ for (bp=first; bp!=NULL; bp=bp->next) {
+ move_one_frag(hpp, bp->mem, bp->used_size, off_heap);
+ off_heap->overhead += bp->off_heap.overhead;
+ }
+ hp_end = *hpp;
+ for (hp=hp_start; hp<hp_end; ++hp) {
+ Eterm* ptr;
+ Eterm val;
+ Eterm gval = *hp;
+ switch (primary_tag(gval)) {
+ case TAG_PRIMARY_BOXED:
+ ptr = boxed_val(gval);
+ val = *ptr;
+ if (IS_MOVED_BOXED(val)) {
+ ASSERT(is_boxed(val));
+ *hp = val;
+ }
+ break;
+ case TAG_PRIMARY_LIST:
+ ptr = list_val(gval);
+ val = *ptr;
+ if (IS_MOVED_CONS(val)) {
+ *hp = ptr[1];
+ }
+ break;
+ case TAG_PRIMARY_HEADER:
+ if (header_is_thing(gval)) {
+ hp += thing_arityval(gval);
+ }
+ break;
+ }
+ }
+ for (i=0; i<nrefs; ++i) {
+ refs[i] = follow_moved(refs[i]);
+ }
+}
+
+static void
+move_one_frag(Eterm** hpp, Eterm* src, Uint src_sz, ErlOffHeap* off_heap)
+{
+ union {
+ Uint *up;
+ ProcBin *pbp;
+ ErlFunThing *efp;
+ ExternalThing *etp;
+ } ohe;
+ Eterm* ptr = src;
+ Eterm* end = ptr + src_sz;
+ Eterm dummy_ref;
+ Eterm* hp = *hpp;
+
+ while (ptr != end) {
+ Eterm val;
+ ASSERT(ptr < end);
+ val = *ptr;
+ ASSERT(val != ERTS_HOLE_MARKER);
+ if (is_header(val)) {
+ ASSERT(ptr + header_arity(val) < end);
+ ohe.up = hp;
+ MOVE_BOXED(ptr, val, hp, &dummy_ref);
+ switch (val & _HEADER_SUBTAG_MASK) {
+ case REFC_BINARY_SUBTAG:
+ ohe.pbp->next = off_heap->mso;
+ off_heap->mso = ohe.pbp;
+ break;
+ case FUN_SUBTAG:
+ ohe.efp->next = off_heap->funs;
+ off_heap->funs = ohe.efp;
+ break;
+ case EXTERNAL_PID_SUBTAG:
+ case EXTERNAL_PORT_SUBTAG:
+ case EXTERNAL_REF_SUBTAG:
+ ohe.etp->next = off_heap->externals;
+ off_heap->externals = ohe.etp;
+ break;
+ }
+ }
+ else { /* must be a cons cell */
+ ASSERT(ptr+1 < end);
+ MOVE_CONS(ptr, val, hp, &dummy_ref);
+ ptr += 2;
+ }
+ }
+ *hpp = hp;
+}
+
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index de60ca49fa..70d0e91a2c 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -1140,9 +1140,9 @@ process_info_aux(Process *BIF_P,
}
else {
/* Make our copy of the message */
- ASSERT(size_object(msg) == hfp->size);
+ ASSERT(size_object(msg) == hfp->used_size);
msg = copy_struct(msg,
- hfp->size,
+ hfp->used_size,
&hp,
&MSO(BIF_P));
}
@@ -2715,7 +2715,7 @@ BIF_RETTYPE port_info_2(BIF_ALIST_2)
erts_doforall_links(prt->nlinks, &one_link_size, &size);
for (bp = prt->bp; bp; bp = bp->next)
- size += sizeof(ErlHeapFragment) + (bp->size - 1)*sizeof(Eterm);
+ size += sizeof(ErlHeapFragment) + (bp->alloc_size - 1)*sizeof(Eterm);
if (prt->linebuf)
size += sizeof(LineBuf) + prt->linebuf->ovsiz;
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 9b56ddd4f8..378c5e73fd 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -579,8 +579,8 @@ BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
if (prt->bp == NULL) { /* MUST be CONST! */
res = prt->data;
} else {
- Eterm* hp = HAlloc(BIF_P, prt->bp->size);
- res = copy_struct(prt->data, prt->bp->size, &hp, &MSO(BIF_P));
+ Eterm* hp = HAlloc(BIF_P, prt->bp->used_size);
+ res = copy_struct(prt->data, prt->bp->used_size, &hp, &MSO(BIF_P));
}
erts_smp_port_unlock(prt);
BIF_RET(res);
diff --git a/erts/emulator/beam/erl_bif_timer.c b/erts/emulator/beam/erl_bif_timer.c
index eb40c75110..4ae2f6ebf4 100644
--- a/erts/emulator/beam/erl_bif_timer.c
+++ b/erts/emulator/beam/erl_bif_timer.c
@@ -357,7 +357,7 @@ bif_timer_timeout(ErtsBifTimer* btm)
rp,
&rp_locks);
} else {
- Eterm old_size = bp->size;
+ Eterm old_size = bp->used_size;
bp = erts_resize_message_buffer(bp, old_size + wrap_size,
&message, 1);
hp = &bp->mem[0] + old_size;
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index fd7de98ac9..93a47eb76f 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -1547,10 +1547,9 @@ restart:
*/
context.save = NULL;
error: /* Here is were we land when compilation failed. */
- while (context.save != NULL) {
- ErlHeapFragment *ll = context.save->next;
+ if (context.save != NULL) {
free_message_buffer(context.save);
- context.save = ll;
+ context.save = NULL;
}
DMC_FREE(stack);
DMC_FREE(text);
@@ -1567,15 +1566,11 @@ error: /* Here is were we land when compilation failed. */
void erts_db_match_prog_destructor(Binary *bprog)
{
MatchProg *prog;
- ErlHeapFragment *tmp, *ll;
if (bprog == NULL)
return;
prog = Binary2MatchProg(bprog);
- tmp = prog->term_save;
- while (tmp != NULL) {
- ll = tmp->next;
- free_message_buffer(tmp);
- tmp = ll;
+ if (prog->term_save != NULL) {
+ free_message_buffer(prog->term_save);
}
if (prog->saved_program_buf != NULL)
free_message_buffer(prog->saved_program_buf);
@@ -4125,7 +4120,7 @@ static int match_compact(ErlHeapFragment *expr, DMCErrInfo *err_info)
DMC_INIT_STACK(heap);
p = expr->mem;
- i = expr->size;
+ i = expr->used_size;
while (i--) {
if (is_thing(*p)) {
a = thing_arityval(*p);
@@ -4154,7 +4149,7 @@ static int match_compact(ErlHeapFragment *expr, DMCErrInfo *err_info)
}
p = expr->mem;
- i = expr->size;
+ i = expr->used_size;
while (i--) {
if (is_thing(*p)) {
a = thing_arityval(*p);
diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index 58d3f92f56..d7d6fcf0a2 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -261,7 +261,7 @@ static int verify_eterm(Process *p,Eterm element)
return 1;
for (mbuf = p->mbuf; mbuf; mbuf = mbuf->next) {
- if (WITHIN(ptr, &mbuf->mem[0], &mbuf->mem[0] + mbuf->size)) {
+ if (WITHIN(ptr, &mbuf->mem[0], &mbuf->mem[0] + mbuf->used_size)) {
return 1;
}
}
@@ -308,7 +308,7 @@ void erts_check_stack(Process *p)
if (IN_HEAP(p, ptr))
continue;
for (mbuf = p->mbuf; mbuf; mbuf = mbuf->next)
- if (WITHIN(ptr, &mbuf->mem[0], &mbuf->mem[0] + mbuf->size)) {
+ if (WITHIN(ptr, &mbuf->mem[0], &mbuf->mem[0] + mbuf->used_size)) {
in_mbuf = 1;
break;
}
@@ -746,7 +746,7 @@ static void print_process_memory(Process *p)
PTR_SIZE, "heap fragments",
dashes, dashes, dashes, dashes);
while (bp) {
- print_untagged_memory(bp->mem,bp->mem + bp->size);
+ print_untagged_memory(bp->mem,bp->mem + bp->used_size);
bp = bp->next;
}
}
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 9ed566e66e..a19e090f1e 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -667,7 +667,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, Uint lit_size)
case TAG_PRIMARY_BOXED:
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*g_ptr++ = val;
} else if (in_area(ptr, area, area_size)) {
@@ -679,7 +679,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, Uint lit_size)
case TAG_PRIMARY_LIST:
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) { /* Moved */
+ if (IS_MOVED_CONS(val)) { /* Moved */
*g_ptr++ = ptr[1];
} else if (in_area(ptr, area, area_size)) {
MOVE_CONS(ptr,val,old_htop,g_ptr++);
@@ -913,7 +913,7 @@ do_minor(Process *p, int new_sz, Eterm* objv, int nobj)
case TAG_PRIMARY_BOXED: {
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*g_ptr++ = val;
} else if (in_area(ptr, heap, mature_size)) {
@@ -929,7 +929,7 @@ do_minor(Process *p, int new_sz, Eterm* objv, int nobj)
case TAG_PRIMARY_LIST: {
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) { /* Moved */
+ if (IS_MOVED_CONS(val)) { /* Moved */
*g_ptr++ = ptr[1];
} else if (in_area(ptr, heap, mature_size)) {
MOVE_CONS(ptr,val,old_htop,g_ptr++);
@@ -972,7 +972,7 @@ do_minor(Process *p, int new_sz, Eterm* objv, int nobj)
case TAG_PRIMARY_BOXED: {
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*n_hp++ = val;
} else if (in_area(ptr, heap, mature_size)) {
@@ -987,7 +987,7 @@ do_minor(Process *p, int new_sz, Eterm* objv, int nobj)
case TAG_PRIMARY_LIST: {
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
*n_hp++ = ptr[1];
} else if (in_area(ptr, heap, mature_size)) {
MOVE_CONS(ptr,val,old_htop,n_hp++);
@@ -1008,7 +1008,7 @@ do_minor(Process *p, int new_sz, Eterm* objv, int nobj)
Eterm* origptr = &(mb->orig);
ptr = boxed_val(*origptr);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
*origptr = val;
mb->base = binary_bytes(val);
} else if (in_area(ptr, heap, mature_size)) {
@@ -1161,7 +1161,7 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
case TAG_PRIMARY_BOXED: {
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*g_ptr++ = val;
} else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
@@ -1175,7 +1175,7 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
case TAG_PRIMARY_LIST: {
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
*g_ptr++ = ptr[1];
} else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
MOVE_CONS(ptr,val,n_htop,g_ptr++);
@@ -1216,7 +1216,7 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
case TAG_PRIMARY_BOXED: {
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*n_hp++ = val;
} else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
@@ -1229,7 +1229,7 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
case TAG_PRIMARY_LIST: {
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
*n_hp++ = ptr[1];
} else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
MOVE_CONS(ptr,val,n_htop,n_hp++);
@@ -1249,7 +1249,7 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
origptr = &(mb->orig);
ptr = boxed_val(*origptr);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
*origptr = val;
mb->base = binary_bytes(*origptr);
} else if (in_area(ptr, src, src_size) ||
@@ -1392,17 +1392,12 @@ combined_message_size(Process* p)
static void
remove_message_buffers(Process* p)
{
- ErlHeapFragment* bp = MBUF(p);
-
- MBUF(p) = NULL;
- MBUF_SIZE(p) = 0;
- while (bp != NULL) {
- ErlHeapFragment* next_bp = bp->next;
- free_message_buffer(bp);
- bp = next_bp;
- }
+ if (MBUF(p) != NULL) {
+ free_message_buffer(MBUF(p));
+ MBUF(p) = NULL;
+ }
+ MBUF_SIZE(p) = 0;
}
-
#ifdef HARDDEBUG
/*
@@ -1433,12 +1428,12 @@ disallow_heap_frag_ref(Process* p, Eterm* n_htop, Eterm* objv, int nobj)
case TAG_PRIMARY_BOXED: {
ptr = _unchecked_boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
objv++;
} else {
for (qb = mbuf; qb != NULL; qb = qb->next) {
- if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
+ if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
abort();
}
}
@@ -1450,11 +1445,11 @@ disallow_heap_frag_ref(Process* p, Eterm* n_htop, Eterm* objv, int nobj)
case TAG_PRIMARY_LIST: {
ptr = _unchecked_list_val(gval);
val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
objv++;
} else {
for (qb = mbuf; qb != NULL; qb = qb->next) {
- if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
+ if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
abort();
}
}
@@ -1499,7 +1494,7 @@ disallow_heap_frag_ref_in_heap(Process* p)
ptr = _unchecked_boxed_val(val);
if (!in_area(ptr, heap, heap_size)) {
for (qb = MBUF(p); qb != NULL; qb = qb->next) {
- if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
+ if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
abort();
}
}
@@ -1509,7 +1504,7 @@ disallow_heap_frag_ref_in_heap(Process* p)
ptr = _unchecked_list_val(val);
if (!in_area(ptr, heap, heap_size)) {
for (qb = MBUF(p); qb != NULL; qb = qb->next) {
- if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
+ if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
abort();
}
}
@@ -1557,7 +1552,7 @@ disallow_heap_frag_ref_in_old_heap(Process* p)
abort();
}
for (qb = MBUF(p); qb != NULL; qb = qb->next) {
- if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
+ if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
abort();
}
}
@@ -1570,7 +1565,7 @@ disallow_heap_frag_ref_in_old_heap(Process* p)
abort();
}
for (qb = MBUF(p); qb != NULL; qb = qb->next) {
- if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
+ if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
abort();
}
}
@@ -1610,7 +1605,7 @@ sweep_rootset(Rootset* rootset, Eterm* htop, char* src, Uint src_size)
case TAG_PRIMARY_BOXED: {
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*g_ptr++ = val;
} else if (in_area(ptr, src, src_size)) {
@@ -1623,7 +1618,7 @@ sweep_rootset(Rootset* rootset, Eterm* htop, char* src, Uint src_size)
case TAG_PRIMARY_LIST: {
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) { /* Moved */
+ if (IS_MOVED_CONS(val)) {
*g_ptr++ = ptr[1];
} else if (in_area(ptr, src, src_size)) {
MOVE_CONS(ptr,val,htop,g_ptr++);
@@ -1657,7 +1652,7 @@ sweep_one_area(Eterm* n_hp, Eterm* n_htop, char* src, Uint src_size)
case TAG_PRIMARY_BOXED: {
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*n_hp++ = val;
} else if (in_area(ptr, src, src_size)) {
@@ -1670,7 +1665,7 @@ sweep_one_area(Eterm* n_hp, Eterm* n_htop, char* src, Uint src_size)
case TAG_PRIMARY_LIST: {
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
*n_hp++ = ptr[1];
} else if (in_area(ptr, src, src_size)) {
MOVE_CONS(ptr,val,n_htop,n_hp++);
@@ -1690,7 +1685,7 @@ sweep_one_area(Eterm* n_hp, Eterm* n_htop, char* src, Uint src_size)
origptr = &(mb->orig);
ptr = boxed_val(*origptr);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
*origptr = val;
mb->base = binary_bytes(*origptr);
} else if (in_area(ptr, src, src_size)) {
@@ -1722,7 +1717,7 @@ sweep_one_heap(Eterm* heap_ptr, Eterm* heap_end, Eterm* htop, char* src, Uint sr
case TAG_PRIMARY_BOXED: {
ptr = boxed_val(gval);
val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*heap_ptr++ = val;
} else if (in_area(ptr, src, src_size)) {
@@ -1735,7 +1730,7 @@ sweep_one_heap(Eterm* heap_ptr, Eterm* heap_end, Eterm* htop, char* src, Uint sr
case TAG_PRIMARY_LIST: {
ptr = list_val(gval);
val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
*heap_ptr++ = ptr[1];
} else if (in_area(ptr, src, src_size)) {
MOVE_CONS(ptr,val,htop,heap_ptr++);
@@ -1830,28 +1825,6 @@ collect_heap_frags(Process* p, Eterm* n_hstart, Eterm* n_htop,
return n_htop;
}
-#ifdef DEBUG
-static Eterm follow_moved(Eterm term)
-{
- Eterm* ptr;
- switch (primary_tag(term)) {
- case TAG_PRIMARY_IMMED1:
- break;
- case TAG_PRIMARY_BOXED:
- ptr = boxed_val(term);
- if (IS_MOVED(*ptr)) term = *ptr;
- break;
- case TAG_PRIMARY_LIST:
- ptr = list_val(term);
- if (is_non_value(ptr[0])) term = ptr[1];
- break;
- default:
- abort();
- }
- return term;
-}
-#endif
-
static Uint
setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset)
{
@@ -2090,7 +2063,7 @@ sweep_proc_externals(Process *p, int fullsweep)
while (ptr) {
Eterm* ppt = (Eterm *) ptr;
- if (IS_MOVED(*ppt)) { /* Object is alive */
+ if (IS_MOVED_BOXED(*ppt)) { /* Object is alive */
ExternalThing* ro = external_thing_ptr(*ppt);
*prev = ro; /* Patch to moved pos */
@@ -2130,7 +2103,7 @@ sweep_proc_funs(Process *p, int fullsweep)
while (ptr) {
Eterm* ppt = (Eterm *) ptr;
- if (IS_MOVED(*ppt)) { /* Object is alive */
+ if (IS_MOVED_BOXED(*ppt)) { /* Object is alive */
ErlFunThing* ro = (ErlFunThing *) fun_val(*ppt);
*prev = ro; /* Patch to moved pos */
@@ -2244,7 +2217,7 @@ sweep_proc_bins(Process *p, int fullsweep)
while (ptr) {
Eterm* ppt = (Eterm *) ptr;
- if (IS_MOVED(*ppt)) { /* Object is alive */
+ if (IS_MOVED_BOXED(*ppt)) { /* Object is alive */
bin_vheap += ptr->size / sizeof(Eterm);
ptr = (ProcBin*) binary_val(*ppt);
link_live_proc_bin(&shrink,
@@ -2542,7 +2515,7 @@ within2(Eterm *ptr, Process *p, Eterm *real_htop)
return 1;
}
while (bp != NULL) {
- if (bp->mem <= ptr && ptr < bp->mem + bp->size) {
+ if (bp->mem <= ptr && ptr < bp->mem + bp->used_size) {
return 1;
}
bp = bp->next;
@@ -2556,7 +2529,7 @@ within2(Eterm *ptr, Process *p, Eterm *real_htop)
hfp = erts_dist_ext_trailer(mp->data.dist_ext);
else
hfp = NULL;
- if (hfp && hfp->mem <= ptr && ptr < hfp->mem + hfp->size)
+ if (hfp && hfp->mem <= ptr && ptr < hfp->mem + hfp->used_size)
return 1;
}
mp = mp->next;
diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h
index af55b6363f..807ef8ae8d 100644
--- a/erts/emulator/beam/erl_gc.h
+++ b/erts/emulator/beam/erl_gc.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2007-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2007-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,11 +22,12 @@
/* GC declarations shared by beam/erl_gc.c and hipe/hipe_gc.c */
-#ifdef DEBUG
+#if defined(DEBUG) && !ERTS_GLB_INLINE_INCL_FUNC_DEF
# define HARDDEBUG 1
#endif
-#define IS_MOVED(x) (!is_header((x)))
+#define IS_MOVED_BOXED(x) (!is_header((x)))
+#define IS_MOVED_CONS(x) (is_non_value((x)))
#define MOVE_CONS(PTR,CAR,HTOP,ORIG) \
do { \
@@ -69,4 +70,28 @@ extern Uint erts_test_long_gc_sleep;
int within(Eterm *ptr, Process *p);
#endif
+ERTS_GLB_INLINE Eterm follow_moved(Eterm term);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE Eterm follow_moved(Eterm term)
+{
+ Eterm* ptr;
+ switch (primary_tag(term)) {
+ case TAG_PRIMARY_IMMED1:
+ break;
+ case TAG_PRIMARY_BOXED:
+ ptr = boxed_val(term);
+ if (IS_MOVED_BOXED(*ptr)) term = *ptr;
+ break;
+ case TAG_PRIMARY_LIST:
+ ptr = list_val(term);
+ if (IS_MOVED_CONS(ptr[0])) term = ptr[1];
+ break;
+ default:
+ ASSERT(!"strange tag in follow_moved");
+ }
+ return term;
+}
+#endif
+
#endif /* __ERL_GC_H__ */
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index a056fce0c5..b63f3df7df 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -42,6 +42,15 @@ ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(message,
#undef HARD_DEBUG
#endif
+
+
+
+static ERTS_INLINE int in_heapfrag(const Eterm* ptr, const ErlHeapFragment *bp)
+{
+ return ((unsigned)(ptr - bp->mem) < bp->used_size);
+}
+
+
void
init_message(void)
{
@@ -81,9 +90,12 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size,
#endif
ErlHeapFragment* nbp;
+ /* ToDo: Make use of 'used_size' to avoid realloc
+ when shrinking just a few words */
+
#ifdef DEBUG
{
- Uint off_sz = size < bp->size ? size : bp->size;
+ Uint off_sz = size < bp->used_size ? size : bp->used_size;
for (i = 0; i < brefs_size; i++) {
Eterm *ptr;
if (is_immed(brefs[i]))
@@ -95,12 +107,12 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size,
}
#endif
- if (size == bp->size)
+ if (size == bp->used_size)
return bp;
#ifdef HARD_DEBUG
dbg_brefs = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(Eterm *)*brefs_size);
- dbg_bp = new_message_buffer(bp->size);
+ dbg_bp = new_message_buffer(bp->used_size);
dbg_hp = dbg_bp->mem;
dbg_tot_size = 0;
for (i = 0; i < brefs_size; i++) {
@@ -109,15 +121,15 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size,
dbg_brefs[i] = copy_struct(brefs[i], dbg_size, &dbg_hp,
&dbg_bp->off_heap);
}
- ASSERT(dbg_tot_size == (size < bp->size ? size : bp->size));
+ ASSERT(dbg_tot_size == (size < bp->used_size ? size : bp->used_size));
#endif
nbp = (ErlHeapFragment*) ERTS_HEAP_REALLOC(ERTS_ALC_T_HEAP_FRAG,
(void *) bp,
- ERTS_HEAP_FRAG_SIZE(bp->size),
+ ERTS_HEAP_FRAG_SIZE(bp->alloc_size),
ERTS_HEAP_FRAG_SIZE(size));
if (bp != nbp) {
- Uint off_sz = size < nbp->size ? size : nbp->size;
+ Uint off_sz = size < nbp->used_size ? size : nbp->used_size;
Eterm *sp = &bp->mem[0];
Eterm *ep = sp + off_sz;
Sint offs = &nbp->mem[0] - sp;
@@ -135,7 +147,7 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size,
}
#endif
}
- nbp->size = size;
+ nbp->alloc_size = size;
nbp->used_size = size;
#ifdef HARD_DEBUG
@@ -168,10 +180,15 @@ erts_cleanup_offheap(ErlOffHeap *offheap)
void
free_message_buffer(ErlHeapFragment* bp)
{
- erts_cleanup_offheap(&bp->off_heap);
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP_FRAG,
- (void *) bp,
- ERTS_HEAP_FRAG_SIZE(bp->size));
+ ASSERT(bp != NULL);
+ do {
+ ErlHeapFragment* next_bp = bp->next;
+
+ erts_cleanup_offheap(&bp->off_heap);
+ ERTS_HEAP_FREE(ERTS_ALC_T_HEAP_FRAG, (void *) bp,
+ ERTS_HEAP_FRAG_SIZE(bp->size));
+ bp = next_bp;
+ }while (bp != NULL);
}
static ERTS_INLINE void
@@ -181,7 +198,7 @@ link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp)
/* Link the message buffer */
bp->next = MBUF(proc);
MBUF(proc) = bp;
- MBUF_SIZE(proc) += bp->size;
+ MBUF_SIZE(proc) += bp->used_size;
FLAGS(proc) |= F_FORCE_GC;
/* Move any binaries into the process */
@@ -242,7 +259,7 @@ erts_msg_distext2heap(Process *pp,
goto decode_error;
if (is_not_nil(*tokenp)) {
ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp);
- tok_sz = heap_frag->size;
+ tok_sz = heap_frag->used_size;
sz += tok_sz;
}
if (pp)
@@ -283,12 +300,13 @@ erts_msg_distext2heap(Process *pp,
erts_cleanup_offheap(&heap_frag->off_heap);
}
erts_free_dist_ext_copy(dist_extp);
- if (*bpp)
+ if (*bpp) {
free_message_buffer(*bpp);
+ *bpp = NULL;
+ }
else if (hp) {
HRelease(pp, hp_end, hp);
}
- *bpp = NULL;
return THE_NON_VALUE;
}
@@ -436,11 +454,10 @@ erts_queue_message(Process* receiver,
ERL_MESSAGE_TERM(mp) = message;
ERL_MESSAGE_TOKEN(mp) = seq_trace_token;
mp->next = NULL;
+ mp->data.heap_frag = bp;
#ifdef ERTS_SMP
if (*receiver_locks & ERTS_PROC_LOCK_MAIN) {
- mp->data.heap_frag = bp;
-
/*
* We move 'in queue' to 'private queue' and place
* message at the end of 'private queue' in order
@@ -453,11 +470,9 @@ erts_queue_message(Process* receiver,
LINK_MESSAGE_PRIVQ(receiver, mp);
}
else {
- mp->data.heap_frag = bp;
LINK_MESSAGE(receiver, mp);
}
#else
- mp->data.heap_frag = bp;
LINK_MESSAGE(receiver, mp);
#endif
@@ -530,32 +545,27 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
#ifdef HARD_DEBUG
dbg_term_sz = size_object(term);
dbg_token_sz = size_object(token);
- ASSERT(bp->size == dbg_term_sz + dbg_token_sz);
-
- dbg_bp = new_message_buffer(bp->size);
+ /*ASSERT(dbg_term_sz + dbg_token_sz == erts_msg_used_frag_sz(msg));
+ Copied size may be smaller due to removed SubBins's or garbage.
+ Copied size may be larger due to duplicated shared terms.
+ */
+ dbg_bp = new_message_buffer(dbg_term_sz + dbg_token_sz);
dbg_hp = dbg_bp->mem;
dbg_term = copy_struct(term, dbg_term_sz, &dbg_hp, &dbg_bp->off_heap);
dbg_token = copy_struct(token, dbg_token_sz, &dbg_hp, &dbg_bp->off_heap);
dbg_thp_start = *hpp;
#endif
- ASSERT(bp);
- msg->data.attached = NULL;
+ if (bp->next != NULL) {
+ move_multi_frags(hpp, off_heap, bp, msg->m, 2);
+ goto copy_done;
+ }
off_heap->overhead += bp->off_heap.overhead;
- sz = bp->size;
+ sz = bp->used_size;
-#ifdef DEBUG
- if (is_not_immed(term)) {
- ASSERT(bp->mem <= ptr_val(term));
- ASSERT(bp->mem + bp->size > ptr_val(term));
- }
-
- if (is_not_immed(token)) {
- ASSERT(bp->mem <= ptr_val(token));
- ASSERT(bp->mem + bp->size > ptr_val(token));
- }
-#endif
+ ASSERT(is_immed(term) || in_heapfrag(ptr_val(term),bp));
+ ASSERT(is_immed(token) || in_heapfrag(ptr_val(token),bp));
fhp = bp->mem;
hp = *hpp;
@@ -574,8 +584,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
break;
case TAG_PRIMARY_LIST:
case TAG_PRIMARY_BOXED:
- ASSERT(bp->mem <= ptr_val(val));
- ASSERT(bp->mem + bp->size > ptr_val(val));
+ ASSERT(in_heapfrag(ptr_val(val), bp));
*hp++ = offset_ptr(val, offs);
break;
case TAG_PRIMARY_HEADER:
@@ -609,6 +618,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
cpy_sz = header_arity(val);
cpy_words:
+ ASSERT(sz >= cpy_sz);
sz -= cpy_sz;
while (cpy_sz >= 8) {
cpy_sz -= 8;
@@ -676,12 +686,11 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
}
}
- ASSERT(bp->size == hp - *hpp);
+ ASSERT(bp->used_size == hp - *hpp);
*hpp = hp;
if (is_not_immed(token)) {
- ASSERT(bp->mem <= ptr_val(token));
- ASSERT(bp->mem + bp->size > ptr_val(token));
+ ASSERT(in_heapfrag(ptr_val(token), bp));
ERL_MESSAGE_TOKEN(msg) = offset_ptr(token, offs);
#ifdef HARD_DEBUG
ASSERT(dbg_thp_start <= ptr_val(ERL_MESSAGE_TOKEN(msg)));
@@ -690,8 +699,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
}
if (is_not_immed(term)) {
- ASSERT(bp->mem <= ptr_val(term));
- ASSERT(bp->mem + bp->size > ptr_val(term));
+ ASSERT(in_heapfrag(ptr_val(term),bp));
ERL_MESSAGE_TERM(msg) = offset_ptr(term, offs);
#ifdef HARD_DEBUG
ASSERT(dbg_thp_start <= ptr_val(ERL_MESSAGE_TERM(msg)));
@@ -699,10 +707,12 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
#endif
}
+copy_done:
#ifdef HARD_DEBUG
{
int i, j;
+ ErlHeapFragment* frag;
{
ProcBin *mso = off_heap->mso;
i = j = 0;
@@ -710,10 +720,12 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
mso = mso->next;
i++;
}
- mso = bp->off_heap.mso;
- while (mso) {
- mso = mso->next;
- j++;
+ for (frag=bp; frag; frag=frag->next) {
+ mso = frag->off_heap.mso;
+ while (mso) {
+ mso = mso->next;
+ j++;
+ }
}
ASSERT(i == j);
}
@@ -724,10 +736,12 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
fun = fun->next;
i++;
}
- fun = bp->off_heap.funs;
- while (fun) {
- fun = fun->next;
- j++;
+ for (frag=bp; frag; frag=frag->next) {
+ fun = frag->off_heap.funs;
+ while (fun) {
+ fun = fun->next;
+ j++;
+ }
}
ASSERT(i == j);
}
@@ -738,10 +752,12 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
external = external->next;
i++;
}
- external = bp->off_heap.externals;
- while (external) {
- external = external->next;
- j++;
+ for (frag=bp; frag; frag=frag->next) {
+ external = frag->off_heap.externals;
+ while (external) {
+ external = external->next;
+ j++;
+ }
}
ASSERT(i == j);
}
@@ -755,6 +771,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
#endif
bp->off_heap.externals = NULL;
free_message_buffer(bp);
+ msg->data.heap_frag = NULL;
#ifdef HARD_DEBUG
ASSERT(eq(ERL_MESSAGE_TERM(msg), dbg_term));
@@ -764,6 +781,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
}
+
Uint
erts_msg_attached_data_size_aux(ErlMessage *msg)
{
@@ -789,7 +807,7 @@ erts_msg_attached_data_size_aux(ErlMessage *msg)
if (is_not_nil(msg->m[1])) {
ErlHeapFragment *heap_frag;
heap_frag = erts_dist_ext_trailer(msg->data.dist_ext);
- sz += heap_frag->size;
+ sz += heap_frag->used_size;
}
return sz;
}
@@ -805,7 +823,7 @@ erts_move_msg_attached_data_to_heap(Eterm **hpp, ErlOffHeap *ohp, ErlMessage *ms
ErlHeapFragment *heap_frag;
heap_frag = erts_dist_ext_trailer(msg->data.dist_ext);
ERL_MESSAGE_TOKEN(msg) = copy_struct(ERL_MESSAGE_TOKEN(msg),
- heap_frag->size,
+ heap_frag->used_size,
hpp,
ohp);
erts_cleanup_offheap(&heap_frag->off_heap);
@@ -1062,3 +1080,4 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp,
erts_queue_message(to, to_locksp, bp, save, NIL);
}
}
+
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index 489dee7b37..f478572ac2 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -49,7 +49,7 @@ typedef struct erl_heap_fragment ErlHeapFragment;
struct erl_heap_fragment {
ErlHeapFragment* next; /* Next heap fragment */
ErlOffHeap off_heap; /* Offset heap data. */
- unsigned size; /* Size in (half)words of mem */
+ unsigned alloc_size; /* Size in (half)words of mem */
unsigned used_size; /* With terms to be moved to heap by GC */
Eterm mem[1]; /* Data */
};
@@ -199,7 +199,7 @@ do { \
#define ERTS_INIT_HEAP_FRAG(HEAP_FRAG_P, DATA_WORDS) \
do { \
(HEAP_FRAG_P)->next = NULL; \
- (HEAP_FRAG_P)->size = (DATA_WORDS); \
+ (HEAP_FRAG_P)->alloc_size = (DATA_WORDS); \
(HEAP_FRAG_P)->used_size = (DATA_WORDS); \
(HEAP_FRAG_P)->off_heap.mso = NULL; \
(HEAP_FRAG_P)->off_heap.funs = NULL; \
@@ -227,14 +227,25 @@ void erts_move_msg_attached_data_to_heap(Eterm **, ErlOffHeap *, ErlMessage *);
Eterm erts_msg_distext2heap(Process *, ErtsProcLocks *, ErlHeapFragment **,
Eterm *, ErtsDistExternal *);
+ERTS_GLB_INLINE Uint erts_msg_used_frag_sz(const ErlMessage *msg);
ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErlMessage *msg);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE Uint erts_msg_used_frag_sz(const ErlMessage *msg)
+{
+ const ErlHeapFragment *bp;
+ Uint sz = 0;
+ for (bp = msg->data.heap_frag; bp!=NULL; bp=bp->next) {
+ sz += bp->used_size;
+ }
+ return sz;
+}
+
ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErlMessage *msg)
{
ASSERT(msg->data.attached);
if (is_value(ERL_MESSAGE_TERM(msg)))
- return msg->data.heap_frag->size;
+ return erts_msg_used_frag_sz(msg);
else if (msg->data.dist_ext->heap_size < 0)
return erts_msg_attached_data_size_aux(msg);
else {
@@ -242,7 +253,7 @@ ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErlMessage *msg)
if (is_not_nil(ERL_MESSAGE_TOKEN(msg))) {
ErlHeapFragment *heap_frag;
heap_frag = erts_dist_ext_trailer(msg->data.dist_ext);
- sz += heap_frag->size;
+ sz += heap_frag->used_size;
}
return sz;
}
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 7095ae03e7..75de00d4c1 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -48,7 +48,7 @@ struct erl_module_nif {
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 */
+ Module* mod; /* Can be NULL if orphan with dtor-resources left */
};
#ifdef DEBUG
@@ -61,6 +61,10 @@ static void add_readonly_check(ErlNifEnv*, unsigned char* ptr, unsigned sz);
# define ADD_READONLY_CHECK(ENV,PTR,SIZE) ((void)0)
#endif
+#ifdef DEBUG
+static int is_offheap(const ErlOffHeap* off_heap);
+#endif
+
#define MIN_HEAP_FRAG_SZ 200
static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp);
@@ -84,7 +88,8 @@ static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp)
HEAP_TOP(env->proc) = env->hp;
}
else {
- HRelease(env->proc, env->hp_end, env->hp);
+ env->heap_frag->used_size = hp - env->heap_frag->mem;
+ ASSERT(env->heap_frag->used_size <= env->heap_frag->alloc_size);
}
frag_sz = need + MIN_HEAP_FRAG_SZ;
hp = erts_heap_alloc(env->proc, frag_sz);
@@ -143,8 +148,9 @@ void erts_post_nif(ErlNifEnv* env)
}
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);
+ ASSERT(env->hp_end - env->hp <= env->heap_frag->alloc_size);
+ env->heap_frag->used_size = env->hp - env->heap_frag->mem;
+ ASSERT(env->heap_frag->used_size <= env->heap_frag->alloc_size);
}
free_tmp_objs(env);
}
@@ -158,7 +164,7 @@ static void post_nif_noproc(ErlNifEnv* env)
/* Flush out our cached heap pointers to allow an ordinary HAlloc
*/
-static void enable_halloc(ErlNifEnv* env)
+static void flush_env(ErlNifEnv* env)
{
if (env->heap_frag == NULL) {
ASSERT(env->hp_end == HEAP_LIMIT(env->proc));
@@ -168,14 +174,15 @@ static void enable_halloc(ErlNifEnv* env)
}
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);
+ ASSERT(env->hp_end - env->hp <= env->heap_frag->alloc_size);
+ env->heap_frag->used_size = env->hp - env->heap_frag->mem;
+ ASSERT(env->heap_frag->used_size <= env->heap_frag->alloc_size);
}
}
-/* Restore cached heap pointers
+/* Restore cached heap pointers to allow alloc_heap again.
*/
-static void disable_halloc(ErlNifEnv* env)
+static void cache_env(ErlNifEnv* env)
{
if (env->heap_frag == NULL) {
ASSERT(env->hp_end == HEAP_LIMIT(env->proc));
@@ -185,34 +192,192 @@ static void disable_halloc(ErlNifEnv* env)
}
else {
ASSERT(env->hp_end != HEAP_LIMIT(env->proc));
- ASSERT(env->hp_end - env->hp <= env->heap_frag->size);
+ ASSERT(env->hp_end - env->hp <= env->heap_frag->alloc_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;
+ env->hp_end = env->heap_frag->mem + env->heap_frag->alloc_size;
}
}
-
void* enif_priv_data(ErlNifEnv* env)
{
return env->mod_nif->priv_data;
}
-void* enif_alloc(ErlNifEnv* env, size_t size)
+void* enif_alloc(size_t size)
{
return erts_alloc_fnf(ERTS_ALC_T_NIF, (Uint) size);
}
-void* enif_realloc(ErlNifEnv* env, void* ptr, size_t size)
+void* enif_realloc(void* ptr, size_t size)
{
return erts_realloc_fnf(ERTS_ALC_T_NIF, ptr, size);
}
-void enif_free(ErlNifEnv* env, void* ptr)
+void enif_free(void* ptr)
{
erts_free(ERTS_ALC_T_NIF, ptr);
}
+struct enif_msg_environment_t
+{
+ ErlNifEnv env;
+ Process phony_proc;
+};
+
+ErlNifEnv* enif_alloc_env(void)
+{
+ struct enif_msg_environment_t* msg_env =
+ erts_alloc_fnf(ERTS_ALC_T_NIF, sizeof(struct enif_msg_environment_t));
+ Eterm* phony_heap = (Eterm*) msg_env; /* dummy non-NULL ptr */
+
+ msg_env->env.hp = phony_heap;
+ msg_env->env.hp_end = phony_heap;
+ msg_env->env.heap_frag = NULL;
+ msg_env->env.mod_nif = NULL;
+ msg_env->env.tmp_obj_list = (struct enif_tmp_obj_t*) 1; /* invalid non-NULL */
+ msg_env->env.proc = &msg_env->phony_proc;
+ memset(&msg_env->phony_proc, 0, sizeof(Process));
+ HEAP_START(&msg_env->phony_proc) = phony_heap;
+ HEAP_TOP(&msg_env->phony_proc) = phony_heap;
+ HEAP_LIMIT(&msg_env->phony_proc) = phony_heap;
+ HEAP_END(&msg_env->phony_proc) = phony_heap;
+ MBUF(&msg_env->phony_proc) = NULL;
+ msg_env->phony_proc.id = ERTS_INVALID_PID;
+#ifdef FORCE_HEAP_FRAGS
+ msg_env->phony_proc.space_verified = 0;
+ msg_env->phony_proc.space_verified_from = NULL;
+#endif
+ return &msg_env->env;
+}
+void enif_free_env(ErlNifEnv* env)
+{
+ enif_clear_env(env);
+ erts_free(ERTS_ALC_T_NIF, env);
+}
+
+static ERTS_INLINE void clear_offheap(ErlOffHeap* oh)
+{
+ oh->mso = NULL;
+ oh->externals = NULL;
+ oh->funs = NULL;
+ oh->overhead = 0;
+}
+
+void enif_clear_env(ErlNifEnv* env)
+{
+ struct enif_msg_environment_t* menv = (struct enif_msg_environment_t*)env;
+ Process* p = &menv->phony_proc;
+ ASSERT(p == menv->env.proc);
+ ASSERT(p->id == ERTS_INVALID_PID);
+ ASSERT(MBUF(p) == menv->env.heap_frag);
+ if (MBUF(p) != NULL) {
+ erts_cleanup_offheap(&MSO(p));
+ clear_offheap(&MSO(p));
+ free_message_buffer(MBUF(p));
+ MBUF(p) = NULL;
+ menv->env.heap_frag = NULL;
+ }
+ ASSERT(HEAP_TOP(p) == HEAP_END(p));
+ menv->env.hp = menv->env.hp_end = HEAP_TOP(p);
+
+ ASSERT(!is_offheap(&MSO(p)));
+}
+int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
+ ErlNifEnv* msg_env, ERL_NIF_TERM msg)
+{
+ struct enif_msg_environment_t* menv = (struct enif_msg_environment_t*)msg_env;
+ ErtsProcLocks rp_locks = 0;
+ Process* rp;
+ Process* c_p;
+ ErlHeapFragment* frags;
+#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)
+ ErtsProcLocks rp_had_locks;
+#endif
+ Eterm receiver = to_pid->pid;
+ int flush_me = 0;
+
+ if (env != NULL) {
+ c_p = env->proc;
+ if (receiver == c_p->id) {
+ rp_locks = ERTS_PROC_LOCK_MAIN;
+ flush_me = 1;
+ }
+ }
+ else {
+#ifdef ERTS_SMP
+ c_p = NULL;
+#else
+ erl_exit(ERTS_ABORT_EXIT,"enif_send: env==NULL on non-SMP VM");
+#endif
+ }
+
+#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)
+ rp_had_locks = rp_locks;
+#endif
+ rp = erts_pid2proc_opt(c_p, ERTS_PROC_LOCK_MAIN,
+ receiver, rp_locks, ERTS_P2P_FLG_SMP_INC_REFC);
+ if (rp == NULL) {
+ ASSERT(env == NULL || receiver != c_p->id);
+ return 0;
+ }
+ flush_env(msg_env);
+ frags = menv->env.heap_frag;
+ ASSERT(frags == MBUF(&menv->phony_proc));
+ if (frags != NULL) {
+ /* Move all offheap's from phony proc to the first fragment.
+ Quick and dirty, but erts_move_msg_mbuf_to_heap doesn't care. */
+ ASSERT(!is_offheap(&frags->off_heap));
+ frags->off_heap = MSO(&menv->phony_proc);
+ clear_offheap(&MSO(&menv->phony_proc));
+ menv->env.heap_frag = NULL;
+ MBUF(&menv->phony_proc) = NULL;
+ }
+ ASSERT(!is_offheap(&MSO(&menv->phony_proc)));
+
+ if (flush_me) {
+ flush_env(env); /* Needed for ERTS_HOLE_CHECK */
+ }
+ erts_queue_message(rp, &rp_locks, frags, msg, am_undefined);
+ if (rp_locks) {
+ ERTS_SMP_LC_ASSERT(rp_locks == (rp_had_locks | (ERTS_PROC_LOCK_MSGQ |
+ ERTS_PROC_LOCK_STATUS)));
+ erts_smp_proc_unlock(rp, (ERTS_PROC_LOCK_MSGQ | ERTS_PROC_LOCK_STATUS));
+ }
+ erts_smp_proc_dec_refc(rp);
+ if (flush_me) {
+ cache_env(env);
+ }
+ return 1;
+}
+
+ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
+{
+ Uint sz;
+ Eterm* hp;
+ sz = size_object(src_term);
+ hp = alloc_heap(dst_env, sz);
+ return copy_struct(src_term, sz, &hp, &MSO(dst_env->proc));
+}
+
+
+#ifdef DEBUG
+static int is_offheap(const ErlOffHeap* oh)
+{
+ return oh->mso != NULL || oh->funs != NULL || oh->externals != NULL;
+}
+#endif
+
+ErlNifPid* enif_self(ErlNifEnv* caller_env, ErlNifPid* pid)
+{
+ pid->pid = caller_env->proc->id;
+ return pid;
+}
+int enif_get_local_pid(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPid* pid)
+{
+ return is_internal_pid(term) ? (pid->pid=term, 1) : 0;
+}
+
int enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term)
{
return is_atom(term);
@@ -324,7 +489,7 @@ int enif_inspect_iolist_as_binary(ErlNifEnv* env, Eterm term, ErlNifBinary* bin)
return 1;
}
-int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin)
+int enif_alloc_binary(size_t size, ErlNifBinary* bin)
{
Binary* refbin;
@@ -343,7 +508,7 @@ int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin)
return 1;
}
-int enif_realloc_binary(ErlNifEnv* env, ErlNifBinary* bin, unsigned size)
+int enif_realloc_binary(ErlNifBinary* bin, size_t size)
{
if (bin->ref_bin != NULL) {
Binary* oldbin;
@@ -361,15 +526,15 @@ int enif_realloc_binary(ErlNifEnv* env, ErlNifBinary* bin, unsigned size)
}
else {
unsigned char* old_data = bin->data;
- unsigned cpy_sz = (size < bin->size ? size : bin->size);
- enif_alloc_binary(env, size, bin);
+ size_t cpy_sz = (size < bin->size ? size : bin->size);
+ enif_alloc_binary(size, bin);
sys_memcpy(bin->data, old_data, cpy_sz);
}
return 1;
}
-void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
+void enif_release_binary(ErlNifBinary* bin)
{
if (bin->ref_bin != NULL) {
Binary* refbin = bin->ref_bin;
@@ -385,21 +550,21 @@ void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
#endif
}
-unsigned char* enif_make_new_binary(ErlNifEnv* env, unsigned size,
+unsigned char* enif_make_new_binary(ErlNifEnv* env, size_t size,
ERL_NIF_TERM* termp)
{
- enable_halloc(env);
+ flush_env(env);
*termp = new_binary(env->proc, NULL, size);
- disable_halloc(env);
+ cache_env(env);
return binary_bytes(*termp);
}
-int enif_is_identical(ErlNifEnv* env, Eterm lhs, Eterm rhs)
+int enif_is_identical(Eterm lhs, Eterm rhs)
{
return EQ(lhs,rhs);
}
-int enif_compare(ErlNifEnv* env, Eterm lhs, Eterm rhs)
+int enif_compare(Eterm lhs, Eterm rhs)
{
return cmp(lhs,rhs);
}
@@ -478,15 +643,15 @@ Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
return bin_term;
}
else {
- enable_halloc(env);
+ flush_env(env);
bin->bin_term = new_binary(env->proc, bin->data, bin->size);
- disable_halloc(env);
+ cache_env(env);
return bin->bin_term;
}
}
Eterm enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term,
- unsigned pos, unsigned size)
+ size_t pos, size_t size)
{
ErlSubBin* sb;
Eterm orig;
@@ -516,9 +681,11 @@ Eterm enif_make_badarg(ErlNifEnv* env)
BIF_ERROR(env->proc, BADARG);
}
-int enif_get_atom(ErlNifEnv* env, Eterm atom, char* buf, unsigned len)
+int enif_get_atom(ErlNifEnv* env, Eterm atom, char* buf, unsigned len,
+ ErlNifCharEncoding encoding)
{
Atom* ap;
+ ASSERT(encoding == ERL_NIF_LATIN1);
if (is_not_atom(atom)) {
return 0;
}
@@ -566,10 +733,8 @@ int enif_get_long(ErlNifEnv* env, Eterm term, long* ip)
#if SIZEOF_LONG == ERTS_SIZEOF_ETERM
return term_to_Sint(term, ip);
#elif SIZEOF_INT == ERTS_SIZEOF_ETERM
- Uint u;
- term_to_Sint(term, u);
- *ip = (long) u;
- return 1;
+ Sint i;
+ return term_to_Sint(term, &i) ? (*ip = (long) i, 1) : 0;
#else
# error Unknown long word size
#endif
@@ -581,10 +746,7 @@ int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip)
return term_to_Uint(term, ip);
#elif SIZEOF_INT == ERTS_SIZEOF_ETERM
Uint u;
- int r;
- r = term_to_Uint(term, &u);
- *ip = (unsigned long) u;
- return r;
+ return term_to_Uint(term, &u) ? (*ip = (unsigned long) u, 1) : 0;
#else
# error Unknown long word size
#endif
@@ -601,9 +763,11 @@ int enif_get_double(ErlNifEnv* env, Eterm term, double* dp)
return 1;
}
-int enif_get_atom_length(ErlNifEnv* env, Eterm atom, unsigned* len)
+int enif_get_atom_length(ErlNifEnv* env, Eterm atom, unsigned* len,
+ ErlNifCharEncoding enc)
{
Atom* ap;
+ ASSERT(enc == ERL_NIF_LATIN1);
if (is_not_atom(atom)) return 0;
ap = atom_tab(atom_val(atom));
*len = ap->len;
@@ -674,14 +838,16 @@ ERL_NIF_TERM enif_make_atom_len(ErlNifEnv* env, const char* name, size_t len)
return am_atom_put(name, len);
}
-int enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom)
+int enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom,
+ ErlNifCharEncoding enc)
{
- return enif_make_existing_atom_len(env, name, sys_strlen(name), atom);
+ return enif_make_existing_atom_len(env, name, sys_strlen(name), atom, enc);
}
int enif_make_existing_atom_len(ErlNifEnv* env, const char* name, size_t len,
- ERL_NIF_TERM* atom)
+ ERL_NIF_TERM* atom, ErlNifCharEncoding encoding)
{
+ ASSERT(encoding == ERL_NIF_LATIN1);
return erts_atom_get(name, len, atom);
}
@@ -841,7 +1007,8 @@ struct enif_resource_type_t
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];
+ Eterm module;
+ Eterm name;
};
/* dummy node in circular list */
@@ -859,14 +1026,14 @@ typedef struct enif_resource_t
#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)
+static ErlNifResourceType* find_resource_type(Eterm module, Eterm name)
{
ErlNifResourceType* type;
for (type = resource_type_list.next;
type != &resource_type_list;
type = type->next) {
- if (sys_strcmp(type->name, name) == 0) {
+ if (type->module == module && type->name == name) {
return type;
}
}
@@ -899,33 +1066,42 @@ static void steal_resource_type(ErlNifResourceType* type)
if (type->dtor != NULL
&& erts_refc_dectest(&lib->rt_dtor_cnt, 0) == 0
- && lib->is_orphan) {
+ && lib->mod == NULL) {
/* last type with destructor gone, close orphan lib */
close_lib(lib);
}
if (erts_refc_dectest(&lib->rt_cnt, 0) == 0
- && lib->is_orphan) {
+ && lib->mod == NULL) {
erts_free(ERTS_ALC_T_NIF, lib);
}
}
ErlNifResourceType*
-enif_open_resource_type(ErlNifEnv* env, const char* type_name,
- ErlNifResourceDtor* dtor,
- enum ErlNifResourceFlags flags,
- enum ErlNifResourceFlags* tried)
+enif_open_resource_type(ErlNifEnv* env,
+ const char* module_str,
+ const char* name_str,
+ ErlNifResourceDtor* dtor,
+ ErlNifResourceFlags flags,
+ ErlNifResourceFlags* tried)
{
- ErlNifResourceType* type = find_resource_type(type_name);
- enum ErlNifResourceFlags op = flags;
+ ErlNifResourceType* type = NULL;
+ ErlNifResourceFlags op = flags;
+ Eterm module_am, name_am;
+
ASSERT(erts_smp_is_system_blocked(0));
+ ASSERT(module_str == NULL); /* for now... */
+ module_am = make_atom(env->mod_nif->mod->module);
+ name_am = enif_make_atom(env, name_str);
+
+ type = find_resource_type(module_am, name_am);
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));
+ sizeof(struct enif_resource_type_t));
type->dtor = dtor;
- sys_strcpy(type->name, type_name);
+ type->module = module_am;
+ type->name = name_am;
erts_refc_init(&type->refc, 1);
type->owner = env->mod_nif;
type->prev = &resource_type_list;
@@ -973,13 +1149,13 @@ static void nif_resource_dtor(Binary* bin)
if (erts_refc_dectest(&type->refc, 0) == 0) {
ASSERT(type->next == NULL);
ASSERT(type->owner != NULL);
- ASSERT(type->owner->is_orphan);
+ ASSERT(type->owner->mod == NULL);
steal_resource_type(type);
erts_free(ERTS_ALC_T_NIF, type);
}
}
-void* enif_alloc_resource(ErlNifEnv* env, ErlNifResourceType* type, unsigned size)
+void* enif_alloc_resource(ErlNifResourceType* type, size_t size)
{
Binary* bin = erts_create_magic_binary(SIZEOF_ErlNifResource(size), &nif_resource_dtor);
ErlNifResource* resource = ERTS_MAGIC_BIN_DATA(bin);
@@ -992,7 +1168,7 @@ void* enif_alloc_resource(ErlNifEnv* env, ErlNifResourceType* type, unsigned siz
return resource->data;
}
-void enif_release_resource(ErlNifEnv* env, void* obj)
+void enif_release_resource(void* obj)
{
ErlNifResource* resource = DATA_TO_RESOURCE(obj);
ErtsBinary* bin = ERTS_MAGIC_BIN_FROM_DATA(resource);
@@ -1006,6 +1182,18 @@ void enif_release_resource(ErlNifEnv* env, void* obj)
}
}
+void enif_keep_resource(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_inc(&resource->nif_refc, 1);
+#endif
+ erts_refc_inc(&bin->binary.refc, 2);
+}
+
ERL_NIF_TERM enif_make_resource(ErlNifEnv* env, void* obj)
{
ErlNifResource* resource = DATA_TO_RESOURCE(obj);
@@ -1014,15 +1202,30 @@ ERL_NIF_TERM enif_make_resource(ErlNifEnv* env, void* obj)
return erts_mk_magic_binary_term(&hp, &MSO(env->proc), &bin->binary);
}
+ERL_NIF_TERM enif_make_resource_binary(ErlNifEnv* env, void* obj,
+ const void* data, size_t size)
+{
+ Eterm bin = enif_make_resource(env, obj);
+ ProcBin* pb = (ProcBin*) binary_val(bin);
+ pb->bytes = (byte*) data;
+ pb->size = size;
+ return bin;
+}
+
int enif_get_resource(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifResourceType* type,
void** objp)
{
+ ProcBin* pb;
Binary* mbin;
ErlNifResource* resource;
if (!ERTS_TERM_IS_MAGIC_BINARY(term)) {
return 0;
}
- mbin = ((ProcBin*) binary_val(term))->val;
+ pb = (ProcBin*) binary_val(term);
+ /*if (pb->size != 0) {
+ return 0; / * Or should we allow "resource binaries" as handles? * /
+ }*/
+ mbin = pb->val;
resource = (ErlNifResource*) ERTS_MAGIC_BIN_DATA(mbin);
if (ERTS_MAGIC_BIN_DESTRUCTOR(mbin) != &nif_resource_dtor
|| resource->type != type) {
@@ -1032,7 +1235,7 @@ int enif_get_resource(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifResourceType* typ
return 1;
}
-unsigned enif_sizeof_resource(ErlNifEnv* env, void* obj)
+size_t enif_sizeof_resource(void* obj)
{
ErlNifResource* resource = DATA_TO_RESOURCE(obj);
Binary* bin = &ERTS_MAGIC_BIN_FROM_DATA(resource)->binary;
@@ -1262,7 +1465,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
lib->entry = entry;
erts_refc_init(&lib->rt_cnt, 0);
erts_refc_init(&lib->rt_dtor_cnt, 0);
- lib->is_orphan = 0;
+ lib->mod = mod;
env.mod_nif = lib;
if (mod->nif != NULL) { /* Reload */
int k;
@@ -1376,7 +1579,7 @@ erts_unload_nif(struct erl_module_nif* lib)
ErlNifResourceType* next;
ASSERT(erts_smp_is_system_blocked(0));
ASSERT(lib != NULL);
- ASSERT(!lib->is_orphan);
+ ASSERT(lib->mod != NULL);
for (rt = resource_type_list.next;
rt != &resource_type_list;
rt = next) {
@@ -1406,7 +1609,7 @@ erts_unload_nif(struct erl_module_nif* lib)
else {
ASSERT(erts_refc_read(&lib->rt_cnt, 1) > 0);
}
- lib->is_orphan = 1;
+ lib->mod = NULL; /* orphan lib */
}
void erl_nif_init()
@@ -1415,7 +1618,8 @@ void erl_nif_init()
resource_type_list.prev = &resource_type_list;
resource_type_list.dtor = NULL;
resource_type_list.owner = NULL;
- resource_type_list.name[0] = '\0';
+ resource_type_list.module = THE_NON_VALUE;
+ resource_type_list.name = THE_NON_VALUE;
}
#ifdef READONLY_CHECK
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index a345837569..936f03bce1 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -23,14 +23,16 @@
#ifndef __ERL_NIF_H__
#define __ERL_NIF_H__
+
#include "erl_drv_nif.h"
/* Version history:
** 0.1: R13B03
** 1.0: R13B04
+** 2.0: R14A
*/
-#define ERL_NIF_MAJOR_VERSION 1
-#define ERL_NIF_MINOR_VERSION 1
+#define ERL_NIF_MAJOR_VERSION 2
+#define ERL_NIF_MINOR_VERSION 0
#include <stdlib.h>
@@ -60,6 +62,10 @@
#endif
#include "erl_int_sizes_config.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifdef HALFWORD_HEAP_EMULATOR
typedef unsigned int ERL_NIF_TERM;
#else
@@ -93,7 +99,7 @@ typedef struct enif_entry_t
typedef struct
{
- unsigned size;
+ size_t size;
unsigned char* data;
/* Internals (avert your eyes) */
@@ -103,17 +109,22 @@ typedef struct
typedef struct enif_resource_type_t ErlNifResourceType;
typedef void ErlNifResourceDtor(ErlNifEnv*, void*);
-enum ErlNifResourceFlags
+typedef enum
{
ERL_NIF_RT_CREATE = 1,
ERL_NIF_RT_TAKEOVER = 2
-};
+}ErlNifResourceFlags;
typedef enum
{
ERL_NIF_LATIN1 = 1
}ErlNifCharEncoding;
+typedef struct
+{
+ ERL_NIF_TERM pid; /* internal, may change */
+}ErlNifPid;
+
typedef ErlDrvSysInfo ErlNifSysInfo;
typedef struct ErlDrvTid_ *ErlNifTid;
@@ -146,8 +157,6 @@ extern TWinDynNifCallbacks WinDynNifCallbacks;
#endif
-
-
#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
# define ERL_NIF_INIT_GLOB TWinDynNifCallbacks WinDynNifCallbacks;
# define ERL_NIF_INIT_DECL(MODNAME) __declspec(dllexport) ErlNifEntry* nif_init(TWinDynNifCallbacks* callbacks)
@@ -163,7 +172,18 @@ extern TWinDynNifCallbacks WinDynNifCallbacks;
#endif
+#ifdef __cplusplus
+}
+# define ERL_NIF_INIT_PROLOGUE extern "C" {
+# define ERL_NIF_INIT_EPILOGUE }
+#else
+# define ERL_NIF_INIT_PROLOGUE
+# define ERL_NIF_INIT_EPILOGUE
+#endif
+
+
#define ERL_NIF_INIT(NAME, FUNCS, LOAD, RELOAD, UPGRADE, UNLOAD) \
+ERL_NIF_INIT_PROLOGUE \
ERL_NIF_INIT_GLOB \
ERL_NIF_INIT_DECL(NAME) \
{ \
@@ -178,7 +198,9 @@ ERL_NIF_INIT_DECL(NAME) \
}; \
ERL_NIF_INIT_BODY; \
return &entry; \
-}
+} \
+ERL_NIF_INIT_EPILOGUE
+
#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 44bcca9ca4..ef4e9580b0 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -23,29 +23,29 @@
#ifdef ERL_NIF_API_FUNC_DECL
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(void*,enif_alloc,(size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_free,(void* ptr));
ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_is_ref,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_inspect_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, ErlNifBinary* bin));
-ERL_NIF_API_FUNC_DECL(int,enif_alloc_binary,(ErlNifEnv*, unsigned size, ErlNifBinary* bin));
-ERL_NIF_API_FUNC_DECL(int,enif_realloc_binary,(ErlNifEnv*, ErlNifBinary* bin, unsigned size));
-ERL_NIF_API_FUNC_DECL(void,enif_release_binary,(ErlNifEnv*, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_alloc_binary,(size_t size, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_realloc_binary,(ErlNifBinary* bin, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_release_binary,(ErlNifBinary* bin));
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, 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(int,enif_is_identical,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(int,enif_compare,(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_badarg,(ErlNifEnv* env));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int,(ErlNifEnv* env, int i));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ulong,(ErlNifEnv* env, unsigned long i));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_double,(ErlNifEnv* env, double d));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_atom,(ErlNifEnv* env, const char* name));
-ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom));
+ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom, ErlNifCharEncoding));
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));
@@ -82,13 +82,13 @@ 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_realloc,(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(ERL_NIF_TERM,enif_make_sub_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, size_t pos, size_t 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_get_atom,(ErlNifEnv*, ERL_NIF_TERM atom, char* buf, unsigned len, ErlNifCharEncoding));
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));
@@ -99,20 +99,29 @@ 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(ErlNifResourceType*,enif_open_resource_type,(ErlNifEnv*, const char* module_str, const char* name_str, void (*dtor)(ErlNifEnv*,void *), ErlNifResourceFlags flags, ErlNifResourceFlags* tried));
+ERL_NIF_API_FUNC_DECL(void*,enif_alloc_resource,(ErlNifResourceType* type, size_t size));
+ERL_NIF_API_FUNC_DECL(void,enif_release_resource,(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));
-ERL_NIF_API_FUNC_DECL(unsigned char*,enif_make_new_binary,(ErlNifEnv*,unsigned size,ERL_NIF_TERM* termp));
+ERL_NIF_API_FUNC_DECL(size_t,enif_sizeof_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(unsigned char*,enif_make_new_binary,(ErlNifEnv*,size_t size,ERL_NIF_TERM* termp));
ERL_NIF_API_FUNC_DECL(int,enif_is_list,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_is_tuple,(ErlNifEnv*, ERL_NIF_TERM term));
-ERL_NIF_API_FUNC_DECL(int,enif_get_atom_length,(ErlNifEnv*, ERL_NIF_TERM atom, unsigned* len));
+ERL_NIF_API_FUNC_DECL(int,enif_get_atom_length,(ErlNifEnv*, ERL_NIF_TERM atom, unsigned* len, ErlNifCharEncoding));
ERL_NIF_API_FUNC_DECL(int,enif_get_list_length,(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_atom_len,(ErlNifEnv* env, const char* name, size_t len));
-ERL_NIF_API_FUNC_DECL(int, enif_make_existing_atom_len,(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom));
+ERL_NIF_API_FUNC_DECL(int, enif_make_existing_atom_len,(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom, ErlNifCharEncoding));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding));
+ERL_NIF_API_FUNC_DECL(ErlNifEnv*,enif_alloc_env,(void));
+ERL_NIF_API_FUNC_DECL(void,enif_free_env,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(void,enif_clear_env,(ErlNifEnv* env));
+ERL_NIF_API_FUNC_DECL(int,enif_send,(ErlNifEnv* env, const ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_copy,(ErlNifEnv* dst_env, ERL_NIF_TERM src_term));
+ERL_NIF_API_FUNC_DECL(ErlNifPid*,enif_self,(ErlNifEnv* caller_env, ErlNifPid* pid));
+ERL_NIF_API_FUNC_DECL(int,enif_get_local_pid,(ErlNifEnv* env, ERL_NIF_TERM, ErlNifPid* pid));
+ERL_NIF_API_FUNC_DECL(void,enif_keep_resource,(void* obj));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource_binary,(ErlNifEnv*,void* obj,const void* data, size_t size));
/*
** Add last to keep compatibility on Windows!!!
@@ -212,6 +221,15 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const c
# define enif_make_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_atom_len)
# define enif_make_existing_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom_len)
# define enif_make_string_len ERL_NIF_API_FUNC_MACRO(enif_make_string_len)
+# define enif_alloc_env ERL_NIF_API_FUNC_MACRO(enif_alloc_env)
+# define enif_free_env ERL_NIF_API_FUNC_MACRO(enif_free_env)
+# define enif_clear_env ERL_NIF_API_FUNC_MACRO(enif_clear_env)
+# define enif_send ERL_NIF_API_FUNC_MACRO(enif_send)
+# define enif_make_copy ERL_NIF_API_FUNC_MACRO(enif_make_copy)
+# define enif_self ERL_NIF_API_FUNC_MACRO(enif_self)
+# define enif_get_local_pid ERL_NIF_API_FUNC_MACRO(enif_get_local_pid)
+# define enif_keep_resource ERL_NIF_API_FUNC_MACRO(enif_keep_resource)
+# define enif_make_resource_binary ERL_NIF_API_FUNC_MACRO(enif_make_resource_binary)
#endif
#ifndef enif_make_list1
@@ -233,9 +251,7 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const c
# 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 */
+# define enif_make_pid(ENV, PID) ((const ERL_NIF_TERM)((PID)->pid))
#endif
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 11ca85a41c..e329bfd2d1 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -7187,8 +7187,6 @@ erts_debug_verify_clean_empty_process(Process* p)
void
erts_cleanup_empty_process(Process* p)
{
- ErlHeapFragment* mbufp;
-
/* We only check fields that are known to be used... */
erts_cleanup_offheap(&p->off_heap);
@@ -7199,13 +7197,10 @@ erts_cleanup_empty_process(Process* p)
p->off_heap.externals = NULL;
p->off_heap.overhead = 0;
- mbufp = p->mbuf;
- while (mbufp) {
- ErlHeapFragment *next = mbufp->next;
- free_message_buffer(mbufp);
- mbufp = next;
+ if (p->mbuf != NULL) {
+ free_message_buffer(p->mbuf);
+ p->mbuf = NULL;
}
- p->mbuf = NULL;
#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP)
erts_lcnt_proc_lock_destroy(p);
#endif
@@ -7221,7 +7216,6 @@ static void
delete_process(Process* p)
{
ErlMessage* mp;
- ErlHeapFragment* bp;
VERBOSE(DEBUG_PROCESSES, ("Removing process: %T\n",p->id));
@@ -7271,11 +7265,8 @@ delete_process(Process* p)
/*
* Free all pending message buffers.
*/
- bp = p->mbuf;
- while (bp != NULL) {
- ErlHeapFragment* next_bp = bp->next;
- free_message_buffer(bp);
- bp = next_bp;
+ if (p->mbuf != NULL) {
+ free_message_buffer(p->mbuf);
}
erts_erase_dicts(p);
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index cbcdec4ba7..e2cb523cf5 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -765,7 +765,7 @@ ERTS_GLB_INLINE void erts_heap_frag_shrink(Process* p, Eterm* hp)
{
ErlHeapFragment* hf = MBUF(p);
- ASSERT(hf!=NULL && (hp - hf->mem < (unsigned long)hf->size));
+ ASSERT(hf!=NULL && (hp - hf->mem < (unsigned long)hf->alloc_size));
hf->used_size = hp - hf->mem;
}
diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h
index eeeeb7ccfd..cd63401581 100644
--- a/erts/emulator/beam/erl_vm.h
+++ b/erts/emulator/beam/erl_vm.h
@@ -84,6 +84,7 @@
#define ErtsHAllocLockCheck(P) \
ERTS_SMP_LC_ASSERT((ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks((P))) \
+ || ((P)->id == ERTS_INVALID_PID) \
|| ((P)->scheduler_data \
&& (P) == (P)->scheduler_data->match_pseudo_process) \
|| erts_is_system_blocked(0))
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index d5d63631ff..19dd3d6f97 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -881,6 +881,8 @@ Eterm copy_object(Eterm, Process*);
Uint size_object(Eterm);
Eterm copy_struct(Eterm, Uint, Eterm**, ErlOffHeap*);
Eterm copy_shallow(Eterm*, Uint, Eterm**, ErlOffHeap*);
+void move_multi_frags(Eterm** hpp, ErlOffHeap*, ErlHeapFragment* first,
+ Eterm* refs, unsigned nrefs);
#ifdef HYBRID
#define RRMA_DEFAULT_SIZE 256
@@ -1078,6 +1080,7 @@ Eterm erts_heap_sizes(Process* p);
void erts_offset_off_heap(ErlOffHeap *, Sint, Eterm*, Eterm*);
void erts_offset_heap_ptr(Eterm*, Uint, Sint, Eterm*, Eterm*);
void erts_offset_heap(Eterm*, Uint, Sint, Eterm*, Eterm*);
+void erts_free_heap_frags(Process* p);
#ifdef HYBRID
int erts_global_garbage_collect(Process*, int, Eterm*, int);
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 51c12a0b69..445a8eebd9 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -32,6 +32,7 @@
#include "erl_binary.h"
#include "erl_bits.h"
#include "packet_parser.h"
+#include "erl_gc.h"
#define ERTS_WANT_DB_INTERNAL__
#include "erl_db.h"
#include "erl_threads.h"
@@ -125,7 +126,7 @@ erts_heap_alloc(Process* p, Uint need)
n = need;
bp = MBUF(p);
- if (bp != NULL && need <= (bp->size - bp->used_size)) {
+ if (bp != NULL && need <= (bp->alloc_size - bp->used_size)) {
Eterm* ret = bp->mem + bp->used_size;
bp->used_size += need;
return ret;
@@ -158,7 +159,7 @@ erts_heap_alloc(Process* p, Uint need)
bp->next = MBUF(p);
MBUF(p) = bp;
- bp->size = n;
+ bp->alloc_size = n;
bp->used_size = n;
MBUF_SIZE(p) += n;
bp->off_heap.mso = NULL;
diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c
index e57e293547..6c9e1d9ba7 100644
--- a/erts/emulator/hipe/hipe_gc.c
+++ b/erts/emulator/hipe/hipe_gc.c
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2004-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%
*/
/* $Id$
@@ -86,7 +86,7 @@ Eterm *fullsweep_nstack(Process *p, Eterm *n_htop)
if (is_boxed(gval)) {
Eterm *ptr = boxed_val(gval);
Eterm val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*nsp_i = val;
} else if (in_area(ptr, src, src_size) ||
@@ -96,7 +96,7 @@ Eterm *fullsweep_nstack(Process *p, Eterm *n_htop)
} else if (is_list(gval)) {
Eterm *ptr = list_val(gval);
Eterm val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
*nsp_i = ptr[1];
} else if (in_area(ptr, src, src_size) ||
in_area(ptr, oh, oh_size)) {
@@ -193,7 +193,7 @@ void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop)
if (is_boxed(gval)) {
Eterm *ptr = boxed_val(gval);
Eterm val = *ptr;
- if (IS_MOVED(val)) {
+ if (IS_MOVED_BOXED(val)) {
ASSERT(is_boxed(val));
*nsp_i = val;
} else if (in_area(ptr, heap, mature_size)) {
@@ -205,7 +205,7 @@ void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop)
} else if (is_list(gval)) {
Eterm *ptr = list_val(gval);
Eterm val = *ptr;
- if (is_non_value(val)) {
+ if (IS_MOVED_CONS(val)) {
*nsp_i = ptr[1];
} else if (in_area(ptr, heap, mature_size)) {
MOVE_CONS(ptr, val, old_htop, nsp_i);
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 161e38c68a..a1f61dad67 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -20,24 +20,39 @@
-module(nif_SUITE).
%%-define(line_trace,true).
-%%-define(CHECK(Exp,Got), ?line check(Exp,Got,?LINE)).
--define(CHECK(Exp,Got), ?line Exp = Got).
+-define(CHECK(Exp,Got), check(Exp,Got,?LINE)).
+%%-define(CHECK(Exp,Got), ?line Exp = Got).
-include("test_server.hrl").
--export([all/1, fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1,
+-export([all/1,
+ %%init_per_testcase/2,
+ fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1,
types/1, many_args/1, binaries/1, get_string/1, get_atom/1, api_macros/1,
- from_array/1, iolist_as_binary/1, resource/1, resource_takeover/1,
- threading/1, neg/1, is_checks/1, get_length/1, make_atom/1, make_string/1]).
+ from_array/1, iolist_as_binary/1, resource/1, resource_binary/1, resource_takeover/1,
+ threading/1, send/1, send2/1, send_threaded/1, neg/1, is_checks/1,
+ get_length/1, make_atom/1, make_string/1]).
-export([many_args_100/100]).
+
+
+%% -export([lib_version/0,call_history/0,hold_nif_mod_priv_data/1,nif_mod_call_history/0,
+%% list_seq/1,type_test/0,tuple_2_list/1,is_identical/2,compare/2,
+%% clone_bin/1,make_sub_bin/3,string_to_bin/2,atom_to_bin/2,macros/1,
+%% tuple_2_list_and_tuple/1,iolist_2_bin/1,get_resource_type/1,alloc_resource/2,
+%% make_resource/1,get_resource/2,release_resource/1,last_resource_dtor_call/0,
+%% make_new_resource/2,make_new_resource_binary/1,send_list_seq/2,send_new_blob/2,
+%% alloc_msgenv/0,clear_msgenv/1,grow_blob/2,send_blob/2,send_blob_thread/3,
+%% join_send_thread/1]).
+
+
-define(nif_stub,nif_stub_error(?LINE)).
all(suite) ->
[basic, reload, upgrade, heap_frag, types, many_args, binaries, get_string,
- get_atom, api_macros, from_array, iolist_as_binary, resource,
- resource_takeover, threading, neg, is_checks, get_length, make_atom,
- make_string].
+ get_atom, api_macros, from_array, iolist_as_binary, resource, resource_binary,
+ resource_takeover, threading, send, send2, send_threaded, neg, is_checks,
+ get_length, make_atom, make_string].
%%init_per_testcase(_Case, Config) ->
%% ?line Dog = ?t:timetrap(?t:seconds(60*60*24)),
@@ -474,12 +489,51 @@ resource_new_do2(Type) ->
{{PtrA,BinA}, {ResB,PtrB,BinB}}.
resource_neg(TypeA) ->
+ resource_neg_do(TypeA),
+
+ catch exit(42), % dummy exception to purge saved stacktraces from earlier exception
+ erlang:garbage_collect(),
+ ?line {_,_,2} = last_resource_dtor_call(),
+ ok.
+
+resource_neg_do(TypeA) ->
TypeB = get_resource_type(1),
- Aptr = alloc_resource(TypeA, <<"Arnold">>),
- Bptr = alloc_resource(TypeB, <<"Bobo">>),
- ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeA, Bptr)),
- ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeB, Aptr)),
+ ResA = make_new_resource(TypeA, <<"Arnold">>),
+ ResB= make_new_resource(TypeB, <<"Bobo">>),
+ ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeA, ResB)),
+ ?line {'EXIT',{badarg,_}} = (catch get_resource(TypeB, ResA)),
+ ok.
+
+resource_binary(doc) -> ["Test enif_make_resource_binary"];
+resource_binary(suite) -> [];
+resource_binary(Config) when is_list(Config) ->
+ ?line ensure_lib_loaded(Config, 1),
+ ?line {Ptr,Bin} = resource_binary_do(),
+ erlang:garbage_collect(),
+ Last = last_resource_dtor_call(),
+ ?CHECK({Ptr,Bin,1}, Last),
ok.
+
+resource_binary_do() ->
+ Bin = <<"Hej Hopp i lingonskogen">>,
+ ?line {Ptr,ResBin1} = make_new_resource_binary(Bin),
+ ?line ResBin1 = Bin,
+ ?line ResInfo = {Ptr,_} = get_resource(binary_resource_type,ResBin1),
+
+ Papa = self(),
+ Forwarder = spawn_link(fun() -> forwarder(Papa) end),
+ io:format("sending to forwarder pid=~p\n",[Forwarder]),
+ Forwarder ! ResBin1,
+ ResBin2 = receive_any(),
+ ?line ResBin2 = ResBin1,
+ ?line ResInfo = get_resource(binary_resource_type,ResBin2),
+ Forwarder ! terminate,
+ ?line {Forwarder, 1} = receive_any(),
+ erlang:garbage_collect(),
+ ?line ResInfo = get_resource(binary_resource_type,ResBin1),
+ ?line ResInfo = get_resource(binary_resource_type,ResBin2),
+ ResInfo.
+
-define(RT_CREATE,1).
-define(RT_TAKEOVER,2).
@@ -744,6 +798,124 @@ threading(Config) when is_list(Config) ->
?line ok = tester:load_nif_lib(Config, "tsd"),
?line ok = tester:run().
+
+send(doc) -> ["Test NIF message sending"];
+send(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+
+ N = 1500,
+ List = lists:seq(1,N),
+ ?line {ok,1} = send_list_seq(N, self),
+ ?line {ok,1} = send_list_seq(N, self()),
+ ?line List = receive_any(),
+ ?line List = receive_any(),
+ Papa = self(),
+ spawn_link(fun() -> ?line {ok,1} = send_list_seq(N, Papa) end),
+ ?line List = receive_any(),
+
+ ?line {ok, 1, BlobS} = send_new_blob(self(), other_term()),
+ ?line BlobR = receive_any(),
+ io:format("Sent ~p\nGot ~p\n", [BlobS, BlobR]),
+ ?line BlobR = BlobS,
+
+ %% send to dead pid
+ {DeadPid, DeadMon} = spawn_monitor(fun() -> void end),
+ ?line {'DOWN', DeadMon, process, DeadPid, normal} = receive_any(),
+ {ok,0} = send_list_seq(7, DeadPid),
+ ok.
+
+send2(doc) -> ["More NIF message sending"];
+send2(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+
+ send2_do1(fun send_blob_dbg/2),
+ ok.
+
+send_threaded(doc) -> ["Send msg from user thread"];
+send_threaded(Config) when is_list(Config) ->
+ case erlang:system_info(smp_support) of
+ true ->
+ send2_do1(fun(ME,To) -> send_blob_thread_dbg(ME,To,join) end),
+ send2_do1(fun(ME,To) -> send_blob_thread_and_join(ME,To) end),
+ ok;
+ false ->
+ {skipped,"No threaded send on non-SMP"}
+ end.
+
+
+send2_do1(SendBlobF) ->
+ io:format("sending to self=~p\n",[self()]),
+ send2_do2(SendBlobF, self()),
+
+ Papa = self(),
+ Forwarder = spawn_link(fun() -> forwarder(Papa) end),
+ io:format("sending to forwarder pid=~p\n",[Forwarder]),
+ send2_do2(SendBlobF, Forwarder),
+ Forwarder ! terminate,
+ ?line {Forwarder, 4} = receive_any(),
+ ok.
+
+send2_do2(SendBlobF, To) ->
+ MsgEnv = alloc_msgenv(),
+ repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []),
+ ?line {ok,1,Blob0} = SendBlobF(MsgEnv, To),
+ ?line Blob1 = receive_any(),
+ ?line Blob1 = Blob0,
+
+ clear_msgenv(MsgEnv),
+ repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []),
+ ?line {ok,1,Blob2} = SendBlobF(MsgEnv, To),
+ ?line Blob3 = receive_any(),
+ ?line Blob3 = Blob2,
+
+ clear_msgenv(MsgEnv),
+ repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []),
+
+ clear_msgenv(MsgEnv),
+ repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []),
+ ?line {ok,1,Blob4} = SendBlobF(MsgEnv, To),
+ ?line Blob5 = receive_any(),
+ ?line Blob5 = Blob4,
+
+ clear_msgenv(MsgEnv),
+ clear_msgenv(MsgEnv),
+ repeat(50, fun(_) -> grow_blob(MsgEnv,other_term()) end, []),
+ ?line {ok,1,Blob6} = SendBlobF(MsgEnv, To),
+ ?line Blob7 = receive_any(),
+ ?line Blob7 = Blob6,
+
+ ok.
+
+
+send_blob_thread_and_join(MsgEnv, To) ->
+ ?line {ok,Blob} = send_blob_thread_dbg(MsgEnv, To, no_join),
+ ?line {ok,SendRes} = join_send_thread(MsgEnv),
+ {ok,SendRes,Blob}.
+
+send_blob_dbg(MsgEnv, To) ->
+ Ret = send_blob(MsgEnv, To),
+ %%io:format("send_blob to ~p returned ~p\n",[To,Ret]),
+ Ret.
+
+send_blob_thread_dbg(MsgEnv, To, Join) ->
+ Ret = send_blob_thread(MsgEnv, To, Join),
+ %%io:format("send_blob_thread to ~p Join=~p returned ~p\n",[To,Join,Ret]),
+ Ret.
+
+
+forwarder(To) ->
+ forwarder(To, 0).
+forwarder(To, N) ->
+ case receive_any() of
+ terminate ->
+ To ! {self(), N};
+ Msg ->
+ To ! Msg,
+ forwarder(To, N+1)
+ end.
+
+other_term() ->
+ {fun(X,Y) -> X*Y end, make_ref()}.
neg(doc) -> ["Negative testing of load_nif"];
neg(Config) when is_list(Config) ->
@@ -848,13 +1020,18 @@ call(Pid,Cmd) ->
receive_any() ->
receive M -> M end.
-%% check(Exp,Got,Line) ->
-%% case Got of
-%% Exp -> Exp;
-%% _ ->
-%% io:format("CHECK at ~p: Expected ~p but got ~p\n",[Line,Exp,Got]),
-%% Got
-%% end.
+repeat(0, _, Arg) ->
+ Arg;
+repeat(N, Fun, Arg0) ->
+ repeat(N-1, Fun, Fun(Arg0)).
+
+check(Exp,Got,Line) ->
+ case Got of
+ Exp -> Exp;
+ _ ->
+ io:format("CHECK at ~p: Expected ~p but got ~p\n",[Line,Exp,Got]),
+ Got
+ end.
%% The NIFs:
@@ -886,6 +1063,16 @@ check_is(_,_,_,_,_,_,_,_,_,_) -> ?nif_stub.
length_test(_,_,_,_,_) -> ?nif_stub.
make_atoms() -> ?nif_stub.
make_strings() -> ?nif_stub.
+make_new_resource_binary(_) -> ?nif_stub.
+send_list_seq(_,_) -> ?nif_stub.
+send_new_blob(_,_) -> ?nif_stub.
+alloc_msgenv() -> ?nif_stub.
+clear_msgenv(_) -> ?nif_stub.
+grow_blob(_,_) -> ?nif_stub.
+send_blob(_,_) -> ?nif_stub.
+send_blob_thread(_,_,_) -> ?nif_stub.
+join_send_thread(_) -> ?nif_stub.
+
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 73226a09cb..bacf7845e2 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -28,6 +28,12 @@
static int static_cntA; /* zero by default */
static int static_cntB = NIF_SUITE_LIB_VER * 100;
+static ERL_NIF_TERM atom_self;
+static ERL_NIF_TERM atom_ok;
+static ERL_NIF_TERM atom_join;
+static ERL_NIF_TERM atom_binary_resource_type;
+
+
typedef struct
{
int ref_cnt;
@@ -38,7 +44,7 @@ typedef struct
void add_call(ErlNifEnv* env, PrivData* data, const char* func_name)
{
- CallInfo* call = enif_alloc(env, sizeof(CallInfo)+strlen(func_name));
+ CallInfo* call = enif_alloc(sizeof(CallInfo)+strlen(func_name));
strcpy(call->func_name, func_name);
call->lib_ver = NIF_SUITE_LIB_VER;
call->next = data->call_history;
@@ -49,7 +55,7 @@ void add_call(ErlNifEnv* env, PrivData* data, const char* func_name)
call->arg_sz = 0;
}
-#define ADD_CALL(FUNC_NAME) add_call(env, enif_get_data(env),FUNC_NAME)
+#define ADD_CALL(FUNC_NAME) add_call(env, enif_priv_data(env),FUNC_NAME)
static void* resource_dtor_last = NULL;
static unsigned resource_dtor_last_sz = 0;
@@ -60,15 +66,24 @@ static void resource_dtor(ErlNifEnv* env, void* obj)
{
resource_dtor_last = obj;
resource_dtor_cnt++;
- resource_dtor_last_sz = enif_sizeof_resource(env, obj);
+ resource_dtor_last_sz = enif_sizeof_resource(obj);
assert(resource_dtor_last_sz <= sizeof(resource_dtor_last_data));
memcpy(resource_dtor_last_data, obj, resource_dtor_last_sz);
}
+static ErlNifResourceType* msgenv_resource_type;
+static void msgenv_dtor(ErlNifEnv* env, void* obj);
+
+static ErlNifResourceType* binary_resource_type;
+static void binary_resource_dtor(ErlNifEnv* env, void* obj);
+struct binary_resource {
+ unsigned char* data;
+ unsigned size;
+};
+
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
- /*ERL_NIF_TERM head, tail;*/
- PrivData* data = enif_alloc(env, sizeof(PrivData));
+ PrivData* data = enif_alloc(sizeof(PrivData));
assert(data != NULL);
data->ref_cnt = 1;
data->call_history = NULL;
@@ -76,41 +91,71 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
add_call(env, data, "load");
- /*
- head = load_info;
- data->rt_cnt = 0;
- for (head=load_info; enif_get_list_cell(env,load_info,&head,&tail);
- head=tail) {
- char buf[20];
- int n = enif_get_string(env,head,buf,sizeof(buf));
- assert(n > 0);
- assert(i < sizeof(data->rt_arr)/sizeof(*data->rt_arr));
- data->rt_arr[data->rt_cnt++].t = enif_create_resource_type(env,buf,resource_dtor,
- ERL_NIF_RT_CREATE,NULL);
- }
- assert(enif_is_empty_list(env,head));
- */
- data->rt_arr[0].t = enif_open_resource_type(env,"Gold",resource_dtor,
+ data->rt_arr[0].t = enif_open_resource_type(env,NULL,"Gold",resource_dtor,
ERL_NIF_RT_CREATE,NULL);
- data->rt_arr[1].t = enif_open_resource_type(env,"Silver",resource_dtor,
+ data->rt_arr[1].t = enif_open_resource_type(env,NULL,"Silver",resource_dtor,
ERL_NIF_RT_CREATE,NULL);
+ binary_resource_type = enif_open_resource_type(env,NULL,"nif_SUITE.binary",
+ binary_resource_dtor,
+ ERL_NIF_RT_CREATE, NULL);
+
+ msgenv_resource_type = enif_open_resource_type(env,NULL,"nif_SUITE.msgenv",
+ msgenv_dtor,
+ ERL_NIF_RT_CREATE, NULL);
+
+ atom_self = enif_make_atom(env,"self");
+ atom_ok = enif_make_atom(env,"ok");
+ atom_join = enif_make_atom(env,"join");
+ atom_binary_resource_type = enif_make_atom(env,"binary_resource_type");
+
*priv_data = data;
return 0;
}
+static void resource_takeover(ErlNifEnv* env, PrivData* priv)
+{
+ ErlNifResourceFlags tried;
+ ErlNifResourceType* rt;
+ rt = enif_open_resource_type(env, NULL, "Gold", resource_dtor,
+ ERL_NIF_RT_TAKEOVER, &tried);
+ assert(rt == priv->rt_arr[0].t);
+ assert(tried == ERL_NIF_RT_TAKEOVER);
+ rt = enif_open_resource_type(env, NULL, "Silver", resource_dtor,
+ ERL_NIF_RT_TAKEOVER, &tried);
+ assert(rt == priv->rt_arr[1].t);
+ assert(tried == ERL_NIF_RT_TAKEOVER);
+
+ rt = enif_open_resource_type(env, NULL, "nif_SUITE.binary", binary_resource_dtor,
+ ERL_NIF_RT_TAKEOVER, &tried);
+ assert(rt != NULL);
+ assert(tried == ERL_NIF_RT_TAKEOVER);
+ assert(binary_resource_type==NULL || binary_resource_type == rt);
+ binary_resource_type = rt;
+
+ rt = enif_open_resource_type(env, NULL, "nif_SUITE.msgenv", msgenv_dtor,
+ ERL_NIF_RT_TAKEOVER, &tried);
+ assert(rt != NULL);
+ assert(tried == ERL_NIF_RT_TAKEOVER);
+ assert(msgenv_resource_type==NULL || msgenv_resource_type == rt);
+ msgenv_resource_type = rt;
+}
+
static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
- add_call(env, *priv_data, "reload");
+ PrivData* priv = (PrivData*) *priv_data;
+ add_call(env, priv, "reload");
+ resource_takeover(env,priv);
return 0;
}
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
{
- PrivData* data = *old_priv_data;
- add_call(env, data, "upgrade");
- data->ref_cnt++;
- *priv_data = *old_priv_data;
+ PrivData* priv = (PrivData*) *old_priv_data;
+ add_call(env, priv, "upgrade");
+ priv->ref_cnt++;
+ *priv_data = *old_priv_data;
+ resource_takeover(env,priv);
return 0;
}
@@ -119,7 +164,10 @@ static void unload(ErlNifEnv* env, void* priv_data)
PrivData* data = priv_data;
add_call(env, data, "unload");
if (--data->ref_cnt == 0) {
- enif_free(env, priv_data);
+ if (data->nif_mod != NULL) {
+ NifModPrivData_release(data->nif_mod);
+ }
+ enif_free(priv_data);
}
}
@@ -149,28 +197,28 @@ static ERL_NIF_TERM make_call_history(ErlNifEnv* env, CallInfo** headp)
enif_make_int(env,call->static_cntB));
list = enif_make_list_cell(env, tpl, list);
*headp = call->next;
- enif_free(env,call);
+ enif_free(call);
}
return list;
}
static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- PrivData* data = (PrivData*) enif_get_data(env);
+ PrivData* data = (PrivData*) enif_priv_data(env);
return make_call_history(env,&data->call_history);
}
static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- PrivData* data = (PrivData*) enif_get_data(env);
+ PrivData* data = (PrivData*) enif_priv_data(env);
unsigned long ptr_as_ulong;
if (!enif_get_ulong(env,argv[0],&ptr_as_ulong)) {
return enif_make_badarg(env);
}
- if (data->nif_mod != NULL && --(data->nif_mod->ref_cnt) == 0) {
- enif_free(env,data->nif_mod);
+ if (data->nif_mod != NULL) {
+ NifModPrivData_release(data->nif_mod);
}
data->nif_mod = (NifModPrivData*) ptr_as_ulong;
return enif_make_int(env,++(data->nif_mod->ref_cnt));
@@ -178,7 +226,7 @@ static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_N
static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- PrivData* data = (PrivData*) enif_get_data(env);
+ PrivData* data = (PrivData*) enif_priv_data(env);
ERL_NIF_TERM ret;
if (data->nif_mod == NULL) {
return enif_make_string(env,"nif_mod pointer is NULL", ERL_NIF_LATIN1);
@@ -354,13 +402,13 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
}
}
- if (!enif_make_existing_atom(env,"nif_SUITE", &atom)
- || !enif_is_identical(env,atom,enif_make_atom(env,"nif_SUITE"))) {
+ if (!enif_make_existing_atom(env,"nif_SUITE", &atom, ERL_NIF_LATIN1)
+ || !enif_is_identical(atom,enif_make_atom(env,"nif_SUITE"))) {
fprintf(stderr, "nif_SUITE not an atom?\r\n");
goto error;
}
for (i=2; i; i--) {
- if (enif_make_existing_atom(env,"nif_SUITE_pink_unicorn", &atom)) {
+ if (enif_make_existing_atom(env,"nif_SUITE_pink_unicorn", &atom, ERL_NIF_LATIN1)) {
fprintf(stderr, "pink unicorn exist?\r\n");
goto error;
}
@@ -368,7 +416,7 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ref1 = enif_make_ref(env);
ref2 = enif_make_ref(env);
if (!enif_is_ref(env,ref1) || !enif_is_ref(env,ref2)
- || enif_is_identical(env,ref1,ref2) || enif_compare(env,ref1,ref2)==0) {
+ || enif_is_identical(ref1,ref2) || enif_compare(ref1,ref2)==0) {
fprintf(stderr, "strange refs?\r\n");
goto error;
}
@@ -398,7 +446,7 @@ static ERL_NIF_TERM is_identical(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
if (argc != 2) {
return enif_make_badarg(env);
}
- return enif_make_atom(env, (enif_is_identical(env,argv[0],argv[1]) ?
+ return enif_make_atom(env, (enif_is_identical(argv[0],argv[1]) ?
"true" : "false"));
}
@@ -407,7 +455,7 @@ static ERL_NIF_TERM compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if (argc != 2) {
return enif_make_badarg(env);
}
- return enif_make_int(env, enif_compare(env,argv[0],argv[1]));
+ return enif_make_int(env, enif_compare(argv[0],argv[1]));
}
static ERL_NIF_TERM many_args_100(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -454,7 +502,7 @@ static ERL_NIF_TERM string_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
unsigned size;
int n;
if (!enif_get_int(env,argv[1],(int*)&size)
- || !enif_alloc_binary(env,size,&obin)) {
+ || !enif_alloc_binary(size,&obin)) {
return enif_make_badarg(env);
}
n = enif_get_string(env, argv[0], (char*)obin.data, size, ERL_NIF_LATIN1);
@@ -468,10 +516,10 @@ static ERL_NIF_TERM atom_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
unsigned size;
int n;
if (!enif_get_int(env,argv[1],(int*)&size)
- || !enif_alloc_binary(env,size,&obin)) {
+ || !enif_alloc_binary(size,&obin)) {
return enif_make_badarg(env);
}
- n = enif_get_atom(env, argv[0], (char*)obin.data, size);
+ n = enif_get_atom(env, argv[0], (char*)obin.data, size, ERL_NIF_LATIN1);
return enif_make_tuple(env, 2, enif_make_int(env,n),
enif_make_binary(env,&obin));
}
@@ -552,7 +600,7 @@ static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_
static ERL_NIF_TERM get_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- PrivData* data = (PrivData*) enif_get_data(env);
+ PrivData* data = (PrivData*) enif_priv_data(env);
int ix;
if (!enif_get_int(env, argv[0], &ix) || ix >= 2) {
@@ -568,7 +616,7 @@ static ERL_NIF_TERM alloc_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM
union { void* p; long l;} data;
if (!enif_get_long(env, argv[0], &type.l)
|| !enif_inspect_binary(env, argv[1], &data_bin)
- || (data.p = enif_alloc_resource(env, type.t, data_bin.size))==NULL) {
+ || (data.p = enif_alloc_resource(type.t, data_bin.size))==NULL) {
return enif_make_badarg(env);
}
@@ -593,28 +641,65 @@ static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TE
ERL_NIF_TERM ret;
if (!enif_get_long(env, argv[0], &type.l)
|| !enif_inspect_binary(env, argv[1], &data_bin)
- || (data = enif_alloc_resource(env, type.t, data_bin.size))==NULL) {
+ || (data = enif_alloc_resource(type.t, data_bin.size))==NULL) {
return enif_make_badarg(env);
}
ret = enif_make_resource(env, data);
memcpy(data, data_bin.data, data_bin.size);
- enif_release_resource(env, data);
+ enif_release_resource(data);
return ret;
}
+static ERL_NIF_TERM make_new_resource_binary(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary data_bin;
+ union { struct binary_resource* p; void* vp; long l;} br;
+ void* buf;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &data_bin)
+ || (br.vp = enif_alloc_resource(binary_resource_type,
+ sizeof(struct binary_resource)))==NULL
+ || (buf = enif_alloc(data_bin.size)) == NULL) {
+
+ return enif_make_badarg(env);
+ }
+ memset(br.vp,0xba,sizeof(struct binary_resource)); /* avoid valgrind warning */
+ br.p->data = buf;
+ br.p->size = data_bin.size;
+ memcpy(br.p->data, data_bin.data, data_bin.size);
+ ret = enif_make_resource_binary(env, br.vp, br.p->data, br.p->size);
+ enif_release_resource(br.p);
+ return enif_make_tuple2(env, enif_make_long(env,br.l), ret);
+}
+
+static void binary_resource_dtor(ErlNifEnv* env, void* obj)
+{
+ struct binary_resource* br = (struct binary_resource*) obj;
+ resource_dtor(env,obj);
+ assert(br->data != NULL);
+ enif_free(br->data);
+ br->data = NULL;
+}
+
static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
union { ErlNifResourceType* t; long l; } type;
union { void* p; long l; } data;
- if (!enif_get_long(env, argv[0], &type.l)
+ type.t = NULL;
+ if (enif_is_identical(argv[0], atom_binary_resource_type)) {
+ type.t = binary_resource_type;
+ }
+ else {
+ enif_get_long(env, argv[0], &type.l);
+ }
+ if (type.t == NULL
|| !enif_get_resource(env, argv[1], type.t, &data.p)) {
return enif_make_badarg(env);
}
-
- enif_alloc_binary(env, enif_sizeof_resource(env,data.p), &data_bin);
+ enif_alloc_binary(enif_sizeof_resource(data.p), &data_bin);
memcpy(data_bin.data, data.p, data_bin.size);
return enif_make_tuple2(env, enif_make_long(env,data.l),
enif_make_binary(env, &data_bin));
@@ -626,7 +711,7 @@ static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TER
if (!enif_get_long(env, argv[0], &data.l)) {
return enif_make_badarg(env);
}
- enif_release_resource(env, data.p);
+ enif_release_resource(data.p);
return enif_make_atom(env,"ok");
}
@@ -649,7 +734,7 @@ static ERL_NIF_TERM check_is(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env);
if (!enif_is_binary(env, argv[1])) return enif_make_badarg(env);
if (!enif_is_ref(env, argv[2])) return enif_make_badarg(env);
- if (!enif_is_identical(env, argv[3], ok_atom)) return enif_make_badarg(env);
+ if (!enif_is_identical(argv[3], ok_atom)) return enif_make_badarg(env);
if (!enif_is_fun(env, argv[4])) return enif_make_badarg(env);
if (!enif_is_pid(env, argv[5])) return enif_make_badarg(env);
if (!enif_is_port(env, argv[6])) return enif_make_badarg(env);
@@ -672,7 +757,7 @@ static ERL_NIF_TERM length_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
{
unsigned len;
- if (!enif_get_atom_length(env, argv[0], &len) || len != 6)
+ if (!enif_get_atom_length(env, argv[0], &len, ERL_NIF_LATIN1) || len != 6)
return enif_make_badarg(env);
if (!enif_get_list_length(env, argv[1], &len) || len != 6)
@@ -681,7 +766,7 @@ static ERL_NIF_TERM length_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
if (!enif_get_list_length(env, argv[2], &len) || len != 0)
return enif_make_badarg(env);
- if (enif_get_atom_length(env, argv[3], &len))
+ if (enif_get_atom_length(env, argv[3], &len, ERL_NIF_LATIN1))
return enif_make_badarg(env);
if (enif_get_list_length(env, argv[4], &len))
@@ -703,15 +788,15 @@ static ERL_NIF_TERM make_atoms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
arr[2] = enif_make_atom_len(env, an0atom, 7);
arr[3] = enif_make_atom_len(env, an0atom0, 8);
- if (!enif_make_existing_atom(env, "an0atom", &existingatom0a))
+ if (!enif_make_existing_atom(env, "an0atom", &existingatom0a, ERL_NIF_LATIN1))
return enif_make_atom(env, "error");
arr[4] = existingatom0a;
- if (!enif_make_existing_atom_len(env, an0atom, 7, &existingatom0b))
+ if (!enif_make_existing_atom_len(env, an0atom, 7, &existingatom0b, ERL_NIF_LATIN1))
return enif_make_atom(env, "error");
arr[5] = existingatom0b;
- if (!enif_make_existing_atom_len(env, an0atom0, 8, &existing0atom0))
+ if (!enif_make_existing_atom_len(env, an0atom0, 8, &existing0atom0, ERL_NIF_LATIN1))
return enif_make_atom(env, "error");
arr[6] = existing0atom0;
@@ -730,6 +815,442 @@ static ERL_NIF_TERM make_strings(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
enif_make_string_len(env, a0string, 8, ERL_NIF_LATIN1),
enif_make_string_len(env, a0string0, 9, ERL_NIF_LATIN1));
}
+static ERL_NIF_TERM send_list_seq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid to;
+ ERL_NIF_TERM msg;
+ ErlNifEnv* msg_env;
+ int i, res;
+
+ if (!enif_get_int(env, argv[0], &i)) {
+ return enif_make_badarg(env);
+ }
+ if (argv[1] == atom_self) {
+ enif_self(env, &to);
+ }
+ else if (!enif_get_local_pid(env, argv[1], &to)) {
+ return enif_make_badarg(env);
+ }
+ msg_env = enif_alloc_env();
+ msg = enif_make_list(msg_env,0);
+ for ( ; i>0 ; i--) {
+ msg = enif_make_list_cell(msg_env, enif_make_int(msg_env, i), msg);
+ }
+ res = enif_send(env, &to, msg_env, msg);
+ enif_free_env(msg_env);
+ return enif_make_tuple2(env, atom_ok, enif_make_int(env,res));
+}
+
+static void fill(void* dst, unsigned bytes, int seed)
+{
+ unsigned char* ptr = dst;
+ int i;
+ for (i=bytes; i>0; i--) {
+ *ptr++ = seed;
+ seed += 7;
+ }
+}
+
+#define MAKE_TERM_REUSE_LEN 16
+struct make_term_info
+{
+ ErlNifEnv* caller_env;
+ ErlNifEnv* dst_env;
+ ERL_NIF_TERM reuse[MAKE_TERM_REUSE_LEN];
+ unsigned reuse_push;
+ unsigned reuse_pull;
+ ErlNifResourceType* resource_type;
+ ERL_NIF_TERM other_term;
+ ERL_NIF_TERM blob;
+ ErlNifPid to_pid;
+ ErlNifTid tid;
+ ErlNifCond* cond;
+ ErlNifMutex* mtx;
+ int send_it;
+ int send_res;
+ unsigned n;
+};
+
+
+static void push_term(struct make_term_info* mti, ERL_NIF_TERM term)
+{
+ unsigned ix = (mti->reuse_push++) % MAKE_TERM_REUSE_LEN;
+ mti->reuse[ix] = term;
+ //enif_fprintf(stderr, "push at %u: %T\r\n", ix, term);
+}
+static ERL_NIF_TERM pull_term(struct make_term_info* mti)
+{
+ unsigned ix;
+ if (mti->reuse_pull >= mti->reuse_push &&
+ mti->reuse_push < MAKE_TERM_REUSE_LEN) {
+ mti->reuse_pull = 0;
+ if (mti->reuse_push == 0) {
+ mti->reuse[0] = enif_make_list(mti->dst_env, 0);
+ }
+ }
+ ix = (mti->reuse_pull++) % MAKE_TERM_REUSE_LEN;
+ //enif_fprintf(stderr, "pull from %u: %T\r\n", ix, mti->reuse[ix]);
+ return mti->reuse[ix];
+}
+
+static int make_term_n(struct make_term_info* mti, int n, ERL_NIF_TERM* res);
+
+static ERL_NIF_TERM make_term_binary(struct make_term_info* mti, int n)
+{
+ ErlNifBinary bin;
+ enif_alloc_binary(100, &bin);
+ fill(bin.data, bin.size, n);
+ return enif_make_binary(mti->dst_env, &bin);
+}
+
+static ERL_NIF_TERM make_term_int(struct make_term_info* mti, int n)
+{
+ int i;
+ fill(&i, sizeof(i), n);
+ return enif_make_int(mti->dst_env, i);
+}
+
+static ERL_NIF_TERM make_term_ulong(struct make_term_info* mti, int n)
+{
+ unsigned long ul;
+ fill(&ul, sizeof(ul), n);
+ return enif_make_ulong(mti->dst_env, ul);
+}
+
+static ERL_NIF_TERM make_term_double(struct make_term_info* mti, int n)
+{
+ double d = 3.141592;
+ return enif_make_double(mti->dst_env, d);
+}
+static ERL_NIF_TERM make_term_atom(struct make_term_info* mti, int n)
+{
+ return enif_make_atom(mti->dst_env, "make_term_n");
+}
+static ERL_NIF_TERM make_term_existing_atom(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM res;
+ int exist = enif_make_existing_atom(mti->dst_env, "nif_SUITE", &res,
+ ERL_NIF_LATIN1);
+ assert(exist);
+ return res;
+}
+static ERL_NIF_TERM make_term_string(struct make_term_info* mti, int n)
+{
+ return enif_make_string(mti->dst_env, "Hello!", ERL_NIF_LATIN1);
+}
+static ERL_NIF_TERM make_term_ref(struct make_term_info* mti, int n)
+{
+ return enif_make_ref(mti->dst_env);
+}
+static ERL_NIF_TERM make_term_sub_binary(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM orig;
+ unsigned char* ptr = enif_make_new_binary(mti->dst_env, 10, &orig);
+ fill(ptr, 10, n);
+ return enif_make_sub_binary(mti->dst_env, orig, 3, 5);
+}
+static ERL_NIF_TERM make_term_uint(struct make_term_info* mti, int n)
+{
+ unsigned int ui;
+ fill(&ui, sizeof(ui), n);
+ return enif_make_uint(mti->dst_env, ui);
+}
+static ERL_NIF_TERM make_term_long(struct make_term_info* mti, int n)
+{
+ long l;
+ fill(&l, sizeof(l), n);
+ return enif_make_long(mti->dst_env, l);
+}
+static ERL_NIF_TERM make_term_tuple0(struct make_term_info* mti, int n)
+{
+ return enif_make_tuple(mti->dst_env, 0);
+}
+static ERL_NIF_TERM make_term_list0(struct make_term_info* mti, int n)
+{
+ return enif_make_list(mti->dst_env, 0);
+}
+static ERL_NIF_TERM make_term_resource(struct make_term_info* mti, int n)
+{
+ void* resource = enif_alloc_resource(mti->resource_type, 10);
+ fill(resource, 10, n);
+ return enif_make_resource(mti->dst_env, resource);
+}
+static ERL_NIF_TERM make_term_new_binary(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM res;
+ unsigned char* ptr = enif_make_new_binary(mti->dst_env,20,&res);
+ fill(ptr, 20, n);
+ return res;
+}
+static ERL_NIF_TERM make_term_caller_pid(struct make_term_info* mti, int n)
+{
+ ErlNifPid pid;
+ return enif_make_pid(mti->dst_env, enif_self(mti->caller_env, &pid));
+}
+
+static ERL_NIF_TERM make_term_tuple(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM t[3];
+ t[0] = pull_term(mti);
+ t[1] = pull_term(mti);
+ t[2] = pull_term(mti);
+ return enif_make_tuple3(mti->dst_env, t[0], t[1], t[2]);
+}
+static ERL_NIF_TERM make_term_list(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM t[3];
+ t[0] = pull_term(mti);
+ t[1] = pull_term(mti);
+ t[2] = pull_term(mti);
+ return enif_make_list3(mti->dst_env, t[0], t[1], t[2]);
+}
+static ERL_NIF_TERM make_term_list_cell(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM t[2];
+ t[0] = pull_term(mti);
+ t[1] = pull_term(mti);
+ return enif_make_list_cell(mti->dst_env, t[0], t[1]);
+}
+static ERL_NIF_TERM make_term_tuple_from_array(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM t[3];
+ t[0] = pull_term(mti);
+ t[1] = pull_term(mti);
+ t[2] = pull_term(mti);
+ return enif_make_tuple_from_array(mti->dst_env, t, 3);
+}
+static ERL_NIF_TERM make_term_list_from_array(struct make_term_info* mti, int n)
+{
+ ERL_NIF_TERM t[3];
+ t[0] = pull_term(mti);
+ t[1] = pull_term(mti);
+ t[2] = pull_term(mti);
+ return enif_make_list_from_array(mti->dst_env, t, 3);
+}
+static ERL_NIF_TERM make_term_garbage(struct make_term_info* mti, int n)
+{
+ (void) enif_make_string(mti->dst_env, "garbage string", ERL_NIF_LATIN1);
+ return pull_term(mti);
+}
+static ERL_NIF_TERM make_term_copy(struct make_term_info* mti, int n)
+{
+ return enif_make_copy(mti->dst_env, mti->other_term);
+}
+static int make_term_n(struct make_term_info* mti, int n, ERL_NIF_TERM* res)
+{
+ typedef ERL_NIF_TERM Make_term_Func(struct make_term_info*, int);
+ static Make_term_Func* funcs[] = {
+ make_term_binary,
+ make_term_int,
+ make_term_ulong,
+ make_term_double,
+ make_term_atom,
+ make_term_existing_atom,
+ make_term_string,
+ //make_term_ref,
+ make_term_sub_binary,
+ make_term_uint,
+ make_term_long,
+ make_term_tuple0,
+ make_term_list0,
+ make_term_resource,
+ make_term_new_binary,
+ make_term_caller_pid,
+ make_term_tuple,
+ make_term_list,
+ make_term_list_cell,
+ make_term_tuple_from_array,
+ make_term_list_from_array,
+ make_term_garbage,
+ make_term_copy
+ };
+ if (n < sizeof(funcs)/sizeof(*funcs)) {
+ *res = funcs[n](mti, n);
+ push_term(mti, *res);
+ return 1;
+ }
+ return 0;
+}
+
+static ERL_NIF_TERM make_blob(ErlNifEnv* caller_env, ErlNifEnv* dst_env,
+ ERL_NIF_TERM other_term)
+{
+ PrivData* priv = (PrivData*) enif_priv_data(caller_env);
+ ERL_NIF_TERM term, list;
+ int n = 0;
+ struct make_term_info mti;
+ mti.caller_env = caller_env;
+ mti.dst_env = dst_env;
+ mti.reuse_push = 0;
+ mti.reuse_pull = 0;
+ mti.resource_type = priv->rt_arr[0].t;
+ mti.other_term = other_term;
+
+ list = enif_make_list(dst_env, 0);
+ while (make_term_n(&mti, n++, &term)) {
+ list = enif_make_list_cell(dst_env, term, list);
+ }
+ return list;
+}
+
+static ERL_NIF_TERM send_new_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid to;
+ ERL_NIF_TERM msg, copy;
+ ErlNifEnv* msg_env;
+ int res;
+
+ if (!enif_get_local_pid(env, argv[0], &to)) {
+ return enif_make_badarg(env);
+ }
+ msg_env = enif_alloc_env();
+ msg = make_blob(env,msg_env, argv[1]);
+ copy = make_blob(env,env, argv[1]);
+ res = enif_send(env, &to, msg_env, msg);
+ enif_free_env(msg_env);
+ return enif_make_tuple3(env, atom_ok, enif_make_int(env,res), copy);
+}
+
+static ERL_NIF_TERM alloc_msgenv(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ PrivData* priv = (PrivData*) enif_priv_data(env);
+ struct make_term_info* mti;
+ ERL_NIF_TERM ret;
+
+ mti = (struct make_term_info*) enif_alloc_resource(msgenv_resource_type,
+ sizeof(*mti));
+ mti->caller_env = NULL;
+ mti->dst_env = enif_alloc_env();
+ mti->reuse_push = 0;
+ mti->reuse_pull = 0;
+ mti->resource_type = priv->rt_arr[0].t;
+ mti->other_term = enif_make_list(mti->dst_env, 0);
+ mti->blob = enif_make_list(mti->dst_env, 0);
+ mti->mtx = enif_mutex_create("nif_SUITE:mtx");
+ mti->cond = enif_cond_create("nif_SUITE:cond");
+ mti->send_res = 0xcafebabe;
+ mti->n = 0;
+ ret = enif_make_resource(env, mti);
+ enif_release_resource(mti);
+ return ret;
+}
+
+static void msgenv_dtor(ErlNifEnv* env, void* obj)
+{
+ struct make_term_info* mti = (struct make_term_info*) obj;
+ if (mti->dst_env != NULL) {
+ enif_free_env(mti->dst_env);
+ }
+ enif_mutex_destroy(mti->mtx);
+ enif_cond_destroy(mti->cond);
+}
+
+static ERL_NIF_TERM clear_msgenv(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union {
+ void* vp;
+ struct make_term_info* p;
+ }mti;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)) {
+ return enif_make_badarg(env);
+ }
+ enif_clear_env(mti.p->dst_env);
+ mti.p->reuse_pull = 0;
+ mti.p->reuse_push = 0;
+ mti.p->blob = enif_make_list(mti.p->dst_env, 0);
+ return atom_ok;
+}
+
+static ERL_NIF_TERM grow_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ ERL_NIF_TERM term;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)) {
+ return enif_make_badarg(env);
+ }
+ mti.p->caller_env = env;
+ mti.p->other_term = argv[1];
+ while (!make_term_n(mti.p, mti.p->n++, &term)) {
+ mti.p->n = 0;
+ }
+ mti.p->blob = enif_make_list_cell(mti.p->dst_env, term, mti.p->blob);
+ return atom_ok;
+}
+
+static ERL_NIF_TERM send_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ ErlNifPid to;
+ ERL_NIF_TERM copy;
+ int res;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)
+ || !enif_get_local_pid(env, argv[1], &to)) {
+ return enif_make_badarg(env);
+ }
+ copy = enif_make_copy(env, mti.p->blob);
+ res = enif_send(env, &to, mti.p->dst_env, mti.p->blob);
+ return enif_make_tuple3(env, atom_ok, enif_make_int(env,res), copy);
+}
+
+void* threaded_sender(void *arg)
+{
+
+ union { void* vp; struct make_term_info* p; }mti;
+ mti.vp = arg;
+
+ enif_mutex_lock(mti.p->mtx);
+ while (!mti.p->send_it) {
+ enif_cond_wait(mti.p->cond, mti.p->mtx);
+ }
+ mti.p->send_it = 0;
+ enif_mutex_unlock(mti.p->mtx);
+ mti.p->send_res = enif_send(NULL, &mti.p->to_pid, mti.p->dst_env, mti.p->blob);
+ return NULL;
+}
+
+static ERL_NIF_TERM send_blob_thread(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ ERL_NIF_TERM copy;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)
+ || !enif_get_local_pid(env,argv[1], &mti.p->to_pid)) {
+ return enif_make_badarg(env);
+ }
+ copy = enif_make_copy(env, mti.p->blob);
+
+ mti.p->send_it = enif_is_identical(argv[2],atom_join);
+ if (enif_thread_create("nif_SUITE:send_from_thread", &mti.p->tid,
+ threaded_sender, mti.p, NULL) != 0) {
+ return enif_make_badarg(env);
+ }
+ if (enif_is_identical(argv[2],atom_join)) {
+ int err = enif_thread_join(mti.p->tid, NULL);
+ assert(err == 0);
+ return enif_make_tuple3(env, atom_ok, enif_make_int(env, mti.p->send_res), copy);
+ }
+ else {
+ enif_keep_resource(mti.vp);
+ return enif_make_tuple2(env, atom_ok, copy);
+ }
+}
+
+static ERL_NIF_TERM join_send_thread(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ int err;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)) {
+ return enif_make_badarg(env);
+ }
+ enif_mutex_lock(mti.p->mtx);
+ mti.p->send_it = 1;
+ enif_cond_signal(mti.p->cond);
+ enif_mutex_unlock(mti.p->mtx);
+ err = enif_thread_join(mti.p->tid, NULL);
+ assert(err == 0);
+ enif_release_resource(mti.vp);
+ return enif_make_tuple2(env, atom_ok, enif_make_int(env, mti.p->send_res));
+}
+
static ErlNifFunc nif_funcs[] =
{
@@ -760,8 +1281,17 @@ static ErlNifFunc nif_funcs[] =
{"check_is", 10, check_is},
{"length_test", 5, length_test},
{"make_atoms", 0, make_atoms},
- {"make_strings", 0, make_strings}
-
+ {"make_strings", 0, make_strings},
+ {"make_new_resource", 2, make_new_resource},
+ {"make_new_resource_binary", 1, make_new_resource_binary},
+ {"send_list_seq", 2, send_list_seq},
+ {"send_new_blob", 2, send_new_blob},
+ {"alloc_msgenv", 0, alloc_msgenv},
+ {"clear_msgenv", 1, clear_msgenv},
+ {"grow_blob", 2, grow_blob},
+ {"send_blob", 2, send_blob},
+ {"send_blob_thread", 3, send_blob_thread},
+ {"join_send_thread", 1, join_send_thread}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index 75df9d56d5..e32d10057c 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -42,6 +42,11 @@ static ERL_NIF_TERM am_resource_type;
static ERL_NIF_TERM am_resource_dtor_A;
static ERL_NIF_TERM am_resource_dtor_B;
+static NifModPrivData* priv_data(ErlNifEnv* env)
+{
+ return (NifModPrivData*) enif_priv_data(env);
+}
+
static void init(ErlNifEnv* env)
{
am_true = enif_make_atom(env, "true");
@@ -54,7 +59,7 @@ static void init(ErlNifEnv* env)
static void add_call_with_arg(ErlNifEnv* env, NifModPrivData* data, const char* func_name,
const char* arg, int arg_sz)
{
- CallInfo* call = enif_alloc(env, sizeof(CallInfo)+strlen(func_name) + arg_sz);
+ CallInfo* call = (CallInfo*)enif_alloc(sizeof(CallInfo)+strlen(func_name) + arg_sz);
strcpy(call->func_name, func_name);
call->lib_ver = NIF_LIB_VER;
call->static_cntA = ++static_cntA;
@@ -78,7 +83,7 @@ static void add_call(ErlNifEnv* env, NifModPrivData* data,const char* func_name)
add_call_with_arg(env, data, func_name, NULL, 0);
}
-#define ADD_CALL(FUNC_NAME) add_call(env, enif_priv_data(env),FUNC_NAME)
+#define ADD_CALL(FUNC_NAME) add_call(env, priv_data(env),FUNC_NAME)
#define STRINGIFY_(X) #X
#define STRINGIFY(X) STRINGIFY_(X)
@@ -87,56 +92,56 @@ static void resource_dtor_A(ErlNifEnv* env, void* a)
{
const char dtor_name[] = "resource_dtor_A_v" STRINGIFY(NIF_LIB_VER);
- add_call_with_arg(env, enif_priv_data(env), dtor_name,
- a, enif_sizeof_resource(env, a));
+ add_call_with_arg(env, priv_data(env), dtor_name, (const char*)a,
+ enif_sizeof_resource(a));
}
static void resource_dtor_B(ErlNifEnv* env, void* a)
{
- const char dtor_name[] = "resource_dtor_B_v" STRINGIFY(NIF_LIB_VER);
+ const char dtor_name[] = "resource_dtor_B_v" STRINGIFY(NIF_LIB_VER);
- add_call_with_arg(env, enif_priv_data(env), dtor_name,
- a, enif_sizeof_resource(env, a));
+ add_call_with_arg(env, priv_data(env), dtor_name, (const char*)a,
+ enif_sizeof_resource(a));
}
/* {resource_type, Ix|null, ErlNifResourceFlags in, "TypeName", dtor(A|B|null), ErlNifResourceFlags out}*/
static void open_resource_type(ErlNifEnv* env, ERL_NIF_TERM op_tpl)
{
- NifModPrivData* data = enif_priv_data(env);
+ NifModPrivData* data = priv_data(env);
const ERL_NIF_TERM* arr;
int arity;
char rt_name[30];
- union { enum ErlNifResourceFlags e; int i; } flags, exp_res, got_res;
+ union { ErlNifResourceFlags e; int i; } flags, exp_res, got_res;
unsigned ix;
ErlNifResourceDtor* dtor;
ErlNifResourceType* got_ptr;
CHECK(enif_get_tuple(env, op_tpl, &arity, &arr));
CHECK(arity == 6);
- CHECK(enif_is_identical(env, arr[0], am_resource_type));
+ CHECK(enif_is_identical(arr[0], am_resource_type));
CHECK(enif_get_int(env, arr[2], &flags.i));
CHECK(enif_get_string(env, arr[3], rt_name, sizeof(rt_name), ERL_NIF_LATIN1) > 0);
CHECK(enif_get_int(env, arr[5], &exp_res.i));
- if (enif_is_identical(env, arr[4], am_null)) {
+ if (enif_is_identical(arr[4], am_null)) {
dtor = NULL;
}
- else if (enif_is_identical(env, arr[4], am_resource_dtor_A)) {
+ else if (enif_is_identical(arr[4], am_resource_dtor_A)) {
dtor = resource_dtor_A;
}
else {
- CHECK(enif_is_identical(env, arr[4], am_resource_dtor_B));
+ CHECK(enif_is_identical(arr[4], am_resource_dtor_B));
dtor = resource_dtor_B;
}
- got_ptr = enif_open_resource_type(env, rt_name, dtor,
+ got_ptr = enif_open_resource_type(env, NULL, rt_name, dtor,
flags.e, &got_res.e);
if (enif_get_uint(env, arr[1], &ix) && ix < RT_MAX && got_ptr != NULL) {
data->rt_arr[ix] = got_ptr;
}
else {
- CHECK(enif_is_identical(env, arr[1], am_null));
+ CHECK(enif_is_identical(arr[1], am_null));
CHECK(got_ptr == NULL);
}
CHECK(got_res.e == exp_res.e);
@@ -144,7 +149,7 @@ static void open_resource_type(ErlNifEnv* env, ERL_NIF_TERM op_tpl)
static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
- NifModPrivData* data = enif_priv_data(env);
+ NifModPrivData* data = priv_data(env);
ERL_NIF_TERM head, tail;
unsigned ix;
for (ix=0; ix<RT_MAX; ix++) {
@@ -158,17 +163,18 @@ static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
CHECK(enif_is_empty_list(env, head));
}
-static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
NifModPrivData* data;
init(env);
- data = enif_alloc(env, sizeof(NifModPrivData));
+ data = (NifModPrivData*) enif_alloc(sizeof(NifModPrivData));
CHECK(data != NULL);
- *priv_data = data;
+ *priv = data;
data->mtx = enif_mutex_create("nif_mod_priv_data");
data->ref_cnt = 1;
data->call_history = NULL;
+
add_call(env, data, "load");
do_load_info(env, load_info);
@@ -176,39 +182,35 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
return 0;
}
-static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+static int reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
+ NifModPrivData* data = (NifModPrivData*) *priv;
init(env);
- add_call(env, *priv_data, "reload");
+ add_call(env, data, "reload");
do_load_info(env, load_info);
return 0;
}
-static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
+static int upgrade(ErlNifEnv* env, void** priv, void** old_priv_data, ERL_NIF_TERM load_info)
{
- NifModPrivData* data = *old_priv_data;
+ NifModPrivData* data = (NifModPrivData*) *old_priv_data;
init(env);
add_call(env, data, "upgrade");
data->ref_cnt++;
- *priv_data = *old_priv_data;
+ *priv = *old_priv_data;
do_load_info(env, load_info);
return 0;
}
-static void unload(ErlNifEnv* env, void* priv_data)
+static void unload(ErlNifEnv* env, void* priv)
{
- NifModPrivData* data = priv_data;
+ NifModPrivData* data = (NifModPrivData*) priv;
+ int is_last;
add_call(env, data, "unload");
- enif_mutex_lock(data->mtx);
- if (--data->ref_cnt == 0) {
- enif_mutex_unlock(data->mtx);
- enif_mutex_destroy(data->mtx);
- enif_free(env, data);
- }
- enif_mutex_unlock(data->mtx);
+ NifModPrivData_release(data);
}
static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -220,12 +222,12 @@ static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ADD_CALL("get_priv_data_ptr");
- return enif_make_ulong(env, (unsigned long)enif_priv_data(env));
+ return enif_make_ulong(env, (unsigned long)priv_data(env));
}
static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- NifModPrivData* data = (NifModPrivData*) enif_priv_data(env);
+ NifModPrivData* data = priv_data(env);
ErlNifBinary ibin;
char* a;
ERL_NIF_TERM ret;
@@ -234,22 +236,22 @@ static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TE
|| !enif_inspect_binary(env, argv[1], &ibin)) {
return enif_make_badarg(env);
}
- a = enif_alloc_resource(env, data->rt_arr[ix], ibin.size);
+ a = (char*) enif_alloc_resource(data->rt_arr[ix], ibin.size);
memcpy(a, ibin.data, ibin.size);
ret = enif_make_resource(env, a);
- enif_release_resource(env, a);
+ enif_release_resource(a);
return ret;
}
static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- NifModPrivData* data = (NifModPrivData*) enif_priv_data(env);
+ NifModPrivData* data = priv_data(env);
ErlNifBinary obin;
unsigned ix;
void* a;
if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX
|| !enif_get_resource(env, argv[1], data->rt_arr[ix], &a)
- || !enif_alloc_binary(env, enif_sizeof_resource(env, a), &obin)) {
+ || !enif_alloc_binary(enif_sizeof_resource(a), &obin)) {
return enif_make_badarg(env);
}
memcpy(obin.data, a, obin.size);
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.h b/erts/emulator/test/nif_SUITE_data/nif_mod.h
index 0eaf91d6e1..cd0ecf4b54 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.h
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.h
@@ -20,3 +20,15 @@ typedef struct
ErlNifResourceType* rt_arr[RT_MAX];
}NifModPrivData;
+#define NifModPrivData_release(NMPD) \
+ do { \
+ int is_last; \
+ enif_mutex_lock((NMPD)->mtx); \
+ is_last = (--(NMPD)->ref_cnt == 0); \
+ enif_mutex_unlock((NMPD)->mtx); \
+ if (is_last) { \
+ enif_mutex_destroy((NMPD)->mtx); \
+ enif_free((NMPD)); \
+ } \
+ }while (0)
+