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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Mon Dec 24 18:24:22 2012 +0100

cobalt: introduce application interface to the SCHED_TP policy

---

 include/cobalt/sched.h      |   51 +++++++++++--
 include/cobalt/syscall.h    |    1 +
 kernel/cobalt/syscall.c     |    1 +
 kernel/cobalt/thread.c      |  182 +++++++++++++++++++++++++++++++++++++++++--
 kernel/cobalt/thread.h      |    5 +
 lib/cobalt/thread.c         |    8 ++
 testsuite/latency/latency.c |   10 ++-
 testsuite/unit/Makefile.am  |   15 ++++
 testsuite/unit/Makefile.in  |   47 ++++++++++-
 testsuite/unit/sched-tp.c   |  170 ++++++++++++++++++++++++++++++++++++++++
 10 files changed, 472 insertions(+), 18 deletions(-)

diff --git a/include/cobalt/sched.h b/include/cobalt/sched.h
index f0f7c7e..b277cc1 100644
--- a/include/cobalt/sched.h
+++ b/include/cobalt/sched.h
@@ -50,15 +50,15 @@ int __sched_cpucount(size_t __setsize, const cpu_set_t 
*__setp);
 
 #ifndef SCHED_SPORADIC
 #define SCHED_SPORADIC         10
-#define sched_ss_low_priority  u.ss.__sched_low_priority
-#define sched_ss_repl_period   u.ss.__sched_repl_period
-#define sched_ss_init_budget   u.ss.__sched_init_budget
-#define sched_ss_max_repl      u.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 */
 
 #define SCHED_COBALT           42
 
-#define sched_rr_quantum       u.rr.__sched_rr_quantum
+#define sched_rr_quantum       sched_u.rr.__sched_rr_quantum
 
 struct __sched_ss_param {
        int __sched_low_priority;
@@ -71,14 +71,53 @@ struct __sched_rr_param {
        struct timespec __sched_rr_quantum;
 };
 
+#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;
        union {
                struct __sched_ss_param ss;
                struct __sched_rr_param rr;
-       } u;
+               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 /* !_COBALT_SCHED_H */
diff --git a/include/cobalt/syscall.h b/include/cobalt/syscall.h
index f6a9982..7705bb9 100644
--- a/include/cobalt/syscall.h
+++ b/include/cobalt/syscall.h
@@ -105,6 +105,7 @@
 #define sc_cobalt_event_wait            90
 #define sc_cobalt_event_sync            91
 #define sc_cobalt_event_destroy         92
+#define sc_cobalt_sched_setconfig_np   93
 
 #ifdef __KERNEL__
 
diff --git a/kernel/cobalt/syscall.c b/kernel/cobalt/syscall.c
index c4177ab..3efe180 100644
--- a/kernel/cobalt/syscall.c
+++ b/kernel/cobalt/syscall.c
@@ -309,6 +309,7 @@ static struct xnsysent __systab[] = {
        SKINCALL_DEF(sc_cobalt_event_destroy, cobalt_event_destroy, any),
        SKINCALL_DEF(sc_cobalt_event_wait, cobalt_event_wait, primary),
        SKINCALL_DEF(sc_cobalt_event_sync, cobalt_event_sync, any),
+       SKINCALL_DEF(sc_cobalt_sched_setconfig_np, cobalt_sched_setconfig_np, 
any),
 };
 
 static void *cobalt_eventcb(int event, void *data)
diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
index 8051471..1cc2161 100644
--- a/kernel/cobalt/thread.c
+++ b/kernel/cobalt/thread.c
@@ -261,8 +261,8 @@ 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;
  *
@@ -317,6 +317,12 @@ pthread_getschedparam_ex(pthread_t tid, int *pol, struct 
sched_param_ex *par)
                goto unlock_and_exit;
        }
 #endif
+#ifdef CONFIG_XENO_OPT_SCHED_TP
+       if (base_class == &xnsched_class_tp) {
+               par->sched_tp_partition = thread->tps - 
thread->sched->tp.partitions;
+               goto unlock_and_exit;
+       }
+#endif
 
 unlock_and_exit:
 
@@ -723,6 +729,7 @@ pthread_setschedparam(pthread_t tid, int pol, const struct 
sched_param *par)
                /* falldown wanted */
        case SCHED_FIFO:
        case SCHED_SPORADIC:
