nptl: Add pthread_thread_number_np function

Message ID 20171214185611.D08E1439942EA@oldenburg.str.redhat.com
State Superseded
Headers

Commit Message

Florian Weimer Dec. 14, 2017, 6:56 p.m. UTC
  The implementation is actually in libc.so.  With a full implementation
of pthread_self in libc.so, pthread_thread_number_np is completely
usable without libpthread.

2017-12-14  Florian Weimer  <fweimer@redhat.com>

	nptl: Add pthread_thread_number_np function.
	* csu/libc-tls.c (__libc_setup_tls): Call __dl_inittcb.
	* elf/Makefile (dl-routines): Add dl-inittcb.
	* elf/dl-inittcb.c: New file.
	* elf/rtld.c (init_tls): Call __dl_inittcb.
	* manual/threads.texi (Non-POSIX Extensions): Reference Non-POSIX
	Extensions.
	(Non-POSIX Extensions): New node.
	* nptl/Makefile (routines): Add thread_number.
	(tests): Add tst-thread_number-single, tst-thread_number-multi,
	tst-thread_number-single-static, tst-thread_number-multi-static.
	(tests-nolibpthread): Add tst-thread_number-single,
	tst-thread_number-single-static.
	(tests-static): Add tst-thread_number-single-static,
	tst-thread_number-multi-static.
	* nptl/Versions (GLIBC_2.27): Export pthread_thread_number_np.
	* nptl/allocatestack.c (allocate_stack): Increment
	global_thread_number under__default_pthread_attr_lock and use its
	value to set the new thread number.
	* nptl/descr.h (struct pthread): Add number member.
	* nptl/thread_number.c: New file.
	* nptl/tst-thread_number-multi.c: Likewise.
	* nptl/tst-thread_number-single.c: Likewise.
	* nptl/tst-thread_number-multi-static.c: Likewise.
	* nptl/tst-thread_number-single-static.c: Likewise.
	* sysdeps/nptl/pthread.h (pthread_thread_number_np): Declare.
	* sysdeps/unix/sysv/linux/libc**.abilist: Update.
  

Comments

Florian Weimer Dec. 14, 2017, 8:24 p.m. UTC | #1
On 12/14/2017 07:56 PM, Florian Weimer wrote:
> The implementation is actually in libc.so.  With a full implementation
> of pthread_self in libc.so, pthread_thread_number_np is completely
> usable without libpthread.

And once again, I forgot the NEWS entry.

I should say that this is something completely different from gettid, 
and by itself usable for logging, certain concurrency-related 
algorithms, and writing DRBGs (where the current thread's number can be 
used to ensure that different threads get different bit sequences).

Thanks,
Florian
  
Nix Dec. 14, 2017, 11:34 p.m. UTC | #2
On 14 Dec 2017, Florian Weimer uttered the following:
> diff --git a/nptl/Versions b/nptl/Versions
> index 0ae5def464..8b6c839408 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -28,6 +28,9 @@ libc {
>      pthread_cond_wait; pthread_cond_signal;
>      pthread_cond_broadcast; pthread_cond_timedwait;
>    }
> +  GLBIC_2.27 {
> +    pthread_thread_number_np;
> +  }
>    GLIBC_PRIVATE {
>      __libc_alloca_cutoff;
>      # Internal libc interface to libpthread

GLBIC is a definite typo (repeated, of course, in all the abilist
files).
  
Andrew Pinski Dec. 15, 2017, 12:29 a.m. UTC | #3
On Thu, Dec 14, 2017 at 10:56 AM, Florian Weimer <fweimer@redhat.com> wrote:
> The implementation is actually in libc.so.  With a full implementation
> of pthread_self in libc.so, pthread_thread_number_np is completely
> usable without libpthread.
>
> 2017-12-14  Florian Weimer  <fweimer@redhat.com>
>
>         nptl: Add pthread_thread_number_np function.
>         * csu/libc-tls.c (__libc_setup_tls): Call __dl_inittcb.
>         * elf/Makefile (dl-routines): Add dl-inittcb.
>         * elf/dl-inittcb.c: New file.
>         * elf/rtld.c (init_tls): Call __dl_inittcb.
>         * manual/threads.texi (Non-POSIX Extensions): Reference Non-POSIX
>         Extensions.
>         (Non-POSIX Extensions): New node.
>         * nptl/Makefile (routines): Add thread_number.
>         (tests): Add tst-thread_number-single, tst-thread_number-multi,
>         tst-thread_number-single-static, tst-thread_number-multi-static.
>         (tests-nolibpthread): Add tst-thread_number-single,
>         tst-thread_number-single-static.
>         (tests-static): Add tst-thread_number-single-static,
>         tst-thread_number-multi-static.
>         * nptl/Versions (GLIBC_2.27): Export pthread_thread_number_np.
>         * nptl/allocatestack.c (allocate_stack): Increment
>         global_thread_number under__default_pthread_attr_lock and use its
>         value to set the new thread number.
>         * nptl/descr.h (struct pthread): Add number member.
>         * nptl/thread_number.c: New file.
>         * nptl/tst-thread_number-multi.c: Likewise.
>         * nptl/tst-thread_number-single.c: Likewise.
>         * nptl/tst-thread_number-multi-static.c: Likewise.
>         * nptl/tst-thread_number-single-static.c: Likewise.
>         * sysdeps/nptl/pthread.h (pthread_thread_number_np): Declare.
>         * sysdeps/unix/sysv/linux/libc**.abilist: Update.
>
> diff --git a/csu/libc-tls.c b/csu/libc-tls.c
> index 00138eb43a..af81cba12c 100644
> --- a/csu/libc-tls.c
> +++ b/csu/libc-tls.c
> @@ -195,6 +195,7 @@ __libc_setup_tls (void)
>  #endif
>    if (__builtin_expect (lossage != NULL, 0))
>      _startup_fatal (lossage);
> +  __dl_inittcb ();
>
>    /* Update the executable's link map with enough information to make
>       the TLS routines happy.  */
> diff --git a/elf/Makefile b/elf/Makefile
> index 8563555079..66ce2953a4 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -30,7 +30,7 @@ routines      = $(all-dl-routines) dl-support dl-iteratephdr \
>  # profiled libraries.
>  dl-routines    = $(addprefix dl-,load lookup object reloc deps hwcaps \
>                                   runtime init fini debug misc \
> -                                 version profile tls origin scope \
> +                                 version profile tls inittcb origin scope \
>                                   execstack caller open close trampoline \
>                                   exception sort-maps)
>  ifeq (yes,$(use-ldconfig))
> diff --git a/elf/dl-inittcb.c b/elf/dl-inittcb.c
> new file mode 100644
> index 0000000000..5a70e9775d
> --- /dev/null
> +++ b/elf/dl-inittcb.c
> @@ -0,0 +1,22 @@
> +/* Initialize TCB contents.  Generic version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +void
> +__dl_inittcb (void)
> +{
> +}
> diff --git a/elf/rtld.c b/elf/rtld.c
> index cfd3729b8e..214e2312fa 100644
> --- a/elf/rtld.c
> +++ b/elf/rtld.c
> @@ -740,6 +740,7 @@ cannot allocate TLS data structures for initial thread\n");
>    const char *lossage = TLS_INIT_TP (tcbp);
>    if (__glibc_unlikely (lossage != NULL))
>      _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
> +  __dl_inittcb ();
>    tls_init_tp_called = true;
>
>    return tcbp;
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 769d974d50..6c62ff3da0 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -80,6 +80,7 @@ the standard.
>  @menu
>  * Default Thread Attributes::             Setting default attributes for
>                                           threads in a process.
> +* Identifying Threads::                   Unique identifiers for threads.
>  @end menu
>
>  @node Default Thread Attributes
> @@ -124,6 +125,29 @@ The system does not have sufficient memory.
>  @end table
>  @end deftypefun
>
> +@node Identifying Threads
> +@subsection Unique identifiers for threads
> +
> +@Theglibc{} provides a non-standard function to obtain a unique thread
> +identifier.
> +
> +@deftypefun uint64_t pthread_thread_number_np (pthread_t @var{thread})
> +@standards{GNU, pthread.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +
> +This function returns a number that uniquely identifies @var{thread}
> +among all past, current, and future running threads.  This number does
> +not change during the life-time of the thread.  Once returned by this
> +function, a number will not be reused after the thread terminates.
> +
> +The returned number is only unique with regards to the current process.
> +It may be shared by subprocesses and other processes in the system.
> +
> +The initial (main) thread has number 1.  Thread numbers are not
> +necessarily assigned in a consecutive fashion.  They bear no
> +relationship to process IDs or thread IDs assigned by the kernel.
> +@end deftypefun
> +
>  @c FIXME these are undocumented:
>  @c pthread_atfork
>  @c pthread_attr_destroy
> diff --git a/nptl/Makefile b/nptl/Makefile
> index ae388d1112..087fb6a8b5 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -30,7 +30,7 @@ install-lib-ldscripts := libpthread.so
>
>  routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
>            libc-cleanup libc_pthread_init libc_multiple_threads \
> -          register-atfork unregister-atfork pthread_self
> +          register-atfork unregister-atfork pthread_self thread_number
>  shared-only-routines = forward
>
>  # We need to provide certain routines for compatibility with existing
> @@ -302,7 +302,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
>                             c89 gnu89 c99 gnu99 c11 gnu11) \
>         tst-bad-schedattr \
>         tst-thread_local1 tst-mutex-errorcheck tst-robust10 \
> -       tst-robust-fork tst-create-detached tst-memstream
> +       tst-robust-fork tst-create-detached tst-memstream \
> +       tst-thread_number-single tst-thread_number-multi \
>
>  tests-internal := tst-rwlock19 tst-rwlock20 \
>                   tst-sem11 tst-sem12 tst-sem13 \
> @@ -318,7 +319,9 @@ test-srcs = tst-oddstacklimit
>  test-xfail-tst-once5 = yes
>
>  # Files which must not be linked with libpthread.
> -tests-nolibpthread = tst-unload
> +tests-nolibpthread = tst-unload \
> +  tst-thread_number-single \
> +  tst-thread_number-single-static \
>
>  gen-as-const-headers = pthread-errnos.sym \
>                        unwindbuf.sym \
> @@ -433,9 +436,13 @@ link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \
>  tests-static += tst-locale1 tst-locale2 tst-stackguard1-static \
>                 tst-cancel21-static tst-cancel24-static tst-cond8-static \
>                 tst-mutex8-static tst-mutexpi8-static tst-sem11-static \
> -               tst-sem12-static
> +               tst-sem12-static tst-thread_number-single-static \
> +               tst-thread_number-multi-static \
> +
>  tests += tst-cancel21-static tst-cancel24-static \
> -        tst-cond8-static
> +  tst-cond8-static tst-thread_number-single-static \
> +  tst-thread_number-multi-static \
> +
>  tests-internal += tst-sem11-static tst-sem12-static tst-stackguard1-static
>  xtests-static += tst-setuid1-static
>
> diff --git a/nptl/Versions b/nptl/Versions
> index 0ae5def464..8b6c839408 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -28,6 +28,9 @@ libc {
>      pthread_cond_wait; pthread_cond_signal;
>      pthread_cond_broadcast; pthread_cond_timedwait;
>    }
> +  GLBIC_2.27 {
> +    pthread_thread_number_np;
> +  }
>    GLIBC_PRIVATE {
>      __libc_alloca_cutoff;
>      # Internal libc interface to libpthread
> diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
> index 1cc7893195..0e1cf3939e 100644
> --- a/nptl/allocatestack.c
> +++ b/nptl/allocatestack.c
> @@ -413,16 +413,21 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
>    assert (powerof2 (pagesize_m1 + 1));
>    assert (TCB_ALIGNMENT >= STACK_ALIGN);
>
> -  /* Get the stack size from the attribute if it is set.  Otherwise we
> -     use the default we determined at start time.  */
> -  if (attr->stacksize != 0)
> -    size = attr->stacksize;
> -  else
> -    {
> -      lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
> +  uint64_t thread_number;
> +  lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
> +  {
> +    /* Number 1 is reserved for the initial thread.  */
> +    static uint64_t global_thread_number = 1;
> +    thread_number = ++global_thread_number;
> +
> +    /* Get the stack size from the attribute if it is set.  Otherwise
> +       we use the default we determined at start time.  */
> +    if (attr->stacksize != 0)
> +      size = attr->stacksize;
> +    else
>        size = __default_pthread_attr.stacksize;
> -      lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
> -    }
> +  }
> +  lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);


