aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/doc/src/erl.xml22
-rw-r--r--erts/emulator/beam/bif.tab2
-rw-r--r--erts/emulator/beam/erl_init.c29
-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/inet_drv.c4
-rw-r--r--erts/emulator/sys/common/erl_sys_common_misc.c16
-rw-r--r--erts/etc/common/erlexec.c10
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44132 -> 44228 bytes
-rw-r--r--erts/preloaded/src/prim_file.erl9
14 files changed, 298 insertions, 89 deletions
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 5bfa518266..bd03fb4970 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -615,6 +615,28 @@
debugging.</item>
</taglist>
</item>
+ <tag><marker id="+pc"/><marker id="max_processes"><c><![CDATA[+pc Range]]></c></marker></tag>
+ <item>
+ <p>Sets the range of characters that the system will consider printable in heuristic detection of strings. This typically affects the shell, debugger and io:format functions (when ~tp is used in the format string).</p>
+ <p>Currently two values for the <c>Range</c> are supported:
+ <taglist>
+ <tag><c>latin1</c></tag> <item>The default. Only characters
+ in the ISO-latin-1 range can be considered printable, which means
+ that a character with a code point &gt; 255 will never be
+ considered printable and that lists containing such
+ characters will be displayed as lists of integers rather
+ than text strings by tools.</item>
+ <tag><c>unicode</c></tag>
+ <item>All printable Unicode characters are considered when
+ determining if a list of integers is to be displayed in
+ string syntax. This may give unexpected results if for
+ example your font does not cover all Unicode
+ characters.</item>
+ </taglist>
+ </p>
+ <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>
<item>
<p>Sets the maximum number of simultaneously existing processes for this
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_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_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/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/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/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 577554c43d..9d674a7c65 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -912,6 +912,16 @@ int main(int argc, char **argv)
i++;
}
break;
+ case 'p':
+ if (argv[i][2] != 'c' || argv[i][3] != '\0')
+ goto the_default;
+ if (i+1 >= argc)
+ usage(argv[i]);
+ argv[i][0] = '-';
+ add_Eargs(argv[i]);
+ add_Eargs(argv[i+1]);
+ i++;
+ break;
case 'z':
if (!is_one_of_strings(&argv[i][2], plusz_val_switches)) {
goto the_default;
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index b64fe522e8..360887de9d 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index b40a6d9633..489e8ca4ea 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -933,7 +933,12 @@ list_dir_int(Port, Dir) ->
fun(P) ->
case list_dir_response(P, []) of
{ok, RawNames} ->
- {ok, list_dir_convert(RawNames)};
+ try
+ {ok, list_dir_convert(RawNames)}
+ catch
+ throw:Reason ->
+ Reason
+ end;
Error ->
Error
end
@@ -979,7 +984,7 @@ list_dir_convert([Name|Names]) ->
{error, ignore} ->
list_dir_convert(Names);
{error, error} ->
- {error, {no_translation, Name}};
+ throw({error, {no_translation, Name}});
Converted when is_list(Converted) ->
[Converted|list_dir_convert(Names)]
end;