diff options
80 files changed, 2065 insertions, 903 deletions
diff --git a/.gitignore b/.gitignore index 46a47febcb..e639bacd85 100644 --- a/.gitignore +++ b/.gitignore @@ -119,6 +119,7 @@ JAVADOC-GENERATED /bootstrap/lib/syntax_tools /bootstrap/lib/test_server /bootstrap/lib/wx +/bootstrap/lib/xmerl /Makefile /configure diff --git a/Makefile.in b/Makefile.in index 77dbd58181..ea95751401 100644 --- a/Makefile.in +++ b/Makefile.in @@ -175,12 +175,14 @@ BOOTSTRAP_ONLY = @BOOTSTRAP_ONLY@ CROSS_COMPILING = @CROSS_COMPILING@ ifeq ($(CROSS_COMPILING),yes) INSTALL_CROSS = -cross +TARGET_HOST=$(shell $(ERL_TOP)/erts/autoconf/config.guess) else ifneq ($(DESTDIR),) INSTALL_CROSS = -cross else INSTALL_CROSS = endif +TARGET_HOST= endif # A BSD compatible install program @@ -228,10 +230,10 @@ BOOTSTRAP_ROOT = $(ERL_TOP) LOCAL_PATH = $(ERL_TOP)/erts/bin/$(TARGET):$(ERL_TOP)/erts/bin ifeq ($(TARGET),win32) BOOT_PREFIX=$(WIN32_WRAPPER_PATH):$(BOOTSTRAP_ROOT)/bootstrap/bin: -TEST_PATH_PREFIX=$(WIN32_WRAPPER_PATH):$(ERL_TOP)/bin: +TEST_PATH_PREFIX=$(WIN32_WRAPPER_PATH):$(ERL_TOP)/bin/win32: else BOOT_PREFIX=$(BOOTSTRAP_ROOT)/bootstrap/bin: -TEST_PATH_PREFIX=$(ERL_TOP)/bin: +TEST_PATH_PREFIX=$(ERL_TOP)/bin/$(TARGET_HOST): endif # ---------------------------------------------------------------------- @@ -651,6 +653,8 @@ tertiary_bootstrap_copy: if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; fi if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server ; fi if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include ; fi + if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; fi + if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; fi for x in lib/ic/ebin/*.beam; do \ BN=`basename $$x`; \ TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin/$$BN; \ @@ -728,6 +732,7 @@ tertiary_bootstrap_copy: true; \ done +# copy test includes to be able to compile tests with bootstrap compiler for x in lib/test_server/include/*.hrl; do \ BN=`basename $$x`; \ TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include/$$BN; \ @@ -738,6 +743,17 @@ tertiary_bootstrap_copy: cp $$x $$TF; \ true; \ done + + for x in lib/common_test/include/*.hrl; do \ + BN=`basename $$x`; \ + TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include/$$BN; \ + test -f $$TF && \ + test '!' -z "`find $$x -newer $$TF -print`" && \ + cp $$x $$TF; \ + test '!' -f $$TF && \ + cp $$x $$TF; \ + true; \ + done # cp lib/syntax_tools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin .PHONY: check_recreate_primary_bootstrap recreate_primary_bootstrap diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index cfbc38f176..72cbf1f3b2 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -766,6 +766,16 @@ <seealso marker="erlang#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. </p> </item> + <tag><marker id="+sbwt"><c>+sbwt none|very_short|short|medium|long|very_long</c></marker></tag> + <item> + <p>Set scheduler busy wait threshold. Default is <c>medium</c>. + The threshold determines how long schedulers should busy + wait when running out of work before going to sleep. + </p> + <p><em>NOTE:</em> This flag may be removed or changed at any time + without prior notice. + </p> + </item> <tag><marker id="+scl"><c>+scl true|false</c></marker></tag> <item> <p>Enable or disable scheduler compaction of load. By default @@ -901,6 +911,17 @@ <p>For more information, see <seealso marker="erlang#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>.</p> </item> + <tag><marker id="+sws"><c>+sws default|legacy|proposal</c></marker></tag> + <item> + <p>Set scheduler wakeup strategy. Default is <c>legacy</c> (has been + used since OTP-R13B). The <c>proposal</c> strategy is the currently + proposed strategy for OTP-R16. Note that the <c>proposal</c> strategy + might change during OTP-R15. + </p> + <p><em>NOTE:</em> This flag may be removed or changed at any time + without prior notice. + </p> + </item> <tag><marker id="+swt"><c>+swt very_low|low|medium|high|very_high</c></marker></tag> <item> <p>Set scheduler wakeup threshold. Default is <c>medium</c>. diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 0963904b83..cfc7fff3af 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -3573,6 +3573,10 @@ os_prompt% </pre> <p><c>Bytes</c> is the total number of bytes written to the port.</p> </item> + <tag><c>{os_pid, Integer | undefined}</c></tag> + <item> + <p><c>Integer</c> is the process identifier (or equivalent) of an OS process created with <c>open_port({spawn | spawn_executable, Command}, Options)</c>. If the port is not the result of spawning an OS process, the value is <c>undefined</c>.</p> + </item> </taglist> <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port.</p> </desc> diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 028a2bbf3d..6b6a3374d1 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -30,6 +30,74 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 5.9.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If threads support for the runtime system had been + disabled at compile time (<c>--disable-threads</c> had + been passed to <c>configure</c>), and the <c>+A</c> + command line argument of <c>erl</c> was passed when + starting the runtime system, <seealso + marker="erl_driver#driver_system_info">driver_system_info()</seealso> + erroneously claimed that the runtime system had async + threads even though it had not.</p> + <p> + Due to this bug the file driver did not split tasks into + smaller chunks, but instead completed the whole task at + once, i.e., the scheduler got occupied with I/O for a + longer time than intended.</p> + <p> + Own Id: OTP-10059</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + A proposal for a new scheduler wakeup strategy has been + implemented. For more information see the documentation + of the <seealso marker="erl#+sws">+sws</seealso> command + line argument of <c>erl</c>.</p> + <p> + Own Id: OTP-10033 Aux Id: Seq12025 </p> + </item> + <item> + <p> + A switch for configuration of busy wait length for + scheduler threads has been added. For more information + see the documentation of the <seealso + marker="erl#+sbwt">+sbwt</seealso> command line argument + of <c>erl</c>.</p> + <p> + Own Id: OTP-10044 Aux Id: Seq11976 </p> + </item> + <item> + <p> + The extra memory barriers introduced by bug-fix OTP-9281 + were unnecessarily used also on tables without the + <c>write_concurrency</c> option enabled. This could + unnecessarily degrade performance of ETS tables without + <c>write_concurrency</c> on some hardware (e.g. PowerPC) + while not effecting performance at all on other hardware + (e.g. x86/x86_64).</p> + <p> + OTP-9281 (R14B03): ETS tables using the + <c>write_concurrency</c> option could potentially get + into an internally inconsistent state.</p> + <p> + Own Id: OTP-10048 Aux Id: OTP-9281 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 5.9.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 02735d4b68..78c566ed38 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -391,6 +391,7 @@ atom opt atom or atom ordered_set atom orelse +atom os_pid atom os_type atom os_version atom ose_bg_proc diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index f321ed21aa..cb975d64b0 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -253,7 +253,9 @@ erts_get_async_ready_queue(Uint sched_id) static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) { +#ifdef USE_VM_PROBES int len; +#endif if (is_internal_port(a->port)) { #if ERTS_USE_ASYNC_READY_Q @@ -291,7 +293,9 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, int saved_fin_deq = 0; ErtsThrQFinDeQ_t fin_deq; #endif +#ifdef USE_VM_PROBES int len; +#endif while (1) { ErtsAsync *a = (ErtsAsync *) erts_thr_q_dequeue(q); diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index f889ccdb93..2373dc7af4 100644..100755 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -2765,7 +2765,8 @@ port_info_1(BIF_ALIST_1) am_id, am_connected, am_input, - am_output + am_output, + am_os_pid }; Eterm items[ASIZE(keys)]; Eterm result = NIL; @@ -2822,6 +2823,7 @@ port_info_1(BIF_ALIST_1) ** name String ** input Number of bytes input from port program ** output Number of bytes output to the port program +** os_pid The child's process ID */ BIF_RETTYPE port_info_2(BIF_ALIST_2) @@ -2922,6 +2924,18 @@ static BIF_RETTYPE port_info(Process* p, Eterm portid, Eterm item) hp = HAlloc(p, hsz); res = erts_bld_uint(&hp, NULL, n); } + else if (item == am_os_pid) { + if (prt->os_pid >= 0) { + Uint hsz = 3; + UWord n = prt->os_pid; + (void) erts_bld_uword(NULL, &hsz, n); + hp = HAlloc(p, hsz); + res = erts_bld_uword(&hp, NULL, n); + } else { + hp = HAlloc(p, 3); + res = am_undefined; + } + } else if (item == am_registered_name) { RegProc *reg; reg = prt->reg; @@ -4110,48 +4124,52 @@ BIF_RETTYPE erts_debug_lock_counters_1(BIF_ALIST_1) Eterm* tp = tuple_val(BIF_ARG_1); switch (arityval(tp[0])) { - case 2: + case 2: { + int opt = 0; + int val = 0; if (ERTS_IS_ATOM_STR("copy_save", tp[1])) { - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - if (tp[2] == am_true) { - - res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_COPYSAVE) ? am_true : am_false; - - } else if (tp[2] == am_false) { - - res = erts_lcnt_clear_rt_opt(ERTS_LCNT_OPT_COPYSAVE) ? am_true : am_false; - - } else { - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_ERROR(BIF_P, BADARG); - } - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); - + opt = ERTS_LCNT_OPT_COPYSAVE; } else if (ERTS_IS_ATOM_STR("process_locks", tp[1])) { - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - if (tp[2] == am_true) { - - res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_PROCLOCK) ? am_true : am_false; - - } else if (tp[2] == am_false) { - - res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_PROCLOCK) ? am_true : am_false; + opt = ERTS_LCNT_OPT_PROCLOCK; + } else if (ERTS_IS_ATOM_STR("port_locks", tp[1])) { + opt = ERTS_LCNT_OPT_PORTLOCK; + } else if (ERTS_IS_ATOM_STR("suspend", tp[1])) { + opt = ERTS_LCNT_OPT_SUSPEND; + } else if (ERTS_IS_ATOM_STR("location", tp[1])) { + opt = ERTS_LCNT_OPT_LOCATION; + } else { + BIF_ERROR(BIF_P, BADARG); + } + if (tp[2] == am_true) { + val = 1; + } else if (tp[2] == am_false) { + val = 0; + } else { + BIF_ERROR(BIF_P, BADARG); + } - } else { - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_ERROR(BIF_P, BADARG); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + + if (val) { + res = erts_lcnt_set_rt_opt(opt) ? am_true : am_false; + } else { + res = erts_lcnt_clear_rt_opt(opt) ? am_true : am_false; + } +#ifdef ERTS_SMP + if (res != tp[2]) { + if (opt == ERTS_LCNT_OPT_PORTLOCK) { + erts_lcnt_enable_io_lock_count(val); + } else if (opt == ERTS_LCNT_OPT_PROCLOCK) { + erts_lcnt_enable_proc_lock_count(val); } - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); - } - break; + } +#endif + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + BIF_RET(res); + break; + } default: break; diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index c726be5fb4..2fea4671e1 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -105,7 +105,20 @@ #define NSEG_2 256 /* Size of second segment table */ #define NSEG_INC 128 /* Number of segments to grow after that */ -#define SEGTAB(tb) ((struct segment**)erts_smp_atomic_read_ddrb(&(tb)->segtab)) +#ifdef ERTS_SMP +# define DB_USING_FINE_LOCKING(TB) (((TB))->common.type & DB_FINE_LOCKED) +#else +# define DB_USING_FINE_LOCKING(TB) 0 +#endif + +#ifdef ETHR_ORDERED_READ_DEPEND +#define SEGTAB(tb) ((struct segment**) erts_smp_atomic_read_nob(&(tb)->segtab)) +#else +#define SEGTAB(tb) \ + (DB_USING_FINE_LOCKING(tb) \ + ? ((struct segment**) erts_smp_atomic_read_ddrb(&(tb)->segtab)) \ + : ((struct segment**) erts_smp_atomic_read_nob(&(tb)->segtab))) +#endif #define NACTIVE(tb) ((int)erts_smp_atomic_read_nob(&(tb)->nactive)) #define NITEMS(tb) ((int)erts_smp_atomic_read_nob(&(tb)->common.nitems)) @@ -122,7 +135,9 @@ */ static ERTS_INLINE Uint hash_to_ix(DbTableHash* tb, HashValue hval) { - Uint mask = erts_smp_atomic_read_acqb(&tb->szm); + Uint mask = (DB_USING_FINE_LOCKING(tb) + ? erts_smp_atomic_read_acqb(&tb->szm) + : erts_smp_atomic_read_nob(&tb->szm)); Uint ix = hval & mask; if (ix >= erts_smp_atomic_read_nob(&tb->nactive)) { ix &= mask>>1; @@ -319,7 +334,10 @@ struct ext_segment { static ERTS_INLINE void SET_SEGTAB(DbTableHash* tb, struct segment** segtab) { - erts_smp_atomic_set_wb(&tb->segtab, (erts_aint_t) segtab); + if (DB_USING_FINE_LOCKING(tb)) + erts_smp_atomic_set_wb(&tb->segtab, (erts_aint_t) segtab); + else + erts_smp_atomic_set_nob(&tb->segtab, (erts_aint_t) segtab); #ifdef VALGRIND tb->top_ptr_to_segment_with_active_segtab = EXTSEG(segtab); #endif @@ -2501,6 +2519,28 @@ static Eterm build_term_list(Process* p, HashDbTerm* ptr1, HashDbTerm* ptr2, return list; } +static ERTS_INLINE int +begin_resizing(DbTableHash* tb) +{ + if (DB_USING_FINE_LOCKING(tb)) + return !erts_smp_atomic_xchg_acqb(&tb->is_resizing, 1); + else { + if (erts_smp_atomic_read_nob(&tb->is_resizing)) + return 0; + erts_smp_atomic_set_nob(&tb->is_resizing, 1); + return 1; + } +} + +static ERTS_INLINE void +done_resizing(DbTableHash* tb) +{ + if (DB_USING_FINE_LOCKING(tb)) + erts_smp_atomic_set_relb(&tb->is_resizing, 0); + else + erts_smp_atomic_set_nob(&tb->is_resizing, 0); +} + /* Grow table with one new bucket. ** Allocate new segment if needed. */ @@ -2513,9 +2553,8 @@ static void grow(DbTableHash* tb, int nactive) int from_ix; int szm; - if (erts_smp_atomic_xchg_acqb(&tb->is_resizing, 1)) { + if (!begin_resizing(tb)) return; /* already in progress */ - } if (NACTIVE(tb) != nactive) { goto abort; /* already done (race) */ } @@ -2547,9 +2586,12 @@ static void grow(DbTableHash* tb, int nactive) } erts_smp_atomic_inc_nob(&tb->nactive); if (from_ix == 0) { - erts_smp_atomic_set_relb(&tb->szm, szm); + if (DB_USING_FINE_LOCKING(tb)) + erts_smp_atomic_set_relb(&tb->szm, szm); + else + erts_smp_atomic_set_nob(&tb->szm, szm); } - erts_smp_atomic_set_relb(&tb->is_resizing, 0); + done_resizing(tb); /* Finally, let's split the bucket. We try to do it in a smart way to keep link order and avoid unnecessary updates of next-pointers */ @@ -2581,7 +2623,7 @@ static void grow(DbTableHash* tb, int nactive) return; abort: - erts_smp_atomic_set_relb(&tb->is_resizing, 0); + done_resizing(tb); } @@ -2590,9 +2632,8 @@ abort: */ static void shrink(DbTableHash* tb, int nactive) { - if (erts_smp_atomic_xchg_acqb(&tb->is_resizing, 1)) { + if (!begin_resizing(tb)) return; /* already in progress */ - } if (NACTIVE(tb) == nactive) { erts_smp_rwmtx_t* lck; int src_ix = nactive - 1; @@ -2639,7 +2680,7 @@ static void shrink(DbTableHash* tb, int nactive) } /*else already done */ - erts_smp_atomic_set_relb(&tb->is_resizing, 0); + done_resizing(tb); } diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index ca4385dd3a..7bf8d14708 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -511,10 +511,14 @@ void erts_usage(void) erts_fprintf(stderr, "-rg amount set reader groups limit\n"); erts_fprintf(stderr, "-sbt type set scheduler bind type, valid types are:\n"); erts_fprintf(stderr, " u|ns|ts|ps|s|nnts|nnps|tnnps|db\n"); + erts_fprintf(stderr, "-sbwt val set scheduler busy wait threshold, valid values are:\n"); + erts_fprintf(stderr, " none|very_short|short|medium|long|very_long.\n"); erts_fprintf(stderr, "-scl bool enable/disable compaction of scheduler load,\n"); erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); erts_fprintf(stderr, "-sct cput set cpu topology,\n"); erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); + erts_fprintf(stderr, "-sws val set scheduler wakeup strategy, valid values are:\n"); + erts_fprintf(stderr, " default|legacy|proposal.\n"); erts_fprintf(stderr, "-swt val set scheduler wakeup threshold, valid values are:\n"); erts_fprintf(stderr, " very_low|low|medium|high|very_high.\n"); erts_fprintf(stderr, "-sss size suggested stack size in kilo words for scheduler threads,\n"); @@ -790,6 +794,10 @@ early_init(int *argc, char **argv) /* } } +#ifndef USE_THREADS + erts_async_max_threads = 0; +#endif + #ifdef ERTS_SMP no_schedulers = schdlrs; no_schedulers_online = schdlrs_onln; @@ -1198,6 +1206,16 @@ erl_start(int argc, char **argv) erts_usage(); } } + else if (has_prefix("bwt", sub_param)) { + arg = get_arg(sub_param+3, argv[i+1], &i); + if (erts_sched_set_busy_wait_threshold(arg) != 0) { + erts_fprintf(stderr, "bad scheduler busy wait threshold: %s\n", + arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, + ("scheduler wakup threshold: %s\n", arg)); + } else if (has_prefix("cl", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); if (sys_strcmp("true", arg) == 0) @@ -1258,13 +1276,23 @@ erl_start(int argc, char **argv) erts_use_sender_punish = 0; else if (sys_strcmp("wt", sub_param) == 0) { arg = get_arg(sub_param+2, argv[i+1], &i); - if (erts_sched_set_wakeup_limit(arg) != 0) { + if (erts_sched_set_wakeup_other_thresold(arg) != 0) { erts_fprintf(stderr, "scheduler wakeup threshold: %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, - ("scheduler wakup threshold: %s\n", arg)); + ("scheduler wakeup threshold: %s\n", arg)); + } + else if (sys_strcmp("ws", sub_param) == 0) { + arg = get_arg(sub_param+2, argv[i+1], &i); + if (erts_sched_set_wakeup_other_type(arg) != 0) { + erts_fprintf(stderr, "scheduler wakeup strategy: %s\n", + arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, + ("scheduler wakeup threshold: %s\n", arg)); } else if (has_prefix("ss", sub_param)) { /* suggested stack size (Kilo Words) for scheduler threads */ diff --git a/erts/emulator/beam/erl_lock_count.c b/erts/emulator/beam/erl_lock_count.c index a36c53560e..741c0cb08e 100644 --- a/erts/emulator/beam/erl_lock_count.c +++ b/erts/emulator/beam/erl_lock_count.c @@ -49,7 +49,7 @@ const char *str_undefined = "undefined"; static ethr_tsd_key lcnt_thr_data_key; static int lcnt_n_thr; -static erts_lcnt_thread_data_t *lcnt_thread_data[1024]; +static erts_lcnt_thread_data_t *lcnt_thread_data[4096]; /* local functions */ @@ -240,7 +240,7 @@ void erts_lcnt_init() { lcnt_lock(); - erts_lcnt_rt_options = ERTS_LCNT_OPT_PROCLOCK; + erts_lcnt_rt_options = ERTS_LCNT_OPT_PROCLOCK | ERTS_LCNT_OPT_LOCATION; eltd = lcnt_thread_data_alloc(); @@ -312,7 +312,7 @@ void erts_lcnt_list_insert(erts_lcnt_lock_list_t *list, erts_lcnt_lock_t *lock) } void erts_lcnt_list_delete(erts_lcnt_lock_list_t *list, erts_lcnt_lock_t *lock) { - + if (lock->next) lock->next->prev = lock->prev; if (lock->prev) lock->prev->next = lock->next; if (list->head == lock) list->head = lock->next; @@ -334,6 +334,10 @@ void erts_lcnt_init_lock(erts_lcnt_lock_t *lock, char *name, Uint16 flag ) { } void erts_lcnt_init_lock_x(erts_lcnt_lock_t *lock, char *name, Uint16 flag, Eterm id) { int i; + if (!name) { + lock->flag = 0; + return; + } lcnt_lock(); lock->next = NULL; @@ -363,6 +367,8 @@ void erts_lcnt_init_lock_x(erts_lcnt_lock_t *lock, char *name, Uint16 flag, Eter void erts_lcnt_destroy_lock(erts_lcnt_lock_t *lock) { erts_lcnt_lock_t *deleted_lock; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; + lcnt_lock(); if (erts_lcnt_rt_options & ERTS_LCNT_OPT_COPYSAVE) { @@ -378,6 +384,7 @@ void erts_lcnt_destroy_lock(erts_lcnt_lock_t *lock) { } /* delete original */ erts_lcnt_list_delete(erts_lcnt_data->current_locks, lock); + lock->flag = 0; lcnt_unlock(); } @@ -389,6 +396,7 @@ void erts_lcnt_lock_opt(erts_lcnt_lock_t *lock, Uint16 option) { erts_lcnt_thread_data_t *eltd; if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; eltd = lcnt_get_thread_data(); @@ -422,6 +430,7 @@ void erts_lcnt_lock(erts_lcnt_lock_t *lock) { erts_lcnt_thread_data_t *eltd; if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; w_state = ethr_atomic_read(&lock->w_state); ethr_atomic_inc( &lock->w_state); @@ -452,6 +461,7 @@ void erts_lcnt_lock_unaquire(erts_lcnt_lock_t *lock) { /* should check if this thread was "waiting" */ if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; ethr_atomic_dec( &lock->w_state); } @@ -475,6 +485,7 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; #ifdef DEBUG if (!(lock->flag & (ERTS_LCNT_LT_RWMUTEX | ERTS_LCNT_LT_RWSPINLOCK))) { @@ -489,9 +500,13 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line ASSERT(eltd); /* if lock was in conflict, time it */ - - stats = lcnt_get_lock_stats(lock, file, line); + if (erts_lcnt_rt_options & ERTS_LCNT_OPT_LOCATION) { + stats = lcnt_get_lock_stats(lock, file, line); + } else { + stats = &lock->stats[0]; + } + if (eltd->timer_set) { lcnt_time(&timer); @@ -510,6 +525,7 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line void erts_lcnt_unlock_opt(erts_lcnt_lock_t *lock, Uint16 option) { if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; if (option & ERTS_LCNT_LO_WRITE) ethr_atomic_dec(&lock->w_state); if (option & ERTS_LCNT_LO_READ ) ethr_atomic_dec(&lock->r_state); } @@ -520,6 +536,7 @@ void erts_lcnt_unlock(erts_lcnt_lock_t *lock) { erts_aint_t flowstate; #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; #ifdef DEBUG /* flowstate */ flowstate = ethr_atomic_read(&lock->flowstate); @@ -537,6 +554,7 @@ void erts_lcnt_unlock(erts_lcnt_lock_t *lock) { void erts_lcnt_trylock_opt(erts_lcnt_lock_t *lock, int res, Uint16 option) { if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; /* Determine lock_state via res instead of state */ if (res != EBUSY) { if (option & ERTS_LCNT_LO_WRITE) ethr_atomic_inc(&lock->w_state); @@ -555,6 +573,7 @@ void erts_lcnt_trylock(erts_lcnt_lock_t *lock, int res) { erts_aint_t flowstate; #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; if (res != EBUSY) { #ifdef DEBUG diff --git a/erts/emulator/beam/erl_lock_count.h b/erts/emulator/beam/erl_lock_count.h index 6306580ae4..690551c71f 100644 --- a/erts/emulator/beam/erl_lock_count.h +++ b/erts/emulator/beam/erl_lock_count.h @@ -89,6 +89,7 @@ #define ERTS_LCNT_OPT_LOCATION (((Uint16) 1) << 1) #define ERTS_LCNT_OPT_PROCLOCK (((Uint16) 1) << 2) #define ERTS_LCNT_OPT_COPYSAVE (((Uint16) 1) << 3) +#define ERTS_LCNT_OPT_PORTLOCK (((Uint16) 1) << 4) typedef struct { unsigned long s; @@ -201,5 +202,7 @@ void erts_lcnt_clear_counters(void); char *erts_lcnt_lock_type(Uint16 type); erts_lcnt_data_t *erts_lcnt_get_data(void); +#define ERTS_LCNT_LOCK_TYPE(lockp) ((lockp)->flag & ERTS_LCNT_LT_ALL) + #endif /* ifdef ERTS_ENABLE_LOCK_COUNT */ #endif /* ifndef ERTS_LOCK_COUNT_H__ */ diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 95d408f79d..09ca536188 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -52,21 +52,22 @@ #define ERTS_SCHED_SPIN_UNTIL_YIELD 100 -#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT 10 +#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT_VERY_LONG 40 +#define ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_VERY_LONG 1000 +#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT_LONG 20 +#define ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_LONG 1000 +#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM 10 +#define ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_MEDIUM 1000 +#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT_SHORT 10 +#define ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_SHORT 0 +#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT_VERY_SHORT 5 +#define ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_VERY_SHORT 0 +#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT_NONE 0 +#define ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_NONE 0 + #define ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT 1000 -#define ERTS_SCHED_TSE_SLEEP_SPINCOUNT \ - (ERTS_SCHED_SYS_SLEEP_SPINCOUNT*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT) #define ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT 0 -#define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH (200*CONTEXT_REDS) -#define ERTS_WAKEUP_OTHER_LIMIT_HIGH (50*CONTEXT_REDS) -#define ERTS_WAKEUP_OTHER_LIMIT_MEDIUM (10*CONTEXT_REDS) -#define ERTS_WAKEUP_OTHER_LIMIT_LOW (CONTEXT_REDS) -#define ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW (CONTEXT_REDS/10) - -#define ERTS_WAKEUP_OTHER_DEC 10 -#define ERTS_WAKEUP_OTHER_FIXED_INC (CONTEXT_REDS/10) - #if 0 || defined(DEBUG) #define ERTS_FAKE_SCHED_BIND_PRINT_SORTED_CPU_DATA #endif @@ -123,14 +124,18 @@ Uint erts_no_schedulers; Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES; Uint erts_process_tab_index_mask; -static int wakeup_other_limit; - int erts_sched_thread_suggested_stack_size = -1; #ifdef ERTS_ENABLE_LOCK_CHECK ErtsLcPSDLocks erts_psd_required_locks[ERTS_PSD_SIZE]; #endif +static struct { + int aux_work; + int tse; + int sys_schedule; +} sched_busy_wait; + #ifdef ERTS_SMP int erts_disable_proc_not_running_opt; @@ -2046,7 +2051,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) erts_smp_runq_unlock(rq); - spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT; + spincount = sched_busy_wait.tse; tse_wait: @@ -2097,7 +2102,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) } flgs = sched_prep_cont_spin_wait(ssi); - spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT; + spincount = sched_busy_wait.aux_work; if (!(flgs & ERTS_SSI_FLG_WAITING)) { ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING)); @@ -2134,7 +2139,9 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) ASSERT(working); sched_wall_time_change(esdp, working = 0); - spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT; + spincount = sched_busy_wait.sys_schedule; + if (spincount == 0) + goto sys_aux_work; while (spincount-- > 0) { @@ -3560,31 +3567,280 @@ erts_debug_nbalance(void) #endif } +/* Wakeup other schedulers */ + +typedef enum { + ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH, + ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH, + ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM, + ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW, + ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW +} ErtsSchedWakeupOtherThreshold; + +typedef enum { + ERTS_SCHED_WAKEUP_OTHER_TYPE_PROPOSAL, + ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY +} ErtsSchedWakeupOtherType; + +/* First proposal */ + +#define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH (200*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_HIGH (50*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_MEDIUM (10*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_LOW (CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW (CONTEXT_REDS/10) + +#define ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_HIGH 3 +#define ERTS_WAKEUP_OTHER_DEC_SHIFT_HIGH 1 +#define ERTS_WAKEUP_OTHER_DEC_SHIFT_MEDIUM 0 +#define ERTS_WAKEUP_OTHER_DEC_SHIFT_LOW -2 +#define ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_LOW -5 + +#define ERTS_WAKEUP_OTHER_DEC_SHIFT 2 +#define ERTS_WAKEUP_OTHER_FIXED_INC (CONTEXT_REDS/10) + +/* To be legacy */ + +#define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH_LEGACY (200*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_HIGH_LEGACY (50*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_MEDIUM_LEGACY (10*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_LOW_LEGACY (CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW_LEGACY (CONTEXT_REDS/10) + +#define ERTS_WAKEUP_OTHER_DEC_LEGACY 10 +#define ERTS_WAKEUP_OTHER_FIXED_INC_LEGACY (CONTEXT_REDS/10) + +#ifdef ERTS_SMP + +static struct { + ErtsSchedWakeupOtherThreshold threshold; + ErtsSchedWakeupOtherType type; + int limit; + int dec_shift; + int dec_mask; + void (*check)(ErtsRunQueue *rq); +} wakeup_other; + +static void +wakeup_other_check(ErtsRunQueue *rq) +{ + int wo_reds = rq->wakeup_other_reds; + if (wo_reds) { + int left_len = rq->len - 1; + if (left_len < 1) { + int wo_reduce = wo_reds << wakeup_other.dec_shift; + wo_reduce &= wakeup_other.dec_mask; + rq->wakeup_other -= wo_reduce; + if (rq->wakeup_other < 0) + rq->wakeup_other = 0; + } + else { + rq->wakeup_other += (left_len*wo_reds + + ERTS_WAKEUP_OTHER_FIXED_INC); + if (rq->wakeup_other > wakeup_other.limit) { + int empty_rqs = + erts_smp_atomic32_read_acqb(&no_empty_run_queues); + if (empty_rqs != 0) + wake_scheduler_on_empty_runq(rq); + rq->wakeup_other = 0; + } + } + rq->wakeup_other_reds = 0; + } +} + +static void +wakeup_other_set_limit(void) +{ + switch (wakeup_other.threshold) { + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH; + wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_HIGH; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH; + wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_HIGH; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM; + wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_MEDIUM; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_LOW; + wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_LOW; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW; + wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_LOW; + break; + } + if (wakeup_other.dec_shift < 0) + wakeup_other.dec_mask = (1 << (sizeof(wakeup_other.dec_mask)*8 + + wakeup_other.dec_shift)) - 1; + else { + wakeup_other.dec_mask = 0; + wakeup_other.dec_mask = ~wakeup_other.dec_mask; + } +} + +static void +wakeup_other_check_legacy(ErtsRunQueue *rq) +{ + int wo_reds = rq->wakeup_other_reds; + if (wo_reds) { + if (rq->len < 2) { + rq->wakeup_other -= ERTS_WAKEUP_OTHER_DEC_LEGACY*wo_reds; + if (rq->wakeup_other < 0) + rq->wakeup_other = 0; + } + else if (rq->wakeup_other < wakeup_other.limit) + rq->wakeup_other += rq->len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC_LEGACY; + else { + if (erts_smp_atomic32_read_acqb(&no_empty_run_queues) != 0) { + wake_scheduler_on_empty_runq(rq); + rq->wakeup_other = 0; + } + rq->wakeup_other = 0; + } + } + rq->wakeup_other_reds = 0; +} + +static void +wakeup_other_set_limit_legacy(void) +{ + switch (wakeup_other.threshold) { + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH_LEGACY; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH_LEGACY; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM_LEGACY; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_LOW_LEGACY; + break; + case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW: + wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW_LEGACY; + break; + } +} + +static void +set_wakeup_other_data(void) +{ + switch (wakeup_other.type) { + case ERTS_SCHED_WAKEUP_OTHER_TYPE_PROPOSAL: + wakeup_other.check = wakeup_other_check; + wakeup_other_set_limit(); + break; + case ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY: + wakeup_other.check = wakeup_other_check_legacy; + wakeup_other_set_limit_legacy(); + break; + } +} + +#endif + void erts_early_init_scheduling(int no_schedulers) { aux_work_timeout_early_init(no_schedulers); - wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM; +#ifdef ERTS_SMP + wakeup_other.threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM; + wakeup_other.type = ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY; +#endif + sched_busy_wait.sys_schedule = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM; + sched_busy_wait.tse = (ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM + * ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT); + sched_busy_wait.aux_work = (ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM + * ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_MEDIUM); } int -erts_sched_set_wakeup_limit(char *str) +erts_sched_set_wakeup_other_thresold(char *str) { + ErtsSchedWakeupOtherThreshold threshold; if (sys_strcmp(str, "very_high") == 0) - wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH; + threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH; else if (sys_strcmp(str, "high") == 0) - wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH; + threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH; else if (sys_strcmp(str, "medium") == 0) - wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM; + threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM; else if (sys_strcmp(str, "low") == 0) - wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_LOW; + threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW; else if (sys_strcmp(str, "very_low") == 0) - wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW; + threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW; + else + return EINVAL; +#ifdef ERTS_SMP + wakeup_other.threshold = threshold; + set_wakeup_other_data(); +#endif + return 0; +} + +int +erts_sched_set_wakeup_other_type(char *str) +{ + ErtsSchedWakeupOtherType type; + if (sys_strcmp(str, "proposal") == 0) + type = ERTS_SCHED_WAKEUP_OTHER_TYPE_PROPOSAL; + else if (sys_strcmp(str, "default") == 0) + type = ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY; + else if (sys_strcmp(str, "legacy") == 0) + type = ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY; else return EINVAL; +#ifdef ERTS_SMP + wakeup_other.type = type; +#endif return 0; } +int +erts_sched_set_busy_wait_threshold(char *str) +{ + int sys_sched; + int aux_work_fact; + + if (sys_strcmp(str, "very_long") == 0) { + sys_sched = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_VERY_LONG; + aux_work_fact = ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_VERY_LONG; + } + else if (sys_strcmp(str, "long") == 0) { + sys_sched = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_LONG; + aux_work_fact = ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_LONG; + } + else if (sys_strcmp(str, "medium") == 0) { + sys_sched = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM; + aux_work_fact = ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_MEDIUM; + } + else if (sys_strcmp(str, "short") == 0) { + sys_sched = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_SHORT; + aux_work_fact = ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_SHORT; + } + else if (sys_strcmp(str, "very_short") == 0) { + sys_sched = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_VERY_SHORT; + aux_work_fact = ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_VERY_SHORT; + } + else if (sys_strcmp(str, "none") == 0) { + sys_sched = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_NONE; + aux_work_fact = ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_NONE; + } + else { + return EINVAL; + } + + sched_busy_wait.sys_schedule = sys_sched; + sched_busy_wait.tse = sys_sched*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT; + sched_busy_wait.aux_work = sys_sched*aux_work_fact; + + return 0; +} static void init_aux_work_data(ErtsAuxWorkData *awdp, ErtsSchedulerData *esdp) { @@ -3613,6 +3869,10 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) init_misc_op_list_alloc(); +#ifdef ERTS_SMP + set_wakeup_other_data(); +#endif + ASSERT(no_schedulers_online <= no_schedulers); ASSERT(no_schedulers_online >= 1); ASSERT(no_schedulers >= 1); @@ -6502,26 +6762,7 @@ Process *schedule(Process *p, int calls) exec_misc_ops(rq); #ifdef ERTS_SMP - { - int wo_reds = rq->wakeup_other_reds; - if (wo_reds) { - if (rq->len < 2) { - rq->wakeup_other -= ERTS_WAKEUP_OTHER_DEC*wo_reds; - if (rq->wakeup_other < 0) - rq->wakeup_other = 0; - } - else if (rq->wakeup_other < wakeup_other_limit) - rq->wakeup_other += rq->len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC; - else { - if (erts_smp_atomic32_read_acqb(&no_empty_run_queues) != 0) { - wake_scheduler_on_empty_runq(rq); - rq->wakeup_other = 0; - } - rq->wakeup_other = 0; - } - } - rq->wakeup_other_reds = 0; - } + wakeup_other.check(rq); #endif /* diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index cff0783bc4..28aaedf2e2 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1096,7 +1096,9 @@ ErtsProcList *erts_proclist_create(Process *); void erts_proclist_destroy(ErtsProcList *); int erts_proclist_same(ErtsProcList *, Process *); -int erts_sched_set_wakeup_limit(char *str); +int erts_sched_set_wakeup_other_thresold(char *str); +int erts_sched_set_wakeup_other_type(char *str); +int erts_sched_set_busy_wait_threshold(char *str); #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) int erts_dbg_check_halloc_lock(Process *p); @@ -1400,10 +1402,14 @@ ERTS_GLB_INLINE Eterm erts_get_current_pid(void); ERTS_GLB_INLINE Uint erts_get_scheduler_id(void); ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_proc(Process *p); ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_current(ErtsSchedulerData *esdp); +#ifndef ERTS_ENABLE_LOCK_COUNT ERTS_GLB_INLINE void erts_smp_runq_lock(ErtsRunQueue *rq); +#endif ERTS_GLB_INLINE int erts_smp_runq_trylock(ErtsRunQueue *rq); ERTS_GLB_INLINE void erts_smp_runq_unlock(ErtsRunQueue *rq); +#ifndef ERTS_ENABLE_LOCK_COUNT ERTS_GLB_INLINE void erts_smp_xrunq_lock(ErtsRunQueue *rq, ErtsRunQueue *xrq); +#endif ERTS_GLB_INLINE void erts_smp_xrunq_unlock(ErtsRunQueue *rq, ErtsRunQueue *xrq); ERTS_GLB_INLINE void erts_smp_runqs_lock(ErtsRunQueue *rq1, ErtsRunQueue *rq2); ERTS_GLB_INLINE void erts_smp_runqs_unlock(ErtsRunQueue *rq1, ErtsRunQueue *rq2); @@ -1492,6 +1498,12 @@ erts_get_runq_current(ErtsSchedulerData *esdp) #endif } +#ifdef ERTS_ENABLE_LOCK_COUNT + +#define erts_smp_runq_lock(rq) erts_smp_mtx_lock_x(&(rq)->mtx, __FILE__, __LINE__) + +#else + ERTS_GLB_INLINE void erts_smp_runq_lock(ErtsRunQueue *rq) { @@ -1500,6 +1512,8 @@ erts_smp_runq_lock(ErtsRunQueue *rq) #endif } +#endif + ERTS_GLB_INLINE int erts_smp_runq_trylock(ErtsRunQueue *rq) { @@ -1518,6 +1532,31 @@ erts_smp_runq_unlock(ErtsRunQueue *rq) #endif } +#ifdef ERTS_ENABLE_LOCK_COUNT + +#define erts_smp_xrunq_lock(rq, xrq) erts_smp_xrunq_lock_x((rq), (xrq), __FILE__, __LINE__) + +ERTS_GLB_INLINE void +erts_smp_xrunq_lock_x(ErtsRunQueue *rq, ErtsRunQueue *xrq, char* file, int line) +{ +#ifdef ERTS_SMP + ERTS_SMP_LC_ASSERT(erts_smp_lc_mtx_is_locked(&rq->mtx)); + if (xrq != rq) { + if (erts_smp_mtx_trylock(&xrq->mtx) == EBUSY) { + if (rq < xrq) + erts_smp_mtx_lock_x(&xrq->mtx, file, line); + else { + erts_smp_mtx_unlock(&rq->mtx); + erts_smp_mtx_lock_x(&xrq->mtx, file, line); + erts_smp_mtx_lock_x(&rq->mtx, file, line); + } + } + } +#endif +} + +#else + ERTS_GLB_INLINE void erts_smp_xrunq_lock(ErtsRunQueue *rq, ErtsRunQueue *xrq) { @@ -1537,6 +1576,8 @@ erts_smp_xrunq_lock(ErtsRunQueue *rq, ErtsRunQueue *xrq) #endif } +#endif + ERTS_GLB_INLINE void erts_smp_xrunq_unlock(ErtsRunQueue *rq, ErtsRunQueue *xrq) { diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c index a5a753b798..b3b4601a31 100644 --- a/erts/emulator/beam/erl_process_lock.c +++ b/erts/emulator/beam/erl_process_lock.c @@ -1002,7 +1002,7 @@ erts_proc_lock_init(Process *p) #ifdef ERTS_ENABLE_LOCK_COUNT void erts_lcnt_proc_lock_init(Process *p) { - + if (erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK) { if (p->id != ERTS_INVALID_PID) { erts_lcnt_init_lock_x(&(p->lock.lcnt_main), "proc_main", ERTS_LCNT_LT_PROCLOCK, p->id); erts_lcnt_init_lock_x(&(p->lock.lcnt_msgq), "proc_msgq", ERTS_LCNT_LT_PROCLOCK, p->id); @@ -1014,6 +1014,12 @@ void erts_lcnt_proc_lock_init(Process *p) { erts_lcnt_init_lock(&(p->lock.lcnt_link), "proc_link", ERTS_LCNT_LT_PROCLOCK); erts_lcnt_init_lock(&(p->lock.lcnt_status), "proc_status", ERTS_LCNT_LT_PROCLOCK); } + } else { + sys_memzero(&(p->lock.lcnt_main), sizeof(p->lock.lcnt_main)); + sys_memzero(&(p->lock.lcnt_msgq), sizeof(p->lock.lcnt_msgq)); + sys_memzero(&(p->lock.lcnt_link), sizeof(p->lock.lcnt_link)); + sys_memzero(&(p->lock.lcnt_status), sizeof(p->lock.lcnt_status)); + } } @@ -1108,6 +1114,26 @@ void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res } } + +void erts_lcnt_enable_proc_lock_count(int enable) { + int i; + + for (i = 0; i < erts_max_processes; ++i) { + Process* p = process_tab[i]; + if (p) { + if (enable) { + if (!ERTS_LCNT_LOCK_TYPE(&(p->lock.lcnt_main))) { + erts_lcnt_proc_lock_init(p); + } + } else { + if (ERTS_LCNT_LOCK_TYPE(&(p->lock.lcnt_main))) { + erts_lcnt_proc_lock_destroy(p); + } + } + } + } +} + #endif /* ifdef ERTS_ENABLE_LOCK_COUNT */ diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h index 8dbdaccc68..413c45480c 100644 --- a/erts/emulator/beam/erl_process_lock.h +++ b/erts/emulator/beam/erl_process_lock.h @@ -215,6 +215,8 @@ void erts_lcnt_proc_lock_unaquire(erts_proc_lock_t *lock, ErtsProcLocks locks); void erts_lcnt_proc_unlock(erts_proc_lock_t *lock, ErtsProcLocks locks); void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res); +void erts_lcnt_enable_proc_lock_count(int enable); + #endif /* ERTS_ENABLE_LOCK_COUNT*/ diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index b000e2c5d4..894872dbc0 100644..100755 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -173,6 +173,7 @@ struct port { char *name; /* String used in the open */ erts_driver_t* drv_ptr; UWord drv_data; + SWord os_pid; /* Child process ID */ ErtsProcList *suspended; /* List of suspended processes. */ LineBuf *linebuf; /* Buffer to hold data not ready for process to get (line oriented I/O)*/ @@ -1187,6 +1188,10 @@ void erts_fire_port_monitor(Port *prt, Eterm ref); void erts_smp_xports_unlock(Port *); #endif +#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_COUNT) +void erts_lcnt_enable_io_lock_count(int enable); +#endif + #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) int erts_lc_is_port_locked(Port *); #endif diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 8a2a43bebd..204bff299e 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -440,6 +440,7 @@ setup_port(Port* prt, Eterm pid, erts_driver_t *driver, sys_strcpy(new_name, name); erts_smp_runq_lock(runq); erts_smp_port_state_lock(prt); + prt->os_pid = -1; prt->status = ERTS_PORT_SFLG_CONNECTED | xstatus; prt->snapshot = erts_smp_atomic32_read_nob(&erts_ports_snapshot); old_name = prt->name; @@ -625,7 +626,11 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ port->lock = erts_alloc(ERTS_ALC_T_PORT_LOCK, sizeof(erts_smp_mtx_t)); erts_smp_mtx_init_x(port->lock, +#ifdef ERTS_ENABLE_LOCK_COUNT + (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_lock" : NULL, +#else "port_lock", +#endif port->id); xstatus |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK; } @@ -783,7 +788,13 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */ creator_port->xports = xplp; port->lock = erts_alloc(ERTS_ALC_T_PORT_LOCK, sizeof(erts_smp_mtx_t)); - erts_smp_mtx_init_locked_x(port->lock, "port_lock", port_id); + erts_smp_mtx_init_locked_x(port->lock, +#ifdef ERTS_ENABLE_LOCK_COUNT + (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_lock" : NULL, +#else + "port_lock", +#endif + port_id); xstatus |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK; } @@ -1347,7 +1358,13 @@ void init_io(void) erts_smp_atomic_init_nob(&erts_port[i].refc, 0); erts_port[i].lock = NULL; erts_port[i].xports = NULL; - erts_smp_spinlock_init_x(&erts_port[i].state_lck, "port_state", make_small(i)); + erts_smp_spinlock_init_x(&erts_port[i].state_lck, +#ifdef ERTS_ENABLE_LOCK_COUNT + (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_state" : NULL, +#else + "port_state", +#endif + make_small(0)); #endif erts_port[i].tracer_proc = NIL; erts_port[i].trace_flags = 0; @@ -1380,6 +1397,27 @@ void init_io(void) erts_smp_mtx_unlock(&erts_driver_list_lock); } +#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP) +void erts_lcnt_enable_io_lock_count(int enable) { + int i; + + for (i = 0; i < erts_max_ports; i++) { + Port* p = &erts_port[i]; + if (enable) { + erts_lcnt_init_lock_x(&p->state_lck.lcnt, "port_state", ERTS_LCNT_LT_SPINLOCK, make_small(i)); + if (p->lock) { + erts_lcnt_init_lock_x(&p->lock->lcnt, "port_lock", ERTS_LCNT_LT_MUTEX, make_small(i)); + } + } else { + erts_lcnt_destroy_lock(&p->state_lck.lcnt); + if (p->lock) { + erts_lcnt_destroy_lock(&p->lock->lcnt); + } + } + } +} +#endif + /* * Buffering of data when using line oriented I/O on ports */ @@ -3222,6 +3260,8 @@ driver_deliver_term(ErlDrvPort port, Uint size = ptr[1]; Uint offset = ptr[2]; + erts_smp_atomic_add_nob(&erts_bytes_in, (erts_aint_t) size); + if (size <= ERL_ONHEAP_BIN_LIMIT) { ErlHeapBin* hbp = (ErlHeapBin *) hp; hp += heap_bin_size(size); @@ -3253,6 +3293,9 @@ driver_deliver_term(ErlDrvPort port, case ERL_DRV_BUF2BINARY: { /* char*, size */ byte *bufp = (byte *) ptr[0]; Uint size = (Uint) ptr[1]; + + erts_smp_atomic_add_nob(&erts_bytes_in, (erts_aint_t) size); + if (size <= ERL_ONHEAP_BIN_LIMIT) { ErlHeapBin* hbp = (ErlHeapBin *) hp; hp += heap_bin_size(size); @@ -3289,6 +3332,7 @@ driver_deliver_term(ErlDrvPort port, } case ERL_DRV_STRING: /* char*, length */ + erts_smp_atomic_add_nob(&erts_bytes_in, (erts_aint_t) ptr[1]); mess = buf_to_intlist(&hp, (char*)ptr[0], ptr[1], NIL); ptr += 2; break; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index bf376f0494..76a9b55179 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -3124,6 +3124,7 @@ static int tcp_message(inet_descriptor* desc, const char* buf, int len) int i = 0; DEBUGF(("tcp_message(%ld): len = %d\r\n", (long)desc->port, len)); + /* XXX fprintf(stderr,"tcp_message send.\r\n"); */ i = LOAD_ATOM(spec, i, am_tcp); i = LOAD_PORT(spec, i, desc->dport); @@ -5426,6 +5427,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) if (IS_SCTP(desc)) return sctp_set_opts(desc, ptr, len); #endif + /* XXX { int i; for(i=0;i<len;++i) fprintf(stderr,"0x%02X, ", (unsigned) ptr[i]); fprintf(stderr,"\r\n");} */ while(len >= 5) { opt = *ptr++; @@ -5755,10 +5757,16 @@ skip_os_setopt: if (desc->active != old_active) sock_select(desc, (FD_READ|FD_CLOSE), (desc->active>0)); + /* XXX: UDP sockets could also trigger immediate read here NIY */ if ((desc->stype==SOCK_STREAM) && desc->active) { if (!old_active || (desc->htype != old_htype)) { /* passive => active change OR header type change in active mode */ - return 1; + /* Return > 1 if only active changed to INET_ONCE -> direct read if + header type is unchanged. */ + /* XXX fprintf(stderr,"desc->htype == %d, old_htype == %d, + desc->active == %d, old_active == %d\r\n",(int)desc->htype, + (int) old_htype, (int) desc->active, (int) old_active );*/ + return 1+(desc->htype == old_htype && desc->active == INET_ONCE); } return 0; } @@ -7592,17 +7600,27 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, case INET_REQ_SETOPTS: { /* set options */ DEBUGF(("inet_ctl(%ld): SETOPTS\r\n", (long)desc->port)); + /* XXX fprintf(stderr,"inet_ctl(%ld): SETOPTS (len = %d)\r\n", (long)desc->port,(int) len); */ switch(inet_set_opts(desc, buf, len)) { case -1: return ctl_error(EINVAL, rbuf, rsize); case 0: return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); - default: /* active/passive change!! */ + case 1: /* * Let's hope that the descriptor really is a tcp_descriptor here. */ + /* fprintf(stderr,"Triggered tcp_deliver by setopt.\r\n"); */ tcp_deliver((tcp_descriptor *) desc, 0); return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); + default: + /* fprintf(stderr,"Triggered tcp_recv by setopt.\r\n"); */ + /* + * Same as above, but active changed to once w/o header type + * change, so try a read instead of just deliver. + */ + tcp_recv((tcp_descriptor *) desc, 0); + return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } } @@ -9196,6 +9214,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) #endif ASSERT(!INETP(desc)->is_ignored); DEBUGF(("tcp_inet_input(%ld) {s=%d\r\n", port, desc->inet.s)); + /* XXX fprintf(stderr,"tcp_inet_input(%ld) {s=%d}\r\n",(long) desc->inet.port, desc->inet.s); */ if (desc->inet.state == INET_STATE_ACCEPTING) { SOCKET s; unsigned int len; diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index f94e0f2296..bf69f3bf90 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -1163,6 +1163,8 @@ static int set_driver_data(int port_num, report_exit_list = report_exit; } + erts_port[port_num].os_pid = pid; + if (read_write & DO_READ) { driver_data[ifd].packet_bytes = packet_bytes; driver_data[ifd].port_num = port_num; diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index b106f0932d..acbbfc2ce9 100755 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -68,9 +68,9 @@ static int async_write_file(struct async_io* aio, LPVOID buf, DWORD numToWrite); static int get_overlapped_result(struct async_io* aio, LPDWORD pBytesRead, BOOL wait); static BOOL create_child_process(char *, HANDLE, HANDLE, - HANDLE, LPHANDLE, BOOL, - LPVOID, LPTSTR, unsigned, - char **, int *); + HANDLE, LPHANDLE, LPDWORD, BOOL, + LPVOID, LPTSTR, unsigned, + char **, int *); static int create_pipe(LPHANDLE, LPHANDLE, BOOL, BOOL); static int application_type(const char* originalName, char fullPath[MAX_PATH], BOOL search_in_path, BOOL handle_quotes, @@ -1136,6 +1136,7 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) HANDLE hChildStdin = INVALID_HANDLE_VALUE; /* Child's stdin. */ HANDLE hChildStdout = INVALID_HANDLE_VALUE; /* Child's stout. */ HANDLE hChildStderr = INVALID_HANDLE_VALUE; /* Child's sterr. */ + DWORD pid; int close_child_stderr = 0; DriverData* dp; /* Pointer to driver data. */ ErlDrvData retval = ERL_DRV_ERROR_GENERAL; /* Return value. */ @@ -1211,6 +1212,7 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) hChildStdout, hChildStderr, &dp->port_pid, + &pid, opts->hide_window, (LPVOID) envir, (LPTSTR) opts->wd, @@ -1254,6 +1256,9 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) #endif retval = set_driver_data(dp, hFromChild, hToChild, opts->read_write, opts->exit_status); + if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO) + /* We assume that this cannot generate a negative number */ + erts_port[port_num].os_pid = (SWord) pid; } if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO) @@ -1397,7 +1402,8 @@ create_child_process HANDLE hStdin, /* The standard input handle for child. */ HANDLE hStdout, /* The standard output handle for child. */ HANDLE hStderr, /* The standard error handle for child. */ - LPHANDLE phPid, /* Pointer to variable to received PID. */ + LPHANDLE phPid, /* Pointer to variable to received Process handle. */ + LPDWORD pdwID, /* Pointer to variable to received Process ID */ BOOL hide, /* Hide the window unconditionally. */ LPVOID env, /* Environment for the child */ LPTSTR wd, /* Working dir for the child */ @@ -1629,7 +1635,8 @@ create_child_process } CloseHandle(piProcInfo.hThread); /* Necessary to avoid resource leak. */ *phPid = piProcInfo.hProcess; - + *pdwID = piProcInfo.dwProcessId; + if (applType == APPL_DOS) { WaitForSingleObject(hProcess, 50); } diff --git a/erts/emulator/test/port_bif_SUITE.erl b/erts/emulator/test/port_bif_SUITE.erl index d9c82aba0e..8feea87d7e 100644 --- a/erts/emulator/test/port_bif_SUITE.erl +++ b/erts/emulator/test/port_bif_SUITE.erl @@ -24,6 +24,7 @@ init_per_group/2,end_per_group/2, command/1, command_e_1/1, command_e_2/1, command_e_3/1, command_e_4/1, port_info1/1, port_info2/1, + port_info_os_pid/1, connect/1, control/1, echo_to_busy/1]). -export([do_command_e_1/1, do_command_e_2/1, do_command_e_4/1]). @@ -41,7 +42,7 @@ all() -> groups() -> [{command_e, [], [command_e_1, command_e_2, command_e_3, command_e_4]}, - {port_info, [], [port_info1, port_info2]}]. + {port_info, [], [port_info1, port_info2, port_info_os_pid]}]. init_per_suite(Config) -> Config. @@ -65,15 +66,15 @@ end_per_testcase(_Func, Config) when is_list(Config) -> test_server:timetrap_cancel(Dog). command(Config) when is_list(Config) -> - ?line load_control_drv(Config), - - ?line P = open_port({spawn, control_drv}, []), - ?line do_command(P, "hello"), - ?line do_command(P, <<"hello">>), - ?line do_command(P, sub_bin(<<"1234kalle">>)), - ?line do_command(P, unaligned_sub_bin(<<"blurf">>)), - ?line do_command(P, ["bl"|unaligned_sub_bin(<<"urf">>)]), - ?line true = erlang:port_close(P), + load_control_drv(Config), + + P = open_port({spawn, control_drv}, []), + do_command(P, "hello"), + do_command(P, <<"hello">>), + do_command(P, sub_bin(<<"1234kalle">>)), + do_command(P, unaligned_sub_bin(<<"blurf">>)), + do_command(P, ["bl"|unaligned_sub_bin(<<"urf">>)]), + true = erlang:port_close(P), ok. do_command(P, Data) -> @@ -94,139 +95,163 @@ do_command(P, Data) -> %% port_command/2: badarg 1st arg command_e_1(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line Program = filename:join(DataDir, "port_test"), + DataDir = ?config(data_dir, Config), + Program = filename:join(DataDir, "port_test"), process_flag(trap_exit, true), - ?line _ = spawn_link(?MODULE, do_command_e_1, [Program]), - ?line receive - {'EXIT', Pid, {badarg, _}} when is_pid(Pid) -> - ok; - Other -> - ?line test_server:fail(Other) - after 10000 -> - ?line test_server:fail(timeout) - end, + _ = spawn_link(?MODULE, do_command_e_1, [Program]), + receive + {'EXIT', Pid, {badarg, _}} when is_pid(Pid) -> + ok; + Other -> + test_server:fail(Other) + after 10000 -> + test_server:fail(timeout) + end, ok. do_command_e_1(Program) -> - ?line _ = open_port({spawn, Program}, []), - ?line erlang:port_command(apple, "plock"), + _ = open_port({spawn, Program}, []), + erlang:port_command(apple, "plock"), exit(survived). %% port_command/2: badarg 2nd arg command_e_2(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line Program = filename:join(DataDir, "port_test"), + DataDir = ?config(data_dir, Config), + Program = filename:join(DataDir, "port_test"), process_flag(trap_exit, true), - ?line _ = spawn_link(?MODULE, do_command_e_2, [Program]), - ?line receive - {'EXIT', Pid, {badarg, _}} when is_pid(Pid) -> - ok; - Other -> - ?line test_server:fail(Other) - after 10000 -> - ?line test_server:fail(timeout) - end, + _ = spawn_link(?MODULE, do_command_e_2, [Program]), + receive + {'EXIT', Pid, {badarg, _}} when is_pid(Pid) -> + ok; + Other -> + test_server:fail(Other) + after 10000 -> + test_server:fail(timeout) + end, ok. do_command_e_2(Program) -> - ?line P = open_port({spawn, Program}, []), - ?line erlang:port_command(P, 1), + P = open_port({spawn, Program}, []), + erlang:port_command(P, 1), exit(survived). %% port_command/2: Posix signals trapped command_e_3(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line Program = filename:join(DataDir, "port_test"), + DataDir = ?config(data_dir, Config), + Program = filename:join(DataDir, "port_test"), process_flag(trap_exit, true), - ?line P = open_port({spawn, Program}, [{packet, 1}]), - ?line Data = lists:duplicate(257, $a), - ?line erlang:port_command(P, Data), - ?line receive - {'EXIT', Port, einval} when is_port(Port) -> - ok; - Other -> - test_server:fail(Other) - after 10000 -> - test_server:fail(timeout) - end, + P = open_port({spawn, Program}, [{packet, 1}]), + Data = lists:duplicate(257, $a), + erlang:port_command(P, Data), + receive + {'EXIT', Port, einval} when is_port(Port) -> + ok; + Other -> + test_server:fail(Other) + after 10000 -> + test_server:fail(timeout) + end, ok. %% port_command/2: Posix exit signals not trapped command_e_4(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line Program = filename:join(DataDir, "port_test"), + DataDir = ?config(data_dir, Config), + Program = filename:join(DataDir, "port_test"), process_flag(trap_exit, true), - ?line _ = spawn_link(?MODULE, do_command_e_4, [Program]), - ?line receive - {'EXIT', Pid, {einval, _}} when is_pid(Pid) -> - ok; - Other -> - ?line test_server:fail(Other) - after 10000 -> - ?line test_server:fail(timeout) - end, + _ = spawn_link(?MODULE, do_command_e_4, [Program]), + receive + {'EXIT', Pid, {einval, _}} when is_pid(Pid) -> + ok; + Other -> + test_server:fail(Other) + after 10000 -> + test_server:fail(timeout) + end, ok. do_command_e_4(Program) -> - ?line P = open_port({spawn, Program}, [{packet, 1}]), - ?line Data = lists:duplicate(257, $a), - ?line erlang:port_command(P, Data), + P = open_port({spawn, Program}, [{packet, 1}]), + Data = lists:duplicate(257, $a), + erlang:port_command(P, Data), exit(survived). %% Tests the port_info/1 BIF port_info1(Config) when is_list(Config) -> - ?line load_control_drv(Config), + load_control_drv(Config), Me=self(), - ?line P = open_port({spawn, control_drv}, []), - ?line A1 = erlang:port_info(P), - ?line false = lists:keysearch(registered_name, 1, A1), - ?line register(myport, P), - ?line A = erlang:port_info(P), - ?line {value,{registered_name,myport}}= - lists:keysearch(registered_name, 1, A), - ?line {value,{name,"control_drv"}}=lists:keysearch(name, 1, A), - ?line {value,{links,[Me]}}=lists:keysearch(links, 1, A), - ?line {value,{id,_IdNum}}=lists:keysearch(id, 1, A), - ?line {value,{connected,_}}=lists:keysearch(connected, 1, A), - ?line {value,{input,0}}=lists:keysearch(input, 1, A), - ?line {value,{output,0}}=lists:keysearch(output, 1, A), - ?line true=erlang:port_close(P), + P = open_port({spawn, control_drv}, []), + A1 = erlang:port_info(P), + false = lists:keysearch(registered_name, 1, A1), + register(myport, P), + A = erlang:port_info(P), + {value,{registered_name,myport}}= lists:keysearch(registered_name, 1, A), + {value,{name,"control_drv"}}=lists:keysearch(name, 1, A), + {value,{links,[Me]}}=lists:keysearch(links, 1, A), + {value,{id,_IdNum}}=lists:keysearch(id, 1, A), + {value,{connected,_}}=lists:keysearch(connected, 1, A), + {value,{input,0}}=lists:keysearch(input, 1, A), + {value,{output,0}}=lists:keysearch(output, 1, A), + {value,{os_pid,undefined}}=lists:keysearch(os_pid, 1, A), % linked-in driver doesn't have a OS pid + true=erlang:port_close(P), ok. %% Tests erlang:port_info/2" port_info2(Config) when is_list(Config) -> - ?line load_control_drv(Config), + load_control_drv(Config), - ?line P = open_port({spawn,control_drv}, [binary]), - ?line [] = erlang:port_info(P, registered_name), - ?line register(myport, P), - ?line {registered_name, myport} = erlang:port_info(P, registered_name), + P = open_port({spawn,control_drv}, [binary]), + [] = erlang:port_info(P, registered_name), + register(myport, P), + {registered_name, myport} = erlang:port_info(P, registered_name), - ?line {name, "control_drv"}=erlang:port_info(P, name), - ?line {id, _IdNum} = erlang:port_info(P, id), + {name, "control_drv"}=erlang:port_info(P, name), + {id, _IdNum} = erlang:port_info(P, id), Me=self(), - ?line {links, [Me]} = erlang:port_info(P, links), - ?line {connected, Me} = erlang:port_info(P, connected), - ?line {input, 0}=erlang:port_info(P, input), - ?line {output,0}=erlang:port_info(P, output), - - ?line erlang:port_control(P, $i, "abc"), - ?line receive - {P,{data,<<"abc">>}} -> ok - end, - ?line {input,3} = erlang:port_info(P, input), - ?line {output,0} = erlang:port_info(P, output), - - ?line Bin = list_to_binary(lists:duplicate(2047, 42)), - ?line output_test(P, Bin, 3, 0), + {links, [Me]} = erlang:port_info(P, links), + {connected, Me} = erlang:port_info(P, connected), + {input, 0}=erlang:port_info(P, input), + {output,0}=erlang:port_info(P, output), + {os_pid, undefined}=erlang:port_info(P, os_pid), % linked-in driver doesn't have a OS pid + + erlang:port_control(P, $i, "abc"), + receive + {P,{data,<<"abc">>}} -> ok + end, + {input,3} = erlang:port_info(P, input), + {output,0} = erlang:port_info(P, output), + + Bin = list_to_binary(lists:duplicate(2047, 42)), + output_test(P, Bin, 3, 0), - ?line true = erlang:port_close(P), + true = erlang:port_close(P), + ok. + +%% Tests the port_info/1,2 os_pid option BIF +port_info_os_pid(Config) when is_list(Config) -> + case os:type() of + {unix,_} -> + do_port_info_os_pid(); + _ -> + {skip,"Only on Unix."} + end. + +do_port_info_os_pid() -> + P = open_port({spawn, "echo $$"}, [eof]), + A = erlang:port_info(P), + {os_pid, InfoOSPid} = erlang:port_info(P, os_pid), + EchoPidStr = receive + {P, {data, EchoPidStr0}} -> EchoPidStr0 + after 10000 -> test_server:fail(timeout) + end, + {ok, [EchoPid], []} = io_lib:fread("~u\n", EchoPidStr), + {value,{os_pid, InfoOSPid}}=lists:keysearch(os_pid, 1, A), + EchoPid = InfoOSPid, + true = erlang:port_close(P), ok. output_test(_, _, Input, Output) when Output > 16#1fffffff -> @@ -237,7 +262,7 @@ output_test(P, Bin, Input0, Output0) -> {P,{data,Bin}} -> ok; Other -> io:format("~p", [Other]), - ?line ?t:fail() + ?t:fail() end, Input = Input0 + size(Bin), Output = Output0 + size(Bin), @@ -254,109 +279,106 @@ output_test(P, Bin, Input0, Output0) -> %% Tests the port_connect/2 BIF. connect(Config) when is_list(Config) -> - ?line load_control_drv(Config), + load_control_drv(Config), - ?line P = open_port({spawn, control_drv}, []), + P = open_port({spawn, control_drv}, []), register(myport, P), - ?line true = erlang:port_connect(myport, self()), + true = erlang:port_connect(myport, self()), %% Connect the port to another process. Data = "hello, world", Parent = self(), - ?line Rec = - fun(Me) -> receive - {P,{data,Data}} -> - Parent ! connect_ok, - Me(Me) - end - end, - ?line RecPid = spawn_link(fun() -> Rec(Rec) end), - ?line true = erlang:port_connect(P, RecPid), - ?line unlink(P), + Rec = fun(Me) -> + receive + {P,{data,Data}} -> + Parent ! connect_ok, + Me(Me) + end + end, + RecPid = spawn_link(fun() -> Rec(Rec) end), + true = erlang:port_connect(P, RecPid), + unlink(P), %% Send a command to the port and make sure that the %% other process receives the echo. - ?line erlang:port_command(P, Data), - ?line receive - connect_ok -> ok - end, + erlang:port_command(P, Data), + receive + connect_ok -> ok + end, %% Tests some errors. - ?line {'EXIT',{badarg, _}}=(catch erlang:port_connect(self(), self())), - ?line {'EXIT',{badarg, _}}=(catch erlang:port_connect(self(), P)), - ?line {'EXIT',{badarg, _}}=(catch erlang:port_connect(P, P)), - ?line {'EXIT',{badarg, _}}=(catch erlang:port_connect(P, xxxx)), - ?line {'EXIT',{badarg, _}}=(catch erlang:port_connect(P, [])), + {'EXIT',{badarg, _}}=(catch erlang:port_connect(self(), self())), + {'EXIT',{badarg, _}}=(catch erlang:port_connect(self(), P)), + {'EXIT',{badarg, _}}=(catch erlang:port_connect(P, P)), + {'EXIT',{badarg, _}}=(catch erlang:port_connect(P, xxxx)), + {'EXIT',{badarg, _}}=(catch erlang:port_connect(P, [])), - ?line process_flag(trap_exit, true), - ?line exit(P, you_should_die), - ?line receive - {'EXIT',RecPid,you_should_die} -> ok; - Other -> ?line ?t:fail({bad_message,Other}) - end, + process_flag(trap_exit, true), + exit(P, you_should_die), + receive + {'EXIT',RecPid,you_should_die} -> ok; + Other -> ?line ?t:fail({bad_message,Other}) + end, %% Done. ok. %% Tests port_control/3 control(Config) when is_list(Config) -> - ?line load_control_drv(Config), - ?line P = open_port({spawn, control_drv}, []), + load_control_drv(Config), + P = open_port({spawn, control_drv}, []), %% Test invalid (out-of-range) arguments. - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(self(), 1, [])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(self(), 1, [])), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, -1, [])), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, -34887348739733833, [])), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 16#100000000, [])), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, a, [])), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 'e', dum)), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, dum)), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, fun(X) -> X end)), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, - [fun(X) -> X end])), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, - [1|fun(X) -> X end])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, -1, [])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, -34887348739733833, [])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 16#100000000, [])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, a, [])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 'e', dum)), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, dum)), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, fun(X) -> X end)), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, [fun(X) -> X end])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, $e, [1|fun(X) -> X end])), %% Test errors detected by the driver. - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 177, [])), - ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 155, - random_packet(1024))), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 177, [])), + {'EXIT', {badarg, _}} = (catch erlang:port_control(P, 155, random_packet(1024))), %% Test big op codes. register(myport, P), - ?line test_op(myport, 256), - ?line test_op(P, 256), - ?line test_op(P, 16#0033A837), - ?line test_op(P, 16#0ab37938), - ?line test_op(P, 16#eab37938), - ?line test_op(P, 16#ffffFFFF), + test_op(myport, 256), + test_op(P, 256), + test_op(P, 16#0033A837), + test_op(P, 16#0ab37938), + test_op(P, 16#eab37938), + test_op(P, 16#ffffFFFF), %% Test the echo function of the driver. - ?line echo(P, 0), - ?line echo(P, 1), - ?line echo(P, 10), - ?line echo(P, 13), - ?line echo(P, 63), - ?line echo(P, 64), - ?line echo(P, 65), - ?line echo(P, 127), - ?line echo(P, 1023), - ?line echo(P, 1024), - ?line echo(P, 11243), - ?line echo(P, 70000), + echo(P, 0), + echo(P, 1), + echo(P, 10), + echo(P, 13), + echo(P, 63), + echo(P, 64), + echo(P, 65), + echo(P, 127), + echo(P, 1023), + echo(P, 1024), + echo(P, 11243), + echo(P, 70000), %% Done. - ?line true=erlang:port_close(myport), + true = erlang:port_close(myport), ok. test_op(P, Op) -> @@ -364,23 +386,23 @@ test_op(P, Op) -> <<Op:32>> = list_to_binary(R). echo_to_busy(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line load_control_drv(Config), - ?line P = open_port({spawn, control_drv}, []), - ?line erlang:port_control(P, $b, [1]), % Set to busy. + Dog = test_server:timetrap(test_server:seconds(10)), + load_control_drv(Config), + P = open_port({spawn, control_drv}, []), + erlang:port_control(P, $b, [1]), % Set to busy. Self = self(), - ?line Echoer = spawn(fun() -> echoer(P, Self) end), - ?line receive after 500 -> ok end, - ?line erlang:port_control(P, $b, [0]), % Set to not busy. - ?line receive - {Echoer, done} -> - ok; - {Echoer, Other} -> - test_server:fail(Other); - Other -> - test_server:fail({unexpected_message, Other}) - end, - ?line test_server:timetrap_cancel(Dog), + Echoer = spawn(fun() -> echoer(P, Self) end), + receive after 500 -> ok end, + erlang:port_control(P, $b, [0]), % Set to not busy. + receive + {Echoer, done} -> + ok; + {Echoer, Other} -> + test_server:fail(Other); + Other -> + test_server:fail({unexpected_message, Other}) + end, + test_server:timetrap_cancel(Dog), ok. echoer(P, ReplyTo) -> @@ -405,9 +427,9 @@ echo(P, Size) -> Packet = erlang:port_control(P, $e, [unaligned_sub_bin(Bin)]). load_control_drv(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line erl_ddll:start(), - ?line ok = load_driver(DataDir, "control_drv"). + DataDir = ?config(data_dir, Config), + erl_ddll:start(), + ok = load_driver(DataDir, "control_drv"). load_driver(Dir, Driver) -> case erl_ddll:load_driver(Dir, Driver) of @@ -459,4 +481,3 @@ sub_bin(Bin) when is_binary(Bin) -> B. id(I) -> I. - diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index 19b3bb82ef..c9aee16def 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -121,9 +121,11 @@ static char *plusM_other_switches[] = { /* +s arguments with values */ static char *pluss_val_switches[] = { "bt", + "bwt", "cl", "ct", "wt", + "ws", "ss", NULL }; diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c index 8db8e09bee..6b350e8bd5 100644 --- a/erts/etc/unix/run_erl.c +++ b/erts/etc/unix/run_erl.c @@ -126,7 +126,7 @@ /* prototypes */ static void usage(char *); static int create_fifo(char *name, int perm); -static int open_pty_master(char **name); +static int open_pty_master(char **name, int *sfd); static int open_pty_slave(char *name); static void pass_on(pid_t); static void exec_shell(char **); @@ -150,6 +150,10 @@ static int write_all(int fd, const char* buf, int len); static int extract_ctrl_seq(char* buf, int len); static void set_window_size(unsigned col, unsigned row); +static ssize_t sf_write(int fd, const void *buffer, size_t len); +static ssize_t sf_read(int fd, void *buffer, size_t len); +static int sf_open(const char *path, int flags, mode_t mode); +static int sf_close(int fd); #ifdef DEBUG static void show_terminal_settings(struct termios *t); @@ -216,7 +220,7 @@ static char* outbuf_in; int main(int argc, char **argv) { int childpid; - int sfd; + int sfd = -1; int fd; char *p, *ptyslave=NULL; int i = 1; @@ -338,9 +342,9 @@ int main(int argc, char **argv) strn_cat(fifo2, sizeof(fifo2), ".w"); /* Check that nobody is running run_erl already */ - if ((fd = open (fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { + if ((fd = sf_open(fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { /* Open as client succeeded -- run_erl is already running! */ - close(fd); + sf_close(fd); if (calculated_pipename) { ++highest_pipe_num; strn_catf(pipename, sizeof(pipename), "%s.%d", @@ -361,7 +365,7 @@ int main(int argc, char **argv) * Open master pseudo-terminal */ - if ((mfd = open_pty_master(&ptyslave)) < 0) { + if ((mfd = open_pty_master(&ptyslave, &sfd)) < 0) { ERRNO_ERR0(LOG_ERR,"Could not open pty master"); exit(1); } @@ -376,7 +380,7 @@ int main(int argc, char **argv) } if (childpid == 0) { /* Child */ - close(mfd); + sf_close(mfd); /* disassociate from control terminal */ #ifdef USE_SETPGRP_NOARGS /* SysV */ setpgrp(); @@ -386,15 +390,30 @@ int main(int argc, char **argv) setsid(); #endif /* Open the slave pty */ - if ((sfd = open_pty_slave(ptyslave)) < 0) { - ERRNO_ERR1(LOG_ERR,"Could not open pty slave '%s'", ptyslave); - exit(1); + if (sfd < 0) { + /* not allocated by open_pty_master */ + if ((sfd = open_pty_slave(ptyslave)) < 0) { + ERRNO_ERR1(LOG_ERR,"Could not open pty slave '%s'", ptyslave); + exit(1); + } + /* But sfd may be one of the stdio fd's now, and we should be unmodern and not use dup2... */ + /* easiest to dup it up... */ + while (sfd < 3) { + sfd = dup(sfd); + } } - /* But sfd may be one of the stdio fd's now, and we should be unmodern and not use dup2... */ - /* easiest to dup it up... */ - while (sfd < 3) { - sfd = dup(sfd); +#if defined(HAVE_OPENPTY) && defined(TIOCSCTTY) + else { + /* sfd is from open_pty_master + * openpty -> fork -> login_tty (forkpty) + * + * It would be preferable to implement a portable + * forkpty instead of open_pty_master / open_pty_slave + */ + /* login_tty(sfd); <- FAIL */ + ioctl(sfd, TIOCSCTTY, (char *)NULL); } +#endif #ifndef NO_SYSLOG /* Before fiddling with file descriptors we make sure syslog is turned off @@ -407,14 +426,14 @@ int main(int argc, char **argv) #endif /* Close stdio */ - close(0); - close(1); - close(2); + sf_close(0); + sf_close(1); + sf_close(2); if (dup(sfd) != 0 || dup(sfd) != 1 || dup(sfd) != 2) { status("Cannot dup\n"); } - close(sfd); + sf_close(sfd); exec_shell(argv+off_argv); /* exec_shell expects argv[2] to be */ /* the command name, so we have to */ /* adjust. */ @@ -466,7 +485,7 @@ static void pass_on(pid_t childpid) * We can't open the writing side because nobody is reading and * we'd either hang or get an error. */ - if ((rfd = open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { + if ((rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2); exit(1); } @@ -559,7 +578,7 @@ static void pass_on(pid_t childpid) char* buf = outbuf_first(); len = outbuf_size(); - written = write(wfd, buf, len); + written = sf_write(wfd, buf, len); if (written < 0 && errno == EAGAIN) { /* * Nothing was written - this is really strange because @@ -570,7 +589,7 @@ static void pass_on(pid_t childpid) * A write error. Assume that to_erl has terminated. */ clear_outbuf(); - close(wfd); + sf_close(wfd); wfd = 0; } else { /* Delete the written part (or all) from the buffer. */ @@ -585,10 +604,10 @@ static void pass_on(pid_t childpid) #ifdef DEBUG status("Pty master read; "); #endif - if ((len = read(mfd, buf, BUFSIZ)) <= 0) { - close(rfd); - if(wfd) close(wfd); - close(mfd); + if ((len = sf_read(mfd, buf, BUFSIZ)) <= 0) { + sf_close(rfd); + if(wfd) sf_close(wfd); + sf_close(mfd); unlink(fifo1); unlink(fifo2); if (len < 0) { @@ -619,10 +638,10 @@ static void pass_on(pid_t childpid) #ifdef DEBUG status("FIFO read; "); #endif - if ((len = read(rfd, buf, BUFSIZ)) < 0) { - close(rfd); - if(wfd) close(wfd); - close(mfd); + if ((len = sf_read(rfd, buf, BUFSIZ)) < 0) { + sf_close(rfd); + if(wfd) sf_close(wfd); + sf_close(mfd); unlink(fifo1); unlink(fifo2); ERRNO_ERR0(LOG_ERR,"Error in reading from FIFO."); @@ -631,8 +650,8 @@ static void pass_on(pid_t childpid) if(!len) { /* to_erl closed its end of the pipe */ - close(rfd); - rfd = open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0); + sf_close(rfd); + rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0); if (rfd < 0) { ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2); exit(1); @@ -645,11 +664,11 @@ static void pass_on(pid_t childpid) * from to_erl, to_erl should already be reading this pipe - open * should succeed. But in case of error, we just ignore it. */ - if ((wfd = open(fifo1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { + if ((wfd = sf_open(fifo1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { status("Client expected on FIFO %s, but can't open (len=%d)\n", fifo1, len); - close(rfd); - rfd = open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0); + sf_close(rfd); + rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0); if (rfd < 0) { ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2); exit(1); @@ -683,9 +702,9 @@ static void pass_on(pid_t childpid) } else if (len>0 && write_all(mfd, buf, len) != len) { ERRNO_ERR0(LOG_ERR,"Error in writing to terminal."); - close(rfd); - if(wfd) close(wfd); - close(mfd); + sf_close(rfd); + if(wfd) sf_close(wfd); + sf_close(mfd); exit(1); } } @@ -797,7 +816,7 @@ static int open_log(int log_num, int flags) /* Create or continue on the current log file */ sn_printf(buf, sizeof(buf), "%s/%s%d", log_dir, LOG_STUBNAME, log_num); - if((lfd = open(buf, flags, LOG_PERM))<0){ + if((lfd = sf_open(buf, flags, LOG_PERM))<0){ ERRNO_ERR1(LOG_ERR,"Can't open log file '%s'.", buf); exit(1); } @@ -841,7 +860,7 @@ static void write_to_log(int* lfd, int* log_num, char* buf, int len) size = lseek(*lfd,0,SEEK_END); if(size+len > log_maxsize) { - close(*lfd); + sf_close(*lfd); *log_num = next_log(*log_num); *lfd = open_log(*log_num, O_RDWR|O_CREAT|O_TRUNC|O_SYNC); } @@ -872,7 +891,7 @@ static int create_fifo(char *name, int perm) * Find a master device, open and return fd and slave device name. */ -static int open_pty_master(char **ptyslave) +static int open_pty_master(char **ptyslave, int *sfdp) { int mfd; @@ -882,7 +901,9 @@ static int open_pty_master(char **ptyslave) # ifdef HAVE_WORKING_POSIX_OPENPT if ((mfd = posix_openpt(O_RDWR)) >= 0) { # elif defined(__sun) && defined(__SVR4) - if ((mfd = open("/dev/ptmx", O_RDWR)) >= 0) { + mfd = sf_open("/dev/ptmx", O_RDWR, 0); + + if (mfd >= 0) { # endif if ((*ptyslave = ptsname(mfd)) != NULL && grantpt(mfd) == 0 && @@ -890,12 +911,12 @@ static int open_pty_master(char **ptyslave) return mfd; } - close(mfd); + sf_close(mfd); } /* fallback to openpty if it exist */ #endif -#ifdef HAVE_OPENPTY +#if defined(HAVE_OPENPTY) # ifdef PATH_MAX # define SLAVE_SIZE PATH_MAX # else @@ -903,11 +924,8 @@ static int open_pty_master(char **ptyslave) # endif { static char slave[SLAVE_SIZE]; - int sfd; # undef SLAVE_SIZE - - if (openpty(&mfd, &sfd, slave, NULL, NULL) == 0) { - close(sfd); + if (openpty(&mfd, sfdp, slave, NULL, NULL) == 0) { *ptyslave = slave; return mfd; } @@ -939,7 +957,8 @@ static int open_pty_master(char **ptyslave) for (minor = minorchars; *minor; minor++) { ptyname[10] = *minor; - if ((mfd = open(ptyname, O_RDWR, 0)) >= 0) { + + if ((mfd = sf_open(ptyname, O_RDWR, 0)) >= 0) { ptyname[9] = 's'; *ptyslave = ptyname; return mfd; @@ -957,7 +976,7 @@ static int open_pty_master(char **ptyslave) ptyname[13] = *major; for (minor = minorchars; *minor; minor++) { ptyname[14] = *minor; - if ((mfd = open(ptyname, O_RDWR, 0)) >= 0) { + if ((mfd = sf_open(ptyname, O_RDWR, 0)) >= 0) { ttyname[12] = *major; ttyname[13] = *minor; *ptyslave = ttyname; @@ -976,7 +995,7 @@ static int open_pty_master(char **ptyslave) ptyname[8] = *major; for (minor = minorchars; *minor; minor++) { ptyname[9] = *minor; - if ((mfd = open(ptyname, O_RDWR, 0)) >= 0) { + if ((mfd = sf_open(ptyname, O_RDWR, 0)) >= 0) { ptyname[5] = 't'; *ptyslave = ptyname; return mfd; @@ -993,7 +1012,7 @@ static int open_pty_slave(char *name) int sfd; struct termios tty_rmode; - if ((sfd = open(name, O_RDWR, 0)) < 0) { + if ((sfd = sf_open(name, O_RDWR, 0)) < 0) { return -1; } @@ -1120,7 +1139,7 @@ static void daemon_init(void) would be backward incompatible */ for (i = 0; i < maxfd; ++i ) { - close(i); + sf_close(i); } OPEN_SYSLOG(); @@ -1246,7 +1265,7 @@ static int write_all(int fd, const char* buf, int len) int left = len; int written; for (;;) { - written = write(fd,buf,left); + written = sf_write(fd,buf,left); if (written == left) { return len; } @@ -1258,6 +1277,36 @@ static int write_all(int fd, const char* buf, int len) } } +static ssize_t sf_read(int fd, void *buffer, size_t len) { + ssize_t n = 0; + + do { n = read(fd, buffer, len); } while (n < 0 && errno == EINTR); + + return n; +} + +static ssize_t sf_write(int fd, const void *buffer, size_t len) { + ssize_t n = 0; + + do { n = write(fd, buffer, len); } while (n < 0 && errno == EINTR); + + return n; +} + +static int sf_open(const char *path, int type, mode_t mode) { + int fd = 0; + + do { fd = open(path, type, mode); } while(fd < 0 && errno == EINTR); + + return fd; +} +static int sf_close(int fd) { + int res = 0; + + do { res = close(fd); } while(fd < 0 && errno == EINTR); + + return res; +} /* Extract any control sequences that are ment only for run_erl * and should not be forwarded to the pty. */ diff --git a/erts/lib_src/common/ethr_aux.c b/erts/lib_src/common/ethr_aux.c index 521640317e..89149b716b 100644 --- a/erts/lib_src/common/ethr_aux.c +++ b/erts/lib_src/common/ethr_aux.c @@ -40,7 +40,7 @@ #include <unistd.h> #endif -#define ERTS_TS_EV_ALLOC_DEFAULT_POOL_SIZE 100 +#define ERTS_TS_EV_ALLOC_DEFAULT_POOL_SIZE 4000 #define ERTS_TS_EV_ALLOC_POOL_SIZE 25 erts_cpu_info_t *ethr_cpu_info__; diff --git a/erts/test/erl_print_SUITE_data/Makefile.src b/erts/test/erl_print_SUITE_data/Makefile.src index dec5650416..ebcbb10c15 100644 --- a/erts/test/erl_print_SUITE_data/Makefile.src +++ b/erts/test/erl_print_SUITE_data/Makefile.src @@ -22,6 +22,8 @@ include @erts_lib_include_internal_generated@@[email protected] CC = @CC@ CFLAGS = @ERTS_CFLAGS@ LIBS = @ERTS_LIBS@ +CP=cp +CHMOD=chmod EPTF_CFLAGS = -Wall $(CFLAGS) @DEFS@ -I@erts_lib_include_internal@ -I@erts_lib_include_internal_generated@ EPTF_LIBS = $(LIBS) -L@erts_lib_internal_path@ -lerts_internal@type_marker@ @@ -31,12 +33,18 @@ EPTT_LIBS = -L@erts_lib_internal_path@ -lerts_internal_r@type_marker@ $(ETHR_LIB GCC = .@DS@gccifier -CC"$(CC)" -PROGS = erl_print_tests.@emu_threads@@exe@ +PROGS = erl_print_tests.true@exe@ erl_print_tests.false@exe@ all: $(PROGS) +@IFEQ@ (@cross@, yes) +gccifier@exe@: + $(CP) ..@DS@utils@[email protected] gccifier@exe@ + $(CHMOD) a+x gccifier@exe@ +@ELSE@ gccifier@exe@: ..@DS@utils@[email protected] $(CC) $(CFLAGS) -o gccifier@exe@ ..@DS@utils@[email protected] $(LIBS) +@ENDIF@ erl_print_tests.false@exe@: gccifier@exe@ erl_print_tests.c $(GCC) $(EPTF_CFLAGS) -o erl_print_tests.false@exe@ erl_print_tests.c $(EPTF_LIBS) diff --git a/erts/test/erlexec_SUITE_data/Makefile.src b/erts/test/erlexec_SUITE_data/Makefile.src index b751547b8f..970a905c32 100644 --- a/erts/test/erlexec_SUITE_data/Makefile.src +++ b/erts/test/erlexec_SUITE_data/Makefile.src @@ -20,6 +20,8 @@ CC = @CC@ CFLAGS = @ERTS_CFLAGS@ LIBS = @ERTS_LIBS@ +CP=cp +CHMOD=chmod ERLX_T_CFLAGS = -Wall $(ERLX_DEFS) $(CFLAGS) @DEFS@ @@ -29,8 +31,14 @@ PROGS = erlexec_tests@exe@ all: $(PROGS) +@IFEQ@ (@cross@, yes) +gccifier@exe@: + $(CP) ..@DS@utils@[email protected] gccifier@exe@ + $(CHMOD) a+x gccifier@exe@ +@ELSE@ gccifier@exe@: ..@DS@utils@[email protected] $(CC) $(CFLAGS) -o gccifier@exe@ ..@DS@utils@[email protected] $(LIBS) +@ENDIF@ erlexec_tests@exe@: gccifier@exe@ erlexec_tests.c $(GCC) $(ERLX_T_CFLAGS) -o erlexec_tests@exe@ erlexec_tests.c diff --git a/erts/test/ethread_SUITE_data/Makefile.src b/erts/test/ethread_SUITE_data/Makefile.src index 132b23344c..f93a31178b 100644 --- a/erts/test/ethread_SUITE_data/Makefile.src +++ b/erts/test/ethread_SUITE_data/Makefile.src @@ -23,6 +23,8 @@ include @erts_lib_include_internal_generated@@DS@erts_internal.mk CC = @CC@ CFLAGS = @ERTS_CFLAGS@ LIBS = @ERTS_LIBS@ +CP=cp +CHMOD=chmod ETHR_T_CFLAGS = -Wall $(ETHR_DEFS) $(CFLAGS) @DEFS@ -I@erts_lib_include_internal@ -I@erts_lib_include_internal_generated@ ETHR_T_LIBS = $(LIBS) -L@erts_lib_internal_path@ $(ETHR_LIBS) $(ERTS_INTERNAL_X_LIBS) @@ -33,8 +35,14 @@ PROGS = ethread_tests@exe@ all: $(PROGS) +@IFEQ@ (@cross@, yes) +gccifier@exe@: + $(CP) ..@DS@utils@[email protected] gccifier@exe@ + $(CHMOD) a+x gccifier@exe@ +@ELSE@ gccifier@exe@: ..@DS@utils@[email protected] $(CC) $(CFLAGS) -o gccifier@exe@ ..@DS@utils@[email protected] $(LIBS) +@ENDIF@ ethread_tests@exe@: gccifier@exe@ ethread_tests.c $(GCC) $(ETHR_T_CFLAGS) -o ethread_tests@exe@ ethread_tests.c -lerts_internal_r $(ETHR_T_LIBS) diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index f146bf1d69..644b54f0e1 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -97,9 +97,11 @@ undefined_functions(Config) when is_list(Config) -> Fd = open_log(Config, "undefined_functions"), foreach(fun ({MFA1,MFA2}) -> io:format("~s calls undefined ~s", - [format_mfa(MFA1),format_mfa(MFA2)]), + [format_mfa(Server, MFA1), + format_mfa(MFA2)]), io:format(Fd, "~s ~s\n", - [format_mfa(MFA1),format_mfa(MFA2)]) + [format_mfa(Server, MFA1), + format_mfa(MFA2)]) end, Undef), close_log(Fd), ?line ?t:fail({length(Undef),undefined_functions_in_otp}) @@ -215,9 +217,9 @@ deprecated_not_in_obsolete(Config) when is_list(Config) -> _ -> io:put_chars("The following functions have -deprecated() attributes,\n" "but are not listed in otp_internal:obsolete/3.\n"), - ?line print_mfas(group_leader(), L), + print_mfas(group_leader(), Server, L), Fd = open_log(Config, "deprecated_not_obsolete"), - print_mfas(Fd, L), + print_mfas(Fd, Server, L), close_log(Fd), ?line ?t:fail({length(L),deprecated_but_not_obsolete}) end. @@ -239,9 +241,9 @@ obsolete_but_not_deprecated(Config) when is_list(Config) -> io:put_chars("The following functions are listed " "in otp_internal:obsolete/3,\n" "but don't have -deprecated() attributes.\n"), - ?line print_mfas(group_leader(), L), + print_mfas(group_leader(), Server, L), Fd = open_log(Config, "obsolete_not_deprecated"), - print_mfas(Fd, L), + print_mfas(Fd, Server, L), close_log(Fd), ?line ?t:fail({length(L),obsolete_but_not_deprecated}) end. @@ -310,15 +312,22 @@ strong_components(Config) when is_list(Config) -> %%% Common help functions. %%% - -print_mfas(Fd, [MFA|T]) -> - io:format(Fd, "~s\n", [format_mfa(MFA)]), - print_mfas(Fd, T); -print_mfas(_, []) -> ok. +print_mfas(Fd, Server, MFAs) -> + [io:format(Fd, "~s\n", [format_mfa(Server, MFA)]) || MFA <- MFAs], + ok. format_mfa({M,F,A}) -> lists:flatten(io_lib:format("~s:~s/~p", [M,F,A])). +format_mfa(Server, MFA) -> + MFAString = format_mfa(MFA), + AQ = "(App)" ++ MFAString, + AppPrefix = case xref:q(Server, AQ) of + {ok,[App]} -> "[" ++ atom_to_list(App) ++ "]"; + _ -> "" + end, + AppPrefix ++ MFAString. + open_log(Config, Name) -> PrivDir = ?config(priv_dir, Config), RunDir = filename:dirname(filename:dirname(PrivDir)), diff --git a/erts/test/utils/gccifier.sh b/erts/test/utils/gccifier.sh new file mode 100755 index 0000000000..4c6ba35db2 --- /dev/null +++ b/erts/test/utils/gccifier.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2005-2009. 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% +# + +CC=`echo "$1" | sed -e "s/-CC//"` +shift +echo "->" +echo "$CC $*" +$CC $* +echo "" diff --git a/erts/vsn.mk b/erts/vsn.mk index bbf77b1a68..da0f03b24f 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -17,8 +17,8 @@ # %CopyrightEnd% # -VSN = 5.9.1 -SYSTEM_VSN = R15B01 +VSN = 5.9.2 +SYSTEM_VSN = R15B02 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/cosNotification/test/Makefile b/lib/cosNotification/test/Makefile index f509370430..ddd809ec65 100644 --- a/lib/cosNotification/test/Makefile +++ b/lib/cosNotification/test/Makefile @@ -128,6 +128,7 @@ ERL_COMPILE_FLAGS += \ $(ERL_IDL_FLAGS) \ -pa $(ERL_TOP)/lib/orber/include \ -pa $(ERL_TOP)/internal_tools/test_server/ebin \ + -pa $(ERL_TOP)/lib/cosEvent/ebin \ -pa $(ERL_TOP)/lib/cosNotification/ebin \ -pa $(ERL_TOP)/lib/cosNotification/test/idl_output \ -pa $(ERL_TOP)/lib/cosTime/ebin \ diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index 285537643e..94d156b0ec 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -85,7 +85,7 @@ DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@ ifeq ($(DYNAMIC_CRYPTO_LIB),yes) SSL_DED_LD_RUNTIME_LIBRARY_PATH = @SSL_DED_LD_RUNTIME_LIBRARY_PATH@ -CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) +CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME) else SSL_DED_LD_RUNTIME_LIBRARY_PATH= CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 4dc62421d2..4be593e208 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -1456,10 +1456,37 @@ static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a return ret; } +static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) +{ + /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */ + ERL_NIF_TERM head, tail; + + if (!enif_get_list_cell(env, key, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->e) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->n) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->d) + || (!enif_is_empty_list(env, tail) && + (!enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->p) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->q) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->dmp1) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->dmq1) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->iqmp) + || !enif_is_empty_list(env, tail)))) { + return 0; + } + return 1; +} + static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Data,Key=[E,N,D]) */ +{/* (Type,Data,Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ ErlNifBinary data_bin, ret_bin; - ERL_NIF_TERM head, tail; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; unsigned rsa_s_len; RSA *rsa = RSA_new(); @@ -1470,13 +1497,7 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar else goto badarg; if (!inspect_mpint(env,argv[1],&data_bin) - || !enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->d) - || !enif_is_empty_list(env,tail)) { + || !get_rsa_private_key(env, argv[2], rsa)) { badarg: RSA_free(rsa); return enif_make_badarg(env); @@ -1623,20 +1644,13 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER } static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data, PublKey=[E,N,D], Padding, IsEncrypt) */ +{/* (Data, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Padding, IsEncrypt) */ ErlNifBinary data_bin, ret_bin; - ERL_NIF_TERM head, tail; int padding, i; RSA* rsa = RSA_new(); if (!enif_inspect_binary(env, argv[0], &data_bin) - || !enif_get_list_cell(env, argv[1], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->d) - || !enif_is_empty_list(env,tail) + || !get_rsa_private_key(env, argv[1], rsa) || !rsa_pad(argv[2], &padding)) { RSA_free(rsa); diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 8cb893cd1c..19db6c9dd4 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -870,10 +870,15 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <fsummary>Sign the data using rsa with the given key.</fsummary> <type> <v>Data = Mpint</v> - <v>Key = [E, N, D]</v> + <v>Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v> <v>E, N, D = Mpint</v> <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and <c>D</c> is the private exponent.</d> + <v>P1, P2, E1, E2, C = Mpint</v> + <d>The longer key format contains redundant information that will make + the calculation faster. <c>P1,P2</c> are first and second prime factors. + <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient. + Terminology is taken from RFC 3447.</d> <v>DigestType = md5 | sha</v> <d>The default <c>DigestType</c> is sha.</d> <v>Mpint = binary()</v> @@ -943,10 +948,15 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <fsummary>Decrypts ChipherText using the private Key.</fsummary> <type> <v>ChipherText = binary()</v> - <v>PrivateKey = [E, N, D]</v> + <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v> <v>E, N, D = Mpint</v> <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and <c>D</c> is the private exponent.</d> + <v>P1, P2, E1, E2, C = Mpint</v> + <d>The longer key format contains redundant information that will make + the calculation faster. <c>P1,P2</c> are first and second prime factors. + <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient. + Terminology is taken from RFC 3447.</d> <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v> <v>PlainText = binary()</v> </type> @@ -965,10 +975,15 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <fsummary>Encrypts Msg using the private Key.</fsummary> <type> <v>PlainText = binary()</v> - <v>PrivateKey = [E, N, D]</v> - <v>E, N, D = Mpint</v> + <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v> + <v>E, N, D = Mpint</v> <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and <c>D</c> is the private exponent.</d> + <v>P1, P2, E1, E2, C = Mpint</v> + <d>The longer key format contains redundant information that will make + the calculation faster. <c>P1,P2</c> are first and second prime factors. + <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient. + Terminology is taken from RFC 3447.</d> <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v> <v>ChipherText = binary()</v> </type> diff --git a/lib/dialyzer/test/small_SUITE_data/results/port_info_test b/lib/dialyzer/test/small_SUITE_data/results/port_info_test index 9ee863f9eb..863a3d61df 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/port_info_test +++ b/lib/dialyzer/test/small_SUITE_data/results/port_info_test @@ -3,4 +3,5 @@ port_info_test.erl:10: The pattern {'connected', 42} can never match the type 'u port_info_test.erl:14: The pattern {'registered_name', "42"} can never match the type 'undefined' | {'registered_name',atom()} port_info_test.erl:19: The pattern {'output', 42} can never match the type 'undefined' | {'connected',pid()} port_info_test.erl:24: Guard test 'links' =:= Atom::'connected' can never succeed -port_info_test.erl:28: The pattern {'gazonk', _} can never match the type 'undefined' | {'connected' | 'id' | 'input' | 'links' | 'name' | 'output' | 'registered_name',atom() | pid() | [pid() | char()] | integer()} +port_info_test.erl:28: The pattern {'gazonk', _} can never match the type 'undefined' | {'connected' | 'id' | 'input' | 'links' | 'name' | 'os_pid' | 'output' | 'registered_name',atom() | pid() | [pid() | char()] | integer()} +port_info_test.erl:32: The pattern {'os_pid', "42"} can never match the type 'undefined' | {'os_pid','undefined' | non_neg_integer()} diff --git a/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl b/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl index 2ee9a3a6e2..07f22256c9 100644 --- a/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl +++ b/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl @@ -3,7 +3,7 @@ %% and the quality of the warnings that Dialyzer spits out %% -module(port_info_test). --export([t1/1, t2/1, t3/1, t4/1, t5/2, buggy/1]). +-export([t1/1, t2/1, t3/1, t4/1, t5/2, t6/1, buggy/1]). %% The following errors are correctly caught, but the messages are a bit weird t1(X) when is_port(X) -> @@ -28,6 +28,10 @@ t5(X, Atom) when is_port(X) -> {gazonk, _} = erlang:port_info(X, Atom); t5(_, _) -> ok. +t6(X) when is_port(X) -> + {os_pid, "42"} = erlang:port_info(X, os_pid); +t6(_) -> ok. + %% The type system is not strong enough to catch the following errors buggy(X) when is_atom(X) -> {links, X} = erlang:port_info(foo, X). diff --git a/lib/eldap/.gitignore b/lib/eldap/.gitignore index 5585418186..d3dd8228d5 100644 --- a/lib/eldap/.gitignore +++ b/lib/eldap/.gitignore @@ -1,4 +1,4 @@ *.beam *.asn1db -src/ELDAPv3.hrl -src/ELDAPv3.erl +ebin/ELDAPv3.hrl +ebin/ELDAPv3.erl diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile index a17d4f56b2..2349e4b292 100644 --- a/lib/eldap/test/Makefile +++ b/lib/eldap/test/Makefile @@ -50,7 +50,7 @@ RELSYSDIR = $(RELEASE_PATH)/eldap_test # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -ERL_COMPILE_FLAGS += $(INCLUDES) +ERL_COMPILE_FLAGS += $(INCLUDES) -pa $(ERL_TOP)/lib/eldap/ebin EBIN = . diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index 4ed4fa14c4..bf17406d84 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -1564,7 +1564,7 @@ </xsl:variable> <fo:block xsl:use-attribute-sets="image"> - <fo:external-graphic content-width="60%" src="{@file}"/> + <fo:external-graphic content-width="scale-down-to-fit" inline-progression-dimension.maximum="100%" src="{@file}"/> <xsl:apply-templates> <xsl:with-param name="chapnum" select="$chapnum"/> diff --git a/lib/erl_interface/test/all_SUITE_data/Makefile.src b/lib/erl_interface/test/all_SUITE_data/Makefile.src index 70652e47c5..39085def2d 100644 --- a/lib/erl_interface/test/all_SUITE_data/Makefile.src +++ b/lib/erl_interface/test/all_SUITE_data/Makefile.src @@ -32,7 +32,7 @@ all: $(ALL_OBJS) $(EI_COMMON_OBJS): gccifier@exe@ -@IFEQ@ (@erl_interface_cross_compile@, true) +@IFEQ@ (@cross@, yes) gccifier@exe@: $(CP) gccifier.sh gccifier@exe@ $(CHMOD) a+x gccifier@exe@ diff --git a/lib/erl_interface/test/all_SUITE_data/init_tc.erl b/lib/erl_interface/test/all_SUITE_data/init_tc.erl index 7a599994fc..60c965eda3 100644 --- a/lib/erl_interface/test/all_SUITE_data/init_tc.erl +++ b/lib/erl_interface/test/all_SUITE_data/init_tc.erl @@ -48,8 +48,7 @@ run1(Name) -> generate(TcName, Cases) -> Hrl = TcName ++ "_cases.hrl", {ok, HrlFile} = file:open(Hrl, write), - {ok, Dir} = file:get_cwd(), - generate_hrl(Cases, HrlFile, {filename:join(Dir, TcName), 0}), + generate_hrl(Cases, HrlFile, {TcName, 0}), file:close(HrlFile), C = TcName ++ "_decl.c", {ok, CFile} = file:open(C, write), @@ -57,7 +56,7 @@ generate(TcName, Cases) -> file:close(CFile). generate_hrl([Case|Rest], File, {Name, Number}) -> - io:format(File, "-define(~s, {\"~s\", ~w}).~n", [Case, Name, Number]), + io:format(File, "-define(~s, {filename:join(proplists:get_value(data_dir,Config),\"~s\"), ~w}).~n", [Case, Name, Number]), generate_hrl(Rest, File, {Name, Number+1}); generate_hrl([], _, _) -> ok. diff --git a/lib/eunit/src/Makefile b/lib/eunit/src/Makefile index bec2fdbe0b..0b6ed1e839 100644 --- a/lib/eunit/src/Makefile +++ b/lib/eunit/src/Makefile @@ -28,6 +28,9 @@ ERL_COMPILE_FLAGS += -pa $(EBIN) -I$(INCLUDE) +warn_unused_vars +nowarn_shadow_v PARSE_TRANSFORM = eunit_autoexport.erl +BEHAVIOUR_SOURCES= \ + eunit_listener.erl + SOURCES= \ eunit_striptests.erl \ eunit.erl \ @@ -40,13 +43,16 @@ SOURCES= \ eunit_data.erl \ eunit_tty.erl \ eunit_surefire.erl \ - eunit_listener.erl INCLUDE_FILES = eunit.hrl PARSE_TRANSFORM_BIN = $(PARSE_TRANSFORM:%.erl=$(EBIN)/%.$(EMULATOR)) -OBJECTS=$(SOURCES:%.erl=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) +TARGET_FILES= $(SOURCES:%.erl=$(EBIN)/%.$(EMULATOR)) + +BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_SOURCES:%.erl=$(EBIN)/%.$(EMULATOR)) + +OBJECTS= $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) INCLUDE_DELIVERABLES = $(INCLUDE_FILES:%=$(INCLUDE)/%) @@ -62,6 +68,8 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE) # Targets # ---------------------------------------------------- +$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) + debug opt: $(PARSE_TRANSFORM_BIN) $(OBJECTS) docs: diff --git a/lib/gs/src/gstk_generic.erl b/lib/gs/src/gstk_generic.erl index 10cb890013..9b0efd07c1 100644 --- a/lib/gs/src/gstk_generic.erl +++ b/lib/gs/src/gstk_generic.erl @@ -323,7 +323,7 @@ handle_external_opt_call([Opt|Options],Gstkid,TkW,DB,ExtraArg,ExtRes,S,P,C) -> end. handle_external_read(Res) -> - case Res of + _ = case Res of {bad_result,{Objtype,Reason,Option}} -> {error,{Objtype,Reason,Option}}; _ -> ok diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 0c2e846010..5033cef8c5 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1186,6 +1186,7 @@ type(erlang, port_info, 2, Xs) -> ['links'] -> t_tuple([Item, t_list(t_pid())]); ['name'] -> t_tuple([Item, t_string()]); ['output'] -> t_tuple([Item, t_integer()]); + ['os_pid'] -> t_tuple([Item, t_sup(t_non_neg_integer(),t_atom('undefined'))]); ['registered_name'] -> t_tuple([Item, t_atom()]); List when is_list(List) -> t_tuple([t_sup([t_atom(A) || A <- List]), @@ -3789,7 +3790,7 @@ arg_types(erlang, port_info, 1) -> arg_types(erlang, port_info, 2) -> [t_sup(t_port(), t_atom()), t_atoms(['registered_name', 'id', 'connected', - 'links', 'name', 'input', 'output'])]; + 'links', 'name', 'input', 'output', 'os_pid'])]; arg_types(erlang, port_to_list, 1) -> [t_port()]; arg_types(erlang, ports, 0) -> diff --git a/lib/inets/src/tftp/Makefile b/lib/inets/src/tftp/Makefile index 759b70c8e4..f728543adb 100644 --- a/lib/inets/src/tftp/Makefile +++ b/lib/inets/src/tftp/Makefile @@ -39,8 +39,10 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- +BEHAVIOUR_MODULES= \ + tftp + MODULES = \ - tftp \ tftp_binary \ tftp_engine \ tftp_file \ @@ -50,10 +52,13 @@ MODULES = \ HRL_FILES = tftp.hrl -ERL_FILES = $(MODULES:%=%.erl) +ERL_FILES= \ + $(MODULES:%=%.erl) \ + $(BEHAVIOUR_MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- # FLAGS @@ -72,10 +77,12 @@ ERL_COMPILE_FLAGS += \ # Targets # ---------------------------------------------------- +$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) + debug opt: $(TARGET_FILES) clean: - rm -f $(TARGET_FILES) + rm -f $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) rm -f core docs: @@ -90,7 +97,7 @@ release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/src/tftp $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/tftp $(INSTALL_DIR) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index 579b7f1f74..e327a4f907 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -123,7 +123,7 @@ <p>Completely closes the socket and all associations on it. The unsent data is flushed as in <c>eof/2</c>. The <c>close/1</c> call is blocking or otherwise depending of the value of - the <seealso marker="#option-linger">linger</seealso> socket + the <seealso marker="inet#option-linger">linger</seealso> socket <seealso marker="#options">option</seealso>. If <c>close</c> does not linger or linger timeout expires, the call returns and the data is flushed in the background.</p> @@ -309,8 +309,8 @@ <seealso marker="#option-active">passive</seealso> mode, with <anno>SockType</anno> <c>seqpacket</c>, and with reasonably large - <seealso marker="#option-sndbuf">kernel</seealso> and driver - <seealso marker="#option-buffer">buffers.</seealso></p> + <seealso marker="inet#option-sndbuf">kernel</seealso> and driver + <seealso marker="inet#option-buffer">buffers.</seealso></p> </desc> </func> <func> @@ -530,19 +530,8 @@ SCTP data interleaved with other inter-process messages.</p> </item> </list> - <marker id="option-buffer"></marker> </item> - <tag><c>{buffer, integer()}</c></tag> - <item> - <p>Determines the size of the user-level software buffer used by - the SCTP driver. Not to be confused with <c>sndbuf</c> - and <c>recbuf</c> options which correspond to - the kernel socket buffers. It is recommended - to have <c>val(buffer) >= max(val(sndbuf),val(recbuf))</c>. - In fact, the <c>val(buffer)</c> is automatically set to - the above maximum when <c>sndbuf</c> or <c>recbuf</c> values are set.</p> - </item> - <tag><c>{tos, integer()}</c></tag> + <tag><c>{tos, integer()}</c></tag> <item> <p>Sets the Type-Of-Service field on the IP datagrams being sent, to the given value, which effectively determines a prioritization @@ -567,19 +556,8 @@ <c>{IP,Port}</c> of the socket can be re-used immediately: no waiting in the CLOSE_WAIT state is performed (may be required for high-throughput servers).</p> - <marker id="option-linger"></marker> - </item> - <tag><c>{linger, {true|false, integer()}</c></tag> - <item> - <p>Determines the timeout in seconds for flushing unsent data in the - <c>gen_sctp:close/1</c> socket call. If the 1st component of the value - tuple is <c>false</c>, the 2nd one is ignored, which means that - <c>gen_sctp:close/1</c> returns immediately not waiting - for data to be flushed. Otherwise, the 2nd component is - the flushing time-out in seconds.</p> - <marker id="option-sndbuf"></marker> </item> - <tag><c>{sndbuf, integer()}</c></tag> + <tag><c>{sndbuf, integer()}</c></tag> <item> <p>The size, in bytes, of the *kernel* send buffer for this socket. Sending errors would occur for datagrams larger than @@ -593,6 +571,15 @@ <c>val(sndbuf)</c>. Setting this option also adjusts the size of the driver buffer (see <c>buffer</c> above).</p> </item> + + <tag><c>{sctp_module, module()}</c></tag> + <item> <p> + Override which callback module is used. Defaults to + <c>inet_sctp</c> for IPv4 and <c>inet6_sctp</c> for IPv6. + </p> + </item> + + <tag><c>{sctp_rtoinfo, #sctp_rtoinfo{}}</c></tag> <item> <pre> #sctp_rtoinfo{ diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index cf97607af1..daf26a0b63 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -96,37 +96,47 @@ do_recv(Sock, Bs) -> can be either a hostname, or an IP address.</p> <p>The available options are:</p> <taglist> - <tag><c>list</c></tag> - <item> - <p>Received <c>Packet</c> is delivered as a list.</p> - </item> - <tag><c>binary</c></tag> - <item> - <p>Received <c>Packet</c> is delivered as a binary.</p> - </item> - <tag><c>{ip, ip_address()}</c></tag> + <tag><c>{ip, ip_address()}</c></tag> <item> <p>If the host has several network interfaces, this option specifies which one to use.</p> </item> - <tag><c>{port, Port}</c></tag> + + <tag><c>{ifaddr, ip_address()}</c></tag> <item> - <p>Specify which local port number to use.</p> - </item> + <p>Same as <c>{ip, ip_address()}</c>. If the host has several network interfaces, this option + specifies which one to use.</p> + </item> + <tag><c>{fd, integer() >= 0}</c></tag> <item> <p>If a socket has somehow been connected without using <c>gen_tcp</c>, use this option to pass the file descriptor for it.</p> </item> - <tag><c>inet6</c></tag> + + <tag><c>inet</c></tag> <item> + <p>Set up the socket for IPv4.</p> + </item> + + <tag><c>inet6</c></tag> + <item> <p>Set up the socket for IPv6.</p> </item> - <tag><c>inet</c></tag> + + <tag><c>{port, Port}</c></tag> <item> - <p>Set up the socket for IPv4.</p> + <p>Specify which local port number to use.</p> </item> + + <tag><c>{tcp_module, module()}</c></tag> + <item> <p> + Override which callback module is used. Defaults to + <c>inet_tcp</c> for IPv4 and <c>inet6_tcp</c> for IPv6. + </p> + </item> + <tag><c>Opt</c></tag> <item> <p>See @@ -197,6 +207,13 @@ do_recv(Sock, Bs) -> <c>gen_tcp</c>, use this option to pass the file descriptor for it.</p> </item> + + <tag><c>{ifaddr, ip_address()}</c></tag> + <item> + <p>Same as <c>{ip, ip_address()}</c>. If the host has several network interfaces, this option + specifies which one to use.</p> + </item> + <tag><c>inet6</c></tag> <item> <p>Set up the socket for IPv6.</p> @@ -205,6 +222,14 @@ do_recv(Sock, Bs) -> <item> <p>Set up the socket for IPv4.</p> </item> + + <tag><c>{tcp_module, module()}</c></tag> + <item> <p> + Override which callback module is used. Defaults to + <c>inet_tcp</c> for IPv4 and <c>inet6_tcp</c> for IPv6. + </p> + </item> + <tag><c>Opt</c></tag> <item> <p>See diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index daa9b7d887..6b83dfa030 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -72,6 +72,14 @@ <p>If the host has several network interfaces, this option specifies which one to use.</p> </item> + + <tag><c>{ifaddr, ip_address()}</c></tag> + <item> + <p>Same as <c>{ip, ip_address()}</c>. If the host has several network interfaces, this option + specifies which one to use.</p> + </item> + + <tag><c>{fd, integer() >= 0}</c></tag> <item> <p>If a socket has somehow been opened without using @@ -86,6 +94,51 @@ <item> <p>Set up the socket for IPv4.</p> </item> + + <tag><c>{udp_module, module()}</c></tag> + <item> <p> + Override which callback module is used. Defaults to + <c>inet_udp</c> for IPv4 and <c>inet6_udp</c> for IPv6. + </p> + </item> + + <tag><c>{multicast_if, Address}</c></tag> + <item> + <p>Set the local device for a multicast socket.</p> + </item> + + <tag><c>{multicast_loop, true | false}</c></tag> + <item> + <p> + When <c>true</c> sent multicast packets will be looped back to the local + sockets. + </p> + </item> + + <tag><c>{multicast_ttl, Integer}</c></tag> + <item> + <p> + The <c>multicast_ttl</c> option changes the time-to-live (TTL) for + outgoing multicast datagrams in order to control the scope of the + multicasts. + </p> + <p> + Datagrams with a TTL of 1 are not forwarded beyond the local + network. + <br />Default: 1 + </p> + </item> + + <tag><c>{add_membership, {MultiAddress, InterfaceAddress}}</c></tag> + <item> + <p>Join a multicast group. </p> + </item> + + <tag><c>{drop_membership, {MultiAddress, InterfaceAddress}}</c></tag> + <item> + <p>Leave multicast group.</p> + </item> + <tag><c>Opt</c></tag> <item> <p>See diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index bf6c4cfb1a..096ddfd847 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -445,10 +445,34 @@ fe80::204:acff:fe17:bf38 flow control; the other side will not be able send faster than the receiver can read.</p> </item> + + <tag><c>{bit8, clear | set | on | off}</c></tag> + <item> + <p> + Scans every byte in received data-packets and checks if the 8 bit + is set in any of them. Information is retrieved with + <c>inet:getopts/2</c>. + <note>Deprecated! Will be removed in Erlang/OTP R16.</note> + </p> + </item> + <tag><c>{broadcast, Boolean}</c>(UDP sockets)</tag> <item> <p>Enable/disable permission to send broadcasts.</p> + <marker id="option-buffer"></marker> </item> + + <tag><c>{buffer, Size}</c></tag> + <item> + <p>Determines the size of the user-level software buffer used by + the driver. Not to be confused with <c>sndbuf</c> + and <c>recbuf</c> options which correspond to + the kernel socket buffers. It is recommended + to have <c>val(buffer) >= max(val(sndbuf),val(recbuf))</c>. + In fact, the <c>val(buffer)</c> is automatically set to + the above maximum when <c>sndbuf</c> or <c>recbuf</c> values are set.</p> + </item> + <tag><c>{delay_send, Boolean}</c></tag> <item> <p>Normally, when an Erlang process sends to a socket, @@ -463,10 +487,19 @@ fe80::204:acff:fe17:bf38 real property of the socket. Needless to say it is an implementation specific option. Default is <c>false</c>.</p> </item> + + <tag><c>{deliver, port | term}</c></tag> + <item> <p> When <c>{active, true}</c> delivers data on the forms + <c>port</c> : <c>{S, {data, [H1,..Hsz | Data]}}</c> or + <c>term</c> : <c>{tcp, S, [H1..Hsz | Data]}</c>. + </p> + </item> + <tag><c>{dontroute, Boolean}</c></tag> <item> <p>Enable/disable routing bypass for outgoing messages.</p> </item> + <tag><c>{exit_on_close, Boolean}</c></tag> <item> <p>By default this option is set to <c>true</c>.</p> @@ -476,6 +509,7 @@ fe80::204:acff:fe17:bf38 <seealso marker="gen_tcp#shutdown/2">gen_tcp:shutdown/2</seealso> to shutdown the write side.</p> </item> + <tag><c>{header, Size}</c></tag> <item> <p>This option is only meaningful if the <c>binary</c> @@ -487,6 +521,15 @@ fe80::204:acff:fe17:bf38 example <c>Size == 2</c>, the data received will match <c>[Byte1,Byte2|Binary]</c>.</p> </item> + + <tag><c>{high_watermark, Size}</c></tag> + <item> <p> + Sender is forced busy if sent and enqueued data + reaches the highwater mark. + <br /> Default: 8192 kB. + </p> + </item> + <tag><c>{keepalive, Boolean}</c>(TCP/IP sockets)</tag> <item> <p>Enables/disables periodic transmission on a connected @@ -494,7 +537,43 @@ fe80::204:acff:fe17:bf38 the other end does not respond, the connection is considered broken and an error message will be sent to the controlling process. Default disabled.</p> + <marker id="option-linger"></marker> </item> + + <tag><c>{linger, {true|false, Seconds}}</c></tag> + <item> + <p>Determines the timeout in seconds for flushing unsent data in the + <c>close/1</c> socket call. If the 1st component of the value + tuple is <c>false</c>, the 2nd one is ignored, which means that + <c>close/1</c> returns immediately not waiting + for data to be flushed. Otherwise, the 2nd component is + the flushing time-out in seconds.</p> + </item> + + <tag><c>{low_watermark, Size}</c></tag> + <item> <p> + If the port has reached its <c>high_watermark</c> it will + force busy onto senders. When the port data queue reaches the + <c>low_watermark</c> callers are no longer forced busy. + <br /> Default: 4096 kB. + </p> + </item> + + <tag><c>{mode, Mode :: binary | list}</c></tag> + <item> + <p>Received <c>Packet</c> is delivered as defined by Mode.</p> + </item> + + <tag><c>list</c></tag> + <item> + <p>Received <c>Packet</c> is delivered as a list.</p> + </item> + + <tag><c>binary</c></tag> + <item> + <p>Received <c>Packet</c> is delivered as a binary.</p> + </item> + <tag><c>{nodelay, Boolean}</c>(TCP/IP sockets)</tag> <item> <p>If <c>Boolean == true</c>, the <c>TCP_NODELAY</c> option @@ -578,6 +657,16 @@ fe80::204:acff:fe17:bf38 indicated length are accepted and not considered invalid due to internal buffer limitations.</p> </item> + + <tag><c>{priority, Priority}</c></tag> + <item> <p>Set the protocol-defined priority for all packets to be sent + on this socket.</p> + </item> + + <tag><c>{raw, Protocol, OptionNum, ValueBin}</c></tag> + <item> <p>See below.</p> + </item> + <tag><c>{read_packets, Integer}</c>(UDP sockets)</tag> <item> <p>Sets the max number of UDP packets to read without @@ -589,7 +678,7 @@ fe80::204:acff:fe17:bf38 high the system can become unresponsive due to UDP packet flooding.</p> </item> - <tag><c>{recbuf, Integer}</c></tag> + <tag><c>{recbuf, Size}</c></tag> <item> <p>Gives the size of the receive buffer to use for the socket.</p> @@ -618,9 +707,10 @@ fe80::204:acff:fe17:bf38 returns <c>{error,timeout}</c>. The recommended setting is <c>true</c> which will automatically close the socket. Default is <c>false</c> due to backward compatibility.</p> + <marker id="option-sndbuf"></marker> </item> - <tag><c>{sndbuf, Integer}</c></tag> + <tag><c>{sndbuf, Size}</c></tag> <item> <p>Gives the size of the send buffer to use for the socket.</p> </item> @@ -639,6 +729,7 @@ fe80::204:acff:fe17:bf38 not implemented. Use with caution.</p> </item> </taglist> + <p>In addition to the options mentioned above, <em>raw</em> option specifications can be used. The raw options are specified as a tuple of arity four, beginning with the tag diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index ef6bfdf7f4..e6dfdadb03 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -31,7 +31,6 @@ -type option() :: {active, true | false | once} | - {bit8, clear | set | on | off} | {buffer, non_neg_integer()} | {delay_send, boolean()} | {deliver, port | term} | @@ -61,7 +60,6 @@ {tos, non_neg_integer()}. -type option_name() :: active | - bit8 | buffer | delay_send | deliver | diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index c74a258af9..0c53b1e85b 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -2044,7 +2044,7 @@ send_timeout_active(Config) when is_list(Config) -> ?line {error,timeout} = Loop(fun() -> receive - {tcp, Sock, _Data} -> + {tcp, _Sock, _Data} -> inet:setopts(A, [{active, once}]), Res = gen_tcp:send(A,lists:duplicate(1000, $a)), %erlang:display(Res), @@ -2536,7 +2536,7 @@ otp_8102_do(LSocket, PortNum, {Bin,PType}) -> otp_9389(doc) -> ["Verify packet_size handles long HTTP header lines"]; otp_9389(suite) -> []; otp_9389(Config) when is_list(Config) -> - ?line {ok, LS} = gen_tcp:listen(0, []), + ?line {ok, LS} = gen_tcp:listen(0, [{active,false}]), ?line {ok, {_, PortNum}} = inet:sockname(LS), io:format("Listening on ~w with port number ~p\n", [LS, PortNum]), OrigLinkHdr = "/" ++ string:chars($S, 8192), diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 76d3003ff4..c494f8a864 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15.1 +KERNEL_VSN = 2.15.2 diff --git a/lib/megaco/src/engine/Makefile b/lib/megaco/src/engine/Makefile index 3943f4b957..c6a8bc86c7 100644 --- a/lib/megaco/src/engine/Makefile +++ b/lib/megaco/src/engine/Makefile @@ -42,9 +42,14 @@ RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN) include modules.mk -ERL_FILES = $(MODULES:%=%.erl) +ERL_FILES = \ + $(MODULES:%=%.erl) \ + $(BEHAVIOUR_MODULES:%=%.erl) -TARGET_FILES = \ +BEHAVIOUR_TARGET_FILES= \ + $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) + +TARGET_FILES = \ $(MODULES:%=$(EBIN)/%.$(EMULATOR)) @@ -65,19 +70,23 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- + +$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) + debug: @${MAKE} TYPE=debug opt opt: $(TARGET_FILES) clean: - rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) rm -f errs core *~ docs: info: @echo "MODULES = $(MODULES)" + @echo "BEHAVIOUR_MODULES = $(BEHAVIOUR_MODULES)" @echo "" @@ -89,7 +98,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(RELSYSDIR)/ebin $(INSTALL_DIR) $(RELSYSDIR)/src $(INSTALL_DIR) $(RELSYSDIR)/src/engine $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/engine diff --git a/lib/megaco/src/engine/modules.mk b/lib/megaco/src/engine/modules.mk index 4bc57cd63e..6e2f9246f0 100644 --- a/lib/megaco/src/engine/modules.mk +++ b/lib/megaco/src/engine/modules.mk @@ -23,7 +23,6 @@ BEHAVIOUR_MODULES = \ megaco_transport MODULES = \ - $(BEHAVIOUR_MODULES) \ megaco_config_misc \ megaco_config \ megaco_digit_map \ diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 2e2a6cd296..9f1a0b3af5 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -241,15 +241,15 @@ pkix_encode(Asn1Type, Term0, otp) when is_atom(Asn1Type) -> decrypt_private(CipherText, Key) -> decrypt_private(CipherText, Key, []). -decrypt_private(CipherText, - #'RSAPrivateKey'{modulus = N,publicExponent = E, - privateExponent = D}, - Options) when is_binary(CipherText), - is_list(Options) -> +decrypt_private(CipherText, + #'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D} = Key, + Options) + when is_binary(CipherText), + is_integer(N), is_integer(E), is_integer(D), + is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_decrypt(CipherText, - [crypto:mpint(E), crypto:mpint(N), - crypto:mpint(D)], Padding). + crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- -spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) -> @@ -307,14 +307,29 @@ encrypt_public(PlainText, #'RSAPrivateKey'{modulus=N,publicExponent=E}, encrypt_private(PlainText, Key) -> encrypt_private(PlainText, Key, []). -encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N, - publicExponent = E, - privateExponent = D}, - Options) when is_binary(PlainText), is_list(Options) -> +encrypt_private(PlainText, + #'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D} = Key, + Options) + when is_binary(PlainText), + is_integer(N), is_integer(E), is_integer(D), + is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - crypto:rsa_private_encrypt(PlainText, [crypto:mpint(E), - crypto:mpint(N), - crypto:mpint(D)], Padding). + crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). + + +format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D, + prime1 = P1, prime2 = P2, + exponent1 = E1, exponent2 = E2, + coefficient = C}) + when is_integer(P1), is_integer(P2), + is_integer(E1), is_integer(E2), is_integer(C) -> + [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]]; + +format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) -> + [crypto:mpint(K) || K <- [E, N, D]]. %%-------------------------------------------------------------------- -spec sign(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), @@ -323,15 +338,13 @@ encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N, %% %% Description: Create digital signature. %%-------------------------------------------------------------------- -sign(PlainText, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) +sign(PlainText, DigestType, + #'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D} = Key) when is_binary(PlainText), - (DigestType == md5 orelse - DigestType == sha) -> - - crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E), - crypto:mpint(N), - crypto:mpint(D)]); + (DigestType == md5 orelse DigestType == sha), + is_integer(N), is_integer(E), is_integer(D) -> + crypto:rsa_sign(DigestType, sized_binary(PlainText), + format_rsa_private_key(Key)); sign(Digest, none, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) when is_binary(Digest)-> diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile index b7f91981a5..397a0eb2d5 100644 --- a/lib/public_key/test/Makefile +++ b/lib/public_key/test/Makefile @@ -21,7 +21,7 @@ include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk -INCLUDES= -I. -I ../include +INCLUDES= -I. -I ../include -pa $(ERL_TOP)/lib/public_key/ebin # ---------------------------------------------------- # Target Specs diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile index d8a7adb837..932532d811 100644 --- a/lib/reltool/test/Makefile +++ b/lib/reltool/test/Makefile @@ -49,7 +49,7 @@ RELSYSDIR = $(RELEASE_PATH)/reltool_test # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -#ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/reltool/ebin/ EBIN = . diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index 1734ae4df4..a247692d9d 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -38,15 +38,17 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN) # Behaviour (api) modules are first so they are compiled when # the compiler reaches a callback module using them. -MODULES= \ +BEHAVIOUR_MODULES= \ ssh_sftpd_file_api \ - ssh_key_api \ + ssh_channel \ + ssh_key_api + +MODULES= \ ssh \ ssh_sup \ sshc_sup \ sshd_sup \ ssh_connection_sup \ - ssh_channel \ ssh_connection \ ssh_connection_handler \ ssh_connection_manager \ @@ -73,11 +75,14 @@ MODULES= \ PUBLIC_HRL_FILES= ssh.hrl ssh_userauth.hrl ssh_xfer.hrl -ERL_FILES= $(MODULES:%=%.erl) +ERL_FILES= \ + $(MODULES:%=%.erl) \ + $(BEHAVIOUR_MODULES:%=%.erl) -ALL_MODULES= $(MODULES) -TARGET_FILES= $(ALL_MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) APP_FILE= ssh.app APPUP_FILE= ssh.appup @@ -93,29 +98,29 @@ INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -ERL_COMPILE_FLAGS += -pa$(EBIN)\ - -pz $(ERL_TOP)/lib/public_key/ebin +EXTRA_ERLC_FLAGS = +warn_unused_vars +ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \ + -pz $(EBIN) \ + -pz $(ERL_TOP)/lib/public_key/ebin \ + $(EXTRA_ERLC_FLAGS) + + # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) -debug: ERLC_FLAGS += -Ddebug +debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) clean: - rm -f $(TARGET_FILES) + rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) rm -f errs core *~ -$(TARGET_FILES): ssh.hrl - -# $(EBIN)/ssh_sftpd_file.$(EMULATOR): ERLC_FLAGS += -pa$(EBIN) -# $(EBIN)/ssh_sftpd_file.$(EMULATOR): $(EBIN)/ssh_sftpd_file_api.$(EMULATOR) - -$(APP_TARGET): $(APP_SRC) ../vsn.mk +$(APP_TARGET): $(APP_SRC) ../vsn.mk sed -e 's;%VSN%;$(VSN);' $< > $@ -$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk sed -e 's;%VSN%;$(VSN);' $< > $@ @@ -130,7 +135,8 @@ release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/src $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src $(INSTALL_DIR) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) \ + $(APPUP_TARGET) $(RELSYSDIR)/ebin $(INSTALL_DIR) $(RELSYSDIR)/include $(INSTALL_DATA) $(PUBLIC_HRL_FILES) $(RELSYSDIR)/include diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 39c7fe329e..f4a40c81a4 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -346,8 +346,9 @@ handle_option([{role, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{compression, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); -handle_option([{allow_user_interaction, _} = Opt | Rest], SocketOptions, SshOptions) -> - handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +%%Backwards compatibility +handle_option([{allow_user_interaction, Value} | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option({user_interaction, Value}) | SshOptions]); handle_option([{infofun, _} = Opt | Rest],SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{connectfun, _} = Opt | Rest], SocketOptions, SshOptions) -> @@ -366,6 +367,8 @@ handle_option([{ssh_cli, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{shell, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{exec, _} = Opt | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions). @@ -401,8 +404,9 @@ handle_ssh_option({key_cb, Value} = Opt) when is_atom(Value) -> Opt; handle_ssh_option({compression, Value} = Opt) when is_atom(Value) -> Opt; -handle_ssh_option({allow_user_interaction, Value} = Opt) when Value == true; - Value == false -> +handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module), + is_atom(Function) -> + Opt; handle_ssh_option({infofun, Value} = Opt) when is_function(Value) -> Opt; @@ -412,11 +416,12 @@ handle_ssh_option({disconnectfun , Value} = Opt) when is_function(Value) -> Opt; handle_ssh_option({failfun, Value} = Opt) when is_function(Value) -> Opt; -handle_ssh_option({ip_v6_disabled, Value} = Opt) when is_function(Value) -> +handle_ssh_option({ip_v6_disabled, Value} = Opt) when Value == true; + Value == false -> Opt; handle_ssh_option({transport, {Protocol, Cb, ClosTag}} = Opt) when is_atom(Protocol), - is_atom(Cb), - is_atom(ClosTag) -> + is_atom(Cb), + is_atom(ClosTag) -> Opt; handle_ssh_option({subsystems, Value} = Opt) when is_list(Value) -> Opt; @@ -495,4 +500,3 @@ verify_data(Data, Signature, Algorithm) when is_binary(Data), is_binary(Signatur Error -> Error end. - diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index 1a4517c689..aa452a8e09 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -71,7 +71,7 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb, ssh_bits:install_messages(userauth_passwd_messages()), Password = case proplists:get_value(password, Opts) of undefined -> - user_interaction(Opts, IoCb); + user_interaction(IoCb); PW -> PW end, @@ -89,13 +89,10 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb, Ssh) end. -user_interaction(Opts, IoCb) -> - case proplists:get_value(allow_user_interaction, Opts, true) of - true -> - IoCb:read_password("ssh password: "); - false -> - not_ok - end. +user_interaction(ssh_no_io) -> + not_ok; +user_interaction(IoCb) -> + IoCb:read_password("ssh password: "). %% See RFC 4256 for info on keyboard-interactive @@ -124,8 +121,7 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts, ?PREFERRED_PK_ALG)), SecondAlg = other_alg(FirstAlg), - AllowUserInt = proplists:get_value(allow_user_interaction, Opts, - true), + AllowUserInt = proplists:get_value(user_interaction, Opts, true), Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, userauth_preference = Prefs, diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl index 7b600ed8b2..1938858420 100644 --- a/lib/ssh/src/ssh_channel.erl +++ b/lib/ssh/src/ssh_channel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. 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 @@ -215,7 +215,7 @@ handle_info({ssh_cm, ConnectionManager, {closed, ChannelId}}, close_sent = false} = State) -> %% To be on the safe side, i.e. the manager has already been terminated. (catch ssh_connection:close(ConnectionManager, ChannelId)), - {stop, normal, State}; + {stop, normal, State#state{close_sent = true}}; handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager, channel_cb = Module, diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl index e993f597a5..8c1f88e572 100644 --- a/lib/ssh/src/ssh_connection_manager.erl +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -384,9 +384,10 @@ handle_call({close, ChannelId}, _, #state{connection = Pid, connection_state = #connection{channel_cache = Cache}} = State) -> case ssh_channel:cache_lookup(Cache, ChannelId) of - #channel{remote_id = Id} -> + #channel{remote_id = Id} = Channel -> send_msg({connection_reply, Pid, ssh_connection:channel_close_msg(Id)}), + ssh_channel:cache_update(Cache, Channel#channel{sent_close = true}), {reply, ok, State}; undefined -> {reply, ok, State} diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index d66214d415..c5019425cd 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -183,7 +183,29 @@ app_test(doc) -> app_test(Config) when is_list(Config) -> ?t:app_test(ssh), ok. +%%-------------------------------------------------------------------- +misc_ssh_options(doc) -> + ["Test that we can set some misc options not tested elsewhere, " + "some options not yet present are not decided if we should support or " + "if they need thier own test case."]; +misc_ssh_options(suite) -> + []; +misc_ssh_options(Config) when is_list(Config) -> + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + CMiscOpt0 = [{connecect_timeout, 1000}, {ip_v6_disable, false}, {user_dir, UserDir}], + CMiscOpt1 = [{connecect_timeout, infinity}, {ip_v6_disable, true}, {user_dir, UserDir}], + SMiscOpt0 = [{ip_v6_disable, false}, {user_dir, UserDir}, {system_dir, SystemDir}], + SMiscOpt1 = [{ip_v6_disable, true}, {user_dir, UserDir}, {system_dir, SystemDir}], + + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + basic_test([{client_opts, CMiscOpt0 ++ ClientOpts}, {server_opts, SMiscOpt0 ++ ServerOpts}]), + basic_test([{client_opts, CMiscOpt1 ++ ClientOpts}, {server_opts, SMiscOpt1 ++ ServerOpts}]). +%%-------------------------------------------------------------------- exec(doc) -> ["Test api function ssh_connection:exec"]; @@ -500,13 +522,14 @@ internal_error(Config) when is_list(Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), - {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), {error,"Internal error"} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user_dir, UserDir}, - {user_interaction, false}]). + {user_interaction, false}]), + ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- close(doc) -> @@ -539,3 +562,12 @@ close(Config) when is_list(Config) -> %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- + +basic_test(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon(ServerOpts), + {ok, CM} = ssh:connect(Host, Port, ClientOpts), + ok = ssh:close(CM), + ssh:stop_daemon(Pid). diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index dc69b53b28..f99dd8559e 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -37,6 +37,9 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN) # Common Macros # ---------------------------------------------------- +BEHAVIOUR_MODULES= \ + ssl_session_cache_api + MODULES= \ ssl \ ssl_alert \ @@ -53,7 +56,6 @@ MODULES= \ ssl_handshake \ ssl_manager \ ssl_session \ - ssl_session_cache_api \ ssl_session_cache \ ssl_record \ ssl_ssl2 \ @@ -66,10 +68,15 @@ INTERNAL_HRL_FILES = \ ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \ ssl_record.hrl -ERL_FILES= $(MODULES:%=%.erl) +ERL_FILES= \ + $(MODULES:%=%.erl) \ + $(BEHAVIOUR_MODULES:%=%.erl) + TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) + APP_FILE= ssl.app APPUP_FILE= ssl.appup @@ -83,6 +90,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE) # ---------------------------------------------------- EXTRA_ERLC_FLAGS = +warn_unused_vars ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \ + -pz $(EBIN) \ -pz $(ERL_TOP)/lib/public_key/ebin \ $(EXTRA_ERLC_FLAGS) -DVSN=\"$(VSN)\" @@ -91,6 +99,8 @@ ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \ # Targets # ---------------------------------------------------- +$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) + debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) clean: @@ -105,6 +115,7 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk docs: + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- @@ -114,14 +125,8 @@ release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/src $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src $(INSTALL_DIR) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) \ + $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) \ $(APPUP_TARGET) $(RELSYSDIR)/ebin release_docs_spec: - - - - - - diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 694d39ce9c..3df7495ec4 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.18.1 +STDLIB_VSN = 1.18.2 diff --git a/lib/test_server/src/configure.in b/lib/test_server/src/configure.in index 097853bcfc..77bc993ccd 100644 --- a/lib/test_server/src/configure.in +++ b/lib/test_server/src/configure.in @@ -108,7 +108,7 @@ AC_CHECK_HEADER(poll.h, AC_DEFINE(HAVE_POLL_H)) # for the system. AC_MSG_CHECKING([system version (for dynamic loading)]) -system=`uname -s`-`uname -r` +system=`./config.sub $host` AC_MSG_RESULT($system) # Step 2: check for existence of -ldl library. This is needed because @@ -119,10 +119,9 @@ AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) # Step 3: set configuration options based on system name and version. SHLIB_LDLIBS= - fullSrcDir=`cd $srcdir; pwd` case $system in - Linux*) + *-linux-*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" if test "$have_dl" = yes; then @@ -136,7 +135,7 @@ case $system in fi SHLIB_EXTRACT_ALL="" ;; - NetBSD-*|FreeBSD-*|OpenBSD-*|DragonFly*) + *-netbsd*|*-freebsd*|*-openbsd*|*-dragonfly*) # Not available on all versions: check for include file. AC_CHECK_HEADER(dlfcn.h, [ SHLIB_CFLAGS="-fpic" @@ -153,28 +152,21 @@ case $system in ]) SHLIB_EXTRACT_ALL="" ;; - SunOS-4*) - SHLIB_CFLAGS="-PIC" - SHLIB_LD="ld" - SHLIB_LDFLAGS="$LDFLAGS" - SHLIB_SUFFIX=".so" - SHLIB_EXTRACT_ALL="" - ;; - SunOS-5*|UNIX_SV-4.2*) + *-solaris2*|*-sysv4*) SHLIB_CFLAGS="-KPIC" SHLIB_LD="/usr/ccs/bin/ld" SHLIB_LDFLAGS="$LDFLAGS -G -z text" SHLIB_SUFFIX=".so" SHLIB_EXTRACT_ALL="-z allextract" ;; - Darwin*) + *darwin*) SHLIB_CFLAGS="-fno-common" SHLIB_LD="cc" SHLIB_LDFLAGS="$LDFLAGS -bundle -flat_namespace -undefined suppress" SHLIB_SUFFIX=".so" SHLIB_EXTRACT_ALL="" ;; - OSF1*) + *osf1*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld" SHLIB_LDFLAGS="$LDFLAGS -shared" @@ -206,19 +198,19 @@ esac if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then case $system in - AIX-*) + *-aix) ;; - BSD/OS*) + *-bsd*) ;; - IRIX*) + *-irix) ;; - NetBSD-*|FreeBSD-*|OpenBSD-*) + *-netbsd|*-freebsd|*-openbsd) ;; - RISCos-*) + *-riscos) ;; - ULTRIX-4.*) + *ultrix4.*) ;; - Darwin*) + *darwin*) ;; *) SHLIB_CFLAGS="-fPIC" diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl index cb06264adb..4899f38d2b 100644 --- a/lib/test_server/src/ts.erl +++ b/lib/test_server/src/ts.erl @@ -27,9 +27,10 @@ -export([run/0, run/1, run/2, run/3, run/4, clean/0, clean/1, tests/0, tests/1, - install/0, install/1, install/2, index/0, + install/0, install/1, index/0, estone/0, estone/1, cross_cover_analyse/1, + compile_testcases/0, compile_testcases/1, help/0]). -export([i/0, l/1, r/0, r/1, r/2, r/3]). @@ -88,35 +89,25 @@ -define( install_help, [ - " ts:install() - Install TS for local target with no Options.\n" - " ts:install([Options])\n", - " - Install TS for local target with Options\n" - " ts:install({Architecture, Target_name})\n", - " - Install TS for a remote target architecture.\n", - " and target network name (e.g. {vxworks_cpu32, sauron}).\n", - " ts:install({Architecture, Target_name}, [Options])\n", - " - Install TS as above, and with Options.\n", + " ts:install() - Install TS with no Options.\n" + " ts:install([Options]) - Install TS with Options\n" "\n", "Installation options supported:\n", " {longnames, true} - Use fully qualified hostnames\n", - " {hosts, [HostList]}\n" - " - Use theese hosts for distributed testing.\n" " {verbose, Level} - Sets verbosity level for TS output (0,1,2), 0 is\n" " quiet(default).\n" - " {slavetargets, SlaveTarges}\n" - " - Available hosts for starting slave nodes for\n" - " platforms which cannot have more than one erlang\n" - " node per host.\n" - " {crossroot, TargetErlRoot}\n" - " - Erlang root directory on target host\n" - " Mandatory for remote targets\n" - " {master, {MasterHost, MasterCookie}}\n" - " - Master host and cookie for targets which are\n" - " started as slave nodes.\n" - " erl_boot_server must be started on master before\n" - " test is run.\n" - " Optional, default is controller host and then\n" - " erl_boot_server is started autmatically\n" + " {crossroot, ErlTop}\n" + " - Erlang root directory on build host, ~n" + " normally same value as $ERL_TOP\n" + " {crossenv, [{Key,Val}]}\n" + " - Environmentals used by test configure on build host\n" + " {crossflags, FlagsString}\n" + " - Flags used by test configure on build host\n" + " {xcomp, XCompFile}\n" + " - The xcomp file to use for cross compiling the~n" + " testcases. Using this option will override any~n" + " cross* configurations given to ts. Note that you~n" + " have to have a correct ERL_TOP as well.~n" ]). help() -> @@ -183,26 +174,24 @@ help(installed) -> " cover_details. Analyses modules specified in\n" " cross.cover.\n" " Level can be 'overview' or 'details'.\n", + " ts:compile_testcases()~n" + " ts:compile_testcases(Apps)~n" + " - Compile all testcases for usage in a cross ~n" + " compile environment." " \n" "Installation (already done):\n" ], show_help([H,?install_help]). show_help(H) -> - io:put_chars(lists:flatten(H)). + io:format(lists:flatten(H)). %% Installs tests. install() -> ts_install:install(install_local,[]). -install({Architecture, Target_name}) -> - ts_install:install({ts_lib:maybe_atom_to_list(Architecture), - ts_lib:maybe_atom_to_list(Target_name)}, []); install(Options) when is_list(Options) -> ts_install:install(install_local,Options). -install({Architecture, Target_name}, Options) when is_list(Options)-> - ts_install:install({ts_lib:maybe_atom_to_list(Architecture), - ts_lib:maybe_atom_to_list(Target_name)}, Options). %% Updates the local index page. @@ -728,3 +717,23 @@ cover_type(cover_details) -> details. do_load(Mod) -> code:purge(Mod), code:load_file(Mod). + + +compile_testcases() -> + compile_datadirs("../*/*_data"). + +compile_testcases(App) when is_atom(App) -> + compile_testcases([App]); +compile_testcases([App | T]) -> + compile_datadirs(io_lib:format("../~s_test/*_data", [App])), + compile_testcases(T); +compile_testcases([]) -> + ok. + +compile_datadirs(DataDirs) -> + {ok,Variables} = file:consult("variables"), + + lists:foreach(fun(Dir) -> + ts_lib:make_non_erlang(Dir, Variables) + end, + filelib:wildcard(DataDirs)). diff --git a/lib/test_server/src/ts.hrl b/lib/test_server/src/ts.hrl index 885a726c54..db804d23a1 100644 --- a/lib/test_server/src/ts.hrl +++ b/lib/test_server/src/ts.hrl @@ -28,6 +28,7 @@ -define(run_summary, "suite.summary"). -define(cover_total,"total_cover.log"). -define(variables, "variables"). +-define(cross_variables, "variables-cross"). -define(LF, [10]). % Newline in VxWorks script -define(CHAR_PER_LINE, 60). % Characters per VxWorks script building line -define(CROSS_COOKIE, "cross"). % cookie used when cross platform testing diff --git a/lib/test_server/src/ts_erl_config.erl b/lib/test_server/src/ts_erl_config.erl index 5585e8ccd3..ed26156180 100644 --- a/lib/test_server/src/ts_erl_config.erl +++ b/lib/test_server/src/ts_erl_config.erl @@ -220,10 +220,6 @@ erl_interface(Vars,OsType) -> _ -> "" % VxWorks end, - CrossCompile = case OsType of - vxworks -> "true"; - _ -> "false" - end, [{erl_interface_libpath, filename:nativename(LibPath)}, {erl_interface_sock_libs, sock_libraries(OsType)}, {erl_interface_lib, Lib}, @@ -232,8 +228,8 @@ erl_interface(Vars,OsType) -> {erl_interface_eilib_drv, Lib1Drv}, {erl_interface_threadlib, ThreadLib}, {erl_interface_include, filename:nativename(Incl)}, - {erl_interface_mk_include, filename:nativename(MkIncl)}, - {erl_interface_cross_compile, CrossCompile} | Vars]. + {erl_interface_mk_include, filename:nativename(MkIncl)} + | Vars]. ic(Vars, OsType) -> {ClassPath, LibPath, Incl} = @@ -276,8 +272,6 @@ lib_dir(Vars, Lib) -> case {get_var(crossroot, Vars), LibLibDir} of {{error, _}, _} -> %no crossroot LibLibDir; - {_, {error, _}} -> %no lib - LibLibDir; {CrossRoot, _} -> %% XXX: Ugly. So ugly I won't comment it %% /Patrik @@ -299,18 +293,16 @@ lib_dir(Vars, Lib) -> end. erl_root(Vars) -> - Root = code:root_dir(), - case ts_lib:erlang_type() of + Root = case get_var(crossroot,Vars) of + {error, notfound} -> code:root_dir(); + CrossRoot -> CrossRoot + end, + case ts_lib:erlang_type(Root) of {srctree, _Version} -> Target = get_var(target, Vars), {srctree, Root, Target}; {_, _Version} -> - case get_var(crossroot,Vars) of - {error, notfound} -> - {installed, Root}; - CrossRoot -> - {installed, CrossRoot} - end + {installed, Root} end. diff --git a/lib/test_server/src/ts_install.erl b/lib/test_server/src/ts_install.erl index 9703478f20..c70a41be4b 100644 --- a/lib/test_server/src/ts_install.erl +++ b/lib/test_server/src/ts_install.erl @@ -28,12 +28,25 @@ install(install_local, Options) -> install(os:type(), Options); install(TargetSystem, Options) -> - io:format("Running configure for cross architecture, network target name~n" - "~p~n", [TargetSystem]), - case autoconf(TargetSystem) of + case file:consult(?variables) of + {ok, Vars} -> + case proplists:get_value(cross,Vars) of + "yes" when Options == []-> + target_install(Vars); + _ -> + build_install(TargetSystem, Options) + end; + _ -> + build_install(TargetSystem, Options) + end. + + +build_install(TargetSystem, Options) -> + XComp = parse_xcomp_file(proplists:get_value(xcomp,Options)), + case autoconf(TargetSystem, XComp++Options) of {ok, Vars0} -> OsType = os_type(TargetSystem), - Vars1 = ts_erl_config:variables(merge(Vars0,Options),OsType), + Vars1 = ts_erl_config:variables(Vars0++XComp++Options,OsType), {Options1, Vars2} = add_vars(Vars1, Options), Vars3 = lists:flatten([Options1|Vars2]), write_terms(?variables, Vars3); @@ -45,32 +58,43 @@ os_type({unix,_}=OsType) -> OsType; os_type({win32,_}=OsType) -> OsType; os_type(_Other) -> vxworks. -merge(Vars,[]) -> - Vars; -merge(Vars,[{crossroot,X}| Tail]) -> - merge([{crossroot, X} | Vars], Tail); -merge(Vars,[_X | Tail]) -> - merge(Vars,Tail). +target_install(CrossVars) -> + io:format("Cross installation detected, skipping configure and data_dir make~n"), + case file:rename(?variables,?cross_variables) of + ok -> + ok; + _ -> + io:format("Could not find variables file from cross make~n"), + throw(cross_installation_failed) + end, + CPU = proplists:get_value('CPU',CrossVars), + OS = proplists:get_value(os,CrossVars), + {Options,Vars} = add_vars([{cross,"yes"},{'CPU',CPU},{os,OS}],[]), + Variables = lists:flatten([Options|Vars]), + write_terms(?variables, Variables). %% Autoconf for various platforms. %% unix uses the configure script %% win32 uses ts_autoconf_win32 %% VxWorks uses ts_autoconf_vxworks. -autoconf(TargetSystem) -> - case autoconf1(TargetSystem) of +autoconf(TargetSystem, XComp) -> + case autoconf1(TargetSystem, XComp) of ok -> autoconf2(file:read_file("conf_vars")); Error -> Error end. -autoconf1({win32, _}) -> +autoconf1({win32, _},[{cross,"no"}]) -> ts_autoconf_win32:configure(); -autoconf1({unix, _}) -> - unix_autoconf(); -autoconf1(Other) -> - ts_autoconf_vxworks:configure(Other). +autoconf1({unix, _},XCompFile) -> + unix_autoconf(XCompFile); +autoconf1(Other,[{cross,"no"}]) -> + ts_autoconf_vxworks:configure(Other); +autoconf1(_,_) -> + io:format("cross compilation not supported for that this platform~n"), + throw(cross_installation_failed). autoconf2({ok, Bin}) -> get_vars(binary_to_list(Bin), name, [], []); @@ -92,27 +116,40 @@ get_vars([], name, [], Result) -> get_vars(_, _, _, _) -> {error, fatal_bad_conf_vars}. -unix_autoconf() -> +unix_autoconf(XConf) -> Configure = filename:absname("configure"), - Args = case catch erlang:system_info(threads) of - false -> ""; - _ -> " --enable-shlib-thread-safety" - end - ++ case catch string:str(erlang:system_info(system_version), - "debug") > 0 of - false -> ""; - _ -> " --enable-debug-mode" - end, + Flags = proplists:get_value(crossflags,XConf,[]), + Env = proplists:get_value(crossenv,XConf,[]), + Host = get_xcomp_flag("host", Flags), + Build = get_xcomp_flag("build", Flags), + Threads = [" --enable-shlib-thread-safety" || + erlang:system_info(threads) /= false], + Debug = [" --enable-debug-mode" || + string:str(erlang:system_info(system_version),"debug") > 0], + Args = Host ++ Build ++ Threads ++ Debug, case filelib:is_file(Configure) of true -> - Env = macosx_cflags(), - Port = open_port({spawn, Configure ++ Args}, - [stream, eof, {env,Env}]), + OSXEnv = macosx_cflags(), + io:format("Running ~sEnv: ~p~n", + [lists:flatten(Configure ++ Args),Env++OSXEnv]), + Port = open_port({spawn, lists:flatten(Configure ++ Args)}, + [stream, eof, {env,Env++OSXEnv}]), ts_lib:print_data(Port); false -> {error, no_configure_script} end. + +get_xcomp_flag(Flag, Flags) -> + get_xcomp_flag(Flag, Flag, Flags). +get_xcomp_flag(Flag, Tag, Flags) -> + case proplists:get_value(Flag,Flags) of + undefined -> ""; + "guess" -> [" --",Tag,"=",os:cmd("$ERL_TOP/erts/autoconf/config.guess")]; + HostVal -> [" --",Tag,"=",HostVal] + end. + + macosx_cflags() -> case os:type() of {unix, darwin} -> @@ -125,10 +162,33 @@ macosx_cflags() -> [] end. +parse_xcomp_file(undefined) -> + [{cross,"no"}]; +parse_xcomp_file(Filepath) -> + {ok,Bin} = file:read_file(Filepath), + Lines = binary:split(Bin,<<"\n">>,[global,trim]), + {Envs,Flags} = parse_xcomp_file(Lines,[],[]), + [{cross,"yes"},{crossroot,os:getenv("ERL_TOP")}, + {crossenv,Envs},{crossflags,Flags}]. + +parse_xcomp_file([<<A:8,_/binary>> = Line|R],Envs,Flags) + when $A =< A, A =< $Z -> + [Var,Value] = binary:split(Line,<<"=">>), + parse_xcomp_file(R,[{binary_to_list(Var), + binary_to_list(Value)}|Envs],Flags); +parse_xcomp_file([<<"erl_xcomp_",Line/binary>>|R],Envs,Flags) -> + [Var,Value] = binary:split(Line,<<"=">>), + parse_xcomp_file(R,Envs,[{binary_to_list(Var), + binary_to_list(Value)}|Flags]); +parse_xcomp_file([_|R],Envs,Flags) -> + parse_xcomp_file(R,Envs,Flags); +parse_xcomp_file([],Envs,Flags) -> + {lists:reverse(Envs),lists:reverse(Flags)}. + write_terms(Name, Terms) -> case file:open(Name, [write]) of {ok, Fd} -> - Result = write_terms1(Fd, Terms), + Result = write_terms1(Fd, remove_duplicates(Terms)), file:close(Fd), Result; {error, Reason} -> @@ -141,6 +201,17 @@ write_terms1(Fd, [Term|Rest]) -> write_terms1(_, []) -> ok. +remove_duplicates(List) -> + lists:reverse( + lists:foldl(fun({Key,Val},Acc) -> + R = make_ref(), + case proplists:get_value(Key,Acc,R) of + R -> [{Key,Val}|Acc]; + _Else -> + Acc + end + end,[],List)). + add_vars(Vars0, Opts0) -> {Opts,LongNames} = case lists:keymember(longnames, 1, Opts0) of diff --git a/lib/test_server/src/ts_install_cth.erl b/lib/test_server/src/ts_install_cth.erl index a41916fd0a..67f2df0cae 100644 --- a/lib/test_server/src/ts_install_cth.erl +++ b/lib/test_server/src/ts_install_cth.erl @@ -95,17 +95,12 @@ pre_init_per_suite(_Suite,Config,State) -> try {ok,Variables} = file:consult(filename:join(State#state.ts_conf_dir,"variables")), - - %% Make the stuff in all_SUITE_data if it exists - AllDir = filename:join(DataDir,"../all_SUITE_data"), - case filelib:is_dir(AllDir) of - true -> - make_non_erlang(AllDir,Variables); - false -> - ok + case proplists:get_value(cross,Variables) of + "yes" -> + ct:log("Not making data dir as tests have been cross compiled"); + _ -> + ts_lib:make_non_erlang(DataDir, Variables) end, - - make_non_erlang(DataDir, Variables), {add_node_name(Config, State), State} catch Error:Reason -> @@ -219,39 +214,6 @@ terminate(_State) -> %%% ============================================================================ %%% Local functions %%% ============================================================================ -%% Configure and run all the Makefiles in the data dirs of the suite -%% in question -make_non_erlang(DataDir, Variables) -> - {ok,CurrWD} = file:get_cwd(), - try - file:set_cwd(DataDir), - MakeCommand = proplists:get_value(make_command,Variables), - - FirstMakefile = filename:join(DataDir,"Makefile.first"), - case filelib:is_regular(FirstMakefile) of - true -> - ct:log("Making ~p",[FirstMakefile]), - ok = ts_make:make( - MakeCommand, DataDir, filename:basename(FirstMakefile)); - false -> - ok - end, - - MakefileSrc = filename:join(DataDir,"Makefile.src"), - MakefileDest = filename:join(DataDir,"Makefile"), - case filelib:is_regular(MakefileSrc) of - true -> - ok = ts_lib:subst_file(MakefileSrc,MakefileDest,Variables), - ct:log("Making ~p",[MakefileDest]), - ok = ts_make:make([{makefile,"Makefile"},{data_dir,DataDir} - | Variables]); - false -> - ok - end - after - file:set_cwd(CurrWD), - timer:sleep(100) - end. %% Add a nodename to config if it does not exist add_node_name(Config, State) -> diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl index 2f0a4ea8c0..d521d2beda 100644 --- a/lib/test_server/src/ts_lib.erl +++ b/lib/test_server/src/ts_lib.erl @@ -24,10 +24,12 @@ %% Avoid warning for local function error/1 clashing with autoimported BIF. -compile({no_auto_import,[error/1]}). -export([error/1, var/2, erlang_type/0, + erlang_type/1, initial_capital/1, interesting_logs/1, specs/1, suites/2, last_test/1, force_write_file/2, force_delete/1, subst_file/3, subst/2, print_data/1, + make_non_erlang/2, maybe_atom_to_list/1, progress/4 ]). @@ -73,8 +75,10 @@ progress(Vars, Level, Format, Args) -> %% Returns: {Type, Version} where Type is otp|src erlang_type() -> + erlang_type(code:root_dir()). +erlang_type(RootDir) -> {_, Version} = init:script_id(), - RelDir = filename:join(code:root_dir(), "releases"), % Only in installed + RelDir = filename:join(RootDir, "releases"), % Only in installed case filelib:is_file(RelDir) of true -> {otp,Version}; % installed OTP false -> {srctree,Version} % source code tree @@ -333,3 +337,45 @@ maybe_atom_to_list(To_list) when is_list(To_list) -> maybe_atom_to_list(To_list) when is_atom(To_list)-> atom_to_list(To_list). + +%% Configure and run all the Makefiles in the data dir of the suite +%% in question +make_non_erlang(DataDir, Variables) -> + %% Make the stuff in all_SUITE_data if it exists + AllDir = filename:join(DataDir,"../all_SUITE_data"), + case filelib:is_dir(AllDir) of + true -> + make_non_erlang_do(AllDir,Variables); + false -> + ok + end, + make_non_erlang_do(DataDir, Variables). + +make_non_erlang_do(DataDir, Variables) -> + try + MakeCommand = proplists:get_value(make_command,Variables), + + FirstMakefile = filename:join(DataDir,"Makefile.first"), + case filelib:is_regular(FirstMakefile) of + true -> + io:format("Making ~p",[FirstMakefile]), + ok = ts_make:make( + MakeCommand, DataDir, filename:basename(FirstMakefile)); + false -> + ok + end, + + MakefileSrc = filename:join(DataDir,"Makefile.src"), + MakefileDest = filename:join(DataDir,"Makefile"), + case filelib:is_regular(MakefileSrc) of + true -> + ok = ts_lib:subst_file(MakefileSrc,MakefileDest,Variables), + io:format("Making ~p",[MakefileDest]), + ok = ts_make:make([{makefile,"Makefile"},{data_dir,DataDir} + | Variables]); + false -> + ok + end + after + timer:sleep(100) %% maybe unnecessary now when we don't do set_cwd anymore + end. diff --git a/lib/test_server/src/ts_make.erl b/lib/test_server/src/ts_make.erl index 3df66111a3..f0db60013a 100644 --- a/lib/test_server/src/ts_make.erl +++ b/lib/test_server/src/ts_make.erl @@ -25,12 +25,12 @@ %% Functions to be called from make test cases. make(Config) when is_list(Config) -> - DataDir = ?config(data_dir, Config), - Makefile = ?config(makefile, Config), - Make = ?config(make_command, Config), + DataDir = proplists:get_value(data_dir, Config), + Makefile = proplists:get_value(makefile, Config), + Make = proplists:get_value(make_command, Config), case make(Make, DataDir, Makefile) of ok -> ok; - {error,Reason} -> ?t:fail({make_failed,Reason}) + {error,Reason} -> exit({make_failed,Reason}) end. unmake(Config) when is_list(Config) -> diff --git a/lib/wx/configure.in b/lib/wx/configure.in index b27e114a3d..8e5f696bc7 100755 --- a/lib/wx/configure.in +++ b/lib/wx/configure.in @@ -571,7 +571,7 @@ if test X"$WX_HAVE_STATIC_LIBS" = X"true" ; then LIBS=$WX_LIBS_STATIC fi -AC_LINK_IFELSE([ +AC_LINK_IFELSE([AC_LANG_SOURCE([ #ifdef WIN32 # include <windows.h> # include <gl/gl.h> @@ -583,6 +583,7 @@ AC_LINK_IFELSE([ #include "wx/wx.h" #include "wx/stc/stc.h" #include "wx/glcanvas.h" + ]) class MyApp : public wxApp { diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml index 585d8bb688..bd12e688d0 100644 --- a/lib/xmerl/doc/src/notes.xml +++ b/lib/xmerl/doc/src/notes.xml @@ -31,6 +31,21 @@ <p>This document describes the changes made to the Xmerl application.</p> +<section><title>Xmerl 1.3.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Fix a continuation bug when a new block of bytes is + to be read during parsing of a default declaration. </p> + <p> + Own Id: OTP-10063 Aux Id: seq12049 </p> + </item> + </list> + </section> + +</section> + <section><title>Xmerl 1.3.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc index df0970ef14..d38045f2a5 100644 --- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc @@ -155,16 +155,16 @@ parse_xml_decl(?BYTE_ORDER_MARK_2, State) -> cf(?BYTE_ORDER_MARK_2, State, fun parse_xml_decl/2); parse_xml_decl(?BYTE_ORDER_MARK_REST(Rest), State) -> cf(Rest, State, fun parse_xml_decl/2); -parse_xml_decl(?STRING("<"), State) -> - cf(?STRING("<"), State, fun parse_xml_decl/2); -parse_xml_decl(?STRING("<?"), State) -> - cf(?STRING("<?"), State, fun parse_xml_decl/2); -parse_xml_decl(?STRING("<?x"), State) -> - cf(?STRING("<?x"), State, fun parse_xml_decl/2); -parse_xml_decl(?STRING("<?xm"), State) -> - cf(?STRING("<?xm"), State, fun parse_xml_decl/2); -parse_xml_decl(?STRING("<?xml"), State) -> - cf(?STRING("<?xml"), State, fun parse_xml_decl/2); +parse_xml_decl(?STRING("<") = Bytes, State) -> + cf(Bytes, State, fun parse_xml_decl/2); +parse_xml_decl(?STRING("<?") = Bytes, State) -> + cf(Bytes, State, fun parse_xml_decl/2); +parse_xml_decl(?STRING("<?x") = Bytes, State) -> + cf(Bytes, State, fun parse_xml_decl/2); +parse_xml_decl(?STRING("<?xm") = Bytes, State) -> + cf(Bytes, State, fun parse_xml_decl/2); +parse_xml_decl(?STRING("<?xml") = Bytes, State) -> + cf(Bytes, State, fun parse_xml_decl/2); parse_xml_decl(?STRING_REST("<?xml", Rest1), State) -> parse_xml_decl_1(Rest1, State); parse_xml_decl(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State) when is_binary(Bytes) -> @@ -204,8 +204,8 @@ parse_xml_decl_1(Bytes, State) -> %%---------------------------------------------------------------------- parse_prolog(?STRING_EMPTY, State) -> cf(?STRING_EMPTY, State, fun parse_prolog/2); -parse_prolog(?STRING("<"), State) -> - cf(?STRING("<"), State, fun parse_prolog/2); +parse_prolog(?STRING("<") = Bytes, State) -> + cf(Bytes, State, fun parse_prolog/2); parse_prolog(?STRING_REST("<?", Rest), State) -> {Rest1, State1} = parse_pi(Rest, State), parse_prolog(Rest1, State1); @@ -223,18 +223,18 @@ parse_prolog(Bytes, State) -> parse_prolog_1(?STRING_EMPTY, State) -> cf(?STRING_EMPTY, State, fun parse_prolog_1/2); -parse_prolog_1(?STRING("D"), State) -> - cf(?STRING("D"), State, fun parse_prolog_1/2); -parse_prolog_1(?STRING("DO"), State) -> - cf(?STRING("DO"), State, fun parse_prolog_1/2); -parse_prolog_1(?STRING("DOC"), State) -> - cf(?STRING("DOC"), State, fun parse_prolog_1/2); -parse_prolog_1(?STRING("DOCT"), State) -> - cf(?STRING("DOCT"), State, fun parse_prolog_1/2); -parse_prolog_1(?STRING("DOCTY"), State) -> - cf(?STRING("DOCTY"), State, fun parse_prolog_1/2); -parse_prolog_1(?STRING("DOCTYP"), State) -> - cf(?STRING("DOCTYP"), State, fun parse_prolog_1/2); +parse_prolog_1(?STRING("D") = Bytes, State) -> + cf(Bytes, State, fun parse_prolog_1/2); +parse_prolog_1(?STRING("DO") = Bytes, State) -> + cf(Bytes, State, fun parse_prolog_1/2); +parse_prolog_1(?STRING("DOC") = Bytes, State) -> + cf(Bytes, State, fun parse_prolog_1/2); +parse_prolog_1(?STRING("DOCT") = Bytes, State) -> + cf(Bytes, State, fun parse_prolog_1/2); +parse_prolog_1(?STRING("DOCTY") = Bytes, State) -> + cf(Bytes, State, fun parse_prolog_1/2); +parse_prolog_1(?STRING("DOCTYP") = Bytes, State) -> + cf(Bytes, State, fun parse_prolog_1/2); parse_prolog_1(?STRING_REST("DOCTYPE", Rest), State) -> {Rest1, State1} = parse_doctype(Rest, State), State2 = event_callback(endDTD, State1), @@ -512,10 +512,10 @@ parse_ns_name(Bytes, State, Prefix, Name) -> %%---------------------------------------------------------------------- parse_pi_data(?STRING_EMPTY, State, Acc) -> cf(?STRING_EMPTY, State, Acc, fun parse_pi_data/3); -parse_pi_data(?STRING("?"), State, Acc) -> - cf(?STRING("?"), State, Acc, fun parse_pi_data/3); -parse_pi_data(?STRING("\r"), State, Acc) -> - cf(?STRING("\r"), State, Acc, fun parse_pi_data/3); +parse_pi_data(?STRING("?") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_pi_data/3); +parse_pi_data(?STRING("\r") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_pi_data/3); parse_pi_data(?STRING_REST("?>", Rest), State, Acc) -> {lists:reverse(Acc), Rest, State}; parse_pi_data(?STRING_REST("\n", Rest), #xmerl_sax_parser_state{line_no=N} = State, Acc) -> @@ -544,23 +544,23 @@ parse_pi_data(Bytes, State, Acc) -> %%---------------------------------------------------------------------- parse_cdata(?STRING_EMPTY, State) -> cf(?STRING_EMPTY, State, fun parse_cdata/2); -parse_cdata(?STRING("["), State) -> - cf(?STRING("["), State, fun parse_cdata/2); -parse_cdata(?STRING("[C"), State) -> - cf(?STRING("[C"), State, fun parse_cdata/2); -parse_cdata(?STRING("[CD"), State) -> - cf(?STRING("[CD"), State, fun parse_cdata/2); -parse_cdata(?STRING("[CDA"), State) -> - cf(?STRING("[CDA"), State, fun parse_cdata/2); -parse_cdata(?STRING("[CDAT"), State) -> - cf(?STRING("[CDAT"), State, fun parse_cdata/2); -parse_cdata(?STRING("[CDATA"), State) -> - cf(?STRING("[CDATA"), State, fun parse_cdata/2); -parse_cdata(?STRING_REST("[CDATA[", Rest), State) -> - State1 = event_callback(startCDATA, State), +parse_cdata(?STRING("[") = Bytes, State) -> + cf(Bytes, State, fun parse_cdata/2); +parse_cdata(?STRING("[C") = Bytes, State) -> + cf(Bytes, State, fun parse_cdata/2); +parse_cdata(?STRING("[CD") = Bytes, State) -> + cf(Bytes, State, fun parse_cdata/2); +parse_cdata(?STRING("[CDA") = Bytes, State) -> + cf(Bytes, State, fun parse_cdata/2); +parse_cdata(?STRING("[CDAT") = Bytes, State) -> + cf(Bytes, State, fun parse_cdata/2); +parse_cdata(?STRING("[CDATA") = Bytes, State) -> + cf(Bytes, State, fun parse_cdata/2); +parse_cdata(?STRING_REST("[CDATA[", Rest), State) -> + State1 = event_callback(startCDATA, State), parse_cdata(Rest, State1, []); -parse_cdata(Bytes, State) -> - unicode_incomplete_check([Bytes, State, fun parse_cdata/2], +parse_cdata(Bytes, State) -> + unicode_incomplete_check([Bytes, State, fun parse_cdata/2], "expecting comment or CDATA"). @@ -574,12 +574,12 @@ parse_cdata(Bytes, State) -> %%---------------------------------------------------------------------- parse_cdata(?STRING_EMPTY, State, Acc) -> cf(?STRING_EMPTY, State, Acc, fun parse_cdata/3); -parse_cdata(?STRING("\r"), State, Acc) -> - cf(?STRING("\r"), State, Acc, fun parse_cdata/3); -parse_cdata(?STRING("]"), State, Acc) -> - cf(?STRING("]"), State, Acc, fun parse_cdata/3); -parse_cdata(?STRING("]]"), State, Acc) -> - cf(?STRING("]]"), State, Acc, fun parse_cdata/3); +parse_cdata(?STRING("\r") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_cdata/3); +parse_cdata(?STRING("]") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_cdata/3); +parse_cdata(?STRING("]]") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_cdata/3); parse_cdata(?STRING_REST("]]>", Rest), State, Acc) -> State1 = event_callback({characters, lists:reverse(Acc)}, State), State2 = event_callback(endCDATA, State1), @@ -610,12 +610,12 @@ parse_cdata(Bytes, State, Acc) -> %%---------------------------------------------------------------------- parse_comment(?STRING_EMPTY, State, Acc) -> cf(?STRING_EMPTY, State, Acc, fun parse_comment/3); -parse_comment(?STRING("\r"), State, Acc) -> - cf(?STRING("\r"), State, Acc, fun parse_comment/3); -parse_comment(?STRING("-"), State, Acc) -> - cf(?STRING("-"), State, Acc, fun parse_comment/3); -parse_comment(?STRING("--"), State, Acc) -> - cf(?STRING("--"), State, Acc, fun parse_comment/3); +parse_comment(?STRING("\r") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_comment/3); +parse_comment(?STRING("-") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_comment/3); +parse_comment(?STRING("--") = Bytes, State, Acc) -> + cf(Bytes, State, Acc, fun parse_comment/3); parse_comment(?STRING_REST("-->", Rest), State, Acc) -> State1 = event_callback({comment, lists:reverse(Acc)}, State), {Rest, State1}; @@ -713,8 +713,8 @@ parse_stag(Bytes, State) -> %%---------------------------------------------------------------------- parse_attributes(?STRING_EMPTY, State, CurrentTag) -> cf(?STRING_EMPTY, State, CurrentTag, fun parse_attributes/3); -parse_attributes(?STRING("/"), State, CurrentTag) -> - cf(?STRING("/"), State, CurrentTag, fun parse_attributes/3); +parse_attributes(?STRING("/") = Bytes, State, CurrentTag) -> + cf(Bytes, State, CurrentTag, fun parse_attributes/3); parse_attributes(?STRING_REST("/>", Rest), State, {Tag, AttList, NewNsList}) -> CompleteNsList = NewNsList ++ State#xmerl_sax_parser_state.ns, {Uri, LocalName, QName, Attributes} = fix_ns(Tag, AttList, CompleteNsList), @@ -911,20 +911,20 @@ parse_att_value(?STRING_EMPTY, State, undefined, Acc) -> {Acc, [], State}; %% stop clause when parsing references parse_att_value(?STRING_EMPTY, State, Stop, Acc) -> cf(?STRING_EMPTY, State, Stop, Acc, fun parse_att_value/4); -parse_att_value(?STRING("\r"), State, Stop, Acc) -> - cf(?STRING("\r"), State, Stop, Acc, fun parse_att_value/4); +parse_att_value(?STRING("\r") = Bytes, State, Stop, Acc) -> + cf(Bytes, State, Stop, Acc, fun parse_att_value/4); parse_att_value(?STRING_REST("\n", Rest), #xmerl_sax_parser_state{line_no=N} = State, Stop, Acc) -> parse_att_value(Rest, - State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); + State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); parse_att_value(?STRING_REST("\r\n", Rest), #xmerl_sax_parser_state{line_no=N} = State, Stop, Acc) -> parse_att_value(Rest, - State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); + State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); parse_att_value(?STRING_REST("\r", Rest), #xmerl_sax_parser_state{line_no=N} = State, Stop, Acc) -> parse_att_value(Rest, - State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); + State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); parse_att_value(?STRING_REST("\t", Rest), #xmerl_sax_parser_state{line_no=N} = State, Stop, Acc) -> parse_att_value(Rest, - State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); + State#xmerl_sax_parser_state{line_no=N+1}, Stop, [?space |Acc]); parse_att_value(?STRING_REST("&", Rest), State, Stop, Acc) -> {Ref, Rest1, State1} = parse_reference(Rest, State, true), case Ref of @@ -1046,17 +1046,17 @@ parse_content(?STRING_EMPTY, State, Acc, IgnorableWS) -> Other -> throw(Other) end; -parse_content(?STRING("\r"), State, Acc, IgnorableWS) -> - cf(?STRING("\r"), State, Acc, IgnorableWS, fun parse_content/4); -parse_content(?STRING("<"), State, Acc, IgnorableWS) -> - cf(?STRING("<"), State, Acc, IgnorableWS, fun parse_content/4); +parse_content(?STRING("\r") = Bytes, State, Acc, IgnorableWS) -> + cf(Bytes, State, Acc, IgnorableWS, fun parse_content/4); +parse_content(?STRING("<") = Bytes, State, Acc, IgnorableWS) -> + cf(Bytes, State, Acc, IgnorableWS, fun parse_content/4); parse_content(?STRING_REST("</", Rest), State, Acc, IgnorableWS) -> State1 = send_character_event(length(Acc), IgnorableWS, lists:reverse(Acc), State), parse_etag(Rest, State1); -parse_content(?STRING("<!"), State, _Acc, IgnorableWS) -> - cf(?STRING("<!"), State, [], IgnorableWS, fun parse_content/4); -parse_content(?STRING("<!-"), State, _Acc, IgnorableWS) -> - cf(?STRING("<!-"), State, [], IgnorableWS, fun parse_content/4); +parse_content(?STRING("<!") = Bytes, State, _Acc, IgnorableWS) -> + cf(Bytes, State, [], IgnorableWS, fun parse_content/4); +parse_content(?STRING("<!-") = Bytes, State, _Acc, IgnorableWS) -> + cf(Bytes, State, [], IgnorableWS, fun parse_content/4); parse_content(?STRING_REST("<!--", Rest), State, Acc, IgnorableWS) -> State1 = send_character_event(length(Acc), IgnorableWS, lists:reverse(Acc), State), {Rest1, State2} = parse_comment(Rest, State1, []), @@ -1227,8 +1227,8 @@ whitespace(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State, Acc) when is_bi %%---------------------------------------------------------------------- parse_reference(?STRING_EMPTY, State, HaveToExist) -> cf(?STRING_EMPTY, State, HaveToExist, fun parse_reference/3); -parse_reference(?STRING("#"), State, HaveToExist) -> - cf(?STRING("#"), State, HaveToExist, fun parse_reference/3); +parse_reference(?STRING("#") = Bytes, State, HaveToExist) -> + cf(Bytes, State, HaveToExist, fun parse_reference/3); parse_reference(?STRING_REST("#x", Rest), State, _HaveToExist) -> {CharValue, RefString, Rest1, State1} = parse_hex(Rest, State, []), if @@ -1702,16 +1702,16 @@ parse_external_entity_1(?BYTE_ORDER_MARK_2, State) -> cf(?BYTE_ORDER_MARK_2, State, fun parse_external_entity_1/2); parse_external_entity_1(?BYTE_ORDER_MARK_REST(Rest), State) -> parse_external_entity_1(Rest, State); -parse_external_entity_1(?STRING("<"), State) -> - cf(?STRING("<"), State, fun parse_external_entity_1/2); -parse_external_entity_1(?STRING("<?"), State) -> - cf(?STRING("<?"), State, fun parse_external_entity_1/2); -parse_external_entity_1(?STRING("<?x"), State) -> - cf(?STRING("<?x"), State, fun parse_external_entity_1/2); -parse_external_entity_1(?STRING("<?xm"), State) -> - cf(?STRING("<?xm"), State, fun parse_external_entity_1/2); -parse_external_entity_1(?STRING("<?xml"), State) -> - cf(?STRING("<?xml"), State, fun parse_external_entity_1/2); +parse_external_entity_1(?STRING("<") = Bytes, State) -> + cf(Bytes, State, fun parse_external_entity_1/2); +parse_external_entity_1(?STRING("<?") = Bytes, State) -> + cf(Bytes, State, fun parse_external_entity_1/2); +parse_external_entity_1(?STRING("<?x") = Bytes, State) -> + cf(Bytes, State, fun parse_external_entity_1/2); +parse_external_entity_1(?STRING("<?xm") = Bytes, State) -> + cf(Bytes, State, fun parse_external_entity_1/2); +parse_external_entity_1(?STRING("<?xml") = Bytes, State) -> + cf(Bytes, State, fun parse_external_entity_1/2); parse_external_entity_1(?STRING_REST("<?xml", Rest) = Bytes, #xmerl_sax_parser_state{file_type=Type} = State) -> {Rest1, State1} = @@ -1781,29 +1781,29 @@ is_next_char_whitespace(Bytes, State) -> %%---------------------------------------------------------------------- parse_external_id(?STRING_EMPTY, State, OptionalSystemId) -> cf(?STRING_EMPTY, State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("S"), State,OptionalSystemId) -> - cf(?STRING("S"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("SY"), State, OptionalSystemId) -> - cf(?STRING("SY"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("SYS"), State, OptionalSystemId) -> - cf(?STRING("SYS"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("SYST"), State, OptionalSystemId) -> - cf(?STRING("SYST"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("SYSTE"), State, OptionalSystemId) -> - cf(?STRING("SYSTE"), State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("S") = Bytes, State,OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("SY") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("SYS") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("SYST") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("SYSTE") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); parse_external_id(?STRING_REST("SYSTEM", Rest), State, _) -> {SysId, Rest1, State1} = parse_system_id(Rest, State, false), {"", SysId, Rest1, State1}; -parse_external_id(?STRING("P"), State, OptionalSystemId) -> - cf(?STRING("P"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("PU"), State, OptionalSystemId) -> - cf(?STRING("PU"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("PUB"), State, OptionalSystemId) -> - cf(?STRING("PUB"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("PUBL"), State, OptionalSystemId) -> - cf(?STRING("PUBL"), State, OptionalSystemId, fun parse_external_id/3); -parse_external_id(?STRING("PUBLI"), State, OptionalSystemId) -> - cf(?STRING("PUBLI"), State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("P") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("PU") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("PUB") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("PUBL") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); +parse_external_id(?STRING("PUBLI") = Bytes, State, OptionalSystemId) -> + cf(Bytes, State, OptionalSystemId, fun parse_external_id/3); parse_external_id(?STRING_REST("PUBLIC", Rest), State, OptionalSystemId) -> parse_public_id(Rest, State, OptionalSystemId); parse_external_id(Bytes, State, OptionalSystemId) -> @@ -1923,70 +1923,70 @@ parse_doctype_decl(Bytes, State) -> parse_doctype_decl_1(?STRING_EMPTY, State) -> cf(?STRING_EMPTY, State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("E"), State) -> - cf(?STRING("E"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("EL"), State) -> - cf(?STRING("EL"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ELE"), State) -> - cf(?STRING("ELE"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ELEM"), State) -> - cf(?STRING("ELEM"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ELEME"), State) -> - cf(?STRING("ELEME"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ELEMEN"), State) -> - cf(?STRING("ELEMEN"), State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("E") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("EL") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ELE") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ELEM") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ELEME") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ELEMEN") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); parse_doctype_decl_1(?STRING_REST("ELEMENT", Rest), State) -> {Rest1, State1} = parse_element_decl(Rest, State), parse_doctype_decl(Rest1, State1); -parse_doctype_decl_1(?STRING("A"), State) -> - cf(?STRING("A"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("AT"), State) -> - cf(?STRING("AT"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ATT"), State) -> - cf(?STRING("ATT"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ATTL"), State) -> - cf(?STRING("ATTL"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ATTLI"), State) -> - cf(?STRING("ATTLI"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ATTLIS"), State) -> - cf(?STRING("ATTLIS"), State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("A") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("AT") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ATT") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ATTL") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ATTLI") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ATTLIS") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); parse_doctype_decl_1(?STRING_REST("ATTLIST", Rest), State) -> {Rest1, State1} = parse_att_list_decl(Rest, State), parse_doctype_decl(Rest1, State1); %% E clause not needed here because already taken care of above. -parse_doctype_decl_1(?STRING("EN"), State) -> - cf(?STRING("EN"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ENT"), State) -> - cf(?STRING("ENT"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ENTI"), State) -> - cf(?STRING("ENTI"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("ENTIT"), State) -> - cf(?STRING("ENTIT"), State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("EN") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ENT") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ENTI") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("ENTIT") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); parse_doctype_decl_1(?STRING_REST("ENTITY", Rest), State) -> {Rest1, State1} = parse_entity_decl(Rest, State), parse_doctype_decl(Rest1, State1); -parse_doctype_decl_1(?STRING("N"), State) -> - cf(?STRING("N"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("NO"), State) -> - cf(?STRING("NO"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("NOT"), State) -> - cf(?STRING("NOT"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("NOTA"), State) -> - cf(?STRING("NOTA"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("NOTAT"), State) -> - cf(?STRING("NOTAT"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("NOTATI"), State) -> - cf(?STRING("NOTATI"), State, fun parse_doctype_decl_1/2); -parse_doctype_decl_1(?STRING("NOTATIO"), State) -> - cf(?STRING("NOTATIO"), State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("N") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("NO") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("NOT") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("NOTA") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("NOTAT") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("NOTATI") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("NOTATIO") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); parse_doctype_decl_1(?STRING_REST("NOTATION", Rest), State) -> {Rest1, State1} = parse_notation_decl(Rest, State), parse_doctype_decl(Rest1, State1); -parse_doctype_decl_1(?STRING("-"), State) -> - cf(?STRING("-"), State, fun parse_doctype_decl_1/2); +parse_doctype_decl_1(?STRING("-") = Bytes, State) -> + cf(Bytes, State, fun parse_doctype_decl_1/2); parse_doctype_decl_1(?STRING_REST("--", Rest), State) -> {Rest1, State1} = parse_comment(Rest, State, []), parse_doctype_decl(Rest1, State1); @@ -2264,52 +2264,52 @@ parse_default_decl(Bytes, State) -> %%---------------------------------------------------------------------- parse_default_decl_1(?STRING_EMPTY, State) -> cf(?STRING_EMPTY, State, fun parse_default_decl_1/2); -parse_default_decl_1(?STRING_REST("#", Rest), State) -> - case Rest of - ?STRING("R") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("RE") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("REQ") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("REQU") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("REQUI") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("REQUIR") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("REQUIRE") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING_REST("REQUIRED", Rest1) -> +parse_default_decl_1(?STRING_REST("#", _Rest) = Bytes, State) -> + case Bytes of + ?STRING("#R") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#RE") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#REQ") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#REQU") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#REQUI") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#REQUIR") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#REQUIRE") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING_REST("#REQUIRED", Rest1) -> {"#REQUIRED", undefined, Rest1, State}; - ?STRING("I") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("IM") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("IMP") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("IMPL") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("IMPLI") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("IMPLIE") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING_REST("IMPLIED", Rest1) -> + ?STRING("#I") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#IM") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#IMP") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#IMPL") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#IMPLI") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#IMPLIE") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING_REST("#IMPLIED", Rest1) -> {"#IMPLIED", undefined, Rest1, State}; - ?STRING("F") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("FI") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("FIX") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING("FIXE") -> - cf(Rest, State, fun parse_default_decl_1/2); - ?STRING_REST("FIXED", Rest1) -> + ?STRING("#F") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#FI") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#FIX") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING("#FIXE") -> + cf(Bytes, State, fun parse_default_decl_1/2); + ?STRING_REST("#FIXED", Rest1) -> parse_fixed(Rest1, State); _ -> - ?fatal_error(State, "REQUIRED, IMPLIED or FIXED expected") + ?fatal_error(State, "REQUIRED, IMPLIED or FIXED expected after #") end; parse_default_decl_1(?STRING_UNBOUND_REST(C, Rest), State) when C == $'; C == $" -> {DefaultValue, Rest1, State1} = parse_att_value(Rest, State, C, []), @@ -2560,14 +2560,14 @@ parse_ndata_decl(?STRING_EMPTY, State) -> cf(?STRING_EMPTY, State, fun parse_ndata_decl/2); parse_ndata_decl(?STRING_REST(">", Rest), State) -> {undefined, Rest, State}; -parse_ndata_decl(?STRING("N") = Rest, State) -> - cf(Rest, State, fun parse_ndata_decl/2); -parse_ndata_decl(?STRING("ND") = Rest, State) -> - cf(Rest, State, fun parse_ndata_decl/2); -parse_ndata_decl(?STRING("NDA") = Rest, State) -> - cf(Rest, State, fun parse_ndata_decl/2); -parse_ndata_decl(?STRING("NDAT") = Rest, State) -> - cf(Rest, State, fun parse_ndata_decl/2); +parse_ndata_decl(?STRING("N") = Bytes, State) -> + cf(Bytes, State, fun parse_ndata_decl/2); +parse_ndata_decl(?STRING("ND") = Bytes, State) -> + cf(Bytes, State, fun parse_ndata_decl/2); +parse_ndata_decl(?STRING("NDA") = Bytes, State) -> + cf(Bytes, State, fun parse_ndata_decl/2); +parse_ndata_decl(?STRING("NDAT") = Bytes, State) -> + cf(Bytes, State, fun parse_ndata_decl/2); parse_ndata_decl(?STRING_REST("NDATA", Rest), State) -> parse_ndata_decl_1(Rest, State); parse_ndata_decl(Bytes, State) -> diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk index 399e5b3602..599bc0b9d3 100644 --- a/lib/xmerl/vsn.mk +++ b/lib/xmerl/vsn.mk @@ -1 +1 @@ -XMERL_VSN = 1.3.1 +XMERL_VSN = 1.3.2 @@ -84,7 +84,7 @@ usage () ;; git) echo "" - echo "update_primary - build and commit a new primary bootstrap" + echo "update_primary [--no-commit] - build and maybe commit a new primary bootstrap" ;; esac @@ -93,7 +93,7 @@ usage () ;; git) echo "" - echo "update_preloaded - build and commit the preloaded modules" + echo "update_preloaded [--no-commit] - build and maybe commit the preloaded modules" ;; esac } @@ -1094,33 +1094,61 @@ setup_make () fi export MAKE } - + +get_do_commit () +{ + if [ "x$1" = "x" ]; then + do_commit=true + elif [ "$1" = "--no-commit" ]; then + do_commit=false + else + echo "Unknown option '$1'" 1>&2 + exit 1 + fi +} + do_primary_git () { + get_do_commit $1 setup_make if [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then do_primary_cross else $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET primary_bootstrap || exit 1; fi - git add -A bootstrap/lib/kernel \ - bootstrap/lib/stdlib \ - bootstrap/lib/compiler \ - bootstrap/bin - find bootstrap -name egen -o -name '*.script' -o \ - -name '*.app' -o -name '*.appup' | + if [ $do_commit = true ]; then + git add -A bootstrap/lib/kernel \ + bootstrap/lib/stdlib \ + bootstrap/lib/compiler \ + bootstrap/bin + find bootstrap -name egen -o -name '*.script' -o \ + -name '*.app' -o -name '*.appup' | xargs git reset HEAD - git commit --no-verify -m 'Update primary bootstrap' + git commit --no-verify -m 'Update primary bootstrap' + echo "Primary bootstrap updated and commited." + else + echo "" + echo "Primary bootstrap rebuilt. Use \"git add bootstrap/...\" to stage changed files." + echo "" + fi } do_update_prel_git () { + get_do_commit $1 setup_make (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET clean) $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET preloaded || exit 1 (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET copy) - git add -A $ERL_TOP/erts/preloaded/ebin/*.beam - git commit -m 'Update preloaded modules' + if [ $do_commit = true ]; then + git add -A $ERL_TOP/erts/preloaded/ebin/*.beam + git commit -m 'Update preloaded modules' + echo "Preloaded updated and commited." + else + echo "" + echo "Preloaded rebuilt. Use \"git add erts/preloaded/ebin/...\" to stage changed beam files." + echo "" + fi } do_boot () @@ -1311,7 +1339,9 @@ case $TARGET in if [ X"$OVERRIDE_TARGET" = X"" -a X"$1" != X"env_win32" -a X"$1" != X"env_msys32" -a X"$1" != X"env_msys64" ];then echo "Building for windows, you should do the " \ "following first:" >&2 - echo 'eval `./otp_build env_msys64`' >&2 + echo 'eval `./otp_build env_win32`' >&2 + echo 'or' >&2 + echo 'eval `./otp_build env_win32 x64`' >&2 echo 'please note that there are backticks (``) in' \ 'the command' exit 1 @@ -1401,12 +1431,12 @@ case "$1" in do_boot;; update_primary) case $version_controller in - git) do_primary_git ;; + git) do_primary_git "$2";; none) git_required ;; esac ;; update_preloaded) case $version_controller in - git) do_update_prel_git ;; + git) do_update_prel_git "$2";; none) git_required ;; esac ;; primary) diff --git a/xcomp/README.md b/xcomp/README.md index 2d79107283..5f4b36bdca 100644 --- a/xcomp/README.md +++ b/xcomp/README.md @@ -291,6 +291,38 @@ and then do the cross build of the system. `otp_build release -a` will do the same as (5), and you will after this have to do a manual install either by doing (6), or (7). +Testing the cross compiled system +-------------------------------------- +Some of the tests that come with erlang use native code to test. This means +that when cross compiling erlang you also have to cross compile test suites +in order to run tests on the target host. To do this you first have to release +the tests as usual. + + $ make release_tests + +or + + $ ./otp_build tests + +The tests will be released into `$ERL_TOP/release/tests`. After releasing the +tests you have to install the tests on the build machine. You supply the same +xcomp file as to `./otp_build` in (9). + + $ cd $ERL_TOP/release/tests/test_server/ + $ $ERL_TOP/bootstrap/bin/erl -eval 'ts:install([{xcomp,"<FILE>"}])' -s ts compile_testcases -s init stop + +You should get a lot of printouts as the testcases are compiled. Once done you +should copy the entire `$ERL_TOP/release/tests` folder to the cross host system. + +Then go to the cross host system and setup the erlang installed in (4) or (5) +to be in your `$PATH`. Then go to what previously was +`$ERL_TOP/release/tests/test_server` and issue the following command. + + $ erl -s ts install -s ts run all_tests -s init stop + +The configure should be skipped and all tests should hopefully pass. For more +details about how to use ts run `erl -s ts help -s init stop` + Currently Used Configuration Variables -------------------------------------- |