Why can't you just make global_thread_number  do an atomic addition
instead of the lock here?   It will be slightly faster.  But I notice
you don't handle the case where you create and destroy over 2^64-1
threads (that is an overflow of global_thread_number).  You don't even
mention this limitation any where.  I can think of (maybe bad)
examples where this could be the case.  Treating threads as cheap as
run pools.  Yes it is not a good idea to do that but people can do it.

Thanks,
Andrew

>
>    /* Get memory for the stack.  */
>    if (__glibc_unlikely (attr->flags & ATTR_FLAG_STACKADDR))
> @@ -758,6 +763,8 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
>  #endif
>    pd->robust_head.list = &pd->robust_head;
>
> +  pd->number = thread_number;
> +
>    /* We place the thread descriptor at the end of the stack.  */
>    *pdp = pd;
>
> diff --git a/nptl/descr.h b/nptl/descr.h
> index c83b17b674..49e266139e 100644
> --- a/nptl/descr.h
> +++ b/nptl/descr.h
> @@ -395,6 +395,9 @@ struct pthread
>    /* Resolver state.  */
>    struct __res_state res;
>
> +  /* Unique number assigned to this thread.  */
> +  uint64_t number;
> +
>    /* This member must be last.  */
>    char end_padding[];
>
> diff --git a/nptl/thread_number.c b/nptl/thread_number.c
> new file mode 100644
> index 0000000000..a9fdaa508b
> --- /dev/null
> +++ b/nptl/thread_number.c
> @@ -0,0 +1,26 @@
> +/* Unique numbers for threads.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "pthreadP.h"
> +
> +__uint64_t
> +pthread_thread_number_np (pthread_t threadid)
> +{
> +  struct pthread *pd = (struct pthread *) threadid;
> +  return pd->number;
> +}
> diff --git a/nptl/tst-thread_number-multi-static.c b/nptl/tst-thread_number-multi-static.c
> new file mode 100644
> index 0000000000..658928cfd5
> --- /dev/null
> +++ b/nptl/tst-thread_number-multi-static.c
> @@ -0,0 +1,19 @@
> +/* Test unique numbers for threads, static multi-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "tst-thread_number-multi.c"
> diff --git a/nptl/tst-thread_number-multi.c b/nptl/tst-thread_number-multi.c
> new file mode 100644
> index 0000000000..e26f19e44a
> --- /dev/null
> +++ b/nptl/tst-thread_number-multi.c
> @@ -0,0 +1,99 @@
> +/* Test unique numbers for threads, non-static multi-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <pthread.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/xthread.h>
> +
> +static void
> +subprocess (void *closure)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +}
> +
> +static void *
> +subthread (void *closure)
> +{
> +  if (closure != NULL)
> +    xpthread_barrier_wait (closure);
> +  return NULL;
> +}
> +
> +static int
> +compare (const void *pleft, const void *pright)
> +{
> +  uint64_t left = *(const uint64_t *)pleft;
> +  uint64_t right = *(const uint64_t *)pright;
> +  if (left < right)
> +    return -1;
> +  if (left > right)
> +    return 1;
> +  return 0;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);
> +
> +  /* Create thread_count threads, half of which are joined
> +     immediately, have of which stay arround.  */
> +  enum { thread_count = 10 };
> +  pthread_barrier_t barrier;
> +  xpthread_barrier_init (&barrier, NULL, thread_count / 2 + 1);
> +  uint64_t ids[thread_count];
> +  pthread_t threads[thread_count]; /* Only even-numbered entries are valid.  */
> +  for (int i = 0; i < thread_count; ++i)
> +    {
> +      bool stay_around = (i % 2) == 0;
> +      threads[i] = xpthread_create (NULL, subthread,
> +                                    stay_around ? &barrier : NULL);
> +      ids[i] = pthread_thread_number_np (threads[i]);
> +      TEST_VERIFY (ids[i] != 1);
> +      if (!stay_around)
> +        xpthread_join (threads[i]);
> +    }
> +
> +  /* Check that the IDs are all distinct.  */
> +  qsort (ids, thread_count, sizeof (ids[0]), compare);
> +  for (int i = 1; i < thread_count; ++i)
> +    TEST_VERIFY (ids[i - 1] < ids[i]);
> +
> +  /* Main thread ID should remain at 1.  */
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);
> +
> +  /* Clean up.  */
> +  xpthread_barrier_wait (&barrier);
> +  for (int i = 0; i < thread_count; ++i)
> +    if ((i % 2) == 0)
> +      xpthread_join (threads[i]);
> +
> +  /* Main thread ID should still remain at 1.  */
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/nptl/tst-thread_number-single-static.c b/nptl/tst-thread_number-single-static.c
> new file mode 100644
> index 0000000000..5c21063c36
> --- /dev/null
> +++ b/nptl/tst-thread_number-single-static.c
> @@ -0,0 +1,19 @@
> +/* Test unique numbers for threads, static single-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "tst-thread_number-single.c"
> diff --git a/nptl/tst-thread_number-single.c b/nptl/tst-thread_number-single.c
> new file mode 100644
> index 0000000000..43497205c7
> --- /dev/null
> +++ b/nptl/tst-thread_number-single.c
> @@ -0,0 +1,38 @@
> +/* Test unique numbers for threads, non-static single-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <pthread.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +
> +static void
> +subprocess (void *closure)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +}
> +
> +static int
> +do_test (void)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
> index 7a65dc641c..99f2e58875 100644
> --- a/sysdeps/generic/ldsodefs.h
> +++ b/sysdeps/generic/ldsodefs.h
> @@ -1056,6 +1056,10 @@ void __libc_setup_tls (void);
>  void __pthread_initialize_minimal (void) weak_function;
>  #endif
>
> +/* Initialize the already-existing TCB for the main thread.  Called
> +   during dynamic linker startup or from __libc_setup_tls.  */
> +void __dl_inittcb (void) attribute_hidden;
> +
>  /* Allocate memory for static TLS block (unless MEM is nonzero) and dtv.  */
>  extern void *_dl_allocate_tls (void *mem);
>  rtld_hidden_proto (_dl_allocate_tls)
> diff --git a/sysdeps/nptl/dl-inittcb.c b/sysdeps/nptl/dl-inittcb.c
> new file mode 100644
> index 0000000000..c25424dfa6
> --- /dev/null
> +++ b/sysdeps/nptl/dl-inittcb.c
> @@ -0,0 +1,27 @@
> +/* Initialize TCB contents.  NPTL version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <ldsodefs.h>
> +#include <tls.h>
> +
> +void
> +__dl_inittcb (void)
> +{
> +  /* The main thread has number 1.  */
> +  THREAD_SELF->number = 1;
> +}
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 2b2b386ab3..e0714ed951 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -1148,6 +1148,10 @@ extern int pthread_atfork (void (*__prepare) (void),
>                            void (*__child) (void)) __THROW;
>
>
> +/* Return a number uniquely identifying THREAD, even after its
> +   termination.  */
> +__uint64_t pthread_thread_number_np (pthread_t __thread_id) __THROW;
> +
>  #ifdef __USE_EXTERN_INLINES
>  /* Optimizations.  */
>  __extern_inline int
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index ec0ead15dd..e206f77540 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.17 GLIBC_2.17 A
>  GLIBC_2.17 _Exit F
>  GLIBC_2.17 _IO_2_1_stderr_ D 0xe0
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 5355769974..92429a8d78 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index 9bafe71b51..bcd54ecdf5 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 90aa8d034f..84445a123e 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 4d44c30c64..caa8dff010 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 112fc57634..02301da334 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 2e8b6a4586..a3fbcb831f 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 3c33400f67..203a63aa27 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index e1b1a579d2..a3be97ef65 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.18 GLIBC_2.18 A
>  GLIBC_2.18 _Exit F
>  GLIBC_2.18 _IO_2_1_stderr_ D 0x98
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index c1550323f3..94de2ef489 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 3b3a172e4f..878bee4bb5 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 101ca7a241..94706fccb4 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 2d129f7170..adc3de5c88 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 8bc350aff8..f6198b3dbb 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.21 GLIBC_2.21 A
>  GLIBC_2.21 _Exit F
>  GLIBC_2.21 _IO_2_1_stderr_ D 0x98
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 127c426e1c..363a3a2e10 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index a9411318e2..dfa0463282 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
> index d7bf5db601..37a34eb833 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.17 GLIBC_2.17 A
>  GLIBC_2.17 _Exit F
>  GLIBC_2.17 _IO_2_1_stderr_ D 0xe0
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> index a3415a72ac..a0dbaf366a 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 414338f9a2..a30b304817 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 GLIBC_2.0 A
>  GLIBC_2.0 _IO_adjust_column F
>  GLIBC_2.0 _IO_default_doallocate F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index f0f7a69b64..a759aa9cf5 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index 9f95aba898..133e0a55ef 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 83fbdf2d7e..e525ed69d6 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.0 .div F
>  GLIBC_2.0 .mul F
>  GLIBC_2.0 .rem F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index ee84ad10bc..d4fb34eceb 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>  GCC_3.0 __deregister_frame_info_bases F
>  GCC_3.0 __register_frame_info_bases F
>  GCC_3.0 __register_frame_info_table_bases F
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> index dcbfbc05ac..f598149374 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.12 GLIBC_2.12 A
>  GLIBC_2.12 _Exit F
>  GLIBC_2.12 _IO_2_1_stderr_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> index 53dc99c45a..cb0054f532 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.12 GLIBC_2.12 A
>  GLIBC_2.12 _Exit F
>  GLIBC_2.12 _IO_2_1_stderr_ D 0xe0
> diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> index dcbfbc05ac..f598149374 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.12 GLIBC_2.12 A
>  GLIBC_2.12 _Exit F
>  GLIBC_2.12 _IO_2_1_stderr_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index ae4dcaa47e..70a15fa003 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.10 GLIBC_2.10 A
>  GLIBC_2.10 __cxa_at_quick_exit F
>  GLIBC_2.10 __posix_getopt F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 0dbda14796..afbdec65d5 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -1,3 +1,5 @@
> +GLBIC_2.27 GLBIC_2.27 A
> +GLBIC_2.27 pthread_thread_number_np F
>  GLIBC_2.16 GLIBC_2.16 A
>  GLIBC_2.16 _Exit F
>  GLIBC_2.16 _IO_2_1_stderr_ D 0xa0<div id="DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2"><br />
<table style="border-top: 1px solid #D3D4DE;">
	<tr>
        <td style="width: 55px; padding-top: 13px;"><a
