mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-27 03:33:33 +08:00
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>
This commit is contained in:
parent
6993670b52
commit
7538d46113
@ -41,6 +41,7 @@ routines = \
|
|||||||
pthread_atfork \
|
pthread_atfork \
|
||||||
pthread_attr_copy \
|
pthread_attr_copy \
|
||||||
pthread_attr_destroy \
|
pthread_attr_destroy \
|
||||||
|
pthread_attr_extension \
|
||||||
pthread_attr_getdetachstate \
|
pthread_attr_getdetachstate \
|
||||||
pthread_attr_getinheritsched \
|
pthread_attr_getinheritsched \
|
||||||
pthread_attr_getschedparam \
|
pthread_attr_getschedparam \
|
||||||
|
@ -578,6 +578,12 @@ extern void __shm_directory_freeres (void) attribute_hidden;
|
|||||||
|
|
||||||
extern void __wait_lookup_done (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
|
#ifdef SHARED
|
||||||
# define PTHREAD_STATIC_FN_REQUIRE(name)
|
# define PTHREAD_STATIC_FN_REQUIRE(name)
|
||||||
#else
|
#else
|
||||||
|
@ -29,18 +29,20 @@ __pthread_attr_copy (pthread_attr_t *target, const pthread_attr_t *source)
|
|||||||
temp.external = *source;
|
temp.external = *source;
|
||||||
|
|
||||||
/* Force new allocation. This function has full ownership of temp. */
|
/* Force new allocation. This function has full ownership of temp. */
|
||||||
temp.internal.cpuset = NULL;
|
temp.internal.extension = NULL;
|
||||||
temp.internal.cpusetsize = 0;
|
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
struct pthread_attr *isource = (struct pthread_attr *) source;
|
struct pthread_attr *isource = (struct pthread_attr *) source;
|
||||||
|
|
||||||
/* Propagate affinity mask information. */
|
if (isource->extension != NULL)
|
||||||
if (isource->cpusetsize > 0)
|
{
|
||||||
ret = __pthread_attr_setaffinity_np (&temp.external,
|
/* Propagate affinity mask information. */
|
||||||
isource->cpusetsize,
|
if (isource->extension->cpusetsize > 0)
|
||||||
isource->cpuset);
|
ret = __pthread_attr_setaffinity_np (&temp.external,
|
||||||
|
isource->extension->cpusetsize,
|
||||||
|
isource->extension->cpuset);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
|
@ -30,12 +30,16 @@ __pthread_attr_destroy (pthread_attr_t *attr)
|
|||||||
iattr = (struct pthread_attr *) attr;
|
iattr = (struct pthread_attr *) attr;
|
||||||
|
|
||||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_1)
|
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_1)
|
||||||
/* In old struct pthread_attr, neither next nor cpuset are
|
/* In old struct pthread_attr, the extension member is missing. */
|
||||||
present. */
|
|
||||||
if (__builtin_expect ((iattr->flags & ATTR_FLAG_OLDATTR), 0) == 0)
|
if (__builtin_expect ((iattr->flags & ATTR_FLAG_OLDATTR), 0) == 0)
|
||||||
#endif
|
#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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
32
nptl/pthread_attr_extension.c
Normal file
32
nptl/pthread_attr_extension.c
Normal file
@ -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;
|
||||||
|
}
|
@ -33,22 +33,22 @@ __pthread_attr_getaffinity_new (const pthread_attr_t *attr, size_t cpusetsize,
|
|||||||
|
|
||||||
iattr = (const struct pthread_attr *) attr;
|
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
|
/* Check whether there are any bits set beyond the limits
|
||||||
the user requested. */
|
the user requested. */
|
||||||
for (size_t cnt = cpusetsize; cnt < iattr->cpusetsize; ++cnt)
|
for (size_t cnt = cpusetsize; cnt < iattr->extension->cpusetsize; ++cnt)
|
||||||
if (((char *) iattr->cpuset)[cnt] != 0)
|
if (((char *) iattr->extension->cpuset)[cnt] != 0)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/* Copy over the cpuset from the thread attribute object. Limit the copy
|
/* 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
|
to the minimum of the source and destination sizes to prevent a buffer
|
||||||
overrun. If the destination is larger, fill the remaining space with
|
overrun. If the destination is larger, fill the remaining space with
|
||||||
zeroes. */
|
zeroes. */
|
||||||
void *p = mempcpy (cpuset, iattr->cpuset,
|
void *p = mempcpy (cpuset, iattr->extension->cpuset,
|
||||||
MIN (iattr->cpusetsize, cpusetsize));
|
MIN (iattr->extension->cpusetsize, cpusetsize));
|
||||||
if (cpusetsize > iattr->cpusetsize)
|
if (cpusetsize > iattr->extension->cpusetsize)
|
||||||
memset (p, '\0', cpusetsize - iattr->cpusetsize);
|
memset (p, '\0', cpusetsize - iattr->extension->cpusetsize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* We have no information. */
|
/* We have no information. */
|
||||||
|
@ -34,23 +34,30 @@ __pthread_attr_setaffinity_np (pthread_attr_t *attr, size_t cpusetsize,
|
|||||||
|
|
||||||
if (cpuset == NULL || cpusetsize == 0)
|
if (cpuset == NULL || cpusetsize == 0)
|
||||||
{
|
{
|
||||||
free (iattr->cpuset);
|
if (iattr->extension != NULL)
|
||||||
iattr->cpuset = NULL;
|
{
|
||||||
iattr->cpusetsize = 0;
|
free (iattr->extension->cpuset);
|
||||||
|
iattr->extension->cpuset = NULL;
|
||||||
|
iattr->extension->cpusetsize = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
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)
|
if (newp == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
iattr->cpuset = newp;
|
iattr->extension->cpuset = newp;
|
||||||
iattr->cpusetsize = cpusetsize;
|
iattr->extension->cpusetsize = cpusetsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (iattr->cpuset, cpuset, cpusetsize);
|
memcpy (iattr->extension->cpuset, cpuset, cpusetsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -884,7 +884,7 @@ __pthread_create_2_0 (pthread_t *newthread, const pthread_attr_t *attr,
|
|||||||
new_attr.guardsize = ps;
|
new_attr.guardsize = ps;
|
||||||
new_attr.stackaddr = NULL;
|
new_attr.stackaddr = NULL;
|
||||||
new_attr.stacksize = 0;
|
new_attr.stacksize = 0;
|
||||||
new_attr.cpuset = NULL;
|
new_attr.extension = NULL;
|
||||||
|
|
||||||
/* We will pass this value on to the real implementation. */
|
/* We will pass this value on to the real implementation. */
|
||||||
attr = (pthread_attr_t *) &new_attr;
|
attr = (pthread_attr_t *) &new_attr;
|
||||||
|
@ -36,9 +36,10 @@ struct pthread_attr
|
|||||||
/* Stack handling. */
|
/* Stack handling. */
|
||||||
void *stackaddr;
|
void *stackaddr;
|
||||||
size_t stacksize;
|
size_t stacksize;
|
||||||
/* Affinity map. */
|
|
||||||
cpu_set_t *cpuset;
|
/* Allocated via a call to __pthread_attr_extension once needed. */
|
||||||
size_t cpusetsize;
|
struct pthread_attr_extension *extension;
|
||||||
|
void *unused;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ATTR_FLAG_DETACHSTATE 0x0001
|
#define ATTR_FLAG_DETACHSTATE 0x0001
|
||||||
@ -57,6 +58,15 @@ union pthread_attr_transparent
|
|||||||
struct pthread_attr internal;
|
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. */
|
/* Mutex attribute data structure. */
|
||||||
struct pthread_mutexattr
|
struct pthread_mutexattr
|
||||||
{
|
{
|
||||||
|
@ -52,8 +52,10 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
|
|||||||
/* Determine whether the newly created threads has to be started
|
/* Determine whether the newly created threads has to be started
|
||||||
stopped since we have to set the scheduling parameters or set the
|
stopped since we have to set the scheduling parameters or set the
|
||||||
affinity. */
|
affinity. */
|
||||||
|
bool need_setaffinity = (attr != NULL && attr->extension != NULL
|
||||||
|
&& attr->extension->cpuset != 0);
|
||||||
if (attr != NULL
|
if (attr != NULL
|
||||||
&& (__glibc_unlikely (attr->cpuset != NULL)
|
&& (__glibc_unlikely (need_setaffinity)
|
||||||
|| __glibc_unlikely ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)))
|
|| __glibc_unlikely ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)))
|
||||||
*stopped_start = true;
|
*stopped_start = true;
|
||||||
|
|
||||||
@ -113,12 +115,13 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
/* Set the affinity mask if necessary. */
|
/* Set the affinity mask if necessary. */
|
||||||
if (attr->cpuset != NULL)
|
if (need_setaffinity)
|
||||||
{
|
{
|
||||||
assert (*stopped_start);
|
assert (*stopped_start);
|
||||||
|
|
||||||
res = INTERNAL_SYSCALL_CALL (sched_setaffinity, pd->tid,
|
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)))
|
if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res)))
|
||||||
err_out:
|
err_out:
|
||||||
|
Loading…
Reference in New Issue
Block a user