]> sourceware.org Git - glibc.git/commitdiff
nptl: Make pthread_attr_t dynamically extensible
authorFlorian Weimer <fweimer@redhat.com>
Tue, 2 Jun 2020 08:33:30 +0000 (10:33 +0200)
committerFlorian Weimer <fweimer@redhat.com>
Tue, 2 Jun 2020 09:54:58 +0000 (11:54 +0200)
This introduces the function __pthread_attr_extension to allocate the
extension space, which is freed by pthread_attr_destroy.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
nptl/Makefile
nptl/pthreadP.h
nptl/pthread_attr_copy.c
nptl/pthread_attr_destroy.c
nptl/pthread_attr_extension.c [new file with mode: 0644]
nptl/pthread_attr_getaffinity.c
nptl/pthread_attr_setaffinity.c
nptl/pthread_create.c
sysdeps/nptl/internaltypes.h
sysdeps/unix/sysv/linux/createthread.c

index ae4000205f84e3cbb8dbc0d74ce33936db02777c..7f8a80a4d1be20d632df22036958c4905202cc3a 100644 (file)
@@ -41,6 +41,7 @@ routines = \
   pthread_atfork \
   pthread_attr_copy \
   pthread_attr_destroy \
+  pthread_attr_extension \
   pthread_attr_getdetachstate \
   pthread_attr_getinheritsched \
   pthread_attr_getschedparam \
index ed30b7292382b79581135da831fd50ba15c9bd68..7b3153594e52656bea00cbf130e1c5767f1db135 100644 (file)
@@ -578,6 +578,12 @@ extern void __shm_directory_freeres (void) attribute_hidden;
 
 extern void __wait_lookup_done (void) attribute_hidden;
 
+/* Allocates the extension space for ATTR.  Returns an error code on
+   memory allocation failure, zero on success.  If ATTR already has an
+   extension space, this function does nothing.  */
+int __pthread_attr_extension (struct pthread_attr *attr) attribute_hidden
+  __attribute_warn_unused_result__;
+
 #ifdef SHARED
 # define PTHREAD_STATIC_FN_REQUIRE(name)
 #else
index 77a1a43eeb80d9b132ca82afe71ec7e2f9ac7812..eb29557505b45c17b02fa40d21130f9f955e656a 100644 (file)
@@ -29,18 +29,20 @@ __pthread_attr_copy (pthread_attr_t *target, const pthread_attr_t *source)
   temp.external = *source;
 
   /* Force new allocation.  This function has full ownership of temp.  */
-  temp.internal.cpuset = NULL;
-  temp.internal.cpusetsize = 0;
+  temp.internal.extension = NULL;
 
   int ret = 0;
 
   struct pthread_attr *isource = (struct pthread_attr *) source;
 
-  /* Propagate affinity mask information.  */
-  if (isource->cpusetsize > 0)
-    ret = __pthread_attr_setaffinity_np (&temp.external,
-                                         isource->cpusetsize,
-                                         isource->cpuset);
+  if (isource->extension != NULL)
+    {
+      /* Propagate affinity mask information.  */
+      if (isource->extension->cpusetsize > 0)
+        ret = __pthread_attr_setaffinity_np (&temp.external,
+                                             isource->extension->cpusetsize,
+                                             isource->extension->cpuset);
+    }
 
   if (ret != 0)
     {
index 21f8026a2c09330d97760efbd6a95a78da1cbe04..b6a3cca657f630374025a7cab42a9cfec989e077 100644 (file)
@@ -30,12 +30,16 @@ __pthread_attr_destroy (pthread_attr_t *attr)
   iattr = (struct pthread_attr *) attr;
 
 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_1)
-  /* In old struct pthread_attr, neither next nor cpuset are
-     present.  */
+  /* In old struct pthread_attr, the extension member is missing.  */
   if (__builtin_expect ((iattr->flags & ATTR_FLAG_OLDATTR), 0) == 0)
 #endif
-    /* The affinity CPU set might be allocated dynamically.  */
-    free (iattr->cpuset);
+    {
+      if (iattr->extension != NULL)
+        {
+          free (iattr->extension->cpuset);
+          free (iattr->extension);
+        }
+    }
 
   return 0;
 }
diff --git a/nptl/pthread_attr_extension.c b/nptl/pthread_attr_extension.c
new file mode 100644 (file)
index 0000000..3b12808
--- /dev/null
@@ -0,0 +1,32 @@
+/* Allocate the extension space for struct pthread_attr.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+#include <stdlib.h>
+
+int
+ __pthread_attr_extension (struct pthread_attr *attr)
+{
+  if (attr->extension != NULL)
+    return 0;
+  attr->extension = calloc (sizeof (*attr->extension), 1);
+  if (attr->extension == NULL)
+    return errno;
+  return 0;
+}
index 212c1f7c0ab9968b00781abe8b3e23f571076043..9483f69ddc68b3683a90c27c88e000157f1611b2 100644 (file)
@@ -33,22 +33,22 @@ __pthread_attr_getaffinity_new (const pthread_attr_t *attr, size_t cpusetsize,
 
   iattr = (const struct pthread_attr *) attr;
 
-  if (iattr->cpuset != NULL)
+  if (iattr->extension != NULL && iattr->extension->cpuset != NULL)
     {
       /* Check whether there are any bits set beyond the limits
         the user requested.  */
