Update.
authorUlrich Drepper <drepper@redhat.com>
Sun, 20 Jul 2003 08:56:05 +0000 (08:56 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 20 Jul 2003 08:56:05 +0000 (08:56 +0000)
2003-07-20  Ulrich Drepper  <drepper@redhat.com>

* Makefile (libpthread-routines): Add pthread_attr_getaffinity and
pthread_attr_setaffinity.
* Versions [libpthread] (GLIBC_2.3.3): Likewise.
* sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: New file.
* sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: New file.
* pthread_attr_destroy.c: Free cpuset element if allocated.
* pthread_create.c: Pass iattr as additional parameter to
create_thread.
* sysdeps/pthread/createthread.c: If attribute is provided and
a new thread is created with affinity set or scheduling parameters,
start thread with CLONE_STOPPED.
* sysdeps/pthread/pthread.h: Declare pthread_attr_getaffinity and
pthread_attr_setaffinity.
* sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add
cpuset element.

12 files changed:
nptl/ChangeLog
nptl/Makefile
nptl/Versions
nptl/pthread_attr_destroy.c
nptl/pthread_create.c
nptl/sysdeps/pthread/createthread.c
nptl/sysdeps/pthread/pthread.h
nptl/sysdeps/unix/sysv/linux/internaltypes.h
nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c [new file with mode: 0644]
nptl/tst-cancel-wrappers.sh
sysdeps/unix/sysv/linux/bits/sched.h

index 804968a..c2e5055 100644 (file)
@@ -1,3 +1,21 @@
+2003-07-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libpthread-routines): Add pthread_attr_getaffinity and
+       pthread_attr_setaffinity.
+       * Versions [libpthread] (GLIBC_2.3.3): Likewise.
+       * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: New file.
+       * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: New file.
+       * pthread_attr_destroy.c: Free cpuset element if allocated.
+       * pthread_create.c: Pass iattr as additional parameter to
+       create_thread.
+       * sysdeps/pthread/createthread.c: If attribute is provided and
+       a new thread is created with affinity set or scheduling parameters,
+       start thread with CLONE_STOPPED.
+       * sysdeps/pthread/pthread.h: Declare pthread_attr_getaffinity and
+       pthread_attr_setaffinity.
+       * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add
+       cpuset element.
+
 2003-07-15  Ulrich Drepper  <drepper@redhat.com>
 
        * tst-tcancel-wrappers.sh: lseek and llseek are not cancelation points.
index b562e66..4c7749e 100644 (file)
@@ -117,6 +117,7 @@ libpthread-routines = init events version \
                      herrno res pt-allocrtsig \
                      pthread_kill_other_threads \
                      pthread_getaffinity pthread_setaffinity \
+                     pthread_attr_getaffinity pthread_attr_setaffinity \
                      cleanup_routine
 
 libpthread-shared-only-routines = version pt-allocrtsig