+       case SCHED_TP:
                if (prio < COBALT_MIN_PRIORITY || prio > COBALT_MAX_PRIORITY)
                        goto fail;
                break;
@@ -757,8 +764,8 @@ pthread_setschedparam(pthread_t tid, int pol, const struct 
sched_param *par)
  * that supports Xenomai-specific or additional 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;
  *
@@ -782,7 +789,7 @@ pthread_setschedparam(pthread_t tid, int pol, const struct 
sched_param *par)
 static inline int pthread_setschedparam_ex(pthread_t tid, int pol,
                                           const struct sched_param_ex *par)
 {
-       union xnsched_policy_param param;
+       union xnsched_policy_param param __attribute__((unused));
        struct sched_param short_param;
        xnticks_t tslice;
        int ret = 0;
@@ -831,8 +838,15 @@ static inline int pthread_setschedparam_ex(pthread_t tid, 
int pol,
                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
        }
 
@@ -1304,6 +1318,7 @@ int cobalt_sched_min_prio(int policy)
        case SCHED_FIFO:
        case SCHED_RR:
        case SCHED_SPORADIC:
+       case SCHED_TP:
        case SCHED_COBALT:
                return COBALT_MIN_PRIORITY;
 
@@ -1321,6 +1336,7 @@ int cobalt_sched_max_prio(int policy)
        case SCHED_FIFO:
        case SCHED_RR:
        case SCHED_SPORADIC:
+       case SCHED_TP:
                return COBALT_MAX_PRIORITY;
 
        case SCHED_COBALT:
@@ -1346,6 +1362,158 @@ int cobalt_sched_yield(void)
        return policy == SCHED_OTHER;
 }
 
+#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 cobalt_sched_setconfig_np(int cpu, int policy,
+                             union sched_config __user *u_config, size_t len)
+{
+       int len, ret, cpu, policy;
+       union sched_config *buf;
+
+       if (cpu < 0 || cpu >= NR_CPUS || !cpu_online(cpu))
+               return -EINVAL;
+
+       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;
+       }
+
+       switch (policy) {
+       case SCHED_TP:
+               ret = -set_tp_config(cpu, buf, len);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+out:
+       xnfree(buf);
+
+       return ret;
+}
+
 void cobalt_threadq_cleanup(cobalt_kqueues_t *q)
 {
        xnholder_t *holder;
diff --git a/kernel/cobalt/thread.h b/kernel/cobalt/thread.h
index 81db737..61c161b 100644
--- a/kernel/cobalt/thread.h
+++ b/kernel/cobalt/thread.h
@@ -137,6 +137,11 @@ int cobalt_sched_min_prio(int policy);
 
 int cobalt_sched_max_prio(int policy);
 
+int cobalt_sched_setconfig_np(int cpu,
+                             int policy,
+                             union sched_config __user *u_config,
+                             size_t len);
+
 void cobalt_threadq_cleanup(cobalt_kqueues_t *q);
 
 void cobalt_thread_pkg_init(u_long rrperiod);
diff --git a/lib/cobalt/thread.c b/lib/cobalt/thread.c
index 1aaf4e2..c21883c 100644
--- a/lib/cobalt/thread.c
+++ b/lib/cobalt/thread.c
@@ -375,6 +375,14 @@ int pthread_probe_np(pid_t tid)
                                 sc_cobalt_thread_probe, tid);
 }
 
+int sched_setconfig_np(int cpu, int policy,
+                      union sched_config *config, size_t len)
+{
+       return -XENOMAI_SKINCALL4(__cobalt_muxid,
+                                 sc_cobalt_sched_setconfig_np,
+                                 cpu, policy, config, len);
+}
+
 int __wrap_pthread_kill(pthread_t thread, int sig)
 {
        int ret;
diff --git a/testsuite/latency/latency.c b/testsuite/latency/latency.c
index 77985c9..29759da 100644
--- a/testsuite/latency/latency.c
+++ b/testsuite/latency/latency.c
@@ -468,6 +468,8 @@ void faulthand(int sig)
        kill(getpid(), sig);
 }
 
