This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] Add getcpu
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: "Carlos O'Donell" <carlos at redhat dot com>
- Cc: GNU C Library <libc-alpha at sourceware dot org>
- Date: Wed, 5 Dec 2018 09:41:52 -0800
- Subject: [PATCH] Add getcpu
- References: <CAMe9rOpcy16tREX8Gb0qYPXXc__Vzykj2c=M20aBOn4p0gUBGw@mail.gmail.com> <a8efebb5-fa4b-d124-a635-c91f5d05e92f@redhat.com>
On Wed, Dec 5, 2018 at 9:33 AM Carlos O'Donell <carlos@redhat.com> wrote:
>
> On 12/5/18 9:29 AM, H.J. Lu wrote:
> > To optimize for multi-node NUMA system, I need a very fast way to identity which
> > node the current process is running on. getcpu:
> >
> > NAME
> > getcpu - determine CPU and NUMA node on which the calling thread is
> > running
> >
> > SYNOPSIS
> > #include <linux/getcpu.h>
> >
> > int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
> >
> > Note: There is no glibc wrapper for this system call; see NOTES.
> >
> > DESCRIPTION
> > The getcpu() system call identifies the processor and node on which the
> > calling thread or process is currently running and writes them into the
> > integers pointed to by the cpu and node arguments. The processor is a
> > unique small integer identifying a CPU. The node is a unique small
> > identifier identifying a NUMA node. When either cpu or node is NULL
> > nothing is written to the respective pointer.
> >
> > returns such info. But syscall () is too slow. I'd like to add a wrapper to
> > glibc. Any comments?
>
> I don't object to adding syscall wrappers, but your comment appears to indicate
> that the glibc wrapper will be doing something more than just wrapping, what
> do you have in mind?
I am enclosing a patch to add getcpu. Testing on x86-64, x32 and i686
are done. I am running build-many-glibcs.py as we speak.
> On some architectures we might have vdso support for this, while on others it
> will be a syscall. What's wrong with just using the fastest mechanism possible
> and that's it?
>
> I see that on x86 you have a vdso vgetcpu, and that lsl is one instruction and
> loads the cpunode mask and ccpunode bits in one shot (atomic). So this should
> work fine, but for all other callers I assume this will be a syscall.
I need vdso getcpu to avoid syscall. I am working on a NUMA spinlock
library which depends on a very fast getcpu.
--
H.J.
From 0ea35bc23578947c60ccc3388f697676ed9942d2 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 5 Dec 2018 08:36:46 -0800
Subject: [PATCH] Add getcpu
Add
#include <sched.h>
int getcpu (unsigned int *cpu, unsigned int *node);
to return currently used CPU and NUMA node.
Tested on x86-64, x32 and i686 as well as with build-many-glibcs.py.
* NEWS: Mention getcpu.
* include/sched.h (__getcpu): New libc_hidden_proto.
* sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Add
getcpu.
(tests): Add tst-affinity-getcpu.
(tests-static): Add tst-affinity-getcpu-static.
* sysdeps/unix/sysv/linux/Versions (GLIBC_2.29): Add getcpu.
* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Add getcpu.
* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist:
Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist:
Likewise.
* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/bits/sched.h (getcpu): New prototype.
* sysdeps/unix/sysv/linux/getcpu.c: New file.
* sysdeps/unix/sysv/linux/tst-affinity-getcpu-static.c: Likewise.
* sysdeps/unix/sysv/linux/tst-affinity-getcpu.c: Likewise.
---
NEWS | 3 +
include/sched.h | 2 +
sysdeps/unix/sysv/linux/Makefile | 6 +-
sysdeps/unix/sysv/linux/Versions | 3 +
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/libc.abilist | 1 +
sysdeps/unix/sysv/linux/bits/sched.h | 3 +
sysdeps/unix/sysv/linux/getcpu.c | 38 +++
sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 +
.../sysv/linux/m68k/coldfire/libc.abilist | 1 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
.../unix/sysv/linux/microblaze/libc.abilist | 1 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 +
.../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
.../powerpc/powerpc32/nofpu/libc.abilist | 1 +
.../linux/powerpc/powerpc64/libc-le.abilist | 1 +
.../sysv/linux/powerpc/powerpc64/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-32/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/libc.abilist | 1 +
.../sysv/linux/sparc/sparc32/libc.abilist | 1 +
.../sysv/linux/sparc/sparc64/libc.abilist | 1 +
.../sysv/linux/tst-affinity-getcpu-static.c | 1 +
sysdeps/unix/sysv/linux/tst-affinity-getcpu.c | 292 ++++++++++++++++++
.../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
34 files changed, 371 insertions(+), 3 deletions(-)
create mode 100644 sysdeps/unix/sysv/linux/getcpu.c
create mode 100644 sysdeps/unix/sysv/linux/tst-affinity-getcpu-static.c
create mode 100644 sysdeps/unix/sysv/linux/tst-affinity-getcpu.c
diff --git a/NEWS b/NEWS
index 8483dcf492..666416a268 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,9 @@ Version 2.29
Major new features:
+* The getcpu wrapper function has been added, which returns currently
+ used CPU and NUMA node.
+
* A new convenience target has been added for distribution maintainers
to build and install all locales as directories with files. The new
target is run by issuing the following command in your build tree:
diff --git a/include/sched.h b/include/sched.h
index b698f78666..2ba718d79c 100644
--- a/include/sched.h
+++ b/include/sched.h
@@ -26,5 +26,7 @@ libc_hidden_proto (__clone)
extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
size_t __child_stack_size, int __flags, void *__arg, ...);
libc_hidden_proto (__clone2)
+extern int __getcpu (unsigned *, unsigned *) __THROW;
+libc_hidden_proto (__getcpu)
#endif
#endif
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 362cf3b950..a8affeb7d3 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -142,11 +142,11 @@ endif
ifeq ($(subdir),posix)
sysdep_headers += bits/initspin.h
-sysdep_routines += sched_getcpu oldglob
+sysdep_routines += sched_getcpu oldglob getcpu
-tests += tst-affinity tst-affinity-pid
+tests += tst-affinity tst-affinity-pid tst-affinity-getcpu
-tests-static := tst-affinity-static
+tests-static := tst-affinity-static tst-affinity-getcpu-static
tests += $(tests-static)
CFLAGS-fork.c = $(libio-mtsafe)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index 336c13b57d..f1e12d9c69 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -171,6 +171,9 @@ libc {
mlock2;
pkey_alloc; pkey_free; pkey_set; pkey_get; pkey_mprotect;
}
+ GLIBC_2.29 {
+ getcpu;
+ }
GLIBC_PRIVATE {
# functions used in other libraries
__syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index e66c741d04..c2ca32e9d2 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2138,4 +2138,5 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 8df162fe99..a86ce442e7 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2033,6 +2033,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index 43c804f9dc..b10c07a51d 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -123,6 +123,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h
index 34f27a7d9b..ea5d51a80d 100644
--- a/sysdeps/unix/sysv/linux/bits/sched.h
+++ b/sysdeps/unix/sysv/linux/bits/sched.h
@@ -86,6 +86,9 @@ extern int unshare (int __flags) __THROW;
/* Get index of currently used CPU. */
extern int sched_getcpu (void) __THROW;
+/* Get currently used CPU and NUMA node. */
+extern int getcpu (unsigned int *, unsigned int *) __THROW;
+
/* Switch process to namespace of type NSTYPE indicated by FD. */
extern int setns (int __fd, int __nstype) __THROW;
#endif
diff --git a/sysdeps/unix/sysv/linux/getcpu.c b/sysdeps/unix/sysv/linux/getcpu.c
new file mode 100644
index 0000000000..5799424bdb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/getcpu.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2007-2018 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 <errno.h>
+#include <sched.h>
+#include <sysdep.h>
+
+#ifdef HAVE_GETCPU_VSYSCALL
+# define HAVE_VSYSCALL
+#endif
+#include <sysdep-vdso.h>
+
+int
+__getcpu (unsigned *cpu, unsigned *node)
+{
+#ifdef __NR_getcpu
+ return INLINE_VSYSCALL (getcpu, 3, cpu, node, NULL);
+#else
+ __set_errno (ENOSYS);
+ return -1;
+#endif
+}
+weak_alias (__getcpu, getcpu)
+libc_hidden_def (__getcpu)
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 88b01c2e75..3527d39971 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1880,6 +1880,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 6d02f31612..979aaae1db 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2045,6 +2045,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 4249712611..a4a90236f8 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1914,6 +1914,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index d47b808862..9f86f26730 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -124,6 +124,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index d5e38308be..558ba5fd4d 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1989,6 +1989,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 8596b84399..ca773e3d07 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2130,4 +2130,5 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 88e0f896d5..89c5c296d2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1967,6 +1967,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index aff7462c34..429624bc95 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1965,6 +1965,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 71d82444aa..fbe714e0bc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1973,6 +1973,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index de6c53d293..baa657f65b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1968,6 +1968,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index e724bab9fb..a2f407b92e 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2171,4 +2171,5 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index e9ecbccb71..1fd4fca8c8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1993,6 +1993,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index da83ea6028..cd3dcc0924 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1997,6 +1997,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 4535b40d15..54ddbb3f80 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2228,4 +2228,5 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 65725de4f0..5b9e494071 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -123,6 +123,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 _Exit F
GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index bbb3c4a8e7..36f5de94d5 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2100,4 +2100,5 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index e85ac2a178..b74e995d37 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2002,6 +2002,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index d56931022c..964ada9d33 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1908,6 +1908,7 @@ GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
GLIBC_2.29 __fentry__ F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index ff939a15c4..7c689af861 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1884,6 +1884,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 64fa9e10a5..e3cc7c1a2e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1996,6 +1996,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index db909d1506..a7dae1e16d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1937,6 +1937,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/tst-affinity-getcpu-static.c b/sysdeps/unix/sysv/linux/tst-affinity-getcpu-static.c
new file mode 100644
index 0000000000..bcfcca315a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-affinity-getcpu-static.c
@@ -0,0 +1 @@
+#include "tst-affinity-getcpu.c"
diff --git a/sysdeps/unix/sysv/linux/tst-affinity-getcpu.c b/sysdeps/unix/sysv/linux/tst-affinity-getcpu.c
new file mode 100644
index 0000000000..a617b6f455
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-affinity-getcpu.c
@@ -0,0 +1,292 @@
+/* Test case for CPU affinity functions with getcpu.
+ Copyright (C) 2018 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 <errno.h>
+#include <limits.h>
+#include <sched.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+static int
+getaffinity (size_t size, cpu_set_t *set)
+{
+ return sched_getaffinity (0, size, set);
+}
+
+static int
+setaffinity (size_t size, const cpu_set_t *set)
+{
+ return sched_setaffinity (0, size, set);
+}
+
+/* CPU set configuration determined. */
+struct conf
+{
+ int set_size; /* in bits */
+ int last_cpu;
+};
+
+static int
+find_set_size (void)
+{
+ /* There is considerable controversy about how to determine the size
+ of the kernel CPU mask. The probing loop below is only intended
+ for testing purposes. */
+ for (int num_cpus = 64; num_cpus <= INT_MAX / 2; ++num_cpus)
+ {
+ cpu_set_t *set = CPU_ALLOC (num_cpus);
+ size_t size = CPU_ALLOC_SIZE (num_cpus);
+
+ if (set == NULL)
+ {
+ printf ("error: CPU_ALLOC (%d) failed\n", num_cpus);
+ return -1;
+ }
+ if (getaffinity (size, set) == 0)
+ {
+ CPU_FREE (set);
+ return num_cpus;
+ }
+ if (errno != EINVAL)
+ {
+ printf ("error: getaffinity for %d CPUs: %m\n", num_cpus);
+ CPU_FREE (set);
+ return -1;
+ }
+ CPU_FREE (set);
+ }
+ puts ("error: Cannot find maximum CPU number");
+ return -1;
+}
+
+static int
+find_last_cpu (const cpu_set_t *set, size_t size)
+{
+ /* We need to determine the set size with CPU_COUNT_S and the
+ cpus_found counter because there is no direct way to obtain the
+ actual CPU set size, in bits, from the value of
+ CPU_ALLOC_SIZE. */
+ size_t cpus_found = 0;
+ size_t total_cpus = CPU_COUNT_S (size, set);
+ int last_cpu = -1;
+
+ for (int cpu = 0; cpus_found < total_cpus; ++cpu)
+ {
+ if (CPU_ISSET_S (cpu, size, set))
+ {
+ last_cpu = cpu;
+ ++cpus_found;
+ }
+ }
+ return last_cpu;
+}
+
+static void
+setup_conf (struct conf *conf)
+{
+ *conf = (struct conf) {-1, -1};
+ conf->set_size = find_set_size ();
+ if (conf->set_size > 0)
+ {
+ cpu_set_t *set = CPU_ALLOC (conf->set_size);
+
+ if (set == NULL)
+ {
+ printf ("error: CPU_ALLOC (%d) failed\n", conf->set_size);
+ CPU_FREE (set);
+ return;
+ }
+ if (getaffinity (CPU_ALLOC_SIZE (conf->set_size), set) < 0)
+ {
+ printf ("error: getaffinity failed: %m\n");
+ CPU_FREE (set);
+ return;
+ }
+ conf->last_cpu = find_last_cpu (set, CPU_ALLOC_SIZE (conf->set_size));
+ if (conf->last_cpu < 0)
+ puts ("info: No test CPU found");
+ CPU_FREE (set);
+ }
+}
+
+static bool
+test_size (const struct conf *conf, size_t size)
+{
+ if (size < conf->set_size)
+ {
+ printf ("info: Test not run for CPU set size %zu\n", size);
+ return true;
+ }
+
+ cpu_set_t *initial_set = CPU_ALLOC (size);
+ cpu_set_t *set2 = CPU_ALLOC (size);
+ cpu_set_t *active_cpu_set = CPU_ALLOC (size);
+
+ if (initial_set == NULL || set2 == NULL || active_cpu_set == NULL)
+ {
+ printf ("error: size %zu: CPU_ALLOC failed\n", size);
+ return false;
+ }
+ size_t kernel_size = CPU_ALLOC_SIZE (size);
+
+ if (getaffinity (kernel_size, initial_set) < 0)
+ {
+ printf ("error: size %zu: getaffinity: %m\n", size);
+ return false;
+ }
+ if (setaffinity (kernel_size, initial_set) < 0)
+ {
+ printf ("error: size %zu: setaffinity: %m\n", size);
+ return true;
+ }
+
+ /* Use one-CPU set to test switching between CPUs. */
+ int last_active_cpu = -1;
+ for (int cpu = 0; cpu <= conf->last_cpu; ++cpu)
+ {
+ int active_cpu = sched_getcpu ();
+ unsigned int numa_cpu, numa_node;
+ if (getcpu (&numa_cpu, &numa_node))
+ {
+ printf ("error: getcpu: %m\n");
+ return true;
+ }
+ if ((unsigned int) active_cpu != numa_cpu)
+ {
+ printf ("error: Unexpected CPU %d, expected %d\n",
+ active_cpu, numa_cpu);
+ return true;
+ }
+ if (last_active_cpu >= 0 && last_active_cpu != active_cpu)
+ {
+ printf ("error: Unexpected CPU %d, expected %d\n",
+ active_cpu, last_active_cpu);
+ return false;
+ }
+
+ if (!CPU_ISSET_S (cpu, kernel_size, initial_set))
+ continue;
+ last_active_cpu = cpu;
+
+ CPU_ZERO_S (kernel_size, active_cpu_set);
+ CPU_SET_S (cpu, kernel_size, active_cpu_set);
+ if (setaffinity (kernel_size, active_cpu_set) < 0)
+ {
+ printf ("error: size %zu: setaffinity (%d): %m\n", size, cpu);
+ return false;
+ }
+ active_cpu = sched_getcpu ();
+ if (getcpu (&numa_cpu, &numa_node))
+ {
+ printf ("error: getcpu: %m\n");
+ return true;
+ }
+ if ((unsigned int) active_cpu != numa_cpu)
+ {
+ printf ("error: Unexpected CPU %d, expected %d\n",
+ active_cpu, numa_cpu);
+ return true;
+ }
+ if (active_cpu != cpu)
+ {
+ printf ("error: Unexpected CPU %d, expected %d\n", active_cpu, cpu);
+ return false;
+ }
+ if (getaffinity (kernel_size, set2) < 0)
+ {
+ printf ("error: size %zu: getaffinity (2): %m\n", size);
+ return false;
+ }
+ if (!CPU_EQUAL_S (kernel_size, active_cpu_set, set2))
+ {
+ printf ("error: size %zu: CPU sets do not match\n", size);
+ return false;
+ }
+ }
+
+ /* Test setting the all-ones set. */
+ for (int cpu = 0; cpu < size; ++cpu)
+ CPU_SET_S (cpu, kernel_size, set2);
+ if (setaffinity (kernel_size, set2) < 0)
+ {
+ printf ("error: size %zu: setaffinity (3): %m\n", size);
+ return false;
+ }
+
+ if (setaffinity (kernel_size, initial_set) < 0)
+ {
+ printf ("error: size %zu: setaffinity (4): %m\n", size);
+ return false;
+ }
+ if (getaffinity (kernel_size, set2) < 0)
+ {
+ printf ("error: size %zu: getaffinity (3): %m\n", size);
+ return false;
+ }
+ if (!CPU_EQUAL_S (kernel_size, initial_set, set2))
+ {
+ printf ("error: size %zu: CPU sets do not match (2)\n", size);
+ return false;
+ }
+
+ CPU_FREE (initial_set);
+ CPU_FREE (set2);
+ CPU_FREE (active_cpu_set);
+
+ return true;
+}
+
+static int
+do_test (void)
+{
+ {
+ cpu_set_t set;
+ if (getaffinity (sizeof (set), &set) < 0 && errno == ENOSYS)
+ {
+ puts ("warning: getaffinity not supported, test cannot run");
+ return 0;
+ }
+ if (sched_getcpu () < 0 && errno == ENOSYS)
+ {
+ puts ("warning: sched_getcpu not supported, test cannot run");
+ return 0;
+ }
+ }
+
+ struct conf conf;
+ setup_conf (&conf);
+ printf ("info: Detected CPU set size (in bits): %d\n", conf.set_size);
+ printf ("info: Maximum test CPU: %d\n", conf.last_cpu);
+ if (conf.set_size < 0 || conf.last_cpu < 0)
+ return 1;
+
+ bool error = false;
+ error |= !test_size (&conf, 1024);
+ error |= !test_size (&conf, conf.set_size);
+ error |= !test_size (&conf, 2);
+ error |= !test_size (&conf, 32);
+ error |= !test_size (&conf, 40);
+ error |= !test_size (&conf, 64);
+ error |= !test_size (&conf, 96);
+ error |= !test_size (&conf, 128);
+ error |= !test_size (&conf, 256);
+ error |= !test_size (&conf, 8192);
+ return error;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 3b175f104b..87b6b6d639 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1895,6 +1895,7 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 1b57710477..39a0009398 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2146,4 +2146,5 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 getcpu F
GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
--
2.19.2