index 0f98663..8eb863d 100644 (file)
@@ -220,6 +220,7 @@ libpthread {
 
     # New affinity interfaces.
     pthread_getaffinity_np; pthread_setaffinity_np;
+    pthread_attr_getaffinity_np; pthread_attr_setaffinity_np;
   }
 
   GLIBC_PRIVATE {
index fec0416..a04f5fe 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -28,16 +28,17 @@ int
 __pthread_attr_destroy (attr)
      pthread_attr_t *attr;
 {
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
   /* Enqueue the attributes to the list of all known variables.  */
   if (DEBUGGING_P)
     {
-      struct pthread_attr *iattr;
       struct pthread_attr *prevp = NULL;
       struct pthread_attr *runp;
 
-      assert (sizeof (*attr) >= sizeof (struct pthread_attr));
-      iattr = (struct pthread_attr *) attr;
-
       lll_lock (__attr_list_lock);
 
       runp = __attr_list;
@@ -62,6 +63,9 @@ __pthread_attr_destroy (attr)
        return EINVAL;
     }
 
+  /* The affinity CPU set might be allocated dynamically.  */
+  free (iattr->cpuset);
+
   return 0;
 }
 strong_alias (__pthread_attr_destroy, pthread_attr_destroy)
index 22024d5..7565826 100644 (file)
@@ -431,7 +431,7 @@ __pthread_create_2_1 (newthread, attr, start_routine, arg)
   *newthread = (pthread_t) pd;
 
   /* Start the thread.  */
-  err = create_thread (pd, STACK_VARIABLES_ARGS);
+  err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
   if (err != 0)
     {
       /* Something went wrong.  Free the resources.  */
index 7563a2b..4a02d1c 100644 (file)
 
 
 #define CLONE_SIGNAL           (CLONE_SIGHAND | CLONE_THREAD)
+/* XXX Remove when definition is common place.  */
+#ifndef CLONE_STOPPED
+# define CLONE_STOPPED 0x02000000
+#endif
 
 /* Unless otherwise specified, the thread "register" is going to be
    initialized with a pointer to the TCB.  */
@@ -48,72 +52,84 @@ int *__libc_multiple_threads_ptr attribute_hidden;
 
 
 static int
-create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
+do_clone (struct pthread *pd, struct pthread_attr *attr, int clone_flags,
+         int (*fct) (void *), STACK_VARIABLES_PARMS)
 {
 #ifdef PREPARE_CREATE
   PREPARE_CREATE;
 #endif
 
-#ifdef TLS_TCB_AT_TP
-  assert (pd->header.tcb != NULL);
-#endif
+  if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
+                 pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
+    /* Failed.  */
+    return errno;
 
-  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
+  /* Now we have the possibility to set scheduling parameters etc.  */
+  if (__builtin_expect ((clone_flags & CLONE_STOPPED) != 0, 0))
     {
-      /* The parent thread is supposed to report events.  Check whether
-        the TD_CREATE event is needed, too.  */
-      const int _idx = __td_eventword (TD_CREATE);
-      const uint32_t _mask = __td_eventmask (TD_CREATE);
+      INTERNAL_SYSCALL_DECL (err);
+      int res = 0;
 
-      if ((_mask & (__nptl_threads_events.event_bits[_idx]
-                   | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
+      /* Set the affinity mask if necessary.  */
+      if (attr->cpuset != NULL)
        {
-         /* We have to report the new thread.  Make sure the thread
-            does not run far by forcing it to get a lock.  We lock it
-            here too so that the new thread cannot continue until we
-            tell it to.  */
-         lll_lock (pd->lock);
+         res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
+                                 sizeof (cpu_set_t), attr->cpuset);
 
-         /* Create the thread.  */
-         if (ARCH_CLONE (start_thread_debug, STACK_VARIABLES_ARGS,
-                         CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
-                         CLONE_SETTLS | CLONE_PARENT_SETTID |
-                         CLONE_CHILD_CLEARTID | CLONE_DETACHED |
-                         CLONE_SYSVSEM | 0, pd, &pd->tid, TLS_VALUE,
-                         &pd->tid) == -1)
-           /* Failed.  */
-           return errno;
-
-         /* We now have for sure more than one thread.  The main
-            thread might not yet have the flag set.  No need to set
-            the global variable again if this is what we use.  */
-         THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
-
-         /* Now fill in the information about the new thread in
-            the newly created thread's data structure.  We cannot let
-            the new thread do this since we don't know whether it was
-            already scheduled when we send the event.  */
-         pd->eventbuf.eventnum = TD_CREATE;
-         pd->eventbuf.eventdata = pd;
-
-         /* Enqueue the descriptor.  */
-         do
-           pd->nextevent = __nptl_last_event;
-         while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, pd,
-                                                      pd->nextevent) != 0);
-
-         /* Now call the function which signals the event.  */
-         __nptl_create_event ();
-
-         /* And finally restart the new thread.  */
-         lll_unlock (pd->lock);
-
-         return 0;
+         if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+           goto err_out;
+       }
+
+      /* Set the scheduling parameters.  */
+      if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
+       {
+         res = INTERNAL_SYSCALL (sched_setparam, err, 2, pd->tid,
+                                 &pd->schedparam);
+
+         if (__builtin_expect (! INTERNAL_SYSCALL_ERROR_P (res, err), 1))
+           {
+             res = INTERNAL_SYSCALL (sched_setscheduler, err, 2, pd->tid,
+                                     &pd->schedpolicy);
+
+             if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+               goto err_out;
+           }
+       }
+
+      /* Now start the thread for real.  */
+      res = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCONT);
+
+      /* If something went wrong, kill the thread.  */
+      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+       {
+         /* The operation failed.  We have to kill the thread.  First
+             send it the cancellation signal.  */
+         INTERNAL_SYSCALL_DECL (err2);
+       err_out:
+         (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
+
+         /* Then wake it up so that the signal can be processed.  */
+         (void) INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCONT);
+
+         return INTERNAL_SYSCALL_ERRNO (res, err);
        }
     }
 
-#ifdef NEED_DL_SYSINFO
-  assert (THREAD_GETMEM (THREAD_SELF, header.sysinfo) == pd->header.sysinfo);
+  /* We now have for sure more than one thread.  The main thread might
+     not yet have the flag set.  No need to set the global variable
+     again if this is what we use.  */
+  THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
+
+  return 0;
+}
+
+
+static int
+create_thread (struct pthread *pd, struct pthread_attr *attr,
+              STACK_VARIABLES_PARMS)
+{
+#ifdef TLS_TCB_AT_TP
+  assert (pd->header.tcb != NULL);
 #endif
 
   /* We rely heavily on various flags the CLONE function understands:
@@ -147,18 +163,68 @@ create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
 
      The termination signal is chosen to be zero which means no signal
      is sent.  */
-  if (ARCH_CLONE (start_thread, STACK_VARIABLES_ARGS,
-                 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
-                 CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
-                 CLONE_DETACHED | CLONE_SYSVSEM | 0, pd, &pd->tid, TLS_VALUE,
-                 &pd->tid) == -1)
-    /* Failed.  */
-    return errno;
+  int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
+                    | CLONE_SETTLS | CLONE_PARENT_SETTID
+                    | CLONE_CHILD_CLEARTID | CLONE_DETACHED | CLONE_SYSVSEM
+                    | 0);
+
+  /* If the newly created threads has to be started stopped since we
+     have to set the scheduling parameters or set the affinity we set
+     the CLONE_STOPPED flag.  */
+  if (attr != NULL && (attr->cpuset != NULL
+                      || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
+    clone_flags |= CLONE_STOPPED;
 
-  /* We now have for sure more than one thread.  The main thread might
-     not yet have the flag set.  No need to set the global variable
-     again if this is what we use.  */
-  THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
+  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
+    {
+      /* The parent thread is supposed to report events.  Check whether
+        the TD_CREATE event is needed, too.  */
+      const int _idx = __td_eventword (TD_CREATE);
+      const uint32_t _mask = __td_eventmask (TD_CREATE);
 
-  return 0;
+      if ((_mask & (__nptl_threads_events.event_bits[_idx]
+                   | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
+       {
+         /* We have to report the new thread.  Make sure the thread
+            does not run far by forcing it to get a lock.  We lock it
+            here too so that the new thread cannot continue until we
+            tell it to.  */
+         lll_lock (pd->lock);
+
+         /* Create the thread.  */
+         int res = do_clone (pd, attr, clone_flags, start_thread_debug,
+                             STACK_VARIABLES_ARGS);
+         if (res == 0)
+           {
+             /* Now fill in the information about the new thread in
+                the newly created thread's data structure.  We cannot let
+                the new thread do this since we don't know whether it was
+                already scheduled when we send the event.  */
+             pd->eventbuf.eventnum = TD_CREATE;
+             pd->eventbuf.eventdata = pd;
+
+             /* Enqueue the descriptor.  */
+             do
+               pd->nextevent = __nptl_last_event;
+             while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
+                                                          pd, pd->nextevent)
+                    != 0);
+
+             /* Now call the function which signals the event.  */
+             __nptl_create_event ();
+
+             /* And finally restart the new thread.  */
+             lll_unlock (pd->lock);
+           }
+
+         return res;
+       }
+    }
+
+#ifdef NEED_DL_SYSINFO
+  assert (THREAD_GETMEM (THREAD_SELF, header.sysinfo) == pd->header.sysinfo);
+#endif
+
+  /* Actually create the thread.  */
+  return do_clone (pd, attr, clone_flags, start_thread, STACK_VARIABLES_ARGS);
 }
index 56d40e7..80409bc 100644 (file)
@@ -321,6 +321,17 @@ extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
 #endif
 
 #ifdef __USE_GNU
+/* Thread created with attribute ATTR will be limited to run only on
+   the processors represented in CPUSET.  */
+extern int pthread_attr_setaffinity_np (pthread_attr_t *__attr,
+                                       __const cpu_set_t *__cpuset) __THROW;
+
+/* Get bit set in CPUSET representing the processors threads created with
+   ATTR can run on.  */
+extern int pthread_attr_getaffinity_np (__const pthread_attr_t *__attr,
+                                       cpu_set_t *__cpuset) __THROW;
+
+
 /* Get thread attributes corresponding to the already running thread TH.  */
 extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW;
 #endif
@@ -359,7 +370,7 @@ extern int pthread_yield (void) __THROW;
 
 /* Limit specified thread TH to run only on the processors represented
    in CPUSET.  */
-extern int pthread_setaffinity_np (pthread_t __th, const cpu_set_t *__cpuset)
+extern int pthread_setaffinity_np (pthread_t __th, __const cpu_set_t *__cpuset)
      __THROW;
 
 /* Get bit set in CPUSET representing the processors TH can run on.  */
index 17d78e4..e2f7b04 100644 (file)
@@ -35,6 +35,8 @@ struct pthread_attr
   /* Stack handling.  */
   void *stackaddr;
   size_t stacksize;
+  /* Affinity map.  */
+  cpu_set_t *cpuset;
 
   /* Chain of all initialized attributes.  Keep this last since it is
      not always used.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c b/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c
new file mode 100644 (file)
index 0000000..e6c795b
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   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 <assert.h>
+#include <errno.h>
+#include <pthreadP.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/types.h>
+
+
+int
+pthread_attr_getaffinity_np (attr, cpuset)
+     const pthread_attr_t *attr;
+     cpu_set_t *cpuset;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  memcpy (cpuset, iattr->cpuset, sizeof (cpu_set_t));
+
+  return 0;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c b/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c
new file mode 100644 (file)
index 0000000..f25ccb2
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   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 <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthreadP.h>
+
+
+int
+pthread_attr_setaffinity_np (attr, cpuset)
+     pthread_attr_t *attr;
+     const cpu_set_t *cpuset;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  if (iattr->cpuset == NULL)
+    {
+      iattr->cpuset = (cpu_set_t *) malloc (sizeof (cpu_set_t));
+      if (iattr->cpuset == NULL)
+       return ENOMEM;
+    }
+
+  memcpy (iattr->cpuset, cpuset, sizeof (cpu_set_t));
+
+  return 0;
+}
index e2035c7..d6f16d1 100644 (file)
@@ -27,8 +27,6 @@ C["connect"]=1
 C["creat"]=1
 C["fcntl"]=1
 C["fsync"]=1
-C["llseek"]=1
-C["lseek"]=1
 C["msgrcv"]=1
 C["msgsnd"]=1
 C["msync"]=1
index b250752..4e963d1 100644 (file)
@@ -110,8 +110,8 @@ typedef struct
 # define __CPU_ZERO(cpusetp) \
   do {                                                                       \
     unsigned int __i;                                                        \
-    cpu_set *__arr = (cpusetp);                                                      \
-    for (__i = 0; __i < sizeof (cpu_set) / sizeof (__cpu_mask); ++__i)       \
+    cpu_set_t *__arr = (cpusetp);                                            \
+    for (__i = 0; __i < sizeof (cpu_set_t) / sizeof (__cpu_mask); ++__i)      \
       __arr->__bits[__i] = 0;                                                \
   } while (0)
 # define __CPU_SET(cpu, cpusetp) \