Module: xenomai-2.6
Branch: master
Commit: ad25f6c2de7b99fdf66815b5bf7dd4304fa56a6c
URL:    
http://git.xenomai.org/?p=xenomai-2.6.git;a=commit;h=ad25f6c2de7b99fdf66815b5bf7dd4304fa56a6c

Author: Philippe Gerum <r...@xenomai.org>
Date:   Thu Dec 20 16:50:04 2012 +0100

posix: provide application interface to the SCHED_TP policy

---

 include/posix/sched.h          |   51 ++++++++++-
 include/posix/syscall.h        |    1 +
 ksrc/skins/posix/sched.c       |  189 +++++++++++++++++++++++++++++++++++++---
 ksrc/skins/posix/syscall.c     |   42 +++++++++
 ksrc/skins/posix/thread_attr.c |   15 ++--
 src/skins/posix/thread.c       |    8 ++
 src/testsuite/unit/Makefile.am |   16 +++-
 src/testsuite/unit/sched-tp.c  |  164 ++++++++++++++++++++++++++++++++++
 8 files changed, 461 insertions(+), 25 deletions(-)

diff --git a/include/posix/sched.h b/include/posix/sched.h
index f1edcc9..bb0d209 100644
--- a/include/posix/sched.h
+++ b/include/posix/sched.h
@@ -66,10 +66,10 @@ int __real_sched_yield(void);
 
 #ifndef SCHED_SPORADIC
 #define SCHED_SPORADIC         10