+#ifdef CONFIG_XENO_COBALT
+
 static const char *reason_str[] = {
        [SIGDEBUG_UNDEFINED] = "latency: received SIGXCPU for unknown reason",
        [SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
@@ -480,7 +482,7 @@ static const char *reason_str[] = {
        "(period too short?)",
 };
 
-void sigdebug(int sig, siginfo_t *si, void *context)
+static void sigdebug(int sig, siginfo_t *si, void *context)
 {
        const char fmt[] = "Mode switch detected (reason: %s), aborting.\n"
                "Enable XENO_OPT_DEBUG_TRACE_RELAX to find the cause.\n";
@@ -512,10 +514,12 @@ void sigdebug(int sig, siginfo_t *si, void *context)
        kill(getpid(), sig);
 }
 
+#endif /* CONFIG_XENO_COBALT */
+
 int main(int argc, char *const *argv)
 {
+       struct sigaction sa __attribute__((unused));
        int cpu = 0, c, err, sig;
-       struct sigaction sa;
        char task_name[16];
        sigset_t mask;
 
@@ -653,10 +657,12 @@ int main(int argc, char *const *argv)
        sigaddset(&mask, SIGALRM);
        pthread_sigmask(SIG_BLOCK, &mask, NULL);
 
+#ifdef CONFIG_XENO_COBALT
        sigemptyset(&sa.sa_mask);
        sa.sa_sigaction = sigdebug;
        sa.sa_flags = SA_SIGINFO;
        sigaction(SIGDEBUG, &sa, NULL);
+#endif
 
        if (freeze_max) {
                /* If something goes wrong, we want to freeze the current
diff --git a/testsuite/unit/Makefile.am b/testsuite/unit/Makefile.am
index 1e5773f..ad3691f 100644
--- a/testsuite/unit/Makefile.am
+++ b/testsuite/unit/Makefile.am
@@ -13,6 +13,7 @@ coredep_lib = ../../lib/cobalt/libcobalt.la
 test_PROGRAMS += arith \
        mutex-torture \
        cond-torture \
+       sched-tp \
        check-vdso
 
 arith_SOURCES = arith.c arith-noinline.c arith-noinline.h
@@ -65,6 +66,20 @@ cond_torture_LDADD = \
        @XENO_USER_LDADD@               \
        -lpthread -lrt -lm
 
+sched_tp_SOURCES = sched-tp.c
+
+sched_tp_CPPFLAGS =                    \
+       @XENO_USER_CFLAGS@              \
+       -I$(top_srcdir)/include
+
+sched_tp_LDFLAGS = $(XENO_POSIX_WRAPPERS)
+
+sched_tp_LDADD = \
+       ../../lib/copperplate/libcopperplate.la \
+       $(coredep_lib)                          \
+       @XENO_USER_LDADD@                       \
+       -lpthread -lrt -lm
+
 check_vdso_SOURCES = check-vdso.c
 
 check_vdso_CPPFLAGS =                  \
diff --git a/testsuite/unit/Makefile.in b/testsuite/unit/Makefile.in
index 351e91b..7b26bcf 100644
--- a/testsuite/unit/Makefile.in
+++ b/testsuite/unit/Makefile.in
@@ -56,6 +56,7 @@ test_PROGRAMS = wakeup-time$(EXEEXT) rtdm$(EXEEXT) 
$(am__EXEEXT_1)
 @XENO_COBALT_TRUE@am__append_1 = arith \
 @XENO_COBALT_TRUE@     mutex-torture \
 @XENO_COBALT_TRUE@     cond-torture \
+@XENO_COBALT_TRUE@     sched-tp \
 @XENO_COBALT_TRUE@     check-vdso
 
 subdir = testsuite/unit
@@ -76,7 +77,8 @@ CONFIG_HEADER = $(top_builddir)/lib/include/xeno_config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 @XENO_COBALT_TRUE@am__EXEEXT_1 = arith$(EXEEXT) mutex-torture$(EXEEXT) \
-@XENO_COBALT_TRUE@     cond-torture$(EXEEXT) check-vdso$(EXEEXT)
+@XENO_COBALT_TRUE@     cond-torture$(EXEEXT) sched-tp$(EXEEXT) \
+@XENO_COBALT_TRUE@     check-vdso$(EXEEXT)
 am__installdirs = "$(DESTDIR)$(testdir)"
 PROGRAMS = $(test_PROGRAMS)
 am__arith_SOURCES_DIST = arith.c arith-noinline.c arith-noinline.h
@@ -128,6 +130,15 @@ rtdm_DEPENDENCIES = ../../lib/alchemy/libalchemy.la \
 rtdm_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(rtdm_LDFLAGS) \
        $(LDFLAGS) -o $@
+am__sched_tp_SOURCES_DIST = sched-tp.c
+@XENO_COBALT_TRUE@am_sched_tp_OBJECTS = sched_tp-sched-tp.$(OBJEXT)
+sched_tp_OBJECTS = $(am_sched_tp_OBJECTS)
+@XENO_COBALT_TRUE@sched_tp_DEPENDENCIES =  \
+@XENO_COBALT_TRUE@     ../../lib/copperplate/libcopperplate.la \
+@XENO_COBALT_TRUE@     $(am__DEPENDENCIES_1)
+sched_tp_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(sched_tp_LDFLAGS) \
+       $(LDFLAGS) -o $@
 am_wakeup_time_OBJECTS = wakeup_time-wakeup-time.$(OBJEXT)
 wakeup_time_OBJECTS = $(am_wakeup_time_OBJECTS)
 wakeup_time_DEPENDENCIES = ../../lib/alchemy/libalchemy.la \
@@ -149,12 +160,12 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) 
$(LIBTOOLFLAGS) \
        $(LDFLAGS) -o $@
 SOURCES = $(arith_SOURCES) $(check_vdso_SOURCES) \
        $(cond_torture_SOURCES) $(mutex_torture_SOURCES) \
-       $(rtdm_SOURCES) $(wakeup_time_SOURCES)
+       $(rtdm_SOURCES) $(sched_tp_SOURCES) $(wakeup_time_SOURCES)
 DIST_SOURCES = $(am__arith_SOURCES_DIST) \
        $(am__check_vdso_SOURCES_DIST) \
        $(am__cond_torture_SOURCES_DIST) \
        $(am__mutex_torture_SOURCES_DIST) $(rtdm_SOURCES) \
-       $(wakeup_time_SOURCES)
+       $(am__sched_tp_SOURCES_DIST) $(wakeup_time_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -375,6 +386,18 @@ CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
 @XENO_COBALT_TRUE@     @XENO_USER_LDADD@               \
 @XENO_COBALT_TRUE@     -lpthread -lrt -lm
 
+@XENO_COBALT_TRUE@sched_tp_SOURCES = sched-tp.c
+@XENO_COBALT_TRUE@sched_tp_CPPFLAGS = \
+@XENO_COBALT_TRUE@     @XENO_USER_CFLAGS@              \
+@XENO_COBALT_TRUE@     -I$(top_srcdir)/include
+
+@XENO_COBALT_TRUE@sched_tp_LDFLAGS = $(XENO_POSIX_WRAPPERS)
+@XENO_COBALT_TRUE@sched_tp_LDADD = \
+@XENO_COBALT_TRUE@     ../../lib/copperplate/libcopperplate.la \
+@XENO_COBALT_TRUE@     $(coredep_lib)                          \
+@XENO_COBALT_TRUE@     @XENO_USER_LDADD@                       \
+@XENO_COBALT_TRUE@     -lpthread -lrt -lm
+
 @XENO_COBALT_TRUE@check_vdso_SOURCES = check-vdso.c
 @XENO_COBALT_TRUE@check_vdso_CPPFLAGS = \
 @XENO_COBALT_TRUE@     @XENO_USER_CFLAGS@              \
@@ -511,6 +534,9 @@ mutex-torture$(EXEEXT): $(mutex_torture_OBJECTS) 
$(mutex_torture_DEPENDENCIES) $
 rtdm$(EXEEXT): $(rtdm_OBJECTS) $(rtdm_DEPENDENCIES) $(EXTRA_rtdm_DEPENDENCIES) 
        @rm -f rtdm$(EXEEXT)
        $(rtdm_LINK) $(rtdm_OBJECTS) $(rtdm_LDADD) $(LIBS)
+sched-tp$(EXEEXT): $(sched_tp_OBJECTS) $(sched_tp_DEPENDENCIES) 
$(EXTRA_sched_tp_DEPENDENCIES) 
+       @rm -f sched-tp$(EXEEXT)
+       $(sched_tp_LINK) $(sched_tp_OBJECTS) $(sched_tp_LDADD) $(LIBS)
 wakeup-time$(EXEEXT): $(wakeup_time_OBJECTS) $(wakeup_time_DEPENDENCIES) 
$(EXTRA_wakeup_time_DEPENDENCIES) 
        @rm -f wakeup-time$(EXEEXT)
        $(wakeup_time_LINK) $(wakeup_time_OBJECTS) $(wakeup_time_LDADD) $(LIBS)
@@ -527,6 +553,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ 
@am__quote@./$(DEPDIR)/cond_torture-cond-torture.Po@am__quote@
 @AMDEP_TRUE@@am__include@ 
@am__quote@./$(DEPDIR)/mutex_torture-mutex-torture.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtdm-rtdm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ 
@am__quote@./$(DEPDIR)/sched_tp-sched-tp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ 
@am__quote@./$(DEPDIR)/wakeup_time-wakeup-time.Po@am__quote@
 
 .c.o:
@@ -634,6 +661,20 @@ rtdm-rtdm.obj: rtdm.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) 
$(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) 
$(rtdm_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rtdm-rtdm.obj `if 
test -f 'rtdm.c'; then $(CYGPATH_W) 'rtdm.c'; else $(CYGPATH_W) 
'$(srcdir)/rtdm.c'; fi`
 
+sched_tp-sched-tp.o: sched-tp.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) 
$(sched_tp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sched_tp-sched-tp.o 
-MD -MP -MF $(DEPDIR)/sched_tp-sched-tp.Tpo -c -o sched_tp-sched-tp.o `test -f 
'sched-tp.c' || echo '$(srcdir)/'`sched-tp.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/sched_tp-sched-tp.Tpo 
$(DEPDIR)/sched_tp-sched-tp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='sched-tp.c' 
object='sched_tp-sched-tp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) 
$(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) 
$(sched_tp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o 
sched_tp-sched-tp.o `test -f 'sched-tp.c' || echo '$(srcdir)/'`sched-tp.c
+
+sched_tp-sched-tp.obj: sched-tp.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) 
$(sched_tp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT 
sched_tp-sched-tp.obj -MD -MP -MF $(DEPDIR)/sched_tp-sched-tp.Tpo -c -o 
sched_tp-sched-tp.obj `if test -f 'sched-tp.c'; then $(CYGPATH_W) 'sched-tp.c'; 
else $(CYGPATH_W) '$(srcdir)/sched-tp.c'; fi`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/sched_tp-sched-tp.Tpo 
$(DEPDIR)/sched_tp-sched-tp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='sched-tp.c' 
object='sched_tp-sched-tp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) 
$(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) 
$(sched_tp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o 
sched_tp-sched-tp.obj `if test -f 'sched-tp.c'; then $(CYGPATH_W) 'sched-tp.c'; 
else $(CYGPATH_W) '$(srcdir)/sched-tp.c'; fi`
+
 wakeup_time-wakeup-time.o: wakeup-time.c
 @am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) 
$(wakeup_time_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT 
wakeup_time-wakeup-time.o -MD -MP -MF $(DEPDIR)/wakeup_time-wakeup-time.Tpo -c 
-o wakeup_time-wakeup-time.o `test -f 'wakeup-time.c' || echo 
'$(srcdir)/'`wakeup-time.c
 @am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/wakeup_time-wakeup-time.Tpo 
$(DEPDIR)/wakeup_time-wakeup-time.Po
diff --git a/testsuite/unit/sched-tp.c b/testsuite/unit/sched-tp.c
new file mode 100644
index 0000000..15d5b4c
--- /dev/null
+++ b/testsuite/unit/sched-tp.c
@@ -0,0 +1,170 @@
+/*
+ * 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>
+
+int clock_nanosleep(clockid_t __clock_id, int __flags,
+                   __const struct timespec *__req,
+                   struct timespec *__rem);
+
+pthread_t threadA, threadB, threadC;
+
+sem_t barrier;
+
+static 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);
+       }
+
+       return NULL;
+}
+
+static 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