href="http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail"
target="_blank"><img
src="https://ipmcdn.avast.com/images/icons/icon-envelope-tick-green-avg-v1.png"
alt="" width="46" height="29" style="width: 46px; height: 29px;"
/></a></td>
		<td style="width: 470px; padding-top: 12px; color: #41424e;
font-size: 13px; font-family: Arial, Helvetica, sans-serif;
line-height: 18px;">Virus-free. <a
href="http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail"
target="_blank" style="color: #4453ea;">www.avg.com</a>
		</td>
	</tr>
</table><a href="#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2" width="1"
height="1"></a></div>
  
Carlos O'Donell Dec. 15, 2017, 4:08 a.m. UTC | #4
On 12/14/2017 10:56 AM, Florian Weimer wrote:
> The implementation is actually in libc.so.  With a full implementation
> of pthread_self in libc.so, pthread_thread_number_np is completely
> usable without libpthread.

High level:

The addition of a new API to libc.so needs a strong justification.

Do you have a use in mind for this API?

When would users use this number?

Why would they use this number?

Do any of the uses you envision overlap with the longstanding 
requests for gettid()?

Design level:

We make claims that the thread number is never reused, but then the
implementation wraps the uint64_t global counter, and reuses the
number. If we really don't allow reuse, then we limit the implementation
to only ever starting 2^64-1 threads, similar to the discussions around
dlopen and void* cookies, I don't know if this kind of limit is a good
idea or not. My instinct tells me we should not limit the implementation
in such ways.

We could allocate the thread numbers lazily, and that would certainly
avoid limiting ourselves to only allocating 2^64-1 threads. On top of
that if the function could return an error then we could return such
an error at overflow:

 int pthread_thread_number_np (uint64_t* thread_number, pthread_t @var{thread})

Returns 0 if the thread has a unique number, otherwise -1 if it does not.

Implementation level:

Just some minor textual nits, and missing comments.


> 2017-12-14  Florian Weimer  <fweimer@redhat.com>
> 
> 	nptl: Add pthread_thread_number_np function.
> 	* csu/libc-tls.c (__libc_setup_tls): Call __dl_inittcb.
> 	* elf/Makefile (dl-routines): Add dl-inittcb.
> 	* elf/dl-inittcb.c: New file.
> 	* elf/rtld.c (init_tls): Call __dl_inittcb.
> 	* manual/threads.texi (Non-POSIX Extensions): Reference Non-POSIX
> 	Extensions.
> 	(Non-POSIX Extensions): New node.
> 	* nptl/Makefile (routines): Add thread_number.
> 	(tests): Add tst-thread_number-single, tst-thread_number-multi,
> 	tst-thread_number-single-static, tst-thread_number-multi-static.
> 	(tests-nolibpthread): Add tst-thread_number-single,
> 	tst-thread_number-single-static.
> 	(tests-static): Add tst-thread_number-single-static,
> 	tst-thread_number-multi-static.
> 	* nptl/Versions (GLIBC_2.27): Export pthread_thread_number_np.
> 	* nptl/allocatestack.c (allocate_stack): Increment
> 	global_thread_number under__default_pthread_attr_lock and use its
> 	value to set the new thread number.
> 	* nptl/descr.h (struct pthread): Add number member.
> 	* nptl/thread_number.c: New file.
> 	* nptl/tst-thread_number-multi.c: Likewise.
> 	* nptl/tst-thread_number-single.c: Likewise.
> 	* nptl/tst-thread_number-multi-static.c: Likewise.
> 	* nptl/tst-thread_number-single-static.c: Likewise.
> 	* sysdeps/nptl/pthread.h (pthread_thread_number_np): Declare.
> 	* sysdeps/unix/sysv/linux/libc**.abilist: Update.
> 
> diff --git a/csu/libc-tls.c b/csu/libc-tls.c
> index 00138eb43a..af81cba12c 100644
> --- a/csu/libc-tls.c
> +++ b/csu/libc-tls.c
> @@ -195,6 +195,7 @@ __libc_setup_tls (void)
>  #endif
>    if (__builtin_expect (lossage != NULL, 0))
>      _startup_fatal (lossage);
> +  __dl_inittcb ();
>  
>    /* Update the executable's link map with enough information to make
>       the TLS routines happy.  */
> diff --git a/elf/Makefile b/elf/Makefile
> index 8563555079..66ce2953a4 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -30,7 +30,7 @@ routines	= $(all-dl-routines) dl-support dl-iteratephdr \
>  # profiled libraries.
>  dl-routines	= $(addprefix dl-,load lookup object reloc deps hwcaps \
>  				  runtime init fini debug misc \
> -				  version profile tls origin scope \
> +				  version profile tls inittcb origin scope \
>  				  execstack caller open close trampoline \
>  				  exception sort-maps)
>  ifeq (yes,$(use-ldconfig))
> diff --git a/elf/dl-inittcb.c b/elf/dl-inittcb.c
> new file mode 100644
> index 0000000000..5a70e9775d
> --- /dev/null
> +++ b/elf/dl-inittcb.c
> @@ -0,0 +1,22 @@
> +/* Initialize TCB contents.  Generic version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +void
> +__dl_inittcb (void)
> +{
> +}
> diff --git a/elf/rtld.c b/elf/rtld.c
> index cfd3729b8e..214e2312fa 100644
> --- a/elf/rtld.c
> +++ b/elf/rtld.c
> @@ -740,6 +740,7 @@ cannot allocate TLS data structures for initial thread\n");
>    const char *lossage = TLS_INIT_TP (tcbp);
>    if (__glibc_unlikely (lossage != NULL))
>      _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
> +  __dl_inittcb ();
>    tls_init_tp_called = true;
>  
>    return tcbp;
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 769d974d50..6c62ff3da0 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -80,6 +80,7 @@ the standard.
>  @menu
>  * Default Thread Attributes::             Setting default attributes for
>  					  threads in a process.
> +* Identifying Threads::                   Unique identifiers for threads.
>  @end menu
>  
>  @node Default Thread Attributes
> @@ -124,6 +125,29 @@ The system does not have sufficient memory.
>  @end table
>  @end deftypefun
>  
> +@node Identifying Threads
> +@subsection Unique identifiers for threads
> +
> +@Theglibc{} provides a non-standard function to obtain a unique thread
> +identifier.
> +
> +@deftypefun uint64_t pthread_thread_number_np (pthread_t @var{thread})
> +@standards{GNU, pthread.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +
> +This function returns a number that uniquely identifies @var{thread}
> +among all past, current, and future running threads.  This number does
> +not change during the life-time of the thread.  Once returned by this
> +function, a number will not be reused after the thread terminates.

We should be clear here that uint64_t (the return type) only has 64-bits,
and while theoretically difficult to reach, this has a limit. The only way
not to reuse the numbers is to limit the implementation to only allowing
uint64_t worth of threads to ever be started. That's a limit that never
existed before the existence of this API.

My worry here is that once you open pandoras box and say that they thread
number *might* be reused after 2^64-1 pthread_create's, then users will
start writing code *not* to treat it as unique.

Thus, see my notes above about changing the interface slightly.

> +
> +The returned number is only unique with regards to the current process.
> +It may be shared by subprocesses and other processes in the system.
> +
> +The initial (main) thread has number 1.  Thread numbers are not
> +necessarily assigned in a consecutive fashion.  They bear no
> +relationship to process IDs or thread IDs assigned by the kernel.

Suggest:

They bear no relationship to POSIX thread IDs (pthread_t), process IDs,
or Linux kernel thread IDs.

> +@end deftypefun
> +
>  @c FIXME these are undocumented:
>  @c pthread_atfork
>  @c pthread_attr_destroy
> diff --git a/nptl/Makefile b/nptl/Makefile
> index ae388d1112..087fb6a8b5 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -30,7 +30,7 @@ install-lib-ldscripts := libpthread.so
>  
>  routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
>  	   libc-cleanup libc_pthread_init libc_multiple_threads \
> -	   register-atfork unregister-atfork pthread_self
> +	   register-atfork unregister-atfork pthread_self thread_number
>  shared-only-routines = forward
>  
>  # We need to provide certain routines for compatibility with existing
> @@ -302,7 +302,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
>  			    c89 gnu89 c99 gnu99 c11 gnu11) \
>  	tst-bad-schedattr \
>  	tst-thread_local1 tst-mutex-errorcheck tst-robust10 \
> -	tst-robust-fork tst-create-detached tst-memstream
> +	tst-robust-fork tst-create-detached tst-memstream \
> +	tst-thread_number-single tst-thread_number-multi \
>  
>  tests-internal := tst-rwlock19 tst-rwlock20 \
>  		  tst-sem11 tst-sem12 tst-sem13 \
> @@ -318,7 +319,9 @@ test-srcs = tst-oddstacklimit
>  test-xfail-tst-once5 = yes
>  
>  # Files which must not be linked with libpthread.
> -tests-nolibpthread = tst-unload
> +tests-nolibpthread = tst-unload \
> +  tst-thread_number-single \
> +  tst-thread_number-single-static \
>  
>  gen-as-const-headers = pthread-errnos.sym \
>  		       unwindbuf.sym \
> @@ -433,9 +436,13 @@ link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \
>  tests-static += tst-locale1 tst-locale2 tst-stackguard1-static \
>  		tst-cancel21-static tst-cancel24-static tst-cond8-static \
>  		tst-mutex8-static tst-mutexpi8-static tst-sem11-static \
> -		tst-sem12-static
> +		tst-sem12-static tst-thread_number-single-static \
> +		tst-thread_number-multi-static \
> +
>  tests += tst-cancel21-static tst-cancel24-static \
> -	 tst-cond8-static
> +  tst-cond8-static tst-thread_number-single-static \
> +  tst-thread_number-multi-static \
> +
>  tests-internal += tst-sem11-static tst-sem12-static tst-stackguard1-static
>  xtests-static += tst-setuid1-static
>  
> diff --git a/nptl/Versions b/nptl/Versions
> index 0ae5def464..8b6c839408 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -28,6 +28,9 @@ libc {
>      pthread_cond_wait; pthread_cond_signal;
>      pthread_cond_broadcast; pthread_cond_timedwait;
>    }
> +  GLBIC_2.27 {

Typo. GLIBC.

> +    pthread_thread_number_np;
> +  }
>    GLIBC_PRIVATE {
>      __libc_alloca_cutoff;
>      # Internal libc interface to libpthread
> diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
> index 1cc7893195..0e1cf3939e 100644
> --- a/nptl/allocatestack.c
> +++ b/nptl/allocatestack.c
> @@ -413,16 +413,21 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
>    assert (powerof2 (pagesize_m1 + 1));
>    assert (TCB_ALIGNMENT >= STACK_ALIGN);
>  
> -  /* Get the stack size from the attribute if it is set.  Otherwise we
> -     use the default we determined at start time.  */
> -  if (attr->stacksize != 0)
> -    size = attr->stacksize;
> -  else
> -    {
> -      lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
> +  uint64_t thread_number;
> +  lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);

