Browse Source

libc: flesh out linux scheduler functions

Most stuff was taken from the eglibc.

Signed-off-by: Henning Heinold <heinold@inf.fu-berlin.de>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Henning Heinold 13 years ago
parent
commit
19dd090a0f

+ 40 - 12
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 <bits/types.h>
 
+#define __need_size_t
+#include <stddef.h>
+
 #define __need_timespec
 #include <time.h>
 
@@ -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

+ 3 - 0
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

+ 4 - 1
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

+ 84 - 16
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

+ 60 - 0
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 <limits.h>
+#include <sched.h>
+
+
+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;
+}

+ 24 - 0
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 <uclibc@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sched.h>
+#include <sysdep.h>
+
+#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

+ 8 - 0
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)

+ 15 - 0
libc/sysdeps/linux/common/unshare.c

@@ -0,0 +1,15 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * unshare() for uClibc
+ *
+ * Copyright (C) 2011 Henning Heinold <heinold@inf.fu-berlin.de>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <sys/syscall.h>
+#include <sched.h>
+
+#if defined __NR_unshare
+_syscall1(int, unshare, int, flags)
+#endif

+ 7 - 0
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

+ 72 - 0
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 <sysdep.h>
+#include <tls.h>
+#define _ERRNO_H	1
+#include <bits/errno.h>
+#include <bits/kernel-features.h>
+
+/* 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)