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.
This commit is contained in:
Ulrich Drepper 2003-07-20 08:56:05 +00:00
parent 4e0dc4af0b
commit 80f536dbf2
12 changed files with 259 additions and 70 deletions

View 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.

View 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

View 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 {

View 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)

View 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. */

View File

@ -27,6 +27,10 @@
#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;
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
goto err_out;
}
/* 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);
/* Set the scheduling parameters. */
if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
{
res = INTERNAL_SYSCALL (sched_setparam, err, 2, pd->tid,
&pd->schedparam);
/* 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;
if (__builtin_expect (! INTERNAL_SYSCALL_ERROR_P (res, err), 1))
{
res = INTERNAL_SYSCALL (sched_setscheduler, err, 2, pd->tid,
&pd->schedpolicy);
/* Enqueue the descriptor. */
do
pd->nextevent = __nptl_last_event;
while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, pd,
pd->nextevent) != 0);
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
goto err_out;
}
}
/* Now call the function which signals the event. */
__nptl_create_event ();
/* Now start the thread for real. */
res = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCONT);
/* And finally restart the new thread. */
lll_unlock (pd->lock);
/* 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);
return 0;
/* 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);
/* 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 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;
return 0;
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);
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);
}

View 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. */

View 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. */

View File

@ -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;
}

View File

@ -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;
}

View 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

View 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) \