You need to add some P&C comments explaining that __default_pthread_attr_lock
is now *also* protecting the global_thread_number global and why.

> +  {
> +    /* Number 1 is reserved for the initial thread.  */
> +    static uint64_t global_thread_number = 1;
> +    thread_number = ++global_thread_number;

Andrew asked this already, but we either need a comment about not worrying
about overflow, or handling it properly.

> +
> +    /* Get the stack size from the attribute if it is set.  Otherwise
> +       we use the default we determined at start time.  */
> +    if (attr->stacksize != 0)
> +      size = attr->stacksize;
> +    else
>        size = __default_pthread_attr.stacksize;
> -      lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
> -    }
> +  }
> +  lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
>  
>    /* Get memory for the stack.  */
>    if (__glibc_unlikely (attr->flags & ATTR_FLAG_STACKADDR))
> @@ -758,6 +763,8 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
>  #endif
>    pd->robust_head.list = &pd->robust_head;
>  
> +  pd->number = thread_number;
> +
>    /* We place the thread descriptor at the end of the stack.  */
>    *pdp = pd;
>  
> diff --git a/nptl/descr.h b/nptl/descr.h
> index c83b17b674..49e266139e 100644
> --- a/nptl/descr.h
> +++ b/nptl/descr.h
> @@ -395,6 +395,9 @@ struct pthread
>    /* Resolver state.  */
>    struct __res_state res;
>  
> +  /* Unique number assigned to this thread.  */
> +  uint64_t number;
> +
>    /* This member must be last.  */
>    char end_padding[];
>  
> diff --git a/nptl/thread_number.c b/nptl/thread_number.c
> new file mode 100644
> index 0000000000..a9fdaa508b
> --- /dev/null
> +++ b/nptl/thread_number.c
> @@ -0,0 +1,26 @@
> +/* Unique numbers for threads.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "pthreadP.h"
> +
> +__uint64_t
> +pthread_thread_number_np (pthread_t threadid)
> +{
> +  struct pthread *pd = (struct pthread *) threadid;
> +  return pd->number;
> +}

OK.

> diff --git a/nptl/tst-thread_number-multi-static.c b/nptl/tst-thread_number-multi-static.c
> new file mode 100644
> index 0000000000..658928cfd5
> --- /dev/null
> +++ b/nptl/tst-thread_number-multi-static.c
> @@ -0,0 +1,19 @@
> +/* Test unique numbers for threads, static multi-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "tst-thread_number-multi.c"
> diff --git a/nptl/tst-thread_number-multi.c b/nptl/tst-thread_number-multi.c
> new file mode 100644
> index 0000000000..e26f19e44a
> --- /dev/null
> +++ b/nptl/tst-thread_number-multi.c
> @@ -0,0 +1,99 @@
> +/* Test unique numbers for threads, non-static multi-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <pthread.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/xthread.h>
> +
> +static void
> +subprocess (void *closure)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +}
> +
> +static void *
> +subthread (void *closure)
> +{
> +  if (closure != NULL)
> +    xpthread_barrier_wait (closure);
> +  return NULL;
> +}
> +
> +static int
> +compare (const void *pleft, const void *pright)
> +{
> +  uint64_t left = *(const uint64_t *)pleft;
> +  uint64_t right = *(const uint64_t *)pright;
> +  if (left < right)
> +    return -1;
> +  if (left > right)
> +    return 1;
> +  return 0;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);

Why do we isolate this in a subprocess?
> +
> +  /* Create thread_count threads, half of which are joined
> +     immediately, have of which stay arround.  */

s/arround/around/g

> +  enum { thread_count = 10 };
> +  pthread_barrier_t barrier;
> +  xpthread_barrier_init (&barrier, NULL, thread_count / 2 + 1);
> +  uint64_t ids[thread_count];
> +  pthread_t threads[thread_count]; /* Only even-numbered entries are valid.  */
> +  for (int i = 0; i < thread_count; ++i)
> +    {
> +      bool stay_around = (i % 2) == 0;
> +      threads[i] = xpthread_create (NULL, subthread,
> +                                    stay_around ? &barrier : NULL);
> +      ids[i] = pthread_thread_number_np (threads[i]);
> +      TEST_VERIFY (ids[i] != 1);
> +      if (!stay_around)
> +        xpthread_join (threads[i]);
> +    }
> +
> +  /* Check that the IDs are all distinct.  */
> +  qsort (ids, thread_count, sizeof (ids[0]), compare);
> +  for (int i = 1; i < thread_count; ++i)
> +    TEST_VERIFY (ids[i - 1] < ids[i]);
> +
> +  /* Main thread ID should remain at 1.  */
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);

Again, why in a subprocess?

> +
> +  /* Clean up.  */
> +  xpthread_barrier_wait (&barrier);
> +  for (int i = 0; i < thread_count; ++i)
> +    if ((i % 2) == 0)
> +      xpthread_join (threads[i]);
> +
> +  /* Main thread ID should still remain at 1.  */
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);

Likewise.

> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/nptl/tst-thread_number-single-static.c b/nptl/tst-thread_number-single-static.c
> new file mode 100644
> index 0000000000..5c21063c36
> --- /dev/null
> +++ b/nptl/tst-thread_number-single-static.c
> @@ -0,0 +1,19 @@
> +/* Test unique numbers for threads, static single-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "tst-thread_number-single.c"
> diff --git a/nptl/tst-thread_number-single.c b/nptl/tst-thread_number-single.c
> new file mode 100644
> index 0000000000..43497205c7
> --- /dev/null
> +++ b/nptl/tst-thread_number-single.c
> @@ -0,0 +1,38 @@
> +/* Test unique numbers for threads, non-static single-threaded version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <pthread.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +
> +static void
> +subprocess (void *closure)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +}
> +
> +static int
> +do_test (void)
> +{
> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
> +  support_isolate_in_subprocess (subprocess, NULL);

Likewise. 

> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
> index 7a65dc641c..99f2e58875 100644
> --- a/sysdeps/generic/ldsodefs.h
> +++ b/sysdeps/generic/ldsodefs.h
> @@ -1056,6 +1056,10 @@ void __libc_setup_tls (void);
>  void __pthread_initialize_minimal (void) weak_function;
>  #endif
>  
> +/* Initialize the already-existing TCB for the main thread.  Called
> +   during dynamic linker startup or from __libc_setup_tls.  */
> +void __dl_inittcb (void) attribute_hidden;
> +
>  /* Allocate memory for static TLS block (unless MEM is nonzero) and dtv.  */
>  extern void *_dl_allocate_tls (void *mem);
>  rtld_hidden_proto (_dl_allocate_tls)
> diff --git a/sysdeps/nptl/dl-inittcb.c b/sysdeps/nptl/dl-inittcb.c
> new file mode 100644
> index 0000000000..c25424dfa6
> --- /dev/null
> +++ b/sysdeps/nptl/dl-inittcb.c
> @@ -0,0 +1,27 @@
> +/* Initialize TCB contents.  NPTL version.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   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 Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <ldsodefs.h>
> +#include <tls.h>
> +
> +void
> +__dl_inittcb (void)
> +{
> +  /* The main thread has number 1.  */
> +  THREAD_SELF->number = 1;

OK.

> +}
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 2b2b386ab3..e0714ed951 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -1148,6 +1148,10 @@ extern int pthread_atfork (void (*__prepare) (void),
>  			   void (*__child) (void)) __THROW;
>  
>  
> +/* Return a number uniquely identifying THREAD, even after its
> +   termination.  */
> +__uint64_t pthread_thread_number_np (pthread_t __thread_id) __THROW;
> +
>  #ifdef __USE_EXTERN_INLINES
>  /* Optimizations.  */
>  __extern_inline int

[abilist updates]

