aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md11
-rw-r--r--erts/doc/src/erts_alloc.xml16
-rw-r--r--erts/emulator/beam/erl_alloc.c16
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c190
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.h11
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c6
-rw-r--r--erts/emulator/test/alloc_SUITE_data/allocator_test.h3
-rw-r--r--erts/emulator/test/alloc_SUITE_data/coalesce.c2
-rw-r--r--erts/emulator/test/alloc_SUITE_data/rbtree.c90
-rw-r--r--erts/emulator/valgrind/suppress.standard2
-rw-r--r--erts/vsn.mk4
-rw-r--r--lib/common_test/src/ct_netconfc.erl94
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl13
-rw-r--r--lib/crypto/c_src/crypto.c194
-rw-r--r--lib/crypto/src/crypto.erl27
-rw-r--r--lib/inets/doc/src/notes.xml15
-rw-r--r--lib/inets/src/http_client/httpc.erl2
-rw-r--r--lib/inets/src/http_server/httpd_manager.erl33
-rw-r--r--lib/inets/test/httpc_proxy_SUITE.erl17
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/public_key/test/pbe_SUITE.erl1
-rw-r--r--lib/public_key/test/pkits_SUITE.erl1
-rw-r--r--lib/public_key/test/public_key_SUITE.erl1
-rw-r--r--lib/sasl/test/systools_SUITE.erl6
-rw-r--r--lib/ssh/doc/src/notes.xml15
-rw-r--r--lib/ssh/src/ssh_cli.erl19
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl3
-rw-r--r--lib/ssh/src/ssh_file.erl9
-rw-r--r--lib/stdlib/src/gen_server.erl2
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/tools/emacs/erlang-skels.el4
-rw-r--r--system/doc/tutorial/nif.xmlsrc6
32 files changed, 488 insertions, 329 deletions
diff --git a/README.md b/README.md
index 1bcf14e760..a6a4f11be8 100644
--- a/README.md
+++ b/README.md
@@ -28,10 +28,13 @@ Here are the [instructions for submitting patches] [2].
In short:
* We prefer to receive proposed updates via email on the
- [`erlang-patches`] [3] mailing list rather than through a pull request.
- Pull requests are not practical because we have a strict policy never to
- merge any untested changes to the development branch (the only exception
- being **obviously** correct changes, such as corrections of typos).
+ [`erlang-patches`] [3] mailing list or through a pull request.
+
+* Pull requests will be handled once everyday and there will be
+ essential testing before we will take a decision on the outcome
+ of the request. If the essential testings fails, the pull request
+ will be closed and you will have to fix the problem and submit another
+ pull request when this is done.
* We merge all proposed updates to the `pu` (*proposed updates*) branch,
typically within one working day.
diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml
index 2ffb55c6ab..6ce2261430 100644
--- a/erts/doc/src/erts_alloc.xml
+++ b/erts/doc/src/erts_alloc.xml
@@ -170,6 +170,15 @@
used. The time complexity is proportional to log N, where
N is the number of free blocks.</p>
</item>
+ <tag>Address order first fit carrier best fit</tag>
+ <item>
+ <p>Strategy: Find the <em>carrier</em> with the lowest address that
+ can satisfy the requested block size, then find a block within
+ that carrier using the "best fit" strategy.</p>
+ <p>Implementation: Balanced binary search trees are
+ used. The time complexity is proportional to log N, where
+ N is the number of free blocks.</p>
+ </item>
<tag>Address order first fit carrier address order best fit</tag>
<item>
<p>Strategy: Find the <em>carrier</em> with the lowest address that
@@ -330,20 +339,21 @@
fetched it will function as an ordinary carrier. This feature has
special requirements on the
<seealso marker="#M_as">allocation strategy</seealso> used. Currently
- only the <c>aoff</c> and the <c>aoffcaobf</c> strategies support
+ only the strategies <c>aoff</c>, <c>aoffcbf</c> and <c>aoffcaobf</c> support
abandoned carriers. This feature also requires
<seealso marker="#M_t">multiple thread specific instances</seealso>
to be enabled. When enabling this feature, multiple thread specific
instances will be enabled if not already enabled, and the
- <c>aoffcaobf</c> strategy will be enabled if current strategy does not
+ <c>aoffcbf</c> strategy will be enabled if current strategy does not
support abandoned carriers. This feature can be enabled on all
allocators based on the <c>alloc_util</c> framework with the
exception of <c>temp_alloc</c> (which would be pointless).
</item>
- <tag><marker id="M_as"><c><![CDATA[+M<S>as bf|aobf|aoff|aoffcaobf|gf|af]]></c></marker></tag>
+ <tag><marker id="M_as"><c><![CDATA[+M<S>as bf|aobf|aoff|aoffcbf|aoffcaobf|gf|af]]></c></marker></tag>
<item>
Allocation strategy. Valid strategies are <c>bf</c> (best fit),
<c>aobf</c> (address order best fit), <c>aoff</c> (address order first fit),
+ <c>aoffcbf</c> (address order first fit carrier best fit),
<c>aoffcaobf</c> (address order first fit carrier address order best fit),
<c>gf</c> (good fit), and <c>af</c> (a fit). See
<seealso marker="#strategy">the description of allocation strategies</seealso> in "the <c>alloc_util</c> framework" section.</item>
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 86575ccb9b..5eacff8829 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -249,7 +249,7 @@ set_default_acul(struct au_init *ip, int acul)
{
ip->thr_spec = 1;
ip->atype = AOFIRSTFIT;
- ip->init.aoff.bf_within_carrier = 1;
+ ip->init.aoff.flavor = AOFF_BF;
ip->init.util.acul = acul;
}
@@ -564,7 +564,7 @@ static ERTS_INLINE int
strategy_support_carrier_migration(struct au_init *auip)
{
/*
- * Currently only aoff and aoffcaobf support carrier
+ * Currently only aoff, aoffcbf and aoffcaobf support carrier
* migration, i.e, type AOFIRSTFIT.
*/
return auip->atype == AOFIRSTFIT;
@@ -587,9 +587,9 @@ ensure_carrier_migration_support(struct au_init *auip)
* default to a strategy that can...
*/
if (!strategy_support_carrier_migration(auip)) {
- /* Default to aoffcaobf */
+ /* Default to aoffcbf */
auip->atype = AOFIRSTFIT;
- auip->init.aoff.bf_within_carrier = 1;
+ auip->init.aoff.flavor = AOFF_BF;
}
}
@@ -1290,11 +1290,15 @@ handle_au_arg(struct au_init *auip,
}
else if (strcmp("aoff", alg) == 0) {
auip->atype = AOFIRSTFIT;
- auip->init.aoff.bf_within_carrier = 0;
+ auip->init.aoff.flavor = AOFF_AOFF;
+ }
+ else if (strcmp("aoffcbf", alg) == 0) {
+ auip->atype = AOFIRSTFIT;
+ auip->init.aoff.flavor = AOFF_BF;
}
else if (strcmp("aoffcaobf", alg) == 0) {
auip->atype = AOFIRSTFIT;
- auip->init.aoff.bf_within_carrier = 1;
+ auip->init.aoff.flavor = AOFF_AOBF;
}
else {
bad_value(param, sub_param + 1, alg);
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index f73ac2eb6e..4e6c8b317e 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.c
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c
@@ -34,10 +34,11 @@
* sub-tree ('max_sz'). By that we can start from root and keep
* left (for low addresses) while dismissing entire sub-trees with
* too small blocks.
- * AOFFCBF:
+ * Bestfit within carrier:
* The only difference for "bestfit within carrier" is the tree
* sorting order. Blocks within the same carrier are sorted
- * wrt size instead of address.
+ * wrt size instead of address. The 'max_sz' field is maintained
+ * in order to dismiss entire carriers with too small blocks.
*
* Authors: Rickard Green/Sverker Eriksson
*/
@@ -67,6 +68,15 @@
# define LEFT_VISITED_FLG (((Uint) 1) << 2)
# define RIGHT_VISITED_FLG (((Uint) 1) << 3)
#endif
+#ifdef DEBUG
+# define IS_BF_FLG (((Uint) 1) << 4)
+#endif
+
+#define IS_TREE_NODE(N) (((AOFF_RBTree_t *) (N))->flags & TREE_NODE_FLG)
+#define IS_LIST_ELEM(N) (!IS_TREE_NODE(((AOFF_RBTree_t *) (N))))
+
+#define SET_TREE_NODE(N) (((AOFF_RBTree_t *) (N))->flags |= TREE_NODE_FLG)
+#define SET_LIST_ELEM(N) (((AOFF_RBTree_t *) (N))->flags &= ~TREE_NODE_FLG)
#define IS_RED(N) (((AOFF_RBTree_t *) (N)) \
&& ((AOFF_RBTree_t *) (N))->flags & RED_FLG)
@@ -98,6 +108,16 @@ struct AOFF_RBTree_t_ {
};
#define AOFF_BLK_SZ(B) MBC_FBLK_SZ(&(B)->hdr)
+/* BF block nodes keeps list of all with equal size
+ */
+typedef struct {
+ AOFF_RBTree_t t;
+ AOFF_RBTree_t *next;
+}AOFF_RBTreeList_t;
+
+#define LIST_NEXT(N) (((AOFF_RBTreeList_t*) (N))->next)
+#define LIST_PREV(N) (((AOFF_RBTreeList_t*) (N))->t.parent)
+
typedef struct AOFF_Carrier_t_ AOFF_Carrier_t;
struct AOFF_Carrier_t_ {
@@ -119,11 +139,11 @@ struct AOFF_Carrier_t_ {
#ifdef HARD_DEBUG
# define HARD_CHECK_IS_MEMBER(ROOT,NODE) rbt_assert_is_member(ROOT,NODE)
-# define HARD_CHECK_TREE(CRR,BF,ROOT,SZ) check_tree(CRR, BF, ROOT, SZ)
-static AOFF_RBTree_t * check_tree(Carrier_t* within_crr, int bestfit, AOFF_RBTree_t* root, Uint);
+# define HARD_CHECK_TREE(CRR,FLV,ROOT,SZ) check_tree(CRR, FLV, ROOT, SZ)
+static AOFF_RBTree_t * check_tree(Carrier_t* within_crr, enum AOFF_Flavor flavor, AOFF_RBTree_t* root, Uint);
#else
# define HARD_CHECK_IS_MEMBER(ROOT,NODE)
-# define HARD_CHECK_TREE(CRR,BF,ROOT,SZ)
+# define HARD_CHECK_TREE(CRR,FLV,ROOT,SZ)
#endif
@@ -161,25 +181,25 @@ static ERTS_INLINE void lower_max_size(AOFF_RBTree_t *node,
else ASSERT(new_max == old_max);
}
-static ERTS_INLINE SWord cmp_blocks(int bestfit,
+static ERTS_INLINE SWord cmp_blocks(enum AOFF_Flavor flavor,
AOFF_RBTree_t* lhs, AOFF_RBTree_t* rhs)
{
ASSERT(lhs != rhs);
- ASSERT(!bestfit || FBLK_TO_MBC(&lhs->hdr) == FBLK_TO_MBC(&rhs->hdr));
- if (bestfit) {
+ ASSERT(flavor == AOFF_AOFF || FBLK_TO_MBC(&lhs->hdr) == FBLK_TO_MBC(&rhs->hdr));
+ if (flavor != AOFF_AOFF) {
SWord diff = (SWord)AOFF_BLK_SZ(lhs) - (SWord)AOFF_BLK_SZ(rhs);
- if (diff) return diff;
+ if (diff || flavor == AOFF_BF) return diff;
}
return (char*)lhs - (char*)rhs;
}
-static ERTS_INLINE SWord cmp_cand_blk(int bestfit,
+static ERTS_INLINE SWord cmp_cand_blk(enum AOFF_Flavor flavor,
Block_t* cand_blk, AOFF_RBTree_t* rhs)
{
- if (bestfit) {
+ if (flavor != AOFF_AOFF) {
if (BLK_TO_MBC(cand_blk) == FBLK_TO_MBC(&rhs->hdr)) {
SWord diff = (SWord)MBC_BLK_SZ(cand_blk) - (SWord)MBC_FBLK_SZ(&rhs->hdr);
- if (diff) return diff;
+ if (diff || flavor == AOFF_BF) return diff;
}
}
return (char*)cand_blk - (char*)rhs;
@@ -198,7 +218,7 @@ static UWord aoff_largest_fblk_in_mbc(Allctr_t*, Carrier_t*);
/* Generic tree functions used by both carrier and block trees. */
static void rbt_delete(AOFF_RBTree_t** root, AOFF_RBTree_t* del);
-static void rbt_insert(int bestfit, AOFF_RBTree_t** root, AOFF_RBTree_t* blk);
+static void rbt_insert(enum AOFF_Flavor flavor, AOFF_RBTree_t** root, AOFF_RBTree_t* blk);
static AOFF_RBTree_t* rbt_search(AOFF_RBTree_t* root, Uint size);
#ifdef HARD_DEBUG
static int rbt_assert_is_member(AOFF_RBTree_t* root, AOFF_RBTree_t* node);
@@ -234,21 +254,21 @@ erts_aoffalc_start(AOFFAllctr_t *alc,
sys_memcpy((void *) alc, (void *) &zero.allctr, sizeof(AOFFAllctr_t));
- alc->bf_within_carrier = aoffinit->bf_within_carrier;
+ alc->flavor = aoffinit->flavor;
allctr->mbc_header_size = sizeof(AOFF_Carrier_t);
allctr->min_mbc_size = MIN_MBC_SZ;
allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
- allctr->min_block_size = sizeof(AOFF_RBTree_t);
+ allctr->min_block_size = (aoffinit->flavor == AOFF_BF ?
+ sizeof(AOFF_RBTreeList_t):sizeof(AOFF_RBTree_t));
- allctr->vsn_str = aoffinit->bf_within_carrier ?
- ERTS_ALC_AOFF_CBF_ALLOC_VSN_STR : ERTS_ALC_AOFF_ALLOC_VSN_STR;
+ allctr->vsn_str = ERTS_ALC_AOFF_ALLOC_VSN_STR;
/* Callback functions */
allctr->get_free_block = aoff_get_free_block;
allctr->link_free_block = aoff_link_free_block;
- allctr->unlink_free_block = aoff_unlink_free_block;
+ allctr->unlink_free_block = aoff_unlink_free_block;
allctr->info_options = info_options;
allctr->get_next_mbc_size = NULL;
@@ -359,9 +379,7 @@ replace(AOFF_RBTree_t **root, AOFF_RBTree_t *x, AOFF_RBTree_t *y)
y->parent = x->parent;
y->right = x->right;
y->left = x->left;
-
- y->max_sz = x->max_sz;
- lower_max_size(y, NULL);
+ y->max_sz = x->max_sz;
}
static void
@@ -458,23 +476,47 @@ tree_insert_fixup(AOFF_RBTree_t** root, AOFF_RBTree_t *blk)
}
static void
-aoff_unlink_free_block(Allctr_t *allctr, Block_t *del)
+aoff_unlink_free_block(Allctr_t *allctr, Block_t *blk)
{
-#ifdef HARD_DEBUG
AOFFAllctr_t* alc = (AOFFAllctr_t*)allctr;
-#endif
- AOFF_Carrier_t *crr = (AOFF_Carrier_t*) FBLK_TO_MBC(del);
+ AOFF_RBTree_t* del = (AOFF_RBTree_t*)blk;
+ AOFF_Carrier_t *crr = (AOFF_Carrier_t*) FBLK_TO_MBC(&del->hdr);
ASSERT(crr->rbt_node.hdr.bhdr == crr->root->max_sz);
- HARD_CHECK_IS_MEMBER(alc->mbc_root, &crr->rbt_node);
- HARD_CHECK_TREE(&crr->crr, alc->bf_within_carrier, crr->root, 0);
+ HARD_CHECK_TREE(&crr->crr, alc->flavor, crr->root, 0);
+
+ if (alc->flavor == AOFF_BF) {
+ ASSERT(del->flags & IS_BF_FLG);
+ if (IS_LIST_ELEM(del)) {
+ /* Remove from list */
+ ASSERT(LIST_PREV(del));
+ ASSERT(LIST_PREV(del)->flags & IS_BF_FLG);
+ LIST_NEXT(LIST_PREV(del)) = LIST_NEXT(del);
+ if (LIST_NEXT(del)) {
+ ASSERT(LIST_NEXT(del)->flags & IS_BF_FLG);
+ LIST_PREV(LIST_NEXT(del)) = LIST_PREV(del);
+ }
+ return;
+ }
+ else if (LIST_NEXT(del)) {
+ /* Replace tree node by next element in list... */
+
+ ASSERT(AOFF_BLK_SZ(LIST_NEXT(del)) == AOFF_BLK_SZ(del));
+ ASSERT(IS_LIST_ELEM(LIST_NEXT(del)));
+
+ replace(&crr->root, (AOFF_RBTree_t*)del, LIST_NEXT(del));
+
+ HARD_CHECK_TREE(&crr->crr, alc->flavor, crr->root, 0);
+ return;
+ }
+ }
rbt_delete(&crr->root, (AOFF_RBTree_t*)del);
- HARD_CHECK_TREE(&crr->crr, alc->bf_within_carrier, crr->root, 0);
+ HARD_CHECK_TREE(&crr->crr, alc->flavor, crr->root, 0);
- /* Update the carrier tree with a potentially new (lower) max_sz
- */
+ /* Update the carrier tree with a potentially new (lower) max_sz
+ */
if (crr->root) {
if (crr->rbt_node.hdr.bhdr == crr->root->max_sz) {
return;
@@ -488,6 +530,7 @@ aoff_unlink_free_block(Allctr_t *allctr, Block_t *del)
lower_max_size(&crr->rbt_node, NULL);
}
+
static void
rbt_delete(AOFF_RBTree_t** root, AOFF_RBTree_t* del)
{
@@ -542,7 +585,9 @@ rbt_delete(AOFF_RBTree_t** root, AOFF_RBTree_t* del)
}
if (y != z) {
/* We spliced out the successor of z; replace z by the successor */
+ ASSERT(z != &null_x);
replace(root, z, y);
+ lower_max_size(y, NULL);
}
if (spliced_is_black) {
@@ -666,12 +711,11 @@ aoff_link_free_block(Allctr_t *allctr, Block_t *block)
ASSERT(allctr == ERTS_ALC_CARRIER_TO_ALLCTR(&blk_crr->crr));
ASSERT(blk_crr->rbt_node.hdr.bhdr == (blk_crr->root ? blk_crr->root->max_sz : 0));
- HARD_CHECK_IS_MEMBER(alc->mbc_root, &blk_crr->rbt_node);
- HARD_CHECK_TREE(&blk_crr->crr, alc->bf_within_carrier, blk_crr->root, 0);
+ HARD_CHECK_TREE(&blk_crr->crr, alc->flavor, blk_crr->root, 0);
- rbt_insert(alc->bf_within_carrier, &blk_crr->root, blk);
+ rbt_insert(alc->flavor, &blk_crr->root, blk);
- /* Update the carrier tree with a potential new (larger) max_sz
+ /* Update the carrier tree with a potentially new (larger) max_sz
*/
crr_node = &blk_crr->rbt_node;
if (blk_sz > crr_node->hdr.bhdr) {
@@ -683,15 +727,19 @@ aoff_link_free_block(Allctr_t *allctr, Block_t *block)
if (!crr_node) break;
}
}
- HARD_CHECK_TREE(&blk_crr->crr, alc->bf_within_carrier, blk_crr->root, 0);
+ HARD_CHECK_TREE(&blk_crr->crr, alc->flavor, blk_crr->root, 0);
}
static void
-rbt_insert(int bestfit, AOFF_RBTree_t** root, AOFF_RBTree_t* blk)
+rbt_insert(enum AOFF_Flavor flavor, AOFF_RBTree_t** root, AOFF_RBTree_t* blk)
{
Uint blk_sz = AOFF_BLK_SZ(blk);
- blk->flags = 0;
+#ifdef DEBUG
+ blk->flags = (flavor == AOFF_BF) ? IS_BF_FLG : 0;
+#else
+ blk->flags = 0;
+#endif
blk->left = NULL;
blk->right = NULL;
blk->max_sz = blk_sz;
@@ -704,10 +752,12 @@ rbt_insert(int bestfit, AOFF_RBTree_t** root, AOFF_RBTree_t* blk)
else {
AOFF_RBTree_t *x = *root;
while (1) {
+ SWord diff;
if (x->max_sz < blk_sz) {
x->max_sz = blk_sz;
}
- if (cmp_blocks(bestfit, blk, x) < 0) {
+ diff = cmp_blocks(flavor, blk, x);
+ if (diff < 0) {
if (!x->left) {
blk->parent = x;
x->left = blk;
@@ -715,7 +765,7 @@ rbt_insert(int bestfit, AOFF_RBTree_t** root, AOFF_RBTree_t* blk)
}
x = x->left;
}
- else {
+ else if (diff > 0) {
if (!x->right) {
blk->parent = x;
x->right = blk;
@@ -723,6 +773,18 @@ rbt_insert(int bestfit, AOFF_RBTree_t** root, AOFF_RBTree_t* blk)
}
x = x->right;
}
+ else {
+ ASSERT(flavor == AOFF_BF);
+ ASSERT(blk->flags & IS_BF_FLG);
+ ASSERT(x->flags & IS_BF_FLG);
+ SET_LIST_ELEM(blk);
+ LIST_NEXT(blk) = LIST_NEXT(x);
+ LIST_PREV(blk) = x;
+ if (LIST_NEXT(x))
+ LIST_PREV(LIST_NEXT(x)) = blk;
+ LIST_NEXT(x) = blk;
+ return;
+ }
}
/* Insert block into size tree */
@@ -732,6 +794,10 @@ rbt_insert(int bestfit, AOFF_RBTree_t** root, AOFF_RBTree_t* blk)
if (IS_RED(blk->parent))
tree_insert_fixup(root, blk);
}
+ if (flavor == AOFF_BF) {
+ SET_TREE_NODE(blk);
+ LIST_NEXT(blk) = NULL;
+ }
}
static AOFF_RBTree_t*
@@ -780,7 +846,7 @@ aoff_get_free_block(Allctr_t *allctr, Uint size,
/* Get block within carrier tree
*/
#ifdef HARD_DEBUG
- dbg_blk = HARD_CHECK_TREE(&crr->crr, alc->bf_within_carrier, crr->root, size);
+ dbg_blk = HARD_CHECK_TREE(&crr->crr, alc->flavor, crr->root, size);
#endif
blk = rbt_search(crr->root, size);
@@ -793,7 +859,7 @@ aoff_get_free_block(Allctr_t *allctr, Uint size,
if (!blk)
return NULL;
- if (cand_blk && cmp_cand_blk(alc->bf_within_carrier, cand_blk, blk) < 0) {
+ if (cand_blk && cmp_cand_blk(alc->flavor, cand_blk, blk) < 0) {
return NULL; /* cand_blk was better */
}
@@ -813,7 +879,7 @@ static void aoff_creating_mbc(Allctr_t *allctr, Carrier_t *carrier)
/* Link carrier in address order tree
*/
crr->rbt_node.hdr.bhdr = 0;
- rbt_insert(0, root, &crr->rbt_node);
+ rbt_insert(AOFF_AOFF, root, &crr->rbt_node);
/* aoff_link_free_block will add free block later */
crr->root = NULL;
@@ -843,7 +909,7 @@ static void aoff_add_mbc(Allctr_t *allctr, Carrier_t *carrier)
/* Link carrier in address order tree
*/
- rbt_insert(0, root, &crr->rbt_node);
+ rbt_insert(AOFF_AOFF, root, &crr->rbt_node);
HARD_CHECK_TREE(NULL, 0, *root, 0);
}
@@ -883,6 +949,7 @@ static struct {
Eterm as;
Eterm aoff;
Eterm aoffcaobf;
+ Eterm aoffcbf;
#ifdef DEBUG
Eterm end_of_atoms;
#endif
@@ -912,6 +979,7 @@ init_atoms(void)
AM_INIT(as);
AM_INIT(aoff);
AM_INIT(aoffcaobf);
+ AM_INIT(aoffcbf);
#ifdef DEBUG
for (atom = (Eterm *) &am; atom < &am.end_of_atoms; atom++) {
@@ -943,13 +1011,15 @@ info_options(Allctr_t *allctr,
{
AOFFAllctr_t* alc = (AOFFAllctr_t*) allctr;
Eterm res = THE_NON_VALUE;
+ const char* flavor_str[3] = {"aoff", "aoffcaobf", "aoffcbf"};
+ Eterm flavor_atom[3] = {am.aoff, am.aoffcaobf, am.aoffcbf};
if (print_to_p) {
erts_print(*print_to_p,
print_to_arg,
"%sas: %s\n",
prefix,
- alc->bf_within_carrier ? "aoffcaobf" : "aoff");
+ flavor_str[alc->flavor]);
}
if (hpp || szp) {
@@ -959,8 +1029,7 @@ info_options(Allctr_t *allctr,
__FILE__, __LINE__);;
res = NIL;
- add_2tup(hpp, szp, &res, am.as,
- alc->bf_within_carrier ? am.aoffcaobf : am.aoff);
+ add_2tup(hpp, szp, &res, am.as, flavor_atom[alc->flavor]);
}
return res;
@@ -978,6 +1047,7 @@ UWord
erts_aoffalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
+ case 0x500: return (UWord) ((AOFFAllctr_t *) a1)->flavor == AOFF_AOBF;
case 0x501: {
AOFF_RBTree_t *node = ((AOFFAllctr_t *) a1)->mbc_root;
Uint size = (Uint) a2;
@@ -987,10 +1057,13 @@ erts_aoffalc_test(UWord op, UWord a1, UWord a2)
case 0x502: return (UWord) ((AOFF_RBTree_t *) a1)->parent;
case 0x503: return (UWord) ((AOFF_RBTree_t *) a1)->left;
case 0x504: return (UWord) ((AOFF_RBTree_t *) a1)->right;
+ case 0x505: return (UWord) LIST_NEXT(a1);
case 0x506: return (UWord) IS_BLACK((AOFF_RBTree_t *) a1);
+ case 0x507: return (UWord) IS_TREE_NODE((AOFF_RBTree_t *) a1);
case 0x508: return (UWord) 0; /* IS_BF_ALGO */
case 0x509: return (UWord) ((AOFF_RBTree_t *) a1)->max_sz;
- case 0x50a: return (UWord) ((AOFFAllctr_t *) a1)->bf_within_carrier;
+ case 0x50a: return (UWord) ((AOFFAllctr_t *) a1)->flavor == AOFF_BF;
+ case 0x50b: return (UWord) LIST_PREV(a1);
default: ASSERT(0); return ~((UWord) 0);
}
}
@@ -1049,7 +1122,7 @@ static void print_tree(AOFF_RBTree_t*);
*/
static AOFF_RBTree_t *
-check_tree(Carrier_t* within_crr, int bestfit, AOFF_RBTree_t* root, Uint size)
+check_tree(Carrier_t* within_crr, enum AOFF_Flavor flavor, AOFF_RBTree_t* root, Uint size)
{
AOFF_RBTree_t *res = NULL;
Sint blacks;
@@ -1061,6 +1134,7 @@ check_tree(Carrier_t* within_crr, int bestfit, AOFF_RBTree_t* root, Uint size)
#ifdef PRINT_TREE
print_tree(root);
#endif
+ ASSERT(within_crr || flavor == AOFF_AOFF);
if (!root)
return res;
@@ -1116,6 +1190,20 @@ check_tree(Carrier_t* within_crr, int bestfit, AOFF_RBTree_t* root, Uint size)
ASSERT(crr == within_crr);
ASSERT((char*)x > (char*)crr);
ASSERT(((char*)x + AOFF_BLK_SZ(x)) <= ((char*)crr + CARRIER_SZ(crr)));
+
+ }
+ if (flavor == AOFF_BF) {
+ AOFF_RBTree_t* y = x;
+ AOFF_RBTree_t* nxt = LIST_NEXT(y);
+ ASSERT(IS_TREE_NODE(x));
+ while (nxt) {
+ ASSERT(IS_LIST_ELEM(nxt));
+ ASSERT(AOFF_BLK_SZ(nxt) == AOFF_BLK_SZ(x));
+ ASSERT(FBLK_TO_MBC(&nxt->hdr) == within_crr);
+ ASSERT(LIST_PREV(nxt) == y);
+ y = nxt;
+ nxt = LIST_NEXT(nxt);
+ }
}
if (IS_RED(x)) {
@@ -1127,13 +1215,13 @@ check_tree(Carrier_t* within_crr, int bestfit, AOFF_RBTree_t* root, Uint size)
if (x->left) {
ASSERT(x->left->parent == x);
- ASSERT(cmp_blocks(bestfit, x->left, x) < 0);
+ ASSERT(cmp_blocks(flavor, x->left, x) < 0);
ASSERT(x->left->max_sz <= x->max_sz);
}
if (x->right) {
ASSERT(x->right->parent == x);
- ASSERT(cmp_blocks(bestfit, x->right, x) > 0);
+ ASSERT(cmp_blocks(flavor, x->right, x) > 0);
ASSERT(x->right->max_sz <= x->max_sz);
}
ASSERT(x->max_sz >= AOFF_BLK_SZ(x));
@@ -1142,7 +1230,7 @@ check_tree(Carrier_t* within_crr, int bestfit, AOFF_RBTree_t* root, Uint size)
|| x->max_sz == (x->right ? x->right->max_sz : 0));
if (size && AOFF_BLK_SZ(x) >= size) {
- if (!res || cmp_blocks(bestfit, x, res) < 0) {
+ if (!res || cmp_blocks(flavor, x, res) < 0) {
res = x;
}
}
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.h b/erts/emulator/beam/erl_ao_firstfit_alloc.h
index e92cb5abb6..25b344c6a8 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.h
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.h
@@ -24,12 +24,17 @@
#include "erl_alloc_util.h"
#define ERTS_ALC_AOFF_ALLOC_VSN_STR "0.9"
-#define ERTS_ALC_AOFF_CBF_ALLOC_VSN_STR "0.9"
typedef struct AOFFAllctr_t_ AOFFAllctr_t;
+enum AOFF_Flavor {
+ AOFF_AOFF = 0,
+ AOFF_AOBF = 1,
+ AOFF_BF = 2
+};
+
typedef struct {
- int bf_within_carrier;
+ enum AOFF_Flavor flavor;
} AOFFAllctrInit_t;
#define ERTS_DEFAULT_AOFF_ALLCTR_INIT {0/*dummy*/}
@@ -52,7 +57,7 @@ struct AOFFAllctr_t_ {
Allctr_t allctr; /* Has to be first! */
struct AOFF_RBTree_t_* mbc_root;
- int bf_within_carrier;
+ enum AOFF_Flavor flavor;
};
UWord erts_aoffalc_test(UWord, UWord, UWord);
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index 58e53c3d00..41f449bb28 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.c
+++ b/erts/emulator/beam/erl_bestfit_alloc.c
@@ -966,15 +966,17 @@ UWord
erts_bfalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x200: return (UWord) ((BFAllctr_t *) a1)->address_order;
+ case 0x200: return (UWord) ((BFAllctr_t *) a1)->address_order; /* IS_AOBF */
case 0x201: return (UWord) ((BFAllctr_t *) a1)->mbc_root;
case 0x202: return (UWord) ((RBTree_t *) a1)->parent;
case 0x203: return (UWord) ((RBTree_t *) a1)->left;
case 0x204: return (UWord) ((RBTree_t *) a1)->right;
- case 0x205: return (UWord) ((RBTreeList_t *) a1)->next;
+ case 0x205: return (UWord) LIST_NEXT(a1);
case 0x206: return (UWord) IS_BLACK((RBTree_t *) a1);
case 0x207: return (UWord) IS_TREE_NODE((RBTree_t *) a1);
case 0x208: return (UWord) 1; /* IS_BF_ALGO */
+ case 0x20a: return (UWord) !((BFAllctr_t *) a1)->address_order; /* IS_BF */
+ case 0x20b: return (UWord) LIST_PREV(a1);
default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
index c37b074f93..2d6c5f9dc7 100644
--- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h
+++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
@@ -102,7 +102,8 @@ typedef void* erts_cond;
#define RBT_IS_TREE(T) ((Ulong) ALC_TEST1(RBT_OP(7), (T)))
#define IS_BF_ALGO(A) ((Ulong) ALC_TEST1(RBT_OP(8), (A)))
#define RBT_MAX_SZ(T) ((Ulong) ALC_TEST1(RBT_OP(9), (T)))
-#define IS_CBF(A) ((Ulong) ALC_TEST1(RBT_OP(0xa), (A)))
+#define IS_BF(A) ((Ulong) ALC_TEST1(RBT_OP(0xa), (A)))
+#define RBT_PREV(T) ((RBTL_t *) ALC_TEST1(RBT_OP(0xb), (T)))
/* From erl_mseg.c */
#define HAVE_MSEG() ((int) ALC_TEST0(0x400))
diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.c b/erts/emulator/test/alloc_SUITE_data/coalesce.c
index 36710bf7b5..9da49a0d14 100644
--- a/erts/emulator/test/alloc_SUITE_data/coalesce.c
+++ b/erts/emulator/test/alloc_SUITE_data/coalesce.c
@@ -267,7 +267,7 @@ void
testcase_run(TestCaseState_t *tcs)
{
char *argv_org[] = {"-tsmbcs511","-tmmbcs511", "-tsbct512", "-trmbcmt100", "-tas", NULL, NULL};
- char *alg[] = {"af", "gf", "bf", "aobf", "aoff", "aoffcaobf", NULL};
+ char *alg[] = {"af", "gf", "bf", "aobf", "aoff", "aoffcbf", "aoffcaobf", NULL};
int i;
for (i = 0; alg[i]; i++) {
diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.c b/erts/emulator/test/alloc_SUITE_data/rbtree.c
index 702f075304..49df2f0245 100644
--- a/erts/emulator/test/alloc_SUITE_data/rbtree.c
+++ b/erts/emulator/test/alloc_SUITE_data/rbtree.c
@@ -85,23 +85,21 @@ print_tree(TestCaseState_t *tcs, RBT_t *root)
static RBT_t *
check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size)
{
- enum { BF, AOBF, AOFF, AOFFCAOBF }type;
+ enum { BF, AOBF, AOFF } type;
int i, max_i;
char stk[128];
RBT_t *root, *x, *y, *res;
Ulong x_sz, y_sz, is_x_black;
long blacks, curr_blacks;
+ int have_max_sz;
res = NULL;
- if (IS_BF_ALGO(alc)) {
- if (IS_AOBF(alc)) type = AOBF;
- else type = BF;
- }
- else { /* AOFF_ALGO */
- if (IS_CBF(alc)) type = AOFFCAOBF;
- else type = AOFF;
- }
+ if (IS_AOBF(alc)) type = AOBF;
+ else if (IS_BF(alc)) type = BF;
+ else type = AOFF;
+
+ have_max_sz = !IS_BF_ALGO(alc);
root = RBT_ROOT(alc, size);
@@ -191,17 +189,10 @@ check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size)
break;
case AOFF:
ASSERT(tcs, y < x);
- ASSERT(tcs, RBT_MAX_SZ(y) <= RBT_MAX_SZ(x));
break;
- case AOFFCAOBF:
- {
- void* x_crr = BLK_TO_MBC(x);
- void* y_crr = BLK_TO_MBC(y);
- ASSERT(tcs, (y < x && (x_crr != y_crr || x_sz == y_sz))
- || (y_sz < x_sz && x_crr == y_crr));
- ASSERT(tcs, RBT_MAX_SZ(y) <= RBT_MAX_SZ(x));
- break;
- }
+ }
+ if (have_max_sz) {
+ ASSERT(tcs, RBT_MAX_SZ(y) <= RBT_MAX_SZ(x));
}
}
@@ -219,27 +210,22 @@ check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size)
break;
case AOFF:
ASSERT(tcs, y > x);
- ASSERT(tcs, RBT_MAX_SZ(y) <= RBT_MAX_SZ(x));
break;
- case AOFFCAOBF:
- {
- void* x_crr = BLK_TO_MBC(x);
- void* y_crr = BLK_TO_MBC(y);
- ASSERT(tcs, (y > x && (x_crr != y_crr || x_sz == y_sz))
- || (y_sz > x_sz && x_crr == y_crr));
- ASSERT(tcs, RBT_MAX_SZ(y) <= RBT_MAX_SZ(x));
- break;
- }
+ }
+ if (have_max_sz) {
+ ASSERT(tcs, RBT_MAX_SZ(y) <= RBT_MAX_SZ(x));
}
}
if (type == BF) {
Ulong l_sz;
- RBTL_t *l = RBT_NEXT(x);
+ RBTL_t *l, *prev=x;
for (l = RBT_NEXT(x); l; l = RBT_NEXT(l)) {
l_sz = BLK_SZ(l);
ASSERT(tcs, l_sz == x_sz);
ASSERT(tcs, !RBT_IS_TREE(l));
+ ASSERT(tcs, RBT_PREV(l) == prev);
+ prev = l;
}
}
@@ -262,18 +248,7 @@ check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size)
res = x;
}
break;
- case AOFFCAOBF:
- if (BLK_TO_MBC(x) != BLK_TO_MBC(res) || x_sz == y_sz) {
- if (x < res) {
- res = x;
- }
- }
- else if (x_sz < y_sz) {
- res = x;
- }
- break;
}
-
}
}
@@ -310,7 +285,7 @@ do_check(TestCaseState_t *tcs, Allctr_t *a, Ulong size, int ignore_null)
tmp = ALLOC(a, sz - ABLK_HDR_SZ);
ASSERT(tcs, tmp);
y = UMEM2BLK(tmp);
- if (!(IS_BF_ALGO(a) && !IS_AOBF(a))) {
+ if (!IS_BF(a)) {
ASSERT(tcs, x == y);
}
else {
@@ -488,6 +463,7 @@ testcase_run(TestCaseState_t *tcs)
char *argv2[] = {"-tasaobf", NULL};
char *argv3[] = {"-tasaoff", NULL};
char *argv4[] = {"-tasaoffcaobf", NULL};
+ char *argv5[] = {"-tasaoffcbf", NULL};
Allctr_t *a;
rbtree_test_data *td;
@@ -511,6 +487,7 @@ testcase_run(TestCaseState_t *tcs)
ASSERT(tcs, a);
ASSERT(tcs, IS_BF_ALGO(a));
ASSERT(tcs, !IS_AOBF(a));
+ ASSERT(tcs, IS_BF(a));
test_it(tcs);
@@ -529,6 +506,7 @@ testcase_run(TestCaseState_t *tcs)
ASSERT(tcs, a);
ASSERT(tcs, IS_BF_ALGO(a));
ASSERT(tcs, IS_AOBF(a));
+ ASSERT(tcs, !IS_BF(a));
test_it(tcs);
@@ -546,7 +524,8 @@ testcase_run(TestCaseState_t *tcs)
ASSERT(tcs, a);
ASSERT(tcs, !IS_BF_ALGO(a));
- ASSERT(tcs, !IS_CBF(a));
+ ASSERT(tcs, !IS_AOBF(a));
+ ASSERT(tcs, !IS_BF(a));
test_it(tcs);
test_carrier_migration(tcs);
@@ -556,7 +535,7 @@ testcase_run(TestCaseState_t *tcs)
testcase_printf(tcs, "Address order first fit test succeeded!\n");
- /* Address order first fit, best fit within carrier */
+ /* Address order first fit, aobf within carrier */
testcase_printf(tcs, "Starting test of aoffcaobf...\n");
@@ -565,7 +544,28 @@ testcase_run(TestCaseState_t *tcs)
ASSERT(tcs, a);
ASSERT(tcs, !IS_BF_ALGO(a));
- ASSERT(tcs, IS_CBF(a));
+ ASSERT(tcs, IS_AOBF(a));
+ ASSERT(tcs, !IS_BF(a));
+
+ test_it(tcs);
+ test_carrier_migration(tcs);
+
+ STOP_ALC(a);
+ td->allocator = NULL;
+
+ testcase_printf(tcs, "aoffcaobf test succeeded!\n");
+
+ /* Address order first fit, bf within carrier */
+
+ testcase_printf(tcs, "Starting test of aoffcbf...\n");
+
+ current_rbt_type_op_base = AO_FIRSTFIT_OP_BASE;
+ td->allocator = a = START_ALC("rbtree_aoffcbf_", 0, argv5);
+
+ ASSERT(tcs, a);
+ ASSERT(tcs, !IS_BF_ALGO(a));
+ ASSERT(tcs, !IS_AOBF(a));
+ ASSERT(tcs, IS_BF(a));
test_it(tcs);
test_carrier_migration(tcs);
diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard
index beecf1a7b5..a4da31a61d 100644
--- a/erts/emulator/valgrind/suppress.standard
+++ b/erts/emulator/valgrind/suppress.standard
@@ -174,6 +174,7 @@ obj:*/crypto.valgrind.*
{
Crypto internal...
Memcheck:Cond
+...
obj:*/libcrypto.*
}
{
@@ -194,6 +195,7 @@ obj:*/crypto.valgrind.*
{
Crypto internal...
Memcheck:Value8
+...
obj:*/libcrypto.*
}
{
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 255def22ca..e235c50f0b 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -17,8 +17,8 @@
# %CopyrightEnd%
#
-VSN = 5.10.2
-SYSTEM_VSN = R16B01
+VSN = 5.10.3
+SYSTEM_VSN = R16B02
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index e094ee877a..7f10e1db09 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -247,7 +247,11 @@
-define(is_timeout(T), (is_integer(T) orelse T==infinity)).
-define(is_filter(F),
- (is_atom(F) orelse (is_tuple(F) andalso is_atom(element(1,F))))).
+ (?is_simple_xml(F)
+ orelse (F==[])
+ orelse (is_list(F) andalso ?is_simple_xml(hd(F))))).
+-define(is_simple_xml(Xml),
+ (is_atom(Xml) orelse (is_tuple(Xml) andalso is_atom(element(1,Xml))))).
-define(is_string(S), (is_list(S) andalso is_integer(hd(S)))).
%%----------------------------------------------------------------------
@@ -540,22 +544,51 @@ get_capabilities(Client) ->
get_capabilities(Client, Timeout) ->
call(Client, get_capabilities, Timeout).
-%% @private
+%%----------------------------------------------------------------------
+%% @spec send(Client, SimpleXml) -> Result
+%% @equiv send(Client, SimpleXml, infinity)
send(Client, SimpleXml) ->
send(Client, SimpleXml, ?DEFAULT_TIMEOUT).
-%% @private
+
+%%----------------------------------------------------------------------
+-spec send(Client, SimpleXml, Timeout) -> Result when
+ Client :: client(),
+ SimpleXml :: simple_xml(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Send an XML document to the server.
+%%
+%% The given XML document is sent as is to the server. This function
+%% can be used for sending XML documents that can not be expressed by
+%% other interface functions in this module.
send(Client, SimpleXml, Timeout) ->
call(Client,{send, Timeout, SimpleXml}).
-%% @private
+%%----------------------------------------------------------------------
+%% @spec send_rpc(Client, SimpleXml) -> Result
+%% @equiv send_rpc(Client, SimpleXml, infinity)
send_rpc(Client, SimpleXml) ->
send_rpc(Client, SimpleXml, ?DEFAULT_TIMEOUT).
-%% @private
+
+%%----------------------------------------------------------------------
+-spec send_rpc(Client, SimpleXml, Timeout) -> Result when
+ Client :: client(),
+ SimpleXml :: simple_xml(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Send a Netconf <code>rpc</code> request to the server.
+%%
+%% The given XML document is wrapped in a valid Netconf
+%% <code>rpc</code> request and sent to the server. The
+%% <code>message-id</code> and namespace attributes are added to the
+%% <code>rpc</code> element.
+%%
+%% This function can be used for sending <code>rpc</code> requests
+%% that can not be expressed by other interface functions in this
+%% module.
send_rpc(Client, SimpleXml, Timeout) ->
call(Client,{send_rpc, SimpleXml, Timeout}).
-
-
%%----------------------------------------------------------------------
%% @spec lock(Client, Target) -> Result
%% @equiv lock(Client, Target, infinity)
@@ -761,7 +794,7 @@ create_subscription(Client,Timeout)
when ?is_timeout(Timeout) ->
create_subscription(Client,?DEFAULT_STREAM,Timeout);
create_subscription(Client,Stream)
- when is_list(Stream) ->
+ when ?is_string(Stream) ->
create_subscription(Client,Stream,?DEFAULT_TIMEOUT);
create_subscription(Client,Filter)
when ?is_filter(Filter) ->
@@ -769,14 +802,14 @@ create_subscription(Client,Filter)
?DEFAULT_TIMEOUT).
create_subscription(Client,Stream,Timeout)
- when is_list(Stream) andalso
+ when ?is_string(Stream) andalso
?is_timeout(Timeout) ->
call(Client,{send_rpc_op,{create_subscription,self()},
[Stream,undefined,undefined,undefined],
Timeout});
create_subscription(Client,StartTime,StopTime)
- when is_list(StartTime) andalso
- is_list(StopTime) ->
+ when ?is_string(StartTime) andalso
+ ?is_string(StopTime) ->
create_subscription(Client,?DEFAULT_STREAM,StartTime,StopTime,
?DEFAULT_TIMEOUT);
create_subscription(Client,Filter,Timeout)
@@ -784,28 +817,28 @@ create_subscription(Client,Filter,Timeout)
?is_timeout(Timeout) ->
create_subscription(Client,?DEFAULT_STREAM,Filter,Timeout);
create_subscription(Client,Stream,Filter)
- when is_list(Stream) andalso
+ when ?is_string(Stream) andalso
?is_filter(Filter) ->
create_subscription(Client,Stream,Filter,?DEFAULT_TIMEOUT).
create_subscription(Client,StartTime,StopTime,Timeout)
- when is_list(StartTime) andalso
- is_list(StopTime) andalso
+ when ?is_string(StartTime) andalso
+ ?is_string(StopTime) andalso
?is_timeout(Timeout) ->
create_subscription(Client,?DEFAULT_STREAM,StartTime,StopTime,Timeout);
create_subscription(Client,Stream,StartTime,StopTime)
- when is_list(Stream) andalso
- is_list(StartTime) andalso
- is_list(StopTime) ->
+ when ?is_string(Stream) andalso
+ ?is_string(StartTime) andalso
+ ?is_string(StopTime) ->
create_subscription(Client,Stream,StartTime,StopTime,?DEFAULT_TIMEOUT);
create_subscription(Client,Filter,StartTime,StopTime)
when ?is_filter(Filter) andalso
- is_list(StartTime) andalso
- is_list(StopTime) ->
+ ?is_string(StartTime) andalso
+ ?is_string(StopTime) ->
create_subscription(Client,?DEFAULT_STREAM,Filter,
StartTime,StopTime,?DEFAULT_TIMEOUT);
create_subscription(Client,Stream,Filter,Timeout)
- when is_list(Stream) andalso
+ when ?is_string(Stream) andalso
?is_filter(Filter) andalso
?is_timeout(Timeout) ->
call(Client,{send_rpc_op,{create_subscription,self()},
@@ -813,18 +846,18 @@ create_subscription(Client,Stream,Filter,Timeout)
Timeout}).
create_subscription(Client,Stream,StartTime,StopTime,Timeout)
- when is_list(Stream) andalso
- is_list(StartTime) andalso
- is_list(StopTime) andalso
+ when ?is_string(Stream) andalso
+ ?is_string(StartTime) andalso
+ ?is_string(StopTime) andalso
?is_timeout(Timeout) ->
call(Client,{send_rpc_op,{create_subscription,self()},
[Stream,undefined,StartTime,StopTime],
Timeout});
create_subscription(Client,Stream,Filter,StartTime,StopTime)
- when is_list(Stream) andalso
+ when ?is_string(Stream) andalso
?is_filter(Filter) andalso
- is_list(StartTime) andalso
- is_list(StopTime) ->
+ ?is_string(StartTime) andalso
+ ?is_string(StopTime) ->
create_subscription(Client,Stream,Filter,StartTime,StopTime,?DEFAULT_TIMEOUT).
%%----------------------------------------------------------------------
@@ -832,7 +865,7 @@ create_subscription(Client,Stream,Filter,StartTime,StopTime)
Result when
Client :: client(),
Stream :: stream_name(),
- Filter :: simple_xml(),
+ Filter :: simple_xml() | [simple_xml()],
StartTime :: xs_datetime(),
StopTime :: xs_datetime(),
Timeout :: timeout(),
@@ -855,8 +888,7 @@ create_subscription(Client,Stream,Filter,StartTime,StopTime)
%% possible events is of interest. The format of this parameter is
%% the same as that of the filter parameter in the NETCONF protocol
%% operations. If not present, all events not precluded by other
-%% parameters will be sent. See section 3.6 for more information on
-%% filters.</dd>
+%% parameters will be sent.</dd>
%%
%% <dt>StartTime:</dt>
%% <dd>An optional parameter used to trigger the replay feature and
@@ -1241,8 +1273,10 @@ filter(undefined) ->
[];
filter({xpath,Filter}) when ?is_string(Filter) ->
[{filter,[{type,"xpath"},{select, Filter}],[]}];
+filter(Filter) when is_list(Filter) ->
+ [{filter,[{type,"subtree"}],Filter}];
filter(Filter) ->
- [{filter,[{type,"subtree"}],[Filter]}].
+ filter([Filter]).
maybe_element(_,undefined) ->
[];
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index 0535eb924b..6ee7fdd6f6 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -886,6 +886,19 @@ create_subscription(Config) ->
?NS:expect_do_reply('close-session',close,ok),
?ok = ct_netconfc:close_session(Client8),
+ %% Multiple filters
+ {ok,Client9} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,filter]},ok),
+ MultiFilters = [{event,[{xmlns,"http://my.namespaces.com/event"}],
+ [{eventClass,["fault"]},
+ {severity,["critical"]}]},
+ {event,[{xmlns,"http://my.namespaces.com/event"}],
+ [{eventClass,["fault"]},
+ {severity,["major"]}]}],
+ ?ok = ct_netconfc:create_subscription(Client9,MultiFilters),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client9),
+
ok.
receive_event(Config) ->
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 35de3dbf0c..c28ff8136c 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -242,8 +242,6 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -372,12 +370,10 @@ static ErlNifFunc nif_funcs[] = {
{"bf_ecb_crypt", 3, bf_ecb_crypt},
{"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},
- {"ec_key_to_term_nif", 1, ec_key_to_term_nif},
- {"term_to_ec_key_nif", 3, term_to_ec_key_nif},
{"ec_key_generate", 1, ec_key_generate},
- {"ecdsa_sign_nif", 3, ecdsa_sign_nif},
- {"ecdsa_verify_nif", 4, ecdsa_verify_nif},
- {"ecdh_compute_key_nif", 2, ecdh_compute_key_nif}
+ {"ecdsa_sign_nif", 4, ecdsa_sign_nif},
+ {"ecdsa_verify_nif", 5, ecdsa_verify_nif},
+ {"ecdh_compute_key_nif", 3, ecdh_compute_key_nif}
};
#if defined(HAVE_EC)
@@ -472,10 +468,7 @@ static struct nid_map ec_curves[] = {
#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map))
-struct nif_ec_key {
- EC_KEY *key;
-};
-#endif
+#endif /* HAVE_EC */
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
@@ -528,17 +521,13 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
-static ERL_NIF_TERM atom_ec;
-
#if defined(HAVE_EC)
+static ERL_NIF_TERM atom_ec;
static ERL_NIF_TERM atom_prime_field;
static ERL_NIF_TERM atom_characteristic_two_field;
static ERL_NIF_TERM atom_tpbasis;
static ERL_NIF_TERM atom_ppbasis;
static ERL_NIF_TERM atom_onbasis;
-
-static ErlNifResourceType* res_type_ec_key;
-static void ec_key_dtor(ErlNifEnv* env, void* obj);
#endif
/*
@@ -570,7 +559,6 @@ static void error_handler(void* null, const char* errstr)
static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
- int i;
ErlNifSysInfo sys_info;
get_crypto_callbacks_t* funcp;
struct crypto_callbacks* ccb;
@@ -591,13 +579,6 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
return 0;
}
-#if defined(HAVE_EC)
- res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY",
- ec_key_dtor,
- ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
- NULL);
-#endif
-
if (library_refc > 0) {
/* Repeated loading of this library (module upgrade).
* Atoms and callbacks are already set, we are done.
@@ -639,8 +620,11 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_ppbasis = enif_make_atom(env,"ppbasis");
atom_onbasis = enif_make_atom(env,"onbasis");
- for (i = 0; i < EC_CURVES_CNT; i++)
+ {
+ int i;
+ for (i = 0; i < EC_CURVES_CNT; i++)
ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name);
+ }
#endif
init_digest_types(env);
@@ -1440,7 +1424,7 @@ static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
HMAC_CTX_cleanup(&ctx);
if (argc == 2 && req_len < mac_len) {
- // Only truncate to req_len bytes if asked.
+ /* Only truncate to req_len bytes if asked. */
mac_len = req_len;
}
mac_bin = enif_make_new_binary(env, mac_len, &ret);
@@ -2939,7 +2923,7 @@ static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
&& c_arity == 5
&& get_bn_from_bin(env, curve[3], &bn_order)
&& (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
- //* {Field, Prime, Point, Order, CoFactor} = Curve */
+ /* {Field, Prime, Point, Order, CoFactor} = Curve */
int f_arity = -1;
const ERL_NIF_TERM* field;
@@ -3093,7 +3077,7 @@ static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
dlen = BN_num_bytes(bn);
ptr = enif_make_new_binary(env, dlen, &ret);
BN_bn2bin(bn, ptr);
-
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ptr, dlen);
return ret;
}
@@ -3116,39 +3100,10 @@ static ERL_NIF_TERM point2term(ErlNifEnv* env,
enif_release_binary(&bin);
return enif_make_badarg(env);
}
-
+ ERL_VALGRIND_MAKE_MEM_DEFINED(bin.data, bin.size);
return enif_make_binary(env, &bin);
}
-#endif
-
-static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
-#if defined(HAVE_EC)
- struct nif_ec_key *obj;
- const EC_GROUP *group;
- const EC_POINT *public_key;
- const BIGNUM *priv_key = NULL;
- ERL_NIF_TERM pub_key = atom_undefined;
-
- if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj))
- return enif_make_badarg(env);
-
- group = EC_KEY_get0_group(obj->key);
- public_key = EC_KEY_get0_public_key(obj->key);
- priv_key = EC_KEY_get0_private_key(obj->key);
-
- if (group) {
- if (public_key)
- pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
- }
-
- return enif_make_tuple2(env, pub_key, bn2term(env, priv_key));
-#else
- return atom_notsup;
-#endif
-}
-#if defined(HAVE_EC)
static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
EC_GROUP *group, EC_POINT **pptr)
{
@@ -3176,24 +3131,22 @@ static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
return ret;
}
-#endif
-static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static int get_ec_key(ErlNifEnv* env,
+ ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub,
+ EC_KEY** res)
{
-#if defined(HAVE_EC)
- ERL_NIF_TERM ret;
EC_KEY *key = NULL;
BIGNUM *priv_key = NULL;
EC_POINT *pub_key = NULL;
- struct nif_ec_key *obj;
EC_GROUP *group = NULL;
- if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key))
- || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) {
+ if (!(priv == atom_undefined || get_bn_from_bin(env, priv, &priv_key))
+ || !(pub == atom_undefined || enif_is_binary(env, pub))) {
goto out_err;
}
- key = ec_key_new(env, argv[0]);
+ key = ec_key_new(env, curve);
if (!key) {
goto out_err;
@@ -3202,12 +3155,12 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
if (!group)
group = EC_GROUP_dup(EC_KEY_get0_group(key));
- if (term2point(env, argv[2], group, &pub_key)) {
+ if (term2point(env, pub, group, &pub_key)) {
if (!EC_KEY_set_public_key(key, pub_key)) {
goto out_err;
}
}
- if (argv[1] != atom_undefined
+ if (priv != atom_undefined
&& !BN_is_zero(priv_key)) {
if (!EC_KEY_set_private_key(key, priv_key))
goto out_err;
@@ -3226,19 +3179,11 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
}
}
- obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
- if (!obj)
- goto out_err;
-
- obj->key = key;
- ret = enif_make_resource(env, obj);
- enif_release_resource(obj);
-
goto out;
out_err:
if (key) EC_KEY_free(key);
- ret = enif_make_badarg(env);
+ key = NULL;
out:
/* some OpenSSL structures are mem-dup'ed into the key,
@@ -3246,11 +3191,12 @@ out:
if (priv_key) BN_clear_free(priv_key);
if (pub_key) EC_POINT_free(pub_key);
if (group) EC_GROUP_free(group);
- return ret;
-#else
- return atom_notsup;
-#endif
+ if (!key)
+ return 0;
+ *res = key;
+ return 1;
}
+#endif /* HAVE_EC */
static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
@@ -3258,14 +3204,21 @@ static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM
EC_KEY *key = ec_key_new(env, argv[0]);
if (key && EC_KEY_generate_key(key)) {
- ERL_NIF_TERM term;
- struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
- if (!obj)
- return atom_error;
- obj->key = key;
- term = enif_make_resource(env, obj);
- enif_release_resource(obj);
- return term;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ ERL_NIF_TERM priv_key;
+ ERL_NIF_TERM pub_key = atom_undefined;
+
+ group = EC_KEY_get0_group(key);
+ public_key = EC_KEY_get0_public_key(key);
+
+ if (group && public_key) {
+ pub_key = point2term(env, group, public_key,
+ EC_KEY_get_conv_form(key));
+ }
+ priv_key = bn2term(env, EC_KEY_get0_private_key(key));
+ EC_KEY_free(key);
+ return enif_make_tuple2(env, pub_key, priv_key);
}
else
return enif_make_badarg(env);
@@ -3274,21 +3227,13 @@ static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM
#endif
}
-#if defined(HAVE_EC)
-static void ec_key_dtor(ErlNifEnv* env, void* obj)
-{
- struct nif_ec_key *key = (struct nif_ec_key*) obj;
- EC_KEY_free(key->key);
-}
-#endif
-
static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Data|{digest,Digest}, Key) */
+{/* (Type, Data|{digest,Digest}, Curve, Key) */
#if defined(HAVE_EC)
ErlNifBinary data_bin, ret_bin;
unsigned char hmacbuf[SHA_DIGEST_LENGTH];
unsigned int dsa_s_len;
- struct nif_ec_key *obj;
+ EC_KEY* key = NULL;
int i;
const ERL_NIF_TERM* tpl_terms;
int tpl_arity;
@@ -3303,30 +3248,32 @@ static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return atom_notsup;
}
- if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj))
- return enif_make_badarg(env);
+ if (!get_ec_key(env, argv[2], argv[3], atom_undefined, &key))
+ goto badarg;
if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
if (tpl_arity != 2 || tpl_terms[0] != atom_digest
|| !enif_inspect_binary(env, tpl_terms[1], &data_bin)
|| data_bin.size != digp->len) {
- return enif_make_badarg(env);
+ goto badarg;
}
digest = data_bin.data;
}
else {
if (!enif_inspect_binary(env,argv[1],&data_bin)) {
- return enif_make_badarg(env);
+ goto badarg;
}
digest = hmacbuf;
digp->funcp(data_bin.data, data_bin.size, digest);
}
- enif_alloc_binary(ECDSA_size(obj->key), &ret_bin);
+ enif_alloc_binary(ECDSA_size(key), &ret_bin);
i = ECDSA_sign(digp->NID_type, digest, digp->len,
- ret_bin.data, &dsa_s_len, obj->key);
+ ret_bin.data, &dsa_s_len, key);
+
+ EC_KEY_free(key);
if (i) {
if (dsa_s_len != ret_bin.size) {
enif_realloc_binary(&ret_bin, dsa_s_len);
@@ -3337,18 +3284,23 @@ static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
enif_release_binary(&ret_bin);
return atom_error;
}
+
+badarg:
+ if (key)
+ EC_KEY_free(key);
+ return enif_make_badarg(env);
#else
return atom_notsup;
#endif
}
static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Data|{digest,Digest}, Signature, Key) */
+{/* (Type, Data|{digest,Digest}, Signature, Curve, Key) */
#if defined(HAVE_EC)
ErlNifBinary data_bin, sign_bin;
unsigned char hmacbuf[SHA512_LEN];
int i;
- struct nif_ec_key *obj;
+ EC_KEY* key = NULL;
const ERL_NIF_TERM type = argv[0];
const ERL_NIF_TERM* tpl_terms;
int tpl_arity;
@@ -3364,15 +3316,15 @@ static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
}
if (!enif_inspect_binary(env, argv[2], &sign_bin)
- || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj))
- return enif_make_badarg(env);
+ || !get_ec_key(env, argv[3], atom_undefined, argv[4], &key))
+ goto badarg;
if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
if (tpl_arity != 2 || tpl_terms[0] != atom_digest
|| !enif_inspect_binary(env, tpl_terms[1], &data_bin)
|| data_bin.size != digp->len) {
- return enif_make_badarg(env);
+ goto badarg;
}
digest = data_bin.data;
}
@@ -3381,13 +3333,20 @@ static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
digp->funcp(data_bin.data, data_bin.size, digest);
}
else {
- return enif_make_badarg(env);
+ goto badarg;
}
i = ECDSA_verify(digp->NID_type, digest, digp->len,
- sign_bin.data, sign_bin.size, obj->key);
+ sign_bin.data, sign_bin.size, key);
+
+ EC_KEY_free(key);
return (i==1 ? atom_true : atom_false);
+
+badarg:
+ if (key)
+ EC_KEY_free(key);
+ return enif_make_badarg(env);
#else
return atom_notsup;
#endif
@@ -3398,24 +3357,24 @@ static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
(_OthersPublicKey, _MyEC_Point)
*/
static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+/* (OtherPublicKey, Curve, My) */
{
#if defined(HAVE_EC)
ERL_NIF_TERM ret;
unsigned char *p;
- struct nif_ec_key *other_key;
+ EC_KEY* key = NULL;
int field_size = 0;
int i;
-
EC_GROUP *group;
const BIGNUM *priv_key;
EC_POINT *my_ecpoint;
EC_KEY *other_ecdh = NULL;
- if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&other_key))
+ if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key))
return enif_make_badarg(env);
- group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key));
- priv_key = EC_KEY_get0_private_key(other_key->key);
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+ priv_key = EC_KEY_get0_private_key(key);
if (!term2point(env, argv[0], group, &my_ecpoint)) {
goto out_err;
@@ -3439,6 +3398,7 @@ out:
if (group) EC_GROUP_free(group);
if (my_ecpoint) EC_POINT_free(my_ecpoint);
if (other_ecdh) EC_KEY_free(other_ecdh);
+ if (key) EC_KEY_free(key);
return ret;
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index a093b45410..8e8370f3b0 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -455,7 +455,7 @@ verify(rsa, Type, DataOrDigest, Signature, Key) ->
Bool -> Bool
end;
verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) ->
- case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Curve, undefined, Key)) of
+ case ecdsa_verify_nif(Type, DataOrDigest, Signature, nif_curve_params(Curve), ensure_int_as_bin(Key)) of
notsup -> erlang:error(notsup);
Bool -> Bool
end.
@@ -474,7 +474,7 @@ sign(dss, Type, DataOrDigest, Key) ->
Sign -> Sign
end;
sign(ecdsa, Type, DataOrDigest, [Key, Curve]) ->
- case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Curve, Key, undefined)) of
+ case ecdsa_sign_nif(Type, DataOrDigest, nif_curve_params(Curve), ensure_int_as_bin(Key)) of
error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
Sign -> Sign
end.
@@ -557,7 +557,7 @@ generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
user_srp_gen_key(Private, Generator, Prime);
generate_key(ecdh, Curve, undefined) ->
- ec_key_to_term_nif(ec_key_generate(Curve)).
+ ec_key_generate(Curve).
compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
@@ -599,7 +599,8 @@ compute_key(srp, UserPublic, {HostPublic, HostPrivate},
compute_key(ecdh, Others, My, Curve) ->
ecdh_compute_key_nif(ensure_int_as_bin(Others),
- term_to_ec_key(Curve,My,undefined)).
+ nif_curve_params(Curve),
+ ensure_int_as_bin(My)).
random_bytes(N) ->
@@ -1399,11 +1400,11 @@ srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_s
%% Digital signatures --------------------------------------------------------------------
rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
-ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
+ecdsa_sign_nif(_Type, _DataOrDigest, _Curve, _Key) -> ?nif_stub.
dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
-ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
+ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Curve, _Key) -> ?nif_stub.
%% Public Keys --------------------------------------------------------------------
%% DH Diffie-Hellman functions
@@ -1456,12 +1457,11 @@ dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
ec_key_generate(_Key) -> ?nif_stub.
-ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
+ecdh_compute_key_nif(_Others, _Curve, _My) -> ?nif_stub.
%%
%% EC
%%
-ec_key_to_term_nif(_Key) -> ?nif_stub.
term_to_nif_prime({prime_field, Prime}) ->
{prime_field, int_to_bin(Prime)};
@@ -1469,19 +1469,12 @@ term_to_nif_prime(PrimeField) ->
PrimeField.
term_to_nif_curve({A, B, Seed}) ->
{ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}.
-term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
+nif_curve_params({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
{term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), int_to_bin(Order), int_to_bin(CoFactor)};
-term_to_nif_curve_parameters(Curve) when is_atom(Curve) ->
+nif_curve_params(Curve) when is_atom(Curve) ->
%% named curve
Curve.
-term_to_ec_key(Curve, PrivKey, PubKey) ->
- term_to_ec_key_nif(term_to_nif_curve_parameters(Curve),
- ensure_int_as_bin(PrivKey),
- ensure_int_as_bin(PubKey)).
-
-term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
-
%% MISC --------------------------------------------------------------------
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 72d67ddb4a..d2e7ade5d6 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,7 +32,6 @@
<file>notes.xml</file>
</header>
-
<section><title>Inets 5.9.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -93,7 +92,6 @@
</section>
<section><title>Inets 5.9.4</title>
-
<section><title>Improvements and New Features</title>
<list>
<item>
@@ -161,6 +159,19 @@
</section>
+<section><title>Inets 5.9.2.1</title>
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Fixed obsolete error report in inets.</p>
+ <p>
+ Own Id: OTP-11185 Aux Id: seq12357 </p>
+ </item>
+ </list>
+ </section>
+</section>
+
<section><title>Inets 5.9.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 41bba7995e..4d7023a8e9 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -175,7 +175,7 @@ request(Method,
request(Method,
{Url, Headers, ContentType, Body},
HTTPOptions, Options, Profile)
- when ((Method =:= post) orelse (Method =:= put)) andalso
+ when ((Method =:= post) orelse (Method =:= put) orelse (Method =:= delete)) andalso
(is_atom(Profile) orelse is_pid(Profile)) ->
?hcrt("request", [{method, Method},
{url, Url},
diff --git a/lib/inets/src/http_server/httpd_manager.erl b/lib/inets/src/http_server/httpd_manager.erl
index c83d06a158..00384fa108 100644
--- a/lib/inets/src/http_server/httpd_manager.erl
+++ b/lib/inets/src/http_server/httpd_manager.erl
@@ -507,37 +507,8 @@ code_change(_FromVsn, State, _Extra) ->
check_connections(#state{connections = []} = State, _Pid, _Reason) ->
State;
-check_connections(#state{admin_state = shutting_down,
- connections = Connections} = State, Pid, Reason) ->
- %% Could be a crashing request handler
- case lists:delete(Pid, Connections) of
- [] -> % Crashing request handler => block complete
- String =
- lists:flatten(
- io_lib:format("request handler (~p) crashed:"
- "~n ~p", [Pid, Reason])),
- report_error(State, String),
- demonitor_blocker(State#state.blocker_ref),
- {Tmr,From,Ref} = State#state.blocking_tmr,
- stop_block_tmr(Tmr),
- From ! {block_reply,ok,Ref},
- State#state{admin_state = blocked, connections = [],
- blocker_ref = undefined};
- Connections1 ->
- State#state{connections = Connections1}
- end;
-check_connections(#state{connections = Connections} = State, Pid, Reason) ->
- case lists:delete(Pid, Connections) of
- Connections -> % Not a request handler, so ignore
- State;
- NewConnections ->
- String =
- lists:flatten(
- io_lib:format("request handler (~p) crashed:"
- "~n ~p", [Pid, Reason])),
- report_error(State, String),
- State#state{connections = NewConnections}
- end.
+check_connections(#state{connections = Connections} = State, Pid, _Reason) ->
+ State#state{connections = lists:delete(Pid, Connections)}.
%% -------------------------------------------------------------------------
diff --git a/lib/inets/test/httpc_proxy_SUITE.erl b/lib/inets/test/httpc_proxy_SUITE.erl
index 84db39e76b..ddd23d0c65 100644
--- a/lib/inets/test/httpc_proxy_SUITE.erl
+++ b/lib/inets/test/httpc_proxy_SUITE.erl
@@ -69,6 +69,7 @@ local_proxy_cases() ->
http_post,
http_put,
http_delete,
+ http_delete_body,
http_headers,
http_proxy_auth,
http_doesnotexist,
@@ -262,6 +263,22 @@ http_delete(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
+http_delete_body(doc) ->
+ ["Perform a DELETE request with a content body. The server will not allow it "
+ "but we only test sending the request."];
+http_delete_body(Config) when is_list(Config) ->
+ Method = delete,
+ URL = url("/delete.html", Config),
+ Content = "foo=bar",
+ Request = {URL,[],"application/x-www-form-urlencoded",Content},
+ HttpOpts = [],
+ Opts = [],
+ {ok,{{_,405,_},[_|_],[_|_]}} =
+ httpc:request(Method, Request, HttpOpts, Opts),
+ ok.
+
+%%--------------------------------------------------------------------
+
http_headers(doc) ->
["Use as many request headers as possible"];
http_headers(Config) when is_list(Config) ->
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 49404196dd..96c1e3d83d 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.16.2
+KERNEL_VSN = 2.16.3
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 254601b107..2c9b17478d 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -42,6 +42,7 @@ groups() ->
%%--------------------------------------------------------------------
init_per_suite(Config) ->
+ application:stop(crypto),
try crypto:start() of
ok ->
Config
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index 9180fa968b..699481b20f 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -111,6 +111,7 @@ groups() ->
%%--------------------------------------------------------------------
init_per_suite(Config) ->
+ application:stop(crypto),
try crypto:start() of
ok ->
application:start(asn1),
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index f2596e3d85..c3aa2e2366 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -56,6 +56,7 @@ groups() ->
].
%%-------------------------------------------------------------------
init_per_suite(Config) ->
+ application:stop(crypto),
try crypto:start() of
ok ->
application:start(asn1),
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 367cab1d77..3921b2d3bb 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -59,6 +59,7 @@
-export([otp_6226_outdir/1]).
-export([init_per_suite/1, end_per_suite/1,
init_per_testcase/2, end_per_testcase/2]).
+-export([delete_tree/1]).
-import(lists, [foldl/3]).
@@ -299,6 +300,11 @@ unicode_script(Config) when is_list(Config) ->
%% 3. path (directory name where unicode_app.tgz is extracted)
true = lists:member({path,[P1]},Instr),
+ %% If all is good, delete the unicode dir to avoid lingering files
+ %% on windows.
+ rpc:call(Node,code,add_pathz,[filename:dirname(code:which(?MODULE))]),
+ rpc:call(Node,?MODULE,delete_tree,[UnicodeLibDir]),
+
ok.
unicode_script(cleanup,Config) ->
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 8e112433c1..299dd5058a 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -195,8 +195,6 @@
</item>
</list>
</section>
-
-
<section><title>Improvements and New Features</title>
<list>
<item>
@@ -251,7 +249,20 @@
</section>
</section>
+<section><title>Ssh 2.1.2.1</title>
+<section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Removed error report in ssh_connection_handler triggered
+ by badmatch failure.</p>
+ <p>
+ Own Id: OTP-11188</p>
+ </item>
+ </list>
+ </section>
+</section>
<section><title>Ssh 2.1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 69b1ab186f..54911e757c 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -68,7 +68,8 @@ init([Shell]) ->
handle_ssh_msg({ssh_cm, _ConnectionManager,
{data, _ChannelId, _Type, Data}},
#state{group = Group} = State) ->
- Group ! {self(), {data, binary_to_list(Data)}},
+ List = binary_to_list(Data),
+ to_group(List, Group),
{ok, State};
handle_ssh_msg({ssh_cm, ConnectionManager,
@@ -188,6 +189,22 @@ terminate(_Reason, _State) ->
%%% Internal functions
%%--------------------------------------------------------------------
+to_group([], _Group) ->
+ ok;
+to_group([$\^C | Tail], Group) ->
+ exit(Group, interrupt),
+ to_group(Tail, Group);
+to_group(Data, Group) ->
+ Func = fun(C) -> C /= $\^C end,
+ Tail = case lists:splitwith(Func, Data) of
+ {[], Right} ->
+ Right;
+ {Left, Right} ->
+ Group ! {self(), {data, Left}},
+ Right
+ end,
+ to_group(Tail, Group).
+
exec(Cmd) ->
case eval(parse(scan(Cmd))) of
{error, _} ->
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 1c4477aeb3..df6175e27c 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -451,11 +451,12 @@ userauth(#ssh_msg_userauth_failure{authentications = Methodes},
case ssh_auth:userauth_request_msg(Ssh1) of
{disconnect, DisconnectMsg, {Msg, Ssh}} ->
send_msg(Msg, State),
- handle_disconnect(DisconnectMsg, State#state{ssh_params = Ssh});
+ handle_disconnect(DisconnectMsg, State#state{ssh_params = Ssh});
{Msg, Ssh} ->
send_msg(Msg, State),
{next_state, userauth, next_packet(State#state{ssh_params = Ssh})}
end;
+
%% The prefered authentication method failed try next method
userauth(#ssh_msg_userauth_failure{},
#state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index f115a32710..21cdedc156 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -315,5 +315,12 @@ default_user_dir()->
{ok,[[Home|_]]} = init:get_argument(home),
UserDir = filename:join(Home, ".ssh"),
ok = filelib:ensure_dir(filename:join(UserDir, "dummy")),
- ok = file:change_mode(UserDir, ?PERM_700),
+ {ok,Info} = file:read_file_info(UserDir),
+ #file_info{mode=Mode} = Info,
+ case (Mode band 8#777) of
+ ?PERM_700 ->
+ ok;
+ _Other ->
+ ok = file:change_mode(UserDir, ?PERM_700)
+ end,
UserDir.
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index bc76c9fd10..b18d3dc0c0 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -124,7 +124,7 @@
{noreply, NewState :: term()} |
{noreply, NewState :: term(), timeout() | hibernate} |
{stop, Reason :: term(), NewState :: term()}.
--callback handle_info(Info :: timeout() | term(), State :: term()) ->
+-callback handle_info(Info :: timeout | term(), State :: term()) ->
{noreply, NewState :: term()} |
{noreply, NewState :: term(), timeout() | hibernate} |
{stop, Reason :: term(), NewState :: term()}.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index fbb838c686..ba6f7cdb8a 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.19.2
+STDLIB_VSN = 1.19.3
diff --git a/lib/tools/emacs/erlang-skels.el b/lib/tools/emacs/erlang-skels.el
index 355b223822..527e812444 100644
--- a/lib/tools/emacs/erlang-skels.el
+++ b/lib/tools/emacs/erlang-skels.el
@@ -457,7 +457,7 @@ Please see the function `tempo-define-template'.")
"handle_info/2," n>
"terminate/2, code_change/3])." n n
- "-define(SERVER, ?MODULE). " n n
+ "-define(SERVER, ?MODULE)." n n
"-record(state, {})." n n
@@ -572,7 +572,7 @@ Please see the function `tempo-define-template'.")
"-export([init/1, handle_event/2, handle_call/2, " n>
"handle_info/2, terminate/2, code_change/3])." n n
- "-define(SERVER, ?MODULE). " n n
+ "-define(SERVER, ?MODULE)." n n
"-record(state, {})." n n
diff --git a/system/doc/tutorial/nif.xmlsrc b/system/doc/tutorial/nif.xmlsrc
index 6cb54ff7ff..79cef31160 100644
--- a/system/doc/tutorial/nif.xmlsrc
+++ b/system/doc/tutorial/nif.xmlsrc
@@ -29,7 +29,7 @@
<file>nif.xml</file>
</header>
<p>This is an example of how to solve the <seealso marker="example">example problem</seealso>
- by using NIFs. NIFs where introduced in R13B03 as an experimental
+ by using NIFs. NIFs were introduced in R13B03 as an experimental
feature. It is a simpler and more efficient way of calling C-code
than using port drivers. NIFs are most suitable for synchronous functions like
<c>foo</c> and <c>bar</c> in the example, that does some
@@ -85,7 +85,7 @@
<p>The function arguments passed to a NIF appears in an array <c>argv</c>,
with <c>argc</c> as the length of the array and thus the arity of the
function. The Nth argument of the function can be accessed as
- <c>argv[N-1]</c>. NIFs also takes an environment argument that
+ <c>argv[N-1]</c>. NIFs also take an environment argument that
serves as an opaque handle that is needed to be passed on to
most API functions. The environment contains information about
the calling Erlang process.</p>
@@ -98,7 +98,7 @@
structures containing name, arity and function pointer of
each NIF. The other arguments are pointers to callback functions
that can be used to initialize the library. We do not use them
- is this simple example so we set them all to <c>NULL</c>.</p>
+ in this simple example so we set them all to <c>NULL</c>.</p>
<p>Function arguments and return values are represented as values
of type <c>ERL_NIF_TERM</c>. We use functions like <c>enif_get_int</c>
and <c>enif_make_int</c> to convert between Erlang term and C-type.