-      for (size_t cnt = cpusetsize; cnt < iattr->cpusetsize; ++cnt)
-       if (((char *) iattr->cpuset)[cnt] != 0)
+      for (size_t cnt = cpusetsize; cnt < iattr->extension->cpusetsize; ++cnt)
+       if (((char *) iattr->extension->cpuset)[cnt] != 0)
          return EINVAL;
 
       /* Copy over the cpuset from the thread attribute object.  Limit the copy
         to the minimum of the source and destination sizes to prevent a buffer
         overrun.  If the destination is larger, fill the remaining space with
         zeroes.  */
-      void *p = mempcpy (cpuset, iattr->cpuset,
-                        MIN (iattr->cpusetsize, cpusetsize));
-      if (cpusetsize > iattr->cpusetsize)
-       memset (p, '\0', cpusetsize - iattr->cpusetsize);
+      void *p = mempcpy (cpuset, iattr->extension->cpuset,
+                        MIN (iattr->extension->cpusetsize, cpusetsize));
+      if (cpusetsize > iattr->extension->cpusetsize)
+       memset (p, '\0', cpusetsize - iattr->extension->cpusetsize);
     }
   else
     /* We have no information.  */
index a42ffd92f43f79476a9defb4ba4a661321e4f357..9f9a70dee069d051c9de9c9513b6300a5d18fb44 100644 (file)
@@ -34,23 +34,30 @@ __pthread_attr_setaffinity_np (pthread_attr_t *attr, size_t cpusetsize,
 
   if (cpuset == NULL || cpusetsize == 0)
     {
-      free (iattr->cpuset);
-      iattr->cpuset = NULL;
-      iattr->cpusetsize = 0;
+      if (iattr->extension != NULL)
+       {
+         free (iattr->extension->cpuset);
+         iattr->extension->cpuset = NULL;
+         iattr->extension->cpusetsize = 0;
+       }
     }
   else
     {
-      if (iattr->cpusetsize != cpusetsize)
+      int ret = __pthread_attr_extension (iattr);
+      if (ret != 0)
+       return ret;
+
+      if (iattr->extension->cpusetsize != cpusetsize)
        {
-         void *newp = (cpu_set_t *) realloc (iattr->cpuset, cpusetsize);
+         void *newp = realloc (iattr->extension->cpuset, cpusetsize);
          if (newp == NULL)
            return ENOMEM;
 
-         iattr->cpuset = newp;
-         iattr->cpusetsize = cpusetsize;
+         iattr->extension->cpuset = newp;
+         iattr->extension->cpusetsize = cpusetsize;
        }
 
-      memcpy (iattr->cpuset, cpuset, cpusetsize);
+      memcpy (iattr->extension->cpuset, cpuset, cpusetsize);
     }
 
   return 0;
index 86fbeb52184939b78471f6badee16e179592dc16..f6418eb5ed16b816a6f39cb789570e22f13efda9 100644 (file)
@@ -884,7 +884,7 @@ __pthread_create_2_0 (pthread_t *newthread, const pthread_attr_t *attr,
       new_attr.guardsize = ps;
       new_attr.stackaddr = NULL;
       new_attr.stacksize = 0;
-      new_attr.cpuset = NULL;
+      new_attr.extension = NULL;
 
       /* We will pass this value on to the real implementation.  */
       attr = (pthread_attr_t *) &new_attr;
index 6d06a76baf1ea533354e10d238f7a77a1b67a19d..ca57c315d484485d91ee9e792074728b0c659edb 100644 (file)
@@ -36,9 +36,10 @@ struct pthread_attr
   /* Stack handling.  */
   void *stackaddr;
   size_t stacksize;
-  /* Affinity map.  */
-  cpu_set_t *cpuset;
-  size_t cpusetsize;
+
+  /* Allocated via a call to __pthread_attr_extension once needed.  */
+  struct pthread_attr_extension *extension;
+  void *unused;
 };
 
 #define ATTR_FLAG_DETACHSTATE          0x0001
@@ -57,6 +58,15 @@ union pthread_attr_transparent
   struct pthread_attr internal;
 };
 
+/* Extension space for pthread attributes.  Referenced by the
+   extension member of struct pthread_attr.  */
+struct pthread_attr_extension
+{
+  /* Affinity map.  */
+  cpu_set_t *cpuset;
+  size_t cpusetsize;
+};
+
 /* Mutex attribute data structure.  */
 struct pthread_mutexattr
 {
index 21f9d24f2d2e89728883c35330043a2bc1a7648f..6588893ba5f54cec6cd4790554fc1fab84562820 100644 (file)
@@ -52,8 +52,10 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
   /* Determine whether the newly created threads has to be started
      stopped since we have to set the scheduling parameters or set the
      affinity.  */
+  bool need_setaffinity = (attr != NULL && attr->extension != NULL
+                          && attr->extension->cpuset != 0);
   if (attr != NULL
-      && (__glibc_unlikely (attr->cpuset != NULL)
+      && (__glibc_unlikely (need_setaffinity)
          || __glibc_unlikely ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)))
     *stopped_start = true;
 
@@ -113,12 +115,13 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
       int res;
 
       /* Set the affinity mask if necessary.  */
-      if (attr->cpuset != NULL)
+      if (need_setaffinity)
        {
          assert (*stopped_start);
 
          res = INTERNAL_SYSCALL_CALL (sched_setaffinity, pd->tid,
-                                      attr->cpusetsize, attr->cpuset);
+                                      attr->extension->cpusetsize,
+                                      attr->extension->cpuset);
 
          if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res)))
          err_out:
This page took 0.059024 seconds and 5 git commands to generate.