As Nix noted there is a typo in nptl/Versions which propagates to the
abilist files too.
  
Florian Weimer Dec. 15, 2017, 6:40 a.m. UTC | #5
On 12/15/2017 12:34 AM, Nix wrote:
> On 14 Dec 2017, Florian Weimer uttered the following:
>> diff --git a/nptl/Versions b/nptl/Versions
>> index 0ae5def464..8b6c839408 100644
>> --- a/nptl/Versions
>> +++ b/nptl/Versions
>> @@ -28,6 +28,9 @@ libc {
>>       pthread_cond_wait; pthread_cond_signal;
>>       pthread_cond_broadcast; pthread_cond_timedwait;
>>     }
>> +  GLBIC_2.27 {
>> +    pthread_thread_number_np;
>> +  }
>>     GLIBC_PRIVATE {
>>       __libc_alloca_cutoff;
>>       # Internal libc interface to libpthread
> 
> GLBIC is a definite typo (repeated, of course, in all the abilist
> files).

Oops, I'll send an updated patch in respond to Carlos' message.

Thanks,
Florian
  
Florian Weimer Dec. 15, 2017, 7:47 a.m. UTC | #6
On 12/15/2017 01:29 AM, Andrew Pinski wrote:
> Why can't you just make global_thread_number  do an atomic addition
> instead of the lock here?   It will be slightly faster.

Not sure about that.  In the common case (no stack size specified) we 
already acquire a lock.  So we'd have to perform three atomic operations 
instead of two if we don't reuse the lock.

There's also the problem of 32-bit architectures without 64-bit atomic 
operations.

> But I notice
> you don't handle the case where you create and destroy over 2^64-1
> threads (that is an overflow of global_thread_number).

Yes, I should add a sanity check and an abort for this case.

> You don't even mention this limitation any where.

Traditionally, we have been ignoring 64-bit counter overflows, treating 
them as impossible.  For a simple counter with no countermeasures 
against contention, I really don't see how the overflow can happen any 
time soon.

Thanks,
Florian
  
Andrew Pinski Dec. 15, 2017, 7:54 a.m. UTC | #7
On Thu, Dec 14, 2017 at 4:29 PM, Andrew Pinski <pinskia@gmail.com> wrote:
> On Thu, Dec 14, 2017 at 10:56 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> The implementation is actually in libc.so.  With a full implementation
>> of pthread_self in libc.so, pthread_thread_number_np is completely
>> usable without libpthread.
>>
>> 2017-12-14  Florian Weimer  <fweimer@redhat.com>
>>
>>         nptl: Add pthread_thread_number_np function.
>>         * csu/libc-tls.c (__libc_setup_tls): Call __dl_inittcb.
>>         * elf/Makefile (dl-routines): Add dl-inittcb.
>>         * elf/dl-inittcb.c: New file.
>>         * elf/rtld.c (init_tls): Call __dl_inittcb.
>>         * manual/threads.texi (Non-POSIX Extensions): Reference Non-POSIX
>>         Extensions.
>>         (Non-POSIX Extensions): New node.
>>         * nptl/Makefile (routines): Add thread_number.
>>         (tests): Add tst-thread_number-single, tst-thread_number-multi,
>>         tst-thread_number-single-static, tst-thread_number-multi-static.
>>         (tests-nolibpthread): Add tst-thread_number-single,
>>         tst-thread_number-single-static.
>>         (tests-static): Add tst-thread_number-single-static,
>>         tst-thread_number-multi-static.
>>         * nptl/Versions (GLIBC_2.27): Export pthread_thread_number_np.
>>         * nptl/allocatestack.c (allocate_stack): Increment
>>         global_thread_number under__default_pthread_attr_lock and use its
>>         value to set the new thread number.
>>         * nptl/descr.h (struct pthread): Add number member.
>>         * nptl/thread_number.c: New file.
>>         * nptl/tst-thread_number-multi.c: Likewise.
>>         * nptl/tst-thread_number-single.c: Likewise.
>>         * nptl/tst-thread_number-multi-static.c: Likewise.
>>         * nptl/tst-thread_number-single-static.c: Likewise.
>>         * sysdeps/nptl/pthread.h (pthread_thread_number_np): Declare.
>>         * sysdeps/unix/sysv/linux/libc**.abilist: Update.
>>
>> diff --git a/csu/libc-tls.c b/csu/libc-tls.c
>> index 00138eb43a..af81cba12c 100644
>> --- a/csu/libc-tls.c
>> +++ b/csu/libc-tls.c
>> @@ -195,6 +195,7 @@ __libc_setup_tls (void)
>>  #endif
>>    if (__builtin_expect (lossage != NULL, 0))
>>      _startup_fatal (lossage);
>> +  __dl_inittcb ();
>>
>>    /* Update the executable's link map with enough information to make
>>       the TLS routines happy.  */
>> diff --git a/elf/Makefile b/elf/Makefile
>> index 8563555079..66ce2953a4 100644
>> --- a/elf/Makefile
>> +++ b/elf/Makefile
>> @@ -30,7 +30,7 @@ routines      = $(all-dl-routines) dl-support dl-iteratephdr \
>>  # profiled libraries.
>>  dl-routines    = $(addprefix dl-,load lookup object reloc deps hwcaps \
>>                                   runtime init fini debug misc \
>> -                                 version profile tls origin scope \
>> +                                 version profile tls inittcb origin scope \
>>                                   execstack caller open close trampoline \
>>                                   exception sort-maps)
>>  ifeq (yes,$(use-ldconfig))
>> diff --git a/elf/dl-inittcb.c b/elf/dl-inittcb.c
>> new file mode 100644
>> index 0000000000..5a70e9775d
>> --- /dev/null
>> +++ b/elf/dl-inittcb.c
>> @@ -0,0 +1,22 @@
>> +/* Initialize TCB contents.  Generic version.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   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 Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +void
>> +__dl_inittcb (void)
>> +{
>> +}
>> diff --git a/elf/rtld.c b/elf/rtld.c
>> index cfd3729b8e..214e2312fa 100644
>> --- a/elf/rtld.c
>> +++ b/elf/rtld.c
>> @@ -740,6 +740,7 @@ cannot allocate TLS data structures for initial thread\n");
>>    const char *lossage = TLS_INIT_TP (tcbp);
>>    if (__glibc_unlikely (lossage != NULL))
>>      _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
>> +  __dl_inittcb ();
>>    tls_init_tp_called = true;
>>
>>    return tcbp;
>> diff --git a/manual/threads.texi b/manual/threads.texi
>> index 769d974d50..6c62ff3da0 100644
>> --- a/manual/threads.texi
>> +++ b/manual/threads.texi
>> @@ -80,6 +80,7 @@ the standard.
>>  @menu
>>  * Default Thread Attributes::             Setting default attributes for
>>                                           threads in a process.
>> +* Identifying Threads::                   Unique identifiers for threads.
>>  @end menu
>>
>>  @node Default Thread Attributes
>> @@ -124,6 +125,29 @@ The system does not have sufficient memory.
>>  @end table
>>  @end deftypefun
>>
>> +@node Identifying Threads
>> +@subsection Unique identifiers for threads
>> +
>> +@Theglibc{} provides a non-standard function to obtain a unique thread
>> +identifier.
>> +
>> +@deftypefun uint64_t pthread_thread_number_np (pthread_t @var{thread})
>> +@standards{GNU, pthread.h}
>> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
>> +
>> +This function returns a number that uniquely identifies @var{thread}
>> +among all past, current, and future running threads.  This number does
>> +not change during the life-time of the thread.  Once returned by this
>> +function, a number will not be reused after the thread terminates.
>> +
>> +The returned number is only unique with regards to the current process.
>> +It may be shared by subprocesses and other processes in the system.
>> +
>> +The initial (main) thread has number 1.  Thread numbers are not
>> +necessarily assigned in a consecutive fashion.  They bear no
>> +relationship to process IDs or thread IDs assigned by the kernel.
>> +@end deftypefun
>> +
>>  @c FIXME these are undocumented:
>>  @c pthread_atfork
>>  @c pthread_attr_destroy
>> diff --git a/nptl/Makefile b/nptl/Makefile
>> index ae388d1112..087fb6a8b5 100644
>> --- a/nptl/Makefile
>> +++ b/nptl/Makefile
>> @@ -30,7 +30,7 @@ install-lib-ldscripts := libpthread.so
>>
>>  routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
>>            libc-cleanup libc_pthread_init libc_multiple_threads \
>> -          register-atfork unregister-atfork pthread_self
>> +          register-atfork unregister-atfork pthread_self thread_number
>>  shared-only-routines = forward
>>
>>  # We need to provide certain routines for compatibility with existing
>> @@ -302,7 +302,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
>>                             c89 gnu89 c99 gnu99 c11 gnu11) \
>>         tst-bad-schedattr \
>>         tst-thread_local1 tst-mutex-errorcheck tst-robust10 \
>> -       tst-robust-fork tst-create-detached tst-memstream
>> +       tst-robust-fork tst-create-detached tst-memstream \
>> +       tst-thread_number-single tst-thread_number-multi \
>>
>>  tests-internal := tst-rwlock19 tst-rwlock20 \
>>                   tst-sem11 tst-sem12 tst-sem13 \
>> @@ -318,7 +319,9 @@ test-srcs = tst-oddstacklimit
>>  test-xfail-tst-once5 = yes
>>
>>  # Files which must not be linked with libpthread.
>> -tests-nolibpthread = tst-unload
>> +tests-nolibpthread = tst-unload \
>> +  tst-thread_number-single \
>> +  tst-thread_number-single-static \
>>
>>  gen-as-const-headers = pthread-errnos.sym \
>>                        unwindbuf.sym \
>> @@ -433,9 +436,13 @@ link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \
>>  tests-static += tst-locale1 tst-locale2 tst-stackguard1-static \
>>                 tst-cancel21-static tst-cancel24-static tst-cond8-static \
>>                 tst-mutex8-static tst-mutexpi8-static tst-sem11-static \
>> -               tst-sem12-static
>> +               tst-sem12-static tst-thread_number-single-static \
>> +               tst-thread_number-multi-static \
>> +
>>  tests += tst-cancel21-static tst-cancel24-static \
>> -        tst-cond8-static
>> +  tst-cond8-static tst-thread_number-single-static \
>> +  tst-thread_number-multi-static \
>> +
>>  tests-internal += tst-sem11-static tst-sem12-static tst-stackguard1-static
>>  xtests-static += tst-setuid1-static
>>
>> diff --git a/nptl/Versions b/nptl/Versions
>> index 0ae5def464..8b6c839408 100644
>> --- a/nptl/Versions
>> +++ b/nptl/Versions
>> @@ -28,6 +28,9 @@ libc {
>>      pthread_cond_wait; pthread_cond_signal;
>>      pthread_cond_broadcast; pthread_cond_timedwait;
>>    }
>> +  GLBIC_2.27 {
>> +    pthread_thread_number_np;
>> +  }
>>    GLIBC_PRIVATE {
>>      __libc_alloca_cutoff;
>>      # Internal libc interface to libpthread
>> diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
>> index 1cc7893195..0e1cf3939e 100644
>> --- a/nptl/allocatestack.c
>> +++ b/nptl/allocatestack.c
>> @@ -413,16 +413,21 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
>>    assert (powerof2 (pagesize_m1 + 1));
>>    assert (TCB_ALIGNMENT >= STACK_ALIGN);
>>
>> -  /* Get the stack size from the attribute if it is set.  Otherwise we
>> -     use the default we determined at start time.  */
>> -  if (attr->stacksize != 0)
>> -    size = attr->stacksize;
>> -  else
>> -    {
>> -      lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
>> +  uint64_t thread_number;
>> +  lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
>> +  {
>> +    /* Number 1 is reserved for the initial thread.  */
>> +    static uint64_t global_thread_number = 1;
>> +    thread_number = ++global_thread_number;
>> +
>> +    /* Get the stack size from the attribute if it is set.  Otherwise
>> +       we use the default we determined at start time.  */
>> +    if (attr->stacksize != 0)
>> +      size = attr->stacksize;
>> +    else
>>        size = __default_pthread_attr.stacksize;
>> -      lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
>> -    }
>> +  }
>> +  lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
>
>
> Why can't you just make global_thread_number  do an atomic addition
> instead of the lock here?   It will be slightly faster.  But I notice
> you don't handle the case where you create and destroy over 2^64-1
> threads (that is an overflow of global_thread_number).  You don't even
> mention this limitation any where.  I can think of (maybe bad)
> examples where this could be the case.  Treating threads as cheap as
> run pools.  Yes it is not a good idea to do that but people can do it.


So I did the math and I take back my objection with respect to the
overflow.  It would take more than a million years to overflow 64bit.
Even if creating a thread was less than 1 microsecond.

Thanks,
Andrew

>
> Thanks,
> Andrew
>
>>
>>    /* Get memory for the stack.  */
>>    if (__glibc_unlikely (attr->flags & ATTR_FLAG_STACKADDR))
>> @@ -758,6 +763,8 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
>>  #endif
>>    pd->robust_head.list = &pd->robust_head;
>>
>> +  pd->number = thread_number;
>> +
>>    /* We place the thread descriptor at the end of the stack.  */
>>    *pdp = pd;
>>
>> diff --git a/nptl/descr.h b/nptl/descr.h
>> index c83b17b674..49e266139e 100644
>> --- a/nptl/descr.h
>> +++ b/nptl/descr.h
>> @@ -395,6 +395,9 @@ struct pthread
>>    /* Resolver state.  */
>>    struct __res_state res;
>>
>> +  /* Unique number assigned to this thread.  */
>> +  uint64_t number;
>> +
>>    /* This member must be last.  */
>>    char end_padding[];
>>
>> diff --git a/nptl/thread_number.c b/nptl/thread_number.c
>> new file mode 100644
>> index 0000000000..a9fdaa508b
>> --- /dev/null
>> +++ b/nptl/thread_number.c
>> @@ -0,0 +1,26 @@
>> +/* Unique numbers for threads.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   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 Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "pthreadP.h"
>> +
>> +__uint64_t
>> +pthread_thread_number_np (pthread_t threadid)
>> +{
>> +  struct pthread *pd = (struct pthread *) threadid;
>> +  return pd->number;
>> +}
>> diff --git a/nptl/tst-thread_number-multi-static.c b/nptl/tst-thread_number-multi-static.c
>> new file mode 100644
>> index 0000000000..658928cfd5
>> --- /dev/null
>> +++ b/nptl/tst-thread_number-multi-static.c
>> @@ -0,0 +1,19 @@
>> +/* Test unique numbers for threads, static multi-threaded version.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   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 Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "tst-thread_number-multi.c"
>> diff --git a/nptl/tst-thread_number-multi.c b/nptl/tst-thread_number-multi.c
>> new file mode 100644
>> index 0000000000..e26f19e44a
>> --- /dev/null
>> +++ b/nptl/tst-thread_number-multi.c
>> @@ -0,0 +1,99 @@
>> +/* Test unique numbers for threads, non-static multi-threaded version.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   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 Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +#include <pthread.h>
>> +#include <stdbool.h>
>> +#include <stdint.h>
>> +#include <stdlib.h>
>> +#include <support/check.h>
>> +#include <support/namespace.h>
>> +#include <support/xthread.h>
>> +
>> +static void
>> +subprocess (void *closure)
>> +{
>> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
>> +}
>> +
>> +static void *
>> +subthread (void *closure)
>> +{
>> +  if (closure != NULL)
>> +    xpthread_barrier_wait (closure);
>> +  return NULL;
>> +}
>> +
>> +static int
>> +compare (const void *pleft, const void *pright)
>> +{
>> +  uint64_t left = *(const uint64_t *)pleft;
>> +  uint64_t right = *(const uint64_t *)pright;
>> +  if (left < right)
>> +    return -1;
>> +  if (left > right)
>> +    return 1;
>> +  return 0;
>> +}
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
>> +  support_isolate_in_subprocess (subprocess, NULL);
>> +
>> +  /* Create thread_count threads, half of which are joined
>> +     immediately, have of which stay arround.  */
>> +  enum { thread_count = 10 };
>> +  pthread_barrier_t barrier;
>> +  xpthread_barrier_init (&barrier, NULL, thread_count / 2 + 1);
>> +  uint64_t ids[thread_count];
>> +  pthread_t threads[thread_count]; /* Only even-numbered entries are valid.  */
>> +  for (int i = 0; i < thread_count; ++i)
>> +    {
>> +      bool stay_around = (i % 2) == 0;
>> +      threads[i] = xpthread_create (NULL, subthread,
>> +                                    stay_around ? &barrier : NULL);
>> +      ids[i] = pthread_thread_number_np (threads[i]);
>> +      TEST_VERIFY (ids[i] != 1);
>> +      if (!stay_around)
>> +        xpthread_join (threads[i]);
>> +    }
>> +
>> +  /* Check that the IDs are all distinct.  */
>> +  qsort (ids, thread_count, sizeof (ids[0]), compare);
>> +  for (int i = 1; i < thread_count; ++i)
>> +    TEST_VERIFY (ids[i - 1] < ids[i]);
>> +
>> +  /* Main thread ID should remain at 1.  */
>> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
>> +  support_isolate_in_subprocess (subprocess, NULL);
>> +
>> +  /* Clean up.  */
>> +  xpthread_barrier_wait (&barrier);
>> +  for (int i = 0; i < thread_count; ++i)
>> +    if ((i % 2) == 0)
>> +      xpthread_join (threads[i]);
>> +
>> +  /* Main thread ID should still remain at 1.  */
>> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
>> +  support_isolate_in_subprocess (subprocess, NULL);
>> +
>> +  return 0;
>> +}
>> +
>> +#include <support/test-driver.c>
>> diff --git a/nptl/tst-thread_number-single-static.c b/nptl/tst-thread_number-single-static.c
>> new file mode 100644
>> index 0000000000..5c21063c36
>> --- /dev/null
>> +++ b/nptl/tst-thread_number-single-static.c
>> @@ -0,0 +1,19 @@
>> +/* Test unique numbers for threads, static single-threaded version.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   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 Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "tst-thread_number-single.c"
>> diff --git a/nptl/tst-thread_number-single.c b/nptl/tst-thread_number-single.c
>> new file mode 100644
>> index 0000000000..43497205c7
>> --- /dev/null
>> +++ b/nptl/tst-thread_number-single.c
>> @@ -0,0 +1,38 @@
>> +/* Test unique numbers for threads, non-static single-threaded version.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   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 Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +#include <pthread.h>
>> +#include <support/check.h>
>> +#include <support/namespace.h>
>> +
>> +static void
>> +subprocess (void *closure)
>> +{
>> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
>> +}
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
>> +  support_isolate_in_subprocess (subprocess, NULL);
>> +
>> +  return 0;
>> +}
>> +
>> +#include <support/test-driver.c>
>> diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
>> index 7a65dc641c..99f2e58875 100644
>> --- a/sysdeps/generic/ldsodefs.h
>> +++ b/sysdeps/generic/ldsodefs.h
>> @@ -1056,6 +1056,10 @@ void __libc_setup_tls (void);
>>  void __pthread_initialize_minimal (void) weak_function;
>>  #endif
>>
>> +/* Initialize the already-existing TCB for the main thread.  Called
>> +   during dynamic linker startup or from __libc_setup_tls.  */
>> +void __dl_inittcb (void) attribute_hidden;
>> +
>>  /* Allocate memory for static TLS block (unless MEM is nonzero) and dtv.  */
>>  extern void *_dl_allocate_tls (void *mem);
>>  rtld_hidden_proto (_dl_allocate_tls)
>> diff --git a/sysdeps/nptl/dl-inittcb.c b/sysdeps/nptl/dl-inittcb.c
>> new file mode 100644
>> index 0000000000..c25424dfa6
>> --- /dev/null
>> +++ b/sysdeps/nptl/dl-inittcb.c
>> @@ -0,0 +1,27 @@
>> +/* Initialize TCB contents.  NPTL version.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   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 Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +#include <ldsodefs.h>
>> +#include <tls.h>
>> +
>> +void
>> +__dl_inittcb (void)
>> +{
>> +  /* The main thread has number 1.  */
>> +  THREAD_SELF->number = 1;
>> +}
>> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
>> index 2b2b386ab3..e0714ed951 100644
>> --- a/sysdeps/nptl/pthread.h
>> +++ b/sysdeps/nptl/pthread.h
>> @@ -1148,6 +1148,10 @@ extern int pthread_atfork (void (*__prepare) (void),
>>                            void (*__child) (void)) __THROW;
>>
>>
>> +/* Return a number uniquely identifying THREAD, even after its
>> +   termination.  */
>> +__uint64_t pthread_thread_number_np (pthread_t __thread_id) __THROW;
>> +
>>  #ifdef __USE_EXTERN_INLINES
>>  /* Optimizations.  */
>>  __extern_inline int
>> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> index ec0ead15dd..e206f77540 100644
>> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.17 GLIBC_2.17 A
>>  GLIBC_2.17 _Exit F
>>  GLIBC_2.17 _IO_2_1_stderr_ D 0xe0
>> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> index 5355769974..92429a8d78 100644
>> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
>> index 9bafe71b51..bcd54ecdf5 100644
>> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> index 90aa8d034f..84445a123e 100644
>> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> index 4d44c30c64..caa8dff010 100644
>> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
>> index 112fc57634..02301da334 100644
>> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> index 2e8b6a4586..a3fbcb831f 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> index 3c33400f67..203a63aa27 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
>> index e1b1a579d2..a3be97ef65 100644
>> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.18 GLIBC_2.18 A
>>  GLIBC_2.18 _Exit F
>>  GLIBC_2.18 _IO_2_1_stderr_ D 0x98
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> index c1550323f3..94de2ef489 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> index 3b3a172e4f..878bee4bb5 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> index 101ca7a241..94706fccb4 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> index 2d129f7170..adc3de5c88 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
>> index 8bc350aff8..f6198b3dbb 100644
>> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.21 GLIBC_2.21 A
>>  GLIBC_2.21 _Exit F
>>  GLIBC_2.21 _IO_2_1_stderr_ D 0x98
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> index 127c426e1c..363a3a2e10 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> index a9411318e2..dfa0463282 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
>> index d7bf5db601..37a34eb833 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.17 GLIBC_2.17 A
>>  GLIBC_2.17 _Exit F
>>  GLIBC_2.17 _IO_2_1_stderr_ D 0xe0
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
>> index a3415a72ac..a0dbaf366a 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> index 414338f9a2..a30b304817 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 GLIBC_2.0 A
>>  GLIBC_2.0 _IO_adjust_column F
>>  GLIBC_2.0 _IO_default_doallocate F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> index f0f7a69b64..a759aa9cf5 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
>> index 9f95aba898..133e0a55ef 100644
>> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> index 83fbdf2d7e..e525ed69d6 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.0 .div F
>>  GLIBC_2.0 .mul F
>>  GLIBC_2.0 .rem F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> index ee84ad10bc..d4fb34eceb 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> @@ -3,6 +3,8 @@ GCC_3.0 _Unwind_Find_FDE F
>>  GCC_3.0 __deregister_frame_info_bases F
>>  GCC_3.0 __register_frame_info_bases F
>>  GCC_3.0 __register_frame_info_table_bases F
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
>> index dcbfbc05ac..f598149374 100644
>> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.12 GLIBC_2.12 A
>>  GLIBC_2.12 _Exit F
>>  GLIBC_2.12 _IO_2_1_stderr_ D 0xa0
>> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
>> index 53dc99c45a..cb0054f532 100644
>> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.12 GLIBC_2.12 A
>>  GLIBC_2.12 _Exit F
>>  GLIBC_2.12 _IO_2_1_stderr_ D 0xe0
>> diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
>> index dcbfbc05ac..f598149374 100644
>> --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.12 GLIBC_2.12 A
>>  GLIBC_2.12 _Exit F
>>  GLIBC_2.12 _IO_2_1_stderr_ D 0xa0
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> index ae4dcaa47e..70a15fa003 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.10 GLIBC_2.10 A
>>  GLIBC_2.10 __cxa_at_quick_exit F
>>  GLIBC_2.10 __posix_getopt F
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> index 0dbda14796..afbdec65d5 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> @@ -1,3 +1,5 @@
>> +GLBIC_2.27 GLBIC_2.27 A
>> +GLBIC_2.27 pthread_thread_number_np F
>>  GLIBC_2.16 GLIBC_2.16 A
>>  GLIBC_2.16 _Exit F
>>  GLIBC_2.16 _IO_2_1_stderr_ D 0xa0<div id="DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2"><br />
> <table style="border-top: 1px solid #D3D4DE;">
>         <tr>
>         <td style="width: 55px; padding-top: 13px;"><a
> href="http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail"
> target="_blank"><img
> src="https://ipmcdn.avast.com/images/icons/icon-envelope-tick-green-avg-v1.png"
> alt="" width="46" height="29" style="width: 46px; height: 29px;"
> /></a></td>
>                 <td style="width: 470px; padding-top: 12px; color: #41424e;
> font-size: 13px; font-family: Arial, Helvetica, sans-serif;
> line-height: 18px;">Virus-free. <a
> href="http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail"
> target="_blank" style="color: #4453ea;">www.avg.com</a>
>                 </td>
>         </tr>
> </table><a href="#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2" width="1"
> height="1"></a></div>
  

