From 19dd090a0f68765db87990ef8eda9bf77bb29581 Mon Sep 17 00:00:00 2001 From: Henning Heinold Date: Sat, 4 Jun 2011 21:21:41 +0200 Subject: libc: flesh out linux scheduler functions Most stuff was taken from the eglibc. Signed-off-by: Henning Heinold Signed-off-by: Bernhard Reutner-Fischer --- include/sched.h | 52 +++++++++--- libc/sysdeps/linux/common/Makefile.in | 3 + libc/sysdeps/linux/common/bits/kernel-features.h | 5 +- libc/sysdeps/linux/common/bits/sched.h | 100 +++++++++++++++++++---- libc/sysdeps/linux/common/sched_cpucount.c | 60 ++++++++++++++ libc/sysdeps/linux/common/sched_getcpu.c | 24 ++++++ libc/sysdeps/linux/common/stubs.c | 8 ++ libc/sysdeps/linux/common/unshare.c | 15 ++++ libc/sysdeps/linux/x86_64/Makefile.arch | 7 ++ libc/sysdeps/linux/x86_64/sched_getcpu.S | 72 ++++++++++++++++ 10 files changed, 317 insertions(+), 29 deletions(-) create mode 100644 libc/sysdeps/linux/common/sched_cpucount.c create mode 100644 libc/sysdeps/linux/common/sched_getcpu.c create mode 100644 libc/sysdeps/linux/common/unshare.c create mode 100644 libc/sysdeps/linux/x86_64/sched_getcpu.S diff --git a/include/sched.h b/include/sched.h index 0d110c303..e265b84ab 100644 --- a/include/sched.h +++ b/include/sched.h @@ -1,5 +1,5 @@ /* Definitions for POSIX 1003.1b-1993 (aka POSIX.4) scheduling interface. - Copyright (C) 1996,1997,1999,2001-2003,2004 Free Software Foundation, Inc. + Copyright (C) 1996,1997,1999,2001-2004,2007 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 @@ -25,6 +25,9 @@ /* Get type definitions. */ #include +#define __need_size_t +#include + #define __need_timespec #include @@ -65,11 +68,42 @@ extern int sched_rr_get_interval (__pid_t __pid, struct timespec *__t) __THROW; #if defined __USE_GNU && defined __UCLIBC_LINUX_SPECIFIC__ /* Access macros for `cpu_set'. */ -#define CPU_SETSIZE __CPU_SETSIZE -#define CPU_SET(cpu, cpusetp) __CPU_SET (cpu, cpusetp) -#define CPU_CLR(cpu, cpusetp) __CPU_CLR (cpu, cpusetp) -#define CPU_ISSET(cpu, cpusetp) __CPU_ISSET (cpu, cpusetp) -#define CPU_ZERO(cpusetp) __CPU_ZERO (cpusetp) +# define CPU_SETSIZE __CPU_SETSIZE +# define CPU_SET(cpu, cpusetp) __CPU_SET_S (cpu, sizeof (cpu_set_t), cpusetp) +# define CPU_CLR(cpu, cpusetp) __CPU_CLR_S (cpu, sizeof (cpu_set_t), cpusetp) +# define CPU_ISSET(cpu, cpusetp) __CPU_ISSET_S (cpu, sizeof (cpu_set_t), \ + cpusetp) +# define CPU_ZERO(cpusetp) __CPU_ZERO_S (sizeof (cpu_set_t), cpusetp) +# define CPU_COUNT(cpusetp) __CPU_COUNT_S (sizeof (cpu_set_t), cpusetp) + +# define CPU_SET_S(cpu, setsize, cpusetp) __CPU_SET_S (cpu, setsize, cpusetp) +# define CPU_CLR_S(cpu, setsize, cpusetp) __CPU_CLR_S (cpu, setsize, cpusetp) +# define CPU_ISSET_S(cpu, setsize, cpusetp) __CPU_ISSET_S (cpu, setsize, \ + cpusetp) +# define CPU_ZERO_S(setsize, cpusetp) __CPU_ZERO_S (setsize, cpusetp) +# define CPU_COUNT_S(setsize, cpusetp) __CPU_COUNT_S (setsize, cpusetp) + +# define CPU_EQUAL(cpusetp1, cpusetp2) \ + __CPU_EQUAL_S (sizeof (cpu_set_t), cpusetp1, cpusetp2) +# define CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \ + __CPU_EQUAL_S (setsize, cpusetp1, cpusetp2) + +# define CPU_AND(destset, srcset1, srcset2) \ + __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, &) +# define CPU_OR(destset, srcset1, srcset2) \ + __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, |) +# define CPU_XOR(destset, srcset1, srcset2) \ + __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, ^) +# define CPU_AND_S(setsize, destset, srcset1, srcset2) \ + __CPU_OP_S (setsize, destset, srcset1, srcset2, &) +# define CPU_OR_S(setsize, destset, srcset1, srcset2) \ + __CPU_OP_S (setsize, destset, srcset1, srcset2, |) +# define CPU_XOR_S(setsize, destset, srcset1, srcset2) \ + __CPU_OP_S (setsize, destset, srcset1, srcset2, ^) + +# define CPU_ALLOC_SIZE(count) __CPU_ALLOC_SIZE (count) +# define CPU_ALLOC(count) __CPU_ALLOC (count) +# define CPU_FREE(cpuset) __CPU_FREE (cpuset) /* Set the CPU affinity for a task */ @@ -79,12 +113,6 @@ extern int sched_setaffinity (__pid_t __pid, size_t __cpusetsize, /* Get the CPU affinity for a task */ extern int sched_getaffinity (__pid_t __pid, size_t __cpusetsize, cpu_set_t *__cpuset) __THROW; - -extern int __clone (int (*__fn) (void *__arg), void *__child_stack, - int __flags, void *__arg, ...); -extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, - size_t __child_stack_size, int __flags, void *__arg, ...); - #endif __END_DECLS diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index 3d20672b8..3b5763c95 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -35,7 +35,9 @@ CSRC-$(UCLIBC_LINUX_SPECIFIC) += \ readahead.c \ reboot.c \ remap_file_pages.c \ + sched_cpucount.c \ sched_getaffinity.c \ + sched_getcpu.c \ sched_setaffinity.c \ sendfile.c \ setfsgid.c \ @@ -53,6 +55,7 @@ CSRC-$(UCLIBC_LINUX_SPECIFIC) += \ timerfd.c \ umount2.c \ umount.c \ + unshare.c \ uselib.c \ vhangup.c \ vmsplice.c diff --git a/libc/sysdeps/linux/common/bits/kernel-features.h b/libc/sysdeps/linux/common/bits/kernel-features.h index 6bf554457..5ea85d2ae 100644 --- a/libc/sysdeps/linux/common/bits/kernel-features.h +++ b/libc/sysdeps/linux/common/bits/kernel-features.h @@ -494,4 +494,7 @@ # define __ASSUME_PRIVATE_FUTEX 1 #endif - +/* getcpu is a syscall for x86-64 since 3.1. */ +#if defined __x86_64__ && __LINUX_KERNEL_VERSION >= 0x030100 +# define __ASSUME_GETCPU_SYSCALL 1 +#endif diff --git a/libc/sysdeps/linux/common/bits/sched.h b/libc/sysdeps/linux/common/bits/sched.h index b48a0c874..7d6273fe4 100644 --- a/libc/sysdeps/linux/common/bits/sched.h +++ b/libc/sysdeps/linux/common/bits/sched.h @@ -1,6 +1,7 @@ /* Definitions of constants and data structure for POSIX 1003.1b-1993 scheduling interface. - Copyright (C) 1996-1999,2001-2003,2005,2006 Free Software Foundation, Inc. + Copyright (C) 1996-1999,2001-2003,2005,2006,2007,2008 + 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 @@ -58,7 +59,13 @@ force CLONE_PTRACE on this clone. */ # define CLONE_CHILD_SETTID 0x01000000 /* Store TID in userlevel buffer in the child. */ -# define CLONE_STOPPED 0x02000000 /* Start in stopped state. */ +# define CLONE_STOPPED 0x02000000 /* Start in stopped state. */ +# define CLONE_NEWUTS 0x04000000 /* New utsname group. */ +# define CLONE_NEWIPC 0x08000000 /* New ipcs. */ +# define CLONE_NEWUSER 0x10000000 /* New user namespace. */ +# define CLONE_NEWPID 0x20000000 /* New pid namespace. */ +# define CLONE_NEWNET 0x40000000 /* New network namespace. */ +# define CLONE_IO 0x80000000 /* Clone I/O context. */ #endif /* The official definition. */ @@ -74,10 +81,11 @@ __BEGIN_DECLS extern int clone (int (*__fn) (void *__arg), void *__child_stack, int __flags, void *__arg, ...) __THROW; -#if 0 /* Unshare the specified resources. */ extern int unshare (int __flags) __THROW; -#endif + +/* Get index of currently used CPU. */ +extern int sched_getcpu (void) __THROW; #endif __END_DECLS @@ -102,7 +110,7 @@ struct __sched_param # define __CPU_SETSIZE 1024 # define __NCPUBITS (8 * sizeof (__cpu_mask)) -/* Type for array elements in 'cpu_set'. */ +/* Type for array elements in 'cpu_set_t'. */ typedef unsigned long int __cpu_mask; /* Basic access functions. */ @@ -116,17 +124,77 @@ typedef struct } cpu_set_t; /* Access functions for CPU masks. */ -# define __CPU_ZERO(cpusetp) \ +# define __CPU_ZERO_S(setsize, cpusetp) \ do { \ - unsigned int __i; \ - cpu_set_t *__arr = (cpusetp); \ - for (__i = 0; __i < sizeof (cpu_set_t) / sizeof (__cpu_mask); ++__i) \ - __arr->__bits[__i] = 0; \ + size_t __i; \ + size_t __imax = (setsize) / sizeof (__cpu_mask); \ + __cpu_mask *__bits = (cpusetp)->__bits; \ + for (__i = 0; __i < __imax; ++__i) \ + __bits[__i] = 0; \ } while (0) -# define __CPU_SET(cpu, cpusetp) \ - ((cpusetp)->__bits[__CPUELT (cpu)] |= __CPUMASK (cpu)) -# define __CPU_CLR(cpu, cpusetp) \ - ((cpusetp)->__bits[__CPUELT (cpu)] &= ~__CPUMASK (cpu)) -# define __CPU_ISSET(cpu, cpusetp) \ - (((cpusetp)->__bits[__CPUELT (cpu)] & __CPUMASK (cpu)) != 0) +# define __CPU_SET_S(cpu, setsize, cpusetp) \ + (__extension__ \ + ({ size_t __cpu = (cpu); \ + __cpu < 8 * (setsize) \ + ? (((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \ + |= __CPUMASK (__cpu)) \ + : 0; })) +# define __CPU_CLR_S(cpu, setsize, cpusetp) \ + (__extension__ \ + ({ size_t __cpu = (cpu); \ + __cpu < 8 * (setsize) \ + ? (((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \ + &= ~__CPUMASK (__cpu)) \ + : 0; })) +# define __CPU_ISSET_S(cpu, setsize, cpusetp) \ + (__extension__ \ + ({ size_t __cpu = (cpu); \ + __cpu < 8 * (setsize) \ + ? ((((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \ + & __CPUMASK (__cpu))) != 0 \ + : 0; })) + +# define __CPU_COUNT_S(setsize, cpusetp) \ + __sched_cpucount (setsize, cpusetp) + +# define __CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \ + (__extension__ \ + ({ __cpu_mask *__arr1 = (cpusetp1)->__bits; \ + __cpu_mask *__arr2 = (cpusetp2)->__bits; \ + size_t __imax = (setsize) / sizeof (__cpu_mask); \ + size_t __i; \ + for (__i = 0; __i < __imax; ++__i) \ + if (__arr1[__i] != __arr2[__i]) \ + break; \ + __i == __imax; })) + +# define __CPU_OP_S(setsize, destset, srcset1, srcset2, op) \ + (__extension__ \ + ({ cpu_set_t *__dest = (destset); \ + __cpu_mask *__arr1 = (srcset1)->__bits; \ + __cpu_mask *__arr2 = (srcset2)->__bits; \ + size_t __imax = (setsize) / sizeof (__cpu_mask); \ + size_t __i; \ + for (__i = 0; __i < __imax; ++__i) \ + ((__cpu_mask *) __dest->__bits)[__i] = __arr1[__i] op __arr2[__i]; \ + __dest; })) + +# define __CPU_ALLOC_SIZE(count) \ + ((((count) + __NCPUBITS - 1) / __NCPUBITS) * sizeof (__cpu_mask)) +# define __CPU_ALLOC(count) __sched_cpualloc (count) +# define __CPU_FREE(cpuset) __sched_cpufree (cpuset) + +__BEGIN_DECLS + +extern int __sched_cpucount (size_t __setsize, const cpu_set_t *__setp) + __THROW; +#if 0 /* in uClibc we use macros */ +extern cpu_set_t *__sched_cpualloc (size_t __count) __THROW __wur; +extern void __sched_cpufree (cpu_set_t *__set) __THROW; +#else +# define __sched_cpualloc(cnt) ((cpu_set_t *)malloc(__CPU_ALLOC_SIZE(cnt))) +# define __sched_cpufree(__set) free(__set) +#endif +__END_DECLS + #endif diff --git a/libc/sysdeps/linux/common/sched_cpucount.c b/libc/sysdeps/linux/common/sched_cpucount.c new file mode 100644 index 000000000..331c0b8df --- /dev/null +++ b/libc/sysdeps/linux/common/sched_cpucount.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2007 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + + +int +__sched_cpucount (size_t setsize, const cpu_set_t *setp) +{ + int s = 0; + const __cpu_mask *p = setp->__bits; + const __cpu_mask *end = &setp->__bits[setsize / sizeof (__cpu_mask)]; + + while (p < end) + { + __cpu_mask l = *p++; + +#ifdef POPCNT + s += POPCNT (l); +#else + if (l == 0) + continue; + +# if LONG_BIT > 32 + l = (l & 0x5555555555555555ul) + ((l >> 1) & 0x5555555555555555ul); + l = (l & 0x3333333333333333ul) + ((l >> 2) & 0x3333333333333333ul); + l = (l & 0x0f0f0f0f0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0f0f0f0f0ful); + l = (l & 0x00ff00ff00ff00fful) + ((l >> 8) & 0x00ff00ff00ff00fful); + l = (l & 0x0000ffff0000fffful) + ((l >> 16) & 0x0000ffff0000fffful); + l = (l & 0x00000000fffffffful) + ((l >> 32) & 0x00000000fffffffful); +# else + l = (l & 0x55555555ul) + ((l >> 1) & 0x55555555ul); + l = (l & 0x33333333ul) + ((l >> 2) & 0x33333333ul); + l = (l & 0x0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0ful); + l = (l & 0x00ff00fful) + ((l >> 8) & 0x00ff00fful); + l = (l & 0x0000fffful) + ((l >> 16) & 0x0000fffful); +# endif + + s += l; +#endif + } + + return s; +} diff --git a/libc/sysdeps/linux/common/sched_getcpu.c b/libc/sysdeps/linux/common/sched_getcpu.c new file mode 100644 index 000000000..bc858ba8e --- /dev/null +++ b/libc/sysdeps/linux/common/sched_getcpu.c @@ -0,0 +1,24 @@ +/* vi: set sw=4 ts=4: */ +/* + * sched_getcpu() for uClibc + * + * Copyright (C) 2011 Bernhard Reutner-Fischer + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include +#include +#include +#include + +#if defined __NR_getcpu +int +sched_getcpu (void) +{ + unsigned int cpu; + int r = INLINE_SYSCALL (getcpu, 3, &cpu, NULL, NULL); + + return r == -1 ? r : cpu; +} +#endif diff --git a/libc/sysdeps/linux/common/stubs.c b/libc/sysdeps/linux/common/stubs.c index 70addec0b..06356afa4 100644 --- a/libc/sysdeps/linux/common/stubs.c +++ b/libc/sysdeps/linux/common/stubs.c @@ -128,6 +128,10 @@ make_stub(fstatfs) make_stub(get_kernel_syms) #endif +#if !defined __NR_getcpu && defined __UCLIBC_LINUX_SPECIFIC__ && ((defined __x86_64__ && !defined __UCLIBC_HAS_TLS__) || !defined __x86_64__) +make_stub(sched_getcpu) +#endif + #if !defined __NR_getpeername && !defined __NR_socketcall && defined __UCLIBC_HAS_SOCKET__ make_stub(getpeername) #endif @@ -385,6 +389,10 @@ make_stub(umount) make_stub(umount2) #endif +#if !defined __NR_unshare && defined __UCLIBC_LINUX_SPECIFIC__ +make_stub(unshare) +#endif + #ifndef __NR_utimensat make_stub(futimens) make_stub(utimensat) diff --git a/libc/sysdeps/linux/common/unshare.c b/libc/sysdeps/linux/common/unshare.c new file mode 100644 index 000000000..624ca12e3 --- /dev/null +++ b/libc/sysdeps/linux/common/unshare.c @@ -0,0 +1,15 @@ +/* vi: set sw=4 ts=4: */ +/* + * unshare() for uClibc + * + * Copyright (C) 2011 Henning Heinold + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include +#include + +#if defined __NR_unshare +_syscall1(int, unshare, int, flags) +#endif diff --git a/libc/sysdeps/linux/x86_64/Makefile.arch b/libc/sysdeps/linux/x86_64/Makefile.arch index de7ce7285..0d14650ff 100644 --- a/libc/sysdeps/linux/x86_64/Makefile.arch +++ b/libc/sysdeps/linux/x86_64/Makefile.arch @@ -17,3 +17,10 @@ SSRC := \ ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) SSRC += vfork.S clone.S endif + +ifeq ($(UCLIBC_LINUX_SPECIFIC),y) +ARCH_OBJ_FILTEROUT = sched_getcpu.c +ifeq ($(UCLIBC_HAS_TLS),y) +SSRC += sched_getcpu.S +endif +endif diff --git a/libc/sysdeps/linux/x86_64/sched_getcpu.S b/libc/sysdeps/linux/x86_64/sched_getcpu.S new file mode 100644 index 000000000..592bcdbdf --- /dev/null +++ b/libc/sysdeps/linux/x86_64/sched_getcpu.S @@ -0,0 +1,72 @@ +/* Copyright (C) 2007, 2011 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#define _ERRNO_H 1 +#include +#include + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgetcpu 0xffffffffff600800 + + +ENTRY (sched_getcpu) + /* Align stack and create local variable for result. */ + sub $0x8, %rsp + cfi_adjust_cfa_offset(8) + + movq %rsp, %rdi + xorl %esi, %esi + movl $VGETCPU_CACHE_OFFSET, %edx + addq %fs:0, %rdx + +#ifdef SHARED + movq __vdso_getcpu(%rip), %rax + PTR_DEMANGLE (%rax) + callq *%rax +#else +# ifdef __NR_getcpu + movl $__NR_getcpu, %eax + syscall +# ifndef __ASSUME_GETCPU_SYSCALL + cmpq $-ENOSYS, %rax + jne 1f +# endif +# endif +# ifndef __ASSUME_GETCPU_SYSCALL + movq $VSYSCALL_ADDR_vgetcpu, %rax + callq *%rax +1: +# else +# ifndef __NR_getcpu +# error "cannot happen" +# endif +# endif +#endif + + cmpq $-4095, %rax + jae SYSCALL_ERROR_LABEL + + movl (%rsp), %eax + +L(pseudo_end): + add $0x8, %rsp + cfi_adjust_cfa_offset(-8) + ret +PSEUDO_END(sched_getcpu) -- cgit v1.2.3