-#define sched_ss_low_priority  ss.__sched_low_priority
-#define sched_ss_repl_period   ss.__sched_repl_period
-#define sched_ss_init_budget   ss.__sched_init_budget
-#define sched_ss_max_repl      ss.__sched_max_repl
+#define sched_ss_low_priority  sched_u.ss.__sched_low_priority
+#define sched_ss_repl_period   sched_u.ss.__sched_repl_period
+#define sched_ss_init_budget   sched_u.ss.__sched_init_budget
+#define sched_ss_max_repl      sched_u.ss.__sched_max_repl
 #endif /* !SCHED_SPORADIC */
 
 struct __sched_ss_param {
@@ -79,11 +79,52 @@ struct __sched_ss_param {
        int __sched_max_repl;
 };
 
+#ifndef SCHED_TP
+#define SCHED_TP               11
+#define sched_tp_partition     sched_u.tp.__sched_partition
+#endif /* !SCHED_TP */
+
+struct __sched_tp_param {
+       int __sched_partition;
+};
+
 struct sched_param_ex {
        int sched_priority;
-       struct __sched_ss_param ss;
+       union {
+               struct __sched_ss_param ss;
+               struct __sched_tp_param tp;
+       } sched_u;
+};
+
+struct sched_tp_window {
+       struct timespec offset;
+       struct timespec duration;
+       int ptid;
 };
 
+struct __sched_config_tp {
+       int nr_windows;
+       struct sched_tp_window windows[0];
+};
+
+union sched_config {
+       struct __sched_config_tp tp;
+};
+
+#define sched_tp_confsz(nr_win) \
+  (sizeof(struct __sched_config_tp) + nr_win * sizeof(struct sched_tp_window))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int sched_setconfig_np(int cpu, int policy,
+                      union sched_config *config, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __sched_extensions_defined */
 
 #endif /* SCHED_H */
diff --git a/include/posix/syscall.h b/include/posix/syscall.h
index 04a528d..b5f920d 100644
--- a/include/posix/syscall.h
+++ b/include/posix/syscall.h
@@ -104,6 +104,7 @@
 #define __pse51_select                77
 #define __pse51_thread_setschedparam_ex        78
 #define __pse51_thread_getschedparam_ex        79
+#define __pse51_sched_setconfig_np     80
 
 #ifdef __KERNEL__
 
diff --git a/ksrc/skins/posix/sched.c b/ksrc/skins/posix/sched.c
index dc195af..3d62421 100644
--- a/ksrc/skins/posix/sched.c
+++ b/ksrc/skins/posix/sched.c
@@ -23,7 +23,7 @@
  * Thread scheduling services.
  *
  * Xenomai POSIX skin supports the scheduling policies SCHED_FIFO,
- * SCHED_RR, SCHED_SPORADIC and SCHED_OTHER.
+ * SCHED_RR, SCHED_SPORADIC, SCHED_TP and SCHED_OTHER.
  *
  * The SCHED_OTHER policy is mainly useful for user-space non-realtime
  * activities that need to synchronize with real-time activities.
@@ -38,6 +38,15 @@
  * The SCHED_SPORADIC policy provides a mean to schedule aperiodic or
  * sporadic threads in periodic-based systems.
  *
+ * The SCHED_TP policy divides the scheduling time into a recurring
+ * global frame, which is itself divided into an arbitrary number of
+ * time partitions. Only threads assigned to the current partition are
+ * deemed runnable, and scheduled according to a FIFO-based rule
+ * within this partition. When completed, the current partition is
+ * advanced automatically to the next one by the scheduler, and the
+ * global time frame recurs from the first partition defined, when the
+ * last partition has ended.
+ *
  * The scheduling policy and priority of a thread is set when creating a 
thread,
  * by using thread creation attributes (see pthread_attr_setinheritsched(),
  * pthread_attr_setschedpolicy() and pthread_attr_setschedparam()), or when the
@@ -57,8 +66,8 @@
  * This service returns the minimum priority of the scheduling policy @a
  * policy.
  *
- * @param policy scheduling policy, one of SCHED_FIFO, SCHED_RR, or
- * SCHED_OTHER.
+ * @param policy scheduling policy, one of SCHED_FIFO, SCHED_RR,
+ * SCHED_SPORADIC, SCHED_TP or SCHED_OTHER.
  *
  * @retval 0 on success;
  * @retval -1 with @a errno set if:
@@ -75,6 +84,7 @@ int sched_get_priority_min(int policy)
        case SCHED_FIFO:
        case SCHED_RR:
        case SCHED_SPORADIC:
+       case SCHED_TP:
                return PSE51_MIN_PRIORITY;
 
        case SCHED_OTHER:
@@ -92,8 +102,8 @@ int sched_get_priority_min(int policy)
  * This service returns the maximum priority of the scheduling policy @a
  * policy.
  *
- * @param policy scheduling policy, one of SCHED_FIFO, SCHED_RR, or
- * SCHED_OTHER.
+ * @param policy scheduling policy, one of SCHED_FIFO, SCHED_RR,
+ * SCHED_SPORADIC, SCHED_TP or SCHED_OTHER.
  *
  * @retval 0 on success;
  * @retval -1 with @a errno set if:
@@ -110,6 +120,7 @@ int sched_get_priority_max(int policy)
        case SCHED_FIFO:
        case SCHED_RR:
        case SCHED_SPORADIC:
+       case SCHED_TP:
                return PSE51_MAX_PRIORITY;
 
        case SCHED_OTHER:
@@ -215,8 +226,8 @@ int pthread_getschedparam(pthread_t tid, int *pol, struct 
sched_param *par)
  * that also supports Xenomai-specific or additional POSIX scheduling
  * policies, which are not available with the host Linux environment.
  *
- * Typically, SCHED_SPORADIC parameters can be retrieved from this
- * call.
+ * Typically, SCHED_SPORADIC or SCHED_TP parameters can be retrieved
+ * from this call.
  *
  * @param tid target thread;
  *
@@ -271,6 +282,13 @@ int pthread_getschedparam_ex(pthread_t tid, int *pol, 
struct sched_param_ex *par
                goto unlock_and_exit;
        }
 #endif
+#ifdef CONFIG_XENO_OPT_SCHED_SPORADIC
+       if (base_class == &xnsched_class_tp) {
+               *pol = SCHED_TP;
+               par->sched_tp_partition = thread->tps - 
thread->sched->tp.partitions;
+               goto unlock_and_exit;
+       }
+#endif
 
 unlock_and_exit:
 
@@ -295,8 +313,8 @@ unlock_and_exit:
  *
  * @param tid target thread;
  *
- * @param pol scheduling policy, one of SCHED_FIFO, SCHED_RR or
- * SCHED_OTHER;
+ * @param pol scheduling policy, one of SCHED_FIFO, SCHED_RR,
+ * SCHED_SPORADIC, SCHED_TP or SCHED_OTHER;
  *
  * @param par scheduling parameters address.
  *
@@ -356,6 +374,7 @@ int pthread_setschedparam(pthread_t tid, int pol, const 
struct sched_param *par)
        case SCHED_OTHER:
        case SCHED_FIFO:
        case SCHED_SPORADIC:
+       case SCHED_TP:
                xnpod_set_thread_tslice(&tid->threadbase, XN_INFINITE);
                break;
 
@@ -390,8 +409,8 @@ int pthread_setschedparam(pthread_t tid, int pol, const 
struct sched_param *par)
  * that supports Xenomai-specific or additional POSIX scheduling
  * policies, which are not available with the host Linux environment.
  *
- * Typically, a Xenomai thread policy can be set to SCHED_SPORADIC
- * using this call.
+ * Typically, a Xenomai thread policy can be set to SCHED_SPORADIC or
+ * SCHED_TP using this call.
  *
  * @param tid target thread;
  *
@@ -457,11 +476,20 @@ int pthread_setschedparam_ex(pthread_t tid, int pol, 
const struct sched_param_ex
                ret = -xnpod_set_thread_schedparam(&tid->threadbase,
                                                   &xnsched_class_sporadic, 
&param);
                break;
-#else
-               (void)param;
+#endif
+#ifdef CONFIG_XENO_OPT_SCHED_TP
+       case SCHED_TP:
+               xnpod_set_thread_tslice(&tid->threadbase, XN_INFINITE);
+               param.tp.prio = par->sched_priority;
+               param.tp.ptid = par->sched_tp_partition;
+               ret = -xnpod_set_thread_schedparam(&tid->threadbase,
+                                                  &xnsched_class_tp, &param);
+               break;
 #endif
        }
 
+       (void)param;
+
        xnpod_schedule();
 
        xnlock_put_irqrestore(&nklock, s);
@@ -487,6 +515,140 @@ int sched_yield(void)
        return 0;
 }
 
+#ifdef CONFIG_XENO_OPT_SCHED_TP
+
+static inline
+int set_tp_config(int cpu, union sched_config *config, size_t len)
+{
+       xnticks_t offset, duration, next_offset;
+       struct xnsched_tp_schedule *gps, *ogps;
+       struct xnsched_tp_window *w;
+       struct sched_tp_window *p;
+       struct xnsched *sched;
+       spl_t s;
+       int n;
+
+       gps = xnmalloc(sizeof(*gps) + config->tp.nr_windows * sizeof(*w));
+       if (gps == NULL)
+               goto fail;
+
+       for (n = 0, p = config->tp.windows, w = gps->pwins, next_offset = 0;
+            n < config->tp.nr_windows; n++, p++, w++) {
+               /*
+                * Time windows must be strictly contiguous. Holes may
+                * be defined using windows assigned to the pseudo
+                * partition #-1.
+                */
+               offset = ts2ticks_ceil(&p->offset);
+               if (offset != next_offset)
+                       goto cleanup_and_fail;
+
+               duration = ts2ticks_ceil(&p->duration);
+               if (duration <= 0)
+                       goto cleanup_and_fail;
+
+               if (p->ptid < -1 ||
+                   p->ptid >= CONFIG_XENO_OPT_SCHED_TP_NRPART)
+                       goto cleanup_and_fail;
+
+               w->w_offset = next_offset;
+               w->w_part = p->ptid;
+               next_offset += duration;
+       }
+
+       gps->pwin_nr = n;
+       gps->tf_duration = next_offset;
+       sched = xnpod_sched_slot(cpu);
+
+       xnlock_get_irqsave(&nklock, s);
+       ogps = xnsched_tp_set_schedule(sched, gps);
+       xnsched_tp_start_schedule(sched);
+       xnlock_put_irqrestore(&nklock, s);
+
+       if (ogps)
+               xnfree(ogps);
+
+       return 0;
+
+cleanup_and_fail:
+       xnfree(gps);
+fail:
+       return EINVAL;
+}
+
+#else /* !CONFIG_XENO_OPT_SCHED_TP */
+
+static inline
+int set_tp_config(int cpu, union sched_config *config, size_t len)
+{
+       return EINVAL;
+}
+
+#endif /* !CONFIG_XENO_OPT_SCHED_TP */
+
+/**
+ * Load CPU-specific scheduler settings for a given policy.
+ *
+ * Currently, this call only supports the SCHED_TP policy, for loading
+ * the temporal partitions. A configuration is strictly local to the
+ * target @a cpu, and may differ from other processors.
+ *
+ * @param cpu processor to load the configuration of.
+ *
+ * @param policy scheduling policy to which the configuration data
+ * applies. Currently, only SCHED_TP is valid.
+ *
+ * @param p a pointer to the configuration data to load for @a
+ * cpu, applicable to @a policy.
+ *
+ * Settings applicable to SCHED_TP:
+ *
+ * This call installs the temporal partitions for @a cpu.
+ *
+ * - config.tp.windows should be a non-null set of time windows,
+ * defining the scheduling time slots for @a cpu. Each window defines
+ * its offset from the start of the global time frame
+ * (windows[].offset), a duration (windows[].duration), and the
+ * partition id it applies to (windows[].ptid).
+ *
+ * Time windows must be strictly contiguous, i.e. windows[n].offset +
+ * windows[n].duration shall equal windows[n + 1].offset.
+ * If windows[].ptid is in the range
+ * [0..CONFIG_XENO_OPT_SCHED_TP_NRPART-1], SCHED_TP threads which
+ * belong to the partition being referred to may run for the duration
+ * of the time window.
+ *
+ * Time holes may be defined using windows assigned to the pseudo
+ * partition #-1, during which no SCHED_TP threads may be scheduled.
+ *
+ * - config.tp.nr_windows should define the number of elements present
+ * in the config.tp.windows[] array.
+ *
+ * @param len size of the configuration data (in bytes).
+ *
+ * @return 0 on success;
+ * @return an error number if:
+ * - EINVAL, @a cpu is invalid, @a policy is different from SCHED_TP,
+ * SCHED_TP support is not compiled in (see CONFIG_XENO_OPT_SCHED_TP),
+ * @a len is zero, or @a p contains invalid parameters.
+ * - ENOMEM, lack of memory to perform the operation.
+ */
+int sched_setconfig_np(int cpu, int policy,
+                      union sched_config *config, size_t len)
+{
+       int ret;
+
+       switch (policy) {
+       case SCHED_TP:
+               ret = set_tp_config(cpu, config, len);
+               break;
+       default:
+               ret = EINVAL;
+       }
+
+       return ret;
+}
+
 /*@}*/
 
 EXPORT_SYMBOL_GPL(sched_get_priority_min);
@@ -497,3 +659,4 @@ EXPORT_SYMBOL_GPL(pthread_getschedparam_ex);
 EXPORT_SYMBOL_GPL(pthread_setschedparam);
 EXPORT_SYMBOL_GPL(pthread_setschedparam_ex);
 EXPORT_SYMBOL_GPL(sched_yield);
+EXPORT_SYMBOL_GPL(sched_setconfig_np);
diff --git a/ksrc/skins/posix/syscall.c b/ksrc/skins/posix/syscall.c
index a30ee8f..49ed764 100644
--- a/ksrc/skins/posix/syscall.c
+++ b/ksrc/skins/posix/syscall.c
@@ -2829,6 +2829,47 @@ static int __munmap_epilogue(struct pt_regs *regs)
 
 #endif /* !CONFIG_XENO_OPT_POSIX_SHM */
 
+#ifdef CONFIG_XENO_OPT_SCHED_TP
+/*
+ * int __sched_setconfig_np(int cpu, int policy, union sched_config *p, size_t 
len)
+ */
+static int __sched_setconfig_np(struct pt_regs *regs)
+{
+       union sched_config __user *u_config, *buf;
+       int len, ret, cpu, policy;
+
+       cpu = __xn_reg_arg1(regs);
+       if (cpu < 0 || cpu >= NR_CPUS || !cpu_online(cpu))
+               return -EINVAL;
+
+       policy = __xn_reg_arg2(regs);
+       u_config = (union sched_config __user *)__xn_reg_arg3(regs);
+       len = __xn_reg_arg4(regs);
+       if (len == 0)
+               return -EINVAL;
+
+       buf = xnmalloc(len);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       if (__xn_safe_copy_from_user(buf, (void __user *)u_config, len)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       ret = -sched_setconfig_np(cpu, policy, buf, len);
+out:
+       xnfree(buf);
+
+       return ret;
+}
+
+#else /* !CONFIG_XENO_OPT_SCHED_TP */
+
+#define __sched_setconfig_np        __pse51_call_not_available
+
+#endif /* !CONFIG_XENO_OPT_SCHED_TP */
+
 int __pse51_call_not_available(struct pt_regs *regs)
 {
        return -ENOSYS;
@@ -2940,6 +2981,7 @@ static xnsysent_t __systab[] = {
        [__pse51_condattr_setpshared] =
            {&__pthread_condattr_setpshared, __xn_exec_any},
        [__pse51_select] = {&__select, __xn_exec_primary},
+       [__pse51_sched_setconfig_np] = {&__sched_setconfig_np, __xn_exec_any},
 };
 
 static void __shadow_delete_hook(xnthread_t *thread)
diff --git a/ksrc/skins/posix/thread_attr.c b/ksrc/skins/posix/thread_attr.c
index 6b9192f..8d25e51 100644
--- a/ksrc/skins/posix/thread_attr.c
+++ b/ksrc/skins/posix/thread_attr.c
@@ -406,7 +406,7 @@ int pthread_attr_setinheritsched(pthread_attr_t * attr, int 
inheritsched)
  * Threads created with the attribute object @a attr use the value of this
  * attribute as scheduling policy if the @a inheritsched attribute is set to
  * PTHREAD_EXPLICIT_SCHED. The value of this attribute is one of SCHED_FIFO,
- * SCHED_RR, SCHED_SPORADIC or SCHED_OTHER.
+ * SCHED_RR, SCHED_SPORADIC, SCHED_TP or SCHED_OTHER.
  *
  * @param attr attribute object;
  *
@@ -449,7 +449,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t * 
attr, int *policy)
  * Threads created with the attribute object @a attr use the value of this
  * attribute as scheduling policy if the @a inheritsched attribute is set to
  * PTHREAD_EXPLICIT_SCHED. The value of this attribute is one of SCHED_FIFO,
- * SCHED_RR, SCHED_SPORADIC or SCHED_OTHER.
+ * SCHED_RR, SCHED_SPORADIC, SCHED_TP or SCHED_OTHER.
  *
  * @param attr attribute object;
  *
@@ -477,6 +477,7 @@ int pthread_attr_setschedpolicy(pthread_attr_t * attr, int 
policy)
        case SCHED_FIFO:
        case SCHED_RR:
        case SCHED_SPORADIC:
+       case SCHED_TP:
 
                break;
        }
@@ -514,7 +515,8 @@ int pthread_attr_setschedpolicy(pthread_attr_t * attr, int 
policy)
  * priorities range from 1 to 99.
  *
  * pthread_attr_getschedparam_ex() should be used to retrieve the
- * parameters for extended scheduling classes, such as SCHED_SPORADIC.
+ * parameters for extended scheduling classes, such as SCHED_SPORADIC
+ * or SCHED_TP.
  *
  * @param attr attribute object;
  *
@@ -557,8 +559,8 @@ int pthread_attr_getschedparam(const pthread_attr_t * attr,
  * or additional POSIX scheduling policies, which are not available
  * with the host Linux environment.
  *
- * Typically, SCHED_SPORADIC parameters can be retrieved from this
- * call.
+ * Typically, SCHED_SPORADIC or SCHED_TP parameters can be retrieved
+ * from this call.
  *
  * @param attr attribute object;
  *
@@ -654,7 +656,8 @@ int pthread_attr_setschedparam(pthread_attr_t * attr,
  * or additional POSIX scheduling policies, which are not available
  * with the host Linux environment.
  *
- * Typically, SCHED_SPORADIC parameters can be set using this call.
+ * Typically, SCHED_SPORADIC or SCHED_TP parameters can be set using
+ * this call.
  *
  * @param attr attribute object;
  *
diff --git a/src/skins/posix/thread.c b/src/skins/posix/thread.c
index 5e9dc63..f83e06f 100644
--- a/src/skins/posix/thread.c
+++ b/src/skins/posix/thread.c
@@ -316,6 +316,14 @@ int pthread_set_name_np(pthread_t thread, const char *name)
                                  __pse51_thread_set_name, thread, name);
 }
 
+int sched_setconfig_np(int cpu, int policy,
+                      union sched_config *config, size_t len)
+{
+       return -XENOMAI_SKINCALL4(__pse51_muxid,
+                                 __pse51_sched_setconfig_np,
+                                 cpu, policy, config, len);
+}
+
 int __wrap_pthread_kill(pthread_t thread, int sig)
 {
        int err;
diff --git a/src/testsuite/unit/Makefile.am b/src/testsuite/unit/Makefile.am
index 4734e04..b6317d3 100644
--- a/src/testsuite/unit/Makefile.am
+++ b/src/testsuite/unit/Makefile.am
@@ -11,7 +11,8 @@ test_PROGRAMS = \
        cond-torture-posix \
        cond-torture-native \
        check-vdso \
-       rtdm
+       rtdm \
+       sched-tp
 
 arith_SOURCES = arith.c arith-noinline.c arith-noinline.h
 
@@ -119,3 +120,16 @@ rtdm_LDADD = \
        ../../skins/native/libnative.la \
        ../../skins/common/libxenomai.la \
        -lpthread -lrt -lm
+
+sched_tp_SOURCES = sched-tp.c
+
+sched_tp_CPPFLAGS = \
+       -I$(top_srcdir)/include/posix @XENO_USER_CFLAGS@ -g -DXENO_POSIX \
+       -I$(top_srcdir)/include
+
+sched_tp_LDFLAGS = $(XENO_POSIX_WRAPPERS) @XENO_USER_LDFLAGS@
+
+sched_tp_LDADD = \
+       ../../skins/posix/libpthread_rt.la \
+       ../../skins/common/libxenomai.la \
+       -lpthread -lrt -lm
diff --git a/src/testsuite/unit/sched-tp.c b/src/testsuite/unit/sched-tp.c
new file mode 100644
index 0000000..db94991
--- /dev/null
+++ b/src/testsuite/unit/sched-tp.c
@@ -0,0 +1,164 @@
+/*
+ * SCHED_TP setup test.
+ *
+ * Copyright (C) Philippe Gerum <r...@xenomai.org>
+ *
+ * Released under the terms of GPLv2.
+ */
+
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <sched.h>
+#include <errno.h>
+#include <error.h>
+
+pthread_t threadA, threadB, threadC;
+
+sem_t barrier;
+
+void *thread_body(void *arg)
+{
+       pthread_t me = pthread_self();
+       struct sched_param_ex param;
+       struct timespec ts;
+       int ret, part;
+
+       part = (int)(long)arg;
+       param.sched_priority = 50 - part;
+       param.sched_tp_partition = part;
+       ret = pthread_setschedparam_ex(me, SCHED_TP, &param);
+       if (ret)
+               error(1, ret, "pthread_setschedparam_ex");
+
+       sem_wait(&barrier);
+       sem_post(&barrier);
+
+       for (;;) {
+               putchar('A' + part);
+               fflush(stdout);
+               ts.tv_sec = 0;
+               ts.tv_nsec = 10000000;
+               clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
+       }
+}
+
+void cleanup(int sig)
+{
+       pthread_cancel(threadC);
+       pthread_cancel(threadB);
+       pthread_cancel(threadA);
+       signal(sig, SIG_DFL);
+       pthread_join(threadC, NULL);
+       pthread_join(threadB, NULL);
+       pthread_join(threadA, NULL);
+}
+
+static void __create_thread(pthread_t *tid, const char *name, int seq)
+{
+       struct sched_param param;
+       pthread_attr_t attr;
+       int ret;
+
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+       pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+       pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+       pthread_attr_setschedparam(&attr, &param);
+       pthread_attr_setstacksize(&attr, 64*1024);
+       ret = pthread_create(tid, &attr, thread_body, (void *)(long)seq);
+       if (ret)
+               error(1, ret, "pthread_create");
+
+       pthread_attr_destroy(&attr);
+       pthread_set_name_np(*tid, name);
+}
+
+#define create_thread(tid, n) __create_thread(&(tid), # tid, n)
+#define NR_WINDOWS  4
+
+int main(int argc, char **argv)
+{
+       sigset_t mask, oldmask;
+       union sched_config *p;
+       size_t len;
+       int ret;
+
+       mlockall(MCL_CURRENT | MCL_FUTURE);
+
+       /*
+        * For a recurring global time frame of 400 ms, we define a TP
+        * schedule as follows:
+        *
+        * - thread(s) assigned to partition #2 (tag C) shall be
+        * allowed to run for 100 ms, when the next global time frame
+        * begins.
+        *
+        * - thread(s) assigned to partition #1 (tag B) shall be
+        * allowed to run for 50 ms, after the previous time slot
+        * ends.
+        *
+        * - thread(s) assigned to partition #0 (tag A) shall be
+        * allowed to run for 20 ms, after the previous time slot
+        * ends.
+        *
+        * - when the previous time slot ends, no TP thread shall be
+        * allowed to run until the global time frame ends (special
+        * setting of ptid == -1), i.e. 230 ms.
+        */
+       len = sched_tp_confsz(NR_WINDOWS);
+       p = malloc(len);
+       if (p == NULL)
+               error(1, ENOMEM, "malloc");
+
+       p->tp.nr_windows = NR_WINDOWS;
+       p->tp.windows[0].offset.tv_sec = 0;
+       p->tp.windows[0].offset.tv_nsec = 0;
+       p->tp.windows[0].duration.tv_sec = 0;
+       p->tp.windows[0].duration.tv_nsec = 100000000;
+       p->tp.windows[0].ptid = 2;
+       p->tp.windows[1].offset.tv_sec = 0;
+       p->tp.windows[1].offset.tv_nsec = 100000000;
+       p->tp.windows[1].duration.tv_sec = 0;
+       p->tp.windows[1].duration.tv_nsec = 50000000;
+       p->tp.windows[1].ptid = 1;
+       p->tp.windows[2].offset.tv_sec = 0;
+       p->tp.windows[2].offset.tv_nsec = 150000000;
+       p->tp.windows[2].duration.tv_sec = 0;
+       p->tp.windows[2].duration.tv_nsec = 20000000;
+       p->tp.windows[2].ptid = 0;
+       p->tp.windows[3].offset.tv_sec = 0;
+       p->tp.windows[3].offset.tv_nsec = 170000000;
+       p->tp.windows[3].duration.tv_sec = 0;
+       p->tp.windows[3].duration.tv_nsec = 230000000;
+       p->tp.windows[3].ptid = -1;
+
+       /* Assign the TP schedule to CPU #0 */
+       ret = sched_setconfig_np(0, SCHED_TP, p, len);
+       if (ret)
+               error(1, ret, "sched_setconfig_np");
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       signal(SIGINT, cleanup);
+       sigaddset(&mask, SIGTERM);
+       signal(SIGTERM, cleanup);
+       sigaddset(&mask, SIGHUP);
+       signal(SIGHUP, cleanup);
+       pthread_sigmask(SIG_BLOCK, &mask, &oldmask);
+
+       sem_init(&barrier, 0, 0);
+       create_thread(threadA, 0);
+       create_thread(threadB, 1);
+       create_thread(threadC, 2);
+       sem_post(&barrier);
+
+       sigsuspend(&oldmask);
+
+       return 0;
+}


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to