Patch

diff --git a/csu/libc-tls.c b/csu/libc-tls.c
index 00138eb43a..af81cba12c 100644
--- a/csu/libc-tls.c
+++ b/csu/libc-tls.c
@@ -195,6 +195,7 @@  __libc_setup_tls (void)
 #endif
   if (__builtin_expect (lossage != NULL, 0))
     _startup_fatal (lossage);
+  __dl_inittcb ();
 
   /* Update the executable's link map with enough information to make
      the TLS routines happy.  */
diff --git a/elf/Makefile b/elf/Makefile
index 8563555079..66ce2953a4 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -30,7 +30,7 @@  routines	= $(all-dl-routines) dl-support dl-iteratephdr \
 # profiled libraries.
 dl-routines	= $(addprefix dl-,load lookup object reloc deps hwcaps \
 				  runtime init fini debug misc \
-				  version profile tls origin scope \
+				  version profile tls inittcb origin scope \
 				  execstack caller open close trampoline \
 				  exception sort-maps)
 ifeq (yes,$(use-ldconfig))
diff --git a/elf/dl-inittcb.c b/elf/dl-inittcb.c
new file mode 100644
index 0000000000..5a70e9775d
--- /dev/null
+++ b/elf/dl-inittcb.c
@@ -0,0 +1,22 @@ 
+/* Initialize TCB contents.  Generic version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+void
+__dl_inittcb (void)
+{
+}
diff --git a/elf/rtld.c b/elf/rtld.c
index cfd3729b8e..214e2312fa 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -740,6 +740,7 @@  cannot allocate TLS data structures for initial thread\n");
   const char *lossage = TLS_INIT_TP (tcbp);
   if (__glibc_unlikely (lossage != NULL))
     _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
+  __dl_inittcb ();
   tls_init_tp_called = true;
 
   return tcbp;
diff --git a/manual/threads.texi b/manual/threads.texi
index 769d974d50..6c62ff3da0 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -80,6 +80,7 @@  the standard.
 @menu
 * Default Thread Attributes::             Setting default attributes for
 					  threads in a process.
+* Identifying Threads::                   Unique identifiers for threads.
 @end menu
 
 @node Default Thread Attributes
@@ -124,6 +125,29 @@  The system does not have sufficient memory.
 @end table
 @end deftypefun
 
+@node Identifying Threads
+@subsection Unique identifiers for threads
+
+@Theglibc{} provides a non-standard function to obtain a unique thread
+identifier.
+
+@deftypefun uint64_t pthread_thread_number_np (pthread_t @var{thread})
+@standards{GNU, pthread.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+
+This function returns a number that uniquely identifies @var{thread}
+among all past, current, and future running threads.  This number does
+not change during the life-time of the thread.  Once returned by this
+function, a number will not be reused after the thread terminates.
+
+The returned number is only unique with regards to the current process.
+It may be shared by subprocesses and other processes in the system.
+
+The initial (main) thread has number 1.  Thread numbers are not
+necessarily assigned in a consecutive fashion.  They bear no
+relationship to process IDs or thread IDs assigned by the kernel.
+@end deftypefun
+
 @c FIXME these are undocumented:
 @c pthread_atfork
 @c pthread_attr_destroy
diff --git a/nptl/Makefile b/nptl/Makefile
index ae388d1112..087fb6a8b5 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -30,7 +30,7 @@  install-lib-ldscripts := libpthread.so
 
 routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
 	   libc-cleanup libc_pthread_init libc_multiple_threads \
-	   register-atfork unregister-atfork pthread_self
+	   register-atfork unregister-atfork pthread_self thread_number
 shared-only-routines = forward
 
 # We need to provide certain routines for compatibility with existing
@@ -302,7 +302,8 @@  tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
 			    c89 gnu89 c99 gnu99 c11 gnu11) \
 	tst-bad-schedattr \
 	tst-thread_local1 tst-mutex-errorcheck tst-robust10 \
-	tst-robust-fork tst-create-detached tst-memstream
+	tst-robust-fork tst-create-detached tst-memstream \
+	tst-thread_number-single tst-thread_number-multi \
 
 tests-internal := tst-rwlock19 tst-rwlock20 \
 		  tst-sem11 tst-sem12 tst-sem13 \
@@ -318,7 +319,9 @@  test-srcs = tst-oddstacklimit
 test-xfail-tst-once5 = yes
 
 # Files which must not be linked with libpthread.
-tests-nolibpthread = tst-unload
+tests-nolibpthread = tst-unload \
+  tst-thread_number-single \
+  tst-thread_number-single-static \
 
 gen-as-const-headers = pthread-errnos.sym \
 		       unwindbuf.sym \
@@ -433,9 +436,13 @@  link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \
 tests-static += tst-locale1 tst-locale2 tst-stackguard1-static \
 		tst-cancel21-static tst-cancel24-static tst-cond8-static \
 		tst-mutex8-static tst-mutexpi8-static tst-sem11-static \
-		tst-sem12-static
+		tst-sem12-static tst-thread_number-single-static \
+		tst-thread_number-multi-static \
+
 tests += tst-cancel21-static tst-cancel24-static \
-	 tst-cond8-static
+  tst-cond8-static tst-thread_number-single-static \
+  tst-thread_number-multi-static \
+
 tests-internal += tst-sem11-static tst-sem12-static tst-stackguard1-static
 xtests-static += tst-setuid1-static
 
diff --git a/nptl/Versions b/nptl/Versions
index 0ae5def464..8b6c839408 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -28,6 +28,9 @@  libc {
     pthread_cond_wait; pthread_cond_signal;
     pthread_cond_broadcast; pthread_cond_timedwait;
   }
+  GLBIC_2.27 {
+    pthread_thread_number_np;
+  }
   GLIBC_PRIVATE {
     __libc_alloca_cutoff;
     # Internal libc interface to libpthread
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 1cc7893195..0e1cf3939e 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -413,16 +413,21 @@  allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
   assert (powerof2 (pagesize_m1 + 1));
   assert (TCB_ALIGNMENT >= STACK_ALIGN);
 
-  /* Get the stack size from the attribute if it is set.  Otherwise we
-     use the default we determined at start time.  */
-  if (attr->stacksize != 0)
-    size = attr->stacksize;
-  else
-    {
-      lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
+  uint64_t thread_number;
+  lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
+  {
+    /* Number 1 is reserved for the initial thread.  */
+    static uint64_t global_thread_number = 1;
+    thread_number = ++global_thread_number;
+
+    /* Get the stack size from the attribute if it is set.  Otherwise
+       we use the default we determined at start time.  */
+    if (attr->stacksize != 0)
+      size = attr->stacksize;
+    else
       size = __default_pthread_attr.stacksize;
-      lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
-    }
+  }
+  lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
 
   /* Get memory for the stack.  */
   if (__glibc_unlikely (attr->flags & ATTR_FLAG_STACKADDR))
