misc: Add twalk_r function
Commit Message
The twalk function is very difficult to use in a multi-threaded
program because there is no way to pass external state to the
iterator function.
(I expect to use this new function in sem_close and
__gconv_release_shlib, but the function is generally useful.)
2019-04-29 Florian Weimer <fweimer@redhat.com>
misc: Add twalk_r function.
* include/search.h (__twalk_r): Declare.
* manual/examples/twalk.c: New file.
* manual/search.texi (Tree Search Function): Document twalk_r.
* misc/Versions (2.30): Export twalk_r.
(GLIBC_PRIVATE): Export __twalk_r.
* misc/search.h [__USE_GNU] (twalk_r): Declare.
* misc/tsearch.c (trecurse_r, __twalk_r): New functions.
(twalk_r): Add weak alias.
* misc/tst-tsearch.c (struct walk_trace_element): Define.
(walk_trace): New variable.
(struct twalk_with_twalk_r_closure): Define.
(twalk_with_twalk_r_action): New function.
(twalk_with_twalk_r): Likewise.
(walk_action): Call walk_trace_add.
(walk_tree_with): Rename from walk_tree. Add walk argument.
(walk_tree): New function.
* sysdeps/mach/hurd/i386/libc.abilist (GLIBC_2.30): Add twalk_r.
* sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
Likewise.
Comments
On 4/29/19 8:51 AM, Florian Weimer wrote:
> The twalk function is very difficult to use in a multi-threaded
> program because there is no way to pass external state to the
> iterator function.
I like *_r variants of existing functions. Thanks for adding this.
OK with typo fix in manual (see below s/threat/thread/g).
For a new API though I'd like to see one more reviewer, can you
track down someone else?
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> (I expect to use this new function in sem_close and
> __gconv_release_shlib, but the function is generally useful.)
>
> 2019-04-29 Florian Weimer <fweimer@redhat.com>
>
> misc: Add twalk_r function.
> * include/search.h (__twalk_r): Declare.
> * manual/examples/twalk.c: New file.
> * manual/search.texi (Tree Search Function): Document twalk_r.
> * misc/Versions (2.30): Export twalk_r.
> (GLIBC_PRIVATE): Export __twalk_r.
> * misc/search.h [__USE_GNU] (twalk_r): Declare.
> * misc/tsearch.c (trecurse_r, __twalk_r): New functions.
> (twalk_r): Add weak alias.
> * misc/tst-tsearch.c (struct walk_trace_element): Define.
> (walk_trace): New variable.
> (struct twalk_with_twalk_r_closure): Define.
> (twalk_with_twalk_r_action): New function.
> (twalk_with_twalk_r): Likewise.
> (walk_action): Call walk_trace_add.
> (walk_tree_with): Rename from walk_tree. Add walk argument.
> (walk_tree): New function.
> * sysdeps/mach/hurd/i386/libc.abilist (GLIBC_2.30): Add twalk_r.
> * sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
> Likewise.
>
> diff --git a/NEWS b/NEWS
> index 792ffb1ec8..a32bcbd7a4 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -16,6 +16,8 @@ Major new features:
> * The dynamic linker accepts the --preload argument to preload shared
> objects, in addition to the LD_PRELOAD environment variable.
>
> +* The twalk_r function has been added.
OK.
> +
> * On Linux, the gettid function has been added.
>
> * Minguo (Republic of China) calendar support has been added as an
> diff --git a/include/search.h b/include/search.h
> index e17693022d..72fbc94476 100644
> --- a/include/search.h
> +++ b/include/search.h
> @@ -23,6 +23,8 @@ extern void *__tdelete (const void *__key, void **__rootp,
> libc_hidden_proto (__tdelete)
> extern void __twalk (const void *__root, __action_fn_t action);
> libc_hidden_proto (__twalk)
> +extern __typeof__ (twalk_r) __twalk_r;
> +libc_hidden_proto (__twalk_r)
OK.
> extern void __tdestroy (void *__root, __free_fn_t freefct);
> libc_hidden_proto (__tdestroy)
> #endif
> diff --git a/manual/examples/twalk.c b/manual/examples/twalk.c
> new file mode 100644
> index 0000000000..04e32731d6
> --- /dev/null
> +++ b/manual/examples/twalk.c
> @@ -0,0 +1,56 @@
> +/* Implement twalk using twalk_r.
OK.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include <search.h>
> +
> +struct twalk_with_twalk_r_closure
> +{
> + void (*action) (const void *, VISIT, int);
> + int depth;
> +};
OK. Closure.
> +
> +static void
> +twalk_with_twalk_r_action (const void *nodep, VISIT which, void *closure0)
> +{
> + struct twalk_with_twalk_r_closure *closure = closure0;
> +
> + switch (which)
> + {
> + case leaf:
> + closure->action (nodep, which, closure->depth);
> + break;
> + case preorder:
> + closure->action (nodep, which, closure->depth);
> + ++closure->depth;
> + break;
> + case postorder:
> + /* The preorder action incremented the depth. */
> + closure->action (nodep, which, closure->depth - 1);
> + break;
> + case endorder:
> + --closure->depth;
> + closure->action (nodep, which, closure->depth);
> + break;
> + }
> +}
OK. Call a specific function, with depth, and take action. Good example.
> +
> +void
> +twalk (const void *root, void (*action) (const void *, VISIT, int))
> +{
> + struct twalk_with_twalk_r_closure closure = { action, 0 };
> + twalk_r (root, twalk_with_twalk_r_action, &closure);
> +}
OK.
> diff --git a/manual/search.texi b/manual/search.texi
> index 1574c96562..26f2ceeb55 100644
> --- a/manual/search.texi
> +++ b/manual/search.texi
> @@ -618,5 +618,28 @@ Since the functions used for the @var{action} parameter to @code{twalk}
> must not modify the tree data, it is safe to run @code{twalk} in more
> than one thread at the same time, working on the same tree. It is also
> safe to call @code{tfind} in parallel. Functions which modify the tree
> -must not be used, otherwise the behavior is undefined.
> +must not be used, otherwise the behavior is undefined. However, it is
> +difficult to pass data external to the tree to the callback function
> +without resorting to global variables (and threat safety issues), so
s/threat/thread/g
> +see the @code{twalk_r} function below.
> +@end deftypefun
> +
> +@deftypefun void twalk_r (const void *@var{root}, void (*@var{action}) (const void *@var{key}, VISIT @var{which}, void *@var{closure}), void *@var{closure})
> +@standards{GNU, search.h}
> +@safety{@prelim{}@mtsafe{@mtsrace{:root}}@assafe{}@acsafe{}}
> +For each node in the tree with a node pointed to by @var{root}, the
> +@code{twalk_r} function calls the function provided by the parameter
> +@var{action}. For leaf nodes the function is called exactly once with
> +@var{value} set to @code{leaf}. For internal nodes the function is
> +called three times, setting the @var{value} parameter or @var{action} to
> +the appropriate value. The @var{closure} parameter is passed down to
> +each call of the @var{action} function, unmodified.
> +
OK.
> +It is possible to implement the @code{twalk} function on top of the
> +@code{twalk_r} function, which is why there is no separate level
> +parameter.
OK.
> +
> +@smallexample
> +@include twalk.c.texi
> +@end smallexample
> @end deftypefun
> diff --git a/misc/Versions b/misc/Versions
> index 900e4ffb79..e749582369 100644
> --- a/misc/Versions
> +++ b/misc/Versions
> @@ -158,11 +158,14 @@ libc {
> GLIBC_2.26 {
> preadv2; preadv64v2; pwritev2; pwritev64v2;
> }
> + GLIBC_2.30 {
> + twalk_r;
OK.
> + }
> GLIBC_PRIVATE {
> __madvise;
> __mktemp;
> __libc_ifunc_impl_list;
> - __tdelete; __tfind; __tsearch; __twalk;
> + __tdelete; __tfind; __tsearch; __twalk; __twalk_r;
OK.
> __mmap; __munmap; __mprotect;
> __sched_get_priority_min; __sched_get_priority_max;
> __libc_allocate_once_slow;
> diff --git a/misc/search.h b/misc/search.h
> index 47e8a43436..be3cc25ef9 100644
> --- a/misc/search.h
> +++ b/misc/search.h
> @@ -150,6 +150,12 @@ typedef void (*__action_fn_t) (const void *__nodep, VISIT __value,
> extern void twalk (const void *__root, __action_fn_t __action);
>
> #ifdef __USE_GNU
> +/* Like twalk, but pass down an additional closure parameter. */
> +extern void twalk_r (const void *__root,
> + void (*) (const void *__nodep, VISIT __value,
> + void *__closure),
> + void *__closure);
> +
OK.
> /* Callback type for function to free a tree node. If the keys are atomic
> data this function should do nothing. */
> typedef void (*__free_fn_t) (void *__nodep);
> diff --git a/misc/tsearch.c b/misc/tsearch.c
> index 5c19082a59..24d8d69de3 100644
> --- a/misc/tsearch.c
> +++ b/misc/tsearch.c
> @@ -719,7 +719,41 @@ __twalk (const void *vroot, __action_fn_t action)
> libc_hidden_def (__twalk)
> weak_alias (__twalk, twalk)
>
> +/* twalk_r is the same as twalk, but with an additional closure
> + parameter. */
> +static void
> +trecurse_r (const void *vroot, void (*action) (const void *, VISIT, void *),
> + void *closure)
> +{
> + const_node root = (const_node) vroot;
>
> + if (LEFT(root) == NULL && RIGHT(root) == NULL)
> + (*action) (root, leaf, closure);
> + else
> + {
> + (*action) (root, preorder, closure);
> + if (LEFT(root) != NULL)
> + trecurse_r (LEFT(root), action, closure);
> + (*action) (root, postorder, closure);
> + if (RIGHT(root) != NULL)
> + trecurse_r (RIGHT(root), action, closure);
> + (*action) (root, endorder, closure);
> + }
> +}
OK. Pass closure to all calls.
> +
> +void
> +__twalk_r (const void *vroot, void (*action) (const void *, VISIT, void *),
> + void *closure)
> +{
> + const_node root = (const_node) vroot;
> +
> + CHECK_TREE ((node) root);
> +
> + if (root != NULL && action != NULL)
> + trecurse_r (root, action, closure);
> +}
OK.
> +libc_hidden_def (__twalk_r)
> +weak_alias (__twalk_r, twalk_r)
>
> /* The standardized functions miss an important functionality: the
> tree cannot be removed easily. We provide a function to do this. */
> diff --git a/misc/tst-tsearch.c b/misc/tst-tsearch.c
> index 5803a456e0..9a570dd6c9 100644
> --- a/misc/tst-tsearch.c
> +++ b/misc/tst-tsearch.c
> @@ -25,6 +25,7 @@
> #include <string.h>
> #include <search.h>
> #include <tst-stack-align.h>
> +#include <support/check.h>
>
> #define SEED 0
> #define BALANCED 1
> @@ -74,6 +75,20 @@ static int max_depth;
>
> static int stack_align_check[2];
>
> +/* Used to compare walk traces between the two implementations. */
> +struct walk_trace_element
> +{
> + const void *key;
> + VISIT which;
> + int depth;
> +};
OK.
> +#define DYNARRAY_STRUCT walk_trace_list
> +#define DYNARRAY_ELEMENT struct walk_trace_element
> +#define DYNARRAY_PREFIX walk_trace_
> +#define DYNARRAY_INITIAL_SIZE 0
> +#include <malloc/dynarray-skeleton.c>
> +static struct walk_trace_list walk_trace;
> +
> /* Compare two keys. */
> static int
> cmp_fn (const void *a, const void *b)
> @@ -102,11 +117,54 @@ memfry (int *string)
> }
> }
>
> +struct twalk_with_twalk_r_closure
> +{
> + void (*action) (const void *, VISIT, int);
> + int depth;
> +};
OK.
> +
> +static void
> +twalk_with_twalk_r_action (const void *nodep, VISIT which, void *closure0)
> +{
> + struct twalk_with_twalk_r_closure *closure = closure0;
> +
> + switch (which)
> + {
> + case leaf:
> + closure->action (nodep, which, closure->depth);
> + break;
> + case preorder:
> + closure->action (nodep, which, closure->depth);
> + ++closure->depth;
> + break;
> + case postorder:
> + /* The preorder action incremented the depth. */
> + closure->action (nodep, which, closure->depth - 1);
> + break;
> + case endorder:
> + --closure->depth;
> + closure->action (nodep, which, closure->depth);
> + break;
> + }
> +}
OK.
> +
> +static void
> +twalk_with_twalk_r (const void *root,
> + void (*action) (const void *, VISIT, int))
> +{
> + struct twalk_with_twalk_r_closure closure = { action, 0 };
> + twalk_r (root, twalk_with_twalk_r_action, &closure);
> + TEST_COMPARE (closure.depth, 0);
> +}
OK.
> +
> static void
> walk_action (const void *nodep, const VISIT which, const int depth)
> {
> int key = **(int **) nodep;
>
> + walk_trace_add (&walk_trace,
> + (struct walk_trace_element) { nodep, which, depth });
> +
OK.
> if (!stack_align_check[1])
> stack_align_check[1] = TEST_STACK_ALIGN () ? -1 : 1;
>
> @@ -128,14 +186,16 @@ walk_action (const void *nodep, const VISIT which, const int depth)
> }
>
> static void
> -walk_tree (void *root, int expected_count)
> +walk_tree_with (void *root, int expected_count,
> + void (*walk) (const void *,
> + void (*) (const void *, VISIT, int)))
OK.
> {
> int i;
>
> memset (z, 0, sizeof z);
> max_depth = 0;
>
> - twalk (root, walk_action);
> + walk (root, walk_action);
OK.
> for (i = 0; i < expected_count; ++i)
> if (z[i] != 1)
> {
> @@ -154,6 +214,31 @@ walk_tree (void *root, int expected_count)
> }
> }
>
> +static void
> +walk_tree (void *root, int expected_count)
> +{
> + walk_trace_clear (&walk_trace);
> + walk_tree_with (root, expected_count, twalk);
> + TEST_VERIFY (!walk_trace_has_failed (&walk_trace));
> + size_t first_list_size;
> + struct walk_trace_element *first_list
> + = walk_trace_finalize (&walk_trace, &first_list_size);
> +
> + walk_tree_with (root, expected_count, twalk_with_twalk_r);
> +
> + /* Compare the two traces. */
> + TEST_COMPARE (first_list_size, walk_trace_size (&walk_trace));
> + for (size_t i = 0; i < first_list_size && i < walk_trace_size (&walk_trace);
> + ++i)
> + {
> + TEST_VERIFY (first_list[i].key == walk_trace_at (&walk_trace, i)->key);
> + TEST_COMPARE (first_list[i].which, walk_trace_at (&walk_trace, i)->which);
> + TEST_COMPARE (first_list[i].depth, walk_trace_at (&walk_trace, i)->depth);
> + }
> +
> + walk_trace_free (&walk_trace);
> +}
OK.
> +
> /* Perform an operation on a tree. */
> static void
> mangle_tree (enum order how, enum action what, void **root, int lag)
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index dd3cf6f9f2..1fc7ab2433 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2175,6 +2175,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
> GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index f3b44d723f..b7283ad486 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2142,3 +2142,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index fd81fc4ad0..a817e683a4 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2217,6 +2217,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index f451fefac9..97b6cbf903 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -127,6 +127,7 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
> GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 018d02b414..796e622a6d 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2086,3 +2086,4 @@ GLIBC_2.29 xencrypt F
> GLIBC_2.29 xprt_register F
> GLIBC_2.29 xprt_unregister F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index fc3c5d5c27..4e7d71d112 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2038,6 +2038,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index f2b04dbbff..11bd8c601a 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2204,6 +2204,7 @@ GLIBC_2.3.4 vm86 F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 10ecf2e47c..589cce5b8d 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2070,6 +2070,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 814e81b9d2..4b3727a91d 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -128,6 +128,7 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> GLIBC_2.4 _IO_2_1_stderr_ D 0x98
> GLIBC_2.4 _IO_2_1_stdin_ D 0x98
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 68e80372e7..4be30c0339 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2147,6 +2147,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index 31178e4f54..e0010965a8 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2134,3 +2134,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 7074573638..2a62f67741 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2121,6 +2121,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 154f9c77fc..5a23f11fc9 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2119,6 +2119,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 97b8f42d5c..32532a19da 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2127,6 +2127,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 5b3e85de93..882f5cb5bf 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2121,6 +2121,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 04a130a81c..c99a299bab 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2175,3 +2175,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index a701584422..d5f4364197 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2177,6 +2177,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index bbb647cd98..581fd10290 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2210,6 +2210,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index bb23bf61a8..ce10e0436e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2040,6 +2040,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 7921dda979..1cc729da7f 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2244,3 +2244,4 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index da123d3867..2bda5692f4 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2104,3 +2104,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 2aed339af4..dddc138a1e 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2172,6 +2172,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index e46feb56e5..b2c75a48a8 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2076,6 +2076,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index 24a8f934cb..8b83449b16 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -2042,6 +2042,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index ebdbd2c5ae..a237be9d93 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2166,6 +2166,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 0992349b06..b850694434 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2093,6 +2093,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index af004fcff6..c6f22f0c7b 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2051,6 +2051,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 84015f0a57..1184385bce 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2150,3 +2150,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
>
OK.
On 29/04/2019 09:51, Florian Weimer wrote:
> The twalk function is very difficult to use in a multi-threaded
> program because there is no way to pass external state to the
> iterator function.
LGTM as well, with some nits below (the whitespace you seems to
fixed already).
>
> (I expect to use this new function in sem_close and
> __gconv_release_shlib, but the function is generally useful.)
As a side note I worked on a sem_open/sem_close refactor some time ago
that uses dynarray and the char array derived structure, aimed to remove
both the twalk and alloca internal usage. It turned to be a slight simpler
implementation as well and I will try to send it upstream.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
>
> 2019-04-29 Florian Weimer <fweimer@redhat.com>
>
> misc: Add twalk_r function.
> * include/search.h (__twalk_r): Declare.
> * manual/examples/twalk.c: New file.
> * manual/search.texi (Tree Search Function): Document twalk_r.
> * misc/Versions (2.30): Export twalk_r.
> (GLIBC_PRIVATE): Export __twalk_r.
> * misc/search.h [__USE_GNU] (twalk_r): Declare.
> * misc/tsearch.c (trecurse_r, __twalk_r): New functions.
> (twalk_r): Add weak alias.
> * misc/tst-tsearch.c (struct walk_trace_element): Define.
> (walk_trace): New variable.
> (struct twalk_with_twalk_r_closure): Define.
> (twalk_with_twalk_r_action): New function.
> (twalk_with_twalk_r): Likewise.
> (walk_action): Call walk_trace_add.
> (walk_tree_with): Rename from walk_tree. Add walk argument.
> (walk_tree): New function.
> * sysdeps/mach/hurd/i386/libc.abilist (GLIBC_2.30): Add twalk_r.
> * sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
> Likewise.
> * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
> Likewise.
>
> diff --git a/NEWS b/NEWS
> index 792ffb1ec8..a32bcbd7a4 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -16,6 +16,8 @@ Major new features:
> * The dynamic linker accepts the --preload argument to preload shared
> objects, in addition to the LD_PRELOAD environment variable.
>
> +* The twalk_r function has been added.
> +
I think we can extend it description a bit by adding it is a GNU extension
that behaves like twalk but with an addional parameter to be passed in
callback action function (like qsort_r).
> * On Linux, the gettid function has been added.
>
> * Minguo (Republic of China) calendar support has been added as an
> diff --git a/include/search.h b/include/search.h
> index e17693022d..72fbc94476 100644
> --- a/include/search.h
> +++ b/include/search.h
> @@ -23,6 +23,8 @@ extern void *__tdelete (const void *__key, void **__rootp,
> libc_hidden_proto (__tdelete)
> extern void __twalk (const void *__root, __action_fn_t action);
> libc_hidden_proto (__twalk)
> +extern __typeof__ (twalk_r) __twalk_r;
> +libc_hidden_proto (__twalk_r)
> extern void __tdestroy (void *__root, __free_fn_t freefct);
> libc_hidden_proto (__tdestroy)
> #endif
Ok.
> diff --git a/manual/examples/twalk.c b/manual/examples/twalk.c
> new file mode 100644
> index 0000000000..04e32731d6
> --- /dev/null
> +++ b/manual/examples/twalk.c
> @@ -0,0 +1,56 @@
> +/* Implement twalk using twalk_r.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include <search.h>
> +
> +struct twalk_with_twalk_r_closure
> +{
> + void (*action) (const void *, VISIT, int);
> + int depth;
> +};
> +
> +static void
> +twalk_with_twalk_r_action (const void *nodep, VISIT which, void *closure0)
> +{
> + struct twalk_with_twalk_r_closure *closure = closure0;
> +
> + switch (which)
> + {
> + case leaf:
> + closure->action (nodep, which, closure->depth);
> + break;
> + case preorder:
> + closure->action (nodep, which, closure->depth);
> + ++closure->depth;
> + break;
> + case postorder:
> + /* The preorder action incremented the depth. */
> + closure->action (nodep, which, closure->depth - 1);
> + break;
> + case endorder:
> + --closure->depth;
> + closure->action (nodep, which, closure->depth);
> + break;
> + }
> +}
> +
> +void
> +twalk (const void *root, void (*action) (const void *, VISIT, int))
> +{
> + struct twalk_with_twalk_r_closure closure = { action, 0 };
> + twalk_r (root, twalk_with_twalk_r_action, &closure);
> +}
Ok.
> diff --git a/manual/search.texi b/manual/search.texi
> index 1574c96562..26f2ceeb55 100644
> --- a/manual/search.texi
> +++ b/manual/search.texi
> @@ -618,5 +618,28 @@ Since the functions used for the @var{action} parameter to @code{twalk}
> must not modify the tree data, it is safe to run @code{twalk} in more
> than one thread at the same time, working on the same tree. It is also
> safe to call @code{tfind} in parallel. Functions which modify the tree
> -must not be used, otherwise the behavior is undefined.
> +must not be used, otherwise the behavior is undefined. However, it is
I think it is missing two spaces after period.
> +difficult to pass data external to the tree to the callback function
> +without resorting to global variables (and threat safety issues), so
> +see the @code{twalk_r} function below.
> +@end deftypefun
> +
> +@deftypefun void twalk_r (const void *@var{root}, void (*@var{action}) (const void *@var{key}, VISIT @var{which}, void *@var{closure}), void *@var{closure})
> +@standards{GNU, search.h}
> +@safety{@prelim{}@mtsafe{@mtsrace{:root}}@assafe{}@acsafe{}}
> +For each node in the tree with a node pointed to by @var{root}, the
> +@code{twalk_r} function calls the function provided by the parameter
> +@var{action}. For leaf nodes the function is called exactly once with
> +@var{value} set to @code{leaf}. For internal nodes the function is
> +called three times, setting the @var{value} parameter or @var{action} to
> +the appropriate value. The @var{closure} parameter is passed down to
> +each call of the @var{action} function, unmodified.
> +
> +It is possible to implement the @code{twalk} function on top of the
> +@code{twalk_r} function, which is why there is no separate level
> +parameter.
> +
> +@smallexample
> +@include twalk.c.texi
> +@end smallexample
> @end deftypefun
Ok.
> diff --git a/misc/Versions b/misc/Versions
> index 900e4ffb79..e749582369 100644
> --- a/misc/Versions
> +++ b/misc/Versions
> @@ -158,11 +158,14 @@ libc {
> GLIBC_2.26 {
> preadv2; preadv64v2; pwritev2; pwritev64v2;
> }
> + GLIBC_2.30 {
> + twalk_r;
> + }
> GLIBC_PRIVATE {
> __madvise;
> __mktemp;
> __libc_ifunc_impl_list;
> - __tdelete; __tfind; __tsearch; __twalk;
> + __tdelete; __tfind; __tsearch; __twalk; __twalk_r;
> __mmap; __munmap; __mprotect;
> __sched_get_priority_min; __sched_get_priority_max;
> __libc_allocate_once_slow;
Ok.
> diff --git a/misc/search.h b/misc/search.h
> index 47e8a43436..be3cc25ef9 100644
> --- a/misc/search.h
> +++ b/misc/search.h
> @@ -150,6 +150,12 @@ typedef void (*__action_fn_t) (const void *__nodep, VISIT __value,
> extern void twalk (const void *__root, __action_fn_t __action);
>
> #ifdef __USE_GNU
> +/* Like twalk, but pass down an additional closure parameter. */
> +extern void twalk_r (const void *__root,
> + void (*) (const void *__nodep, VISIT __value,
> + void *__closure),
> + void *__closure);
> +
> /* Callback type for function to free a tree node. If the keys are atomic
> data this function should do nothing. */
> typedef void (*__free_fn_t) (void *__nodep);
Ok.
> diff --git a/misc/tsearch.c b/misc/tsearch.c
> index 5c19082a59..24d8d69de3 100644
> --- a/misc/tsearch.c
> +++ b/misc/tsearch.c
> @@ -719,7 +719,41 @@ __twalk (const void *vroot, __action_fn_t action)
> libc_hidden_def (__twalk)
> weak_alias (__twalk, twalk)
>
> +/* twalk_r is the same as twalk, but with an additional closure
> + parameter. */
> +static void
> +trecurse_r (const void *vroot, void (*action) (const void *, VISIT, void *),
> + void *closure)
> +{
> + const_node root = (const_node) vroot;
>
> + if (LEFT(root) == NULL && RIGHT(root) == NULL)
> + (*action) (root, leaf, closure);
> + else
> + {
> + (*action) (root, preorder, closure);
> + if (LEFT(root) != NULL)
> + trecurse_r (LEFT(root), action, closure);
> + (*action) (root, postorder, closure);
> + if (RIGHT(root) != NULL)
> + trecurse_r (RIGHT(root), action, closure);
> + (*action) (root, endorder, closure);
> + }
> +}
> +
> +void
> +__twalk_r (const void *vroot, void (*action) (const void *, VISIT, void *),
> + void *closure)
> +{
> + const_node root = (const_node) vroot;
> +
> + CHECK_TREE ((node) root);
> +
> + if (root != NULL && action != NULL)
> + trecurse_r (root, action, closure);
> +}
> +libc_hidden_def (__twalk_r)
> +weak_alias (__twalk_r, twalk_r)
>
> /* The standardized functions miss an important functionality: the
> tree cannot be removed easily. We provide a function to do this. */
Ok.
> diff --git a/misc/tst-tsearch.c b/misc/tst-tsearch.c
> index 5803a456e0..9a570dd6c9 100644
> --- a/misc/tst-tsearch.c
> +++ b/misc/tst-tsearch.c
> @@ -25,6 +25,7 @@
> #include <string.h>
> #include <search.h>
> #include <tst-stack-align.h>
> +#include <support/check.h>
>
> #define SEED 0
> #define BALANCED 1
> @@ -74,6 +75,20 @@ static int max_depth;
>
> static int stack_align_check[2];
>
> +/* Used to compare walk traces between the two implementations. */
> +struct walk_trace_element
> +{
> + const void *key;
> + VISIT which;
> + int depth;
> +};
> +#define DYNARRAY_STRUCT walk_trace_list
> +#define DYNARRAY_ELEMENT struct walk_trace_element
> +#define DYNARRAY_PREFIX walk_trace_
> +#define DYNARRAY_INITIAL_SIZE 0
> +#include <malloc/dynarray-skeleton.c>
> +static struct walk_trace_list walk_trace;
> +
> /* Compare two keys. */
> static int
> cmp_fn (const void *a, const void *b)
> @@ -102,11 +117,54 @@ memfry (int *string)
> }
> }
>
> +struct twalk_with_twalk_r_closure
> +{
> + void (*action) (const void *, VISIT, int);
> + int depth;
> +};
> +
> +static void
> +twalk_with_twalk_r_action (const void *nodep, VISIT which, void *closure0)
> +{
> + struct twalk_with_twalk_r_closure *closure = closure0;
> +
> + switch (which)
> + {
> + case leaf:
> + closure->action (nodep, which, closure->depth);
> + break;
> + case preorder:
> + closure->action (nodep, which, closure->depth);
> + ++closure->depth;
> + break;
> + case postorder:
> + /* The preorder action incremented the depth. */
> + closure->action (nodep, which, closure->depth - 1);
> + break;
> + case endorder:
> + --closure->depth;
> + closure->action (nodep, which, closure->depth);
> + break;
> + }
> +}
> +
> +static void
> +twalk_with_twalk_r (const void *root,
> + void (*action) (const void *, VISIT, int))
> +{
> + struct twalk_with_twalk_r_closure closure = { action, 0 };
> + twalk_r (root, twalk_with_twalk_r_action, &closure);
> + TEST_COMPARE (closure.depth, 0);
> +}
> +
Ok.
> static void
> walk_action (const void *nodep, const VISIT which, const int depth)
> {
> int key = **(int **) nodep;
>
> + walk_trace_add (&walk_trace,
> + (struct walk_trace_element) { nodep, which, depth });
> +
> if (!stack_align_check[1])
> stack_align_check[1] = TEST_STACK_ALIGN () ? -1 : 1;
Ok.
>
> @@ -128,14 +186,16 @@ walk_action (const void *nodep, const VISIT which, const int depth)
> }
>
> static void
> -walk_tree (void *root, int expected_count)
> +walk_tree_with (void *root, int expected_count,
> + void (*walk) (const void *,
> + void (*) (const void *, VISIT, int)))
> {
> int i;
>
> memset (z, 0, sizeof z);
> max_depth = 0;
>
> - twalk (root, walk_action);
> + walk (root, walk_action);
> for (i = 0; i < expected_count; ++i)
> if (z[i] != 1)
> {
> @@ -154,6 +214,31 @@ walk_tree (void *root, int expected_count)
> }
> }
>
Ok.
> +static void
> +walk_tree (void *root, int expected_count)
> +{
> + walk_trace_clear (&walk_trace);
> + walk_tree_with (root, expected_count, twalk);
> + TEST_VERIFY (!walk_trace_has_failed (&walk_trace));
> + size_t first_list_size;
> + struct walk_trace_element *first_list
> + = walk_trace_finalize (&walk_trace, &first_list_size);
> +
> + walk_tree_with (root, expected_count, twalk_with_twalk_r);
> +
> + /* Compare the two traces. */
> + TEST_COMPARE (first_list_size, walk_trace_size (&walk_trace));
> + for (size_t i = 0; i < first_list_size && i < walk_trace_size (&walk_trace);
> + ++i)
> + {
> + TEST_VERIFY (first_list[i].key == walk_trace_at (&walk_trace, i)->key);
> + TEST_COMPARE (first_list[i].which, walk_trace_at (&walk_trace, i)->which);
> + TEST_COMPARE (first_list[i].depth, walk_trace_at (&walk_trace, i)->depth);
> + }
> +
> + walk_trace_free (&walk_trace);
> +}
> +
> /* Perform an operation on a tree. */
> static void
> mangle_tree (enum order how, enum action what, void **root, int lag)
Ok.
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index dd3cf6f9f2..1fc7ab2433 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2175,6 +2175,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
> GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index f3b44d723f..b7283ad486 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2142,3 +2142,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index fd81fc4ad0..a817e683a4 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2217,6 +2217,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index f451fefac9..97b6cbf903 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -127,6 +127,7 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
> GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 018d02b414..796e622a6d 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2086,3 +2086,4 @@ GLIBC_2.29 xencrypt F
> GLIBC_2.29 xprt_register F
> GLIBC_2.29 xprt_unregister F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index fc3c5d5c27..4e7d71d112 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2038,6 +2038,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index f2b04dbbff..11bd8c601a 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2204,6 +2204,7 @@ GLIBC_2.3.4 vm86 F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 10ecf2e47c..589cce5b8d 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2070,6 +2070,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 814e81b9d2..4b3727a91d 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -128,6 +128,7 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> GLIBC_2.4 _IO_2_1_stderr_ D 0x98
> GLIBC_2.4 _IO_2_1_stdin_ D 0x98
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 68e80372e7..4be30c0339 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2147,6 +2147,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index 31178e4f54..e0010965a8 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2134,3 +2134,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 7074573638..2a62f67741 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2121,6 +2121,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 154f9c77fc..5a23f11fc9 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2119,6 +2119,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 97b8f42d5c..32532a19da 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2127,6 +2127,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 5b3e85de93..882f5cb5bf 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2121,6 +2121,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 04a130a81c..c99a299bab 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2175,3 +2175,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index a701584422..d5f4364197 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2177,6 +2177,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index bbb647cd98..581fd10290 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2210,6 +2210,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index bb23bf61a8..ce10e0436e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2040,6 +2040,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 7921dda979..1cc729da7f 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2244,3 +2244,4 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index da123d3867..2bda5692f4 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2104,3 +2104,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 2aed339af4..dddc138a1e 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2172,6 +2172,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index e46feb56e5..b2c75a48a8 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2076,6 +2076,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index 24a8f934cb..8b83449b16 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -2042,6 +2042,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index ebdbd2c5ae..a237be9d93 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2166,6 +2166,7 @@ GLIBC_2.30 __nldbl_vwarnx F
> GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> GLIBC_2.4 _IO_printf F
> GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 0992349b06..b850694434 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2093,6 +2093,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index af004fcff6..c6f22f0c7b 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2051,6 +2051,7 @@ GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 84015f0a57..1184385bce 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2150,3 +2150,4 @@ GLIBC_2.29 getcpu F
> GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 twalk_r F
>
Ok.
* Adhemerval Zanella:
> On 29/04/2019 09:51, Florian Weimer wrote:
>> The twalk function is very difficult to use in a multi-threaded
>> program because there is no way to pass external state to the
>> iterator function.
>
> LGTM as well, with some nits below (the whitespace you seems to
> fixed already).
>
>>
>> (I expect to use this new function in sem_close and
>> __gconv_release_shlib, but the function is generally useful.)
>
> As a side note I worked on a sem_open/sem_close refactor some time ago
> that uses dynarray and the char array derived structure, aimed to remove
> both the twalk and alloca internal usage. It turned to be a slight simpler
> implementation as well and I will try to send it upstream.
>
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
I assume this should be your Reviewed-by?
>> diff --git a/NEWS b/NEWS
>> index 792ffb1ec8..a32bcbd7a4 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -16,6 +16,8 @@ Major new features:
>> * The dynamic linker accepts the --preload argument to preload shared
>> objects, in addition to the LD_PRELOAD environment variable.
>>
>> +* The twalk_r function has been added.
>> +
>
> I think we can extend it description a bit by adding it is a GNU extension
> that behaves like twalk but with an addional parameter to be passed in
> callback action function (like qsort_r).
“The twalk_r function has been added. It is similar to the existing
twalk function, but it passes an additional caller-supplied argument to
the callback function.”
Thanks,
Florian
> Il giorno 1 mag 2019, alle ore 03:11, Florian Weimer <fweimer@redhat.com> ha scritto:
>
> * Adhemerval Zanella:
>
>>> On 29/04/2019 09:51, Florian Weimer wrote:
>>> The twalk function is very difficult to use in a multi-threaded
>>> program because there is no way to pass external state to the
>>> iterator function.
>>
>> LGTM as well, with some nits below (the whitespace you seems to
>> fixed already).
>>
>>>
>>> (I expect to use this new function in sem_close and
>>> __gconv_release_shlib, but the function is generally useful.)
>>
>> As a side note I worked on a sem_open/sem_close refactor some time ago
>> that uses dynarray and the char array derived structure, aimed to remove
>> both the twalk and alloca internal usage. It turned to be a slight simpler
>> implementation as well and I will try to send it upstream.
>>
>> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
>
> I assume this should be your Reviewed-by?
Oops, indeed.
>
>>> diff --git a/NEWS b/NEWS
>>> index 792ffb1ec8..a32bcbd7a4 100644
>>> --- a/NEWS
>>> +++ b/NEWS
>>> @@ -16,6 +16,8 @@ Major new features:
>>> * The dynamic linker accepts the --preload argument to preload shared
>>> objects, in addition to the LD_PRELOAD environment variable.
>>>
>>> +* The twalk_r function has been added.
>>> +
>>
>> I think we can extend it description a bit by adding it is a GNU extension
>> that behaves like twalk but with an addional parameter to be passed in
>> callback action function (like qsort_r).
>
> “The twalk_r function has been added. It is similar to the existing
> twalk function, but it passes an additional caller-supplied argument to
> the callback function.”
>
LGTM.
> Thanks,
> Florian
I'm seeing (at least with GCC 8):
tst-tsearch.c: In function 'walk_tree.constprop':
tst-tsearch.c:231:3: error: 'first_list_size' may be used uninitialized in this function [-Werror=maybe-uninitialized]
for (size_t i = 0; i < first_list_size && i < walk_trace_size (&walk_trace);
^~~
https://sourceware.org/ml/libc-testresults/2019-q2/msg00121.html
@@ -16,6 +16,8 @@ Major new features:
* The dynamic linker accepts the --preload argument to preload shared
objects, in addition to the LD_PRELOAD environment variable.
+* The twalk_r function has been added.
+
* On Linux, the gettid function has been added.
* Minguo (Republic of China) calendar support has been added as an
@@ -23,6 +23,8 @@ extern void *__tdelete (const void *__key, void **__rootp,
libc_hidden_proto (__tdelete)
extern void __twalk (const void *__root, __action_fn_t action);
libc_hidden_proto (__twalk)
+extern __typeof__ (twalk_r) __twalk_r;
+libc_hidden_proto (__twalk_r)
extern void __tdestroy (void *__root, __free_fn_t freefct);
libc_hidden_proto (__tdestroy)
#endif
new file mode 100644
@@ -0,0 +1,56 @@
+/* Implement twalk using twalk_r.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <search.h>
+
+struct twalk_with_twalk_r_closure
+{
+ void (*action) (const void *, VISIT, int);
+ int depth;
+};
+
+static void
+twalk_with_twalk_r_action (const void *nodep, VISIT which, void *closure0)
+{
+ struct twalk_with_twalk_r_closure *closure = closure0;
+
+ switch (which)
+ {
+ case leaf:
+ closure->action (nodep, which, closure->depth);
+ break;
+ case preorder:
+ closure->action (nodep, which, closure->depth);
+ ++closure->depth;
+ break;
+ case postorder:
+ /* The preorder action incremented the depth. */
+ closure->action (nodep, which, closure->depth - 1);
+ break;
+ case endorder:
+ --closure->depth;
+ closure->action (nodep, which, closure->depth);
+ break;
+ }
+}
+
+void
+twalk (const void *root, void (*action) (const void *, VISIT, int))
+{
+ struct twalk_with_twalk_r_closure closure = { action, 0 };
+ twalk_r (root, twalk_with_twalk_r_action, &closure);
+}
@@ -618,5 +618,28 @@ Since the functions used for the @var{action} parameter to @code{twalk}
must not modify the tree data, it is safe to run @code{twalk} in more
than one thread at the same time, working on the same tree. It is also
safe to call @code{tfind} in parallel. Functions which modify the tree
-must not be used, otherwise the behavior is undefined.
+must not be used, otherwise the behavior is undefined. However, it is
+difficult to pass data external to the tree to the callback function
+without resorting to global variables (and threat safety issues), so
+see the @code{twalk_r} function below.
+@end deftypefun
+
+@deftypefun void twalk_r (const void *@var{root}, void (*@var{action}) (const void *@var{key}, VISIT @var{which}, void *@var{closure}), void *@var{closure})
+@standards{GNU, search.h}
+@safety{@prelim{}@mtsafe{@mtsrace{:root}}@assafe{}@acsafe{}}
+For each node in the tree with a node pointed to by @var{root}, the
+@code{twalk_r} function calls the function provided by the parameter
+@var{action}. For leaf nodes the function is called exactly once with
+@var{value} set to @code{leaf}. For internal nodes the function is
+called three times, setting the @var{value} parameter or @var{action} to
+the appropriate value. The @var{closure} parameter is passed down to
+each call of the @var{action} function, unmodified.
+
+It is possible to implement the @code{twalk} function on top of the
+@code{twalk_r} function, which is why there is no separate level
+parameter.
+
+@smallexample
+@include twalk.c.texi
+@end smallexample
@end deftypefun
@@ -158,11 +158,14 @@ libc {
GLIBC_2.26 {
preadv2; preadv64v2; pwritev2; pwritev64v2;
}
+ GLIBC_2.30 {
+ twalk_r;
+ }
GLIBC_PRIVATE {
__madvise;
__mktemp;
__libc_ifunc_impl_list;
- __tdelete; __tfind; __tsearch; __twalk;
+ __tdelete; __tfind; __tsearch; __twalk; __twalk_r;
__mmap; __munmap; __mprotect;
__sched_get_priority_min; __sched_get_priority_max;
__libc_allocate_once_slow;
@@ -150,6 +150,12 @@ typedef void (*__action_fn_t) (const void *__nodep, VISIT __value,
extern void twalk (const void *__root, __action_fn_t __action);
#ifdef __USE_GNU
+/* Like twalk, but pass down an additional closure parameter. */
+extern void twalk_r (const void *__root,
+ void (*) (const void *__nodep, VISIT __value,
+ void *__closure),
+ void *__closure);
+
/* Callback type for function to free a tree node. If the keys are atomic
data this function should do nothing. */
typedef void (*__free_fn_t) (void *__nodep);
@@ -719,7 +719,41 @@ __twalk (const void *vroot, __action_fn_t action)
libc_hidden_def (__twalk)
weak_alias (__twalk, twalk)
+/* twalk_r is the same as twalk, but with an additional closure
+ parameter. */
+static void
+trecurse_r (const void *vroot, void (*action) (const void *, VISIT, void *),
+ void *closure)
+{
+ const_node root = (const_node) vroot;
+ if (LEFT(root) == NULL && RIGHT(root) == NULL)
+ (*action) (root, leaf, closure);
+ else
+ {
+ (*action) (root, preorder, closure);
+ if (LEFT(root) != NULL)
+ trecurse_r (LEFT(root), action, closure);
+ (*action) (root, postorder, closure);
+ if (RIGHT(root) != NULL)
+ trecurse_r (RIGHT(root), action, closure);
+ (*action) (root, endorder, closure);
+ }
+}
+
+void
+__twalk_r (const void *vroot, void (*action) (const void *, VISIT, void *),
+ void *closure)
+{
+ const_node root = (const_node) vroot;
+
+ CHECK_TREE ((node) root);
+
+ if (root != NULL && action != NULL)
+ trecurse_r (root, action, closure);
+}
+libc_hidden_def (__twalk_r)
+weak_alias (__twalk_r, twalk_r)
/* The standardized functions miss an important functionality: the
tree cannot be removed easily. We provide a function to do this. */
@@ -25,6 +25,7 @@
#include <string.h>
#include <search.h>
#include <tst-stack-align.h>
+#include <support/check.h>
#define SEED 0
#define BALANCED 1
@@ -74,6 +75,20 @@ static int max_depth;
static int stack_align_check[2];
+/* Used to compare walk traces between the two implementations. */
+struct walk_trace_element
+{
+ const void *key;
+ VISIT which;
+ int depth;
+};
+#define DYNARRAY_STRUCT walk_trace_list
+#define DYNARRAY_ELEMENT struct walk_trace_element
+#define DYNARRAY_PREFIX walk_trace_
+#define DYNARRAY_INITIAL_SIZE 0
+#include <malloc/dynarray-skeleton.c>
+static struct walk_trace_list walk_trace;
+
/* Compare two keys. */
static int
cmp_fn (const void *a, const void *b)
@@ -102,11 +117,54 @@ memfry (int *string)
}
}
+struct twalk_with_twalk_r_closure
+{
+ void (*action) (const void *, VISIT, int);
+ int depth;
+};
+
+static void
+twalk_with_twalk_r_action (const void *nodep, VISIT which, void *closure0)
+{
+ struct twalk_with_twalk_r_closure *closure = closure0;
+
+ switch (which)
+ {
+ case leaf:
+ closure->action (nodep, which, closure->depth);
+ break;
+ case preorder:
+ closure->action (nodep, which, closure->depth);
+ ++closure->depth;
+ break;
+ case postorder:
+ /* The preorder action incremented the depth. */
+ closure->action (nodep, which, closure->depth - 1);
+ break;
+ case endorder:
+ --closure->depth;
+ closure->action (nodep, which, closure->depth);
+ break;
+ }
+}
+
+static void
+twalk_with_twalk_r (const void *root,
+ void (*action) (const void *, VISIT, int))
+{
+ struct twalk_with_twalk_r_closure closure = { action, 0 };
+ twalk_r (root, twalk_with_twalk_r_action, &closure);
+ TEST_COMPARE (closure.depth, 0);
+}
+
static void
walk_action (const void *nodep, const VISIT which, const int depth)
{
int key = **(int **) nodep;
+ walk_trace_add (&walk_trace,
+ (struct walk_trace_element) { nodep, which, depth });
+
if (!stack_align_check[1])
stack_align_check[1] = TEST_STACK_ALIGN () ? -1 : 1;
@@ -128,14 +186,16 @@ walk_action (const void *nodep, const VISIT which, const int depth)
}
static void
-walk_tree (void *root, int expected_count)
+walk_tree_with (void *root, int expected_count,
+ void (*walk) (const void *,
+ void (*) (const void *, VISIT, int)))
{
int i;
memset (z, 0, sizeof z);
max_depth = 0;
- twalk (root, walk_action);
+ walk (root, walk_action);
for (i = 0; i < expected_count; ++i)
if (z[i] != 1)
{
@@ -154,6 +214,31 @@ walk_tree (void *root, int expected_count)
}
}
+static void
+walk_tree (void *root, int expected_count)
+{
+ walk_trace_clear (&walk_trace);
+ walk_tree_with (root, expected_count, twalk);
+ TEST_VERIFY (!walk_trace_has_failed (&walk_trace));
+ size_t first_list_size;
+ struct walk_trace_element *first_list
+ = walk_trace_finalize (&walk_trace, &first_list_size);
+
+ walk_tree_with (root, expected_count, twalk_with_twalk_r);
+
+ /* Compare the two traces. */
+ TEST_COMPARE (first_list_size, walk_trace_size (&walk_trace));
+ for (size_t i = 0; i < first_list_size && i < walk_trace_size (&walk_trace);
+ ++i)
+ {
+ TEST_VERIFY (first_list[i].key == walk_trace_at (&walk_trace, i)->key);
+ TEST_COMPARE (first_list[i].which, walk_trace_at (&walk_trace, i)->which);
+ TEST_COMPARE (first_list[i].depth, walk_trace_at (&walk_trace, i)->depth);
+ }
+
+ walk_trace_free (&walk_trace);
+}
+
/* Perform an operation on a tree. */
static void
mangle_tree (enum order how, enum action what, void **root, int lag)
@@ -2175,6 +2175,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2142,3 +2142,4 @@ GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
@@ -2217,6 +2217,7 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -127,6 +127,7 @@ GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
@@ -2086,3 +2086,4 @@ GLIBC_2.29 xencrypt F
GLIBC_2.29 xprt_register F
GLIBC_2.29 xprt_unregister F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
@@ -2038,6 +2038,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2204,6 +2204,7 @@ GLIBC_2.3.4 vm86 F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2070,6 +2070,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -128,6 +128,7 @@ GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
@@ -2147,6 +2147,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2134,3 +2134,4 @@ GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
@@ -2121,6 +2121,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2119,6 +2119,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2127,6 +2127,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2121,6 +2121,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2175,3 +2175,4 @@ GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
@@ -2177,6 +2177,7 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2210,6 +2210,7 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2040,6 +2040,7 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2244,3 +2244,4 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
@@ -2104,3 +2104,4 @@ GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
@@ -2172,6 +2172,7 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2076,6 +2076,7 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2042,6 +2042,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2166,6 +2166,7 @@ GLIBC_2.30 __nldbl_vwarnx F
GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2093,6 +2093,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2051,6 +2051,7 @@ GLIBC_2.3.4 setsourcefilter F
GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2150,3 +2150,4 @@ GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 gettid F
+GLIBC_2.30 twalk_r F