Module: xenomai-forge Branch: master Commit: 0e883200a0cae37e954a484a42da2dbfbc658284 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=0e883200a0cae37e954a484a42da2dbfbc658284
Author: Philippe Gerum <r...@xenomai.org> Date: Thu Nov 10 16:31:56 2011 +0100 cobalt: generalize support for extended scheduling attributes We provide the necessary bits to create threads from userland within Cobalt-specific scheduling classes, like SCHED_COBALT, SCHED_SPORADIC or SCHED_TP. To this end, we introduce pthread_create_ex(), which accepts an extended thread attribute structure to hold the class-specific parameters. In addition, a set of attribute accessors for this structure is also provided, as a collection of pthread_attr_*_ex() calls. pthread_create() is internally rebased on pthread_create_ex(), and the kernel support for creating Cobalt shadows is changed to accept the extended attribute set. --- include/cobalt/pthread.h | 141 +++++++++++++++++-------- kernel/cobalt/syscall.c | 39 ++++--- lib/cobalt/Makefile.am | 1 + lib/cobalt/Makefile.in | 28 ++++-- lib/cobalt/attr.c | 121 +++++++++++++++++++++ lib/cobalt/thread.c | 261 +++++++++++++++++++++++++-------------------- 6 files changed, 408 insertions(+), 183 deletions(-) diff --git a/include/cobalt/pthread.h b/include/cobalt/pthread.h index 955a6b4..acfda12 100644 --- a/include/cobalt/pthread.h +++ b/include/cobalt/pthread.h @@ -258,11 +258,11 @@ int pthread_attr_getfp_np(const pthread_attr_t *attr, int pthread_attr_setfp_np(pthread_attr_t *attr, int use_fp); -int pthread_attr_getaffinity_np (const pthread_attr_t *attr, - xnarch_cpumask_t *mask); +int pthread_attr_getaffinity_np(const pthread_attr_t *attr, + xnarch_cpumask_t *mask); -int pthread_attr_setaffinity_np (pthread_attr_t *attr, - xnarch_cpumask_t mask); +int pthread_attr_setaffinity_np(pthread_attr_t *attr, + xnarch_cpumask_t mask); int pthread_create(pthread_t *tid, const pthread_attr_t *attr, @@ -408,49 +408,18 @@ int pthread_set_name_np(pthread_t thread, #else /* !(__KERNEL__ || __XENO_SIM__) */ +typedef struct { + pthread_attr_t std; + struct { + int sched_policy; + struct sched_param_ex sched_param; + } nonstd; +} pthread_attr_ex_t; + #ifdef __cplusplus extern "C" { #endif -#ifndef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL -int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, - int *proto); - -int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, - int proto); -#endif - -#ifndef HAVE_PTHREAD_CONDATTR_SETCLOCK -int pthread_condattr_getclock(const pthread_condattr_t *attr, - clockid_t *clk_id); - -int pthread_condattr_setclock(pthread_condattr_t *attr, - clockid_t clk_id); -#endif - -int pthread_make_periodic_np(pthread_t thread, - clockid_t clk_id, - struct timespec *starttp, - struct timespec *periodtp); - -int pthread_wait_np(unsigned long *overruns_r); - -int pthread_set_mode_np(int clrmask, int setmask, - int *mask_r); - -int pthread_set_name_np(pthread_t thread, - const char *name); - -int pthread_probe_np(pid_t tid); - -int pthread_getschedparam_ex(pthread_t tid, - int *pol, - struct sched_param_ex *par); - -int pthread_setschedparam_ex(pthread_t tid, - int pol, - const struct sched_param_ex *par); - COBALT_DECL(int, pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)); @@ -545,6 +514,92 @@ COBALT_DECL(int, pthread_cond_broadcast(pthread_cond_t *cond)); COBALT_DECL(int, pthread_kill(pthread_t tid, int sig)); +#ifndef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL +COBALT_DECL(int, pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, + int *proto)); + +COBALT_DECL(int, pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, + int proto)); +#endif + +#ifndef HAVE_PTHREAD_CONDATTR_SETCLOCK +COBALT_DECL(int, pthread_condattr_getclock(const pthread_condattr_t *attr, + clockid_t *clk_id)); + +COBALT_DECL(int pthread_condattr_setclock(pthread_condattr_t *attr, + clockid_t clk_id)); +#endif + +int pthread_make_periodic_np(pthread_t thread, + clockid_t clk_id, + struct timespec *starttp, + struct timespec *periodtp); + +int pthread_wait_np(unsigned long *overruns_r); + +int pthread_set_mode_np(int clrmask, int setmask, + int *mask_r); + +int pthread_set_name_np(pthread_t thread, + const char *name); + +int pthread_probe_np(pid_t tid); + +int pthread_create_ex(pthread_t *tid, + const pthread_attr_ex_t *attr_ex, + void *(*start)(void *), + void *arg); + +int pthread_getschedparam_ex(pthread_t tid, + int *pol, + struct sched_param_ex *par); + +int pthread_setschedparam_ex(pthread_t tid, + int pol, + const struct sched_param_ex *par); + +int pthread_attr_init_ex(pthread_attr_ex_t *attr_ex); + +int pthread_attr_destroy_ex(pthread_attr_ex_t *attr_ex); + +int pthread_attr_setschedpolicy_ex(pthread_attr_ex_t *attr_ex, + int policy); + +int pthread_attr_getschedpolicy_ex(const pthread_attr_ex_t *attr_ex, + int *policy); + +int pthread_attr_setschedparam_ex(pthread_attr_ex_t *attr_ex, + const struct sched_param_ex *param_ex); + +int pthread_attr_getschedparam_ex(const pthread_attr_ex_t *attr_ex, + struct sched_param_ex *param_ex); + +int pthread_attr_getinheritsched_ex(const pthread_attr_ex_t *attr_ex, + int *inheritsched); + +int pthread_attr_setinheritsched_ex(pthread_attr_ex_t *attr_ex, + int inheritsched); + +int pthread_attr_getdetachstate_ex(const pthread_attr_ex_t *attr_ex, + int *detachstate); + +int pthread_attr_setdetachstate_ex(pthread_attr_ex_t *attr_ex, + int detachstate); + +int pthread_attr_setdetachstate_ex(pthread_attr_ex_t *attr_ex, + int detachstate); + +int pthread_attr_getstacksize_ex(const pthread_attr_ex_t *attr_ex, + size_t *stacksize); + +int pthread_attr_setstacksize_ex(pthread_attr_ex_t *attr_ex, + size_t stacksize); + +int pthread_attr_getscope_ex(const pthread_attr_ex_t *attr_ex, + int *scope); + +int pthread_attr_setscope_ex(pthread_attr_ex_t *attr_ex, + int scope); #ifdef __cplusplus } #endif diff --git a/kernel/cobalt/syscall.c b/kernel/cobalt/syscall.c index d5c2ff8..9574eeb 100644 --- a/kernel/cobalt/syscall.c +++ b/kernel/cobalt/syscall.c @@ -207,16 +207,19 @@ static int __tid_probe(pid_t h_tid) return ret; } -static int __pthread_create(unsigned long tid, - int policy, int sched_prio, +static int __pthread_create(unsigned long tid, int policy, + struct sched_param_ex __user *u_param, unsigned long __user *u_mode) { struct task_struct *p = current; + struct sched_param_ex param; struct cobalt_hkey hkey; pthread_attr_t attr; pthread_t k_tid; - int err; + int ret; + if (__xn_safe_copy_from_user(¶m, u_param, sizeof(param))) + return -EFAULT; /* * We have been passed the pthread_t identifier the user-space * POSIX library has assigned to our caller; we'll index our @@ -233,25 +236,31 @@ static int __pthread_create(unsigned long tid, pthread_attr_init(&attr); attr.policy = policy; attr.detachstate = PTHREAD_CREATE_DETACHED; - attr.schedparam_ex.sched_priority = sched_prio; + attr.schedparam_ex = param; attr.fp = 1; attr.name = p->comm; - err = pthread_create(&k_tid, &attr, NULL, NULL); + ret = pthread_create(&k_tid, &attr, NULL, NULL); + if (ret) + return -ret; - if (err) - return -err; /* Conventionally, our error codes are negative. */ + ret = xnshadow_map(&k_tid->threadbase, NULL, u_mode); + if (ret) + goto fail; - err = xnshadow_map(&k_tid->threadbase, NULL, u_mode); - if (err == 0 && !__pthread_hash(&hkey, k_tid, task_pid_vnr(p))) - err = -ENOMEM; + if (!__pthread_hash(&hkey, k_tid, task_pid_vnr(p))) { + ret = -ENOMEM; + goto fail; + } - if (err) - cobalt_thread_abort(k_tid, NULL); - else - k_tid->hkey = hkey; + k_tid->hkey = hkey; - return err; + return 0; + +fail: + cobalt_thread_abort(k_tid, NULL); + + return ret; } #define __pthread_detach __cobalt_call_not_available diff --git a/lib/cobalt/Makefile.am b/lib/cobalt/Makefile.am index 6e5942f..28d8453 100644 --- a/lib/cobalt/Makefile.am +++ b/lib/cobalt/Makefile.am @@ -12,6 +12,7 @@ libcobalt_la_LDFLAGS = @XENO_DLOPEN_CONSTRAINT@ -version-info 2:0:0 -lpthread -l libcobalt_la_SOURCES = \ assert_context.c \ + attr.c \ bind.c \ current.c \ sem_heap.c \ diff --git a/lib/cobalt/Makefile.in b/lib/cobalt/Makefile.in index 38b0342..127e993 100644 --- a/lib/cobalt/Makefile.in +++ b/lib/cobalt/Makefile.in @@ -79,15 +79,16 @@ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libcobalt_la_LIBADD = am_libcobalt_la_OBJECTS = libcobalt_la-assert_context.lo \ - libcobalt_la-bind.lo libcobalt_la-current.lo \ - libcobalt_la-sem_heap.lo libcobalt_la-sigshadow.lo \ - libcobalt_la-timeconv.lo libcobalt_la-init.lo \ - libcobalt_la-internal.lo libcobalt_la-thread.lo \ - libcobalt_la-timer.lo libcobalt_la-semaphore.lo \ - libcobalt_la-clock.lo libcobalt_la-cond.lo libcobalt_la-mq.lo \ - libcobalt_la-mutex.lo libcobalt_la-shm.lo \ - libcobalt_la-select.lo libcobalt_la-rtdm.lo \ - libcobalt_la-printf.lo libcobalt_la-wrappers.lo + libcobalt_la-attr.lo libcobalt_la-bind.lo \ + libcobalt_la-current.lo libcobalt_la-sem_heap.lo \ + libcobalt_la-sigshadow.lo libcobalt_la-timeconv.lo \ + libcobalt_la-init.lo libcobalt_la-internal.lo \ + libcobalt_la-thread.lo libcobalt_la-timer.lo \ + libcobalt_la-semaphore.lo libcobalt_la-clock.lo \ + libcobalt_la-cond.lo libcobalt_la-mq.lo libcobalt_la-mutex.lo \ + libcobalt_la-shm.lo libcobalt_la-select.lo \ + libcobalt_la-rtdm.lo libcobalt_la-printf.lo \ + libcobalt_la-wrappers.lo libcobalt_la_OBJECTS = $(am_libcobalt_la_OBJECTS) libcobalt_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -277,6 +278,7 @@ lib_LTLIBRARIES = libcobalt.la libcobalt_la_LDFLAGS = @XENO_DLOPEN_CONSTRAINT@ -version-info 2:0:0 -lpthread -lrt libcobalt_la_SOURCES = \ assert_context.c \ + attr.c \ bind.c \ current.c \ sem_heap.c \ @@ -378,6 +380,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcobalt_la-assert_context.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcobalt_la-attr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcobalt_la-bind.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcobalt_la-clock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcobalt_la-cond.Plo@am__quote@ @@ -426,6 +429,13 @@ libcobalt_la-assert_context.lo: assert_context.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcobalt_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcobalt_la-assert_context.lo `test -f 'assert_context.c' || echo '$(srcdir)/'`assert_context.c +libcobalt_la-attr.lo: attr.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcobalt_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcobalt_la-attr.lo -MD -MP -MF $(DEPDIR)/libcobalt_la-attr.Tpo -c -o libcobalt_la-attr.lo `test -f 'attr.c' || echo '$(srcdir)/'`attr.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libcobalt_la-attr.Tpo $(DEPDIR)/libcobalt_la-attr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='attr.c' object='libcobalt_la-attr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcobalt_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcobalt_la-attr.lo `test -f 'attr.c' || echo '$(srcdir)/'`attr.c + libcobalt_la-bind.lo: bind.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcobalt_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcobalt_la-bind.lo -MD -MP -MF $(DEPDIR)/libcobalt_la-bind.Tpo -c -o libcobalt_la-bind.lo `test -f 'bind.c' || echo '$(srcdir)/'`bind.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libcobalt_la-bind.Tpo $(DEPDIR)/libcobalt_la-bind.Plo diff --git a/lib/cobalt/attr.c b/lib/cobalt/attr.c new file mode 100644 index 0000000..5c8f8d7 --- /dev/null +++ b/lib/cobalt/attr.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2011 Philippe Gerum <r...@xenomai.org>. + * + * This 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 of the License, or (at your option) any later version. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <stddef.h> +#include <errno.h> +#include <pthread.h> + +int pthread_attr_init_ex(pthread_attr_ex_t *attr_ex) +{ + struct sched_param param; + int policy; + + /* We start with the default standard attribute set. */ + pthread_attr_init(&attr_ex->std); + pthread_attr_getschedpolicy(&attr_ex->std, &policy); + attr_ex->nonstd.sched_policy = policy; + pthread_attr_getschedparam(&attr_ex->std, ¶m); + attr_ex->nonstd.sched_param.sched_priority = param.sched_priority; + + return 0; +} + +int pthread_attr_destroy_ex(pthread_attr_ex_t *attr_ex) +{ + return pthread_attr_destroy(&attr_ex->std); +} + +int pthread_attr_setschedpolicy_ex(pthread_attr_ex_t *attr_ex, + int policy) +{ + attr_ex->nonstd.sched_policy = policy; + + return 0; +} + +int pthread_attr_getschedpolicy_ex(const pthread_attr_ex_t *attr_ex, + int *policy) +{ + *policy = attr_ex->nonstd.sched_policy; + + return 0; +} + +int pthread_attr_setschedparam_ex(pthread_attr_ex_t *attr_ex, + const struct sched_param_ex *param_ex) +{ + attr_ex->nonstd.sched_param = *param_ex; + + return 0; +} + +int pthread_attr_getschedparam_ex(const pthread_attr_ex_t *attr_ex, + struct sched_param_ex *param_ex) +{ + *param_ex = attr_ex->nonstd.sched_param; + + return 0; +} + +int pthread_attr_setinheritsched_ex(pthread_attr_ex_t *attr_ex, + int inheritsched) +{ + return pthread_attr_setinheritsched(&attr_ex->std, inheritsched); +} + +int pthread_attr_getinheritsched_ex(const pthread_attr_ex_t *attr_ex, + int *inheritsched) +{ + return pthread_attr_getinheritsched(&attr_ex->std, inheritsched); +} + +int pthread_attr_getdetachstate_ex(const pthread_attr_ex_t *attr_ex, + int *detachstate) +{ + return pthread_attr_getdetachstate(&attr_ex->std, detachstate); +} + +int pthread_attr_setdetachstate_ex(pthread_attr_ex_t *attr_ex, + int detachstate) +{ + return pthread_attr_setdetachstate(&attr_ex->std, detachstate); +} + +int pthread_attr_getstacksize_ex(const pthread_attr_ex_t *attr_ex, + size_t *stacksize) +{ + return pthread_attr_getstacksize(&attr_ex->std, stacksize); +} + +int pthread_attr_setstacksize_ex(pthread_attr_ex_t *attr_ex, + size_t stacksize) +{ + return pthread_attr_setstacksize(&attr_ex->std, stacksize); +} + +int pthread_attr_getscope_ex(const pthread_attr_ex_t *attr_ex, + int *scope) +{ + return pthread_attr_getscope(&attr_ex->std, scope); +} + +int pthread_attr_setscope_ex(pthread_attr_ex_t *attr_ex, + int scope) +{ + return pthread_attr_setscope(&attr_ex->std, scope); +} diff --git a/lib/cobalt/thread.c b/lib/cobalt/thread.c index e4a2ca2..dd23587 100644 --- a/lib/cobalt/thread.c +++ b/lib/cobalt/thread.c @@ -32,28 +32,29 @@ extern int __cobalt_muxid; -static pthread_attr_t default_attr; +static pthread_attr_ex_t default_attr_ex; + static int linuxthreads; int __wrap_pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param) { - pthread_t myself = pthread_self(); + volatile pthread_t myself = pthread_self(); unsigned long mode_offset; - int err, promoted; + int ret, promoted; if (thread == myself) xeno_fault_stack(); - err = -XENOMAI_SKINCALL5(__cobalt_muxid, + ret = -XENOMAI_SKINCALL5(__cobalt_muxid, __cobalt_thread_setschedparam, thread, policy, param, &mode_offset, &promoted); - if (err == EPERM) + if (ret == EPERM) return __STD(pthread_setschedparam(thread, policy, param)); - if (!err && promoted) { + if (ret == 0 && promoted) { xeno_sigshadow_install_once(); xeno_set_current(); xeno_set_current_mode(mode_offset); @@ -61,31 +62,30 @@ int __wrap_pthread_setschedparam(pthread_t thread, XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN); } - return err; + return ret; } int pthread_setschedparam_ex(pthread_t thread, int policy, const struct sched_param_ex *param) { - pthread_t myself = pthread_self(); + volatile pthread_t myself = pthread_self(); struct sched_param short_param; unsigned long mode_offset; - int err, promoted; + int ret, promoted; if (thread == myself) xeno_fault_stack(); - err = -XENOMAI_SKINCALL5(__cobalt_muxid, + ret = -XENOMAI_SKINCALL5(__cobalt_muxid, __cobalt_thread_setschedparam_ex, thread, policy, param, &mode_offset, &promoted); - - if (err == EPERM) { + if (ret == EPERM) { short_param.sched_priority = param->sched_priority; return __STD(pthread_setschedparam(thread, policy, &short_param)); } - if (!err && promoted) { + if (ret == 0 && promoted) { xeno_sigshadow_install_once(); xeno_set_current(); xeno_set_current_mode(mode_offset); @@ -93,23 +93,22 @@ int pthread_setschedparam_ex(pthread_t thread, XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN); } - return err; + return ret; } int __wrap_pthread_getschedparam(pthread_t thread, int *__restrict__ policy, struct sched_param *__restrict__ param) { - int err; + int ret; - err = -XENOMAI_SKINCALL3(__cobalt_muxid, + ret = -XENOMAI_SKINCALL3(__cobalt_muxid, __cobalt_thread_getschedparam, thread, policy, param); - - if (err == ESRCH) + if (ret == ESRCH) return __STD(pthread_getschedparam(thread, policy, param)); - return err; + return ret; } int pthread_getschedparam_ex(pthread_t thread, @@ -117,29 +116,29 @@ int pthread_getschedparam_ex(pthread_t thread, struct sched_param_ex *__restrict__ param) { struct sched_param short_param; - int err; + int ret; - err = -XENOMAI_SKINCALL3(__cobalt_muxid, + ret = -XENOMAI_SKINCALL3(__cobalt_muxid, __cobalt_thread_getschedparam_ex, thread, policy, param); - - if (err == ESRCH) { - err = __STD(pthread_getschedparam(thread, policy, &short_param)); - if (err == 0) + if (ret == ESRCH) { + ret = __STD(pthread_getschedparam(thread, policy, &short_param)); + if (ret == 0) param->sched_priority = short_param.sched_priority; } - return err; + return ret; } int __wrap_sched_yield(void) { - int err = -XENOMAI_SKINCALL0(__cobalt_muxid, __cobalt_sched_yield); + int ret; - if (err == -1) - err = __STD(sched_yield()); + ret = -XENOMAI_SKINCALL0(__cobalt_muxid, __cobalt_sched_yield); + if (ret == -1) + ret = __STD(sched_yield()); - return err; + return ret; } int __wrap_sched_get_priority_min(int policy) @@ -178,131 +177,161 @@ int __wrap_pthread_yield(void) } struct pthread_iargs { - void *(*start) (void *); - void *arg; + struct sched_param_ex param_ex; int policy; - int parent_prio, prio; + void *(*start)(void *); + void *arg; + int parent_prio; sem_t sync; int ret; }; -static void *__pthread_trampoline(void *arg) +static void *__pthread_trampoline(void *p) { - struct pthread_iargs *iargs = (struct pthread_iargs *)arg; - /* Avoid smart versions of gcc to trashes the syscall - registers (again, see later comment). */ + /* + * Volatile is to prevent (too) smart gcc releases from + * trashing the syscall registers (see later comment). + */ volatile pthread_t tid = pthread_self(); - void *(*start) (void *), *cookie; + struct pthread_iargs *iargs = p; + struct sched_param_ex param_ex; + void *(*start)(void *), *arg; unsigned long mode_offset; - struct sched_param param; - void *status = NULL; int parent_prio, policy; - long err; + long ret; xeno_sigshadow_install_once(); - param.sched_priority = iargs->prio; + param_ex = iargs->param_ex; policy = iargs->policy; parent_prio = iargs->parent_prio; - - /* Do _not_ inline the call to pthread_self() in the syscall - macro: this trashes the syscall regs on some archs. */ - err = XENOMAI_SKINCALL4(__cobalt_muxid, __cobalt_thread_create, tid, - iargs->policy, iargs->prio, &mode_offset); - iargs->ret = -err; - - /* We must save anything we'll need to use from *iargs on our own - stack now before posting the sync sema4, since our released - parent could unwind the stack space onto which the iargs struct - is laid on before we actually get the CPU back. */ - start = iargs->start; - cookie = iargs->arg; - - if (!err) { + arg = iargs->arg; + + /* + * Do _not_ inline the call to pthread_self() in the syscall + * macro: this trashes the syscall regs on some archs. + */ + ret = XENOMAI_SKINCALL4(__cobalt_muxid, __cobalt_thread_create, tid, + policy, ¶m_ex, &mode_offset); + if (ret == 0) { xeno_set_current(); xeno_set_current_mode(mode_offset); } + /* + * We must access anything we'll need from *iargs before + * posting the sync semaphore, since our released parent could + * unwind the stack space onto which the iargs struct is laid + * on before we actually get the CPU back. + */ + iargs->ret = -ret; __STD(sem_post(&iargs->sync)); + if (ret) + return (void *)-ret; - if (!err) { - /* If the thread running pthread_create runs with the same - priority as us, we should leave it running, as if there never - was a synchronization with a semaphore. */ - if (param.sched_priority == parent_prio) - __wrap_sched_yield(); + /* + * If the parent thread runs with the same priority as we do, + * then we should yield the CPU to it, to preserve the + * scheduling order. + */ + if (param_ex.sched_priority == parent_prio) + __wrap_sched_yield(); - if (policy != SCHED_OTHER) - XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN); - status = start(cookie); - } else - status = (void *)-err; + if (policy != SCHED_OTHER) + XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN); - return status; + return start(arg); } -int __wrap_pthread_create(pthread_t *tid, - const pthread_attr_t * attr, - void *(*start) (void *), void *arg) +int pthread_create_ex(pthread_t *tid, + const pthread_attr_ex_t *attr_ex, + void *(*start) (void *), void *arg) { struct pthread_iargs iargs; struct sched_param param; - pthread_attr_t iattr; - int inherit, err; + pthread_attr_t attr; + int inherit, ret; pthread_t ltid; size_t stksz; - if (!attr) - attr = &default_attr; + if (attr_ex == NULL) + attr_ex = &default_attr_ex; + + pthread_getschedparam_ex(pthread_self(), &iargs.policy, &iargs.param_ex); + iargs.parent_prio = iargs.param_ex.sched_priority; + memcpy(&attr, &attr_ex->std, sizeof(attr)); - pthread_attr_getinheritsched(attr, &inherit); - __wrap_pthread_getschedparam(pthread_self(), &iargs.policy, ¶m); - iargs.parent_prio = param.sched_priority; + pthread_attr_getinheritsched(&attr, &inherit); if (inherit == PTHREAD_EXPLICIT_SCHED) { - pthread_attr_getschedpolicy(attr, &iargs.policy); - pthread_attr_getschedparam(attr, ¶m); + pthread_attr_getschedpolicy_ex(attr_ex, &iargs.policy); + pthread_attr_getschedparam_ex(attr_ex, &iargs.param_ex); } - iargs.prio = param.sched_priority; - memcpy(&iattr, attr, sizeof(pthread_attr_t)); if (linuxthreads && geteuid()) { - /* Work around linuxthreads shortcoming: it doesn't believe - that it could have RT power as non-root and fails the - thread creation overeagerly. */ - pthread_attr_setinheritsched(&iattr, PTHREAD_EXPLICIT_SCHED); + /* + * Work around linuxthreads shortcoming: it doesn't + * believe that it could have RT power as non-root and + * fails the thread creation overeagerly. + */ + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); param.sched_priority = 0; - pthread_attr_setschedpolicy(&iattr, SCHED_OTHER); - pthread_attr_setschedparam(&iattr, ¶m); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); } else - /* Get the created thread to temporarily inherit pthread_create - caller priority */ - pthread_attr_setinheritsched(&iattr, PTHREAD_INHERIT_SCHED); - pthread_attr_getstacksize(&iattr, &stksz); - pthread_attr_setstacksize(&iattr, xeno_stacksize(stksz)); - attr = &iattr; - - /* First start a native POSIX thread, then associate a Xenomai shadow to - it. */ - + /* + * Get the created thread to temporarily inherit the + * caller priority (we mean linux/libc priority here, + * as we use a libc call to create the thread). + */ + pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); + + pthread_attr_getstacksize(&attr, &stksz); + pthread_attr_setstacksize(&attr, xeno_stacksize(stksz)); + + /* + * First start a native POSIX thread, then mate a Xenomai + * shadow to it. + */ iargs.start = start; iargs.arg = arg; iargs.ret = EAGAIN; __STD(sem_init(&iargs.sync, 0, 0)); - err = __STD(pthread_create(<id, attr, - &__pthread_trampoline, &iargs)); + ret = __STD(pthread_create(<id, &attr, &__pthread_trampoline, &iargs)); + if (ret) + goto fail; + + while (__STD(sem_wait(&iargs.sync)) && errno == EINTR) + ; - if (!err) - while (__STD(sem_wait(&iargs.sync)) && errno == EINTR) ; + ret = iargs.ret; + if (ret == 0) + *tid = ltid; +fail: __STD(sem_destroy(&iargs.sync)); - err = err ?: iargs.ret; + return ret; +} - if (!err) - *tid = ltid; +int __wrap_pthread_create(pthread_t *tid, + const pthread_attr_t *attr, + void *(*start) (void *), void *arg) +{ + pthread_attr_ex_t attr_ex; + struct sched_param param; + int policy; + + if (attr == NULL) + attr = &default_attr_ex.std; + + memcpy(&attr_ex.std, attr, sizeof(*attr)); + pthread_attr_getschedpolicy(attr, &policy); + attr_ex.nonstd.sched_policy = policy; + pthread_attr_getschedparam(attr, ¶m); + attr_ex.nonstd.sched_param.sched_priority = param.sched_priority; - return err; + return pthread_create_ex(tid, &attr_ex, start, arg); } int pthread_make_periodic_np(pthread_t thread, @@ -317,16 +346,16 @@ int pthread_make_periodic_np(pthread_t thread, int pthread_wait_np(unsigned long *overruns_r) { - int err, oldtype; + int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); - err = -XENOMAI_SKINCALL1(__cobalt_muxid, + ret = -XENOMAI_SKINCALL1(__cobalt_muxid, __cobalt_thread_wait, overruns_r); pthread_setcanceltype(oldtype, NULL); - return err; + return ret; } int pthread_set_mode_np(int clrmask, int setmask, int *mode_r) @@ -350,19 +379,19 @@ int pthread_probe_np(pid_t tid) int __wrap_pthread_kill(pthread_t thread, int sig) { - int err; - err = -XENOMAI_SKINCALL2(__cobalt_muxid, - __cobalt_thread_kill, thread, sig); + int ret; - if (err == ESRCH) + ret = -XENOMAI_SKINCALL2(__cobalt_muxid, + __cobalt_thread_kill, thread, sig); + if (ret == ESRCH) return __STD(pthread_kill(thread, sig)); - return err; + return ret; } static __attribute__((constructor)) void cobalt_thread_init(void) { - pthread_attr_init(&default_attr); + pthread_attr_init_ex(&default_attr_ex); #ifdef _CS_GNU_LIBPTHREAD_VERSION { char vers[128]; _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git