@@ -758,6 +763,8 @@  allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 #endif
   pd->robust_head.list = &pd->robust_head;
 
+  pd->number = thread_number;
+
   /* We place the thread descriptor at the end of the stack.  */
   *pdp = pd;
 
diff --git a/nptl/descr.h b/nptl/descr.h
index c83b17b674..49e266139e 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -395,6 +395,9 @@  struct pthread
   /* Resolver state.  */
   struct __res_state res;
 
+  /* Unique number assigned to this thread.  */
+  uint64_t number;
+
   /* This member must be last.  */
   char end_padding[];
 
diff --git a/nptl/thread_number.c b/nptl/thread_number.c
new file mode 100644
index 0000000000..a9fdaa508b
--- /dev/null
+++ b/nptl/thread_number.c
@@ -0,0 +1,26 @@ 
+/* Unique numbers for threads.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "pthreadP.h"
+
+__uint64_t
+pthread_thread_number_np (pthread_t threadid)
+{
+  struct pthread *pd = (struct pthread *) threadid;
+  return pd->number;
+}
diff --git a/nptl/tst-thread_number-multi-static.c b/nptl/tst-thread_number-multi-static.c
new file mode 100644
index 0000000000..658928cfd5
--- /dev/null
+++ b/nptl/tst-thread_number-multi-static.c
@@ -0,0 +1,19 @@ 
+/* Test unique numbers for threads, static multi-threaded version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "tst-thread_number-multi.c"
diff --git a/nptl/tst-thread_number-multi.c b/nptl/tst-thread_number-multi.c
new file mode 100644
index 0000000000..e26f19e44a
--- /dev/null
+++ b/nptl/tst-thread_number-multi.c
@@ -0,0 +1,99 @@ 
+/* Test unique numbers for threads, non-static multi-threaded version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/xthread.h>
+
+static void
+subprocess (void *closure)
+{
+  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
+}
+
+static void *
+subthread (void *closure)
+{
+  if (closure != NULL)
+    xpthread_barrier_wait (closure);
+  return NULL;
+}
+
+static int
+compare (const void *pleft, const void *pright)
+{
+  uint64_t left = *(const uint64_t *)pleft;
+  uint64_t right = *(const uint64_t *)pright;
+  if (left < right)
+    return -1;
+  if (left > right)
+    return 1;
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
+  support_isolate_in_subprocess (subprocess, NULL);
+
+  /* Create thread_count threads, half of which are joined
+     immediately, have of which stay arround.  */
+  enum { thread_count = 10 };
+  pthread_barrier_t barrier;
+  xpthread_barrier_init (&barrier, NULL, thread_count / 2 + 1);
+  uint64_t ids[thread_count];
+  pthread_t threads[thread_count]; /* Only even-numbered entries are valid.  */
+  for (int i = 0; i < thread_count; ++i)
+    {
+      bool stay_around = (i % 2) == 0;
+      threads[i] = xpthread_create (NULL, subthread,
+                                    stay_around ? &barrier : NULL);
+      ids[i] = pthread_thread_number_np (threads[i]);
+      TEST_VERIFY (ids[i] != 1);
+      if (!stay_around)
+        xpthread_join (threads[i]);
+    }
+
+  /* Check that the IDs are all distinct.  */
+  qsort (ids, thread_count, sizeof (ids[0]), compare);
+  for (int i = 1; i < thread_count; ++i)
+    TEST_VERIFY (ids[i - 1] < ids[i]);
+
+  /* Main thread ID should remain at 1.  */
+  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
+  support_isolate_in_subprocess (subprocess, NULL);
+
+  /* Clean up.  */
+  xpthread_barrier_wait (&barrier);
+  for (int i = 0; i < thread_count; ++i)
+    if ((i % 2) == 0)
+      xpthread_join (threads[i]);
+
+  /* Main thread ID should still remain at 1.  */
+  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
+  support_isolate_in_subprocess (subprocess, NULL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nptl/tst-thread_number-single-static.c b/nptl/tst-thread_number-single-static.c
new file mode 100644
index 0000000000..5c21063c36
--- /dev/null
+++ b/nptl/tst-thread_number-single-static.c
@@ -0,0 +1,19 @@ 
+/* Test unique numbers for threads, static single-threaded version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "tst-thread_number-single.c"
diff --git a/nptl/tst-thread_number-single.c b/nptl/tst-thread_number-single.c
new file mode 100644
index 0000000000..43497205c7
--- /dev/null
+++ b/nptl/tst-thread_number-single.c
@@ -0,0 +1,38 @@ 
+/* Test unique numbers for threads, non-static single-threaded version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+#include <support/check.h>
+#include <support/namespace.h>
+
+static void
+subprocess (void *closure)
+{
+  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
+}
+
+static int
+do_test (void)
+{
+  TEST_COMPARE (pthread_thread_number_np (pthread_self ()), 1U);
+  support_isolate_in_subprocess (subprocess, NULL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 7a65dc641c..99f2e58875 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1056,6 +1056,10 @@  void __libc_setup_tls (void);
 void __pthread_initialize_minimal (void) weak_function;
 #endif
 
+/* Initialize the already-existing TCB for the main thread.  Called
+   during dynamic linker startup or from __libc_setup_tls.  */
+void __dl_inittcb (void) attribute_hidden;
+
 /* Allocate memory for static TLS block (unless MEM is nonzero) and dtv.  */
 extern void *_dl_allocate_tls (void *mem);
 rtld_hidden_proto (_dl_allocate_tls)
diff --git a/sysdeps/nptl/dl-inittcb.c b/sysdeps/nptl/dl-inittcb.c
new file mode 100644
index 0000000000..c25424dfa6
--- /dev/null
+++ b/sysdeps/nptl/dl-inittcb.c
@@ -0,0 +1,27 @@ 
+/* Initialize TCB contents.  NPTL version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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 Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+
+void
+__dl_inittcb (void)
+{
+  /* The main thread has number 1.  */
+  THREAD_SELF->number = 1;
+}
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index 2b2b386ab3..e0714ed951 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -1148,6 +1148,10 @@  extern int pthread_atfork (void (*__prepare) (void),
 			   void (*__child) (void)) __THROW;
 
 
