aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/.gitignore1
-rw-r--r--erts/configure.in5
-rw-r--r--erts/doc/src/erl_driver.xml37
-rw-r--r--erts/emulator/beam/erl_ptab.c139
-rw-r--r--erts/emulator/beam/erl_ptab.h2
-rw-r--r--erts/emulator/test/Makefile3
-rw-r--r--erts/emulator/test/emulator_smoke.spec3
-rw-r--r--erts/etc/Makefile3
-rw-r--r--erts/etc/unix/Makefile46
-rw-r--r--erts/etc/unix/etp-commands.in (renamed from erts/etc/unix/etp-commands)4
-rw-r--r--erts/etc/unix/etp-thr.py55
-rw-r--r--erts/include/internal/ethread.h4
-rw-r--r--erts/include/internal/gcc/ethread.h5
-rw-r--r--erts/test/Makefile2
-rw-r--r--erts/test/system_smoke.spec3
-rw-r--r--lib/common_test/src/ct_logs.erl30
-rw-r--r--lib/common_test/src/ct_util.erl15
-rw-r--r--lib/common_test/test/ct_test_support.erl14
-rw-r--r--lib/common_test/test/ct_verbosity_SUITE.erl26
-rw-r--r--lib/erl_interface/test/Makefile2
-rw-r--r--lib/erl_interface/test/erl_interface_smoke.spec1
-rw-r--r--lib/ic/test/Makefile2
-rw-r--r--lib/ic/test/ic_smoke.spec1
-rw-r--r--lib/inets/doc/src/httpd.xml6
-rw-r--r--lib/jinterface/test/Makefile2
-rw-r--r--lib/jinterface/test/jinterface_smoke.spec1
-rw-r--r--lib/kernel/doc/src/inet.xml13
-rw-r--r--lib/kernel/src/inet.erl9
-rw-r--r--lib/kernel/src/inet_parse.erl4
-rw-r--r--lib/kernel/src/rpc.erl2
-rw-r--r--lib/kernel/test/Makefile2
-rw-r--r--lib/kernel/test/inet_SUITE.erl4
-rw-r--r--lib/kernel/test/kernel_smoke.spec9
-rw-r--r--lib/os_mon/test/Makefile3
-rw-r--r--lib/os_mon/test/os_mon_smoke.spec3
-rw-r--r--lib/ssl/src/tls_connection.erl14
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl24
-rw-r--r--lib/stdlib/doc/src/filelib.xml6
-rw-r--r--lib/stdlib/src/gen_server.erl2
-rw-r--r--lib/test_server/src/ts.erl26
-rw-r--r--lib/test_server/src/ts_benchmark.erl7
-rw-r--r--lib/test_server/src/ts_lib.erl12
-rw-r--r--lib/xmerl/doc/src/xmerl_ug.xmlsrc4
43 files changed, 423 insertions, 133 deletions
diff --git a/erts/.gitignore b/erts/.gitignore
index 526d5da0b9..e515dc8811 100644
--- a/erts/.gitignore
+++ b/erts/.gitignore
@@ -11,6 +11,7 @@
/etc/common/Install
/etc/common/erl.src
+/etc/unix/etp-commands
/test/Emakefile
/test/*.beam
diff --git a/erts/configure.in b/erts/configure.in
index 2f624e5853..64436e933c 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1051,12 +1051,15 @@ if test $ERTS_BUILD_SMP_EMU = yes; then
AC_DEFINE(ERTS_HAVE_SMP_EMU, 1, [Define if the smp emulator is built])
+ test "X$smp_require_native_atomics" = "Xyes" &&
+ AC_DEFINE(ETHR_SMP_REQUIRE_NATIVE_IMPLS, 1, [Define if you want to enable check for native ethread implementations])
+
case "$ethr_have_native_atomics-$smp_require_native_atomics-$ethr_have_native_spinlock" in
yes-*)
;;
no-yes-*)
- AC_MSG_ERROR([No native atomic implementation found. See INSTALL.md for more information.])
+ AC_MSG_ERROR([No native atomic implementation found. See Configuring section in INSTALL.md for more information.])
;;
no-no-yes)
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml
index efe0483b31..f52d973709 100644
--- a/erts/doc/src/erl_driver.xml
+++ b/erts/doc/src/erl_driver.xml
@@ -666,7 +666,7 @@ typedef struct ErlDrvBinary {
<item>
<p>The <c>ErlDrvData</c> is a handle to driver-specific data,
passed to the driver call-backs. It is a pointer, and is
- most often type casted to a specific pointer in the driver.</p>
+ most often type cast to a specific pointer in the driver.</p>
</item>
<tag>SysIOVec</tag>
<item>
@@ -1014,7 +1014,7 @@ typedef struct ErlIOVec {
<fsummary>Read a system timestamp</fsummary>
<desc>
<marker id="driver_get_now"></marker>
- <p>This function reads a timestamp into the memory pointed to by
+ <p>This function reads a timestamp into the memory pointed to by
the parameter <c>now</c>. See the description of <seealso marker="#ErlDrvNowData">ErlDrvNowData</seealso> for
specification of its fields. </p>
<p>The return value is 0 unless the <c>now</c> pointer is not
@@ -1056,7 +1056,7 @@ typedef struct ErlIOVec {
returned. Another thread may still be using the event object
internally. To safely close an event object call
<c>driver_select</c> with <c>ERL_DRV_USE</c> and <c>on==0</c>. That
- will clear all events and then call
+ will clear all events and then call
<seealso marker="driver_entry#stop_select">stop_select</seealso>
when it is safe to close the event object.
<c>ERL_DRV_USE</c> should be set together with the first event
@@ -1068,7 +1068,7 @@ typedef struct ErlIOVec {
<p>ERL_DRV_USE was added in OTP release R13. Old drivers will still work
as before. But it is recommended to update them to use <c>ERL_DRV_USE</c> and
<c>stop_select</c> to make sure that event objects are closed in a safe way.</p>
- </note>
+ </note>
<p>The return value is 0 (failure, -1, only if the
<c>ready_input</c>/<c>ready_output</c> is
<c>NULL</c>).</p>
@@ -1524,7 +1524,7 @@ typedef struct ErlIOVec {
<marker id="remove_driver_entry"></marker>
<p>This function removes a driver entry <c>de</c> previously
added with <c>add_driver_entry</c>.</p>
- <p>Driver entries added by the <c>erl_ddll</c> erlang interface can
+ <p>Driver entries added by the <c>erl_ddll</c> erlang interface can
not be removed by using this interface.</p>
</desc>
</func>
@@ -1758,7 +1758,7 @@ typedef struct ErlIOVec {
<pre>
Term type Argument(s)
===========================================
-ERL_DRV_NIL
+ERL_DRV_NIL
ERL_DRV_ATOM ErlDrvTermData atom (from driver_mk_atom(char *string))
ERL_DRV_INT ErlDrvSInt integer
ERL_DRV_UINT ErlDrvUInt integer
@@ -1779,11 +1779,11 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
signed integer data type <c>ErlDrvSInt</c> are 64 bits wide
on a 64 bit runtime system and 32 bits wide on a 32 bit
runtime system. They were introduced in erts version 5.6,
- and replaced some of the <c>int</c> arguments in the list above.
+ and replaced some of the <c>int</c> arguments in the list above.
</p>
<p>The unsigned integer data type <c>ErlDrvUInt64</c> and the
signed integer data type <c>ErlDrvSInt64</c> are always 64 bits
- wide. They were introduced in erts version 5.7.4.
+ wide. They were introduced in erts version 5.7.4.
</p>
<p>To build the tuple <c>{tcp, Port, [100 | Binary]}</c>, the
@@ -1879,7 +1879,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<fsummary>Send term data from driver to port owner</fsummary>
<desc>
<marker id="driver_output_term"></marker>
- <warning><p><c>driver_output_term()</c> is deferred and will
+ <warning><p><c>driver_output_term()</c> is deprecated and will
be removed in the OTP-R17 release. Use
<seealso marker="#erl_drv_send_term">erl_drv_output_term()</seealso>
instead.</p>
@@ -1937,7 +1937,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<fsummary>Send term data to other process than port owner process</fsummary>
<desc>
<marker id="driver_send_term"></marker>
- <warning><p><c>driver_send_term()</c> is deferred and will
+ <warning><p><c>driver_send_term()</c> is deprecated and will
be removed in the OTP-R17 release. Use
<seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso>
instead.</p>
@@ -1998,7 +1998,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
The data should be freed in <c>async_free</c>, because it's
called if <c>driver_async_cancel</c> is called.</p>
<p>When the async operation is done, <seealso marker="driver_entry#ready_async">ready_async</seealso> driver
- entry function is called. If <c>async_ready</c> is null in
+ entry function is called. If <c>ready_async</c> is null in
the driver entry, the <c>async_free</c> function is called
instead.</p>
<p>The return value is a handle to the asynchronous task, which
@@ -2035,7 +2035,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
as of OTP-R15B <c>driver_async_cancel()</c> is deprecated, and
scheduled for removal in OTP-R16. It will currently always fail,
and return 0.</p>
- <warning><p><c>driver_async_cancel()</c> is deferred and will
+ <warning><p><c>driver_async_cancel()</c> is deprecated and will
be removed in the OTP-R16 release.</p>
</warning>
@@ -2048,7 +2048,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<marker id="driver_lock_driver"></marker>
<p>This function locks the driver used by the port <c>port</c>
in memory for the rest of the emulator process'
- lifetime. After this call, the driver behaves as one of Erlang's
+ lifetime. After this call, the driver behaves as one of Erlang's
statically linked in drivers.</p>
</desc>
</func>
@@ -2076,7 +2076,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<seealso marker="driver_entry">driver_entry</seealso>).</item>
<tag><c>drv_data</c></tag>
<item>The driver defined handle that will be passed in subsequent
- calls to driver call-backs. Note, that the
+ calls to driver call-backs. Note, that the
<seealso marker="driver_entry#start">driver start call-back</seealso>
will not be called for this new driver instance.
The driver defined handle is normally created in the
@@ -2284,7 +2284,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<item>A thread identifier.</item>
</taglist>
<p>This function compares two thread identifiers for equality,
- and returns <c>0</c> it they aren't equal, and
+ and returns <c>0</c> it they aren't equal, and
a value not equal to <c>0</c> if they are equal.</p>
<note><p>A Thread identifier may be reused very quickly after
a thread has terminated. Therefore, if a thread
@@ -2469,7 +2469,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
</taglist>
<p>This function broadcasts on a condition variable. That is, if
other threads are waiting on the condition variable being
- broadcasted on, <em>all</em> of them will be woken.
+ broadcast on, <em>all</em> of them will be woken.
</p>
<p>This function is thread-safe.</p>
</desc>
@@ -2498,7 +2498,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
the calling thread when calling this function.
</p>
<note><p><c>erl_drv_cond_wait()</c> might return even though
- no-one has signaled or broadcasted on the condition
+ no-one has signaled or broadcast on the condition
variable. Code calling <c>erl_drv_cond_wait()</c> should
always be prepared for <c>erl_drv_cond_wait()</c>
returning even though the condition that the thread was
@@ -2822,7 +2822,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<item>A pointer to an output buffer.</item>
<tag><c>value_size</c></tag>
<item>A pointer to an integer. The integer is both used for
- passing input and output sizes (see below).
+ passing input and output sizes (see below).
</item>
</taglist>
<p>This function retrieves the value of an environment variable.
@@ -2900,4 +2900,3 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
Guide Ch. 3)</p>
</section>
</cref>
-
diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c
index d69619dd44..fa5482b841 100644
--- a/erts/emulator/beam/erl_ptab.c
+++ b/erts/emulator/beam/erl_ptab.c
@@ -433,7 +433,7 @@ 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);
+ size += ptab->r.o.max*sizeof(erts_smp_atomic32_t);
return size;
}
@@ -474,7 +474,7 @@ erts_ptab_init_table(ErtsPTab *ptab,
tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_smp_atomic_t));
alloc_sz = tab_sz;
if (!legacy)
- alloc_sz += ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(Uint32));
+ alloc_sz += ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_smp_atomic32_t));
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;
@@ -497,6 +497,10 @@ erts_ptab_init_table(ErtsPTab *ptab,
ASSERT(ptab->r.o.pix_cl_shift + ptab->r.o.pix_cli_shift == bits);
+ 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;
+
if (legacy) {
ptab->r.o.free_id_data = NULL;
ptab->r.o.dix_cl_mask = 0;
@@ -506,11 +510,11 @@ erts_ptab_init_table(ErtsPTab *ptab,
}
else {
- tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(Uint32));
- ptab->r.o.free_id_data = (Uint32 *) tab_end;
+ tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_smp_atomic32_t));
+ ptab->r.o.free_id_data = (erts_smp_atomic32_t *) tab_end;
tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
- ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(Uint32));
+ ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(erts_smp_atomic32_t));
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);
@@ -525,7 +529,9 @@ erts_ptab_init_table(ErtsPTab *ptab,
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;
+ erts_smp_atomic32_init_nob(&ptab->r.o.free_id_data[ix],
+ cli*tab_cache_lines+cl);
+ ASSERT(erts_smp_atomic32_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data);
ix++;
}
}
@@ -534,9 +540,6 @@ erts_ptab_init_table(ErtsPTab *ptab,
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;
erts_smp_interval_init(&ptab->list.data.interval);
ptab->list.data.deleted.start = NULL;
@@ -606,11 +609,13 @@ erts_ptab_new_element(ErtsPTab *ptab,
= erts_smp_current_interval_nob(erts_ptab_interval(ptab));
if (ptab->r.o.free_id_data) {
+ do {
+ ix = (Uint32) erts_smp_atomic32_inc_read_acqb(&ptab->vola.tile.aid_ix);
+ ix = ix_to_free_id_data_ix(ptab, ix);
- 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];
+ data = erts_smp_atomic32_xchg_nob(&ptab->r.o.free_id_data[ix],
+ (erts_aint32_t)ptab->r.o.invalid_data);
+ }while ((Eterm)data == ptab->r.o.invalid_data);
init_ptab_el(init_arg, (Eterm) data);
@@ -763,7 +768,7 @@ 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) {
-
+ Uint32 prev_data;
/* Next data for this slot... */
data = (Uint32) erts_ptab_id2data(ptab, ptab_el->id);
data += ptab->r.o.max;
@@ -772,14 +777,17 @@ erts_ptab_delete_element(ErtsPTab *ptab,
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;
+ do {
+ ix = (Uint32) erts_smp_atomic32_inc_read_relb(&ptab->vola.tile.fid_ix);
+ ix = ix_to_free_id_data_ix(ptab, ix);
+
+ prev_data = erts_smp_atomic32_cmpxchg_nob(&ptab->r.o.free_id_data[ix],
+ data,
+ ptab->r.o.invalid_data);
+ }while ((Eterm)prev_data != ptab->r.o.invalid_data);
}
ASSERT(erts_smp_atomic32_read_nob(&ptab->vola.tile.count) > 0);
@@ -1392,6 +1400,31 @@ erts_ptab_init(void)
* Debug stuff
*/
+static void assert_ptab_consistency(ErtsPTab *ptab)
+{
+#ifdef DEBUG
+ if (ptab->r.o.free_id_data) {
+ Uint32 ix, pix, data;
+ int free_pids = 0;
+ int null_slots = 0;
+
+ for (ix=0; ix < ptab->r.o.max; ix++) {
+ if (erts_smp_atomic32_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data) {
+ ++free_pids;
+ data = erts_smp_atomic32_read_nob(&ptab->r.o.free_id_data[ix]);
+ pix = erts_ptab_data2pix(ptab, (Eterm) data);
+ ASSERT(erts_ptab_pix2intptr_nob(ptab, pix) == ERTS_AINT_NULL);
+ }
+ if (erts_smp_atomic_read_nob(&ptab->r.o.tab[ix]) == ERTS_AINT_NULL) {
+ ++null_slots;
+ }
+ }
+ ASSERT(free_pids == null_slots);
+ ASSERT(free_pids == ptab->r.o.max - erts_smp_atomic32_read_nob(&ptab->vola.tile.count));
+ }
+#endif
+}
+
Sint
erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
{
@@ -1402,46 +1435,49 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
erts_ptab_rwlock(ptab);
+ assert_ptab_consistency(ptab);
+
if (ptab->r.o.free_id_data) {
- Uint32 aid_ix, dix;
+ Uint32 id_ix, dix;
if (set) {
- Uint32 max_ix, ser, num, start;
+ Uint32 i, max_ix, num, stop_id_ix;
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);
+ num = next;
+ id_ix = (Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.aid_ix);
+
+ for (i=0; i <= max_ix; ++i) {
+ Uint32 pix;
+ ++num;
+ num &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
+ if (num == ptab->r.o.invalid_data) {
+ num += ptab->r.o.max;
+ num &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
+ }
+ 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++;
+ ++id_ix;
+ dix = ix_to_free_id_data_ix(ptab, id_ix);
+ erts_smp_atomic32_set_nob(&ptab->r.o.free_id_data[dix], num);
+ ASSERT(pix == erts_ptab_data2pix(ptab, num));
}
- if (num == max_ix)
- num = 0;
- else
- num++;
- } while (num != start);
+ }
+ erts_smp_atomic32_set_nob(&ptab->vola.tile.fid_ix, id_ix);
-#ifdef DEBUG
- if (aid_ix == 0)
- aid_ix = max_ix;
- else
- aid_ix--;
- ASSERT((aid_ix & max_ix) == (((Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.fid_ix)) & max_ix));
-#endif
+ /* Write invalid_data in rest of free_id_data[]: */
+ stop_id_ix = (1 + erts_smp_atomic32_read_nob(&ptab->vola.tile.aid_ix)) & max_ix;
+ while (1) {
+ id_ix = (id_ix+1) & max_ix;
+ if (id_ix == stop_id_ix)
+ break;
+ dix = ix_to_free_id_data_ix(ptab, id_ix);
+ erts_smp_atomic32_set_nob(&ptab->r.o.free_id_data[dix],
+ ptab->r.o.invalid_data);
+ }
}
-
- 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];
+ id_ix = (Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.aid_ix) + 1;
+ dix = ix_to_free_id_data_ix(ptab, id_ix);
+ res = (Sint) erts_smp_atomic32_read_nob(&ptab->r.o.free_id_data[dix]);
}
else {
/* Deprecated legacy algorithm... */
@@ -1485,6 +1521,7 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
}
}
+ assert_ptab_consistency(ptab);
erts_ptab_rwunlock(ptab);
return res;
diff --git a/erts/emulator/beam/erl_ptab.h b/erts/emulator/beam/erl_ptab.h
index c2d8bd9cad..e3e05f14af 100644
--- a/erts/emulator/beam/erl_ptab.h
+++ b/erts/emulator/beam/erl_ptab.h
@@ -100,7 +100,7 @@ typedef struct {
typedef struct {
erts_smp_atomic_t *tab;
- Uint32 *free_id_data;
+ erts_smp_atomic32_t *free_id_data;
Uint32 max;
Uint32 pix_mask;
Uint32 pix_cl_mask;
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index 9594ab48b1..f02ca3cb98 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -140,7 +140,8 @@ EMAKEFILE=Emakefile
TEST_SPEC_FILES= emulator.spec \
emulator.spec.win \
- emulator_bench.spec
+ emulator_bench.spec \
+ emulator_smoke.spec
# ----------------------------------------------------
# Release directory specification
diff --git a/erts/emulator/test/emulator_smoke.spec b/erts/emulator/test/emulator_smoke.spec
new file mode 100644
index 0000000000..3219aeb823
--- /dev/null
+++ b/erts/emulator/test/emulator_smoke.spec
@@ -0,0 +1,3 @@
+{suites,"../emulator_test",[smoke_test_SUITE,time_SUITE]}.
+{cases,"../emulator_test",crypto_SUITE,[t_md5]}.
+{cases,"../emulator_test",float_SUITE,[fpe,cmp_integer]}. \ No newline at end of file
diff --git a/erts/etc/Makefile b/erts/etc/Makefile
index 2b32b8ae50..5b54ef9c3e 100644
--- a/erts/etc/Makefile
+++ b/erts/etc/Makefile
@@ -18,10 +18,11 @@
#
include $(ERL_TOP)/make/target.mk
-
SUB_DIRECTORIES = common
ifeq ($(TARGET),win32)
SUB_DIRECTORIES += win32
+else
+SUB_DIRECTORIES += unix
endif
include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/erts/etc/unix/Makefile b/erts/etc/unix/Makefile
new file mode 100644
index 0000000000..e85d2fab0c
--- /dev/null
+++ b/erts/etc/unix/Makefile
@@ -0,0 +1,46 @@
+#
+# %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%
+#
+
+include $(ERL_TOP)/make/output.mk
+include $(ERL_TOP)/make/target.mk
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+include ../../vsn.mk
+
+opt debug: etc
+
+.PHONY: etc
+etc: etp-commands
+
+etp-commands: etp-commands.in
+ sed 's:@ERL_TOP@:${ERL_TOP}:g' etp-commands.in > etp-commands
+
+.PHONY: docs
+docs:
+
+.PHONY: clean
+clean:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+.PHONY: release_spec
+release_spec: etc \ No newline at end of file
diff --git a/erts/etc/unix/etp-commands b/erts/etc/unix/etp-commands.in
index 35f75df5c1..54ff7b3e3a 100644
--- a/erts/etc/unix/etp-commands
+++ b/erts/etc/unix/etp-commands.in
@@ -2757,6 +2757,10 @@ document etp-run
%---------------------------------------------------------------------------
end
+define etp-thr
+ source @ERL_TOP@/erts/etc/unix/etp-thr.py
+end
+
############################################################################
# Toolbox parameter handling
#
diff --git a/erts/etc/unix/etp-thr.py b/erts/etc/unix/etp-thr.py
new file mode 100644
index 0000000000..64fb858d20
--- /dev/null
+++ b/erts/etc/unix/etp-thr.py
@@ -0,0 +1,55 @@
+#
+# %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%
+#
+
+def get_thread_name(t):
+ f = gdb.newest_frame();
+ while f:
+ if f.name() == "async_main":
+ return "async";
+ elif f.name() == "erts_sys_main_thread":
+ return "main";
+ elif f.name() == "signal_dispatcher_thread_func":
+ return "signal_dispatcher";
+ elif f.name() == "sys_msg_dispatcher_func":
+ return "sys_msg_dispatcher";
+ elif f.name() == "child_waiter":
+ return "child_waiter";
+ elif f.name() == "sched_thread_func":
+ return "scheduler";
+ elif f.name() == "aux_thread":
+ return "aux";
+ f = f.older();
+ return "unknown";
+
+
+curr_thread = gdb.selected_thread();
+
+for i in gdb.inferiors():
+ gdb.write(" Id Thread Name Frame\n");
+ for t in i.threads():
+ t.switch();
+ if curr_thread == t:
+ gdb.write("*");
+ else:
+ gdb.write(" ");
+ gdb.write("{0:<3} {1:20} {2}\n".format(
+ t.num,get_thread_name(t),
+ gdb.newest_frame().name()));
+
+curr_thread.switch();
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h
index 407097d4b1..38b8e9e9b6 100644
--- a/erts/include/internal/ethread.h
+++ b/erts/include/internal/ethread.h
@@ -361,6 +361,10 @@ extern ethr_runtime_t ethr_runtime__;
# endif
#endif /* !ETHR_DISABLE_NATIVE_IMPLS */
+#if !defined(ETHR_HAVE_NATIVE_ATOMIC32) && !defined(ETHR_HAVE_NATIVE_ATOMIC64) && !defined(ETHR_DISABLE_NATIVE_IMPLS) && defined(ETHR_SMP_REQUIRE_NATIVE_IMPLS)
+#error "No native ethread implementation found. If you want to use fallbacks you have to disable native ethread support with configure."
+#endif
+
#include "ethr_atomics.h" /* The atomics API */
#if defined(__GNUC__)
diff --git a/erts/include/internal/gcc/ethread.h b/erts/include/internal/gcc/ethread.h
index fcfdc39441..365a3535cf 100644
--- a/erts/include/internal/gcc/ethread.h
+++ b/erts/include/internal/gcc/ethread.h
@@ -25,6 +25,9 @@
#ifndef ETHREAD_GCC_H__
#define ETHREAD_GCC_H__
+#if defined(ETHR_HAVE___SYNC_VAL_COMPARE_AND_SWAP32) \
+ || defined(ETHR_HAVE___SYNC_VAL_COMPARE_AND_SWAP64)
+
#ifndef ETHR_MEMBAR
# include "ethr_membar.h"
#endif
@@ -46,3 +49,5 @@
#endif
#endif
+
+#endif
diff --git a/erts/test/Makefile b/erts/test/Makefile
index 6b409e2f1b..74a5bb1ccc 100644
--- a/erts/test/Makefile
+++ b/erts/test/Makefile
@@ -79,7 +79,7 @@ release_spec:
release_tests_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) system.spec system.dynspec \
+ $(INSTALL_DATA) system.spec system.dynspec system_smoke.spec \
$(ERL_FILES) $(TARGET_FILES) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
tar cf - *_SUITE_data utils | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/erts/test/system_smoke.spec b/erts/test/system_smoke.spec
new file mode 100644
index 0000000000..933d1ba22d
--- /dev/null
+++ b/erts/test/system_smoke.spec
@@ -0,0 +1,3 @@
+{suites,"../system_test",[ethread_SUITE]}.
+{cases,"../system_test",otp_SUITE,[undefined_functions]}.
+{skip_cases,"../system_test",ethread_SUITE,[max_threads],"Skip"}.
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index f5355bfefe..bd37b690b6 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -446,6 +446,8 @@ tc_print(Category,Importance,Format,Args) ->
ct_util:get_verbosity('$unspecified');
{error,bad_invocation} ->
?MAX_VERBOSITY;
+ {error,_Failure} ->
+ ?MAX_VERBOSITY;
Val ->
Val
end,
@@ -690,14 +692,15 @@ logger_loop(State) ->
false ->
%% Group leader is dead, so write to the
%% CtLog or unexpected_io log instead
- unexpected_io(Pid,Category,List,State),
+ unexpected_io(Pid,Category,Importance,
+ List,State),
logger_loop(State)
end;
{ct_log,_Fd,TCGLs} ->
%% If category is ct_internal then write
%% to ct_log, else write to unexpected_io
%% log
- unexpected_io(Pid,Category,List,State),
+ unexpected_io(Pid,Category,Importance,List,State),
logger_loop(State#logger_state{
tc_groupleaders = TCGLs})
end;
@@ -798,7 +801,7 @@ print_to_log(sync, FromPid, Category, TCGL, List, State) ->
IoFun = create_io_fun(FromPid, State),
io:format(TCGL,"~ts", [lists:foldl(IoFun, [], List)]);
true ->
- unexpected_io(FromPid,Category,List,State)
+ unexpected_io(FromPid,Category,?MAX_IMPORTANCE,List,State)
end,
State;
@@ -814,7 +817,8 @@ print_to_log(async, FromPid, Category, TCGL, List, State) ->
end;
true ->
fun() ->
- unexpected_io(FromPid,Category,List,State)
+ unexpected_io(FromPid,Category,?MAX_IMPORTANCE,
+ List,State)
end
end,
case State#logger_state.async_print_jobs of
@@ -3066,10 +3070,20 @@ html_encoding(latin1) ->
html_encoding(utf8) ->
"utf-8".
-unexpected_io(Pid,ct_internal,List,#logger_state{ct_log_fd=Fd}=State) ->
+unexpected_io(Pid,ct_internal,_Importance,List,State) ->
IoFun = create_io_fun(Pid,State),
- io:format(Fd, "~ts", [lists:foldl(IoFun, [], List)]);
-unexpected_io(Pid,_Category,List,State) ->
+ io:format(State#logger_state.ct_log_fd, "~ts",
+ [lists:foldl(IoFun, [], List)]);
+unexpected_io(Pid,Category,Importance,List,State) ->
IoFun = create_io_fun(Pid,State),
Data = io_lib:format("~ts", [lists:foldl(IoFun, [], List)]),
- test_server_io:print_unexpected(Data).
+ %% if unexpected io comes in during startup or shutdown, test_server
+ %% might not be running - if so (noproc exit), simply print to
+ %% stdout instead (will result in double printouts when pal is used)
+ try test_server_io:print_unexpected(Data) of
+ _ ->
+ ok
+ catch
+ _:{noproc,_} -> tc_print(Category,Importance,Data,[]);
+ _:Reason -> exit(Reason)
+ end.
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 68e76c2396..abda87c2cd 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -286,14 +286,23 @@ get_start_dir() ->
%% handle verbosity outside ct_util_server (let the client read
%% the verbosity table) to avoid possible deadlock situations
set_verbosity(Elem = {_Category,_Level}) ->
- ets:insert(?verbosity_table, Elem),
- ok.
+ try ets:insert(?verbosity_table, Elem) of
+ _ ->
+ ok
+ catch
+ _:Reason ->
+ {error,Reason}
+ end.
+
get_verbosity(Category) ->
- case ets:lookup(?verbosity_table, Category) of
+ try ets:lookup(?verbosity_table, Category) of
[{Category,Level}] ->
Level;
_ ->
undefined
+ catch
+ _:Reason ->
+ {error,Reason}
end.
loop(Mode,TestData,StartDir) ->
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 6bcac12326..4132995bf6 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -36,6 +36,8 @@
verify_events/3, verify_events/4, reformat/2, log_events/4,
join_abs_dirs/2]).
+-export([start_slave/3, slave_stop/1]).
+
-export([ct_test_halt/1]).
-include_lib("kernel/include/file.hrl").
@@ -66,10 +68,14 @@ init_per_suite(Config, Level) ->
start_slave(Config, Level).
-start_slave(Config,Level) ->
+start_slave(Config, Level) ->
+ start_slave(ct, Config, Level).
+
+start_slave(NodeName, Config, Level) ->
[_,Host] = string:tokens(atom_to_list(node()), "@"),
- test_server:format(0, "Trying to start ~s~n", ["ct@"++Host]),
- case slave:start(Host, ct, []) of
+ test_server:format(0, "Trying to start ~s~n",
+ [atom_to_list(NodeName)++"@"++Host]),
+ case slave:start(Host, NodeName, []) of
{error,Reason} ->
test_server:fail(Reason);
{ok,CTNode} ->
@@ -77,7 +83,7 @@ start_slave(Config,Level) ->
IsCover = test_server:is_cover(),
if IsCover ->
cover:start(CTNode);
- true->
+ true ->
ok
end,
diff --git a/lib/common_test/test/ct_verbosity_SUITE.erl b/lib/common_test/test/ct_verbosity_SUITE.erl
index 32488b1db9..1aa71953ec 100644
--- a/lib/common_test/test/ct_verbosity_SUITE.erl
+++ b/lib/common_test/test/ct_verbosity_SUITE.erl
@@ -53,9 +53,19 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
ct_test_support:end_per_suite(Config).
+init_per_testcase(no_crashing, Config) ->
+ Opts = ct_test_support:start_slave(ctX, Config, 50),
+ XNode = proplists:get_value(ct_node, Opts),
+ ct:pal("Node ~p started!", [XNode]),
+ [{xnode,XNode} | Config];
init_per_testcase(TestCase, Config) ->
ct_test_support:init_per_testcase(TestCase, Config).
+end_per_testcase(no_crashing, Config) ->
+ XNode = proplists:get_value(xnode, Config),
+ ct_test_support:slave_stop(XNode),
+ ct:pal("Node ~p stopped!", [XNode]),
+ ok;
end_per_testcase(TestCase, Config) ->
ct_test_support:end_per_testcase(TestCase, Config).
@@ -72,7 +82,8 @@ all() ->
combine_categories,
testspec_only,
merge_with_testspec,
- possible_deadlock
+ possible_deadlock,
+ no_crashing
].
%%--------------------------------------------------------------------
@@ -189,6 +200,19 @@ possible_deadlock(Config) ->
%%%-----------------------------------------------------------------
+%%%
+no_crashing(Config) ->
+ XNode = proplists:get_value(xnode, Config),
+ ok = rpc:call(XNode, ct, print, ["hello",[]]),
+ ok = rpc:call(XNode, ct, pal, ["hello",[]]),
+ ok = rpc:call(XNode, ct, log, ["hello",[]]),
+ Data = io_lib:format("hello", []),
+ {badrpc,{'EXIT',{noproc,_}}} =
+ (catch rpc:call(XNode, test_server_io, print_unexpected, [Data])),
+ ok.
+
+
+%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
diff --git a/lib/erl_interface/test/Makefile b/lib/erl_interface/test/Makefile
index 2b85dfc571..1ed34c74a0 100644
--- a/lib/erl_interface/test/Makefile
+++ b/lib/erl_interface/test/Makefile
@@ -42,7 +42,7 @@ MODULES= \
runner
SPEC_FILES = \
- erl_interface.spec
+ erl_interface.spec erl_interface_smoke.spec
COVER_FILE = erl_interface.cover
diff --git a/lib/erl_interface/test/erl_interface_smoke.spec b/lib/erl_interface/test/erl_interface_smoke.spec
new file mode 100644
index 0000000000..bfaea2b279
--- /dev/null
+++ b/lib/erl_interface/test/erl_interface_smoke.spec
@@ -0,0 +1 @@
+{suites,"../erl_interface_test",[ei_decode_encode_SUITE]}.
diff --git a/lib/ic/test/Makefile b/lib/ic/test/Makefile
index 54ac186c16..63af6ed9f1 100644
--- a/lib/ic/test/Makefile
+++ b/lib/ic/test/Makefile
@@ -33,7 +33,7 @@ RELSYSDIR = $(RELEASE_PATH)/ic_test
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-TEST_SPEC_FILE = ic.spec
+TEST_SPEC_FILE = ic.spec ic_smoke.spec
IDL_FILES =
diff --git a/lib/ic/test/ic_smoke.spec b/lib/ic/test/ic_smoke.spec
new file mode 100644
index 0000000000..ec3b5758b1
--- /dev/null
+++ b/lib/ic/test/ic_smoke.spec
@@ -0,0 +1 @@
+{suites,"../ic_test",[ic_SUITE]}.
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 3c132d34fa..4210aea3ec 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -251,14 +251,14 @@
</item>
<marker id="prop_max_uri"></marker>
- <tag>{max_uri, integer()}</tag>
+ <tag>{max_uri_size, integer()}</tag>
<item>
<p>Limits the size of the HTTP request URI. By
default there is no limit. </p>
</item>
<marker id="prop_max_keep_alive_req"></marker>
- <tag>{max_keep_alive_requests, integer()}</tag>
+ <tag>{max_keep_alive_request, integer()}</tag>
<item>
<p>The number of request that a client can do on one
connection. When the server has responded to the number of
@@ -632,7 +632,7 @@ bytes
</item>
<marker id="prop_edlog"></marker>
- <tag>{error_disk_log, internal | external}</tag>
+ <tag>{error_disk_log, path()}</tag>
<item>
<p>Defines the filename of the (disk_log(3)) error log file
to be used to log server errors. If the filename does not begin
diff --git a/lib/jinterface/test/Makefile b/lib/jinterface/test/Makefile
index d9ff406994..90d4e01035 100644
--- a/lib/jinterface/test/Makefile
+++ b/lib/jinterface/test/Makefile
@@ -32,7 +32,7 @@ RELSYSDIR = $(RELEASE_PATH)/jinterface_test
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-TEST_SPEC_FILE = jinterface.spec
+TEST_SPEC_FILE = jinterface.spec jinterface_smoke.spec
COVER_FILE = jinterface.cover
MODULES = nc_SUITE \
diff --git a/lib/jinterface/test/jinterface_smoke.spec b/lib/jinterface/test/jinterface_smoke.spec
new file mode 100644
index 0000000000..4a76cce4cd
--- /dev/null
+++ b/lib/jinterface/test/jinterface_smoke.spec
@@ -0,0 +1 @@
+{cases,"../jinterface_test",jinterface_SUITE,[java_erlang_send_receive]}.
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 7cd98914d1..254dfbf034 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -76,11 +76,11 @@ FFFF::192.168.42.2
{16#3ffe,16#b80,16#1f8d,16#2,16#204,16#acff,16#fe17,16#bf38}
fe80::204:acff:fe17:bf38
{16#fe80,0,0,0,0,16#204,16#acff,16#fe17,16#bf38}</code>
- <p>A function that may be useful is <c>inet_parse:address/1</c>:</p>
+ <p>A function that may be useful is <seealso marker="#parse_address/1">parse_address/1</seealso>:</p>
<pre>
-1> <input>inet_parse:address("192.168.42.2").</input>
+1> <input>inet:parse_address("192.168.42.2").</input>
{ok,{192,168,42,2}}
-2> <input>inet_parse:address("FFFF::192.168.42.2").</input>
+2> <input>inet:parse_address("FFFF::192.168.42.2").</input>
{ok,{65535,0,0,0,0,0,49320,10754}}</pre>
</description>
@@ -375,6 +375,13 @@ fe80::204:acff:fe17:bf38
</desc>
</func>
<func>
+ <name name="ntoa" arity="1" />
+ <fsummary>Convert IPv6 / IPV4 adress to ascii</fsummary>
+ <desc>
+ <p>Parses an <a href="#type-ip_address">ip_address()</a> and returns an IPv4 or IPv6 address string.</p>
+ </desc>
+ </func>
+ <func>
<name name="parse_ipv4_address" arity="1" />
<fsummary>Parse an IPv4 address</fsummary>
<desc>
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 3ea530a366..5749027acd 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -32,7 +32,7 @@
ip/1, stats/0, options/0,
pushf/3, popf/1, close/1, gethostname/0, gethostname/1,
parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1,
- parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1]).
+ parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1, ntoa/1]).
-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
@@ -529,6 +529,13 @@ getservbyname(Name, Protocol) when is_atom(Name) ->
Error -> Error
end.
+-spec ntoa(IpAddress) ->
+ {ok, Address} | {error, einval} when
+ Address :: string(),
+ IpAddress :: ip_address().
+ntoa(Addr) ->
+ inet_parse:ntoa(Addr).
+
-spec parse_ipv4_address(Address) ->
{ok, IPv4Address} | {error, einval} when
Address :: string(),
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 619c78a6ca..98bd8d386c 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -722,7 +722,9 @@ ntoa({0,0,0,0,0,16#ffff,A,B}) ->
"::FFFF:" ++ dig_to_dec(A) ++ "." ++ dig_to_dec(B);
ntoa({_,_,_,_,_,_,_,_}=T) ->
%% Find longest sequence of zeros, at least 2, to replace with "::"
- ntoa(tuple_to_list(T), []).
+ ntoa(tuple_to_list(T), []);
+ntoa(_) ->
+ {error, einval}.
%% Find first double zero
ntoa([], R) ->
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index ced6f47bfe..0e7e7d2031 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -407,7 +407,7 @@ cast(Node, Mod, Fun, Args) ->
true.
-%% Asynchronous broadcast, returns nothing, it's just send'n prey
+%% Asynchronous broadcast, returns nothing, it's just send 'n' pray
-spec abcast(Name, Msg) -> abcast when
Name :: atom(),
Msg :: term().
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index cb11d4e899..f1b8a105ed 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -145,7 +145,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(APP_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) kernel.spec $(EMAKEFILE)\
+ $(INSTALL_DATA) kernel.spec kernel_smoke.spec $(EMAKEFILE)\
$(COVERFILE) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
@tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index 62ba95e1a3..46c8c0b88b 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -226,7 +226,7 @@ t_gethostbyname_v6(Config) when is_list(Config) ->
h_addr_list = [IP4]} = HEnt4,
{ok,IP46} =
inet_parse:ipv6_address(
- "::ffff:" ++ inet_parse:ntoa(IP4)),
+ "::ffff:" ++ inet:ntoa(IP4)),
check_elems(
[{HEnt#hostent.h_name,[Name,FullName]}])
end,
@@ -246,7 +246,7 @@ t_gethostbyname_v6(Config) when is_list(Config) ->
h_addr_list = [IP4F]} = HEnt4F,
{ok,IP46F} =
inet_parse:ipv6_address(
- "::ffff:" ++ inet_parse:ntoa(IP4F)),
+ "::ffff:" ++ inet:ntoa(IP4F)),
check_elems(
[{HEntF#hostent.h_name,[Name,FullName]}])
end;
diff --git a/lib/kernel/test/kernel_smoke.spec b/lib/kernel/test/kernel_smoke.spec
new file mode 100644
index 0000000000..e5d8273c56
--- /dev/null
+++ b/lib/kernel/test/kernel_smoke.spec
@@ -0,0 +1,9 @@
+{config, "../test_server/ts.config"}.
+{config, "../test_server/ts.unix.config"}.
+
+{cases,"../kernel_test", inet_SUITE,[t_gethostbyaddr,t_gethostbyname,
+ t_gethostbyaddr_v6,t_gethostbyname_v6,t_gethostnative,getifaddrs]}.
+{cases,"../kernel_test", inet_res_SUITE,[gethostbyaddr,gethostbyname,
+ gethostbyaddr_v6,gethostbyname_v6,basic]}.
+{cases,"../kernel_test", gen_tcp_echo_SUITE,[active_echo]}.
+{cases,"../kernel_test", heart_SUITE,[reboot]}.
diff --git a/lib/os_mon/test/Makefile b/lib/os_mon/test/Makefile
index 461bebc102..cbb014324d 100644
--- a/lib/os_mon/test/Makefile
+++ b/lib/os_mon/test/Makefile
@@ -85,7 +85,8 @@ release_spec:
release_tests_spec: make_emakefile
$(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) os_mon.spec os_mon.cover $(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
+ $(INSTALL_DATA) os_mon.spec os_mon.cover os_mon_smoke.spec \
+ $(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
$(INSTALL_DATA) os_mon_mib_SUITE.cfg "$(RELSYSDIR)"
## tar chf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/os_mon/test/os_mon_smoke.spec b/lib/os_mon/test/os_mon_smoke.spec
new file mode 100644
index 0000000000..6f0d02494b
--- /dev/null
+++ b/lib/os_mon/test/os_mon_smoke.spec
@@ -0,0 +1,3 @@
+{cases,"../os_mon_test",disksup_SUITE,[api]}.
+{cases,"../os_mon_test",cpu_sup_SUITE,[load_api,util_api]}.
+{cases,"../os_mon_test",memsup_SUITE,[api]}. \ No newline at end of file
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 246fecf34a..51551eab11 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -978,7 +978,7 @@ handle_sync_event(negotiated_next_protocol, _From, StateName, #state{next_protoc
handle_sync_event(negotiated_next_protocol, _From, StateName, #state{next_protocol = NextProtocol} = State) ->
{reply, {ok, NextProtocol}, StateName, State, get_timeout(State)};
-handle_sync_event({set_opts, Opts0}, _From, StateName,
+handle_sync_event({set_opts, Opts0}, _From, StateName0,
#state{socket_options = Opts1,
socket = Socket,
transport_cb = Transport,
@@ -987,11 +987,12 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
State1 = State0#state{socket_options = Opts},
if
Opts#socket_options.active =:= false ->
- {reply, Reply, StateName, State1, get_timeout(State1)};
+ {reply, Reply, StateName0, State1, get_timeout(State1)};
Buffer =:= <<>>, Opts1#socket_options.active =:= false ->
%% Need data, set active once
{Record, State2} = next_record_if_active(State1),
- case next_state(StateName, StateName, Record, State2) of
+ %% Note: Renogotiation may cause StateName0 =/= StateName
+ case next_state(StateName0, StateName0, Record, State2) of
{next_state, StateName, State, Timeout} ->
{reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
@@ -999,13 +1000,14 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
end;
Buffer =:= <<>> ->
%% Active once already set
- {reply, Reply, StateName, State1, get_timeout(State1)};
+ {reply, Reply, StateName0, State1, get_timeout(State1)};
true ->
case read_application_data(<<>>, State1) of
Stop = {stop,_,_} ->
Stop;
{Record, State2} ->
- case next_state(StateName, StateName, Record, State2) of
+ %% Note: Renogotiation may cause StateName0 =/= StateName
+ case next_state(StateName0, StateName0, Record, State2) of
{next_state, StateName, State, Timeout} ->
{reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
@@ -2458,7 +2460,7 @@ do_format_reply(list, _,_, Data) ->
binary_to_list(Data).
header(0, <<>>) ->
- [];
+ <<>>;
header(_, <<>>) ->
[];
header(0, Binary) ->
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 36f7af784d..d50498f547 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -1631,8 +1631,8 @@ header_decode_one_byte_active(Config) when is_list(Config) ->
{from, self()},
{mfa, {?MODULE, client_header_decode_active,
[Data, [11 | <<"Hello world">> ]]}},
- {options, [{active, true}, {header, 1},
- binary | ClientOpts]}]),
+ {options, [{active, true}, binary, {header, 1}
+ | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1688,7 +1688,7 @@ header_decode_two_bytes_two_sent_active(Config) when is_list(Config) ->
Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, server_header_decode_active,
- [Data, [$H, $e]]}},
+ [Data, [$H, $e | <<>>]]}},
{options, [{active, true}, binary,
{header,2}|ServerOpts]}]),
@@ -1697,7 +1697,7 @@ header_decode_two_bytes_two_sent_active(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{mfa, {?MODULE, client_header_decode_active,
- [Data, [$H, $e]]}},
+ [Data, [$H, $e | <<>>]]}},
{options, [{active, true}, {header, 2},
binary | ClientOpts]}]),
@@ -1765,8 +1765,8 @@ header_decode_one_byte_passive(Config) when is_list(Config) ->
{from, self()},
{mfa, {?MODULE, client_header_decode_passive,
[Data, [11 | <<"Hello world">> ]]}},
- {options, [{active, false}, {header, 1},
- binary | ClientOpts]}]),
+ {options, [{active, false}, binary, {header, 1}
+ | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1822,7 +1822,7 @@ header_decode_two_bytes_two_sent_passive(Config) when is_list(Config) ->
Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, server_header_decode_passive,
- [Data, [$H, $e]]}},
+ [Data, [$H, $e | <<>>]]}},
{options, [{active, false}, binary,
{header,2}|ServerOpts]}]),
@@ -1831,7 +1831,7 @@ header_decode_two_bytes_two_sent_passive(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{mfa, {?MODULE, client_header_decode_passive,
- [Data, [$H, $e]]}},
+ [Data, [$H, $e | <<>>]]}},
{options, [{active, false}, {header, 2},
binary | ClientOpts]}]),
@@ -2124,10 +2124,14 @@ client_header_decode_passive(Socket, Packet, Result) ->
%% option and the bitsynax makes it obsolete!
check_header_result([Byte1 | _], [Byte1]) ->
ok;
+check_header_result([Byte1 | _], [Byte1| <<>>]) ->
+ ok;
check_header_result([Byte1, Byte2 | _], [Byte1, Byte2]) ->
ok;
-check_header_result(_,Got) ->
- exit({?LINE, Got}).
+check_header_result([Byte1, Byte2 | _], [Byte1, Byte2 | <<>>]) ->
+ ok;
+check_header_result(Expected,Got) ->
+ exit({?LINE, {Expected, Got}}).
server_line_packet_decode(Socket, Packet) when is_binary(Packet) ->
[L1, L2] = string:tokens(binary_to_list(Packet), "\n"),
diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml
index bd780b2b2f..d24d17be80 100644
--- a/lib/stdlib/doc/src/filelib.xml
+++ b/lib/stdlib/doc/src/filelib.xml
@@ -49,6 +49,12 @@
<datatype>
<name name="dirname"/>
</datatype>
+ <datatype>
+ <name name="dirname_all"/>
+ </datatype>
+ <datatype>
+ <name name="filename_all"/>
+ </datatype>
</datatypes>
<funcs>
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index b18d3dc0c0..7f65131f67 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -217,7 +217,7 @@ reply({To, Tag}, Reply) ->
catch To ! {Tag, Reply}.
%% -----------------------------------------------------------------
-%% Asyncronous broadcast, returns nothing, it's just send'n prey
+%% Asynchronous broadcast, returns nothing, it's just send 'n' pray
%%-----------------------------------------------------------------
abcast(Name, Request) when is_atom(Name) ->
do_abcast([node() | nodes()], Name, cast_msg(Request)).
diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl
index 4e5dc1b759..8e71c69d35 100644
--- a/lib/test_server/src/ts.erl
+++ b/lib/test_server/src/ts.erl
@@ -28,6 +28,7 @@
tests/0, tests/1,
install/0, install/1,
bench/0, bench/1, bench/2, benchmarks/0,
+ smoke_test/0, smoke_test/1,smoke_test/2, smoke_tests/0,
estone/0, estone/1,
cross_cover_analyse/1,
compile_testcases/0, compile_testcases/1,
@@ -174,6 +175,13 @@ help(installed) ->
" ts:bench(Spec) - Runs all benchmarks in the given spec file.\n"
" The spec file is actually ../*_test/Spec_bench.spec\n\n"
" ts:bench can take the same Options argument as ts:run.\n"
+ "Smoke test functions:\n"
+ " ts:smoke_tests() - Get all available families of smoke tests\n"
+ " ts:smoke_test() - Runs all smoke tests\n"
+ " ts:smoke_test(Spec)\n"
+ " - Runs all smoke tests in the given spec file.\n"
+ " The spec file is actually ../*_test/Spec_smoke.spec\n\n"
+ " ts:smoke_test can take the same Options argument as ts:run.\n"
"\n"
"Installation (already done):\n"
],
@@ -258,6 +266,7 @@ run(List, Opts) when is_list(List), is_list(Opts) ->
%% Runs one test spec with Options
run(Testspec, Config) when is_atom(Testspec), is_list(Config) ->
Options=check_test_get_opts(Testspec, Config),
+ IsSmoke=proplists:get_value(smoke,Config),
File=atom_to_list(Testspec),
WhatToDo =
case Testspec of
@@ -293,6 +302,8 @@ run(Testspec, Config) when is_atom(Testspec), is_list(Config) ->
case WhatToDo of
skip ->
create_skip_spec(Testspec, tests(Testspec));
+ test when IsSmoke ->
+ File++"_smoke.spec";
test ->
File++".spec"
end,
@@ -507,7 +518,22 @@ bench(Specs, Opts) ->
benchmarks() ->
ts_benchmark:benchmarks().
+smoke_test() ->
+ smoke_test([]).
+smoke_test(Opts) when is_list(Opts) ->
+ smoke_test(smoke_tests(),Opts);
+smoke_test(Spec) ->
+ smoke_test([Spec],[]).
+
+smoke_test(Spec, Opts) when is_atom(Spec) ->
+ smoke_test([Spec],Opts);
+smoke_test(Specs, Opts) ->
+ run(Specs, [{smoke,true}|Opts]).
+
+smoke_tests() ->
+ {ok, Cwd} = file:get_cwd(),
+ ts_lib:specialized_specs(Cwd,"smoke").
%%
%% estone/0, estone/1
diff --git a/lib/test_server/src/ts_benchmark.erl b/lib/test_server/src/ts_benchmark.erl
index 516d22fd2d..bd6abc3372 100644
--- a/lib/test_server/src/ts_benchmark.erl
+++ b/lib/test_server/src/ts_benchmark.erl
@@ -30,12 +30,7 @@
benchmarks() ->
{ok, Cwd} = file:get_cwd(),
- Benches = filelib:wildcard(
- filename:join([Cwd,"..","*_test","*_bench.spec"])),
- [begin
- Base = filename:basename(N),
- list_to_atom(string:substr(Base,1,string:rstr(Base,"_")-1))
- end || N <- Benches].
+ ts_lib:specialized_specs(Cwd,"bench").
run(Specs, Opts, Vars) ->
{ok, Cwd} = file:get_cwd(),
diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl
index a00f607fc1..52bb346043 100644
--- a/lib/test_server/src/ts_lib.erl
+++ b/lib/test_server/src/ts_lib.erl
@@ -27,6 +27,7 @@
erlang_type/1,
initial_capital/1,
specs/1, suites/2,
+ specialized_specs/2,
subst_file/3, subst/2, print_data/1,
make_non_erlang/2,
maybe_atom_to_list/1, progress/4,
@@ -91,13 +92,22 @@ initial_capital([C|Rest]) when $a =< C, C =< $z ->
initial_capital(String) ->
String.
+specialized_specs(Dir,PostFix) ->
+ Specs = filelib:wildcard(filename:join([filename:dirname(Dir),
+ "*_test", "*_"++PostFix++".spec"])),
+ sort_tests([begin
+ Base = filename:basename(Name),
+ list_to_atom(string:substr(Base,1,string:rstr(Base,"_")-1))
+ end || Name <- Specs]).
+
specs(Dir) ->
Specs = filelib:wildcard(filename:join([filename:dirname(Dir),
"*_test", "*.{dyn,}spec"])),
- % Filter away all spec which end with _bench.spec
+ % Filter away all spec which end with {_bench,_smoke}.spec
NoBench = fun(SpecName) ->
case lists:reverse(SpecName) of
"ceps.hcneb_"++_ -> false;
+ "ceps.ekoms_"++_ -> false;
_ -> true
end
end,
diff --git a/lib/xmerl/doc/src/xmerl_ug.xmlsrc b/lib/xmerl/doc/src/xmerl_ug.xmlsrc
index 8a0805020e..10c770c400 100644
--- a/lib/xmerl/doc/src/xmerl_ug.xmlsrc
+++ b/lib/xmerl/doc/src/xmerl_ug.xmlsrc
@@ -409,9 +409,9 @@ Data =
specification but the basic functionality. For all details see
the <seealso marker="xmerl_xs">reference manual</seealso></p>
<p>First, some words about the xmerl_xs functionality:</p>
- <p>You need to wright template functions to be able to control
+ <p>You need to write template functions to be able to control
what kind of output you want. Thus if you want to encapsulate a
- <c>bike</c> element in &lt;p&gt; tags you simply wright a
+ <c>bike</c> element in &lt;p&gt; tags you simply write a
function:</p>
<pre>
template(E = #xmlElement{name='bike'}) ->