aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/Makefile.in2
-rw-r--r--erts/emulator/beam/atom.c10
-rw-r--r--erts/emulator/beam/beam_bif_load.c16
-rw-r--r--erts/emulator/beam/beam_catches.c7
-rw-r--r--erts/emulator/beam/bif.tab2
-rw-r--r--erts/emulator/beam/erl_db_util.c11
-rw-r--r--erts/emulator/beam/erl_gc.c2
-rw-r--r--erts/emulator/beam/erl_init.c29
-rw-r--r--erts/emulator/beam/erl_printf_term.c63
-rw-r--r--erts/emulator/beam/erl_printf_term.h4
-rw-r--r--erts/emulator/beam/erl_process.c3
-rw-r--r--erts/emulator/beam/erl_smp.h18
-rw-r--r--erts/emulator/beam/erl_thr_queue.c161
-rw-r--r--erts/emulator/beam/erl_thr_queue.h13
-rw-r--r--erts/emulator/beam/erl_threads.h82
-rw-r--r--erts/emulator/beam/erl_unicode.c8
-rw-r--r--erts/emulator/beam/sys.h13
-rw-r--r--erts/emulator/drivers/common/efile_drv.c9
-rw-r--r--erts/emulator/drivers/common/inet_drv.c4
-rw-r--r--erts/emulator/hipe/hipe_bif0.c4
-rw-r--r--erts/emulator/hipe/hipe_native_bif.c4
-rw-r--r--erts/emulator/sys/common/erl_sys_common_misc.c16
-rw-r--r--erts/emulator/test/efile_SUITE.erl20
-rw-r--r--erts/emulator/test/hash_SUITE.erl10
24 files changed, 364 insertions, 147 deletions
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 7033ea0a3d..2877e58cdf 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -20,7 +20,7 @@
include $(ERL_TOP)/make/target.mk
include ../vsn.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-include $(TARGET)/gen_git_version.mk
+-include $(TARGET)/gen_git_version.mk
ENABLE_ALLOC_TYPE_VARS = @ENABLE_ALLOC_TYPE_VARS@
diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c
index b69f979397..84d2d5e3ed 100644
--- a/erts/emulator/beam/atom.c
+++ b/erts/emulator/beam/atom.c
@@ -132,9 +132,17 @@ atom_hash(Atom* obj)
byte* p = obj->name;
int len = obj->len;
HashValue h = 0, g;
+ byte v;
while(len--) {
- h = (h << 4) + *p++;
+ v = *p++;
+ /* latin1 clutch for r16 */
+ if ((v & 0xFE) == 0xC2 && (*p & 0xC0) == 0x80) {
+ v = (v << 6) | (*p & 0x3F);
+ p++; len--;
+ }
+ /* normal hashpjw follows for v */
+ h = (h << 4) + v;
if ((g = h & 0xf0000000)) {
h ^= (g >> 24);
h ^= g;
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 73264214ce..8a8239493a 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -1081,7 +1081,21 @@ beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module)
static int
is_native(BeamInstr* code)
{
- return ((Eterm *)code[MI_FUNCTIONS])[1] != 0;
+ Uint i, num_functions = code[MI_NUM_FUNCTIONS];
+
+ /* Check NativeAdress of first real function in module
+ */
+ for (i=0; i<num_functions; i++) {
+ BeamInstr* func_info = (BeamInstr *) code[MI_FUNCTIONS+i];
+ Eterm name = (Eterm) func_info[3];
+
+ if (is_atom(name)) {
+ return func_info[1] != 0;
+ }
+ else ASSERT(is_nil(name)); /* ignore BIF stubs */
+ }
+ /* Not a single non-BIF function? */
+ return 0;
}
diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c
index 7c92408eea..d374d0469e 100644
--- a/erts/emulator/beam/beam_catches.c
+++ b/erts/emulator/beam/beam_catches.c
@@ -160,10 +160,9 @@ void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes,
}
if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) {
erl_exit(1,
- "beam_catches_delmod: item %#x has cp %#lx which is not "
- "in module's range [%#lx,%#lx[\r\n",
- i, (long)p->beam_catches[i].cp,
- (long)code, (long)((char*)code + code_bytes));
+ "beam_catches_delmod: item %#x has cp %p which is not "
+ "in module's range [%p,%p[\r\n",
+ i, p->beam_catches[i].cp, code, ((char*)code + code_bytes));
}
p->beam_catches[i].cp = 0;
cdr = p->beam_catches[i].cdr;
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index b74dc5c3fe..8bc994c8c3 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -569,6 +569,8 @@ bif erlang:float_to_binary/1
bif erlang:float_to_binary/2
bif erlang:binary_to_float/1
+bif io:printable_range/0
+
#
# Obsolete
#
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index fc1c946c7d..713ac0ba18 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -3415,8 +3415,7 @@ static DMCRet dmc_one_term(DMCContext *context,
}
default:
erl_exit(1, "db_match_compile: "
- "Bad object on heap: 0x%08lx\n",
- (unsigned long) c);
+ "Bad object on heap: 0x%bex\n", c);
}
return retOk;
}
@@ -4861,7 +4860,7 @@ static Eterm my_copy_struct(Eterm t, Eterm **hp, ErlOffHeap* off_heap)
ret = copy_struct(b,sz,hp,off_heap);
} else {
erl_exit(1, "Trying to constant-copy non constant expression "
- "0x%08x in (d)ets:match compilation.", (unsigned long) t);
+ "0x%bex in (d)ets:match compilation.", t);
}
} else {
sz = size_object(t);
@@ -5395,7 +5394,7 @@ void db_match_dis(Binary *bp)
erts_printf("Caller\n");
break;
default:
- erts_printf("??? (0x%08x)\n", *t);
+ erts_printf("??? (0x%bpx)\n", *t);
++t;
break;
}
@@ -5407,13 +5406,13 @@ void db_match_dis(Binary *bp)
first = 0;
else
erts_printf(", ");
- erts_printf("0x%08x", (unsigned long) tmp);
+ erts_printf("%p", tmp);
}
erts_printf("}\n");
erts_printf("num_bindings: %d\n", prog->num_bindings);
erts_printf("heap_size: %beu\n", prog->heap_size);
erts_printf("stack_offset: %beu\n", prog->stack_offset);
- erts_printf("text: 0x%08x\n", (unsigned long) prog->text);
+ erts_printf("text: %p\n", prog->text);
erts_printf("stack_size: %d (words)\n", prog->heap_size-prog->stack_offset);
}
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index a33085315a..293d9fa3ec 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -231,7 +231,7 @@ erts_next_heap_size(Uint size, Uint offset)
low = mid + 1;
}
}
- erl_exit(1, "no next heap size found: %lu, offset %lu\n", (unsigned long)size, (unsigned long)offset);
+ erl_exit(1, "no next heap size found: %beu, offset %beu\n", size, offset);
}
return 0;
}
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index ec3e0d54cb..83853dcd43 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -496,7 +496,7 @@ void erts_usage(void)
erts_fprintf(stderr, "-d don't write a crash dump for internally detected errors\n");
erts_fprintf(stderr, " (halt(String) will still produce a crash dump)\n");
-
+ erts_fprintf(stderr, "-fn[u|a|l] Control how filenames are interpreted\n");
erts_fprintf(stderr, "-hms size set minimum heap size in words (default %d)\n",
H_DEFAULT_SIZE);
erts_fprintf(stderr, "-hmbs size set minimum binary virtual heap size in words (default %d)\n",
@@ -509,7 +509,7 @@ void erts_usage(void)
erts_fprintf(stderr, " Note that this flag is deprecated!\n");
erts_fprintf(stderr, "-M<X> <Y> memory allocator switches,\n");
erts_fprintf(stderr, " see the erts_alloc(3) documentation for more info.\n");
-
+ erts_fprintf(stderr, "-pc <set> Control what characters are considered printable (default latin1)\n");
erts_fprintf(stderr, "-P number set maximum number of processes on this node,\n");
erts_fprintf(stderr, " valid range is [%d-%d]\n",
ERTS_MIN_PROCESSES, ERTS_MAX_PROCESSES);
@@ -979,13 +979,30 @@ erl_start(int argc, char **argv)
VERBOSE(DEBUG_SYSTEM,
("using display items %d\n",display_items));
break;
+ case 'p':
+ if (!strncmp(argv[i],"-pc",3)) {
+ int printable_chars = ERL_PRINTABLE_CHARACTERS_LATIN1;
+ arg = get_arg(argv[i]+3, argv[i+1], &i);
+ if (!strcmp(arg,"unicode")) {
+ printable_chars = ERL_PRINTABLE_CHARACTERS_UNICODE;
+ } else if (strcmp(arg,"latin1")) {
+ erts_fprintf(stderr, "bad range of printable "
+ "characters: %s\n", arg);
+ erts_usage();
+ }
+ erts_set_printable_characters(printable_chars);
+ break;
+ } else {
+ erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]);
+ erts_usage();
+ }
case 'f':
if (!strncmp(argv[i],"-fn",3)) {
int warning_type = ERL_FILENAME_WARNING_WARNING;
arg = get_arg(argv[i]+3, argv[i+1], &i);
switch (*arg) {
case 'u':
- switch (*(argv[i]+4)) {
+ switch (*(arg+1)) {
case 'w':
case 0:
break;
@@ -997,7 +1014,7 @@ erl_start(int argc, char **argv)
break;
default:
erts_fprintf(stderr, "bad type of warnings for "
- "wrongly coded filename: %s\n", argv[i]+4);
+ "wrongly coded filename: %s\n", arg+1);
erts_usage();
}
erts_set_user_requested_filename_encoding
@@ -1014,7 +1031,7 @@ erl_start(int argc, char **argv)
);
break;
case 'a':
- switch (*(argv[i]+4)) {
+ switch (*(arg+1)) {
case 'w':
case 0:
break;
@@ -1026,7 +1043,7 @@ erl_start(int argc, char **argv)
break;
default:
erts_fprintf(stderr, "bad type of warnings for "
- "wrongly coded filename: %s\n", argv[i]+4);
+ "wrongly coded filename: %s\n", arg+1);
erts_usage();
}
erts_set_user_requested_filename_encoding
diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c
index 2320b64295..ce544503bd 100644
--- a/erts/emulator/beam/erl_printf_term.c
+++ b/erts/emulator/beam/erl_printf_term.c
@@ -57,17 +57,17 @@ do { \
(CNT) += res__; \
} while (0)
-#define PRINT_ULONG(CNT, FN, ARG, C, P, W, I) \
+#define PRINT_UWORD(CNT, FN, ARG, C, P, W, I) \
do { \
- int res__ = erts_printf_ulong((FN), (ARG), (C), (P), (W), (I)); \
+ int res__ = erts_printf_uword((FN), (ARG), (C), (P), (W), (I)); \
if (res__ < 0) \
return res__; \
(CNT) += res__; \
} while (0)
-#define PRINT_SLONG(CNT, FN, ARG, C, P, W, I) \
+#define PRINT_SWORD(CNT, FN, ARG, C, P, W, I) \
do { \
- int res__ = erts_printf_slong((FN), (ARG), (C), (P), (W), (I)); \
+ int res__ = erts_printf_sword((FN), (ARG), (C), (P), (W), (I)); \
if (res__ < 0) \
return res__; \
(CNT) += res__; \
@@ -153,7 +153,7 @@ static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount)
if ((i < 0) || (i >= atom_table_size()) || (atom_tab(i) == NULL)) {
PRINT_STRING(res, fn, arg, "<bad atom index: ");
- PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) i);
+ PRINT_SWORD(res, fn, arg, 'd', 0, 1, (ErlPfSWord) i);
PRINT_CHAR(res, fn, arg, '>');
return res;
}
@@ -203,7 +203,7 @@ static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount)
default:
if (IS_CNTRL(c)) {
PRINT_CHAR(res, fn, arg, '\\');
- PRINT_ULONG(res, fn, arg, 'o', 1, 3, (unsigned long) c);
+ PRINT_UWORD(res, fn, arg, 'o', 1, 3, (ErlPfUWord) c);
}
else
PRINT_CHAR(res, fn, arg, (char) c);
@@ -334,7 +334,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
break;
}
case SMALL_DEF:
- PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) signed_val(obj));
+ PRINT_SWORD(res, fn, arg, 'd', 0, 1, (ErlPfSWord) signed_val(obj));
break;
case BIG_DEF: {
int print_res;
@@ -360,36 +360,36 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
case REF_DEF:
case EXTERNAL_REF_DEF:
PRINT_STRING(res, fn, arg, "#Ref<");
- PRINT_ULONG(res, fn, arg, 'u', 0, 1,
- (unsigned long) ref_channel_no(wobj));
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1,
+ (ErlPfUWord) ref_channel_no(wobj));
ref_num = ref_numbers(wobj);
for (i = ref_no_of_numbers(wobj)-1; i >= 0; i--) {
PRINT_CHAR(res, fn, arg, '.');
- PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) ref_num[i]);
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1, (ErlPfUWord) ref_num[i]);
}
PRINT_CHAR(res, fn, arg, '>');
break;
case PID_DEF:
case EXTERNAL_PID_DEF:
PRINT_CHAR(res, fn, arg, '<');
- PRINT_ULONG(res, fn, arg, 'u', 0, 1,
- (unsigned long) pid_channel_no(wobj));
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1,
+ (ErlPfUWord) pid_channel_no(wobj));
PRINT_CHAR(res, fn, arg, '.');
- PRINT_ULONG(res, fn, arg, 'u', 0, 1,
- (unsigned long) pid_number(wobj));
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1,
+ (ErlPfUWord) pid_number(wobj));
PRINT_CHAR(res, fn, arg, '.');
- PRINT_ULONG(res, fn, arg, 'u', 0, 1,
- (unsigned long) pid_serial(wobj));
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1,
+ (ErlPfUWord) pid_serial(wobj));
PRINT_CHAR(res, fn, arg, '>');
break;
case PORT_DEF:
case EXTERNAL_PORT_DEF:
PRINT_STRING(res, fn, arg, "#Port<");
- PRINT_ULONG(res, fn, arg, 'u', 0, 1,
- (unsigned long) port_channel_no(wobj));
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1,
+ (ErlPfUWord) port_channel_no(wobj));
PRINT_CHAR(res, fn, arg, '.');
- PRINT_ULONG(res, fn, arg, 'u', 0, 1,
- (unsigned long) port_number(wobj));
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1,
+ (ErlPfUWord) port_number(wobj));
PRINT_CHAR(res, fn, arg, '>');
break;
case LIST_DEF:
@@ -446,7 +446,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
PRINT_STRING(res, fn, arg, "<<1 byte>>");
else {
PRINT_STRING(res, fn, arg, "<<");
- PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) pb->size);
+ PRINT_UWORD(res, fn, arg, 'u', 0, 1, (ErlPfUWord) pb->size);
PRINT_STRING(res, fn, arg, " bytes>>");
}
}
@@ -462,8 +462,8 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
PRINT_CHAR(res, fn, arg, '.');
PRINT_BUF(res, fn, arg, name->name, name->len);
PRINT_CHAR(res, fn, arg, '.');
- PRINT_SLONG(res, fn, arg, 'd', 0, 1,
- (signed long) ep->code[2]);
+ PRINT_SWORD(res, fn, arg, 'd', 0, 1,
+ (ErlPfSWord) ep->code[2]);
PRINT_CHAR(res, fn, arg, '>');
}
break;
@@ -475,11 +475,11 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
PRINT_STRING(res, fn, arg, "#Fun<");
PRINT_BUF(res, fn, arg, ap->name, ap->len);
PRINT_CHAR(res, fn, arg, '.');
- PRINT_SLONG(res, fn, arg, 'd', 0, 1,
- (signed long) funp->fe->old_index);
+ PRINT_SWORD(res, fn, arg, 'd', 0, 1,
+ (ErlPfSWord) funp->fe->old_index);
PRINT_CHAR(res, fn, arg, '.');
- PRINT_SLONG(res, fn, arg, 'd', 0, 1,
- (signed long) funp->fe->old_uniq);
+ PRINT_SWORD(res, fn, arg, 'd', 0, 1,
+ (ErlPfSWord) funp->fe->old_uniq);
PRINT_CHAR(res, fn, arg, '>');
}
break;
@@ -498,10 +498,13 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
}
int
-erts_printf_term(fmtfn_t fn, void* arg, unsigned long term, long precision,
- unsigned long* term_base)
+erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision,
+ ErlPfEterm* term_base)
{
- int res = print_term(fn, arg, (Eterm)term, &precision, (Eterm*)term_base);
+ int res;
+ ASSERT(sizeof(ErlPfEterm) == sizeof(Eterm));
+
+ res = print_term(fn, arg, (Eterm)term, &precision, (Eterm*)term_base);
if (res < 0)
return res;
if (precision <= 0)
diff --git a/erts/emulator/beam/erl_printf_term.h b/erts/emulator/beam/erl_printf_term.h
index a48a3de34c..d9bf79a5ce 100644
--- a/erts/emulator/beam/erl_printf_term.h
+++ b/erts/emulator/beam/erl_printf_term.h
@@ -21,6 +21,6 @@
#define ERL_PRINTF_TERM_H__
#include "erl_printf_format.h"
-int erts_printf_term(fmtfn_t fn, void* arg, unsigned long term, long precision,
- unsigned long* term_base);
+int erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision,
+ ErlPfEterm* term_base);
#endif
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 96af19fb83..00247b387a 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -4311,8 +4311,7 @@ erts_sched_set_wakeup_other_type(char *str)
wakeup_other.type = type;
return 0;
#else
- if (sys_strcmp(str, "proposal") == 0 || sys_strcmp(str, "default") == 0 ||
- sys_strcmp(str, "legacy") == 0) {
+ if (sys_strcmp(str, "default") == 0 || sys_strcmp(str, "legacy") == 0) {
return 0;
}
return EINVAL;
diff --git a/erts/emulator/beam/erl_smp.h b/erts/emulator/beam/erl_smp.h
index 34c90c0bda..0dd9e29e8e 100644
--- a/erts/emulator/beam/erl_smp.h
+++ b/erts/emulator/beam/erl_smp.h
@@ -259,6 +259,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_dw_atomic_read_wb erts_dw_atomic_read_wb
#define erts_smp_dw_atomic_cmpxchg_wb erts_dw_atomic_cmpxchg_wb
+#define erts_smp_dw_atomic_set_dirty erts_dw_atomic_set_dirty
+#define erts_smp_dw_atomic_read_dirty erts_dw_atomic_read_dirty
+
/* Word size atomics */
#define erts_smp_atomic_init_nob erts_atomic_init_nob
@@ -366,6 +369,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_cmpxchg_wb erts_atomic_cmpxchg_wb
#define erts_smp_atomic_read_bset_wb erts_atomic_read_bset_wb
+#define erts_smp_atomic_set_dirty erts_atomic_set_dirty
+#define erts_smp_atomic_read_dirty erts_atomic_read_dirty
+
/* 32-bit atomics */
#define erts_smp_atomic32_init_nob erts_atomic32_init_nob
@@ -473,6 +479,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_cmpxchg_wb erts_atomic32_cmpxchg_wb
#define erts_smp_atomic32_read_bset_wb erts_atomic32_read_bset_wb
+#define erts_smp_atomic32_set_dirty erts_atomic32_set_dirty
+#define erts_smp_atomic32_read_dirty erts_atomic32_read_dirty
+
#else /* !ERTS_SMP */
/* Double word size atomics */
@@ -512,6 +521,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_dw_atomic_read_wb erts_no_dw_atomic_read
#define erts_smp_dw_atomic_cmpxchg_wb erts_no_dw_atomic_cmpxchg
+#define erts_smp_dw_atomic_set_dirty erts_no_dw_atomic_set
+#define erts_smp_dw_atomic_read_dirty erts_no_dw_atomic_read
+
/* Word size atomics */
#define erts_smp_atomic_init_nob erts_no_atomic_set
@@ -619,6 +631,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_cmpxchg_wb erts_no_atomic_cmpxchg
#define erts_smp_atomic_read_bset_wb erts_no_atomic_read_bset
+#define erts_smp_atomic_set_dirty erts_no_atomic_set
+#define erts_smp_atomic_read_dirty erts_no_atomic_read
+
/* 32-bit atomics */
#define erts_smp_atomic32_init_nob erts_no_atomic32_set
@@ -726,6 +741,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_cmpxchg_wb erts_no_atomic32_cmpxchg
#define erts_smp_atomic32_read_bset_wb erts_no_atomic32_read_bset
+#define erts_smp_atomic32_set_dirty erts_no_atomic32_set
+#define erts_smp_atomic32_read_dirty erts_no_atomic32_read
+
#endif /* !ERTS_SMP */
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c
index f07964a265..ee2ff765e0 100644
--- a/erts/emulator/beam/erl_thr_queue.c
+++ b/erts/emulator/beam/erl_thr_queue.c
@@ -113,6 +113,11 @@ sl_element_free(ErtsThrQElement_t *p)
#endif
+#define ErtsThrQDirtyReadEl(A) \
+ ((ErtsThrQElement_t *) erts_atomic_read_dirty((A)))
+#define ErtsThrQDirtySetEl(A, V) \
+ erts_atomic_set_dirty((A), (erts_aint_t) (V))
+
typedef union {
ErtsThrQ_t q;
char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsThrQ_t))];
@@ -137,7 +142,7 @@ erts_thr_q_initialize(ErtsThrQ_t *q, ErtsThrQInit_t *qi)
q->last = NULL;
q->q.blk = NULL;
#else
- erts_atomic_init_nob(&q->tail.data.marker.next.atmc, ERTS_AINT_NULL);
+ erts_atomic_init_nob(&q->tail.data.marker.next, ERTS_AINT_NULL);
q->tail.data.marker.data.ptr = NULL;
erts_atomic_init_nob(&q->tail.data.last,
(erts_aint_t) &q->tail.data.marker);
@@ -150,7 +155,7 @@ erts_thr_q_initialize(ErtsThrQ_t *q, ErtsThrQInit_t *qi)
if (!q->tail.data.notify)
q->tail.data.notify = noop_callback;
- q->head.head.ptr = &q->tail.data.marker;
+ erts_atomic_init_nob(&q->head.head, (erts_aint_t) &q->tail.data.marker);
q->head.live = qi->live.objects;
q->head.first = &q->tail.data.marker;
q->head.unref_end = &q->tail.data.marker;
@@ -296,17 +301,17 @@ element_free(ErtsThrQ_t *q, ErtsThrQElement_t *el)
#ifdef USE_THREADS
static ERTS_INLINE ErtsThrQElement_t *
-enqueue_managed(ErtsThrQ_t *q, ErtsThrQElement_t *this, int want_last)
+enqueue_managed(ErtsThrQ_t *q, ErtsThrQElement_t *this)
{
erts_aint_t ilast, itmp;
- erts_atomic_init_nob(&this->next.atmc, ERTS_AINT_NULL);
+ erts_atomic_init_nob(&this->next, ERTS_AINT_NULL);
/* Enqueue at end of list... */
ilast = erts_atomic_read_nob(&q->tail.data.last);
while (1) {
ErtsThrQElement_t *last = (ErtsThrQElement_t *) ilast;
- itmp = erts_atomic_cmpxchg_mb(&last->next.atmc,
+ itmp = erts_atomic_cmpxchg_mb(&last->next,
(erts_aint_t) this,
ERTS_AINT_NULL);
if (itmp == ERTS_AINT_NULL)
@@ -316,31 +321,57 @@ enqueue_managed(ErtsThrQ_t *q, ErtsThrQElement_t *this, int want_last)
/* Move last pointer forward... */
while (1) {
- if (want_last) {
- if (erts_atomic_read_rb(&this->next.atmc) != ERTS_AINT_NULL) {
- /* Someone else will move it forward */
- ilast = erts_atomic_read_rb(&q->tail.data.last);
- return (ErtsThrQElement_t *) ilast;
- }
- }
- else {
- if (erts_atomic_read_nob(&this->next.atmc) != ERTS_AINT_NULL) {
- /* Someone else will move it forward */
- return NULL;
- }
+ if (erts_atomic_read_rb(&this->next) != ERTS_AINT_NULL) {
+ /* Someone else will move it forward */
+ ilast = erts_atomic_read_rb(&q->tail.data.last);
+ return (ErtsThrQElement_t *) ilast;
}
itmp = erts_atomic_cmpxchg_mb(&q->tail.data.last,
(erts_aint_t) this,
ilast);
if (ilast == itmp)
- return want_last ? this : NULL;
+ return this;
ilast = itmp;
}
}
+static ERTS_INLINE ErtsThrQElement_t *
+enqueue_marker(ErtsThrQ_t *q, ErtsThrQElement_t **headp)
+{
+ int maybe_notify;
+ erts_aint_t inext;
+ ErtsThrQElement_t *last, *head;
+
+ if (headp)
+ head = *headp;
+ else
+ head = ErtsThrQDirtyReadEl(&q->head.head);
+
+ ASSERT(!q->head.used_marker);
+ q->head.used_marker = 1;
+ last = enqueue_managed(q, &q->tail.data.marker);
+ maybe_notify = &q->tail.data.marker == last;
+ inext = erts_atomic_read_acqb(&head->next);
+ if (inext == (erts_aint_t) &q->tail.data.marker) {
+ ErtsThrQDirtySetEl(&q->head.head, &q->tail.data.marker);
+ if (headp)
+ *headp = &q->tail.data.marker;
+ }
+ else if (maybe_notify) {
+ /*
+ * We need to notify; otherwise, we might loose a notification
+ * for a concurrently inserted element.
+ */
+ q->head.notify(q->head.arg);
+ }
+ return last;
+}
+
+
static ErtsThrQCleanState_t
clean(ErtsThrQ_t *q, int max_ops, int do_notify)
{
+ ErtsThrQElement_t *head;
erts_aint_t ilast;
int um_refc_ix;
int ops;
@@ -349,7 +380,8 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify)
ErtsThrQElement_t *tmp;
restart:
ASSERT(q->head.first);
- if (q->head.first == q->head.head.ptr) {
+ head = ErtsThrQDirtyReadEl(&q->head.head);
+ if (q->head.first == head) {
q->head.clean_reached_head_count++;
if (q->head.clean_reached_head_count
>= ERTS_THR_Q_MAX_CLEAN_REACHED_HEAD_COUNT) {
@@ -362,19 +394,20 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify)
break;
if (q->head.first == &q->tail.data.marker) {
q->head.used_marker = 0;
- q->head.first = q->head.first->next.ptr;
+ q->head.first = ErtsThrQDirtyReadEl(&q->head.first->next);
goto restart;
}
tmp = q->head.first;
- q->head.first = q->head.first->next.ptr;
+ q->head.first = ErtsThrQDirtyReadEl(&q->head.first->next);
if (q->head.deq_fini.automatic)
element_free(q, tmp);
else {
tmp->data.ptr = (void *) (UWord) q->head.live;
if (!q->head.deq_fini.start)
q->head.deq_fini.start = tmp;
- else if (q->head.deq_fini.end->next.ptr == &q->tail.data.marker)
- q->head.deq_fini.end->next.ptr = tmp;
+ else if (ErtsThrQDirtyReadEl(&q->head.deq_fini.end->next)
+ == &q->tail.data.marker)
+ ErtsThrQDirtySetEl(&q->head.deq_fini.end->next, tmp);
q->head.deq_fini.end = tmp;
}
}
@@ -401,21 +434,8 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify)
q->head.unref_end = q->head.next.unref_end;
if (!q->head.used_marker
- && q->head.unref_end == (ErtsThrQElement_t *) ilast) {
- q->head.used_marker = 1;
- ilast = (erts_aint_t) enqueue_managed(q,
- &q->tail.data.marker,
- 1);
- if (q->head.head.ptr == q->head.unref_end) {
- ErtsThrQElement_t *next;
- next = ((ErtsThrQElement_t *)
- erts_atomic_read_acqb(&q->head.head.ptr->next.atmc));
- if (next == &q->tail.data.marker) {
- q->head.head.ptr->next.ptr = &q->tail.data.marker;
- q->head.head.ptr = &q->tail.data.marker;
- }
- }
- }
+ && q->head.unref_end == (ErtsThrQElement_t *) ilast)
+ ilast = (erts_aint_t) enqueue_marker(q, NULL);
if (q->head.unref_end == (ErtsThrQElement_t *) ilast)
ERTS_SMP_MEMORY_BARRIER;
@@ -436,20 +456,16 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify)
}
#endif
- if (q->head.first == q->head.head.ptr) {
+ head = ErtsThrQDirtyReadEl(&q->head.head);
+ if (q->head.first == head) {
inspect_head:
if (!q->head.used_marker) {
erts_aint_t inext;
- inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
+ inext = erts_atomic_read_acqb(&head->next);
if (inext == ERTS_AINT_NULL) {
- q->head.used_marker = 1;
- (void) enqueue_managed(q, &q->tail.data.marker, 0);
- inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
- if (inext == (erts_aint_t) &q->tail.data.marker) {
- q->head.head.ptr->next.ptr = &q->tail.data.marker;
- q->head.head.ptr = &q->tail.data.marker;
+ enqueue_marker(q, &head);
+ if (head == &q->tail.data.marker)
goto check_thr_progress;
- }
}
}
@@ -506,26 +522,27 @@ erts_thr_q_inspect(ErtsThrQ_t *q, int ensure_empty)
#ifndef USE_THREADS
return ERTS_THR_Q_CLEAN;
#else
+ ErtsThrQElement_t *head = ErtsThrQDirtyReadEl(&q->head.head);
if (ensure_empty) {
erts_aint_t inext;
- inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
+ inext = erts_atomic_read_acqb(&head->next);
if (inext != ERTS_AINT_NULL) {
if (&q->tail.data.marker != (ErtsThrQElement_t *) inext)
return ERTS_THR_Q_DIRTY;
else {
- q->head.head.ptr->next.ptr = (ErtsThrQElement_t *) inext;
- q->head.head.ptr = (ErtsThrQElement_t *) inext;
- inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
+ head = (ErtsThrQElement_t *) inext;
+ ErtsThrQDirtySetEl(&q->head.head, head);
+ inext = erts_atomic_read_acqb(&head->next);
if (inext != ERTS_AINT_NULL)
return ERTS_THR_Q_DIRTY;
}
}
}
- if (q->head.first == q->head.head.ptr) {
+ if (q->head.first == head) {
if (!q->head.used_marker) {
erts_aint_t inext;
- inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
+ inext = erts_atomic_read_acqb(&head->next);
if (inext == ERTS_AINT_NULL)
return ERTS_THR_Q_DIRTY;
}
@@ -553,11 +570,11 @@ enqueue(ErtsThrQ_t *q, void *data, ErtsThrQElement_t *this)
#ifndef USE_THREADS
ASSERT(data);
- this->next.ptr = NULL;
+ this->next = NULL;
this->data.ptr = data;
if (q->last)
- q->last->next.ptr = this;
+ q->last->next = this;
else {
q->first = q->last = this;
q->init.notify(q->init.arg);
@@ -595,7 +612,7 @@ enqueue(ErtsThrQ_t *q, void *data, ErtsThrQElement_t *this)
}
}
- notify = this == enqueue_managed(q, this, 1);
+ notify = this == enqueue_managed(q, this);
#ifdef ERTS_SMP
@@ -638,17 +655,17 @@ erts_thr_q_get_finalize_dequeue_data(ErtsThrQ_t *q, ErtsThrQFinDeQ_t *fdp)
ErtsThrQElement_t *e = q->head.deq_fini.start;
ErtsThrQElement_t *end = q->head.deq_fini.end;
while (e != end) {
- ASSERT(q->head.head.ptr != e);
+ ASSERT(ErtsThrQDirtyReadEl(&q->head.head) != e);
ASSERT(q->head.first != e);
ASSERT(q->head.unref_end != e);
- e = e->next.ptr;
+ e = ErtsThrQDirtyReadEl(&e->next);
}
}
#endif
fdp->start = q->head.deq_fini.start;
fdp->end = q->head.deq_fini.end;
if (fdp->end)
- fdp->end->next.ptr = NULL;
+ ErtsThrQDirtySetEl(&fdp->end->next, NULL);
q->head.deq_fini.start = NULL;
q->head.deq_fini.end = NULL;
return fdp->start != NULL;
@@ -662,7 +679,7 @@ erts_thr_q_append_finalize_dequeue_data(ErtsThrQFinDeQ_t *fdp0,
#ifdef USE_THREADS
if (fdp1->start) {
if (fdp0->end)
- fdp0->end->next.ptr = fdp1->start;
+ ErtsThrQDirtySetEl(&fdp0->end->next, fdp1->start);
else
fdp0->start = fdp1->start;
fdp0->end = fdp1->end;
@@ -683,7 +700,7 @@ int erts_thr_q_finalize_dequeue(ErtsThrQFinDeQ_t *state)
if (!start)
break;
tmp = start;
- start = start->next.ptr;
+ start = ErtsThrQDirtyReadEl(&start->next);
live = (ErtsThrQLive_t) (UWord) tmp->data.ptr;
element_live_free(live, tmp);
}
@@ -724,7 +741,7 @@ erts_thr_q_dequeue(ErtsThrQ_t *q)
return NULL;
tmp = q->first;
res = tmp->data.ptr;
- q->first = tmp->next.ptr;
+ q->first = tmp->next;
if (!q->first)
q->last = NULL;
@@ -732,24 +749,26 @@ erts_thr_q_dequeue(ErtsThrQ_t *q)
return res;
#else
+ ErtsThrQElement_t *head;
erts_aint_t inext;
void *res;
- inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
+ head = ErtsThrQDirtyReadEl(&q->head.head);
+ inext = erts_atomic_read_acqb(&head->next);
if (inext == ERTS_AINT_NULL)
return NULL;
- q->head.head.ptr->next.ptr = (ErtsThrQElement_t *) inext;
- q->head.head.ptr = (ErtsThrQElement_t *) inext;
- if (q->head.head.ptr == &q->tail.data.marker) {
- inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
+ head = (ErtsThrQElement_t *) inext;
+ ErtsThrQDirtySetEl(&q->head.head, head);
+ if (head == &q->tail.data.marker) {
+ inext = erts_atomic_read_acqb(&head->next);
if (inext == ERTS_AINT_NULL)
return NULL;
- q->head.head.ptr->next.ptr = (ErtsThrQElement_t *) inext;
- q->head.head.ptr = (ErtsThrQElement_t *) inext;
+ head = (ErtsThrQElement_t *) inext;
+ ErtsThrQDirtySetEl(&q->head.head, head);
}
- res = q->head.head.ptr->data.ptr;
+ res = head->data.ptr;
#if ERTS_THR_Q_DBG_CHK_DATA
- q->head.head.ptr->data.ptr = NULL;
+ head->data.ptr = NULL;
if (!res)
erl_exit(ERTS_ABORT_EXIT, "Missing data in dequeue\n");
#endif
diff --git a/erts/emulator/beam/erl_thr_queue.h b/erts/emulator/beam/erl_thr_queue.h
index edcf2c3823..ae8c7fb19a 100644
--- a/erts/emulator/beam/erl_thr_queue.h
+++ b/erts/emulator/beam/erl_thr_queue.h
@@ -76,13 +76,12 @@ typedef struct {
typedef struct ErtsThrQElement_t_ ErtsThrQElement_t;
typedef struct ErtsThrQElement_t ErtsThrQPrepEnQ_t;
-typedef union {
- erts_atomic_t atmc;
- ErtsThrQElement_t *ptr;
-} ErtsThrQPtr_t;
-
struct ErtsThrQElement_t_ {
- ErtsThrQPtr_t next;
+#ifdef USE_THREADS
+ erts_atomic_t next;
+#else
+ ErtsThrQElement_t *next;
+#endif
union {
erts_atomic_t atmc;
void *ptr;
@@ -130,7 +129,7 @@ struct ErtsThrQ_t_ {
* thread dequeuing.
*/
struct {
- ErtsThrQPtr_t head;
+ erts_atomic_t head;
ErtsThrQLive_t live;
ErtsThrQElement_t *first;
ErtsThrQElement_t *unref_end;
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index 1dc3ffeb3c..594d38b2a1 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -690,6 +690,19 @@ do { \
} while (0)
#endif
+ERTS_GLB_INLINE void
+erts_dw_atomic_set_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val);
+ERTS_GLB_INLINE void
+erts_dw_atomic_read_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val);
+ERTS_GLB_INLINE void
+erts_atomic_set_dirty(erts_atomic_t *var, erts_aint_t val);
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_dirty(erts_atomic_t *var);
+ERTS_GLB_INLINE void
+erts_atomic32_set_dirty(erts_atomic32_t *var, erts_aint32_t val);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_dirty(erts_atomic32_t *var);
+
/*
* See "Documentation of atomics and memory barriers" at the top
* of this file for info on atomics.
@@ -732,6 +745,26 @@ do { \
#define erts_dw_atomic_read_wb ethr_dw_atomic_read_wb
#define erts_dw_atomic_cmpxchg_wb ethr_dw_atomic_cmpxchg_wb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE void
+erts_dw_atomic_set_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val)
+{
+ ethr_sint_t *sint = ethr_dw_atomic_addr(var);
+ sint[0] = val->sint[0];
+ sint[1] = val->sint[1];
+}
+
+ERTS_GLB_INLINE void
+erts_dw_atomic_read_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val)
+{
+ ethr_sint_t *sint = ethr_dw_atomic_addr(var);
+ val->sint[0] = sint[0];
+ val->sint[1] = sint[1];
+}
+
+#endif
+
/* Word size atomics */
#define erts_atomic_init_nob ethr_atomic_init
@@ -911,6 +944,7 @@ erts_atomic_read_bset_rb(erts_atomic_t *var,
#define erts_atomic_cmpxchg_wb ethr_atomic_cmpxchg_wb
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
ERTS_GLB_INLINE erts_aint_t
erts_atomic_read_bset_wb(erts_atomic_t *var,
erts_aint_t mask,
@@ -921,6 +955,25 @@ erts_atomic_read_bset_wb(erts_atomic_t *var,
ethr_atomic_cmpxchg_wb,
var, mask, set);
}
+
+#endif
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE void
+erts_atomic_set_dirty(erts_atomic_t *var, erts_aint_t val)
+{
+ ethr_sint_t *sint = ethr_atomic_addr(var);
+ *sint = val;
+}
+
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_dirty(erts_atomic_t *var)
+{
+ ethr_sint_t *sint = ethr_atomic_addr(var);
+ return *sint;
+}
+
#endif
/* 32-bit atomics */
@@ -1102,6 +1155,7 @@ erts_atomic32_read_bset_rb(erts_atomic32_t *var,
#define erts_atomic32_cmpxchg_wb ethr_atomic32_cmpxchg_wb
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
ERTS_GLB_INLINE erts_aint32_t
erts_atomic32_read_bset_wb(erts_atomic32_t *var,
erts_aint32_t mask,
@@ -1112,10 +1166,29 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var,
ethr_atomic32_cmpxchg_wb,
var, mask, set);
}
+
#endif
#undef ERTS_ATOMIC_BSET_IMPL__
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE void
+erts_atomic32_set_dirty(erts_atomic32_t *var, erts_aint32_t val)
+{
+ ethr_sint32_t *sint = ethr_atomic32_addr(var);
+ *sint = val;
+}
+
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_dirty(erts_atomic32_t *var)
+{
+ ethr_sint32_t *sint = ethr_atomic32_addr(var);
+ return *sint;
+}
+
+#endif
+
#else /* !USE_THREADS */
/* Double word size atomics */
@@ -1155,6 +1228,9 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var,
#define erts_dw_atomic_read_wb erts_no_dw_atomic_read
#define erts_dw_atomic_cmpxchg_wb erts_no_dw_atomic_cmpxchg
+#define erts_dw_atomic_set_dirty erts_no_dw_atomic_set
+#define erts_dw_atomic_read_dirty erts_no_dw_atomic_read
+
/* Word size atomics */
#define erts_atomic_init_nob erts_no_atomic_set
@@ -1262,6 +1338,9 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var,
#define erts_atomic_cmpxchg_wb erts_no_atomic_cmpxchg
#define erts_atomic_read_bset_wb erts_no_atomic_read_bset
+#define erts_atomic_set_dirty erts_no_atomic_set
+#define erts_atomic_read_dirty erts_no_atomic_read
+
/* 32-bit atomics */
#define erts_atomic32_init_nob erts_no_atomic32_set
@@ -1369,6 +1448,9 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var,
#define erts_atomic32_cmpxchg_wb erts_no_atomic32_cmpxchg
#define erts_atomic32_read_bset_wb erts_no_atomic32_read_bset
+#define erts_atomic32_set_dirty erts_no_atomic32_set
+#define erts_atomic32_read_dirty erts_no_atomic32_read
+
#endif /* !USE_THREADS */
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index 80982f3760..fa53fd0937 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -2747,3 +2747,11 @@ int erts_utf8_to_latin1(byte* dest, const byte* source, int slen)
return dp - dest;
}
+BIF_RETTYPE io_printable_range_0(BIF_ALIST_0)
+{
+ if (erts_get_printable_characters() == ERL_PRINTABLE_CHARACTERS_UNICODE) {
+ BIF_RET(am_unicode);
+ } else {
+ BIF_RET(am_latin1);
+ }
+}
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 9416a91480..05bff430e3 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -1040,11 +1040,24 @@ char* win32_errorstr(int);
#define ERL_FILENAME_WARNING_IGNORE (1)
#define ERL_FILENAME_WARNING_ERROR (2)
+/***********************************************************************
+ * The user can request a range of character that he/she consider
+ * printable. Currently this can be either latin1 or unicode, but
+ * in the future a set of ranges, or languages, could be specified.
+ ***********************************************************************/
+#define ERL_PRINTABLE_CHARACTERS_LATIN1 (0)
+#define ERL_PRINTABLE_CHARACTERS_UNICODE (1)
+
int erts_get_native_filename_encoding(void);
/* The set function is only to be used by erl_init! */
void erts_set_user_requested_filename_encoding(int encoding, int warning);
int erts_get_user_requested_filename_encoding(void);
int erts_get_filename_warning_type(void);
+/* This function is called from erl_init. The setting is read by BIF's
+ in io/io_lib. Setting is not atomic. */
+void erts_set_printable_characters(int range);
+/* Get the setting (ERL_PRINTABLE_CHARACTERS_{LATIN1|UNICODE} */
+int erts_get_printable_characters(void);
void erts_init_sys_common_misc(void);
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 2279fec72a..22328fcd11 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -1160,7 +1160,14 @@ static void invoke_read_line(void *data)
/* Need more place */
ErlDrvSizeT need = (d->c.read_line.read_size >= DEFAULT_LINEBUF_SIZE) ?
d->c.read_line.read_size + DEFAULT_LINEBUF_SIZE : DEFAULT_LINEBUF_SIZE;
- ErlDrvBinary *newbin = driver_alloc_binary(need);
+ ErlDrvBinary *newbin;
+#if !ALWAYS_READ_LINE_AHEAD
+ /* Use read_ahead size if need does not exceed it */
+ if (need < (d->c.read_line.binp)->orig_size &&
+ d->c.read_line.read_ahead)
+ need = (d->c.read_line.binp)->orig_size;
+#endif
+ newbin = driver_alloc_binary(need);
if (newbin == NULL) {
d->result_ok = 0;
d->errInfo.posix_errno = ENOMEM;
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index f0c22e9ebe..3832cf1227 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -7834,7 +7834,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (!IS_CONNECTED(desc))
return ctl_error(ENOTCONN, rbuf, rsize);
- if (!desc->stype == SOCK_STREAM)
+ if (desc->stype != SOCK_STREAM)
return ctl_error(EINVAL, rbuf, rsize);
if (*buf == 1 && !desc->is_ignored) {
@@ -8816,7 +8816,7 @@ static int tcp_recv_error(tcp_descriptor* desc, int err)
if (desc->inet.exitf)
driver_exit(desc->inet.port, err);
else
- desc_close(INETP(desc));
+ desc_close_read(INETP(desc));
}
return -1;
}
diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c
index 1562748f2d..059c013322 100644
--- a/erts/emulator/hipe/hipe_bif0.c
+++ b/erts/emulator/hipe/hipe_bif0.c
@@ -1791,7 +1791,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1)
if (BIF_ARG_1 == am_all) {
hipe_purge_all_refs();
- BIF_RET(NIL);
+ BIF_RET(am_ok);
}
if (!term_to_mfa(BIF_ARG_1, &mfa))
@@ -1828,7 +1828,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1)
caller_mfa->refers_to = NULL;
}
hipe_mfa_info_table_unlock();
- BIF_RET(NIL);
+ BIF_RET(am_ok);
}
diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c
index 3be821f8f7..af1c36777f 100644
--- a/erts/emulator/hipe/hipe_native_bif.c
+++ b/erts/emulator/hipe/hipe_native_bif.c
@@ -503,9 +503,7 @@ static int validate_unicode(Eterm arg)
{
if (is_not_small(arg) ||
arg > make_small(0x10FFFFUL) ||
- (make_small(0xD800UL) <= arg && arg <= make_small(0xDFFFUL)) ||
- arg == make_small(0xFFFEUL) ||
- arg == make_small(0xFFFFUL))
+ (make_small(0xD800UL) <= arg && arg <= make_small(0xDFFFUL)))
return 0;
return 1;
}
diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c
index 0b31c125e5..31ad3b82d5 100644
--- a/erts/emulator/sys/common/erl_sys_common_misc.c
+++ b/erts/emulator/sys/common/erl_sys_common_misc.c
@@ -49,10 +49,15 @@
static int filename_encoding = ERL_FILENAME_UNKNOWN;
static int filename_warning = ERL_FILENAME_WARNING_WARNING;
#if defined(__WIN32__) || defined(__DARWIN__)
-static int user_filename_encoding = ERL_FILENAME_UTF8; /* Default unicode on windows */
+/* Default unicode on windows and MacOS X */
+static int user_filename_encoding = ERL_FILENAME_UTF8;
#else
static int user_filename_encoding = ERL_FILENAME_LATIN1;
#endif
+/* This controls the heuristic in printing characters in shell and w/
+ io:format("~tp", ...) etc. */
+static int printable_character_set = ERL_PRINTABLE_CHARACTERS_LATIN1;
+
void erts_set_user_requested_filename_encoding(int encoding, int warning)
{
user_filename_encoding = encoding;
@@ -69,6 +74,15 @@ int erts_get_filename_warning_type(void)
return filename_warning;
}
+void erts_set_printable_characters(int range) {
+ /* Not an atomic */
+ printable_character_set = range;
+}
+
+int erts_get_printable_characters(void) {
+ return printable_character_set;
+}
+
void erts_init_sys_common_misc(void)
{
#if defined(__WIN32__)
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index 9ac004200e..ddf23f90fd 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -21,6 +21,8 @@
init_per_group/2,end_per_group/2]).
-export([iter_max_files/1]).
+-export([do_iter_max_files/2]).
+
-include_lib("test_server/include/test_server.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -51,11 +53,17 @@ end_per_group(_GroupName, Config) ->
iter_max_files(suite) -> [];
iter_max_files(Config) when is_list(Config) ->
- ?line DataDir = ?config(data_dir,Config),
- ?line TestFile = filename:join(DataDir, "existing_file"),
- ?line L = do_iter_max_files(10, TestFile),
- ?line io:format("Number of files opened in each test:~n~w\n", [L]),
- ?line all_equal(L),
+ DataDir = ?config(data_dir,Config),
+ TestFile = filename:join(DataDir, "existing_file"),
+ N = 10,
+ %% Run on a different node in order to set the max ports
+ Dir = filename:dirname(code:which(?MODULE)),
+ {ok,Node} = test_server:start_node(test_iter_max_files,slave,
+ [{args,"+Q 1524 -pa " ++ Dir}]),
+ L = rpc:call(Node,?MODULE,do_iter_max_files,[N, TestFile]),
+ test_server:stop_node(Node),
+ io:format("Number of files opened in each test:~n~w\n", [L]),
+ all_equal(L),
Head = hd(L),
if Head >= 2 -> ok;
true -> ?line test_server:fail(too_few_files)
@@ -91,6 +99,6 @@ open_files(Name) ->
{ok, Fd} ->
[Fd| open_files(Name)];
{error, Reason} ->
- io:format("Error reason: ~p", [Reason]),
+% io:format("Error reason: ~p", [Reason]),
[]
end.
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index 898eae8c15..e34050cd07 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -363,6 +364,15 @@ phash2_test() ->
%% (cannot use block_hash due to compatibility issues...)
{abc,26499},
{abd,26500},
+ {'åäö', 62518},
+ %% 81 runes as an atom, 'ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰ'
+ {erlang:binary_to_term(<<131, 118, 0, 243, (unicode:characters_to_binary(lists:seq(5792, 5872)))/binary >>), 241561024},
+ %% åäö dynamic
+ {erlang:binary_to_term(<<131, 118, 0, 6, 195, 165, 195, 164, 195, 182>>),62518},
+ %% the atom '゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズ'
+ {erlang:binary_to_term(<<131, 118, 0, 102, (unicode:characters_to_binary(lists:seq(12441, 12542)))/binary>>), 246053818},
+ %% the atom, '😃'
+ {erlang:binary_to_term(<<131, 118, 0, 4, 240, 159, 152, 131>>), 1026307},
%% small
{0,3175731469},