+/* Return a number uniquely identifying THREAD, even after its
+   termination.  */
+__uint64_t pthread_thread_number_np (pthread_t __thread_id) __THROW;
+
 #ifdef __USE_EXTERN_INLINES
 /* Optimizations.  */
 __extern_inline int
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index ec0ead15dd..e206f77540 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.17 GLIBC_2.17 A
 GLIBC_2.17 _Exit F
 GLIBC_2.17 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 5355769974..92429a8d78 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index 9bafe71b51..bcd54ecdf5 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 90aa8d034f..84445a123e 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 4d44c30c64..caa8dff010 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 112fc57634..02301da334 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 2e8b6a4586..a3fbcb831f 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 3c33400f67..203a63aa27 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index e1b1a579d2..a3be97ef65 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.18 GLIBC_2.18 A
 GLIBC_2.18 _Exit F
 GLIBC_2.18 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index c1550323f3..94de2ef489 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 3b3a172e4f..878bee4bb5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 101ca7a241..94706fccb4 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 2d129f7170..adc3de5c88 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 8bc350aff8..f6198b3dbb 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.21 GLIBC_2.21 A
 GLIBC_2.21 _Exit F
 GLIBC_2.21 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 127c426e1c..363a3a2e10 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index a9411318e2..dfa0463282 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index d7bf5db601..37a34eb833 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.17 GLIBC_2.17 A
 GLIBC_2.17 _Exit F
 GLIBC_2.17 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index a3415a72ac..a0dbaf366a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 414338f9a2..a30b304817 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 GLIBC_2.0 A
 GLIBC_2.0 _IO_adjust_column F
 GLIBC_2.0 _IO_default_doallocate F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index f0f7a69b64..a759aa9cf5 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 9f95aba898..133e0a55ef 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 83fbdf2d7e..e525ed69d6 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.0 .div F
 GLIBC_2.0 .mul F
 GLIBC_2.0 .rem F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index ee84ad10bc..d4fb34eceb 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -3,6 +3,8 @@  GCC_3.0 _Unwind_Find_FDE F
 GCC_3.0 __deregister_frame_info_bases F
 GCC_3.0 __register_frame_info_bases F
 GCC_3.0 __register_frame_info_table_bases F
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index dcbfbc05ac..f598149374 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.12 GLIBC_2.12 A
 GLIBC_2.12 _Exit F
 GLIBC_2.12 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 53dc99c45a..cb0054f532 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.12 GLIBC_2.12 A
 GLIBC_2.12 _Exit F
 GLIBC_2.12 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index dcbfbc05ac..f598149374 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.12 GLIBC_2.12 A
 GLIBC_2.12 _Exit F
 GLIBC_2.12 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index ae4dcaa47e..70a15fa003 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.10 GLIBC_2.10 A
 GLIBC_2.10 __cxa_at_quick_exit F
 GLIBC_2.10 __posix_getopt F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 0dbda14796..afbdec65d5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -1,3 +1,5 @@ 
+GLBIC_2.27 GLBIC_2.27 A
+GLBIC_2.27 pthread_thread_number_np F
 GLIBC_2.16 GLIBC_2.16 A
 GLIBC_2.16 _Exit F
 GLIBC_2.16 _IO_2_1_stderr_ D 0xa0