diff options
author | Florian Weimer <fweimer@redhat.com> | 2020-06-02 10:33:30 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2020-06-02 11:54:58 +0200 |
commit | 7538d461134bf306e31b40e4032f0c225bb40d51 (patch) | |
tree | 34c4ceb7c6565864dfc62d8e23dd8f37e24944af | |
parent | 6993670b52daa413717e840dfb17b5322e7f4a88 (diff) | |
download | glibc-7538d461134bf306e31b40e4032f0c225bb40d51.zip glibc-7538d461134bf306e31b40e4032f0c225bb40d51.tar.gz glibc-7538d461134bf306e31b40e4032f0c225bb40d51.tar.bz2 |
nptl: Make pthread_attr_t dynamically extensible
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>
-rw-r--r-- | nptl/Makefile | 1 | ||||
-rw-r--r-- | nptl/pthreadP.h | 6 | ||||
-rw-r--r-- | nptl/pthread_attr_copy.c | 16 | ||||
-rw-r--r-- | nptl/pthread_attr_destroy.c | 12 | ||||
-rw-r--r-- | nptl/pthread_attr_extension.c | 32 | ||||
-rw-r--r-- | nptl/pthread_attr_getaffinity.c | 14 | ||||
-rw-r--r-- | nptl/pthread_attr_setaffinity.c | 23 | ||||
-rw-r--r-- | nptl/pthread_create.c | 2 | ||||
-rw-r--r-- | sysdeps/nptl/internaltypes.h | 16 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/createthread.c | 9 |
10 files changed, 98 insertions, 33 deletions
diff --git a/nptl/Makefile b/nptl/Makefile index ae40002..7f8a80a 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -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 \ diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index ed30b72..7b31535 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -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 diff --git a/nptl/pthread_attr_copy.c b/nptl/pthread_attr_copy.c index 77a1a43..eb29557 100644 --- a/nptl/pthread_attr_copy.c +++ b/nptl/pthread_attr_copy.c @@ -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) { diff --git a/nptl/pthread_attr_destroy.c b/nptl/pthread_attr_destroy.c index 21f8026..b6a3cca 100644 --- a/nptl/pthread_attr_destroy.c +++ b/nptl/pthread_attr_destroy.c @@ -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 index 0000000..3b12808 --- /dev/null +++ b/nptl/pthread_attr_extension.c @@ -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; +} diff --git a/nptl/pthread_attr_getaffinity.c b/nptl/pthread_attr_getaffinity.c index 212c1f7..9483f69 100644 --- a/nptl/pthread_attr_getaffinity.c +++ b/nptl/pthread_attr_getaffinity.c @@ -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. */ diff --git a/nptl/pthread_attr_setaffinity.c b/nptl/pthread_attr_setaffinity.c index a42ffd9..9f9a70d 100644 --- a/nptl/pthread_attr_setaffinity.c +++ b/nptl/pthread_attr_setaffinity.c @@ -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; diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index 86fbeb5..f6418eb 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -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; diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h index 6d06a76..ca57c31 100644 --- a/sysdeps/nptl/internaltypes.h +++ b/sysdeps/nptl/internaltypes.h @@ -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 { diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c index 21f9d24..6588893 100644 --- a/sysdeps/unix/sysv/linux/createthread.c +++ b/sysdeps/unix/sysv/linux/createthread.c @@ -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: |