Back to index

glibc  2.9
pthread_setaffinity.c
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <alloca.h>
00021 #include <errno.h>
00022 #include <pthreadP.h>
00023 #include <sysdep.h>
00024 #include <sys/types.h>
00025 #include <shlib-compat.h>
00026 
00027 
00028 size_t __kernel_cpumask_size attribute_hidden;
00029 
00030 
00031 /* Determine the current affinity.  As a side affect we learn
00032    about the size of the cpumask_t in the kernel.  */
00033 int
00034 __determine_cpumask_size (pid_t tid)
00035 {
00036   INTERNAL_SYSCALL_DECL (err);
00037   int res;
00038 
00039   size_t psize = 128;
00040   void *p = alloca (psize);
00041 
00042   while (res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, tid, psize, p),
00043         INTERNAL_SYSCALL_ERROR_P (res, err)
00044         && INTERNAL_SYSCALL_ERRNO (res, err) == EINVAL)
00045     p = extend_alloca (p, psize, 2 * psize);
00046 
00047   if (res == 0 || INTERNAL_SYSCALL_ERROR_P (res, err))
00048     return INTERNAL_SYSCALL_ERRNO (res, err);
00049 
00050   __kernel_cpumask_size = res;
00051 
00052   return 0;
00053 }
00054 
00055 
00056 int
00057 __pthread_setaffinity_new (pthread_t th, size_t cpusetsize,
00058                         const cpu_set_t *cpuset)
00059 {
00060   const struct pthread *pd = (const struct pthread *) th;
00061 
00062   INTERNAL_SYSCALL_DECL (err);
00063   int res;
00064 
00065   if (__builtin_expect (__kernel_cpumask_size == 0, 0))
00066     {
00067       res = __determine_cpumask_size (pd->tid);
00068       if (res != 0)
00069        return res;
00070     }
00071 
00072   /* We now know the size of the kernel cpumask_t.  Make sure the user
00073      does not request to set a bit beyond that.  */
00074   for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt)
00075     if (((char *) cpuset)[cnt] != '\0')
00076       /* Found a nonzero byte.  This means the user request cannot be
00077         fulfilled.  */
00078       return EINVAL;
00079 
00080   res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, cpusetsize,
00081                        cpuset);
00082 
00083 #ifdef RESET_VGETCPU_CACHE
00084   if (!INTERNAL_SYSCALL_ERROR_P (res, err))
00085     RESET_VGETCPU_CACHE ();
00086 #endif
00087 
00088   return (INTERNAL_SYSCALL_ERROR_P (res, err)
00089          ? INTERNAL_SYSCALL_ERRNO (res, err)
00090          : 0);
00091 }
00092 versioned_symbol (libpthread, __pthread_setaffinity_new,
00093                 pthread_setaffinity_np, GLIBC_2_3_4);
00094 
00095 
00096 #if SHLIB_COMPAT (libpthread, GLIBC_2_3_3, GLIBC_2_3_4)
00097 int
00098 __pthread_setaffinity_old (pthread_t th, cpu_set_t *cpuset)
00099 {
00100   /* The old interface by default assumed a 1024 processor bitmap.  */
00101   return __pthread_setaffinity_new (th, 128, cpuset);
00102 }
00103 compat_symbol (libpthread, __pthread_setaffinity_old, pthread_setaffinity_np,
00104               GLIBC_2_3_3);
00105 #endif