aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nptl/ChangeLog18
-rw-r--r--nptl/Makefile1
-rw-r--r--nptl/Versions1
-rw-r--r--nptl/pthread_attr_destroy.c14
-rw-r--r--nptl/pthread_create.c2
-rw-r--r--nptl/sysdeps/pthread/createthread.c196
-rw-r--r--nptl/sysdeps/pthread/pthread.h13
-rw-r--r--nptl/sysdeps/unix/sysv/linux/internaltypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c41
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c47
-rw-r--r--nptl/tst-cancel-wrappers.sh2
-rw-r--r--sysdeps/unix/sysv/linux/bits/sched.h4
12 files changed, 265 insertions, 76 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 804968a8c5..c2e50552d8 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -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.
diff --git a/nptl/Makefile b/nptl/Makefile
index b562e6618c..4c7749eb48 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -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
diff --git a/nptl/Versions b/nptl/Versions
index 0f98663d72..8eb863d0f4 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -220,6 +220,7 @@ libpthread {
# New affinity interfaces.
pthread_getaffinity_np; pthread_setaffinity_np;
+ pthread_attr_getaffinity_np; pthread_attr_setaffinity_np;
}
GLIBC_PRIVATE {
diff --git a/nptl/pthread_attr_destroy.c b/nptl/pthread_attr_destroy.c
index fec04163b1..a04f5fe441 100644
--- a/nptl/pthread_attr_destroy.c
+++ b/nptl/pthread_attr_destroy.c
@@ -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)
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 22024d5c8f..7565826997 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -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. */
diff --git a/nptl/sysdeps/pthread/createthread.c b/nptl/sysdeps/pthread/createthread.c
index 7563a2b71c..4a02d1c14b 100644
--- a/nptl/sysdeps/pthread/createthread.c
+++ b/nptl/sysdeps/pthread/createthread.c
@@ -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;
-
- /* 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);
}
diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
index 56d40e716e..80409bcac3 100644
--- a/nptl/sysdeps/pthread/pthread.h
+++ b/nptl/sysdeps/pthread/pthread.h
@@ -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. */
diff --git a/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
index 17d78e4b9f..e2f7b047f1 100644
--- a/nptl/sysdeps/unix/sysv/linux/internaltypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
@@ -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
index 0000000000..e6c795b8b4
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c
@@ -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
index 0000000000..f25ccb213e
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c
@@ -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;
+}
diff --git a/nptl/tst-cancel-wrappers.sh b/nptl/tst-cancel-wrappers.sh
index e2035c7ed5..d6f16d1ed2 100644
--- a/nptl/tst-cancel-wrappers.sh
+++ b/nptl/tst-cancel-wrappers.sh
@@ -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
diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h
index b250752810..4e963d1baa 100644
--- a/sysdeps/unix/sysv/linux/bits/sched.h
+++ b/sysdeps/unix/sysv/linux/bits/sched.h
@@ -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) \