aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/configure.in1
-rw-r--r--erts/doc/src/erl.xml24
-rw-r--r--erts/emulator/Makefile.in7
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c6
-rw-r--r--erts/emulator/beam/erl_afit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_alloc.c23
-rw-r--r--erts/emulator/beam/erl_alloc.types2
-rw-r--r--erts/emulator/beam/erl_alloc_util.c62
-rw-r--r--erts/emulator/beam/erl_alloc_util.h2
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c22
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c24
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.h2
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c19
-rw-r--r--erts/emulator/beam/erl_gc.c173
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c14
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_init.c61
-rw-r--r--erts/emulator/beam/erl_process.c7
-rw-r--r--erts/emulator/beam/erl_process.h9
-rw-r--r--erts/emulator/beam/erl_ptab.c342
-rw-r--r--erts/emulator/beam/erl_ptab.h13
-rwxr-xr-xerts/emulator/beam/global.h8
-rw-r--r--erts/emulator/beam/io.c6
-rw-r--r--erts/emulator/sys/common/erl_mseg.c27
-rw-r--r--erts/emulator/sys/common/erl_mseg.h5
-rw-r--r--erts/emulator/sys/win32/sys_float.c4
-rw-r--r--erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c75
-rw-r--r--erts/emulator/test/port_SUITE.erl13
-rw-r--r--erts/emulator/test/process_SUITE.erl12
-rw-r--r--erts/etc/unix/cerl.src33
-rw-r--r--erts/preloaded/ebin/erlang.beambin92912 -> 93520 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin0 -> 1352 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin70072 -> 70216 bytes
-rw-r--r--erts/preloaded/src/.gitignore1
-rw-r--r--erts/preloaded/src/Makefile26
-rw-r--r--erts/preloaded/src/add_abstract_code34
-rw-r--r--erts/preloaded/src/erlang.erl20
-rw-r--r--erts/preloaded/src/prim_eval.S70
-rw-r--r--erts/preloaded/src/prim_eval.erl28
-rw-r--r--erts/preloaded/src/prim_inet.erl23
43 files changed, 891 insertions, 318 deletions
diff --git a/erts/configure.in b/erts/configure.in
index b9c9a76ef6..c47c211c4e 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -624,6 +624,7 @@ case $chk_arch_ in
armv5teb) ARCH=arm;;
armv5tel) ARCH=arm;;
armv5tejl) ARCH=arm;;
+ armv6l) ARCH=arm;;
armv7l) ARCH=arm;;
tile) ARCH=tile;;
*) ARCH=noarch;;
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index a68e62d051..8dca7402e8 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -657,10 +657,11 @@
<p>Se also <seealso marker="stdlib:io#printable_range/0">
io:printable_range/0</seealso>.</p>
</item>
- <tag><marker id="+P"/><marker id="max_processes"><c><![CDATA[+P Number]]></c></marker></tag>
+ <tag><marker id="+P"/><marker id="max_processes"><c><![CDATA[+P Number|legacy]]></c></marker></tag>
<item>
<p>Sets the maximum number of simultaneously existing processes for this
- system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p>
+ system if a <c>Number</c> is passed as value. Valid range for
+ <c>Number</c> is <c>[1024-134217727]</c></p>
<p><em>NOTE</em>: The actual maximum chosen may be much larger than
the <c>Number</c> passed. Currently the runtime system often,
but not always, chooses a value that is a power of 2. This might,
@@ -668,11 +669,19 @@
checked by calling
<seealso marker="erlang#system_info_process_limit">erlang:system_info(process_limit)</seealso>.</p>
<p>The default value is <c>262144</c></p>
+ <p>If <c>legacy</c> is passed as value, the legacy algorithm for
+ allocation of process identifiers will be used. Using the legacy
+ algorithm, identifiers will be allocated in a strictly increasing
+ fashion until largest possible identifier has been reached. Note that
+ this algorithm suffers from performance issues and can under certain
+ circumstances be extremely expensive. The legacy algoritm is deprecated,
+ and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p>
</item>
- <tag><marker id="+Q"/><marker id="max_ports"><c><![CDATA[+Q Number]]></c></marker></tag>
+ <tag><marker id="+Q"/><marker id="max_ports"><c><![CDATA[+Q Number|legacy]]></c></marker></tag>
<item>
<p>Sets the maximum number of simultaneously existing ports for this
- system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p>
+ system if a Number is passed as value. Valid range for <c>Number</c>
+ is <c>[1024-134217727]</c></p>
<p><em>NOTE</em>: The actual maximum chosen may be much larger than
the actual <c>Number</c> passed. Currently the runtime system often,
but not always, chooses a value that is a power of 2. This might,
@@ -691,6 +700,13 @@
for setting the maximum number of simultaneously existing ports. This
environment variable is deprecated, and scheduled for removal in
OTP-R17, but can still be used.</p>
+ <p>If <c>legacy</c> is passed as value, the legacy algorithm for
+ allocation of port identifiers will be used. Using the legacy
+ algorithm, identifiers will be allocated in a strictly increasing
+ fashion until largest possible identifier has been reached. Note that
+ this algorithm suffers from performance issues and can under certain
+ circumstances be extremely expensive. The legacy algoritm is deprecated,
+ and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p>
</item>
<tag><marker id="compat_rel"><c><![CDATA[+R ReleaseNumber]]></c></marker></tag>
<item>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 2031ec3a4c..58e83540e1 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -559,13 +559,14 @@ GENERATE += $(TTF_DIR)/driver_tab.c
# Preloaded code.
#
# This list must be consistent with PRE_LOADED_MODULES in
-# lib/kernel/src/Makefile.
+# erts/preloaded/src/Makefile.
ifeq ($(TARGET),win32)
# On windows the preloaded objects are in a resource object.
PRELOAD_OBJ = $(OBJDIR)/beams.$(RES_EXT)
PRELOAD_SRC = $(TARGET)/beams.rc
$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/init.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/prim_eval.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \
$(ERL_TOP)/erts/preloaded/ebin/zlib.beam \
@@ -579,6 +580,7 @@ PRELOAD_OBJ = $(OBJDIR)/preload.o
PRELOAD_SRC = $(TARGET)/preload.c
$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/init.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/prim_eval.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \
$(ERL_TOP)/erts/preloaded/ebin/zlib.beam \
@@ -1021,7 +1023,8 @@ endif
$(TARGET)/gen_git_version.mk:
# We touch beam/erl_bif.info.c if we regenerated the git version to force a
# rebuild.
- if $(gen_verbose)utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi
+ $(gen_verbose)
+ $(V_at)if utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi
.PHONY: depend
ifdef VOID_EMULATOR
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index ce60bb9bbc..9e12080732 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -248,6 +248,7 @@ atom get_data
atom get_seq_token
atom get_tcw
atom getenv
+atom gather_gc_info_result
atom gather_sched_wall_time_result
atom getting_linked
atom getting_unlinked
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
index 5850f80843..b45201af42 100644
--- a/erts/emulator/beam/erl_afit_alloc.c
+++ b/erts/emulator/beam/erl_afit_alloc.c
@@ -259,10 +259,10 @@ info_options(Allctr_t *allctr,
* to erts_afalc_test() *
\* */
-unsigned long
-erts_afalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_afalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_afit_alloc.h b/erts/emulator/beam/erl_afit_alloc.h
index cf7b99c463..b90ac8f7c5 100644
--- a/erts/emulator/beam/erl_afit_alloc.h
+++ b/erts/emulator/beam/erl_afit_alloc.h
@@ -56,7 +56,7 @@ struct AFAllctr_t_ {
AFFreeBlock_t * free_list;
};
-unsigned long erts_afalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_afalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_AF_ALLOC_IMPL)
&& !defined(ERL_AF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index c19a2647e4..403776aade 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -2176,7 +2176,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
if (want_tot_or_sys || want.processes || want.processes_used) {
- int max_processes = erts_ptab_max(&erts_proc);
UWord tmp;
if (ERTS_MEM_NEED_ALL_ALCU)
@@ -2186,7 +2185,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
fi, ERTS_ALC_NO_FIXED_SIZES);
tmp = alcu_size(ERTS_ALC_A_EHEAP, NULL, 0);
}
- tmp += max_processes*sizeof(erts_smp_atomic_t);
+ tmp += erts_ptab_mem_size(&erts_proc);
tmp += erts_bif_timer_memory_size();
tmp += erts_tot_link_lh_size();
@@ -2312,13 +2311,11 @@ struct aa_values {
Eterm
erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
{
-#define MAX_AA_VALUES (23)
+#define MAX_AA_VALUES (24)
struct aa_values values[MAX_AA_VALUES];
Eterm res = THE_NON_VALUE;
int i, length;
Uint reserved_atom_space, atom_space;
- int max_processes = erts_ptab_max(&erts_proc);
- int max_ports = erts_ptab_max(&erts_port);
if (proc) {
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN
@@ -2349,8 +2346,8 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
values[i].arity = 2;
values[i].name = "static";
- values[i].ui[0] =
- max_ports*sizeof(erts_smp_atomic_t) /* Port table */
+ values[i].ui[0] =
+ sizeof(ErtsPTab)*2 /* proc & port tables */
+ erts_timer_wheel_memory_size(); /* Timer wheel */
i++;
@@ -2429,7 +2426,12 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
values[i].arity = 2;
values[i].name = "process_table";
- values[i].ui[0] = max_processes*sizeof(Process*);
+ values[i].ui[0] = erts_ptab_mem_size(&erts_proc);
+ i++;
+
+ values[i].arity = 2;
+ values[i].name = "port_table";
+ values[i].ui[0] = erts_ptab_mem_size(&erts_port);
i++;
values[i].arity = 2;
@@ -3219,10 +3221,7 @@ void *safe_realloc(void *ptr, Uint sz)
\* */
#define ERTS_ALC_TEST_ABORT erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n")
-UWord erts_alc_test(UWord op,
- UWord a1,
- UWord a2,
- UWord a3)
+UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
{
switch (op >> 8) {
case 0x0: return erts_alcu_test(op, a1, a2);
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 5a92ab7f24..f913525726 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -366,6 +366,7 @@ type MONITOR_SH STANDARD_LOW PROCESSES monitor_sh
type NLINK_SH STANDARD_LOW PROCESSES nlink_sh
type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request
type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request
+type GC_INFO_REQ STANDARD_LOW SYSTEM gc_info_request
+else # "fullword"
@@ -383,6 +384,7 @@ type MONITOR_SH FIXED_SIZE PROCESSES monitor_sh
type NLINK_SH FIXED_SIZE PROCESSES nlink_sh
type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request
type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request
+type GC_INFO_REQ SHORT_LIVED SYSTEM gc_info_request
+endif
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index cbeb2c1e3a..53062979a6 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -4405,42 +4405,42 @@ erts_alcu_init(AlcUInit_t *init)
* to erts_alcu_test() *
\* */
-unsigned long
-erts_alcu_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_alcu_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x000: return (unsigned long) BLK_SZ((Block_t *) a1);
- case 0x001: return (unsigned long) BLK_UMEM_SZ((Block_t *) a1);
- case 0x002: return (unsigned long) IS_PREV_BLK_FREE((Block_t *) a1);
- case 0x003: return (unsigned long) IS_FREE_BLK((Block_t *) a1);
- case 0x004: return (unsigned long) IS_LAST_BLK((Block_t *) a1);
- case 0x005: return (unsigned long) UMEM2BLK((void *) a1);
- case 0x006: return (unsigned long) BLK2UMEM((Block_t *) a1);
- case 0x007: return (unsigned long) IS_SB_CARRIER((Carrier_t *) a1);
- case 0x008: return (unsigned long) IS_SBC_BLK((Block_t *) a1);
- case 0x009: return (unsigned long) IS_MB_CARRIER((Carrier_t *) a1);
- case 0x00a: return (unsigned long) IS_MSEG_CARRIER((Carrier_t *) a1);
- case 0x00b: return (unsigned long) CARRIER_SZ((Carrier_t *) a1);
- case 0x00c: return (unsigned long) SBC2BLK((Allctr_t *) a1,
+ case 0x000: return (UWord) BLK_SZ((Block_t *) a1);
+ case 0x001: return (UWord) BLK_UMEM_SZ((Block_t *) a1);
+ case 0x002: return (UWord) IS_PREV_BLK_FREE((Block_t *) a1);
+ case 0x003: return (UWord) IS_FREE_BLK((Block_t *) a1);
+ case 0x004: return (UWord) IS_LAST_BLK((Block_t *) a1);
+ case 0x005: return (UWord) UMEM2BLK((void *) a1);
+ case 0x006: return (UWord) BLK2UMEM((Block_t *) a1);
+ case 0x007: return (UWord) IS_SB_CARRIER((Carrier_t *) a1);
+ case 0x008: return (UWord) IS_SBC_BLK((Block_t *) a1);
+ case 0x009: return (UWord) IS_MB_CARRIER((Carrier_t *) a1);
+ case 0x00a: return (UWord) IS_MSEG_CARRIER((Carrier_t *) a1);
+ case 0x00b: return (UWord) CARRIER_SZ((Carrier_t *) a1);
+ case 0x00c: return (UWord) SBC2BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00d: return (unsigned long) BLK_TO_SBC((Block_t *) a2);
- case 0x00e: return (unsigned long) MBC_TO_FIRST_BLK((Allctr_t *) a1,
+ case 0x00d: return (UWord) BLK_TO_SBC((Block_t *) a2);
+ case 0x00e: return (UWord) MBC_TO_FIRST_BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00f: return (unsigned long) FIRST_BLK_TO_MBC((Allctr_t *) a1,
+ case 0x00f: return (UWord) FIRST_BLK_TO_MBC((Allctr_t *) a1,
(Block_t *) a2);
- case 0x010: return (unsigned long) ((Allctr_t *) a1)->mbc_list.first;
- case 0x011: return (unsigned long) ((Allctr_t *) a1)->mbc_list.last;
- case 0x012: return (unsigned long) ((Allctr_t *) a1)->sbc_list.first;
- case 0x013: return (unsigned long) ((Allctr_t *) a1)->sbc_list.last;
- case 0x014: return (unsigned long) ((Carrier_t *) a1)->next;
- case 0x015: return (unsigned long) ((Carrier_t *) a1)->prev;
- case 0x016: return (unsigned long) ABLK_HDR_SZ;
- case 0x017: return (unsigned long) ((Allctr_t *) a1)->min_block_size;
- case 0x018: return (unsigned long) NXT_BLK((Block_t *) a1);
- case 0x019: return (unsigned long) PREV_BLK((Block_t *) a1);
- case 0x01a: return (unsigned long) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2);
- case 0x01b: return (unsigned long) sizeof(Unit_t);
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x010: return (UWord) ((Allctr_t *) a1)->mbc_list.first;
+ case 0x011: return (UWord) ((Allctr_t *) a1)->mbc_list.last;
+ case 0x012: return (UWord) ((Allctr_t *) a1)->sbc_list.first;
+ case 0x013: return (UWord) ((Allctr_t *) a1)->sbc_list.last;
+ case 0x014: return (UWord) ((Carrier_t *) a1)->next;
+ case 0x015: return (UWord) ((Carrier_t *) a1)->prev;
+ case 0x016: return (UWord) ABLK_HDR_SZ;
+ case 0x017: return (UWord) ((Allctr_t *) a1)->min_block_size;
+ case 0x018: return (UWord) NXT_BLK((Block_t *) a1);
+ case 0x019: return (UWord) PREV_BLK((Block_t *) a1);
+ case 0x01a: return (UWord) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2);
+ case 0x01b: return (UWord) sizeof(Unit_t);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index e0754e7f69..4773598561 100644
--- a/erts/emulator/beam/erl_alloc_util.h
+++ b/erts/emulator/beam/erl_alloc_util.h
@@ -501,7 +501,7 @@ void erts_alcu_stop(Allctr_t *);
void erts_alcu_verify_unused(Allctr_t *);
void erts_alcu_verify_unused_ts(Allctr_t *allctr);
-unsigned long erts_alcu_test(unsigned long, unsigned long, unsigned long);
+UWord erts_alcu_test(UWord, UWord, UWord);
#ifdef DEBUG
int is_sbc_blk(Block_t*);
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index 6ce209085c..b916cb6198 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.c
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c
@@ -780,19 +780,19 @@ info_options(Allctr_t *allctr,
* to erts_aoffalc_test() *
\* */
-unsigned long
-erts_aoffalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_aoffalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x500: return (unsigned long) 0; /* IS_AOBF */
- case 0x501: return (unsigned long) ((AOFFAllctr_t *) a1)->mbc_root;
- case 0x502: return (unsigned long) ((AOFF_RBTree_t *) a1)->parent;
- case 0x503: return (unsigned long) ((AOFF_RBTree_t *) a1)->left;
- case 0x504: return (unsigned long) ((AOFF_RBTree_t *) a1)->right;
- case 0x506: return (unsigned long) IS_BLACK((AOFF_RBTree_t *) a1);
- case 0x508: return (unsigned long) 1; /* IS_AOFF */
- case 0x509: return (unsigned long) ((AOFF_RBTree_t *) a1)->max_sz;
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x500: return (UWord) 0; /* IS_AOBF */
+ case 0x501: return (UWord) ((AOFFAllctr_t *) a1)->mbc_root;
+ case 0x502: return (UWord) ((AOFF_RBTree_t *) a1)->parent;
+ case 0x503: return (UWord) ((AOFF_RBTree_t *) a1)->left;
+ case 0x504: return (UWord) ((AOFF_RBTree_t *) a1)->right;
+ case 0x506: return (UWord) IS_BLACK((AOFF_RBTree_t *) a1);
+ case 0x508: return (UWord) 1; /* IS_AOFF */
+ case 0x509: return (UWord) ((AOFF_RBTree_t *) a1)->max_sz;
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.h b/erts/emulator/beam/erl_ao_firstfit_alloc.h
index 6fa626f723..21c36c6654 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.h
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.h
@@ -54,7 +54,7 @@ struct AOFFAllctr_t_ {
struct AOFF_RBTree_t_* sbmbc_root;
};
-unsigned long erts_aoffalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_aoffalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_AOFF_ALLOC_IMPL)
&& !defined(ERL_AOFF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index 5625622e3f..ed843a51fb 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.c
+++ b/erts/emulator/beam/erl_bestfit_alloc.c
@@ -972,20 +972,20 @@ info_options(Allctr_t *allctr,
* to erts_bfalc_test() *
\* */
-unsigned long
-erts_bfalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_bfalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x200: return (unsigned long) ((BFAllctr_t *) a1)->address_order;
- case 0x201: return (unsigned long) ((BFAllctr_t *) a1)->mbc_root;
- case 0x202: return (unsigned long) ((RBTree_t *) a1)->parent;
- case 0x203: return (unsigned long) ((RBTree_t *) a1)->left;
- case 0x204: return (unsigned long) ((RBTree_t *) a1)->right;
- case 0x205: return (unsigned long) ((RBTreeList_t *) a1)->next;
- case 0x206: return (unsigned long) IS_BLACK((RBTree_t *) a1);
- case 0x207: return (unsigned long) IS_TREE_NODE((RBTree_t *) a1);
- case 0x208: return (unsigned long) 0; /* IS_AOFF */
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x200: return (UWord) ((BFAllctr_t *) a1)->address_order;
+ case 0x201: return (UWord) ((BFAllctr_t *) a1)->mbc_root;
+ case 0x202: return (UWord) ((RBTree_t *) a1)->parent;
+ case 0x203: return (UWord) ((RBTree_t *) a1)->left;
+ case 0x204: return (UWord) ((RBTree_t *) a1)->right;
+ case 0x205: return (UWord) ((RBTreeList_t *) a1)->next;
+ case 0x206: return (UWord) IS_BLACK((RBTree_t *) a1);
+ case 0x207: return (UWord) IS_TREE_NODE((RBTree_t *) a1);
+ case 0x208: return (UWord) 0; /* IS_AOFF */
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_bestfit_alloc.h b/erts/emulator/beam/erl_bestfit_alloc.h
index 0c29662852..f2d2f07d7a 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.h
+++ b/erts/emulator/beam/erl_bestfit_alloc.h
@@ -59,7 +59,7 @@ struct BFAllctr_t_ {
int address_order;
};
-unsigned long erts_bfalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_bfalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_BF_ALLOC_IMPL)
&& !defined(ERL_BF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 54eefe8d12..1744afbae1 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -59,6 +59,7 @@ static Export* alloc_info_trap = NULL;
static Export* alloc_sizes_trap = NULL;
static Export *gather_sched_wall_time_res_trap;
+static Export *gather_gc_info_res_trap;
#define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
@@ -3103,18 +3104,10 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1)
res = TUPLE2(hp, cs, SMALL_ZERO);
BIF_RET(res);
} else if (BIF_ARG_1 == am_garbage_collection) {
- Uint hsz = 4;
- ErtsGCInfo gc_info;
- Eterm gcs;
- Eterm recl;
- erts_gc_info(&gc_info);
- (void) erts_bld_uint(NULL, &hsz, gc_info.garbage_collections);
- (void) erts_bld_uint(NULL, &hsz, gc_info.reclaimed);
- hp = HAlloc(BIF_P, hsz);
- gcs = erts_bld_uint(&hp, NULL, gc_info.garbage_collections);
- recl = erts_bld_uint(&hp, NULL, gc_info.reclaimed);
- res = TUPLE3(hp, gcs, recl, SMALL_ZERO);
- BIF_RET(res);
+ res = erts_gc_info_request(BIF_P);
+ if (is_non_value(res))
+ BIF_RET(am_undefined);
+ BIF_TRAP1(gather_gc_info_res_trap, BIF_P, res);
} else if (BIF_ARG_1 == am_reductions) {
Uint reds;
Uint diff;
@@ -4082,6 +4075,8 @@ erts_bif_info_init(void)
alloc_sizes_trap = erts_export_put(am_erlang, am_alloc_sizes, 1);
gather_sched_wall_time_res_trap
= erts_export_put(am_erlang, am_gather_sched_wall_time_result, 1);
+ gather_gc_info_res_trap
+ = erts_export_put(am_erlang, am_gather_gc_info_result, 1);
process_info_init();
os_info_init();
}
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 298909c921..0d12e658d9 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -47,10 +47,6 @@
*/
#define ALENGTH(a) (sizeof(a)/sizeof(a[0]))
-static erts_smp_spinlock_t info_lck;
-static Uint garbage_cols; /* no of garbage collections */
-static Uint reclaimed; /* no of words reclaimed in GCs */
-
# define STACK_SZ_ON_HEAP(p) ((p)->hend - (p)->stop)
# define OverRunCheck(P) \
if ((P)->stop < (P)->htop) { \
@@ -120,6 +116,8 @@ static void offset_rootset(Process *p, Sint offs, char* area, Uint area_size,
static void offset_off_heap(Process* p, Sint offs, char* area, Uint area_size);
static void offset_mqueue(Process *p, Sint offs, char* area, Uint area_size);
+static void init_gc_info(ErtsGCInfo *gcip);
+
#ifdef HARDDEBUG
static void disallow_heap_frag_ref_in_heap(Process* p);
static void disallow_heap_frag_ref_in_old_heap(Process* p);
@@ -137,13 +135,41 @@ static int num_heap_sizes; /* Number of heap sizes. */
Uint erts_test_long_gc_sleep; /* Only used for testing... */
+typedef struct {
+ Process *proc;
+ Eterm ref;
+ Eterm ref_heap[REF_THING_SIZE];
+ Uint req_sched;
+ erts_smp_atomic32_t refc;
+} ErtsGCInfoReq;
+
+#if !HALFWORD_HEAP
+ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(gcireq,
+ ErtsGCInfoReq,
+ 5,
+ ERTS_ALC_T_GC_INFO_REQ)
+#else
+static ERTS_INLINE ErtsGCInfoReq *
+gcireq_alloc(void)
+{
+ return erts_alloc(ERTS_ALC_T_GC_INFO_REQ,
+ sizeof(ErtsGCInfoReq));
+}
+
+static ERTS_INLINE void
+gcireq_free(ErtsGCInfoReq *ptr)
+{
+ erts_free(ERTS_ALC_T_GC_INFO_REQ, ptr);
+}
+#endif
+
/*
* Initialize GC global data.
*/
void
erts_init_gc(void)
{
- int i = 0;
+ int i = 0, ix;
Sint max_heap_size = 0;
ASSERT(offsetof(ProcBin,thing_word) == offsetof(struct erl_off_heap_header,thing_word));
@@ -156,9 +182,6 @@ erts_init_gc(void)
ASSERT(offsetof(ProcBin,next) == offsetof(ErlFunThing,next));
ASSERT(offsetof(ProcBin,next) == offsetof(ExternalThing,next));
- erts_smp_spinlock_init(&info_lck, "gc_info");
- garbage_cols = 0;
- reclaimed = 0;
erts_test_long_gc_sleep = 0;
/*
@@ -199,6 +222,16 @@ erts_init_gc(void)
}
}
num_heap_sizes = i;
+
+ for (ix = 0; ix < erts_no_schedulers; ix++) {
+ ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(ix);
+ init_gc_info(&esdp->gc_info);
+ }
+
+#if !HALFWORD_HEAP
+ init_gcireq_alloc();
+#endif
+
}
/*
@@ -287,17 +320,6 @@ erts_heap_sizes(Process* p)
return res;
}
-void
-erts_gc_info(ErtsGCInfo *gcip)
-{
- if (gcip) {
- erts_smp_spin_lock(&info_lck);
- gcip->garbage_collections = garbage_cols;
- gcip->reclaimed = reclaimed;
- erts_smp_spin_unlock(&info_lck);
- }
-}
-
void
erts_offset_heap(Eterm* hp, Uint sz, Sint offs, Eterm* low, Eterm* high)
{
@@ -378,6 +400,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
Uint reclaimed_now = 0;
int done = 0;
Uint ms1, s1, us1;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
#ifdef USE_VM_PROBES
DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE);
#endif
@@ -455,11 +478,9 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
monitor_large_heap(p);
}
- erts_smp_spin_lock(&info_lck);
- garbage_cols++;
- reclaimed += reclaimed_now;
- erts_smp_spin_unlock(&info_lck);
-
+ esdp->gc_info.garbage_cols++;
+ esdp->gc_info.reclaimed += reclaimed_now;
+
FLAGS(p) &= ~F_FORCE_GC;
#ifdef CHECK_FOR_HOLES
@@ -2543,6 +2564,110 @@ offset_rootset(Process *p, Sint offs, char* area, Uint area_size,
offset_one_rootset(p, offs, area, area_size, objv, nobj);
}
+static void
+init_gc_info(ErtsGCInfo *gcip)
+{
+ gcip->reclaimed = 0;
+ gcip->garbage_cols = 0;
+}
+
+static void
+reply_gc_info(void *vgcirp)
+{
+ Uint64 reclaimed = 0, garbage_cols = 0;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ ErtsGCInfoReq *gcirp = (ErtsGCInfoReq *) vgcirp;
+ ErtsProcLocks rp_locks = (gcirp->req_sched == esdp->no
+ ? ERTS_PROC_LOCK_MAIN
+ : 0);
+ Process *rp = gcirp->proc;
+ Eterm ref_copy = NIL, msg;
+ Eterm *hp = NULL;
+ Eterm **hpp;
+ Uint sz, *szp;
+ ErlOffHeap *ohp = NULL;
+ ErlHeapFragment *bp = NULL;
+
+ ASSERT(esdp);
+
+ reclaimed = esdp->gc_info.reclaimed;
+ garbage_cols = esdp->gc_info.garbage_cols;
+
+ sz = 0;
+ hpp = NULL;
+ szp = &sz;
+
+ while (1) {
+ if (hpp)
+ ref_copy = STORE_NC(hpp, ohp, gcirp->ref);
+ else
+ *szp += REF_THING_SIZE;
+
+ msg = erts_bld_tuple(hpp, szp, 3,
+ make_small(esdp->no),
+ erts_bld_uint64(hpp, szp, garbage_cols),
+ erts_bld_uint64(hpp, szp, reclaimed));
+
+ msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg);
+ if (hpp)
+ break;
+
+ hp = erts_alloc_message_heap(sz, &bp, &ohp, rp, &rp_locks);
+ szp = NULL;
+ hpp = &hp;
+ }
+
+ erts_queue_message(rp, &rp_locks, bp, msg, NIL
+#ifdef USE_VM_PROBES
+ , NIL
+#endif
+ );
+
+ if (gcirp->req_sched == esdp->no)
+ rp_locks &= ~ERTS_PROC_LOCK_MAIN;
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+
+ erts_smp_proc_dec_refc(rp);
+
+ if (erts_smp_atomic32_dec_read_nob(&gcirp->refc) == 0)
+ gcireq_free(vgcirp);
+}
+
+Eterm
+erts_gc_info_request(Process *c_p)
+{
+ ErtsSchedulerData *esdp = ERTS_PROC_GET_SCHDATA(c_p);
+ Eterm ref;
+ ErtsGCInfoReq *gcirp;
+ Eterm *hp;
+
+ gcirp = gcireq_alloc();
+ ref = erts_make_ref(c_p);
+ hp = &gcirp->ref_heap[0];
+
+ gcirp->proc = c_p;
+ gcirp->ref = STORE_NC(&hp, NULL, ref);
+ gcirp->req_sched = esdp->no;
+ erts_smp_atomic32_init_nob(&gcirp->refc,
+ (erts_aint32_t) erts_no_schedulers);
+
+ erts_smp_proc_add_refc(c_p, (Sint32) erts_no_schedulers);
+
+#ifdef ERTS_SMP
+ if (erts_no_schedulers > 1)
+ erts_schedule_multi_misc_aux_work(1,
+ erts_no_schedulers,
+ reply_gc_info,
+ (void *) gcirp);
+#endif
+
+ reply_gc_info((void *) gcirp);
+
+ return ref;
+}
+
#if defined(DEBUG) || defined(ERTS_OFFHEAP_DEBUG)
static int
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
index c2088929e9..79d8b40f8c 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.c
+++ b/erts/emulator/beam/erl_goodfit_alloc.c
@@ -589,16 +589,16 @@ info_options(Allctr_t *allctr,
* to erts_gfalc_test() *
\* */
-unsigned long
-erts_gfalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_gfalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x100: return (unsigned long) BKT_IX((GFAllctr_t *) a1, (Uint) a2);
- case 0x101: return (unsigned long) BKT_MIN_SZ((GFAllctr_t *) a1, (int) a2);
- case 0x102: return (unsigned long) NO_OF_BKTS;
- case 0x103: return (unsigned long)
+ case 0x100: return (UWord) BKT_IX((GFAllctr_t *) a1, (Uint) a2);
+ case 0x101: return (UWord) BKT_MIN_SZ((GFAllctr_t *) a1, (int) a2);
+ case 0x102: return (UWord) NO_OF_BKTS;
+ case 0x103: return (UWord)
find_bucket(&((GFAllctr_t *) a1)->bucket_mask, (int) a2);
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_goodfit_alloc.h b/erts/emulator/beam/erl_goodfit_alloc.h
index a554a6f466..11bef77e7f 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.h
+++ b/erts/emulator/beam/erl_goodfit_alloc.h
@@ -82,7 +82,7 @@ struct GFAllctr_t_ {
};
-unsigned long erts_gfalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_gfalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_GF_ALLOC_IMPL)
&& !defined(ERL_GF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index e6a96d427f..b3a3c3d403 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -131,8 +131,10 @@ extern void ConWaitForExit(void);
static void erl_init(int ncpu,
int proc_tab_sz,
+ int legacy_proc_tab,
int port_tab_sz,
- int port_tab_sz_ignore_files);
+ int port_tab_sz_ignore_files,
+ int legacy_port_tab);
static erts_atomic_t exiting;
@@ -280,7 +282,9 @@ erts_short_init(void)
int ncpu = early_init(NULL, NULL);
erl_init(ncpu,
ERTS_DEFAULT_MAX_PROCESSES,
+ 0,
ERTS_DEFAULT_MAX_PORTS,
+ 0,
0);
erts_initialized = 1;
}
@@ -288,19 +292,21 @@ erts_short_init(void)
static void
erl_init(int ncpu,
int proc_tab_sz,
+ int legacy_proc_tab,
int port_tab_sz,
- int port_tab_sz_ignore_files)
+ int port_tab_sz_ignore_files,
+ int legacy_port_tab)
{
init_benchmarking();
erts_init_monitors();
- erts_init_gc();
erts_init_time();
erts_init_sys_common_misc();
- erts_init_process(ncpu, proc_tab_sz);
+ erts_init_process(ncpu, proc_tab_sz, legacy_proc_tab);
erts_init_scheduling(no_schedulers,
no_schedulers_online);
erts_init_cpu_topology(); /* Must be after init_scheduling */
+ erts_init_gc(); /* Must be after init_scheduling */
erts_alloc_late_init();
H_MIN_SIZE = erts_next_heap_size(H_MIN_SIZE, 0);
@@ -327,7 +333,7 @@ erl_init(int ncpu,
init_dist();
erl_drv_thr_init();
erts_init_async();
- erts_init_io(port_tab_sz, port_tab_sz_ignore_files);
+ erts_init_io(port_tab_sz, port_tab_sz_ignore_files, legacy_port_tab);
init_load();
erts_init_bif();
erts_init_bif_chksum();
@@ -923,6 +929,9 @@ erl_start(int argc, char **argv)
int proc_tab_sz = ERTS_DEFAULT_MAX_PROCESSES;
int port_tab_sz = ERTS_DEFAULT_MAX_PORTS;
int port_tab_sz_ignore_files = 0;
+ int legacy_proc_tab = 0;
+ int legacy_port_tab = 0;
+
envbufsz = sizeof(envbuf);
if (erts_sys_getenv_raw(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 0)
@@ -1268,27 +1277,35 @@ erl_start(int argc, char **argv)
case 'P': /* set maximum number of processes */
arg = get_arg(argv[i]+2, argv[i+1], &i);
- errno = 0;
- proc_tab_sz = strtol(arg, NULL, 10);
- if (errno != 0
- || proc_tab_sz < ERTS_MIN_PROCESSES
- || ERTS_MAX_PROCESSES < proc_tab_sz) {
- erts_fprintf(stderr, "bad number of processes %s\n", arg);
- erts_usage();
+ if (strcmp(arg, "legacy") == 0)
+ legacy_proc_tab = 1;
+ else {
+ errno = 0;
+ proc_tab_sz = strtol(arg, NULL, 10);
+ if (errno != 0
+ || proc_tab_sz < ERTS_MIN_PROCESSES
+ || ERTS_MAX_PROCESSES < proc_tab_sz) {
+ erts_fprintf(stderr, "bad number of processes %s\n", arg);
+ erts_usage();
+ }
}
break;
case 'Q': /* set maximum number of ports */
arg = get_arg(argv[i]+2, argv[i+1], &i);
- errno = 0;
- port_tab_sz = strtol(arg, NULL, 10);
- if (errno != 0
- || port_tab_sz < ERTS_MIN_PROCESSES
- || ERTS_MAX_PROCESSES < port_tab_sz) {
- erts_fprintf(stderr, "bad number of ports %s\n", arg);
- erts_usage();
+ if (strcmp(arg, "legacy") == 0)
+ legacy_port_tab = 1;
+ else {
+ errno = 0;
+ port_tab_sz = strtol(arg, NULL, 10);
+ if (errno != 0
+ || port_tab_sz < ERTS_MIN_PROCESSES
+ || ERTS_MAX_PROCESSES < port_tab_sz) {
+ erts_fprintf(stderr, "bad number of ports %s\n", arg);
+ erts_usage();
+ }
+ port_tab_sz_ignore_files = 1;
}
- port_tab_sz_ignore_files = 1;
break;
case 'S' : /* Was handled in early_init() just read past it */
@@ -1642,8 +1659,10 @@ erl_start(int argc, char **argv)
erl_init(ncpu,
proc_tab_sz,
+ legacy_proc_tab,
port_tab_sz,
- port_tab_sz_ignore_files);
+ port_tab_sz_ignore_files,
+ legacy_port_tab);
load_preloaded();
erts_end_staging_code_ix();
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 7415a5721f..81799ddbb1 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -485,7 +485,7 @@ release_process(void *vproc)
/* initialize the scheduler */
void
-erts_init_process(int ncpu, int proc_tab_size)
+erts_init_process(int ncpu, int proc_tab_size, int legacy_proc_tab)
{
#ifdef ERTS_SMP
@@ -505,7 +505,8 @@ erts_init_process(int ncpu, int proc_tab_size)
(ErtsPTabElementCommon *) &erts_invalid_process.common,
proc_tab_size,
sizeof(Process),
- "process_table");
+ "process_table",
+ legacy_proc_tab);
last_reductions = 0;
last_exact_reductions = 0;
@@ -4670,8 +4671,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
esdp->reductions = 0;
init_sched_wall_time(&esdp->sched_wall_time);
-
erts_port_task_handle_init(&esdp->nosuspend_port_task_handle);
+
}
init_misc_aux_work();
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 5a1f6bbe8d..7dd8116857 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -420,6 +420,11 @@ typedef struct {
} ErtsSchedWallTime;
typedef struct {
+ Uint64 reclaimed;
+ Uint64 garbage_cols;
+} ErtsGCInfo;
+
+typedef struct {
int sched;
erts_aint32_t aux_work;
} ErtsDelayedAuxWorkWakeupJob;
@@ -507,6 +512,7 @@ struct ErtsSchedulerData_ {
Uint64 reductions;
ErtsSchedWallTime sched_wall_time;
+ ErtsGCInfo gc_info;
ErtsPortTaskHandle nosuspend_port_task_handle;
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
@@ -1126,6 +1132,7 @@ void erts_early_init_scheduling(int);
void erts_init_scheduling(int, int);
Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable);
+Eterm erts_gc_info_request(Process *c_p);
Uint64 erts_get_proc_interval(void);
Uint64 erts_ensure_later_proc_interval(Uint64);
Uint64 erts_step_proc_interval(void);
@@ -1352,7 +1359,7 @@ void erts_schedule_multi_misc_aux_work(int ignore_self,
erts_aint32_t erts_set_aux_work_timeout(int, erts_aint32_t, int);
void erts_sched_notify_check_cpu_bind(void);
Uint erts_active_schedulers(void);
-void erts_init_process(int, int);
+void erts_init_process(int, int, int);
Eterm erts_process_status(Process *, ErtsProcLocks, Process *, Eterm);
Uint erts_run_queues_len(Uint *);
void erts_add_to_runq(Process *);
diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c
index 5bbc71c659..8da135b2c8 100644
--- a/erts/emulator/beam/erl_ptab.c
+++ b/erts/emulator/beam/erl_ptab.c
@@ -34,6 +34,8 @@
typedef struct ErtsPTabListBifData_ ErtsPTabListBifData;
+#define ERTS_PTAB_NEW_MAX_RESERVE_FAIL 1000
+
#define ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED 25
#define ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE 1000
#define ERTS_PTAB_LIST_BIF_MIN_START_REDS \
@@ -415,6 +417,27 @@ last_data_cmp(Uint64 ld1, Uint64 ld2)
#define ERTS_PTAB_LastData2EtermData(LD) \
((Eterm) ((LD) & ~(~((Uint64) 0) << ERTS_PTAB_ID_DATA_SIZE)))
+static ERTS_INLINE Uint32
+ix_to_free_id_data_ix(ErtsPTab *ptab, Uint32 ix)
+{
+ Uint32 dix;
+
+ dix = ((ix & ptab->r.o.dix_cl_mask) << ptab->r.o.dix_cl_shift);
+ dix += ((ix >> ptab->r.o.dix_cli_shift) & ptab->r.o.dix_cli_mask);
+ ASSERT(0 <= dix && dix < ptab->r.o.max);
+ return dix;
+}
+
+UWord
+erts_ptab_mem_size(ErtsPTab *ptab)
+{
+ UWord size = ptab->r.o.max*sizeof(erts_smp_atomic_t);
+ if (ptab->r.o.free_id_data)
+ size += ptab->r.o.max*sizeof(Uint32);
+ return size;
+}
+
+
void
erts_ptab_init_table(ErtsPTab *ptab,
ErtsAlcType_t atype,
@@ -422,10 +445,11 @@ erts_ptab_init_table(ErtsPTab *ptab,
ErtsPTabElementCommon *invalid_element,
int size,
UWord element_size,
- char *name)
+ char *name,
+ int legacy)
{
- size_t tab_sz;
- int bits;
+ size_t tab_sz, alloc_sz;
+ Uint32 bits, cl, cli, ix, ix_per_cache_line, tab_cache_lines;
char *tab_end;
erts_smp_atomic_t *tab_entry;
erts_smp_rwmtx_opt_t rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
@@ -448,7 +472,10 @@ erts_ptab_init_table(ErtsPTab *ptab,
ptab->r.o.max = size;
tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_smp_atomic_t));
- ptab->r.o.tab = erts_alloc_permanent_cache_aligned(atype, tab_sz);
+ alloc_sz = tab_sz;
+ if (!legacy)
+ alloc_sz += ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(Uint32));
+ ptab->r.o.tab = erts_alloc_permanent_cache_aligned(atype, alloc_sz);
tab_end = ((char *) ptab->r.o.tab) + tab_sz;
tab_entry = ptab->r.o.tab;
while (tab_end > ((char *) tab_entry)) {
@@ -456,28 +483,57 @@ erts_ptab_init_table(ErtsPTab *ptab,
tab_entry++;
}
- ptab->r.o.tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
- ptab->r.o.pix_per_cache_line = (ERTS_CACHE_LINE_SIZE
- / sizeof(erts_smp_atomic_t));
+ tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
+ ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(erts_smp_atomic_t));
ASSERT((ptab->r.o.max & (ptab->r.o.max - 1)) == 0); /* power of 2 */
- ASSERT((ptab->r.o.pix_per_cache_line
- & (ptab->r.o.pix_per_cache_line - 1)) == 0); /* power of 2 */
- ASSERT((ptab->r.o.tab_cache_lines
- & (ptab->r.o.tab_cache_lines - 1)) == 0); /* power of 2 */
-
- ptab->r.o.pix_mask
- = (1 << bits) - 1;
- ptab->r.o.pix_cl_mask
- = ptab->r.o.tab_cache_lines-1;
- ptab->r.o.pix_cl_shift
- = erts_fit_in_bits_int32(ptab->r.o.pix_per_cache_line-1);
- ptab->r.o.pix_cli_shift
- = erts_fit_in_bits_int32(ptab->r.o.pix_cl_mask);
- ptab->r.o.pix_cli_mask
- = (1 << (bits - ptab->r.o.pix_cli_shift)) - 1;
+ ASSERT((ix_per_cache_line & (ix_per_cache_line - 1)) == 0); /* power of 2 */
+ ASSERT((tab_cache_lines & (tab_cache_lines - 1)) == 0); /* power of 2 */
+
+ ptab->r.o.pix_mask = (1 << bits) - 1;
+ ptab->r.o.pix_cl_mask = tab_cache_lines-1;
+ ptab->r.o.pix_cl_shift = erts_fit_in_bits_int32(ix_per_cache_line-1);
+ ptab->r.o.pix_cli_shift = erts_fit_in_bits_int32(ptab->r.o.pix_cl_mask);
+ ptab->r.o.pix_cli_mask = (1 << (bits - ptab->r.o.pix_cli_shift)) - 1;
ASSERT(ptab->r.o.pix_cl_shift + ptab->r.o.pix_cli_shift == bits);
+ if (legacy) {
+ ptab->r.o.free_id_data = NULL;
+ ptab->r.o.dix_cl_mask = 0;
+ ptab->r.o.dix_cl_shift = 0;
+ ptab->r.o.dix_cli_shift = 0;
+ ptab->r.o.dix_cli_mask = 0;
+ }
+ else {
+
+ tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(Uint32));
+ ptab->r.o.free_id_data = (Uint32 *) tab_end;
+
+ tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
+ ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(Uint32));
+
+ ptab->r.o.dix_cl_mask = tab_cache_lines-1;
+ ptab->r.o.dix_cl_shift = erts_fit_in_bits_int32(ix_per_cache_line-1);
+ ptab->r.o.dix_cli_shift = erts_fit_in_bits_int32(ptab->r.o.dix_cl_mask);
+ ptab->r.o.dix_cli_mask = (1 << (bits - ptab->r.o.dix_cli_shift)) - 1;
+
+ ASSERT((ix_per_cache_line & (ix_per_cache_line - 1)) == 0); /* power of 2 */
+ ASSERT((tab_cache_lines & (tab_cache_lines - 1)) == 0); /* power of 2 */
+
+ ASSERT(ptab->r.o.dix_cl_shift + ptab->r.o.dix_cli_shift == bits);
+
+ ix = 0;
+ for (cl = 0; cl < tab_cache_lines; cl++) {
+ for (cli = 0; cli < ix_per_cache_line; cli++) {
+ ptab->r.o.free_id_data[ix] = cli*tab_cache_lines+cl;
+ ix++;
+ }
+ }
+
+ erts_smp_atomic32_init_nob(&ptab->vola.tile.aid_ix, -1);
+ erts_smp_atomic32_init_nob(&ptab->vola.tile.fid_ix, -1);
+
+ }
ptab->r.o.invalid_element = invalid_element;
ptab->r.o.invalid_data = erts_ptab_id2data(ptab, invalid_element->id);
ptab->r.o.release_element = release_element;
@@ -522,9 +578,7 @@ erts_ptab_new_element(ErtsPTab *ptab,
void *init_arg,
void (*init_ptab_el)(void *, Eterm))
{
- int pix;
- Uint64 ld, exp_ld;
- Eterm data;
+ Uint32 pix, ix, data;
erts_aint32_t count;
erts_aint_t invalid = (erts_aint_t) ptab->r.o.invalid_element;
@@ -551,62 +605,108 @@ erts_ptab_new_element(ErtsPTab *ptab,
ptab_el->u.alive.started_interval
= erts_smp_current_interval_nob(erts_ptab_interval(ptab));
- ld = last_data_read_acqb(ptab);
+ if (ptab->r.o.free_id_data) {
- /* Reserve slot */
- while (1) {
- ld++;
- pix = erts_ptab_data2pix(ptab, ERTS_PTAB_LastData2EtermData(ld));
- if (erts_smp_atomic_read_nob(&ptab->r.o.tab[pix]) == ERTS_AINT_NULL) {
- erts_aint_t val;
- val = erts_smp_atomic_cmpxchg_relb(&ptab->r.o.tab[pix],
- invalid,
- ERTS_AINT_NULL);
+ ix = (Uint32) erts_smp_atomic32_inc_read_acqb(&ptab->vola.tile.aid_ix);
+ ix = ix_to_free_id_data_ix(ptab, ix);
+
+ data = ptab->r.o.free_id_data[ix];
+
+ init_ptab_el(init_arg, (Eterm) data);
+
+#ifdef ERTS_SMP
+ erts_smp_atomic32_init_nob(&ptab_el->refc, 1);
+#endif
+
+ pix = erts_ptab_data2pix(ptab, (Eterm) data);
+
+#ifdef DEBUG
+ ASSERT(ERTS_AINT_NULL == erts_smp_atomic_xchg_relb(&ptab->r.o.tab[pix],
+ (erts_aint_t) ptab_el));
+#else
+ erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
+#endif
+
+ erts_ptab_runlock(ptab);
- if (ERTS_AINT_NULL == val)
- break;
- }
}
+ else {
+ int rlocked = ERTS_PTAB_NEW_MAX_RESERVE_FAIL;
+ Uint64 ld, exp_ld;
+ /* Deprecated legacy algorithm... */
+
+ restart:
+
+ ptab_el->u.alive.started_interval
+ = erts_smp_current_interval_nob(erts_ptab_interval(ptab));
- data = ERTS_PTAB_LastData2EtermData(ld);
+ ld = last_data_read_acqb(ptab);
+
+ /* Reserve slot */
+ while (1) {
+ ld++;
+ pix = erts_ptab_data2pix(ptab, ERTS_PTAB_LastData2EtermData(ld));
+ if (erts_smp_atomic_read_nob(&ptab->r.o.tab[pix])
+ == ERTS_AINT_NULL) {
+ erts_aint_t val;
+ val = erts_smp_atomic_cmpxchg_relb(&ptab->r.o.tab[pix],
+ invalid,
+ ERTS_AINT_NULL);
+
+ if (ERTS_AINT_NULL == val)
+ break;
+ }
+ if (rlocked && --rlocked == 0) {
+ erts_ptab_runlock(ptab);
+ erts_ptab_rwlock(ptab);
+ goto restart;
+ }
+ }
- if (data == ptab->r.o.invalid_data) {
- /* Do not use invalid data; fix it... */
- ld += ptab->r.o.max;
- ASSERT(pix == erts_ptab_data2pix(ptab,
- ERTS_PTAB_LastData2EtermData(ld)));
data = ERTS_PTAB_LastData2EtermData(ld);
- ASSERT(data != ptab->r.o.invalid_data);
- }
- exp_ld = last_data_read_nob(ptab);
+ if (data == ptab->r.o.invalid_data) {
+ /* Do not use invalid data; fix it... */
+ ld += ptab->r.o.max;
+ ASSERT(pix == erts_ptab_data2pix(ptab,
+ ERTS_PTAB_LastData2EtermData(ld)));
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ ASSERT(data != ptab->r.o.invalid_data);
+ }
- /* Move last data forward */
- while (1) {
- Uint64 act_ld;
- if (last_data_cmp(ld, exp_ld) < 0)
- break;
- act_ld = last_data_cmpxchg_relb(ptab, ld, exp_ld);
- if (act_ld == exp_ld)
- break;
- exp_ld = act_ld;
- }
+ exp_ld = last_data_read_nob(ptab);
+
+ /* Move last data forward */
+ while (1) {
+ Uint64 act_ld;
+ if (last_data_cmp(ld, exp_ld) < 0)
+ break;
+ act_ld = last_data_cmpxchg_relb(ptab, ld, exp_ld);
+ if (act_ld == exp_ld)
+ break;
+ exp_ld = act_ld;
+ }
- init_ptab_el(init_arg, data);
+ init_ptab_el(init_arg, data);
#ifdef ERTS_SMP
- erts_smp_atomic32_init_nob(&ptab_el->refc, 1);
+ erts_smp_atomic32_init_nob(&ptab_el->refc, 1);
#endif
- /* Move into slot reserved */
+ /* Move into slot reserved */
#ifdef DEBUG
- ASSERT(invalid == erts_smp_atomic_xchg_relb(&ptab->r.o.tab[pix],
+ ASSERT(invalid == erts_smp_atomic_xchg_relb(&ptab->r.o.tab[pix],
(erts_aint_t) ptab_el));
#else
- erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
+ erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
#endif
- erts_ptab_runlock(ptab);
+ if (rlocked)
+ erts_ptab_runlock(ptab);
+ else
+ erts_ptab_rwunlock(ptab);
+
+ }
return 1;
}
@@ -647,7 +747,9 @@ erts_ptab_delete_element(ErtsPTab *ptab,
ErtsPTabElementCommon *ptab_el)
{
int maybe_save;
- int pix = erts_ptab_id2pix(ptab, ptab_el->id);
+ Uint32 pix, ix, data;
+
+ pix = erts_ptab_id2pix(ptab, ptab_el->id);
ASSERT(erts_get_scheduler_id()); /* *Need* to be a scheduler */
@@ -660,6 +762,26 @@ erts_ptab_delete_element(ErtsPTab *ptab,
erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], ERTS_AINT_NULL);
+ if (ptab->r.o.free_id_data) {
+
+ /* Next data for this slot... */
+ data = (Uint32) erts_ptab_id2data(ptab, ptab_el->id);
+ data += ptab->r.o.max;
+ data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
+ if (data == ptab->r.o.invalid_data) { /* make sure not invalid */
+ data += ptab->r.o.max;
+ data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
+ }
+
+ ASSERT(data != ptab->r.o.invalid_data);
+ ASSERT(pix == erts_ptab_data2pix(ptab, data));
+
+ ix = (Uint32) erts_smp_atomic32_inc_read_relb(&ptab->vola.tile.fid_ix);
+ ix = ix_to_free_id_data_ix(ptab, ix);
+
+ ptab->r.o.free_id_data[ix] = data;
+ }
+
ASSERT(erts_smp_atomic32_read_nob(&ptab->vola.tile.count) > 0);
erts_smp_atomic32_dec_relb(&ptab->vola.tile.count);
@@ -1280,42 +1402,86 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
erts_ptab_rwlock(ptab);
- if (!set)
- ld = last_data_read_nob(ptab);
- else {
+ if (ptab->r.o.free_id_data) {
+ Uint32 aid_ix, dix;
- ld = (Uint64) next;
- data = ERTS_PTAB_LastData2EtermData(ld);
- if (ptab->r.o.invalid_data == data) {
- ld += ptab->r.o.max;
- ASSERT(erts_ptab_data2pix(ptab, data)
- == erts_ptab_data2pix(ptab,
- ERTS_PTAB_LastData2EtermData(ld)));
+ if (set) {
+ Uint32 max_ix, ser, num, start;
+ max_ix = ptab->r.o.max - 1;
+ ser = next & ~max_ix;
+ start = num = next & max_ix;
+
+ aid_ix = (Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.aid_ix) + 1;
+
+ do {
+ Uint32 pix = erts_ptab_data2pix(ptab, num);
+ if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
+ dix = ix_to_free_id_data_ix(ptab, aid_ix);
+ ptab->r.o.free_id_data[dix] = ser + num;
+ ASSERT(pix == erts_ptab_data2pix(ptab, ser+num));
+ if (aid_ix == max_ix)
+ aid_ix = 0;
+ else
+ aid_ix++;
+ }
+ if (num == max_ix)
+ num = 0;
+ else
+ num++;
+ } while (num != start);
+
+#ifdef DEBUG
+ if (aid_ix == 0)
+ aid_ix = max_ix;
+ else
+ aid_ix--;
+ ASSERT((aid_ix & max_ix) == (((Uint32) erts_atomic32_read_nob(&ptab->vola.tile.fid_ix)) & max_ix));
+#endif
}
- last_data_set_relb(ptab, ld);
+
+ aid_ix = (Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.aid_ix) + 1;
+ dix = ix_to_free_id_data_ix(ptab, aid_ix);
+ res = (Sint) ptab->r.o.free_id_data[dix];
}
+ else {
+ /* Deprecated legacy algorithm... */
+ if (!set)
+ ld = last_data_read_nob(ptab);
+ else {
- while (1) {
- int pix;
- ld++;
- pix = (int) (ld % ptab->r.o.max);
- if (first_pix < 0)
- first_pix = pix;
- else if (pix == first_pix) {
- res = -1;
- break;
- }
- if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
+ ld = (Uint64) next;
data = ERTS_PTAB_LastData2EtermData(ld);
if (ptab->r.o.invalid_data == data) {
ld += ptab->r.o.max;
ASSERT(erts_ptab_data2pix(ptab, data)
== erts_ptab_data2pix(ptab,
ERTS_PTAB_LastData2EtermData(ld)));
+ }
+ last_data_set_relb(ptab, ld);
+ }
+
+ while (1) {
+ int pix;
+ ld++;
+ pix = (int) (ld % ptab->r.o.max);
+ if (first_pix < 0)
+ first_pix = pix;
+ else if (pix == first_pix) {
+ res = -1;
+ break;
+ }
+ if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
data = ERTS_PTAB_LastData2EtermData(ld);
+ if (ptab->r.o.invalid_data == data) {
+ ld += ptab->r.o.max;
+ ASSERT(erts_ptab_data2pix(ptab, data)
+ == erts_ptab_data2pix(ptab,
+ ERTS_PTAB_LastData2EtermData(ld)));
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ }
+ res = data;
+ break;
}
- res = data;
- break;
}
}
diff --git a/erts/emulator/beam/erl_ptab.h b/erts/emulator/beam/erl_ptab.h
index 7fa1251900..84ff7d0de4 100644
--- a/erts/emulator/beam/erl_ptab.h
+++ b/erts/emulator/beam/erl_ptab.h
@@ -94,18 +94,23 @@ typedef struct {
erts_smp_atomic_t last_data;
#endif
erts_smp_atomic32_t count;
+ erts_smp_atomic32_t aid_ix;
+ erts_smp_atomic32_t fid_ix;
} ErtsPTabVolatileData;
typedef struct {
erts_smp_atomic_t *tab;
+ Uint32 *free_id_data;
Uint32 max;
- Uint32 tab_cache_lines;
- Uint32 pix_per_cache_line;
Uint32 pix_mask;
Uint32 pix_cl_mask;
Uint32 pix_cl_shift;
Uint32 pix_cli_mask;
Uint32 pix_cli_shift;
+ Uint32 dix_cl_mask;
+ Uint32 dix_cl_shift;
+ Uint32 dix_cli_mask;
+ Uint32 dix_cli_shift;
ErtsPTabElementCommon *invalid_element;
Eterm invalid_data;
void (*release_element)(void *);
@@ -179,7 +184,8 @@ void erts_ptab_init_table(ErtsPTab *ptab,
ErtsPTabElementCommon *invalid_element,
int size,
UWord element_size,
- char *name);
+ char *name,
+ int legacy);
int erts_ptab_new_element(ErtsPTab *ptab,
ErtsPTabElementCommon *ptab_el,
void *init_arg,
@@ -187,6 +193,7 @@ int erts_ptab_new_element(ErtsPTab *ptab,
void erts_ptab_delete_element(ErtsPTab *ptab,
ErtsPTabElementCommon *ptab_el);
int erts_ptab_initialized(ErtsPTab *ptab);
+UWord erts_ptab_mem_size(ErtsPTab *ptab);
ERTS_GLB_INLINE erts_interval_t *erts_ptab_interval(ErtsPTab *ptab);
ERTS_GLB_INLINE int erts_ptab_max(ErtsPTab *ptab);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 012c1c7e6a..26ed5f82c1 100755
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -688,12 +688,6 @@ void MD5Final(unsigned char [16], MD5_CTX *);
/* ggc.c */
-
-typedef struct {
- Uint garbage_collections;
- Uint reclaimed;
-} ErtsGCInfo;
-
void erts_gc_info(ErtsGCInfo *gcip);
void erts_init_gc(void);
int erts_garbage_collect(Process*, int, Eterm*, int);
@@ -724,7 +718,7 @@ int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_l
void erts_destroy_driver(erts_driver_t *drv);
int erts_save_suspend_process_on_port(Port*, Process*);
Port *erts_open_driver(erts_driver_t*, Eterm, char*, SysDriverOpts*, int *, int *);
-void erts_init_io(int, int);
+void erts_init_io(int, int, int);
void erts_raw_port_command(Port*, byte*, Uint);
void driver_report_exit(ErlDrvPort, int);
LineBuf* allocate_linebuf(int);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index b6b7b47bd6..13cff24b95 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -2707,7 +2707,8 @@ erts_port_link(Process *c_p, Port *prt, Eterm to, Eterm *refp)
}
void erts_init_io(int port_tab_size,
- int port_tab_size_ignore_files)
+ int port_tab_size_ignore_files,
+ int legacy_port_tab)
{
ErlDrvEntry** dp;
UWord common_element_size;
@@ -2750,7 +2751,8 @@ void erts_init_io(int port_tab_size,
(ErtsPTabElementCommon *) &erts_invalid_port.common,
port_tab_size,
common_element_size, /* Doesn't need to be excact */
- "port_table");
+ "port_table",
+ legacy_port_tab);
erts_smp_atomic_init_nob(&erts_bytes_out, 0);
erts_smp_atomic_init_nob(&erts_bytes_in, 0);
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index b6e2c9382b..2748edba02 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -1749,45 +1749,42 @@ erts_mseg_late_init(void)
#endif /* #if HAVE_ERTS_MSEG */
-unsigned long
-erts_mseg_test(unsigned long op,
- unsigned long a1,
- unsigned long a2,
- unsigned long a3)
+UWord
+erts_mseg_test(UWord op, UWord a1, UWord a2, UWord a3)
{
switch (op) {
#if HAVE_ERTS_MSEG
case 0x400: /* Have erts_mseg */
- return (unsigned long) 1;
+ return (UWord) 1;
case 0x401:
- return (unsigned long) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
+ return (UWord) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
case 0x402:
erts_mseg_dealloc(ERTS_ALC_A_INVALID, (void *) a1, (Uint) a2, (Uint) 0);
- return (unsigned long) 0;
+ return (UWord) 0;
case 0x403:
- return (unsigned long) erts_mseg_realloc(ERTS_ALC_A_INVALID,
+ return (UWord) erts_mseg_realloc(ERTS_ALC_A_INVALID,
(void *) a1,
(Uint) a2,
(Uint *) a3,
(Uint) 0);
case 0x404:
erts_mseg_clear_cache();
- return (unsigned long) 0;
+ return (UWord) 0;
case 0x405:
- return (unsigned long) erts_mseg_no(&erts_mseg_default_opt);
+ return (UWord) erts_mseg_no(&erts_mseg_default_opt);
case 0x406: {
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(0);
- unsigned long res;
+ UWord res;
ERTS_MSEG_LOCK(ma);
- res = (unsigned long) tot_cache_size(ma);
+ res = (UWord) tot_cache_size(ma);
ERTS_MSEG_UNLOCK(ma);
return res;
}
#else /* #if HAVE_ERTS_MSEG */
case 0x400: /* Have erts_mseg */
- return (unsigned long) 0;
+ return (UWord) 0;
#endif /* #if HAVE_ERTS_MSEG */
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index 3cab9e18da..a4f250ceab 100644
--- a/erts/emulator/sys/common/erl_mseg.h
+++ b/erts/emulator/sys/common/erl_mseg.h
@@ -109,9 +109,6 @@ Eterm erts_mseg_info(int, int *, void*, int, Uint **, Uint *);
#endif /* #if HAVE_ERTS_MSEG */
-unsigned long erts_mseg_test(unsigned long,
- unsigned long,
- unsigned long,
- unsigned long);
+UWord erts_mseg_test(UWord, UWord, UWord, UWord);
#endif /* #ifndef ERL_MSEG_H_ */
diff --git a/erts/emulator/sys/win32/sys_float.c b/erts/emulator/sys/win32/sys_float.c
index e2a777d182..0e19746cf5 100644
--- a/erts/emulator/sys/win32/sys_float.c
+++ b/erts/emulator/sys/win32/sys_float.c
@@ -52,7 +52,7 @@ void erts_thread_disable_fpe(void)
int
sys_chars_to_double(char *buf, double *fp)
{
- char *s = buf, *t, *dp;
+ unsigned char *s = buf, *t, *dp;
/* Robert says that something like this is what he really wanted:
* (The [.,] radix test is NOT what Robert wanted - it was added later)
@@ -120,7 +120,7 @@ sys_chars_to_double(char *buf, double *fp)
int
sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t decimals)
{
- char *s = buffer;
+ unsigned char *s = buffer;
if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size)
return -1;
diff --git a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
index 95a6ae9bdf..500725a7cd 100644
--- a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
@@ -58,7 +58,7 @@ void *
test_thread(void *vsize)
{
int i;
- int size = (int) (long) vsize;
+ int size = (int) (ErlDrvSInt) vsize;
void *mem;
mem = driver_alloc(size);
if (mem)
@@ -88,7 +88,7 @@ ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf,
res = erl_drv_thread_create("test_thread",
&tid,
test_thread,
- (void *) (long) size,
+ (void *) (ErlDrvSInt) size,
NULL);
if (res == 0) {
res = erl_drv_thread_join(tid, NULL);
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index c8f286f629..0c4a9f7e5c 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -40,7 +40,7 @@ typedef struct
int ref_cnt;
CallInfo* call_history;
NifModPrivData* nif_mod;
- union { ErlNifResourceType* t; long l; } rt_arr[2];
+ union { ErlNifResourceType* t; void* vp; } rt_arr[2];
} PrivData;
/*
@@ -93,6 +93,23 @@ struct binary_resource {
unsigned size;
};
+static int get_pointer(ErlNifEnv* env, ERL_NIF_TERM term, void** pp)
+{
+ ErlNifUInt64 i64;
+ int r = enif_get_uint64(env, term, &i64);
+ if (r) {
+ *pp = (void*)i64;
+ }
+ return r;
+}
+
+static ERL_NIF_TERM make_pointer(ErlNifEnv* env, void* p)
+{
+ ErlNifUInt64 i64 = (ErlNifUInt64) p;
+ return enif_make_uint64(env, i64);
+}
+
+
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
PrivData* data = enif_alloc(sizeof(PrivData));
@@ -224,15 +241,15 @@ static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_priv_data(env);
- unsigned long ptr_as_ulong;
+ void* ptr;
- if (!enif_get_ulong(env,argv[0],&ptr_as_ulong)) {
+ if (!get_pointer(env,argv[0],&ptr)) {
return enif_make_badarg(env);
}
if (data->nif_mod != NULL) {
NifModPrivData_release(data->nif_mod);
}
- data->nif_mod = (NifModPrivData*) ptr_as_ulong;
+ data->nif_mod = (NifModPrivData*) ptr;
return enif_make_int(env,++(data->nif_mod->ref_cnt));
}
@@ -696,7 +713,7 @@ static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_
memcpy(enif_make_new_binary(env, resource_dtor_last_sz, &bin),
resource_dtor_last_data, resource_dtor_last_sz);
ret = enif_make_tuple3(env,
- enif_make_long(env, (long)resource_dtor_last),
+ make_pointer(env, resource_dtor_last),
bin,
enif_make_int(env, resource_dtor_cnt));
}
@@ -717,40 +734,40 @@ static ERL_NIF_TERM get_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TE
if (!enif_get_int(env, argv[0], &ix) || ix >= 2) {
return enif_make_badarg(env);
}
- return enif_make_long(env, data->rt_arr[ix].l);
+ return make_pointer(env, data->rt_arr[ix].vp);
}
static ERL_NIF_TERM alloc_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)
+ union { ErlNifResourceType* t; void* vp; } type;
+ void* data;
+ if (!get_pointer(env, argv[0], &type.vp)
|| !enif_inspect_binary(env, argv[1], &data_bin)
- || (data.p = enif_alloc_resource(type.t, data_bin.size))==NULL) {
+ || (data = enif_alloc_resource(type.t, data_bin.size))==NULL) {
return enif_make_badarg(env);
}
- memcpy(data.p, data_bin.data, data_bin.size);
- return enif_make_long(env, data.l);
+ memcpy(data, data_bin.data, data_bin.size);
+ return make_pointer(env, data);
}
static ERL_NIF_TERM make_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- union { void* p; long l; } data;
- if (!enif_get_long(env, argv[0], &data.l)) {
+ void* data;
+ if (!get_pointer(env, argv[0], &data)) {
return enif_make_badarg(env);
}
- return enif_make_resource(env, data.p);
+ return enif_make_resource(env, data);
}
static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { ErlNifResourceType* t; long l; } type;
+ union { ErlNifResourceType* t; void* vp; } type;
void* data;
ERL_NIF_TERM ret;
- if (!enif_get_long(env, argv[0], &type.l)
+ if (!get_pointer(env, argv[0], &type.vp)
|| !enif_inspect_binary(env, argv[1], &data_bin)
|| (data = enif_alloc_resource(type.t, data_bin.size))==NULL) {
@@ -765,7 +782,7 @@ static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TE
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;
+ union { struct binary_resource* p; void* vp; } br;
void* buf;
ERL_NIF_TERM ret;
if (!enif_inspect_binary(env, argv[0], &data_bin)
@@ -781,7 +798,7 @@ static ERL_NIF_TERM make_new_resource_binary(ErlNifEnv* env, int argc, const ERL
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);
+ return enif_make_tuple2(env, make_pointer(env,br.vp), ret);
}
static void binary_resource_dtor(ErlNifEnv* env, void* obj)
@@ -796,33 +813,33 @@ static void binary_resource_dtor(ErlNifEnv* env, void* obj)
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;
+ union { ErlNifResourceType* t; void* vp; } type;
+ void* data;
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);
+ get_pointer(env, argv[0], &type.vp);
}
if (type.t == NULL
- || !enif_get_resource(env, argv[1], type.t, &data.p)) {
+ || !enif_get_resource(env, argv[1], type.t, &data)) {
return enif_make_badarg(env);
}
- 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_alloc_binary(enif_sizeof_resource(data), &data_bin);
+ memcpy(data_bin.data, data, data_bin.size);
+ return enif_make_tuple2(env, make_pointer(env,data),
enif_make_binary(env, &data_bin));
}
static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- union { void* p; long l; } data;
- if (!enif_get_long(env, argv[0], &data.l)) {
+ void* data;
+ if (!get_pointer(env, argv[0], &data)) {
return enif_make_badarg(env);
}
- enif_release_resource(data.p);
+ enif_release_resource(data);
return enif_make_atom(env,"ok");
}
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 13aa0f4c00..e467e844b3 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -92,7 +92,7 @@
spawn_driver/1, spawn_executable/1, close_deaf_port/1,
unregister_name/1, parallelism_option/1]).
--export([]).
+-export([do_iter_max_ports/2]).
%% Internal exports.
-export([tps/3]).
@@ -635,9 +635,16 @@ iter_max_ports_test(Config) ->
{win32,_} -> 4;
_ -> 10
end,
- L = do_iter_max_ports(Iters, Command),
+ %% Run on a different node in order to limit the effect if this test fails.
+ Dir = filename:dirname(code:which(?MODULE)),
+ {ok,Node} = test_server:start_node(test_iter_max_socks,slave,
+ [{args,"+Q 2048 -pa " ++ Dir}]),
+ L = rpc:call(Node,?MODULE,do_iter_max_ports,[Iters, Command]),
+ test_server:stop_node(Node),
+
io:format("Result: ~p",[L]),
all_equal(L),
+ all_equal(L),
test_server:timetrap_cancel(Dog),
{comment, "Max ports: " ++ integer_to_list(hd(L))}.
@@ -670,7 +677,7 @@ close_ports([]) ->
ok.
open_ports(Name, Settings) ->
- test_server:sleep(50),
+ test_server:sleep(5),
case catch open_port(Name, Settings) of
P when is_port(P) ->
[P| open_ports(Name, Settings)];
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 863cd2d654..72f3e8fe85 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -1494,6 +1494,7 @@ processes_bif_cleaner() ->
spawn_initial_hangarounds(Cleaner) ->
TabSz = erlang:system_info(process_limit),
+ erts_debug:set_internal_state(next_pid,TabSz),
spawn_initial_hangarounds(Cleaner,
TabSz,
TabSz*2,
@@ -1538,14 +1539,21 @@ hangaround(Cleaner, Type) ->
spawn_initial_hangarounds(_Cleaner, NP, Max, Len, HAs) when NP > Max ->
{Len, HAs};
spawn_initial_hangarounds(Cleaner, NP, Max, Len, HAs) ->
- erts_debug:set_internal_state(next_pid,NP),
+ Skip = 30,
HA1 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, low}]),
HA2 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, normal}]),
HA3 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, high}]),
- spawn_initial_hangarounds(Cleaner, NP+30, Max, Len+3, [HA1,HA2,HA3|HAs]).
+ spawn_drop(Skip),
+ spawn_initial_hangarounds(Cleaner, NP+Skip, Max, Len+3, [HA1,HA2,HA3|HAs]).
+
+spawn_drop(N) when N =< 0 ->
+ ok;
+spawn_drop(N) ->
+ spawn(fun () -> ok end),
+ spawn_drop(N-1).
do_processes(WantReds) ->
erts_debug:set_internal_state(reds_left, WantReds),
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index f99059cb72..691b32e143 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -31,6 +31,8 @@
# -debug Run debug compiled emulator
# -gdb Run the debug compiled emulator in emacs and gdb.
# You have to start beam in gdb using "run".
+# -rgdb Run the debug compiled emulator in gdb.
+# You have to start beam in gdb using "run".
# -break F Run the debug compiled emulator in emacs and gdb and set break.
# The session is started, i.e. "run" is already don for you.
# -xxgdb FIXME currently disabled
@@ -178,6 +180,10 @@ while [ $# -gt 0 ]; do
;;
"-gdb")
shift
+ GDB=egdb
+ ;;
+ "-rgdb")
+ shift
GDB=gdb
;;
"-break")
@@ -188,6 +194,12 @@ while [ $# -gt 0 ]; do
;;
"-core")
shift
+ GDB=egdb
+ core="$1"
+ shift
+ ;;
+ "-rcore")
+ shift
GDB=gdb
core="$1"
shift
@@ -285,6 +297,27 @@ if [ "x$GDB" = "x" ]; then
else
exec $EXEC $eeargs $xargs ${1+"$@"}
fi
+elif [ "x$GDB" = "xgdb" ]; then
+ case "x$core" in
+ x)
+ # Get emu args to use from erlexec...
+ beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
+ gdbcmd="--args $EMU_NAME $beam_args"
+ ;;
+ x/*)
+ gdbcmd="$EMU_NAME ${core}"
+ GDBBP=
+ ;;
+ *)
+ dir=`pwd`
+ gdbcmd="$EMU_NAME ${dir}/${core}"
+ GDBBP=
+ ;;
+ esac
+ cmdfile="/tmp/.cerlgdb.$$"
+ echo "source $ROOTDIR/erts/etc/unix/etp-commands" > $cmdfile
+ # Fire up gdb in emacs...
+ exec gdb $GDBBP -x $cmdfile $gdbcmd
else
if [ "x$EMACS" = "x" ]; then
EMACS=emacs
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 308cb99be5..315f9ebd47 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
new file mode 100644
index 0000000000..6c7b7e5262
--- /dev/null
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 43cbc17dbf..a0a4314128 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/.gitignore b/erts/preloaded/src/.gitignore
new file mode 100644
index 0000000000..e4658fe142
--- /dev/null
+++ b/erts/preloaded/src/.gitignore
@@ -0,0 +1 @@
+prim_eval.abstr
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index a224b6a5d4..f53809e765 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -32,7 +32,7 @@ STATIC_EBIN=../ebin
include $(ERL_TOP)/erts/vsn.mk
include $(ERL_TOP)/lib/kernel/vsn.mk
-PRE_LOADED_MODULES = \
+PRE_LOADED_ERL_MODULES = \
erl_prim_loader \
init \
prim_file \
@@ -43,10 +43,17 @@ PRE_LOADED_MODULES = \
erlang \
erts_internal
+PRE_LOADED_BEAM_MODULES = \
+ prim_eval
+
+PRE_LOADED_MODULES = $(PRE_LOADED_ERL_MODULES) $(PRE_LOADED_BEAM_MODULES)
+
RELSYSDIR = $(RELEASE_PATH)/lib/erts-$(VSN)
# not $(RELEASE_PATH)/erts-$(VSN)/preloaded
-ERL_FILES= $(PRE_LOADED_MODULES:%=%.erl)
+ERL_FILES= $(PRE_LOADED_ERL_MODULES:%=%.erl)
+BEAM_FILES= $(PRE_LOADED_BEAM_MODULES:%=%.S)
+STUBS_FILES= $(PRE_LOADED_BEAM_MODULES:%=%.erl)
TARGET_FILES = $(PRE_LOADED_MODULES:%=$(EBIN)/%.$(EMULATOR))
STATIC_TARGET_FILES = $(PRE_LOADED_MODULES:%=$(STATIC_EBIN)/%.$(EMULATOR))
@@ -70,7 +77,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
$(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(BEAM_FILES) $(STUBS_FILES) "$(RELSYSDIR)/src"
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(STATIC_TARGET_FILES) "$(RELSYSDIR)/ebin"
@@ -80,6 +87,19 @@ release_docs_spec:
list_preloaded:
@echo $(PRE_LOADED_MODULES)
+#
+# Combine a BEAM assembly script file a stub Erlang file into a BEAM file.
+# See add_abstract_chunk script.
+#
+
+prim_eval.abstr: prim_eval.erl
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -o$(dir $@) +dabstr $<
+
+prim_eval.beam: prim_eval.S prim_eval.abstr
+ $(gen_verbose)
+ $(V_at)$(ERLC) $(ERL_COMPILE_FLAGS) $<
+ $(V_at)escript add_abstract_code $@ prim_eval.abstr || (rm $@; exit 1)
+
# Include dependencies -- list below added by PaN
$(EBIN)/erl_prim_loader.beam: $(KERNEL_SRC)/inet_boot.hrl $(KERNEL_INCLUDE)/file.hrl
$(EBIN)/prim_file.beam: $(KERNEL_INCLUDE)/file.hrl
diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code
new file mode 100644
index 0000000000..e670156d21
--- /dev/null
+++ b/erts/preloaded/src/add_abstract_code
@@ -0,0 +1,34 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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%
+%%
+
+-mode(compile).
+
+-export([main/1]).
+
+main([BeamFile,AbstrFile]) ->
+ {ok,_,Chunks0} = beam_lib:all_chunks(BeamFile),
+ {ok,Abstr} = file:consult(AbstrFile),
+ Chunks = lists:keyreplace("Abst", 1, Chunks0,
+ {"Abst",term_to_binary({raw_abstract_v1,Abstr})}),
+ {ok,Module} = beam_lib:build_module(Chunks),
+ ok = file:write_file(BeamFile, Module),
+ init:stop().
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 7106c0a4fb..6929ca3fa5 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -45,7 +45,8 @@
-export([alloc_info/1, alloc_sizes/1]).
-export([gather_sched_wall_time_result/1,
- await_sched_wall_time_modifications/2]).
+ await_sched_wall_time_modifications/2,
+ gather_gc_info_result/1]).
-deprecated([hash/2]).
@@ -3536,3 +3537,20 @@ sched_wall_time(Ref, N, Acc) ->
{Ref, undefined} -> sched_wall_time(Ref, N-1, undefined);
{Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc])
end.
+
+-spec erlang:gather_gc_info_result(Ref) -> [{pos_integer(),
+ pos_integer(),
+ 0}] when
+ Ref :: reference().
+
+gather_gc_info_result(Ref) when erlang:is_reference(Ref) ->
+ gc_info(Ref, erlang:system_info(schedulers), {0,0}).
+
+gc_info(_Ref, 0, {Colls,Recl}) ->
+ {Colls,Recl,0};
+gc_info(Ref, N, {OrigColls,OrigRecl}) ->
+ receive
+ {Ref, {_,Colls, Recl}} ->
+ gc_info(Ref, N-1, {Colls+OrigColls,Recl+OrigRecl})
+ end.
+
diff --git a/erts/preloaded/src/prim_eval.S b/erts/preloaded/src/prim_eval.S
new file mode 100644
index 0000000000..958a79a1da
--- /dev/null
+++ b/erts/preloaded/src/prim_eval.S
@@ -0,0 +1,70 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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%
+%%
+{module, prim_eval}.
+
+%% This module uses low-level BEAM instructions for the message queue facility
+%% to allow erl_eval to evaluate receive expressions correctly.
+
+{exports, [{'receive',2},{module_info,0},{module_info,1}]}.
+
+{attributes, []}.
+
+{labels, 10}.
+
+
+{function, 'receive', 2, 2}.
+ {label,1}.
+ {func_info,{atom,prim_eval},{atom,'receive'},2}.
+ {label,2}.
+ {allocate,2,2}.
+ {move,{x,1},{y,0}}.
+ {move,{x,0},{y,1}}.
+ {label,3}.
+ {loop_rec,{f,5},{x,0}}.
+ {move,{y,1},{x,1}}.
+ {call_fun,1}.
+ {test,is_ne_exact,{f,4},[{x,0},{atom,nomatch}]}.
+ remove_message.
+ {deallocate,2}.
+ return.
+ {label,4}.
+ {loop_rec_end,{f,3}}.
+ {label,5}.
+ {wait_timeout,{f,3},{y,0}}.
+ timeout.
+ {move,{atom,timeout},{x,0}}.
+ {deallocate,2}.
+ return.
+
+
+{function, module_info, 0, 8}.
+ {label,6}.
+ {func_info,{atom,prim_eval},{atom,module_info},0}.
+ {label,7}.
+ {move,{atom,prim_eval},{x,0}}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 10}.
+ {label,8}.
+ {func_info,{atom,prim_eval},{atom,module_info},1}.
+ {label,9}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,prim_eval},{x,0}}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/erts/preloaded/src/prim_eval.erl b/erts/preloaded/src/prim_eval.erl
new file mode 100644
index 0000000000..ec5af8c138
--- /dev/null
+++ b/erts/preloaded/src/prim_eval.erl
@@ -0,0 +1,28 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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%
+%%
+-module(prim_eval).
+
+%% This module is simply a stub which abstract code gets included in the result
+%% of compilation of prim_eval.S, to keep Dialyzer happy.
+
+-export(['receive'/2]).
+
+-spec 'receive'(fun((term()) -> nomatch | T), timeout()) -> T.
+'receive'(_, _) ->
+ erlang:nif_error(stub).
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index d0e70aa95c..36a650cb5c 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2013. 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
@@ -151,30 +151,35 @@ shutdown_pend_loop(S, N0) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
close(S) when is_port(S) ->
- unlink(S), %% avoid getting {'EXIT', S, Reason}
case subscribe(S, [subs_empty_out_q]) of
{ok, [{subs_empty_out_q,N}]} when N > 0 ->
close_pend_loop(S, N); %% wait for pending output to be sent
_ ->
- catch erlang:port_close(S),
- ok
+ close_port(S)
end.
close_pend_loop(S, N) ->
receive
{empty_out_q,S} ->
- catch erlang:port_close(S), ok
+ close_port(S)
after ?INET_CLOSE_TIMEOUT ->
case getstat(S, [send_pend]) of
{ok, [{send_pend,N1}]} ->
- if N1 =:= N -> catch erlang:port_close(S), ok;
- true -> close_pend_loop(S, N1)
+ if
+ N1 =:= N ->
+ close_port(S);
+ true ->
+ close_pend_loop(S, N1)
end;
_ ->
- catch erlang:port_close(S), ok
+ close_port(S)
end
end.
-
+
+close_port(S) ->
+ catch erlang:port_close(S),
+ receive {'EXIT',S,_} -> ok after 0 -> ok end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% BIND(insock(), IP, Port) -> {ok, integer()} | {error, Reason}