diff options
102 files changed, 1000 insertions, 1984 deletions
diff --git a/erts/configure.in b/erts/configure.in index 30bc1ef000..a0c5cab181 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -827,6 +827,12 @@ if test -z "$FOP"; then AC_MSG_WARN([No 'fop' command found: going to generate placeholder PDF files]) fi +AC_CHECK_PROGS(XMLLINT, xmllint) +if test -z "$XMLLINT"; then + echo "xmllint" >> doc/CONF_INFO + AC_MSG_WARN([No 'xmllint' command found: can't run the xmllint target for the documentation]) +fi + dnl dnl We can live with Solaris /usr/ucb/install dnl diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 4455d0ac92..d036b4c7fb 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -290,13 +290,6 @@ <item>If E is <c><![CDATA[fun Fc_1 ; ... ; Fc_k end]]></c> where each <c><![CDATA[Fc_i]]></c> is a function clause then Rep(E) = <c><![CDATA[{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}]]></c>.</item> - <item>If E is <c><![CDATA[query [E_0 || W_1, ..., W_k] end]]></c>, - where each <c><![CDATA[W_i]]></c> is a generator or a filter, then - Rep(E) = <c><![CDATA[{'query',LINE,{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}}]]></c>. - For Rep(W), see below.</item> - <item>If E is <c><![CDATA[E_0.Field]]></c>, a Mnesia record access - inside a query, then - Rep(E) = <c><![CDATA[{record_field,LINE,Rep(E_0),Rep(Field)}]]></c>.</item> <item>If E is <c><![CDATA[( E_0 )]]></c>, then Rep(E) = <c><![CDATA[Rep(E_0)]]></c>, i.e., parenthesized expressions cannot be distinguished from their bodies.</item> diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index fe7024b185..37c7f3466b 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -479,7 +479,7 @@ <tag><marker id="async_thread_pool_size"><c><![CDATA[+A size]]></c></marker></tag> <item> <p>Sets the number of threads in async thread pool, valid range - is 0-1024. Default is 0.</p> + is 0-1024. If thread support is available, the default is 10.</p> </item> <tag><c><![CDATA[+B [c | d | i]]]></c></tag> <item> @@ -582,7 +582,7 @@ <seealso marker="erts_alloc">erts_alloc(3)</seealso> for further information.</p> </item> - <tag><c><![CDATA[+n Behavior]]></c></tag> + <tag><marker id="+n"/><c><![CDATA[+n Behavior]]></c></tag> <item> <p>Control behavior of signals to ports.</p> <p>As of OTP-R16 signals to ports are truly asynchronously @@ -615,7 +615,7 @@ debugging.</item> </taglist> </item> - <tag><marker id="max_processes"><c><![CDATA[+P Number]]></c></marker></tag> + <tag><marker id="+P"/><marker id="max_processes"><c><![CDATA[+P Number]]></c></marker></tag> <item> <p>Sets the maximum number of simultaneously existing processes for this system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p> @@ -627,7 +627,7 @@ <seealso marker="erlang#system_info_process_limit">erlang:system_info(process_limit)</seealso>.</p> <p>The default value is <c>262144</c></p> </item> - <tag><marker id="max_ports"><c><![CDATA[+Q Number]]></c></marker></tag> + <tag><marker id="+Q"/><marker id="max_ports"><c><![CDATA[+Q Number]]></c></marker></tag> <item> <p>Sets the maximum number of simultaneously existing ports for this system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p> @@ -710,7 +710,24 @@ <taglist> <tag><marker id="+sbt"><c>+sbt BindType</c></marker></tag> <item> - <p>Set scheduler bind type. Currently valid <c>BindType</c>s: + <p>Set scheduler bind type.</p> + <p>Schedulers can also be bound using the + <seealso marker="#+stbt">+stbt</seealso> flag. The only difference + between these two flags is how the following errors are handled:</p> + <list> + <item>Binding of schedulers is not supported on the specific + platform.</item> + <item>No available CPU topology. That is the runtime system + was not able to automatically detected the CPU topology, and + no <seealso marker="#+sct">user defined CPU topology</seealso> + was set.</item> + </list> + <p>If any of these errors occur when <c>+sbt</c> has been passed, + the runtime system will print an error message, and refuse to + start. If any of these errors occur when <c>+stbt</c> has been + passed, the runtime system will silently ignore the error, and + start up using unbound schedulers.</p> + <p>Currently valid <c>BindType</c>s: </p> <taglist> <tag><c>u</c></tag> @@ -960,6 +977,14 @@ <p>For more information, see <seealso marker="erlang#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>.</p> </item> + <tag><marker id="+stbt"><c>+stbt BindType</c></marker></tag> + <item> + <p>Try to set scheduler bind type. The same as the + <seealso marker="#+sbt">+sbt</seealso> flag with the exception of + how some errors are handled. For more information, see the + documentation of the <seealso marker="#+sbt">+sbt</seealso> flag. + </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 diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 13f42a74a7..1212c34586 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -317,9 +317,9 @@ minor version used by the driver is greater than the one used by the runtime system.</p> <p>The emulator will refuse to load a driver that does not use - the extended driver interface since, + the extended driver interface, to allow for 64-bit capable drivers, - incompatible type changes for the callbacks + since incompatible type changes for the callbacks <seealso marker="driver_entry#output">output</seealso>, <seealso marker="driver_entry#control">control</seealso> and <seealso marker="driver_entry#call">call</seealso> @@ -1560,7 +1560,7 @@ typedef struct ErlIOVec { <c>[ERL_DRV_BUSY_MSGQ_LIM_MIN, ERL_DRV_BUSY_MSGQ_LIM_MAX]</c>. Limits will be automatically adjusted to be sane. That is, the system will adjust values so that the low limit used is - lower or equal to the high limit used. By default the high + lower than or equal to the high limit used. By default the high limit will be 8 kB and the low limit will be 4 kB.</p> <p>By passing a pointer to an integer variable containing diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 1d67be2e52..ce59908036 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -5679,35 +5679,35 @@ ok For more information see the <seealso marker="erl#+spp">+spp</seealso> command line argument of <seealso marker="erl">erl(1)</seealso>.</p></item> - <tag><c>process_count</c></tag> + <tag><marker id="system_info_port_count"/><c>port_count</c></tag> <item> <p>Returns the number of ports currently existing at the local node as an integer. The same value as - <c>length(erlang:ports())</c> returns.</p> + <c>length(erlang:ports())</c> returns, but more efficient.</p> </item> <tag><marker id="system_info_port_limit"><c>port_limit</c></marker></tag> <item> <p>Returns the maximum number of simultaneously existing ports at the local node as an integer. This limit can be configured at startup by using the - <seealso marker="erl#max_ports"><c>+Q</c></seealso> + <seealso marker="erl#+Q">+Q</seealso> command line flag of - <seealso marker="erl"><c>erl(1)</c></seealso>.</p> + <seealso marker="erl">erl(1)</seealso>.</p> </item> - <tag><c>process_count</c></tag> + <tag><marker id="system_info_process_count"/><c>process_count</c></tag> <item> <p>Returns the number of processes currently existing at the local node as an integer. The same value as - <c>length(processes())</c> returns.</p> + <c>length(processes())</c> returns, but more efficient.</p> </item> <tag><marker id="system_info_process_limit"><c>process_limit</c></marker></tag> <item> <p>Returns the maximum number of simultaneously existing processes at the local node as an integer. This limit can be configured at startup by using the - <seealso marker="erl#max_processes"><c>+P</c></seealso> + <seealso marker="erl#+P">+P</seealso> command line flag of - <seealso marker="erl"><c>erl(1)</c></seealso>.</p> + <seealso marker="erl">erl(1)</seealso>.</p> </item> <tag><c>procs</c></tag> <item> diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index 71f232035d..4e456988a3 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -59,6 +59,8 @@ do { \ } while(0) #define BUMP_REDS(p, gc) do { \ + ASSERT(p); \ + ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));\ (p)->fcalls -= (gc); \ if ((p)->fcalls < 0) { \ if (!ERTS_PROC_GET_SAVED_CALLS_BUF((p))) \ diff --git a/erts/emulator/beam/erl_cpu_topology.c b/erts/emulator/beam/erl_cpu_topology.c index 113c4a6a68..88456a85f3 100644 --- a/erts/emulator/beam/erl_cpu_topology.c +++ b/erts/emulator/beam/erl_cpu_topology.c @@ -620,30 +620,38 @@ write_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size) int erts_init_scheduler_bind_type_string(char *how) { + ErtsCpuBindOrder order; + if (sys_strcmp(how, "u") == 0) - cpu_bind_order = ERTS_CPU_BIND_NONE; - else if (erts_bind_to_cpu(cpuinfo, -1) == -ENOTSUP) - return ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED; - else if (!system_cpudata && !user_cpudata) - return ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY; + order = ERTS_CPU_BIND_NONE; else if (sys_strcmp(how, "db") == 0) - cpu_bind_order = ERTS_CPU_BIND_DEFAULT_BIND; + order = ERTS_CPU_BIND_DEFAULT_BIND; else if (sys_strcmp(how, "s") == 0) - cpu_bind_order = ERTS_CPU_BIND_SPREAD; + order = ERTS_CPU_BIND_SPREAD; else if (sys_strcmp(how, "ps") == 0) - cpu_bind_order = ERTS_CPU_BIND_PROCESSOR_SPREAD; + order = ERTS_CPU_BIND_PROCESSOR_SPREAD; else if (sys_strcmp(how, "ts") == 0) - cpu_bind_order = ERTS_CPU_BIND_THREAD_SPREAD; + order = ERTS_CPU_BIND_THREAD_SPREAD; else if (sys_strcmp(how, "tnnps") == 0) - cpu_bind_order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD; + order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD; else if (sys_strcmp(how, "nnps") == 0) - cpu_bind_order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD; + order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD; else if (sys_strcmp(how, "nnts") == 0) - cpu_bind_order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD; + order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD; else if (sys_strcmp(how, "ns") == 0) - cpu_bind_order = ERTS_CPU_BIND_NO_SPREAD; + order = ERTS_CPU_BIND_NO_SPREAD; else - return ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_BAD_TYPE; + return ERTS_INIT_SCHED_BIND_TYPE_ERROR_BAD_TYPE; + + if (order != ERTS_CPU_BIND_NONE) { + if (erts_bind_to_cpu(cpuinfo, -1) == -ENOTSUP) + return ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED; + else if (!system_cpudata && !user_cpudata) + return ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY; + } + + cpu_bind_order = order; + return ERTS_INIT_SCHED_BIND_TYPE_SUCCESS; } diff --git a/erts/emulator/beam/erl_cpu_topology.h b/erts/emulator/beam/erl_cpu_topology.h index c5a9520b61..11915e1ea8 100644 --- a/erts/emulator/beam/erl_cpu_topology.h +++ b/erts/emulator/beam/erl_cpu_topology.h @@ -40,7 +40,7 @@ void erts_init_cpu_topology(void); #define ERTS_INIT_SCHED_BIND_TYPE_SUCCESS 0 #define ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED 1 #define ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY 2 -#define ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_BAD_TYPE 3 +#define ERTS_INIT_SCHED_BIND_TYPE_ERROR_BAD_TYPE 3 int erts_init_scheduler_bind_type_string(char *how); diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 8cdf954dd2..516f7b3cb3 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -55,6 +55,8 @@ # include <sys/resource.h> #endif +#define ERTS_DEFAULT_NO_ASYNC_THREADS 10 + /* * The variables below (prefixed with etp_) are for erts/etc/unix/etp-commands * only. Do not remove even though they aren't used elsewhere in the emulator! @@ -521,7 +523,7 @@ void erts_usage(void) erts_fprintf(stderr, "-r force ets memory block to be moved on realloc\n"); 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, "-stbt type 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"); @@ -529,7 +531,7 @@ void erts_usage(void) 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, " default|legacy.\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"); @@ -631,7 +633,7 @@ early_init(int *argc, char **argv) /* erts_disable_tolerant_timeofday = 0; display_items = 200; erts_backtrace_depth = DEFAULT_BACKTRACE_SIZE; - erts_async_max_threads = 0; + erts_async_max_threads = ERTS_DEFAULT_NO_ASYNC_THREADS; erts_async_thread_suggested_stack_size = ERTS_ASYNC_THREAD_MIN_STACK_SIZE; H_MIN_SIZE = H_DEFAULT_SIZE; BIN_VH_MIN_SIZE = VH_DEFAULT_SIZE; @@ -700,7 +702,7 @@ early_init(int *argc, char **argv) /* if (erts_sys_getenv__("ERL_THREAD_POOL_SIZE", envbuf, &envbufsz) == 0) erts_async_max_threads = atoi(envbuf); else - erts_async_max_threads = 0; + erts_async_max_threads = ERTS_DEFAULT_NO_ASYNC_THREADS; if (erts_async_max_threads > ERTS_MAX_NO_OF_ASYNC_THREADS) erts_async_max_threads = ERTS_MAX_NO_OF_ASYNC_THREADS; @@ -1238,7 +1240,7 @@ erl_start(int argc, char **argv) case ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY: estr = "no cpu topology available"; break; - case ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_BAD_TYPE: + case ERTS_INIT_SCHED_BIND_TYPE_ERROR_BAD_TYPE: estr = "invalid type"; break; default: @@ -1333,6 +1335,16 @@ erl_start(int argc, char **argv) } else if (sys_strcmp("nsp", sub_param) == 0) erts_use_sender_punish = 0; + else if (has_prefix("tbt", sub_param)) { + arg = get_arg(sub_param+3, argv[i+1], &i); + res = erts_init_scheduler_bind_type_string(arg); + if (res == ERTS_INIT_SCHED_BIND_TYPE_ERROR_BAD_TYPE) { + erts_fprintf(stderr, + "setting scheduler bind type '%s' failed: invalid type\n", + arg); + erts_usage(); + } + } else if (sys_strcmp("wt", sub_param) == 0) { arg = get_arg(sub_param+2, argv[i+1], &i); if (erts_sched_set_wakeup_other_thresold(arg) != 0) { diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h index fb07f3d5bc..65b4cd0bfe 100644 --- a/erts/emulator/beam/erl_port.h +++ b/erts/emulator/beam/erl_port.h @@ -273,29 +273,28 @@ extern erts_smp_atomic_t erts_bytes_in; /* no bytes sent into the system */ (ERTS_PORT_SFLGS_INVALID_LOOKUP \ | ERTS_PORT_SFLG_DISTRIBUTION) - /* * Costs in reductions for some port operations. */ -#define ERTS_PORT_REDS_EXECUTE 10 -#define ERTS_PORT_REDS_FREE 100 -#define ERTS_PORT_REDS_TIMEOUT 400 -#define ERTS_PORT_REDS_INPUT 400 -#define ERTS_PORT_REDS_OUTPUT 400 -#define ERTS_PORT_REDS_EVENT 400 -#define ERTS_PORT_REDS_CMD_OUTPUTV 400 -#define ERTS_PORT_REDS_CMD_OUTPUT 400 -#define ERTS_PORT_REDS_EXIT 300 -#define ERTS_PORT_REDS_CONNECT 40 -#define ERTS_PORT_REDS_UNLINK 40 -#define ERTS_PORT_REDS_LINK 40 -#define ERTS_PORT_REDS_BADSIG 40 -#define ERTS_PORT_REDS_CONTROL 400 -#define ERTS_PORT_REDS_CALL 400 -#define ERTS_PORT_REDS_INFO 100 -#define ERTS_PORT_REDS_SET_DATA 40 -#define ERTS_PORT_REDS_GET_DATA 40 -#define ERTS_PORT_REDS_TERMINATE 200 +#define ERTS_PORT_REDS_EXECUTE (CONTEXT_REDS/4) +#define ERTS_PORT_REDS_FREE (CONTEXT_REDS/400) +#define ERTS_PORT_REDS_TIMEOUT (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_INPUT (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_OUTPUT (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_EVENT (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_CMD_OUTPUTV (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_CMD_OUTPUT (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_EXIT (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_CONNECT (CONTEXT_REDS/200) +#define ERTS_PORT_REDS_UNLINK (CONTEXT_REDS/200) +#define ERTS_PORT_REDS_LINK (CONTEXT_REDS/200) +#define ERTS_PORT_REDS_BADSIG (CONTEXT_REDS/200) +#define ERTS_PORT_REDS_CONTROL (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_CALL (CONTEXT_REDS/50) +#define ERTS_PORT_REDS_INFO (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_SET_DATA (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_GET_DATA (CONTEXT_REDS/100) +#define ERTS_PORT_REDS_TERMINATE (CONTEXT_REDS/50) void print_port_info(Port *, int, void *); void erts_port_free(Port *); diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 8ceadcdb8c..09c8e760f4 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -35,6 +35,11 @@ #include "dtrace-wrapper.h" #include <stdarg.h> +/* + * ERTS_PORT_CALLBACK_VREDS: Limit the amount of callback calls we do... + */ +#define ERTS_PORT_CALLBACK_VREDS (CONTEXT_REDS/5) + #if defined(DEBUG) && 0 #define ERTS_HARD_DEBUG_TASK_QUEUES #else @@ -1544,6 +1549,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) ErtsPortTask *execq; int processing_busy_q; int res = 0; + int vreds = 0; int reds = ERTS_PORT_REDS_EXECUTE; erts_aint_t io_tasks_executed = 0; int fpe_was_unmasked; @@ -1688,6 +1694,9 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) break; } + vreds += ERTS_PORT_CALLBACK_VREDS; + reds += ERTS_PORT_CALLBACK_VREDS; + if (reds >= CONTEXT_REDS) break; } @@ -1757,6 +1766,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) != (erts_aint_t) 0); + reds -= vreds; runq->scheduler->reductions += reds; ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index aaca4b5f59..6e9bf7ca12 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -4080,11 +4080,11 @@ typedef enum { } ErtsSchedWakeupOtherThreshold; typedef enum { - ERTS_SCHED_WAKEUP_OTHER_TYPE_PROPOSAL, + ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT, ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY } ErtsSchedWakeupOtherType; -/* First proposal */ +/* Default */ #define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH (200*CONTEXT_REDS) #define ERTS_WAKEUP_OTHER_LIMIT_HIGH (50*CONTEXT_REDS) @@ -4101,7 +4101,7 @@ typedef enum { #define ERTS_WAKEUP_OTHER_DEC_SHIFT 2 #define ERTS_WAKEUP_OTHER_FIXED_INC (CONTEXT_REDS/10) -/* To be legacy */ +/* Legacy */ #define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH_LEGACY (200*CONTEXT_REDS) #define ERTS_WAKEUP_OTHER_LIMIT_HIGH_LEGACY (50*CONTEXT_REDS) @@ -4239,7 +4239,7 @@ static void set_wakeup_other_data(void) { switch (wakeup_other.type) { - case ERTS_SCHED_WAKEUP_OTHER_TYPE_PROPOSAL: + case ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT: wakeup_other.check = wakeup_other_check; wakeup_other_set_limit(); break; @@ -4258,7 +4258,7 @@ erts_early_init_scheduling(int no_schedulers) aux_work_timeout_early_init(no_schedulers); #ifdef ERTS_SMP wakeup_other.threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM; - wakeup_other.type = ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY; + wakeup_other.type = ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT; #endif sched_busy_wait.sys_schedule = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM; sched_busy_wait.tse = (ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM @@ -4294,10 +4294,8 @@ 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; + if (sys_strcmp(str, "default") == 0) + type = ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT; else if (sys_strcmp(str, "legacy") == 0) type = ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY; else diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index e466f0e299..04dc9bb236 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1573,6 +1573,8 @@ bad_port_signal(Process *c_p, try_call_state.state, flags & ERTS_PORT_SIG_FLG_BAD_OUTPUT); finalize_imm_drv_call(&try_call_state); + if (c_p) + BUMP_REDS(c_p, ERTS_PORT_REDS_BADSIG); return ERTS_PORT_OP_BADARG; case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: return ERTS_PORT_OP_DROPPED; @@ -1950,10 +1952,11 @@ erts_port_output(Process *c_p, driver_free_binary(cbin); if (evp != &ev) erts_free(ERTS_ALC_T_TMP, evp); - if (try_call_res == ERTS_TRY_IMM_DRV_CALL_OK) - return ERTS_PORT_OP_DONE; - else + if (try_call_res != ERTS_TRY_IMM_DRV_CALL_OK) return ERTS_PORT_OP_DROPPED; + if (c_p) + BUMP_REDS(c_p, ERTS_PORT_REDS_CMD_OUTPUTV); + return ERTS_PORT_OP_DONE; case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS: sched_flags = try_call_state.sched_flags; case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK: @@ -2096,10 +2099,11 @@ erts_port_output(Process *c_p, /* Fall through... */ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: erts_free(ERTS_ALC_T_TMP, buf); - if (try_call_res == ERTS_TRY_IMM_DRV_CALL_OK) - return ERTS_PORT_OP_DONE; - else + if (try_call_res != ERTS_TRY_IMM_DRV_CALL_OK) return ERTS_PORT_OP_DROPPED; + if (c_p) + BUMP_REDS(c_p, ERTS_PORT_REDS_CMD_OUTPUT); + return ERTS_PORT_OP_DONE; case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS: sched_flags = try_call_state.sched_flags; case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK: @@ -2267,6 +2271,8 @@ erts_port_exit(Process *c_p, reason, flags & ERTS_PORT_SIG_FLG_BROKEN_LINK); finalize_imm_drv_call(&try_call_state); + if (res == ERTS_PORT_OP_DONE && c_p) + BUMP_REDS(c_p, ERTS_PORT_REDS_EXIT); return res; } case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: @@ -2434,6 +2440,8 @@ erts_port_connect(Process *c_p, try_call_state.state, connect_id); finalize_imm_drv_call(&try_call_state); + if (res == ERTS_PORT_OP_DONE) + BUMP_REDS(c_p, ERTS_PORT_REDS_CONNECT); return res; } case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: @@ -2492,6 +2500,7 @@ erts_port_unlink(Process *c_p, Port *prt, Eterm from, Eterm *refp) case ERTS_TRY_IMM_DRV_CALL_OK: port_unlink(prt, from); finalize_imm_drv_call(&try_call_state); + BUMP_REDS(c_p, ERTS_PORT_REDS_UNLINK); return ERTS_PORT_OP_DONE; case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: return ERTS_PORT_OP_DROPPED; @@ -2579,6 +2588,7 @@ erts_port_link(Process *c_p, Port *prt, Eterm to, Eterm *refp) case ERTS_TRY_IMM_DRV_CALL_OK: port_link(prt, try_call_state.state, to); finalize_imm_drv_call(&try_call_state); + BUMP_REDS(c_p, ERTS_PORT_REDS_LINK); return ERTS_PORT_OP_DONE; case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: return ERTS_PORT_OP_BADARG; @@ -3944,6 +3954,7 @@ erts_port_control(Process* c_p, &hp, NULL, &c_p->off_heap); + BUMP_REDS(c_p, ERTS_PORT_REDS_CONTROL); return ERTS_PORT_OP_DONE; } case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: @@ -4244,6 +4255,7 @@ erts_port_call(Process* c_p, if (resp_buf != &resp_buf[0] && !(ret_flags & DRIVER_CALL_KEEP_BUFFER)) driver_free(resp_buf); + BUMP_REDS(c_p, ERTS_PORT_REDS_CALL); return ERTS_PORT_OP_DONE; } case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: @@ -4423,6 +4435,7 @@ erts_port_info(Process* c_p, *retvalp = copy_struct(value, used_h_size, &hp, &MSO(c_p)); free_message_buffer(bp); } + BUMP_REDS(c_p, ERTS_PORT_REDS_INFO); return ERTS_PORT_OP_DONE; } case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: @@ -4509,6 +4522,7 @@ erts_port_set_data(Process* c_p, prt->bp = bp; prt->data = set_data; finalize_imm_drv_call(&try_call_state); + BUMP_REDS(c_p, ERTS_PORT_REDS_SET_DATA); return ERTS_PORT_OP_DONE; case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: return ERTS_PORT_OP_DROPPED; @@ -4641,6 +4655,7 @@ erts_port_get_data(Process* c_p, free_message_buffer(bp); } *retvalp = TUPLE2(hp, am_ok, data); + BUMP_REDS(c_p, ERTS_PORT_REDS_GET_DATA); return ERTS_PORT_OP_DONE; } case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index f5011d11a5..f2b0c8a843 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -41,6 +41,8 @@ #define IS_DOT_OR_DOTDOT(s) \ ((s)[0] == L'.' && ((s)[1] == L'\0' || ((s)[1] == L'.' && (s)[2] == L'\0'))) +#define FILE_SHARE_FLAGS (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) + #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD) 0xFFFFFFFF) #endif @@ -724,7 +726,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ crFlags = CREATE_NEW; } fd = CreateFileW(wname, access, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SHARE_FLAGS, NULL, crFlags, FILE_ATTRIBUTE_NORMAL, NULL); /* @@ -909,7 +911,7 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, { HANDLE handle; /* Handle returned by CreateFile() */ BY_HANDLE_FILE_INFORMATION fileInfo; /* from CreateFile() */ - if (handle = CreateFileW(name, GENERIC_READ, 0,NULL, + if (handle = CreateFileW(name, GENERIC_READ, FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, 0, NULL)) { GetFileInformationByHandle(handle, &fileInfo); pInfo->links = fileInfo.nNumberOfLinks; @@ -1021,7 +1023,7 @@ efile_write_info(Efile_error* errInfo, } fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fd != INVALID_HANDLE_VALUE) { BOOL result = SetFileTime(fd, &CreationFileTime, &AccessFileTime, &ModifyFileTime); @@ -1384,7 +1386,7 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) DWORD fileAttributes = GetFileAttributesW(wname); if ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { BOOLEAN success = 0; - HANDLE h = CreateFileW(wname, GENERIC_READ, 0,NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + HANDLE h = CreateFileW(wname, GENERIC_READ, FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); int len; if(h != INVALID_HANDLE_VALUE) { success = pGetFinalPathNameByHandle(h, wbuffer, size / sizeof(WCHAR),0); diff --git a/erts/emulator/hipe/hipe_x86_gc.h b/erts/emulator/hipe/hipe_x86_gc.h index aa4abb6f59..4bea9276c0 100644 --- a/erts/emulator/hipe/hipe_x86_gc.h +++ b/erts/emulator/hipe/hipe_x86_gc.h @@ -71,7 +71,7 @@ nstack_walk_init_sdesc(const Process *p, struct nstack_walk_state *state) state->sdesc0[0].livebits[0] = 0; # ifdef DEBUG state->sdesc0[0].dbg_M = 0; - state->sdesc0[0].dbg_F = am_init; + state->sdesc0[0].dbg_F = am_undefined; state->sdesc0[0].dbg_A = 0; # endif /* XXX: this appears to prevent a gcc-4.1.1 bug on x86 */ diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index 66971654a2..5c4b11454f 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -42,6 +42,7 @@ typedef struct { TestCaseState_t visible; ErlDrvPort port; + ErlDrvTermData port_id; int result; jmp_buf done_jmp_buf; char *comment; @@ -97,6 +98,7 @@ testcase_drv_start(ErlDrvPort port, char *command) itcs->visible.testcase_name = testcase_name(); itcs->visible.extra = NULL; itcs->port = port; + itcs->port_id = driver_mk_port(port); itcs->result = TESTCASE_FAILED; itcs->comment = ""; @@ -142,7 +144,7 @@ testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) msg[1] = (ErlDrvTermData) result_atom; msg[2] = ERL_DRV_PORT; - msg[3] = driver_mk_port(itcs->port); + msg[3] = itcs->port_id; msg[4] = ERL_DRV_ATOM; msg[5] = driver_mk_atom(itcs->visible.testcase_name); @@ -154,7 +156,7 @@ testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) msg[9] = ERL_DRV_TUPLE; msg[10] = (ErlDrvTermData) 4; - driver_output_term(itcs->port, msg, 11); + erl_drv_output_term(itcs->port_id, msg, 11); } int @@ -184,7 +186,7 @@ testcase_printf(TestCaseState_t *tcs, char *frmt, ...) msg[1] = (ErlDrvTermData) driver_mk_atom("print"); msg[2] = ERL_DRV_PORT; - msg[3] = driver_mk_port(itcs->port); + msg[3] = itcs->port_id; msg[4] = ERL_DRV_ATOM; msg[5] = driver_mk_atom(itcs->visible.testcase_name); @@ -196,7 +198,7 @@ testcase_printf(TestCaseState_t *tcs, char *frmt, ...) msg[9] = ERL_DRV_TUPLE; msg[10] = (ErlDrvTermData) 4; - driver_output_term(itcs->port, msg, 11); + erl_drv_output_term(itcs->port_id, msg, 11); } diff --git a/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c b/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c index 9f6bd310c6..dcbaf500b8 100644 --- a/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c +++ b/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c @@ -71,9 +71,9 @@ void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) ERL_DRV_PID, driver_caller(port), ERL_DRV_TUPLE, (ErlDrvTermData) 3 }; - res = driver_output_term(port, msg, sizeof(msg)/sizeof(ErlDrvTermData)); + res = erl_drv_output_term(driver_mk_port(port), msg, sizeof(msg)/sizeof(ErlDrvTermData)); if (res <= 0) - driver_failure_atom(port, "driver_output_term failed"); + driver_failure_atom(port, "erl_drv_output_term failed"); } ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, diff --git a/erts/emulator/test/driver_SUITE_data/async_blast_drv.c b/erts/emulator/test/driver_SUITE_data/async_blast_drv.c index c2086c5860..d72b20d143 100644 --- a/erts/emulator/test/driver_SUITE_data/async_blast_drv.c +++ b/erts/emulator/test/driver_SUITE_data/async_blast_drv.c @@ -56,6 +56,7 @@ static ErlDrvEntry async_blast_drv_entry = { typedef struct { ErlDrvPort port; + ErlDrvTermData port_id; ErlDrvTermData caller; int counter; } async_blast_data_t; @@ -81,6 +82,7 @@ static ErlDrvData start(ErlDrvPort port, return ERL_DRV_ERROR_GENERAL; abd->port = port; + abd->port_id = driver_mk_port(port); abd->counter = 0; return (ErlDrvData) abd; } @@ -97,12 +99,12 @@ static void ready_async(ErlDrvData drv_data, async_blast_data_t *abd = (async_blast_data_t *) drv_data; if (--abd->counter == 0) { ErlDrvTermData spec[] = { - ERL_DRV_PORT, driver_mk_port(abd->port), + ERL_DRV_PORT, abd->port_id, ERL_DRV_ATOM, driver_mk_atom("done"), ERL_DRV_TUPLE, 2 }; - driver_send_term(abd->port, abd->caller, - spec, sizeof(spec)/sizeof(spec[0])); + erl_drv_send_term(abd->port_id, abd->caller, + spec, sizeof(spec)/sizeof(spec[0])); } } diff --git a/erts/emulator/test/driver_SUITE_data/caller_drv.c b/erts/emulator/test/driver_SUITE_data/caller_drv.c index 1ed20b0638..2731f9b317 100644 --- a/erts/emulator/test/driver_SUITE_data/caller_drv.c +++ b/erts/emulator/test/driver_SUITE_data/caller_drv.c @@ -85,9 +85,9 @@ send_caller(ErlDrvData drv_data, char *func) ERL_DRV_PID, driver_caller(port), ERL_DRV_TUPLE, (ErlDrvTermData) 4 }; - res = driver_output_term(port, msg, sizeof(msg)/sizeof(ErlDrvTermData)); + res = erl_drv_output_term(driver_mk_port(port), msg, sizeof(msg)/sizeof(ErlDrvTermData)); if (res <= 0) - driver_failure_atom(port, "driver_output_term failed"); + driver_failure_atom(port, "erl_drv_output_term failed"); } static ErlDrvData diff --git a/erts/emulator/test/driver_SUITE_data/monitor_drv.c b/erts/emulator/test/driver_SUITE_data/monitor_drv.c index 3da067fd09..81dfb65191 100644 --- a/erts/emulator/test/driver_SUITE_data/monitor_drv.c +++ b/erts/emulator/test/driver_SUITE_data/monitor_drv.c @@ -117,7 +117,7 @@ static void handle_monitor(ErlDrvData drv_data, ErlDrvMonitor *monitor) o->next = p->next; } driver_free(p); - driver_send_term(data->port, data->ipid, spec, sizeof(spec)/sizeof(ErlDrvTermData)); + erl_drv_send_term(driver_mk_port(data->port), data->ipid, spec, sizeof(spec)/sizeof(ErlDrvTermData)); } return; diff --git a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c index 221fd0ce51..93ef767d75 100644 --- a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c +++ b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c @@ -134,8 +134,8 @@ static void send_reply(Otp9302AsyncData *adata) ERL_DRV_ATOM, adata->term_data.msg, ERL_DRV_TUPLE, 2 }; - driver_send_term(adata->port, adata->term_data.receiver, - spec, sizeof(spec)/sizeof(spec[0])); + erl_drv_send_term(adata->term_data.port, adata->term_data.receiver, + spec, sizeof(spec)/sizeof(spec[0])); } static void enqueue_reply(Otp9302AsyncData *adata) diff --git a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c index 0c86a26604..cbee1c3dce 100644 --- a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c +++ b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c @@ -177,15 +177,16 @@ static void ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data) { PeekNonXQDrvData *dp = (PeekNonXQDrvData *) drv_data; if (dp->cmd == PEEK_NONXQ_WAIT) { + ErlDrvTermData port_id = driver_mk_port(dp->port); ErlDrvTermData spec[] = { - ERL_DRV_PORT, driver_mk_port(dp->port), + ERL_DRV_PORT, port_id, ERL_DRV_ATOM, driver_mk_atom("test_successful"), ERL_DRV_TUPLE, 2 }; - driver_send_term(dp->port, - dp->caller, - spec, - sizeof(spec) / sizeof(spec[0])); + erl_drv_send_term(port_id, + dp->caller, + spec, + sizeof(spec) / sizeof(spec[0])); } if (thread_data) driver_free(thread_data); diff --git a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c index 1070678d7b..5a9112afa3 100644 --- a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c +++ b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c @@ -168,8 +168,8 @@ static void *thread(void *varg) for (s = 0; s < THR_MSG_BLAST_NO_SENDS_PER_PROC; s++) { for (p = 0; p < THR_MSG_BLAST_NO_PROCS; p++) { - int res = driver_send_term(tmbd->port, tmbd->proc[p], - spec, sizeof(spec)/sizeof(spec[0])); + int res = erl_drv_send_term(tmbd->td_port, tmbd->proc[p], + spec, sizeof(spec)/sizeof(spec[0])); if (p == 0 && res <= 0) abort(); /* Could not send to creator */ } diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c index b4542f3e36..2cd3209231 100644 --- a/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c @@ -42,6 +42,7 @@ typedef struct { TestCaseState_t visible; ErlDrvPort port; + ErlDrvTermData port_id; int result; jmp_buf done_jmp_buf; char *comment; @@ -98,6 +99,7 @@ testcase_drv_start(ErlDrvPort port, char *command) itcs->visible.testcase_name = testcase_name(); itcs->visible.extra = NULL; itcs->port = port; + itcs->port_id = driver_mk_port(port); itcs->result = TESTCASE_FAILED; itcs->comment = ""; @@ -143,7 +145,7 @@ testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) msg[1] = (ErlDrvTermData) result_atom; msg[2] = ERL_DRV_PORT; - msg[3] = driver_mk_port(itcs->port); + msg[3] = itcs->port_id; msg[4] = ERL_DRV_ATOM; msg[5] = driver_mk_atom(itcs->visible.testcase_name); @@ -155,7 +157,7 @@ testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) msg[9] = ERL_DRV_TUPLE; msg[10] = (ErlDrvTermData) 4; - driver_output_term(itcs->port, msg, 11); + erl_drv_output_term(itcs->port_id, msg, 11); } int @@ -185,7 +187,7 @@ testcase_printf(TestCaseState_t *tcs, char *frmt, ...) msg[1] = (ErlDrvTermData) driver_mk_atom("print"); msg[2] = ERL_DRV_PORT; - msg[3] = driver_mk_port(itcs->port); + msg[3] = itcs->port_id; msg[4] = ERL_DRV_ATOM; msg[5] = driver_mk_atom(itcs->visible.testcase_name); @@ -197,7 +199,7 @@ testcase_printf(TestCaseState_t *tcs, char *frmt, ...) msg[9] = ERL_DRV_TUPLE; msg[10] = (ErlDrvTermData) 4; - driver_output_term(itcs->port, msg, 11); + erl_drv_output_term(itcs->port_id, msg, 11); } diff --git a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c index b3feca79f0..f8613487b0 100644 --- a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c +++ b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c @@ -664,7 +664,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, ErlDrvSizeT count) /* Signal end of test case */ msg[0] = ERL_DRV_NIL; - driver_output_term(erlang_port, msg, 1); + erl_drv_output_term(driver_mk_port(erlang_port), msg, 1); return; } break; @@ -687,14 +687,14 @@ static void send_term_drv_run(ErlDrvData port, char *buf, ErlDrvSizeT count) static void output_term(ErlDrvTermData* msg, int len) { - if (driver_output_term(erlang_port, msg, len) <= 0) { - driver_failure_atom(erlang_port, "driver_output_term_failed"); + if (erl_drv_output_term(driver_mk_port(erlang_port), msg, len) <= 0) { + driver_failure_atom(erlang_port, "erl_drv_output_term_failed"); } } static void fail_term(ErlDrvTermData* msg, int len, int line) { - int status = driver_output_term(erlang_port, msg, len); + int status = erl_drv_output_term(driver_mk_port(erlang_port), msg, len); if (status == 1) { char buf[1024]; diff --git a/erts/emulator/test/trace_local_SUITE.erl b/erts/emulator/test/trace_local_SUITE.erl index b89a8c4a0e..1e0705fabe 100644 --- a/erts/emulator/test/trace_local_SUITE.erl +++ b/erts/emulator/test/trace_local_SUITE.erl @@ -874,7 +874,7 @@ exception_test(Opts, Func0, Args0) -> %% wrap them in wrappers... ?line {Func1,Args1} = case Function of - true -> {fun (F, As) -> exc(F, As) end,[Func0,Args0]}; + true -> {fun exc/2,[Func0,Args0]}; false -> {Func0,Args0} end, diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index 50c61f50eb..d865164bb0 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -124,6 +124,7 @@ static char *pluss_val_switches[] = { "bwt", "cl", "ct", + "tbt", "wt", "ws", "ss", diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex bea586b11c..af7adc2d44 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 061db72dd8..e966ac5296 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2057,6 +2057,8 @@ tuple_to_list(_Tuple) -> (multi_scheduling) -> disabled | blocked | enabled; (multi_scheduling_blockers) -> [PID :: pid()]; (otp_release) -> string(); + (port_count) -> non_neg_integer(); + (port_limit) -> pos_integer(); (process_count) -> pos_integer(); (process_limit) -> pos_integer(); (procs) -> binary(); diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl index ff6c7c11dc..531968b3c8 100644 --- a/lib/compiler/src/beam_dict.erl +++ b/lib/compiler/src/beam_dict.erl @@ -138,17 +138,7 @@ string(Str, Dict) when is_list(Str) -> -spec lambda(label(), non_neg_integer(), bdict()) -> {non_neg_integer(), bdict()}. -lambda(Lbl, 0, #asm{lambdas=Lambdas0}=Dict) -> - case lists:keyfind(Lbl, 1, Lambdas0) of - {Lbl,{OldIndex,_,_,_,_}} -> - {OldIndex,Dict}; - false -> - new_lambda(Lbl, 0, Dict) - end; -lambda(Lbl, NumFree, Dict) -> - new_lambda(Lbl, NumFree, Dict). - -new_lambda(Lbl, NumFree, #asm{lambdas=Lambdas0}=Dict) -> +lambda(Lbl, NumFree, #asm{lambdas=Lambdas0}=Dict) -> OldIndex = length(Lambdas0), %% Set Index the same as OldIndex. Index = OldIndex, @@ -245,12 +235,10 @@ string_table(#asm{strings=Strings,string_offset=Size}) -> -spec lambda_table(bdict()) -> {non_neg_integer(), [<<_:192>>]}. -lambda_table(#asm{exports=Ext0,locals=Loc0,lambdas=Lambdas0}) -> +lambda_table(#asm{locals=Loc0,lambdas=Lambdas0}) -> Lambdas1 = sofs:relation(Lambdas0), Loc = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Loc0]), - Ext = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Ext0]), - All = sofs:union(Loc, Ext), - Lambdas2 = sofs:relative_product1(Lambdas1, All), + Lambdas2 = sofs:relative_product1(Lambdas1, Loc), Lambdas = [<<F:32,A:32,Lbl:32,Index:32,NumFree:32,OldUniq:32>> || {{_,Lbl,Index,NumFree,OldUniq},{F,A}} <- sofs:to_external(Lambdas2)], {length(Lambdas),Lambdas}. diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index f17b0bd130..fbd7452301 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -2672,16 +2672,19 @@ bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) -> bsm_nonempty([], _ ) -> false. %% bsm_ensure_no_partition(Cs, Pos) -> ok (exception if problem) -%% We must make sure that binary matching is not partitioned between +%% We must make sure that matching is not partitioned between %% variables like this: %% foo(<<...>>) -> ... -%% foo(Var) when ... -> ... -%% foo(<<...>>) -> +%% foo(<Variable>) when ... -> ... +%% foo(<Any non-variable pattern>) -> %% If there is such partition, we are not allowed to reuse the binary variable -%% for the match context. Also, arguments to the left of the argument that -%% is matched against a binary, are only allowed to be simple variables, not -%% used in guards. The reason is that we must know that the binary is only -%% matched in one place. +%% for the match context. +%% +%% Also, arguments to the left of the argument that is matched +%% against a binary, are only allowed to be simple variables, not +%% used in guards. The reason is that we must know that the binary is +%% only matched in one place (i.e. there must be only one bs_start_match2 +%% instruction emitted). bsm_ensure_no_partition(Cs, Pos) -> bsm_ensure_no_partition_1(Cs, Pos, before). @@ -2689,6 +2692,12 @@ bsm_ensure_no_partition(Cs, Pos) -> %% Loop through each clause. bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], Pos, State0) -> State = bsm_ensure_no_partition_2(Ps, Pos, G, simple_vars, State0), + case State of + 'after' -> + bsm_ensure_no_partition_after(Cs, Pos); + _ -> + ok + end, bsm_ensure_no_partition_1(Cs, Pos, State); bsm_ensure_no_partition_1([], _, _) -> ok. @@ -2698,8 +2707,7 @@ bsm_ensure_no_partition_2([#c_binary{}=Where|_], 1, _, Vstate, State) -> before when Vstate =:= simple_vars -> within; before -> bsm_problem(Where, Vstate); within when Vstate =:= simple_vars -> within; - within -> bsm_problem(Where, Vstate); - 'after' -> bsm_problem(Where, bin_partition) + within -> bsm_problem(Where, Vstate) end; bsm_ensure_no_partition_2([#c_alias{}=Alias|_], 1, N, Vstate, State) -> %% Retrieve the real pattern that the alias refers to and check that. @@ -2748,6 +2756,15 @@ bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) -> bsm_ensure_no_partition_2([_|Ps], N, G, _, S) -> bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S). +bsm_ensure_no_partition_after([#c_clause{pats=Ps}|Cs], Pos) -> + case nth(Pos, Ps) of + #c_var{} -> + bsm_ensure_no_partition_after(Cs, Pos); + P -> + bsm_problem(P, bin_partition) + end; +bsm_ensure_no_partition_after([], _) -> ok. + bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P); bsm_could_match_binary(#c_cons{}) -> false; bsm_could_match_binary(#c_tuple{}) -> false; @@ -2872,7 +2889,7 @@ format_error(useless_building) -> format_error(bin_opt_alias) -> "INFO: the '=' operator will prevent delayed sub binary optimization"; format_error(bin_partition) -> - "INFO: non-consecutive clauses that match binaries " + "INFO: matching non-variables after a previous clause matching a variable " "will prevent delayed sub binary optimization"; format_error(bin_left_var_used_in_guard) -> "INFO: a variable to the left of the binary pattern is used in a guard; " diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index b1bff47f69..8ef71e1346 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -235,8 +235,16 @@ gexpr_test_add(Ke, St0) -> %% expr(Cexpr, Sub, State) -> {Kexpr,[PreKexpr],State}. %% Convert a Core expression, flattening it at the same time. -expr(#c_var{anno=A,name={Name,Arity}}, Sub, St) -> - {#k_local{anno=A,name=get_fsub(Name, Arity, Sub),arity=Arity},[],St}; +expr(#c_var{anno=A,name={_Name,Arity}}=Fname, Sub, St) -> + %% A local in an expression. + %% For now, these are wrapped into a fun by reverse + %% etha-conversion, but really, there should be exactly one + %% such "lambda function" for each escaping local name, + %% instead of one for each occurrence as done now. + Vs = [#c_var{name=list_to_atom("V" ++ integer_to_list(V))} || + V <- integers(1, Arity)], + Fun = #c_fun{anno=A,vars=Vs,body=#c_apply{anno=A,op=Fname,args=Vs}}, + expr(Fun, Sub, St); expr(#c_var{anno=A,name=V}, Sub, St) -> {#k_var{anno=A,name=get_vsub(V, Sub)},[],St}; expr(#c_literal{anno=A,val=V}, _Sub, St) -> @@ -1655,19 +1663,6 @@ uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) -> #k_int{val=Index},#k_int{val=Uniq}|Fvs], ret=Rs}, Free,add_local_function(Fun, St)}; -uexpr(#k_local{anno=A,name=Name,arity=Arity}, {break,Rs}, St) -> - Fs = get_free(Name, Arity, St), - FsCount = length(Fs), - Free = lit_list_vars(Fs), - %% Set dummy values for Index and Uniq -- the real values will - %% be assigned by beam_asm. - Index = Uniq = 0, - Bif = #k_bif{anno=#k{us=Free,ns=lit_list_vars(Rs),a=A}, - op=#k_internal{name=make_fun,arity=FsCount+3}, - args=[#k_atom{val=Name},#k_int{val=FsCount+Arity}, - #k_int{val=Index},#k_int{val=Uniq}|Fs], - ret=Rs}, - {Bif,Free,St}; uexpr(Lit, {break,Rs0}, St0) -> %% Transform literals to puts here. %%ok = io:fwrite("uexpr ~w:~p~n", [?LINE,Lit]), @@ -1848,6 +1843,12 @@ make_list(Es) -> #c_cons{hd=E,tl=Acc} end, #c_literal{val=[]}, Es). +%% List of integers in interval [N,M]. Empty list if N > M. + +integers(N, M) when N =< M -> + [N|integers(N + 1, M)]; +integers(_, _) -> []. + %% is_in_guard(State) -> true|false. is_in_guard(#kern{guard_refc=Refc}) -> diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index d63d2235d7..e8a92c509e 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -33,7 +33,8 @@ matching_meets_construction/1,simon/1,matching_and_andalso/1, otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1, match_string/1,zero_width/1,bad_size/1,haystack/1, - cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1]). + cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1, + no_partition/1]). -export([coverage_id/1,coverage_external_ignore/2]). @@ -57,7 +58,8 @@ groups() -> matching_meets_construction,simon, matching_and_andalso,otp_7188,otp_7233,otp_7240, otp_7498,match_string,zero_width,bad_size,haystack, - cover_beam_bool,matched_out_size,follow_fail_branch]}]. + cover_beam_bool,matched_out_size,follow_fail_branch, + no_partition]}]. init_per_suite(Config) -> @@ -1133,6 +1135,48 @@ ffb_2(<<_,T/bitstring>>, List, A) -> [_|_] -> bit_size(T) end. +no_partition(_) -> + one = no_partition_1(<<"string">>, a1), + {two,<<"string">>} = no_partition_1(<<"string">>, a2), + {two,<<>>} = no_partition_1(<<>>, a2), + {two,a} = no_partition_1(a, a2), + three = no_partition_1(undefined, a3), + {four,a,[]} = no_partition_1([a], a4), + {five,a,b} = no_partition_1({a,b}, a5), + + one = no_partition_2(<<"string">>, a1), + two = no_partition_2(<<"string">>, a2), + two = no_partition_2(<<>>, a2), + two = no_partition_2(a, a2), + three = no_partition_2(undefined, a3), + four = no_partition_2(42, a4), + five = no_partition_2([], a5), + six = no_partition_2(42.0, a6), + ok. + +no_partition_1(<<"string">>, a1) -> + one; +no_partition_1(V, a2) -> + {two,V}; +no_partition_1(undefined, a3) -> + three; +no_partition_1([H|T], a4) -> + {four,H,T}; +no_partition_1({A,B}, a5) -> + {five,A,B}. + +no_partition_2(<<"string">>, a1) -> + one; +no_partition_2(_, a2) -> + two; +no_partition_2(undefined, a3) -> + three; +no_partition_2(42, a4) -> + four; +no_partition_2([], a5) -> + five; +no_partition_2(42.0, a6) -> + six. check(F, R) -> R = F(). diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index 0b932d5a1f..157c951f77 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -254,14 +254,35 @@ check_extraneous([C|Cs], SuccType) -> end. check_extraneous_1(Contract, SuccType) -> - CRngs = erl_types:t_elements(erl_types:t_fun_range(Contract)), + CRng = erl_types:t_fun_range(Contract), + CRngs = erl_types:t_elements(CRng), STRng = erl_types:t_fun_range(SuccType), ?debug("CR = ~p\nSR = ~p\n", [CRngs, STRng]), - case [CR || CR <- CRngs, erl_types:t_is_none(erl_types:t_inf(CR, STRng, opaque))] of - [] -> ok; + case [CR || CR <- CRngs, + erl_types:t_is_none(erl_types:t_inf(CR, STRng, opaque))] of + [] -> + CRngList = list_part(CRng), + STRngList = list_part(STRng), + case is_not_nil_list(CRngList) andalso is_not_nil_list(STRngList) of + false -> ok; + true -> + CRngElements = erl_types:t_list_elements(CRngList), + STRngElements = erl_types:t_list_elements(STRngList), + Inf = erl_types:t_inf(CRngElements, STRngElements, opaque), + case erl_types:t_is_none(Inf) of + true -> {error, invalid_contract}; + false -> ok + end + end; CRs -> {error, {extra_range, erl_types:t_sup(CRs), STRng}} end. +list_part(Type) -> + erl_types:t_inf(erl_types:t_list(), Type, opaque). + +is_not_nil_list(Type) -> + erl_types:t_is_list(Type) andalso not erl_types:t_is_nil(Type). + %% This is the heart of the "range function" -spec process_contracts([contract_pair()], [erl_types:erl_type()]) -> erl_types:erl_type(). diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia.erl index b4f03fab03..17cc9a953d 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia.erl +++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia.erl @@ -1806,7 +1806,6 @@ system_info2(dump_log_update_in_place) -> system_info2(dump_log_update_in_place) -> mnesia_monitor:get_env(dump_log_update_in_place); system_info2(max_wait_for_decision) -> mnesia_monitor:get_env(max_wait_for_decision); -system_info2(embedded_mnemosyne) -> mnesia_monitor:get_env(embedded_mnemosyne); system_info2(ignore_fallback_at_startup) -> mnesia_monitor:get_env(ignore_fallback_at_startup); system_info2(fallback_error_function) -> mnesia_monitor:get_env(fallback_error_function); system_info2(log_version) -> mnesia_log:version(); @@ -1840,7 +1839,6 @@ system_info_items(yes) -> dump_log_time_threshold, dump_log_update_in_place, dump_log_write_threshold, - embedded_mnemosyne, event_module, extra_db_nodes, fallback_activated, diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_monitor.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_monitor.erl index b64419d5a8..a1c25b5120 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_monitor.erl +++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_monitor.erl @@ -631,7 +631,6 @@ env() -> dump_log_time_threshold, dump_log_update_in_place, dump_log_write_threshold, - embedded_mnemosyne, event_module, extra_db_nodes, ignore_fallback_at_startup, @@ -660,8 +659,6 @@ default_env(dump_log_update_in_place) -> true; default_env(dump_log_write_threshold) -> 1000; -default_env(embedded_mnemosyne) -> - false; default_env(event_module) -> mnesia_event; default_env(extra_db_nodes) -> @@ -703,7 +700,6 @@ do_check_type(event_module, A) when atom(A) -> A; do_check_type(ignore_fallback_at_startup, B) -> bool(B); do_check_type(fallback_error_function, {Mod, Func}) when atom(Mod), atom(Func) -> {Mod, Func}; -do_check_type(embedded_mnemosyne, B) -> bool(B); do_check_type(extra_db_nodes, L) when list(L) -> Fun = fun(N) when N == node() -> false; (A) when atom(A) -> true diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_sup.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_sup.erl index 78609ffdde..970e0e5f47 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_sup.erl +++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_sup.erl @@ -57,9 +57,8 @@ init() -> Event = event_procs(), Kernel = kernel_procs(), - Mnemosyne = mnemosyne_procs(), - {ok, {Flags, Event ++ Kernel ++ Mnemosyne}}. + {ok, {Flags, Event ++ Kernel}}. event_procs() -> KillAfter = timer:seconds(30), @@ -72,16 +71,6 @@ kernel_procs() -> KA = infinity, [{K, {K, start, []}, permanent, KA, supervisor, [K, supervisor]}]. -mnemosyne_procs() -> - case mnesia_monitor:get_env(embedded_mnemosyne) of - true -> - Q = mnemosyne_sup, - KA = infinity, - [{Q, {Q, start, []}, permanent, KA, supervisor, [Q, supervisor]}]; - false -> - [] - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% event handler @@ -107,11 +96,8 @@ add_event_handler() -> kill() -> Mnesia = [mnesia_fallback | mnesia:ms()], - Mnemosyne = mnemosyne_ms(), Kill = fun(Name) -> catch exit(whereis(Name), kill) end, - lists:foreach(Kill, Mnemosyne), lists:foreach(Kill, Mnesia), - lists:foreach(fun ensure_dead/1, Mnemosyne), lists:foreach(fun ensure_dead/1, Mnesia), timer:sleep(10), case lists:keymember(mnesia, 1, application:which_applications()) of @@ -128,9 +114,3 @@ ensure_dead(Name) -> timer:sleep(10), ensure_dead(Name) end. - -mnemosyne_ms() -> - case mnesia_monitor:get_env(embedded_mnemosyne) of - true -> mnemosyne:ms(); - false -> [] - end. diff --git a/lib/dialyzer/test/small_SUITE_data/results/empty_list_infimum b/lib/dialyzer/test/small_SUITE_data/results/empty_list_infimum new file mode 100644 index 0000000000..6eaf60b91d --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/empty_list_infimum @@ -0,0 +1,2 @@ + +empty_list_infimum.erl:38: Invalid type specification for function empty_list_infimum:list_vhost_permissions/1. The success typing is (_) -> [[{_,_}]]
\ No newline at end of file diff --git a/lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl b/lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl new file mode 100644 index 0000000000..b58fa732cb --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl @@ -0,0 +1,57 @@ +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% + +-module(empty_list_infimum). + +-record(permission, {configure, write, read}). +-record(user_vhost, {username, virtual_host}). +-record(user_permission, {user_vhost, permission}). + +%%---------------------------------------------------------------------------- + +-export([i_delete/1]). + +-type(vhost() :: binary()). + +-type(info_key() :: atom()). +-type(info_keys() :: [info_key()]). + +-type(info() :: {info_key(), any()}). +-type(infos() :: [info()]). + +%%---------------------------------------------------------------------------- + +-spec i_delete(vhost()) -> 'ok'. + +i_delete(VHostPath) -> + [ok || _ <- list_vhost_permissions(VHostPath)], + ok. + +%%---------------------------------------------------------------------------- + +vhost_perms_info_keys() -> + [user, configure, write, read]. + +-spec list_vhost_permissions(vhost()) -> infos(). + +list_vhost_permissions(VHostPath) -> + list_permissions(vhost_perms_info_keys(), rabbit_foo:some_list()). + +filter_props(Keys, Props) -> + [T || T = {K, _} <- Props, lists:member(K, Keys)]. + +list_permissions(Keys, SomeList) -> + [filter_props(Keys, [{user, Username}, + {vhost, VHostPath}, + {configure, ConfigurePerm}, + {write, WritePerm}, + {read, ReadPerm}]) || + #user_permission{user_vhost = #user_vhost{username = Username, + virtual_host = VHostPath}, + permission = #permission{configure = ConfigurePerm, + write = WritePerm, + read = ReadPerm}} <- + SomeList]. diff --git a/lib/dialyzer/test/small_SUITE_data/src/unknown_arity_function_spec.erl b/lib/dialyzer/test/small_SUITE_data/src/unknown_arity_function_spec.erl new file mode 100644 index 0000000000..c7d7459614 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/unknown_arity_function_spec.erl @@ -0,0 +1,10 @@ +-module(unknown_arity_function_spec). + +-export([test/2]). + +%-type t() :: 42 | fun((...) -> t()). +%-type f() :: fun((...) -> 42). + +-spec test(fun((...) -> 42), list()) -> 42. +test(F, L) -> + 42 = apply(F, L). diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index 04dad2eee7..bd6f00af1f 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -68,7 +68,7 @@ filter() See present/1, substrings/2, <fsummary>Open a connection to an LDAP server.</fsummary> <type> <v>Handle = handle()</v> - <v>Option = {port, integer()} | {log, function()} | {timeout, integer()} | {ssl, boolean()}</v> + <v>Option = {port, integer()} | {log, function()} | {timeout, integer()} | {ssl, boolean()} | {sslopts, list()}</v> </type> <desc> <p>Setup a connection to an LDAP server, the <c>HOST</c>'s are tried in order.</p> diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index 5753cc4749..d030408770 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -42,7 +42,8 @@ log, % User provided log function timeout = infinity, % Request timeout anon_auth = false, % Allow anonymous authentication - use_tls = false % LDAP/LDAPS + use_tls = false, % LDAP/LDAPS + tls_opts = [] % ssl:ssloptsion() }). %%% For debug purposes @@ -353,6 +354,10 @@ parse_args([{ssl, true}|T], Cpid, Data) -> parse_args(T, Cpid, Data#eldap{use_tls = true}); parse_args([{ssl, _}|T], Cpid, Data) -> parse_args(T, Cpid, Data); +parse_args([{sslopts, Opts}|T], Cpid, Data) when is_list(Opts) -> + parse_args(T, Cpid, Data#eldap{use_tls = true, tls_opts = Opts ++ Data#eldap.tls_opts}); +parse_args([{sslopts, _}|T], Cpid, Data) -> + parse_args(T, Cpid, Data); parse_args([{log, F}|T], Cpid, Data) when is_function(F) -> parse_args(T, Cpid, Data#eldap{log = F}); parse_args([{log, _}|T], Cpid, Data) -> @@ -384,8 +389,8 @@ try_connect([],_) -> do_connect(Host, Data, Opts) when Data#eldap.use_tls == false -> gen_tcp:connect(Host, Data#eldap.port, Opts, Data#eldap.timeout); do_connect(Host, Data, Opts) when Data#eldap.use_tls == true -> - ssl:connect(Host, Data#eldap.port, [{verify,0}|Opts]). - + SslOpts = [{verify,0} | Opts ++ Data#eldap.tls_opts], + ssl:connect(Host, Data#eldap.port, SslOpts). loop(Cpid, Data) -> receive diff --git a/lib/erl_docgen/priv/dtd/common.refs.dtd b/lib/erl_docgen/priv/dtd/common.refs.dtd index c1237766e1..93592607df 100644 --- a/lib/erl_docgen/priv/dtd/common.refs.dtd +++ b/lib/erl_docgen/priv/dtd/common.refs.dtd @@ -26,10 +26,12 @@ <!ELEMENT description (%block;|quote|br|marker|warning|note)* > <!ELEMENT funcs (func)+ > -<!ELEMENT func (name+,type_desc+,fsummary,type?,desc?) > +<!ELEMENT func (name+,type_desc*,fsummary,type?,desc?) > <!-- ELEMENT name is defined in each ref dtd --> <!ELEMENT fsummary (#PCDATA|c|em)* > -<!ELEMENT type (v,d?)+ > +<!ELEMENT type (v,d?)* > +<!ATTLIST type variable CDATA #IMPLIED + name_i CDATA #IMPLIED> <!ELEMENT v (#PCDATA) > <!ELEMENT d (#PCDATA|c|em)* > <!ELEMENT desc (%block;|quote|br|marker|warning|note|anno)* > @@ -41,3 +43,4 @@ <!ELEMENT datatypes (datatype)+ > <!ELEMENT datatype (name+,desc?) > <!ELEMENT type_desc (#PCDATA) > +<!ATTLIST type_desc variable CDATA #REQUIRED> diff --git a/lib/erl_docgen/priv/dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd index 9905086ff4..0cc5cfa06d 100644 --- a/lib/erl_docgen/priv/dtd/erlref.dtd +++ b/lib/erl_docgen/priv/dtd/erlref.dtd @@ -29,3 +29,6 @@ <!-- `name' is used in common.refs.dtd and must therefore be defined in each *ref. dtd --> <!ELEMENT name (#PCDATA) > +<!ATTLIST name name CDATA #IMPLIED + arity CDATA #IMPLIED + clause_i CDATA #IMPLIED> diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index 7de5af2a49..c846bdbf34 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -1102,11 +1102,13 @@ <xsl:template match="taglist/item"> <xsl:param name="partnum"/> - <fo:block xsl:use-attribute-sets="tagitem"> - <xsl:apply-templates> - <xsl:with-param name="partnum" select="$partnum"/> - </xsl:apply-templates> - </fo:block> + <fo:block-container> + <fo:block xsl:use-attribute-sets="tagitem"> + <xsl:apply-templates> + <xsl:with-param name="partnum" select="$partnum"/> + </xsl:apply-templates> + </fo:block> + </fo:block-container> </xsl:template> diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk index 2599dc0ff7..a2262198dc 100644 --- a/lib/erl_docgen/vsn.mk +++ b/lib/erl_docgen/vsn.mk @@ -1,2 +1 @@ -ERL_DOCGEN_VSN = 0.3.3 - +ERL_DOCGEN_VSN = 0.3.4 diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 98d65abba1..d93ad10bd4 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2012. All Rights Reserved. +%% Copyright Ericsson AB 2003-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -765,7 +765,6 @@ type(erlang, node, 0, _) -> t_node(); %% Guard bif, needs to be here. type(erlang, node, 1, Xs) -> strict(arg_types(erlang, node, 1), Xs, fun (_) -> t_node() end); -type(erlang, nodes, 0, _) -> t_list(t_node()); %% Guard bif, needs to be here. type(erlang, round, 1, Xs) -> strict(arg_types(erlang, round, 1), Xs, fun (_) -> t_integer() end); @@ -2250,8 +2249,6 @@ arg_types(erlang, node, 0) -> %% Guard bif, needs to be here. arg_types(erlang, node, 1) -> [t_identifier()]; -arg_types(erlang, nodes, 0) -> - []; %% Guard bif, needs to be here. arg_types(erlang, round, 1) -> [t_number()]; diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index f5be8fb08f..ea1e7b1292 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -3566,7 +3566,7 @@ t_from_form({type, _L, function, []}, _TypeNames, _InOpaque, _RecDict, t_from_form({type, _L, 'fun', []}, _TypeNames, _InOpaque, _RecDict, _VarDict) -> {t_fun(), []}; -t_from_form({type, _L, 'fun', [{type, _, any, []}, Range]}, TypeNames, +t_from_form({type, _L, 'fun', [{type, _, any}, Range]}, TypeNames, InOpaque, RecDict, VarDict) -> {T, R} = t_from_form(Range, TypeNames, InOpaque, RecDict, VarDict), {t_fun(T), R}; @@ -3909,7 +3909,7 @@ t_form_to_string({type, _L, binary, [Base, Unit]} = Type) -> _ -> io_lib:format("Badly formed bitstr type ~w", [Type]) end; t_form_to_string({type, _L, 'fun', []}) -> "fun()"; -t_form_to_string({type, _L, 'fun', [{type, _, any, []}, Range]}) -> +t_form_to_string({type, _L, 'fun', [{type, _, any}, Range]}) -> "fun(...) -> " ++ t_form_to_string(Range); t_form_to_string({type, _L, 'fun', [{type, _, product, Domain}, Range]}) -> "fun((" ++ string:join(t_form_to_string_list(Domain), ",") ++ ") -> " diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index e30ade1bd2..4a9b7d2ceb 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2012</year> + <year>1996</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -100,7 +100,11 @@ <name name="deep_list"/> </datatype> <datatype> - <name name="fd"/> + <name><marker id="type-fd">fd()</marker></name> + <desc> + <p>A file descriptor representing a file opened in <seealso + marker="#raw">raw</seealso> mode.</p> + </desc> </datatype> <datatype> <name name="filename"/> @@ -109,8 +113,8 @@ <name name="io_device"/> <desc> <p>As returned by - <seealso marker="#open/2">file:open/2</seealso>, - a process handling I/O-protocols.</p> + <seealso marker="#open/2">file:open/2</seealso>; + <c>pid()</c> is a process handling I/O-protocols.</p> </desc> </datatype> <datatype> @@ -662,7 +666,8 @@ </item> <tag><c>raw</c></tag> <item> - <p>The <c>raw</c> option allows faster access to a file, + <p><marker id="raw"/> + The <c>raw</c> option allows faster access to a file, because no Erlang process is needed to handle the file. However, a file opened in this way has the following limitations:</p> @@ -1251,11 +1256,11 @@ <p>The record <c>file_info</c> contains the following fields.</p> <taglist> - <tag><c>size = integer()</c></tag> + <tag><c>size = integer() >= 0</c></tag> <item> <p>Size of file in bytes.</p> </item> - <tag><c>type = device | directory | regular | other</c></tag> + <tag><c>type = device | directory | other | regular | symlink</c></tag> <item> <p>The type of the file.</p> </item> @@ -1263,22 +1268,22 @@ <item> <p>The current system access to the file.</p> </item> - <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() </c></tag> + <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> <item> <p>The last time the file was read.</p> </item> - <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() </c></tag> + <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> <item> <p>The last time the file was written.</p> </item> - <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() </c></tag> + <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >=0</c></tag> <item> <p>The interpretation of this time field depends on the operating system. On Unix, it is the last time the file or the inode was changed. In Windows, it is the create time.</p> </item> - <tag><c>mode = integer()</c></tag> + <tag><c>mode = integer() >= 0</c></tag> <item> <p>The file permissions as the sum of the following bit values:</p> @@ -1309,33 +1314,33 @@ <p>On Unix platforms, other bits than those listed above may be set.</p> </item> - <tag><c>links = integer()</c></tag> + <tag><c>links = integer() >= 0</c></tag> <item> <p>Number of links to the file (this will always be 1 for file systems which have no concept of links).</p> </item> - <tag><c>major_device = integer()</c></tag> + <tag><c>major_device = integer() >= 0</c></tag> <item> <p>Identifies the file system where the file is located. In Windows, the number indicates a drive as follows: 0 means A:, 1 means B:, and so on.</p> </item> - <tag><c>minor_device = integer()</c></tag> + <tag><c>minor_device = integer() >= 0</c></tag> <item> <p>Only valid for character devices on Unix. In all other cases, this field is zero.</p> </item> - <tag><c>inode = integer()</c></tag> + <tag><c>inode = integer() >= 0</c></tag> <item> <p>Gives the <c>inode</c> number. On non-Unix file systems, this field will be zero.</p> </item> - <tag><c>uid = integer()</c></tag> + <tag><c>uid = integer() >= 0</c></tag> <item> <p>Indicates the owner of the file. Will be zero for non-Unix file systems.</p> </item> - <tag><c>gid = integer()</c></tag> + <tag><c>gid = integer() >= 0</c></tag> <item> <p>Gives the group that the owner of the file belongs to. Will be zero for non-Unix file systems.</p> @@ -1766,22 +1771,22 @@ <p>The following fields are used from the record, if they are given.</p> <taglist> - <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer()</c></tag> + <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> <item> <p>The last time the file was read.</p> </item> - <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer()</c></tag> + <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> <item> <p>The last time the file was written.</p> </item> - <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer()</c></tag> + <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> <item> <p>On Unix, any value give for this field will be ignored (the "ctime" for the file will be set to the current time). On Windows, this field is the new creation time to set for the file.</p> </item> - <tag><c>mode = integer()</c></tag> + <tag><c>mode = integer() >= 0</c></tag> <item> <p>The file permissions as the sum of the following bit values:</p> @@ -1812,15 +1817,15 @@ <p>On Unix platforms, other bits than those listed above may be set.</p> </item> - <tag><c>uid = integer()</c></tag> + <tag><c>uid = integer() >= 0</c></tag> <item> <p>Indicates the owner of the file. Ignored for non-Unix file systems.</p> </item> - <tag><c>gid = integer()</c></tag> + <tag><c>gid = integer() >= 0</c></tag> <item> <p>Gives the group that the owner of the file belongs to. - Ignored non-Unix file systems.</p> + Ignored for non-Unix file systems.</p> </item> </taglist> <p>Typical error reasons:</p> diff --git a/lib/kernel/include/file.hrl b/lib/kernel/include/file.hrl index bf97173122..69aec1ee36 100644 --- a/lib/kernel/include/file.hrl +++ b/lib/kernel/include/file.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,32 +22,37 @@ %%-------------------------------------------------------------------------- -record(file_info, - {size :: non_neg_integer(), % Size of file in bytes. - type :: 'device' | 'directory' | 'other' | 'regular' | 'symlink', - access :: 'read' | 'write' | 'read_write' | 'none', - atime :: file:date_time() | integer(), % The local time the file was last read: - % {{Year, Mon, Day}, {Hour, Min, Sec}}. - % atime, ctime, mtime may also be unix epochs() - mtime :: file:date_time() | integer(), % The local time the file was last written. - ctime :: file:date_time() | integer(), % The interpretation of this time field - % is dependent on operating system. - % On Unix it is the last time the file - % or the inode was changed. On Windows, - % it is the creation time. - mode :: integer(), % File permissions. On Windows, - % the owner permissions will be - % duplicated for group and user. - links :: non_neg_integer(), % Number of links to the file (1 if the - % filesystem doesn't support links). - major_device :: integer(), % Identifies the file system (Unix), - % or the drive number (A: = 0, B: = 1) - % (Windows). - %% The following are Unix specific. - %% They are set to zero on other operating systems. - minor_device :: integer(), % Only valid for devices. - inode :: integer(), % Inode number for file. - uid :: integer(), % User id for owner. - gid :: integer()}). % Group id for owner. + {size :: non_neg_integer(), % Size of file in bytes. + type :: 'device' | 'directory' | 'other' | 'regular' | 'symlink', + access :: 'read' | 'write' | 'read_write' | 'none', + atime :: file:date_time() | non_neg_integer(), + % The local time the file was last read: + % {{Year, Mon, Day}, {Hour, Min, Sec}}. + % atime, ctime, mtime may also be unix epochs() + mtime :: file:date_time() | non_neg_integer(), + % The local time the file was last written. + ctime :: file:date_time() | non_neg_integer(), + % The interpretation of this time field + % is dependent on operating system. + % On Unix it is the last time the file + % or the inode was changed. On Windows, + % it is the creation time. + mode :: non_neg_integer(), % File permissions. On Windows, + % the owner permissions will be + % duplicated for group and user. + links :: non_neg_integer(), + % Number of links to the file (1 if the + % filesystem doesn't support links). + major_device :: non_neg_integer(), + % Identifies the file system (Unix), + % or the drive number (A: = 0, B: = 1) + % (Windows). + %% The following are Unix specific. + %% They are set to zero on other operating systems. + minor_device :: non_neg_integer(), % Only valid for devices. + inode :: non_neg_integer(), % Inode number for file. + uid :: non_neg_integer(), % User id for owner. + gid :: non_neg_integer()}). % Group id for owner. -record(file_descriptor, diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl index 4d2e31a429..c66e823a04 100644 --- a/lib/kernel/src/group.erl +++ b/lib/kernel/src/group.erl @@ -515,6 +515,27 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding) Drv, Ls, Encoding) end; +%% ^R = backward search, ^S = forward search. +%% Search is tricky to implement and does a lot of back-and-forth +%% work with edlin.erl (from stdlib). Edlin takes care of writing +%% and handling lines and escape characters to get out of search, +%% whereas this module does the actual searching and appending to lines. +%% Erlang's shell wasn't exactly meant to traverse the wall between +%% line and line stack, so we at least restrict it by introducing +%% new modes: search, search_quit, search_found. These are added to +%% the regular ones (none, meta_left_sq_bracket) and handle special +%% cases of history search. +get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls, Encoding) + when ((Mode =:= none) and (Char =:= $\^R)) -> + send_drv_reqs(Drv, Rs), + %% drop current line, move to search mode. We store the current + %% prompt ('N>') and substitute it with the search prompt. + send_drv_reqs(Drv, edlin:erase_line(Cont)), + put(search_quit_prompt, edlin:prompt(Cont)), + Pbs = prompt_bytes("(search)`': ", Encoding), + {more_chars,Ncont,Nrs} = edlin:start(Pbs, search), + send_drv_reqs(Drv, Nrs), + get_line1(edlin:edit_line1(Cs, Ncont), Drv, Ls, Encoding); get_line1({expand, Before, Cs0, Cont,Rs}, Drv, Ls0, Encoding) -> send_drv_reqs(Drv, Rs), ExpandFun = get(expand_fun), @@ -535,8 +556,59 @@ get_line1({undefined,_Char,Cs,Cont,Rs}, Drv, Ls, Encoding) -> send_drv_reqs(Drv, Rs), send_drv(Drv, beep), get_line1(edlin:edit_line(Cs, Cont), Drv, Ls, Encoding); +%% The search item was found and accepted (new line entered on the exact +%% result found) +get_line1({_What,Cont={line,_Prompt,_Chars,search_found},Rs}, Drv, Ls0, Encoding) -> + Line = edlin:current_line(Cont), + %% this may create duplicate entries. + Ls = save_line(new_stack(get_lines(Ls0)), Line), + get_line1({done, Line, "", Rs}, Drv, Ls, Encoding); +%% The search mode has been exited, but the user wants to remain in line +%% editing mode wherever that was, but editing the search result. +get_line1({What,Cont={line,_Prompt,_Chars,search_quit},Rs}, Drv, Ls, Encoding) -> + Line = edlin:current_chars(Cont), + %% Load back the old prompt with the correct line number. + case get(search_quit_prompt) of + undefined -> % should not happen. Fallback. + LsFallback = save_line(new_stack(get_lines(Ls)), Line), + get_line1({done, "\n", Line, Rs}, Drv, LsFallback, Encoding); + Prompt -> % redraw the line and keep going with the same stack position + NCont = {line,Prompt,{lists:reverse(Line),[]},none}, + send_drv_reqs(Drv, Rs), + send_drv_reqs(Drv, edlin:erase_line(Cont)), + send_drv_reqs(Drv, edlin:redraw_line(NCont)), + get_line1({What, NCont ,[]}, Drv, pad_stack(Ls), Encoding) + end; +%% Search mode is entered. +get_line1({What,{line,Prompt,{RevCmd0,_Aft},search},Rs}, + Drv, Ls0, Encoding) -> + send_drv_reqs(Drv, Rs), + %% Figure out search direction. ^S and ^R are returned through edlin + %% whenever we received a search while being already in search mode. + {Search, Ls1, RevCmd} = case RevCmd0 of + [$\^S|RevCmd1] -> + {fun search_down_stack/2, Ls0, RevCmd1}; + [$\^R|RevCmd1] -> + {fun search_up_stack/2, Ls0, RevCmd1}; + _ -> % new search, rewind stack for a proper search. + {fun search_up_stack/2, new_stack(get_lines(Ls0)), RevCmd0} + end, + Cmd = lists:reverse(RevCmd), + {Ls, NewStack} = case Search(Ls1, Cmd) of + {none, Ls2} -> + send_drv(Drv, beep), + {Ls2, {RevCmd, "': "}}; + {Line, Ls2} -> % found. Complete the output edlin couldn't have done. + send_drv_reqs(Drv, [{put_chars, Encoding, Line}]), + {Ls2, {RevCmd, "': "++Line}} + end, + Cont = {line,Prompt,NewStack,search}, + more_data(What, Cont, Drv, Ls, Encoding); get_line1({What,Cont0,Rs}, Drv, Ls, Encoding) -> send_drv_reqs(Drv, Rs), + more_data(What, Cont0, Drv, Ls, Encoding). + +more_data(What, Cont0, Drv, Ls, Encoding) -> receive {Drv,{data,Cs}} -> get_line1(edlin:edit_line(Cs, Cont0), Drv, Ls, Encoding); @@ -557,7 +629,6 @@ get_line1({What,Cont0,Rs}, Drv, Ls, Encoding) -> get_line1(edlin:edit_line([], Cont0), Drv, Ls, Encoding) end. - get_line_echo_off(Chars, Pbs, Drv) -> send_drv_reqs(Drv, [{put_chars, unicode,Pbs}]), get_line_echo_off1(edit_line(Chars,[]), Drv). @@ -632,12 +703,46 @@ save_line({stack, U, {}, []}, Line) -> save_line({stack, U, _L, D}, Line) -> {stack, U, Line, D}. -get_lines({stack, U, {}, []}) -> +get_lines(Ls) -> get_all_lines(Ls). +%get_lines({stack, U, {}, []}) -> +% U; +%get_lines({stack, U, {}, D}) -> +% tl(lists:reverse(D, U)); +%get_lines({stack, U, L, D}) -> +% get_lines({stack, U, {}, [L|D]}). + +%% There's a funny behaviour whenever the line stack doesn't have a "\n" +%% at its end -- get_lines() seemed to work on the assumption it *will* be +%% there, but the manipulations done with search history do not require it. +%% +%% It is an assumption because the function was built with either the full +%% stack being on the 'Up' side (we're on the new line) where it isn't +%% stripped. The only other case when it isn't on the 'Up' side is when +%% someone has used the up/down arrows (or ^P and ^N) to navigate lines, +%% in which case, a line with only a \n is stored at the end of the stack +%% (the \n is returned by edlin:current_line/1). +%% +%% get_all_lines works the same as get_lines, but only strips the trailing +%% character if it's a linebreak. Otherwise it's kept the same. This is +%% because traversing the stack due to search history will *not* insert +%% said empty line in the stack at the same time as other commands do, +%% and thus it should not always be stripped unless we know a new line +%% is the last entry. +get_all_lines({stack, U, {}, []}) -> U; -get_lines({stack, U, {}, D}) -> - tl(lists:reverse(D, U)); -get_lines({stack, U, L, D}) -> - get_lines({stack, U, {}, [L|D]}). +get_all_lines({stack, U, {}, D}) -> + case lists:reverse(D, U) of + ["\n"|Lines] -> Lines; + Lines -> Lines + end; +get_all_lines({stack, U, L, D}) -> + get_all_lines({stack, U, {}, [L|D]}). + +%% For the same reason as above, though, we need to expand the stack +%% in some cases to make sure we play nice with up/down arrows. We need +%% to insert newlines, but not always. +pad_stack({stack, U, L, D}) -> + {stack, U, L, D++["\n"]}. save_line_buffer("\n", Lines) -> save_line_buffer(Lines); @@ -649,6 +754,27 @@ save_line_buffer(Line, Lines) -> save_line_buffer(Lines) -> put(line_buffer, Lines). +search_up_stack(Stack, Substr) -> + case up_stack(Stack) of + {none,NewStack} -> {none,NewStack}; + {L, NewStack} -> + case string:str(L, Substr) of + 0 -> search_up_stack(NewStack, Substr); + _ -> {string:strip(L,right,$\n), NewStack} + end + end. + +search_down_stack(Stack, Substr) -> + case down_stack(Stack) of + {none,NewStack} -> {none,NewStack}; + {L, NewStack} -> + case string:str(L, Substr) of + 0 -> search_down_stack(NewStack, Substr); + _ -> {string:strip(L,right,$\n), NewStack} + end + end. + + %% This is get_line without line editing (except for backspace) and %% without echo. get_password_line(Chars, Drv) -> @@ -687,7 +813,7 @@ edit_password([$\177|Cs],[_|Chars]) ->%% is backspace enough? edit_password([Char|Cs],Chars) -> edit_password(Cs,[Char|Chars]). -%% prompt_bytes(Prompt) +%% prompt_bytes(Prompt, Encoding) %% Return a flat list of characters for the Prompt. prompt_bytes(Prompt, Encoding) -> lists:flatten(io_lib:format_prompt(Prompt, Encoding)). diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 5d45b91ee5..93dc2a69d1 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -47,7 +47,7 @@ %% Internal exports. -export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1, - otp_7731_server/1, zombie_server/2]). + otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]). init_per_testcase(_Func, Config) when is_list(Config) -> Dog = test_server:timetrap(test_server:seconds(240)), @@ -589,7 +589,13 @@ iter_max_socks(doc) -> "that we get the same number of sockets every time."]; iter_max_socks(Config) when is_list(Config) -> N = 20, - L = do_iter_max_socks(N, initalize), + %% Run on a different node in order to limit the effect if this test fails. + Dir = filename:dirname(code:which(?MODULE)), + {ok,Node} = test_server:start_node(test_iter_max_socks,slave, + [{args,"-pa " ++ Dir}]), + L = rpc:call(Node,?MODULE,do_iter_max_socks,[N, initalize]), + test_server:stop_node(Node), + io:format("Result: ~p",[L]), all_equal(L), {comment, "Max sockets: " ++ integer_to_list(hd(L))}. diff --git a/lib/megaco/doc/src/definitions/term.defs b/lib/megaco/doc/src/definitions/term.defs index f3d6f865d2..57379eaa5d 100644 --- a/lib/megaco/doc/src/definitions/term.defs +++ b/lib/megaco/doc/src/definitions/term.defs @@ -110,7 +110,6 @@ the module Erlang in the application kernel","kenneth"}, {"Master Agent","Master Agent","The SNMP agent system consists of one Master Agent which terminates the SNMP protocol","mbj"}, {"MIB","Management Information Base (MIB)","An abstract definition of the management information available through a management interface in a system.","mbj"}, {"matching","matching","See pattern matching.","kenneth"}, {"message queue","message queue","The queue of not yet received messages that are in the mailbox of a process.","olin"}, -{"Mnemosyne","Mnemosyne","Mnemosyne was the query language of Mnesia up to the R11B release. Supersed by QLC.","hakan"}, {"Mnesia","Mnesia","Mnesia is a distributed Database Management System, appropriate for telecommunications applications and other applications with need of continuous operation and soft real-time properties.","hakan"}, {"MIBshort","MIB","See Management Information Base.","mbj"}, {"MIME","MIME","Multi-purpose Internet Mail Extensions.","jocke"}, diff --git a/lib/megaco/doc/src/definitions/term.defs.xml b/lib/megaco/doc/src/definitions/term.defs.xml index 28ac0d6eaf..1c80ee8d80 100644 --- a/lib/megaco/doc/src/definitions/term.defs.xml +++ b/lib/megaco/doc/src/definitions/term.defs.xml @@ -794,13 +794,6 @@ The queue of not yet received messages that are in the mailbox of a process. <resp>olin</resp> </term> <term> - <id>Mnemosyne</id> - <shortdef>Mnemosyne</shortdef> - <def> -Mnemosyne was the query language of Mnesia up to the R11B release. Supersed by QLC.</def> - <resp>hakan</resp> - </term> - <term> <id>Mnesia</id> <shortdef>Mnesia</shortdef> <def> diff --git a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src index b8146c345d..5faddb08c5 100644 --- a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src +++ b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src @@ -76,6 +76,7 @@ typedef struct { ErlDrvPort port; + ErlDrvTermData port_id; char* digit_map_name_ptr; int digit_map_name_len; char* digit_map_value_ptr; @@ -1497,6 +1498,7 @@ static ErlDrvData mfs_start(ErlDrvPort port, char *buf) DBG( ("mfs_start -> entry\n") ); dataP->port = port; + dataP->port_id = driver_mk_port(port); dataP->digit_map_name_ptr = NULL; dataP->digit_map_name_len = 0; dataP->digit_map_value_ptr = NULL; @@ -1841,10 +1843,10 @@ static ErlDrvSSizeT mfs_control(ErlDrvData handle, "\n term_spec_size: %d\n", dataP->term_spec_index, dataP->term_spec_size) ); - driver_send_term(dataP->port, - driver_caller(dataP->port), - dataP->term_spec, - dataP->term_spec_index); + erl_drv_send_term(dataP->port_id, + driver_caller(dataP->port), + dataP->term_spec, + dataP->term_spec_index); if (dataP->text_buf != NULL) FREE(dataP->text_buf); if (dataP->term_spec != NULL) FREE(dataP->term_spec); diff --git a/lib/mnesia/include/mnemosyne.hrl b/lib/mnesia/include/mnemosyne.hrl deleted file mode 100644 index eb6ec53ae1..0000000000 --- a/lib/mnesia/include/mnemosyne.hrl +++ /dev/null @@ -1,18 +0,0 @@ -%% ``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 via the world wide web 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. -%% -%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. -%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -%% AB. All Rights Reserved.'' -%% -%% $Id$ -%% --compile({parse_transform,mnemosyne}). diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl index 3d30debc53..3488d5c99b 100644 --- a/lib/mnesia/src/mnesia.erl +++ b/lib/mnesia/src/mnesia.erl @@ -2186,7 +2186,6 @@ system_info2(dump_log_time_threshold) -> mnesia_monitor:get_env(dump_log_time_th system_info2(dump_log_update_in_place) -> mnesia_monitor:get_env(dump_log_update_in_place); system_info2(max_wait_for_decision) -> mnesia_monitor:get_env(max_wait_for_decision); -system_info2(embedded_mnemosyne) -> mnesia_monitor:get_env(embedded_mnemosyne); system_info2(ignore_fallback_at_startup) -> mnesia_monitor:get_env(ignore_fallback_at_startup); system_info2(fallback_error_function) -> mnesia_monitor:get_env(fallback_error_function); system_info2(log_version) -> mnesia_log:version(); @@ -2224,7 +2223,6 @@ system_info_items(yes) -> dump_log_time_threshold, dump_log_update_in_place, dump_log_write_threshold, - embedded_mnemosyne, event_module, extra_db_nodes, fallback_activated, diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index c08bbc879f..d940bd1cb7 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -673,7 +673,6 @@ env() -> dump_log_time_threshold, dump_log_update_in_place, dump_log_write_threshold, - embedded_mnemosyne, event_module, extra_db_nodes, ignore_fallback_at_startup, @@ -706,8 +705,6 @@ default_env(dump_log_update_in_place) -> true; default_env(dump_log_write_threshold) -> 1000; -default_env(embedded_mnemosyne) -> - false; default_env(event_module) -> mnesia_event; default_env(extra_db_nodes) -> @@ -757,7 +754,6 @@ do_check_type(event_module, A) when is_atom(A) -> A; do_check_type(ignore_fallback_at_startup, B) -> bool(B); do_check_type(fallback_error_function, {Mod, Func}) when is_atom(Mod), is_atom(Func) -> {Mod, Func}; -do_check_type(embedded_mnemosyne, B) -> bool(B); do_check_type(extra_db_nodes, L) when is_list(L) -> Fun = fun(N) when N == node() -> false; (A) when is_atom(A) -> true diff --git a/lib/mnesia/src/mnesia_sup.erl b/lib/mnesia/src/mnesia_sup.erl index 9ee4086f50..ef858d2364 100644 --- a/lib/mnesia/src/mnesia_sup.erl +++ b/lib/mnesia/src/mnesia_sup.erl @@ -60,9 +60,8 @@ init() -> Event = event_procs(), Kernel = kernel_procs(), - Mnemosyne = mnemosyne_procs(), - {ok, {Flags, Event ++ Kernel ++ Mnemosyne}}. + {ok, {Flags, Event ++ Kernel}}. event_procs() -> KillAfter = timer:seconds(30), @@ -75,16 +74,6 @@ kernel_procs() -> KA = infinity, [{K, {K, start, []}, permanent, KA, supervisor, [K, supervisor]}]. -mnemosyne_procs() -> - case mnesia_monitor:get_env(embedded_mnemosyne) of - true -> - Q = mnemosyne_sup, - KA = infinity, - [{Q, {Q, start, []}, permanent, KA, supervisor, [Q, supervisor]}]; - false -> - [] - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% event handler diff --git a/lib/mnesia/test/mnesia.spec b/lib/mnesia/test/mnesia.spec index 204d1519cb..653e515317 100644 --- a/lib/mnesia/test/mnesia.spec +++ b/lib/mnesia/test/mnesia.spec @@ -42,9 +42,6 @@ {skip_cases,"../mnesia_test",mnesia_measure_test, [measure_all_api_functions], "Not yet implemented"}. -{skip_cases,"../mnesia_test",mnesia_measure_test, - [mnemosyne_vs_mnesia_kernel], - "Not yet implemented"}. {skip_cases,"../mnesia_test",mnesia_examples_test, [company], "Not yet implemented"}. diff --git a/lib/mnesia/test/mnesia_SUITE.erl b/lib/mnesia/test/mnesia_SUITE.erl index 2267a94164..5dbb80d4eb 100644 --- a/lib/mnesia/test/mnesia_SUITE.erl +++ b/lib/mnesia/test/mnesia_SUITE.erl @@ -105,7 +105,6 @@ groups() -> {otp_r4b, [], [{mnesia_config_test, access_module}, {mnesia_config_test, dump_log_load_regulation}, - {mnesia_config_test, embedded_mnemosyne}, {mnesia_config_test, ignore_fallback_at_startup}, {mnesia_config_test, max_wait_for_decision}, {mnesia_consistency_test, consistency_after_restore}, diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl index 93510d539c..fd294780da 100644 --- a/lib/mnesia/test/mnesia_config_test.erl +++ b/lib/mnesia/test/mnesia_config_test.erl @@ -36,7 +36,6 @@ dump_log_load_regulation/1, dump_log_update_in_place/1, - embedded_mnemosyne/1, event_module/1, ignore_fallback_at_startup/1, inconsistent_database/1, @@ -104,7 +103,7 @@ end_per_testcase(Func, Conf) -> all() -> [access_module, auto_repair, backup_module, debug, dir, dump_log_load_regulation, {group, dump_log_thresholds}, - dump_log_update_in_place, embedded_mnemosyne, + dump_log_update_in_place, event_module, ignore_fallback_at_startup, inconsistent_database, max_wait_for_decision, send_compressed, app_test, {group, schema_config}, @@ -610,45 +609,6 @@ dump_log_load_regulation(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -embedded_mnemosyne(doc) -> - ["Start Mnemosyne as an embedded part of Mnesia", - "on some of the nodes"]; -embedded_mnemosyne(suite) -> - []; -embedded_mnemosyne(Config) when is_list(Config) -> - Nodes = ?acquire_nodes(1, Config), - Param = embedded_mnemosyne, - - %% Normal - NoMnem = false, - ?match(NoMnem, mnesia:system_info(Param)), - ?match(undefined, whereis(mnemosyne_catalog)), - ?match([], mnesia_test_lib:stop_mnesia(Nodes)), - - %% Bad - Bad = arne_anka, - ?match({error, {bad_type, Param, Bad}}, - mnesia:start([{Param, Bad}])), - - case code:priv_dir(mnemosyne) of - {error, _} -> %% No mnemosyne on later systems - ok; - _ -> - %% Mnemosyne as embedded application - Mnem = true, - ?match(undefined, whereis(mnemosyne_catalog)), - ?match(ok,mnesia:start([{Param, Mnem}])), - ?match(Mnem, mnesia:system_info(Param)), - ?match(Pid when is_pid(Pid), whereis(mnemosyne_catalog)), - ?match([], mnesia_test_lib:stop_mnesia(Nodes)), - ?match(undefined, whereis(mnemosyne_catalog)) - end, - ?verify_mnesia([], Nodes), - ?cleanup(1, Config), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - ignore_fallback_at_startup(doc) -> ["Start Mnesia without rollback of the database to the fallback. ", "Once Mnesia has been (re)started the installed fallback should", diff --git a/lib/mnesia/test/mnesia_measure_test.erl b/lib/mnesia/test/mnesia_measure_test.erl index e63689d83a..dfed302814 100644 --- a/lib/mnesia/test/mnesia_measure_test.erl +++ b/lib/mnesia/test/mnesia_measure_test.erl @@ -72,8 +72,7 @@ groups() -> resource_consumption_at_full_load]}, {benchmarks, [], [{group, meter}, cost, dbn_meters, - measure_all_api_functions, {group, tpcb}, - mnemosyne_vs_mnesia_kernel]}, + measure_all_api_functions, {group, tpcb}]}, {tpcb, [], [ram_tpcb, disc_tpcb, disc_only_tpcb]}, {meter, [], [ram_meter, disc_meter, disc_only_meter]}]. diff --git a/lib/orber/src/orber_ifr_exceptiondef.erl b/lib/orber/src/orber_ifr_exceptiondef.erl index 7665d3d1bc..94c25cc4a5 100644 --- a/lib/orber/src/orber_ifr_exceptiondef.erl +++ b/lib/orber/src/orber_ifr_exceptiondef.erl @@ -111,26 +111,6 @@ cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_ExceptionDef, ObjType) -> describe({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) -> orber_ifr_contained:describe({ObjType,ObjID}). -%%% *** This function should be removed. Use -%%% orber_ifr_repository:lookup_id/2 instead. - -%%lookup_id(SearchId) -> -%% _F = fun() -> -%% Q = query [X.ir_Internal_ID || X <- table(ir_ExceptionDef)] -%% end, -%% mnemosyne:eval(Q) -%% end, -%% case orber_ifr_utils:ifr_transaction_read(_F) of -%% ?read_check_2() -> -%% {ok, []}; -%% ?read_check_1(Rep_IDs) -> -%% ExceptionDefs = lists:map(fun(X) -> {ir_ExceptionDef, X} end, -%% Rep_IDs), -%% {ok, lists:filter(fun(X) -> orber_ifr_exceptiondef:'_get_id'(X) == -%% SearchId end, -%% ExceptionDefs)} -%% end. - move({ObjType, ObjID}, New_container, New_name, New_version) ?tcheck(ir_ExceptionDef, ObjType) -> orber_ifr_contained:move({ObjType,ObjID},New_container,New_name, diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl index 4a0f70ba71..9d591c0d05 100644 --- a/lib/parsetools/test/leex_SUITE.erl +++ b/lib/parsetools/test/leex_SUITE.erl @@ -649,7 +649,6 @@ reserved_word('fun') -> true; reserved_word('if') -> true; reserved_word('let') -> true; reserved_word('of') -> true; -reserved_word('query') -> true; reserved_word('receive') -> true; reserved_word('when') -> true; reserved_word('bnot') -> true; diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index b8af89d040..bd20a5546b 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.17 +PUBLIC_KEY_VSN = 0.18 diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 826a11f1f4..cbd8166bb9 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -19,12 +19,14 @@ {"%VSN%", [ + {<<"2.1.2">>, [{restart_application, ssh}]}, {<<"2.1.1">>, [{restart_application, ssh}]}, {<<"2.1">>, [{restart_application, ssh}]}, {<<"2.0\\.*">>, [{restart_application, ssh}]}, {<<"1\\.*">>, [{restart_application, ssh}]} ], [ + {<<"2.1.2">>, [{restart_application, ssh}]}, {<<"2.1.1">>, [{restart_application, ssh}]}, {<<"2.1">>,[{restart_application, ssh}]}, {<<"2.0\\.*">>, [{restart_application, ssh}]}, diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index b5a0aa2e05..193f877b98 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -31,11 +31,6 @@ stop_listener/1, stop_listener/2, stop_daemon/1, stop_daemon/2, shell/1, shell/2, shell/3]). --deprecated({sign_data, 2, next_major_release}). --deprecated({verify_data, 3, next_major_release}). - --export([sign_data/2, verify_data/3]). - %%-------------------------------------------------------------------- %% Function: start([, Type]) -> ok %% @@ -394,8 +389,8 @@ handle_ssh_option({public_key_alg, Value} = Opt) when Value == 'ssh-rsa'; Value Opt; handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), length(Value) >= 1 -> case handle_pref_algs(Value, []) of - true -> - Opt; + {true, NewOpts} -> + NewOpts; _ -> throw({error, {eoptions, Opt}}) end; @@ -503,38 +498,3 @@ inetopt(false) -> %%% %% Deprecated %%% - -%%-------------------------------------------------------------------- -%% Function: sign_data(Data, Algorithm) -> binary() | -%% {error, Reason} -%% -%% Data = binary() -%% Algorithm = "ssh-rsa" -%% -%% Description: Use SSH key to sign data. -%%-------------------------------------------------------------------- -sign_data(Data, Algorithm) when is_binary(Data) -> - case ssh_file:user_key(Algorithm,[]) of - {ok, Key} when Algorithm == "ssh-rsa" -> - public_key:sign(Data, sha, Key); - Error -> - Error - end. - -%%-------------------------------------------------------------------- -%% Function: verify_data(Data, Signature, Algorithm) -> ok | -%% {error, Reason} -%% -%% Data = binary() -%% Signature = binary() -%% Algorithm = "ssh-rsa" -%% -%% Description: Use SSH signature to verify data. -%%-------------------------------------------------------------------- -verify_data(Data, Signature, Algorithm) when is_binary(Data), is_binary(Signature) -> - case ssh_file:user_key(Algorithm, []) of - {ok, #'RSAPrivateKey'{publicExponent = E, modulus = N}} when Algorithm == "ssh-rsa" -> - public_key:verify(Data, sha, Signature, #'RSAPublicKey'{publicExponent = E, modulus = N}); - Error -> - Error - end. diff --git a/lib/ssh/src/ssh_client_key_api.erl b/lib/ssh/src/ssh_client_key_api.erl index eed0b85f47..58054a9fc5 100644 --- a/lib/ssh/src/ssh_client_key_api.erl +++ b/lib/ssh/src/ssh_client_key_api.erl @@ -26,7 +26,7 @@ Algorithm :: 'ssh-rsa'| 'ssh-dss'| atom(), ConnectOptions :: proplists:proplist()) -> boolean(). --callback user_key(Algorithm :: 'ssh-rsa'| 'ssh-dss'| atom(), ConnectOptions :: proplists:proplists()) -> +-callback user_key(Algorithm :: 'ssh-rsa'| 'ssh-dss'| atom(), ConnectOptions :: proplists:proplist()) -> {ok, PrivateKey :: #'RSAPrivateKey'{}| #'DSAPrivateKey'{} | term()} | {error, string()}. diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 921ec2206a..71666a3179 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.1.2 +SSH_VSN = 2.1.3 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index 49bbd5d27d..73cda03b2f 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1999</year><year>2012</year> + <year>1999</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -22,10 +22,6 @@ </legalnotice> <title>SSL Release Notes</title> - <prepared>Peter Högfeldt</prepared> - <docno></docno> - <date>2003-08-03</date> - <rev>G</rev> <file>notes.xml</file> </header> <p>This document describes the changes made to the SSL application.</p> @@ -605,1285 +601,7 @@ </item> </list> </section> - - </section> - - - <section><title>SSL 3.11.1</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixed handling of several ssl/tls packets arriving at the - same time. This was broken during a refactoring of the - code.</p> - <p> - Own Id: OTP-8679</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - Added missing checks for padding and Mac value. Removed - code for export ciphers and DH certificates as we decided - not to support them.</p> - <p> - Own Id: OTP-7047</p> - </item> - <item> - <p> - New ssl will no longer return esslerrssl to be backwards - compatible with old ssl as this hids infomation from the - user. format_error/1 has been updated to support new ssl.</p> - <p> - *** POTENTIAL INCOMPATIBILITY ***</p> - <p> - Own Id: OTP-7049</p> - </item> - <item> - <p> - New ssl now supports secure renegotiation as described by - RFC 5746.</p> - <p> - Own Id: OTP-8568</p> - </item> - <item> - <p> - Alert handling has been improved to better handle - unexpected but valid messages and the implementation is - also changed to avoid timing related issues that could - cause different error messages depending on network - latency. Packet handling was sort of broken but would - mostly work as expected when socket was in binary mode. - This has now been fixed.</p> - <p> - Own Id: OTP-8588</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.11</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixes handling of the option fail_if_no_peer_cert and - some undocumented options. Thanks to Rory Byrne.</p> - <p> - Own Id: OTP-8557</p> - </item> - </list> - </section> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - Support for Diffie-Hellman. ssl-3.11 requires - public_key-0.6.</p> - <p> - Own Id: OTP-7046</p> - </item> - <item> - <p> - New ssl now properly handles ssl renegotiation, and - initiates a renegotiation if ssl/ltls-sequence numbers - comes close to the max value. However RFC-5746 is not yet - supported, but will be in an upcoming release.</p> - <p> - Own Id: OTP-8517</p> - </item> - <item> - <p> - When gen_tcp is configured with the {packet,http} option, - it automatically switches to expect HTTP Headers after a - HTTP Request/Response line has been received. This update - fixes ssl to behave in the same way. Thanks to Rory - Byrne.</p> - <p> - Own Id: OTP-8545</p> - </item> - <item> - <p> - Ssl now correctly verifies the extended_key_usage - extension and also allows the user to verify application - specific extensions by supplying an appropriate fun.</p> - <p> - Own Id: OTP-8554 Aux Id: OTP-8553 </p> - </item> - <item> - <p> - Fixed ssl:transport_accept/2 to return properly when - socket is closed. Thanks to Rory Byrne.</p> - <p> - Own Id: OTP-8560</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.9</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixed a crash in the certificate certification part.</p> - <p> - Own Id: OTP-8510 Aux Id: seq11525 </p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.8</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p><c>ssl:send/2</c> ignored packet option, fix provided - by YAMASHINA Hio.</p> - <p>Fixed a file cache bug which caused problems when the - same file was used for both cert and cacert.</p> - <p>Allow <c>ssl:listen/2</c> to be called with option - {ssl_imp, old}.</p> - <p> Fixed ssl:setopts(Socket, binary) which didn't work - for 'new' ssl.</p>. - <p> - Own Id: OTP-8441</p> - </item> - <item> - <p> - Do a controlled shutdown if a non ssl packet arrives as - the first packet.</p> - <p> - Own Id: OTP-8459 Aux Id: seq11505 </p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p>Fixed session reuse (in new_ssl), thanks Wil Tan.</p> - <p>Send CA list during Certificate Request (in new_ssl) , - thanks Wil Tan.</p> <p><c>NOTE</c>: SSL (new_ssl) - requires public_key-0.5.</p> - <p> - Own Id: OTP-8372</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.7</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - A ticker process could potentially be blocked - indefinitely trying to send a tick to a node not - responding. If this happened, the connection would not be - brought down as it should.</p> - <p> This requires erts-5.7.4 and kernel-2.13.4 or later - to be able to get the erlang distribution over ssl to work.</p> - <p> - Own Id: OTP-8218</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The documentation is now built with open source tools - (xsltproc and fop) that exists on most platforms. One - visible change is that the frames are removed.</p> - <p> - Own Id: OTP-8250</p> - </item> - <item> - <p> - Code cleanup from Kostis.</p> - <p> - Own Id: OTP-8260</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.6</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - The ssl:ssl_accept/3 issue was not properly fixed in the - previous patch, see OTP-8244.</p> - <p> - Own Id: OTP-8275 Aux Id: seq11451 </p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.5</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Allow clients to not send certificates if option - <c>fail_if_no_peer_cert</c> was not set.</p> - <p> - Own Id: OTP-8224</p> - </item> - <item> - <p>An ssl:ssl_accept/3 could crash a connection if the - timing was wrong.</p> <p>Removed info message if the - socket closed without a proper disconnect from the ssl - layer. </p> <p>ssl:send/2 is now blocking until the - message is sent.</p> - <p> - Own Id: OTP-8244 Aux Id: seq11420 </p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.4</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - A client could avoid a certificate check if the client - code didn't send the requested certificate.</p> - <p> - Own Id: OTP-8137</p> - </item> - </list> - </section> - -</section> - -<section><title>SSL 3.10.3</title> - - <section><title>Improvements and New Features</title> - <list> - <item> - <p>Packet handling was not implemented correctly.</p> - <p>Inet option handling support have been improved.</p> - <p>The <c>verify_fun</c> is now invoked even if - verify_peer is used, that implies that by default - {bad_cert,unknown_ca} is an accepted fault during the - client connection phase. The check can still be done by - suppling another verify_fun.</p> - <p> - Own Id: OTP-8011 Aux Id: seq11287 </p> - </item> - </list> - </section> - -</section> - - -<section><title>SSL 3.10.2</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - A "new_ssl" socket was not closed if the controlling - process died without calling ssl:close/1.</p> - <p> - Own Id: OTP-7963 Aux Id: seq11276 </p> - </item> - </list> </section> - -</section> - -<section><title>SSL 3.10.1</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Fixed bug that caused the ssl handshake finished message - to be calculated wrongly under the circumstances that the - server did not send the trusted cert and that the - previous cert did not have the extension telling us the - trusted certs name. This manifested it self as - bad_record_mac alert from the server.</p> - <p> - Own Id: OTP-7878</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - The cacertsfile option is now optional for ssl servers.</p> - <p> - Own Id: OTP-7656</p> - </item> - <item> - <p> - For the ssl client the options cacertfile, certfile and - keyfile are now optional as they are not always needed - depending on configuration of the client itself and the - configuration of the server. Also as PEM-files may - contain more than one entry the keyfile option will - default to the same file as given by the certfile option.</p> - <p> - Own Id: OTP-7870</p> - </item> - <item> - <p> - Added new ssl client option verify_fun.</p> - <p> - Own Id: OTP-7871</p> - </item> - </list> - </section> - -</section> - - <section><title>SSL 3.10</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - Error log entries are now formatted correctly.</p> - <p> - Own Id: OTP-7258</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - All handling of X509-certificates and public keys have - been moved to the new application public_key.</p> - <p> - Own Id: OTP-6894</p> - </item> - <item> - <p> - New ssl now supports SSL-3.0 and TLS-1.0</p> - <p> - Own Id: OTP-7037</p> - </item> - <item> - <p> - New ssl now supports all inet-packet types.</p> - <p> - Own Id: OTP-7039</p> - </item> - <item> - <p> - The new ssl-server is now able to send a certificate - request to the client. However new options may be - introduced later to fully support all features regarding - certificate requests.</p> - <p> - Own Id: OTP-7150</p> - </item> - </list> - </section> - - - <section><title>Known Bugs and Problems</title> - <list> - <item> - <p> - Running erlang distribution over ssl don't work as - described in the documentation.</p> - <p> - Own Id: OTP-7536</p> - </item> - </list> - </section> - - </section> - - - <section><title>SSL 3.9</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> - <item> - <p> - ssl_prim.erl was passing an FD rather than an #sslsocket - to ssl_broker:ssl_accept_prim. This could cause problems - in the deprecated accept function, this will not cause - any more problems however this function is deprecated!</p> - <p> - Own Id: OTP-6926</p> - </item> - <item> - <p> - Erlang distribution over ssl was broken after R11B-0, - this has now been fixed.</p> - <p> - Own Id: OTP-7004</p> - </item> - </list> - </section> - - - <section><title>Improvements and New Features</title> - <list> - <item> - <p> - All inet options are available in the new ssl - implementation that is released as a alfa in ssl-3.9 and - will replace the old implementation in ssl-4.0. This will - not be fixed in the old implementation.</p> - <p> - Own Id: OTP-4677</p> - </item> - <item> - <p> - The new ssl implementation released as a alfa in this - version supports upgrading of a tcp connection to an ssl - connection so that http client and servers may implement - RFC 2817.</p> - <p> - Own Id: OTP-5510</p> - </item> - <item> - <p>A new implementation of ssl is released as a alfa - version in ssl-3.9 it will later replace the old - implementation in ssl-4.0. The new implementation can be - accessed by providing the option {ssl_imp, new} to the - ssl:connect and ssl:listen functions.</p> - <p>The new implementation is Erlang based and all logic - is in Erlang and only payload encryption calculations are - done in C via the crypto application. The main reason for - making a new implementation is that the old solution was - very crippled as the control of the ssl-socket was deep - down in openssl making it hard if not impossible to - support all inet options, ipv6 and upgrade of a tcp - connection to an ssl connection. The alfa version has a - few limitations that will be removed before the ssl-4.0 - release. Main differences and limitations in the alfa are - listed below.</p> - - <list type="bulleted"> <item>New ssl requires the crypto - application.</item> <item>The option reuseaddr is - supported and the default value is false as in gen_tcp. - Old ssl is patched to accept that the option is set to - true to provide a smoother migration between the - versions. In old ssl the option is hard coded to - true.</item> <item>ssl:version/0 is replaced by - ssl:versions/0</item> <item>ssl:ciphers/0 is replaced by - ssl:cipher_suites/0</item> <item>ssl:pid/1 is a - meaningless function in new ssl and will be deprecated in - ssl-4.0 until it is removed it will return a valid but - meaningless pid.</item> <item>New API functions are - ssl:shutdown/2, ssl:cipher_suites/[0,1] and - ssl:versions/0</item> <item>Diffie-Hellman keyexchange is - not supported.</item> <item>Not all inet packet types are - supported.</item> <item>CRL and policy certificate - extensions are not supported.</item> <item>In this alfa - only sslv3 is enabled, although tlsv1 and tlsv1.1 - versions are implemented and will be supported in future - versions.</item> <item>For security reasons sslv2 is not - supported.</item> </list> - <p> - Own Id: OTP-6619</p> - </item> - <item> - <p> - New ssl implementation, released as alfa in ssl-3.9, - supports ipv6. It will not be supported in the old - implementation.</p> - <p> - Own Id: OTP-6637 Aux Id: OTP-6636 </p> - </item> - </list> - </section> - - </section> - - <section> - <title>SSL 3.1.1.1</title> - - <section> - <title>Minor Makefile changes</title> - <list type="bulleted"> - <item> - <p>Removed use of <c>erl_flags</c> from Makefile.</p> - <p>Own Id: OTP-6689</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.1.1</title> - - <section> - <title>Crash on error in ssl_accept</title> - <list type="bulleted"> - <item> - <p>A bug in ssl_accept could cause all ssl - connections to hang when a connection - attempt was closed by the client while - the server was in <c>ssl_accept</c>.</p> - <p>Own Id: OTP-6612 Aux Id: seq10599</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.1</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>SSL now uses a two-phase accept, with a separate accept - calls for the socket and the ssl protocol. This avoids - timeouts when a client doesn't initiate ssl handshake.</p> - <p>With the old implementation of accept, the server - was locked by a client, if the client didn't do - proper ssl handshake.</p> - <p>Own Id: OTP-6418 Aux Id: seq10105</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.12</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>An integer array pointing to a struct pollfd array, is - now reset before file descriptors are collected to be - included in a call to poll(). This is to prevent file - descriptors to be mixed up.</p> - <p>Own Id: OTP-6084</p> - </item> - <item> - <p>The generation of the module ssl_pkix_oid contained - multiple identifiers, which made the mapping between - atoms and identifiers not one-to-one.</p> - <p>Own Id: OTP-6085</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.11</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The state of a connection in active mode could be in a - restrictive state, so that an internal tcp_closed message - was incorrectly considered illegal, resulting in a - premature termination of the connection process.</p> - <p>Own Id: OTP-5972 Aux Id: seq10188 </p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.10</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Erlang distribution over SSL was broken. Corrected. - (Thanks to Fredrik Thulin.)</p> - <p>Own Id: OTP-5863</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.9</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The port program for the ssl application could waste huge - amounts of CPU time if a write could not be completed - directly and was put in the write queue. (Only on platforms - where poll() is used, such as Solaris and Linux.)</p> - <p>Own Id: OTP-5784</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.8</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>A process reading only a portion of a sufficiently large - amount of data from an accepted socket, and then quering - the ssl library (e.g. ssl:getpeername()), would cause a - global deadlock in the esock port program.</p> - <p>Own Id: OTP-5702</p> - </item> - <item> - <p>A spelling error in the module <c>ssl_pkix</c> caused the - call to <c>ssl:peercert/2</c> to fail when the option - <c>subject</c> was used.</p> - <p>Own Id: OTP-5708</p> - </item> - <item> - <p>Because fopen() on Solaris 8 can't handle file - descriptor numbers above 255, reading of certificate - files would fail if all file descriptors below 256 were - in use (typically, if many connections were open). This - problem has been worked around.</p> - <p>The ssl application's port program used to use - select(), which meant that it could not handle more than - FD_SETSIZE file descriptors (usually 1024). To eliminate - that limitation, poll() is now used on all platforms that - support it.</p> - <p>Solaris/Sparc, 64-bit emulator: The SO_REUSEADDR - option was not set for listen sockets, which essentially - made the ssl application unusable. Corrected.</p> - <p>The default listen queue size for ssl port program was - changed to 128 (from 5).</p> - <p>Own Id: OTP-5755 Aux Id: seq10068 </p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.7</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The R/W buffer length i esock.c was too small. It has - been increased from 4k to 32k.</p> - <p>Own Id: OTP-5620</p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.6</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>A configuration option for choosing protocol versions has - been added (<c>sslv2</c>, <c>sslv3</c>, and - <c>tlsv1</c>).</p> - <p>Own Id: OTP-5429 Aux Id: seq9755 </p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.5</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Linked in drivers in the crypto, and asn1 applications - are now compiled with the -D_THREAD_SAFE and -D_REENTRANT - switches on unix when the emulator has thread support - enabled.</p> - <p>Linked in drivers on MacOSX are not compiled with the - undocumented -lbundle1.o switch anymore. Thanks to Sean - Hinde who sent us a patch.</p> - <p>Linked in driver in crypto, and port programs in ssl, now - compiles on OSF1.</p> - <p>Minor makefile improvements in runtime_tools.</p> - <p>Own Id: OTP-5346</p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.4</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p><c>ssl:recv/3</c> with finite timeout value, closed the - connection at timeout.</p> - <p>Own Id: OTP-4882</p> - </item> - </list> - </section> - </section> - - <section> - <title>Ssl 3.0.3</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>When a file descriptor was marked for closing, and - end-of-file condition had already been detected, the file - descriptor was never closed.</p> - <p>Own Id: OTP-5093 Aux Id: seq8806 </p> - </item> - <item> - <p>When the number of open file descriptors reached - FD_SETSIZE, the SSL port program entered a busy loop.</p> - <p>Own Id: OTP-5094 Aux Id: seq8806 </p> - </item> - </list> - </section> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The SSL application now supports SSL sessions for - servers, which typically speeds up HTTP requests from - browsers.</p> - <p>Own Id: OTP-5095</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 3.0.2</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The UTF8String type is now defined in asn1-1.4.4.2 and - later. Therefore the definitions of UTF8String has been - removed from the ASN.1 modules PKIX1Explicit88.asn1 and - PKIXAttributeCertificate.asn1. The SSL application can now - only be built using asn-1.4.4.2 or later.</p> - <p>OwnId: OTP-4971.</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL-3.0. - </p> - </section> - </section> - - <section> - <title>SSL 3.0.1</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>An unexpected object identifier would crash <c>ssl:peercert</c>. </p> - <p>OwnId: OTP-4771.</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL-3.0. - </p> - </section> - </section> - - <section> - <title>SSL 3.0</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The <c>cache_timout</c> option was silently ignored. It had - to do with SSL sessions, where multiple connections can occur. - Since the Erlang SSL application does not support sessions the - option is still ignored, and consequently the documentation - about it has been removed.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>The Erlang SSL application is now based on OpenSSL version - 0.9.7a. OpenSSL 0.9.6 should also work.</p> - <p>OwnId: OTP-4002</p> - </item> - <item> - <p>When connecting it is now possible to bind to a local address - and local port. </p> - <p>OwnId: OTP-4675</p> - </item> - <item> - <p>The <c>ssl_esock</c> port program is now part of the - distribution and thus does not have to be created - explicitly. It is dynamically linked to OpenSSL - libraries in a "standard" location (typically - <c>/usr/local/lib</c> on UNIX; in the path on Win32).</p> - <p>OwnId: - OTP-4676</p> - </item> - <item> - <p>The new functions <c>ssl:peercert/1/2</c> provide information - from the certificate of a peer of a connection.</p> - <p>OwnId: OTP-4680 - <br></br> -Aux Id: seq7688</p> - </item> - <item> - <p>The function <c>ssl:port/1</c> has been removed from the - documentation, but not from the <c>ssl</c> interface module. - The recommendation is to use <c>ssl:peername/1</c> - instead, which provides both address and port of the peer.</p> - <p>OwnId: OTP-4681 </p> - </item> - <item> - <p>New User's Guide documentation has been added.</p> - <p>OwnId: OTP-4682 </p> - </item> - <item> - <p>The old <c>ssl_socket</c> interface has been removed and also - the documentation of it. </p> - <p>OwnId: OTP-4683 </p> - </item> - <item> - <p>The use of ephemeral RSA keys is now supported. It is - a global configuration option (see the ssl(6) manual page).</p> - <p>OwnId: OTP-4691.</p> - </item> - </list> - </section> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The option <c>cacertfile</c> is now in effect, and can - therefore no longer be set with the OS environment - variable SSL_CERT_FILE (which did set the same value for - all connections). </p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>There was a synchronization error at closing of an SSL - connection. </p> - <p>OwnId: OTP-4435 - <br></br> -Aux Id: seq7534</p> - </item> - <item> - <p>C macros in <c>debuglog.c</c> were not ANSI C compliant.</p> - <p>OwnId: OTP-4674</p> - </item> - <item> - <p>The <c>binary</c> option was not properly handled.</p> - <p>OwnId: OTP-4678</p> - </item> - <item> - <p>The <c>ssl:format_error/1</c> did not consider <c>inet</c> - error codes, nor did it have a catch all for unknown error - codes.</p> - <p>OwnId: OTP-4679</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <list type="bulleted"> - <item> - <p>Change of controlling process in not OTP compliant. </p> - <p>OwnId; OTP-4712</p> - </item> - <item> - <p>There is still no way to restrict the cipher sizes. </p> - <p>OwnId: OTP-4712</p> - </item> - <item> - <p>The <c>keep_alive</c> and <c>reuse_addr</c> options will be - added in a future release. </p> - <p>OwnId: OTP-4677</p> - </item> - <item> - <p>There is currently no way to restrict the SSL/TLS - protocol versions to use. In a future release this will be - supported as a configuration option, and as an option for - each connection as well. </p> - <p>OwnId: OTP-4711.</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.6</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>There was a synchronization error at closing, which could - result in that an SSL socket was removed prematurely, resulting - in that a user process referring to it received an unexpected - exit.</p> - <p>OwnId: OTP-4435 - <br></br> -Aux Id: seq7600</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL 2.2 . </p> - </section> - </section> - - <section> - <title>SSL 2.3.5</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Setting of the option `nodelay' caused the SSL port program - to dump core.</p> - <p>OwnId: OTP-4380 - <br></br> -Aux Id: -</p> - </item> - <item> - <p>Setting of the option '{active, once}' in <c>setopts</c> was - wrong, causing a correct socket message to be regarded as - erroneous. </p> - <p>OwnId: OTP-4380 - <br></br> -Aux Id: -</p> - </item> - <item> - <p>A self-signed peer certificate was always rejected with the - error `eselfsignedcert', irrespective of the `depth' value. </p> - <p>OwnId: OTP-4374 - <br></br> -Aux Id: seq7417</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <p>See SSL 2.2 . </p> - </section> - </section> - - <section> - <title>SSL 2.3.4</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>All TCP options allowed in gen_tcp, are now also allowed in - SSL, except the option <c>{reuseaddr, Boolean}</c>. A new - function <c>getopts</c> has been added to the SSL interface - module <c>ssl</c>. </p> - <p>OwnId: OTP-4305, OTP-4159</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.3</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The roles of the SSLeay and OpenSSL packages has been - clarified in the ssl(6) application manual page. Also - the URLs from which to download SSLeay has been updated.</p> - <p>OwnId: OTP-4002 - <br></br> -Aux Id: seq5269</p> - </item> - <item> - <p>A call to <c>ssl:listen(Port, Options)</c> with - <c>Options = []</c> resulted in the cryptic <c>{error, ebadf}</c> return value. The return value has been changed - to <c>{error, enooptions}</c>, and the behaviour has been - documented in the <c>listen/2</c> function.</p> - <p>OwnId: OTP-4016 - <br></br> -Aux Id: seq7006</p> - </item> - <item> - <p>Use of the option <c>{nodelay, boolean()}</c> crashed - the <c>ssl_server</c>.</p> - <p>OwnId: OTP-4070 - <br></br> -Aux Id:</p> - </item> - <item> - <p>A bug caused the Erlang distribution over ssl to fail. - This bug has now been fixed.</p> - <p>OwnId: OTP-4072 - <br></br> -Aux Id:</p> - </item> - <item> - <p>On Windows when the SSL port program encountered an - error code not anticipated it crashed. </p> - <p>OwnId: OTP-4132 - <br></br> -Aux Id:</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.2</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The <c>ssl:accept/1-2</c> function sometimes returned - <c>{error, {What, Where}}</c> instead of <c>{error, What}</c>, where <c>What</c> is an atom. </p> - <p>OwnId: OTP-3775 - <br></br> -Aux Id: seq4991</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3.1</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Sometimes the SSL portprogram would loop in an accept - loop, without terminating even when the SSL application - was stopped.. </p> - <p>OwnId: OTP-3691</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.3</title> - <p>Functions have been added to SSL to experimentally support - Erlang distribution. - </p> - </section> - - <section> - <title>SSL 2.2.1</title> - <p>The 2.2.1 version of SSL provides code replacement in runtime - by upgrading from, or downgrading to, versions 2.1 and 2.2. - </p> - </section> - - <section> - <title>SSL 2.2</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The restriction that only the creator of an SSL socket can - read from and write to the socket has been lifted.</p> - <p>OwnId: OTP-3301</p> - </item> - <item> - <p>The option <c>{packet, cdr}</c> for SSL sockets has been added, - which means that SSL sockets also supports CDR encoded packets.</p> - <p>OwnId: OTP-3302</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <list type="bulleted"> - <item> - <p>Setting of a CA certificate file with the <c>cacertfile</c> - option (in calls to <c>ssl:accept/1/2</c> or - <c>ssl:connect/3/4</c>) does not work due to weaknesses - in the SSLeay package. </p> - <p>A work-around is to set the OS environment variable - <c>SSL_CERT_FILE</c> before SSL is started. However, then - the CA certificate file will be global for all connections.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>When changing controlling process of an SSL socket, a - temporary process is started, which is not gen_server - compliant.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>Although there is a <c>cache</c> timeout option, it is - silently ignored.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>There is currently no way to restrict the cipher sizes.</p> - <p>OwnId: OTP-3146</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.1</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>The set of possible error reasons has been extended to - contain diagnostics on erroneous certificates and failures - to verify certificates.</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>The maximum number of simultaneous SSL connections on - Windows has been increased from 31 to 127.</p> - <p>OwnId: OTP-3145</p> - </item> - </list> - </section> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>A dead-lock occurring when write queues are not empty has - been removed. </p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>Error reasons have been unified and changed.</p> - <p>(** POTENTIAL INCOMPATIBILITY **)</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>On Windows a check of the existence of the environment - variable <c>ERLSRV_SERVICE_NAME</c> has been added. If - that variable is defined, the port program of the SSL - application will not terminated when a user logs off.</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>An error in the setting of the <c>nodelay</c> option - has been corrected.</p> - <p>OwnId: OTP-3145</p> - </item> - <item> - <p>The confounded notions of verify mode and verify depth has - been corrected. The option <c>verifydepth</c> has been - removed, and the two separate options <c>verify</c> and - <c>depth</c> has been added.</p> - <p>(** POTENTIAL INCOMPATIBILITY **)</p> - <p>OwnId: OTP-3145</p> - </item> - </list> - </section> - - <section> - <title>Known Bugs and Problems</title> - <list type="bulleted"> - <item> - <p>Setting of a CA certificate file with the <c>cacertfile</c> - option (in calls to <c>ssl:accept/1/2</c> or - <c>ssl:connect/3/4</c>) does not work due to weaknesses - in the SSLeay package. </p> - <p>A work-around is to set the OS environment variable - <c>SSL_CERT_FILE</c> before SSL is started. However, then - the CA certificate file will be global for all connections.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>When changing controlling process of an SSL socket, a - temporary process is started, which is not gen_server - compliant.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>Although there is a <c>cache</c> timeout option, it is - silently ignored.</p> - <p>OwnId: OTP-3146</p> - </item> - <item> - <p>There is currently no way to restrict the cipher sizes.</p> - <p>OwnId: OTP-3146</p> - </item> - </list> - </section> - </section> - - <section> - <title>SSL 2.0</title> - <p>A complete new version of SSL with separate I/O channels - for all connections with non-blocking I/O multiplexing.</p> - </section> </chapter> diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 9b1227fa7f..76e14860ec 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,24 +1,13 @@ %% -*- erlang -*- {"%VSN%", [ - {"5.1.1", [{restart_application, ssl}] - }, - {"5.1", [ - {load_module, ssl_connection, soft_purge, soft_purge, []} - ] - }, + {<<"5.1\\*">>, [{restart_application, ssl}]}, {<<"5.0\\*">>, [{restart_application, ssl}]}, {<<"4\\.*">>, [{restart_application, ssl}]}, {<<"3\\.*">>, [{restart_application, ssl}]} ], [ - {"5.1.1", [{restart_application, ssl}] - }, - {"5.1", [ - {load_module, ssl_connection, soft_purge, soft_purge, []} - ] - }, - {"5.1", [{restart_application, ssl}]}, + {<<"5.1\\*">>, [{restart_application, ssl}]}, {<<"5.0\\*">>, [{restart_application, ssl}]}, {<<"4\\.*">>, [{restart_application, ssl}]}, {<<"3\\.*">>, [{restart_application, ssl}]} diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl index 222b3f1ad7..f94a1136a0 100644 --- a/lib/ssl/src/ssl_alert.erl +++ b/lib/ssl/src/ssl_alert.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -36,8 +36,7 @@ %% Internal application API %%==================================================================== %%-------------------------------------------------------------------- --spec reason_code(#alert{}, client | server) -> closed | esslconnect | - esslaccept | string(). +-spec reason_code(#alert{}, client | server) -> closed | {essl, string()}. %% %% Description: Returns the error reason that will be returned to the %% user. @@ -45,12 +44,8 @@ reason_code(#alert{description = ?CLOSE_NOTIFY}, _) -> closed; -reason_code(#alert{description = ?HANDSHAKE_FAILURE}, client) -> - esslconnect; -reason_code(#alert{description = ?HANDSHAKE_FAILURE}, server) -> - esslaccept; reason_code(#alert{description = Description}, _) -> - description_txt(Description). + {essl, description_txt(Description)}. %%-------------------------------------------------------------------- -spec alert_txt(#alert{}) -> string(). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 94f76e0606..68f6a4d4c1 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1135,7 +1135,7 @@ init_certificates(#ssl_options{cacerts = CaCerts, {ok, _, _, _, _, _} = ssl_manager:connection_init(Certs, Role) catch Error:Reason -> - handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile, + handle_file_error(?LINE, Error, Reason, CACertFile, {ecacertfile, Reason}, erlang:get_stacktrace()) end, init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CertFile, Role). @@ -1157,7 +1157,7 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, OwnCert} catch Error:Reason -> - handle_file_error(?LINE, Error, Reason, CertFile, ecertfile, + handle_file_error(?LINE, Error, Reason, CertFile, {ecertfile, Reason}, erlang:get_stacktrace()) end; init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, _, _) -> @@ -1176,7 +1176,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) -> private_key(public_key:pem_entry_decode(PemEntry, Password)) catch Error:Reason -> - handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile, + handle_file_error(?LINE, Error, Reason, KeyFile, {ekeyfile, Reason}, erlang:get_stacktrace()) end; @@ -1234,7 +1234,7 @@ init_diffie_hellman(DbHandle,_, DHParamFile, server) -> catch Error:Reason -> handle_file_error(?LINE, Error, Reason, - DHParamFile, edhfile, erlang:get_stacktrace()) + DHParamFile, {edhfile, Reason}, erlang:get_stacktrace()) end. sync_send_all_state_event(FsmPid, Event) -> diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 13689ce7d8..14fba72d86 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2012. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -142,8 +142,14 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) -> new_session_id(Port) -> call({new_session_id, Port}). +%%-------------------------------------------------------------------- +-spec clean_cert_db(reference(), binary()) -> term(). +%% +%% Description: Send clean request of cert db to ssl_manager process should +%% be called by ssl-connection processes. +%%-------------------------------------------------------------------- clean_cert_db(Ref, File) -> - erlang:send_after(?CLEAN_CERT_DB, self(), {clean_cert_db, Ref, File}). + erlang:send_after(?CLEAN_CERT_DB, get(ssl_manager), {clean_cert_db, Ref, File}). %%-------------------------------------------------------------------- -spec register_session(inet:port_number(), #session{}) -> ok. @@ -320,19 +326,12 @@ handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) -> handle_info({clean_cert_db, Ref, File}, #state{certificate_db = [CertDb,RefDb, PemCache]} = State) -> - case ssl_certificate_db:ref_count(Ref, RefDb, 0) of - 0 -> - MD5 = crypto:md5(File), - case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of - [{Content, Ref}] -> - ssl_certificate_db:insert(MD5, Content, PemCache); - undefined -> - ok - end, - ssl_certificate_db:remove(Ref, RefDb), - ssl_certificate_db:remove_trusted_certs(Ref, CertDb); + + case ssl_certificate_db:lookup(Ref, RefDb) of + undefined -> %% Alredy cleaned + ok; _ -> - ok + clean_cert_db(Ref, CertDb, RefDb, PemCache, File) end, {noreply, State}; @@ -464,3 +463,19 @@ new_id(Port, Tries, Cache, CacheCb) -> _ -> new_id(Port, Tries - 1, Cache, CacheCb) end. + +clean_cert_db(Ref, CertDb, RefDb, PemCache, File) -> + case ssl_certificate_db:ref_count(Ref, RefDb, 0) of + 0 -> + MD5 = crypto:md5(File), + case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of + [{Content, Ref}] -> + ssl_certificate_db:insert(MD5, Content, PemCache); + _ -> + ok + end, + ssl_certificate_db:remove(Ref, RefDb), + ssl_certificate_db:remove_trusted_certs(Ref, CertDb); + _ -> + ok + end. diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 5ba71f9218..df84acacdc 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -84,7 +84,8 @@ basic_tests() -> alerts, send_close, connect_twice, - connect_dist + connect_dist, + clear_pem_cache ]. options_tests() -> @@ -536,6 +537,33 @@ connect_dist(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- + +clear_pem_cache() -> + [{doc,"Test that internal reference tabel is cleaned properly even when " + " the PEM cache is cleared" }]. +clear_pem_cache(Config) when is_list(Config) -> + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + [_,FilRefDb, _] = element(5, State), + {Server, Client} = basic_verify_test_no_close(Config), + 2 = ets:info(FilRefDb, size), + ssl:clear_pem_cache(), + _ = sys:get_status(whereis(ssl_manager)), + {Server1, Client1} = basic_verify_test_no_close(Config), + 4 = ets:info(FilRefDb, size), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + ct:sleep(5000), + _ = sys:get_status(whereis(ssl_manager)), + 2 = ets:info(FilRefDb, size), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1), + ct:sleep(5000), + _ = sys:get_status(whereis(ssl_manager)), + 0 = ets:info(FilRefDb, size). + +%%-------------------------------------------------------------------- peername() -> [{doc,"Test API function peername/1"}]. @@ -1567,8 +1595,8 @@ default_reject_anonymous(Config) when is_list(Config) -> [{ciphers,[Cipher]} | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error, "insufficient security"}, - Client, {error, "insufficient security"}). + ssl_test_lib:check_result(Server, {error, {essl, "insufficient security"}}, + Client, {error, {essl, "insufficient security"}}). %%-------------------------------------------------------------------- reuse_session() -> @@ -2641,6 +2669,26 @@ tcp_send_recv_result(Socket) -> {ok,"Hello world"} = gen_tcp:recv(Socket, 11), ok. +basic_verify_test_no_close(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + {Server, Client}. + basic_test(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -2659,7 +2707,6 @@ basic_test(Config) -> {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), ssl_test_lib:close(Client). diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 9677d98c1b..86e1d47be7 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -252,8 +252,8 @@ server_require_peer_cert_fail(Config) when is_list(Config) -> {from, self()}, {options, [{active, false} | BadClientOpts]}]), - ssl_test_lib:check_result(Server, {error, esslaccept}, - Client, {error, esslconnect}). + ssl_test_lib:check_result(Server, {error, {essl, "handshake failure"}}, + Client, {error, {essl, "handshake failure"}}). %%-------------------------------------------------------------------- @@ -293,14 +293,14 @@ verify_fun_always_run_client(Config) when is_list(Config) -> [{verify, verify_peer}, {verify_fun, FunAndState} | ClientOpts]}]), - %% Server error may be esslaccept or closed depending on timing + %% Server error may be {essl,"handshake failure"} or closed depending on timing %% this is not a bug it is a circumstance of how tcp works! receive {Server, ServerError} -> ct:print("Server Error ~p~n", [ServerError]) end, - ssl_test_lib:check_result(Client, {error, esslconnect}). + ssl_test_lib:check_result(Client, {error, {essl, "handshake failure"}}). %%-------------------------------------------------------------------- verify_fun_always_run_server() -> @@ -342,14 +342,14 @@ verify_fun_always_run_server(Config) when is_list(Config) -> [{verify, verify_peer} | ClientOpts]}]), - %% Client error may be esslconnect or closed depending on timing + %% Client error may be {essl, "handshake failure" } or closed depending on timing %% this is not a bug it is a circumstance of how tcp works! receive {Client, ClientError} -> ct:print("Client Error ~p~n", [ClientError]) end, - ssl_test_lib:check_result(Server, {error, esslaccept}). + ssl_test_lib:check_result(Server, {error, {essl, "handshake failure"}}). %%-------------------------------------------------------------------- @@ -380,7 +380,7 @@ client_verify_none_passive(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- cert_expired() -> - [{doc,"Test server with invalid signature"}]. + [{doc,"Test server with expired certificate"}]. cert_expired(Config) when is_list(Config) -> ClientOpts = ?config(client_verification_opts, Config), @@ -432,8 +432,8 @@ cert_expired(Config) when is_list(Config) -> {from, self()}, {options, [{verify, verify_peer} | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error, "certificate expired"}, - Client, {error, "certificate expired"}). + ssl_test_lib:check_result(Server, {error, {essl, "certificate expired"}}, + Client, {error, {essl, "certificate expired"}}). two_digits_str(N) when N < 10 -> lists:flatten(io_lib:format("0~p", [N])); @@ -679,7 +679,7 @@ delete_authority_key_extension([Head | Rest], Acc) -> %%-------------------------------------------------------------------- invalid_signature_server() -> - [{doc,"Test server with invalid signature"}]. + [{doc,"Test client with invalid signature"}]. invalid_signature_server(Config) when is_list(Config) -> ClientOpts = ?config(client_verification_opts, Config), @@ -710,8 +710,8 @@ invalid_signature_server(Config) when is_list(Config) -> {from, self()}, {options, [{verify, verify_peer} | ClientOpts]}]), - tcp_delivery_workaround(Server, {error, "bad certificate"}, - Client, {error,"bad certificate"}). + tcp_delivery_workaround(Server, {error, {essl, "bad certificate"}}, + Client, {error, {essl, "bad certificate"}}). %%-------------------------------------------------------------------- @@ -747,8 +747,8 @@ invalid_signature_client(Config) when is_list(Config) -> {from, self()}, {options, NewClientOpts}]), - tcp_delivery_workaround(Server, {error, "bad certificate"}, - Client, {error,"bad certificate"}). + tcp_delivery_workaround(Server, {error, {essl, "bad certificate"}}, + Client, {error, {essl, "bad certificate"}}). %%-------------------------------------------------------------------- @@ -829,8 +829,8 @@ unknown_server_ca_fail(Config) when is_list(Config) -> {verify_fun, FunAndState} | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error,"unknown ca"}, - Client, {error, "unknown ca"}). + ssl_test_lib:check_result(Server, {error, {essl, "unknown ca"}}, + Client, {error, {essl, "unknown ca"}}). %%-------------------------------------------------------------------- unknown_server_ca_accept_verify_none() -> @@ -947,10 +947,6 @@ tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> {Client, {error,closed}} -> server_msg(Server, ServerMsg); {Server, {error,closed}} -> - client_msg(Client, ClientMsg); - {Client, {error, esslconnect}} -> - server_msg(Server, ServerMsg); - {Server, {error, esslaccept}} -> client_msg(Client, ClientMsg) end. @@ -961,8 +957,8 @@ client_msg(Client, ClientMsg) -> {Client, {error,closed}} -> ct:print("client got close"), ok; - {Client, {error, esslconnect}} -> - ct:print("client got econnaborted"), + {Client, {error, Reason}} -> + ct:print("client got econnaborted: ~p", [Reason]), ok; Unexpected -> ct:fail(Unexpected) @@ -974,8 +970,8 @@ server_msg(Server, ServerMsg) -> {Server, {error,closed}} -> ct:print("server got close"), ok; - {Server, {error, esslaccept}} -> - ct:print("server got econnaborted"), + {Server, {error, Reason}} -> + ct:print("server got econnaborted: ~p", [Reason]), ok; Unexpected -> ct:fail(Unexpected) diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 76b302b1cb..8d96a70a6e 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -203,6 +203,67 @@ close(Pid) -> ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason]) end. + +check_result(Server, {error, SReason} = ServerMsg, Client, {error, closed} = ClientMsg) -> + receive + {Server, {error, {SReason, _}}} -> + receive + {Client, ClientMsg} -> + ok; + Unexpected -> + Reason = {{expected, {Client, ClientMsg}}, + {got, Unexpected}}, + ct:fail(Reason) + end; + {Client, ClientMsg} -> + receive + {Server, {error, {SReason, _}}} -> + ok; + Unexpected -> + Reason = {{expected, {Server,{error, {SReason, 'term()'}}}, + {got, Unexpected}}}, + ct:fail(Reason) + end; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Server, ServerMsg, Client, ClientMsg); + + Unexpected -> + Reason = {{expected, {Client, ClientMsg}}, + {expected, {Server, {error, {SReason, 'term()'}}}, {got, Unexpected}}}, + ct:fail(Reason) + end; + +check_result(Server, {error, closed} = ServerMsg, Client, {error, CReson} = ClientMsg) -> + receive + {Server, ServerMsg} -> + receive + {Client, {error, {CReson, _}}} -> + ok; + Unexpected -> + Reason = {{expected, {Client, {error, {CReson, 'term()'}}}, + {got, Unexpected}}}, + ct:fail(Reason) + end; + {Client, {error, {CReson, _}}} -> + receive + {Server, ServerMsg} -> + ok; + Unexpected -> + Reason = {{expected, {Server, ServerMsg}}, + {got, Unexpected}}, + ct:fail(Reason) + end; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Server, ServerMsg, Client, ClientMsg); + + Unexpected -> + Reason = {{expected, {Client, {error, {CReson, 'term()'}}}, + {expected, {Server, ServerMsg}}, {got, Unexpected}}}, + ct:fail(Reason) + end; + check_result(Server, ServerMsg, Client, ClientMsg) -> receive {Server, ServerMsg} -> @@ -233,6 +294,22 @@ check_result(Server, ServerMsg, Client, ClientMsg) -> ct:fail(Reason) end. +check_result(Pid, {error, Reason} = Err) when Reason == ecertfile; + Reason == ecacertfile; + Reason == ekeyfile; + Reason == edhfile -> + receive + {Pid, {error, {Reason, Str}}} when is_list(Str) -> + ok; + {Port, {data,Debug}} when is_port(Port) -> + io:format("openssl ~s~n",[Debug]), + check_result(Pid, Err); + Unexpected -> + Reason = {{expected, {Pid, {error, {Reason, "'appropriate error string'"}}}}, + {got, Unexpected}}, + ct:fail(Reason) + end; + check_result(Pid, Msg) -> receive {Pid, Msg} -> diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index d5e7d515fd..7c0c00bf36 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -902,7 +902,7 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> ok end, - ssl_test_lib:check_result(Server, {error,"protocol version"}), + ssl_test_lib:check_result(Server, {error, {essl, "protocol version"}}), process_flag(trap_exit, false). %%-------------------------------------------------------------------- diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index adfb29e639..cb73e86ede 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 5.1.2 +SSL_VSN = 5.2 diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl index 34c6ecc394..51def8c8e1 100644 --- a/lib/stdlib/examples/erl_id_trans.erl +++ b/lib/stdlib/examples/erl_id_trans.erl @@ -153,7 +153,6 @@ pattern({record,Line,Name,Pfs0}) -> pattern({record_index,Line,Name,Field0}) -> Field1 = pattern(Field0), {record_index,Line,Name,Field1}; -%% record_field occurs in query expressions pattern({record_field,Line,Rec0,Name,Field0}) -> Rec1 = expr(Rec0), Field1 = expr(Field0), @@ -431,10 +430,6 @@ expr({'catch',Line,E0}) -> %% No new variables added. E1 = expr(E0), {'catch',Line,E1}; -expr({'query', Line, E0}) -> - %% lc expression - E = expr(E0), - {'query', Line, E}; expr({match,Line,P0,E0}) -> E1 = expr(E0), P1 = pattern(P0), diff --git a/lib/stdlib/src/base64.erl b/lib/stdlib/src/base64.erl index 5d800e87b8..0068d82d43 100644 --- a/lib/stdlib/src/base64.erl +++ b/lib/stdlib/src/base64.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,7 +28,7 @@ %% of (some) functions of this module. %%------------------------------------------------------------------------- --type ascii_string() :: [1..255]. +-type ascii_string() :: [1..127]. %%------------------------------------------------------------------------- %% encode_to_string(ASCII) -> Base64String diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl index 1164ee49eb..3192879f09 100644 --- a/lib/stdlib/src/edlin.erl +++ b/lib/stdlib/src/edlin.erl @@ -22,10 +22,10 @@ %% A simple Emacs-like line editor. %% About Latin-1 characters: see the beginning of erl_scan.erl. --export([init/0,start/1,edit_line/2,prefix_arg/1]). +-export([init/0,start/1,start/2,edit_line/2,prefix_arg/1]). -export([erase_line/1,erase_inp/1,redraw_line/1]). -export([length_before/1,length_after/1,prompt/1]). --export([current_line/1]). +-export([current_line/1, current_chars/1]). %%-export([expand/1]). -export([edit_line1/2]). @@ -54,7 +54,12 @@ init() -> %% {undefined,Char,Rest,Cont,Requests} start(Pbs) -> - {more_chars,{line,Pbs,{[],[]},none},[{put_chars,unicode,Pbs}]}. + start(Pbs, none). + +%% Only two modes used: 'none' and 'search'. Other modes can be +%% handled inline through specific character handling. +start(Pbs, Mode) -> + {more_chars,{line,Pbs,{[],[]},Mode},[{put_chars,unicode,Pbs}]}. edit_line(Cs, {line,P,L,{blink,N}}) -> edit(Cs, P, L, none, [{move_rel,N}]); @@ -76,6 +81,10 @@ edit([C|Cs], P, {Bef,Aft}, Prefix, Rs0) -> edit(Cs, P, {Bef,Aft}, meta, Rs0); meta_left_sq_bracket -> edit(Cs, P, {Bef,Aft}, meta_left_sq_bracket, Rs0); + search_meta -> + edit(Cs, P, {Bef,Aft}, search_meta, Rs0); + search_meta_left_sq_bracket -> + edit(Cs, P, {Bef,Aft}, search_meta_left_sq_bracket, Rs0); ctlx -> edit(Cs, P, {Bef,Aft}, ctlx, Rs0); new_line -> @@ -115,6 +124,8 @@ edit([C|Cs], P, {Bef,Aft}, Prefix, Rs0) -> case do_op(Op, Bef, Aft, Rs0) of {blink,N,Line,Rs} -> edit(Cs, P, Line, {blink,N}, Rs); + {Line, Rs, Mode} -> % allow custom modes from do_op + edit(Cs, P, Line, Mode, Rs); {Line,Rs} -> edit(Cs, P, Line, none, Rs) end @@ -168,9 +179,15 @@ key_map($\^], none) -> auto_blink; key_map($\^X, none) -> ctlx; key_map($\^Y, none) -> yank; key_map($\e, none) -> meta; -key_map($), Prefix) when Prefix =/= meta -> {blink,$),$(}; -key_map($}, Prefix) when Prefix =/= meta -> {blink,$},${}; -key_map($], Prefix) when Prefix =/= meta -> {blink,$],$[}; +key_map($), Prefix) when Prefix =/= meta, + Prefix =/= search, + Prefix =/= search_meta -> {blink,$),$(}; +key_map($}, Prefix) when Prefix =/= meta, + Prefix =/= search, + Prefix =/= search_meta -> {blink,$},${}; +key_map($], Prefix) when Prefix =/= meta, + Prefix =/= search, + Prefix =/= search_meta -> {blink,$],$[}; key_map($B, meta) -> backward_word; key_map($D, meta) -> kill_word; key_map($F, meta) -> forward_word; @@ -188,6 +205,32 @@ key_map($D, meta_left_sq_bracket) -> backward_char; key_map($C, meta_left_sq_bracket) -> forward_char; key_map(C, none) when C >= $\s -> {insert,C}; +%% for search, we need smarter line handling and so +%% we cheat a bit on the dispatching, and allow to +%% return a mode. +key_map($\^H, search) -> {search, backward_delete_char}; +key_map($\177, search) -> {search, backward_delete_char}; +key_map($\^R, search) -> {search, skip_up}; +key_map($\^S, search) -> {search, skip_down}; +key_map($\n, search) -> {search, search_found}; +key_map($\r, search) -> {search, search_found}; +key_map($\^A, search) -> {search, search_quit}; +key_map($\^B, search) -> {search, search_quit}; +key_map($\^D, search) -> {search, search_quit}; +key_map($\^E, search) -> {search, search_quit}; +key_map($\^F, search) -> {search, search_quit}; +key_map($\t, search) -> {search, search_quit}; +key_map($\^L, search) -> {search, search_quit}; +key_map($\^T, search) -> {search, search_quit}; +key_map($\^U, search) -> {search, search_quit}; +key_map($\^], search) -> {search, search_quit}; +key_map($\^X, search) -> {search, search_quit}; +key_map($\^Y, search) -> {search, search_quit}; +key_map($\e, search) -> search_meta; +key_map($[, search_meta) -> search_meta_left_sq_bracket; +key_map(_, search_meta) -> {search, search_quit}; +key_map(_C, search_meta_left_sq_bracket) -> {search, search_quit}; +key_map(C, search) -> {insert_search,C}; key_map(C, _) -> {undefined,C}. %% do_op(Action, Before, After, Requests) @@ -196,6 +239,57 @@ do_op({insert,C}, Bef, [], Rs) -> {{[C|Bef],[]},[{put_chars, unicode,[C]}|Rs]}; do_op({insert,C}, Bef, Aft, Rs) -> {{[C|Bef],Aft},[{insert_chars, unicode, [C]}|Rs]}; +%% Search mode prompt always looks like (search)`$TERMS': $RESULT. +%% the {insert_search, _} handlings allow to share this implementation +%% correctly with group.erl. This module provides $TERMS, and group.erl +%% is in charge of providing $RESULT. +%% This require a bit of trickery. Because search disables moving around +%% on the line (left/right arrow keys and other shortcuts that just exit +%% search mode), we can use the Bef and Aft variables to hold each +%% part of the line. Bef takes charge of "(search)`$TERMS" and Aft +%% takes charge of "': $RESULT". +do_op({insert_search, C}, Bef, [], Rs) -> + Aft="': ", + {{[C|Bef],Aft}, + [{insert_chars, unicode, [C]++Aft}, {delete_chars,-3} | Rs], + search}; +do_op({insert_search, C}, Bef, Aft, Rs) -> + Offset= length(Aft), + NAft = "': ", + {{[C|Bef],NAft}, + [{insert_chars, unicode, [C]++NAft}, {delete_chars,-Offset} | Rs], + search}; +do_op({search, backward_delete_char}, [_|Bef], Aft, Rs) -> + Offset= length(Aft)+1, + NAft = "': ", + {{Bef,NAft}, + [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], + search}; +do_op({search, backward_delete_char}, [], _Aft, Rs) -> + Aft="': ", + {{[],Aft}, Rs, search}; +do_op({search, skip_up}, Bef, Aft, Rs) -> + Offset= length(Aft), + NAft = "': ", + {{[$\^R|Bef],NAft}, % we insert ^R as a flag to whoever called us + [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], + search}; +do_op({search, skip_down}, Bef, Aft, Rs) -> + Offset= length(Aft), + NAft = "': ", + {{[$\^S|Bef],NAft}, % we insert ^S as a flag to whoever called us + [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], + search}; +do_op({search, search_found}, _Bef, Aft, Rs) -> + "': "++NAft = Aft, + {{[],NAft}, + [{put_chars, unicode, "\n"}, {move_rel,-length(Aft)} | Rs], + search_found}; +do_op({search, search_quit}, _Bef, Aft, Rs) -> + "': "++NAft = Aft, + {{[],NAft}, + [{put_chars, unicode, "\n"}, {move_rel,-length(Aft)} | Rs], + search_quit}; %% do blink after $$ do_op({blink,C,M}, Bef=[$$,$$|_], Aft, Rs) -> N = over_paren(Bef, C, M), @@ -453,6 +547,9 @@ prompt({line,Pbs,_,_}) -> current_line({line,_,{Bef, Aft},_}) -> reverse(Bef, Aft ++ "\n"). +current_chars({line,_,{Bef,Aft},_}) -> + reverse(Bef, Aft). + %% %% expand(CurrentBefore) -> %% %% {yes,Expansion} | no %% %% Try to expand the word before as either a module name or a function diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index a0f7660ecf..ebabf8d700 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -1224,8 +1224,6 @@ macro_arg([{'try',Lr}|Toks], E, Arg) -> macro_arg(Toks, ['end'|E], [{'try',Lr}|Arg]); macro_arg([{'cond',Lr}|Toks], E, Arg) -> macro_arg(Toks, ['end'|E], [{'cond',Lr}|Arg]); -macro_arg([{'query',Lr}|Toks], E, Arg) -> - macro_arg(Toks, ['end'|E], [{'query',Lr}|Arg]); macro_arg([{Rb,Lrb}|Toks], [Rb|E], Arg) -> %Found matching close macro_arg(Toks, E, [{Rb,Lrb}|Arg]); macro_arg([T|Toks], E, Arg) -> diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 9a01e85006..642d972582 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -2159,9 +2159,7 @@ expr({op,_Line,_Op,L,R}, Vt, St) -> expr_list([L,R], Vt, St); %They see the same variables %% The following are not allowed to occur anywhere! expr({remote,Line,_M,_F}, _Vt, St) -> - {[],add_error(Line, illegal_expr, St)}; -expr({'query',Line,_Q}, _Vt, St) -> - {[],add_error(Line, {mnemosyne,"query"}, St)}. + {[],add_error(Line, illegal_expr, St)}. %% expr_list(Expressions, Variables, State) -> %% {UsedVarTable,State} diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 002abc11e8..8316462989 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -36,7 +36,7 @@ tuple record_expr record_tuple record_field record_fields if_expr if_clause if_clauses case_expr cr_clause cr_clauses receive_expr fun_expr fun_clause fun_clauses atom_or_var integer_or_var -try_expr try_catch try_clause try_clauses query_expr +try_expr try_catch try_clause try_clauses function_call argument_list exprs guard atomic strings @@ -54,7 +54,7 @@ char integer float atom string var '(' ')' ',' '->' ':-' '{' '}' '[' ']' '|' '||' '<-' ';' ':' '#' '.' 'after' 'begin' 'case' 'try' 'catch' 'end' 'fun' 'if' 'of' 'receive' 'when' -'andalso' 'orelse' 'query' +'andalso' 'orelse' 'bnot' 'not' '*' '/' 'div' 'rem' 'band' 'and' '+' '-' 'bor' 'bxor' 'bsl' 'bsr' 'or' 'xor' @@ -272,7 +272,6 @@ expr_max -> case_expr : '$1'. expr_max -> receive_expr : '$1'. expr_max -> fun_expr : '$1'. expr_max -> try_expr : '$1'. -expr_max -> query_expr : '$1'. list -> '[' ']' : {nil,?line('$1')}. @@ -432,9 +431,6 @@ try_clause -> var ':' expr clause_guard clause_body : L = ?line('$1'), {clause,L,[{tuple,L,['$1','$3',{var,L,'_'}]}],'$4','$5'}. -query_expr -> 'query' list_comprehension 'end' : - {'query',?line('$1'),'$2'}. - argument_list -> '(' ')' : {[],?line('$1')}. argument_list -> '(' exprs ')' : {'$2',?line('$1')}. diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index 0383ce6839..0e1156075a 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -510,8 +510,6 @@ lexpr({'fun',_,{clauses,Cs}}, _Prec, Opts) -> lexpr({'fun',_,{clauses,Cs},Extra}, _Prec, Opts) -> {force_nl,fun_info(Extra), {list,[{first,'fun',fun_clauses(Cs, Opts)},'end']}}; -lexpr({'query',_,Lc}, _Prec, Opts) -> - {list,[{step,leaf("query"),lexpr(Lc, 0, Opts)},'end']}; lexpr({call,_,{remote,_,{atom,_,M},{atom,_,F}=N}=Name,Args}, Prec, Opts) -> case erl_internal:bif(M, F, length(Args)) of true -> diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl index e5bb287c45..bc0eaf015d 100644 --- a/lib/stdlib/src/erl_scan.erl +++ b/lib/stdlib/src/erl_scan.erl @@ -1404,7 +1404,6 @@ reserved_word('fun') -> true; reserved_word('if') -> true; reserved_word('let') -> true; reserved_word('of') -> true; -reserved_word('query') -> true; reserved_word('receive') -> true; reserved_word('when') -> true; reserved_word('bnot') -> true; diff --git a/lib/stdlib/src/queue.erl b/lib/stdlib/src/queue.erl index afe917b151..bc1bd06534 100644 --- a/lib/stdlib/src/queue.erl +++ b/lib/stdlib/src/queue.erl @@ -472,22 +472,24 @@ init(Q) -> drop_r(Q). -compile({inline, [{r2f,1},{f2r,1}]}). -%% Move all but two from R to F, if there are at least three +%% Move half of elements from R to F, if there are at least three r2f([]) -> {[],[]}; r2f([_]=R) -> {[],R}; r2f([X,Y]) -> {[X],[Y]}; -r2f([X,Y|R]) -> - {[X,Y],lists:reverse(R, [])}. +r2f(List) -> + {FF,RR} = lists:split(length(List) div 2 + 1, List), + {FF,lists:reverse(RR, [])}. -%% Move all but two from F to R, if there are enough +%% Move half of elements from F to R, if there are enough f2r([]) -> {[],[]}; f2r([_]=F) -> {F,[]}; f2r([X,Y]) -> {[Y],[X]}; -f2r([X,Y|F]) -> - {lists:reverse(F, []),[X,Y]}. +f2r(List) -> + {FF,RR} = lists:split(length(List) div 2 + 1, List), + {lists:reverse(RR, []),FF}. diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index db416b03b0..37be61d665 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -537,29 +537,9 @@ messages(Config) when is_list(Config) -> ?line true = "\n" =:= lists:flatten(erl_pp:form({eof,0})), ok. -old_mnemosyne_syntax(suite) -> - []; old_mnemosyne_syntax(Config) when is_list(Config) -> - %% Since we have kept the 'query' syntax and ':-' token, + %% Since we have kept the ':-' token, %% better test that we can pretty print it. - Q = {'query',6, - {lc,6, - {var,6,'X'}, - [{generate,6, - {var,6,'X'}, - {call,6,{atom,6,table},[{atom,6,tab}]}}, - {match,7, - {record_field,7,{var,7,'X'},{atom,7,foo}}, - {atom,7,bar}}]}}, - ?line "query\n" - " [ \n" % extra space... - " X ||\n" - " X <- table(tab),\n" - " X.foo = bar\n" - " ]\n" - "end" = - lists:flatten(erl_pp:expr(Q)), - R = {rule,12,sales,2, [{clause,12, [{var,12,'E'},{atom,12,employee}], diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl index 34e1b99abe..9a6b2f8f34 100644 --- a/lib/stdlib/test/erl_scan_SUITE.erl +++ b/lib/stdlib/test/erl_scan_SUITE.erl @@ -197,7 +197,7 @@ otp_7810(Config) when is_list(Config) -> reserved_words() -> L = ['after', 'begin', 'case', 'try', 'cond', 'catch', 'andalso', 'orelse', 'end', 'fun', 'if', 'let', 'of', - 'query', 'receive', 'when', 'bnot', 'not', 'div', + 'receive', 'when', 'bnot', 'not', 'div', 'rem', 'band', 'and', 'bor', 'bxor', 'bsl', 'bsr', 'or', 'xor'], [begin diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl index 1a55a5e71c..1ffcf31134 100644 --- a/lib/syntax_tools/src/erl_prettypr.erl +++ b/lib/syntax_tools/src/erl_prettypr.erl @@ -813,13 +813,6 @@ lay_2(Node, Ctxt) -> reset_prec(Ctxt)), lay_parentheses(D, Ctxt); - query_expr -> - Ctxt1 = reset_prec(Ctxt), - D = lay(erl_syntax:query_expr_body(Node), Ctxt1), - sep([text("query"), - nest(Ctxt1#ctxt.sub_indent, D), - text("end")]); - receive_expr -> Ctxt1 = reset_prec(Ctxt), D1 = lay_clauses(erl_syntax:receive_expr_clauses(Node), diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index f7420030c3..41a1708925 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -235,8 +235,6 @@ prefix_expr/2, prefix_expr_argument/1, prefix_expr_operator/1, - query_expr/1, - query_expr_body/1, receive_expr/1, receive_expr/3, receive_expr_action/1, @@ -449,7 +447,6 @@ %% <td>parentheses</td> %% <td>prefix_expr</td> %% </tr><tr> -%% <td>query_expr</td> %% <td>receive_expr</td> %% <td>record_access</td> %% </tr><tr> @@ -513,7 +510,6 @@ %% @see operator/1 %% @see parentheses/1 %% @see prefix_expr/2 -%% @see query_expr/1 %% @see receive_expr/3 %% @see record_access/3 %% @see record_expr/2 @@ -578,7 +574,6 @@ type(Node) -> {match, _, _, _} -> match_expr; {op, _, _, _, _} -> infix_expr; {op, _, _, _} -> prefix_expr; - {'query', _, _} -> query_expr; {record, _, _, _, _} -> record_expr; {record, _, _, _} -> record_expr; {record_field, _, _, _, _} -> record_access; @@ -4097,7 +4092,6 @@ record_access(Argument, Field) -> %% @see record_access_type/1 %% @see record_access_field/1 %% @see record_expr/3 -%% @see query_expr/1 -record(record_access, {argument :: syntaxTree(), type :: 'none' | syntaxTree(), @@ -4574,50 +4568,6 @@ binary_comp_body(Node) -> %% ===================================================================== -%% @doc Creates an abstract Mnemosyne query expression. The result -%% represents "<code>query <em>Body</em> end</code>". -%% -%% @see query_expr_body/1 -%% @see record_access/2 -%% @see rule/2 - -%% type(Node) = query_expr -%% data(Node) = syntaxTree() -%% -%% `erl_parse' representation: -%% -%% {'query', Pos, Body} -%% -%% Body = erl_parse() - --spec query_expr(syntaxTree()) -> syntaxTree(). - -query_expr(Body) -> - tree(query_expr, Body). - -revert_query_expr(Node) -> - Pos = get_pos(Node), - Body = list_comp_body(Node), - {'query', Pos, Body}. - - -%% ===================================================================== -%% @doc Returns the body subtree of a `query_expr' node. -%% -%% @see query_expr/1 - --spec query_expr_body(syntaxTree()) -> syntaxTree(). - -query_expr_body(Node) -> - case unwrap(Node) of - {'query', _, Body} -> - Body; - Node1 -> - data(Node1) - end. - - -%% ===================================================================== %% @doc Creates an abstract Mnemosyne rule. If `Clauses' is %% `[C1, ..., Cn]', the results represents %% "<code><em>Name</em> <em>C1</em>; ...; <em>Name</em> @@ -6041,8 +5991,6 @@ revert_root(Node) -> revert_parentheses(Node); prefix_expr -> revert_prefix_expr(Node); - query_expr -> - revert_query_expr(Node); receive_expr -> revert_receive_expr(Node); record_access -> @@ -6283,8 +6231,6 @@ subtrees(T) -> prefix_expr -> [[prefix_expr_operator(T)], [prefix_expr_argument(T)]]; - query_expr -> - [[query_expr_body(T)]]; receive_expr -> case receive_expr_timeout(T) of none -> @@ -6413,7 +6359,6 @@ make_tree(match_expr, [[P], [E]]) -> match_expr(P, E); make_tree(module_qualifier, [[M], [N]]) -> module_qualifier(M, N); make_tree(parentheses, [[E]]) -> parentheses(E); make_tree(prefix_expr, [[F], [A]]) -> prefix_expr(F, A); -make_tree(query_expr, [[B]]) -> query_expr(B); make_tree(receive_expr, [C]) -> receive_expr(C); make_tree(receive_expr, [C, [E], A]) -> receive_expr(C, E, A); make_tree(record_access, [[E], [F]]) -> diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl index d9a699ca9f..c0200ab67c 100644 --- a/lib/test_server/src/ts_lib.erl +++ b/lib/test_server/src/ts_lib.erl @@ -143,7 +143,6 @@ suite_order(inets) -> 28; suite_order(asn1) -> 30; suite_order(os_mon) -> 32; suite_order(snmp) -> 38; -suite_order(mnemosyne) -> 40; suite_order(mnesia_session) -> 42; suite_order(mnesia) -> 44; suite_order(system) -> 999; %% IMPORTANT: system SHOULD always be last! diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index ab29d156aa..680c1781ca 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -1519,12 +1519,6 @@ aux_var(Vars, N) -> %% This way we will be able to exclude functions defined in include files. munge({function,0,module_info,_Arity,_Clauses},_Vars,_MainFile,_Switch) -> ignore; % module_info will be added again when the forms are recompiled -munge(Form={function,_,'MNEMOSYNE QUERY',_,_},Vars,_MainFile,Switch) -> - {Form,Vars,Switch}; % No bumps in Mnemosyne code. -munge(Form={function,_,'MNEMOSYNE RULE',_,_},Vars,_MainFile,Switch) -> - {Form,Vars,Switch}; -munge(Form={function,_,'MNEMOSYNE RECFUNDEF',_,_},Vars,_MainFile,Switch) -> - {Form,Vars,Switch}; munge({function,Line,Function,Arity,Clauses},Vars,_MainFile,on) -> Vars2 = Vars#vars{function=Function, arity=Arity, diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl index 92f0c45c7b..2fcc2c503c 100644 --- a/lib/tools/src/xref_reader.erl +++ b/lib/tools/src/xref_reader.erl @@ -80,12 +80,6 @@ form({attribute, Line, xref, Calls}, S) -> % experimental attr(Calls, Line, M, Fun, L, X, B, S); form({attribute, _Line, _Attr, _Val}, S) -> S; -form({function, 0, 'MNEMOSYNE RULE', 1, _Clauses}, S) -> - S; -form({function, 0, 'MNEMOSYNE QUERY', 2, _Clauses}, S) -> - S; -form({function, 0, 'MNEMOSYNE RECFUNDEF', 1, _Clauses}, S) -> - S; form({function, 0, module_info, 0, _Clauses}, S) -> S; form({function, 0, module_info, 1, _Clauses}, S) -> @@ -331,9 +325,6 @@ handle_call(Locality, Module, Name, Arity, Line, S) -> handle_call(Locality, To, Line, S, false) end. -handle_call(_Locality, {_, 'MNEMOSYNE RULE',1}, _Line, S, _) -> S; -handle_call(_Locality, {_, 'MNEMOSYNE QUERY', 2}, _Line, S, _) -> S; -handle_call(_Locality, {_, 'MNEMOSYNE RECFUNDEF',1}, _Line, S, _) -> S; handle_call(Locality, To0, Line, S, IsUnres) -> From = S#xrefr.function, To = adjust_arity(S, To0), diff --git a/lib/tools/test/cprof_SUITE.erl b/lib/tools/test/cprof_SUITE.erl index 93caee0c8f..ce5cf66a14 100644 --- a/lib/tools/test/cprof_SUITE.erl +++ b/lib/tools/test/cprof_SUITE.erl @@ -230,10 +230,10 @@ on_load_test(Config) -> %% ?line N4 = cprof:restart(), ?line {ok,Module} = c:c(File, [{outdir,Priv}]), - ?line L = Module:seq(1, M, fun (I) -> succ(I) end), - ?line Lr = Module:seq_r(1, M, fun (I) -> succ(I) end), - ?line L = seq(1, M, fun (I) -> succ(I) end), - ?line Lr = seq_r(1, M, fun (I) -> succ(I) end), + ?line L = Module:seq(1, M, fun succ/1), + ?line Lr = Module:seq_r(1, M, fun succ/1), + ?line L = seq(1, M, fun succ/1), + ?line Lr = seq_r(1, M, fun succ/1), ?line N2 = cprof:pause(), ?line {Module,0,[]} = cprof:analyse(Module), ?line M_1 = M - 1, @@ -265,10 +265,10 @@ modules_test(Config) -> ?line M2__1 = M2 + 1, ?line erlang:yield(), ?line N = cprof:start(), - ?line L = Module:seq(1, M, fun (I) -> succ(I) end), - ?line Lr = Module:seq_r(1, M, fun (I) -> succ(I) end), - ?line L = seq(1, M, fun (I) -> succ(I) end), - ?line Lr = seq_r(1, M, fun (I) -> succ(I) end), + ?line L = Module:seq(1, M, fun succ/1), + ?line Lr = Module:seq_r(1, M, fun succ/1), + ?line L = seq(1, M, fun succ/1), + ?line Lr = seq_r(1, M, fun succ/1), ?line N = cprof:pause(), ?line Lr = lists:reverse(L), ?line M_1 = M - 1, diff --git a/lib/tv/src/tv_main.hrl b/lib/tv/src/tv_main.hrl index 28329ca83c..06b405ac1f 100644 --- a/lib/tv/src/tv_main.hrl +++ b/lib/tv/src/tv_main.hrl @@ -131,7 +131,6 @@ ir_WstringDef, lmcounter, locks, - mnemosyne_tmp, pg2_table, queue, snmp_agent_table, diff --git a/lib/wx/examples/demo/demo_html_tagger.erl b/lib/wx/examples/demo/demo_html_tagger.erl index 243e5d659f..46bfe73676 100644 --- a/lib/wx/examples/demo/demo_html_tagger.erl +++ b/lib/wx/examples/demo/demo_html_tagger.erl @@ -485,7 +485,6 @@ is_keyword('not') -> true; is_keyword('of' ) -> true; is_keyword('or' ) -> true; is_keyword('orelse' ) -> true; -is_keyword('query' ) -> true; is_keyword('receive' ) -> true; is_keyword('rem' ) -> true; is_keyword('spec') -> true; diff --git a/make/fakefop b/make/fakefop index bbe81ef3b1..b64428bbd1 100755 --- a/make/fakefop +++ b/make/fakefop @@ -1,10 +1,9 @@ #!/bin/sh # -# Copyright Tuncer Ayaz 2010. All Rights Reserved. -# # %CopyrightBegin% # -# Copyright Ericsson AB 2010. All Rights Reserved. +# Copyright Tuncer Ayaz 2010-2013. All Rights Reserved. +# Copyright Ericsson AB 2010-2013. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -22,92 +21,85 @@ # Author: Tuncer Ayaz # -if [ $# -lt 4 ] +if [ $# -lt 6 ] then - echo "Usage: fakefop -fo IGNORED -pdf OUTFILE" + echo "Usage: fakefop -c IGNORED -fo IGNORED -pdf OUTFILE" exit 1 fi -OUTFILE=$4 -NAME=`basename $4 .pdf` +OUTFILE=$6 + +echo -n -e '%PDF-1.4\n%\0342\0343\0317\0323\n\n' > $OUTFILE -echo Write $OUTFILE -cat > $OUTFILE <<EndOfFile -%PDF-1.4 +cat >> $OUTFILE <<EndOfFile 1 0 obj - << /Type /Catalog - /Outlines 2 0 R - /Pages 3 0 R - >> +<< + /Type /Catalog + /Pages 2 0 R +>> endobj 2 0 obj - << /Type /Outlines - /Count 0 - >> +<< + /Type /Pages + /Kids [ 3 0 R ] + /Count 1 +>> endobj 3 0 obj - << /Type /Pages - /Kids [4 0 R] - /Count 1 +<< + /Type /Page + /Parent 2 0 R + /MediaBox [ 0 0 612 492 ] + /Contents 5 0 R + /Resources << + /Font << + /F1 4 0 R + >> >> +>> endobj 4 0 obj - << /Type /Page - /Parent 3 0 R - /MediaBox [0 0 612 492] - /Contents 5 0 R - /Resources << /ProcSet 6 0 R - /Font << /F1 7 0 R >> - >> - >> +<< + /Type /Font + /Subtype /Type1 + /Name /F1 + /BaseFont /Helvetica + /Encoding /StandardEncoding +>> endobj 5 0 obj - << /Length 73 >> +<< + /Length 74 +>> stream - BT - /F1 24 Tf - 10 400 Td - ($NAME) Tj - ET - BT - /F1 24 Tf - 10 350 Td - (\(placeholder PDF generated without FOP\)) Tj - ET +BT +/F1 24 Tf +10 400 Td +(\(placeholder PDF generated with fakefop\)) Tj +ET endstream endobj -6 0 obj - [/PDF /Text] -endobj -7 0 obj - << /Type /Font - /Subtype /Type1 - /Name /F1 - /BaseFont /Helvetica - /Encoding /MacRomanEncoding - >> -endobj xref -0 8 -0000000000 65535 f -0000000009 00000 n -0000000074 00000 n -0000000120 00000 n -0000000179 00000 n -0000000364 00000 n -0000000466 00000 n -0000000496 00000 n +0 6 +0000000000 65536 f +0000000016 00000 n +0000000070 00000 n +0000000136 00000 n +0000000291 00000 n +0000000410 00000 n trailer - << /Size 8 - /Root 1 0 R - >> +<< + /Size 6 + /Root 1 0 R +>> + startxref -625 +536 %%EOF EndOfFile diff --git a/make/otp.mk.in b/make/otp.mk.in index 0e58a27016..fca9cf3cff 100644 --- a/make/otp.mk.in +++ b/make/otp.mk.in @@ -255,6 +255,7 @@ DEFAULT_GIF_FILES = $(HTMLDIR)/min_head.gif # XSLTPROC = @XSLTPROC@ FOP = @FOP@ +XMLLINT = @XMLLINT@ DOCGEN=$(ERL_TOP)/lib/erl_docgen FOP_CONFIG = $(DOCGEN)/priv/fop.xconf diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk index 0be0a2de56..65a2e62979 100644 --- a/make/otp_release_targets.mk +++ b/make/otp_release_targets.mk @@ -106,6 +106,9 @@ $(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) $(SPECS_FILES) docs: $(HTMLDIR)/$(APPLICATION).eix +xmllint: $(XML_FILES) + $(XMLLINT) --noout --valid --nodefdtd --loaddtd --path $(DOCGEN)/priv/dtd:$(DOCGEN)/priv/dtd_html_entities $(XML_FILES) + # ---------------------------------------------------- # Local documentation target for testing # ---------------------------------------------------- |