From: Juri Lelli <juri.le...@gmail.com>

This patch adds the possibility to get the delivery of two signals
whenever there is a runtime overrun or a deadline miss, respectively.
The request is done through the sched_flags field within the sched_attr
structure.

Forward port of https://lkml.org/lkml/2009/10/16/170

Signed-off-by: Juri Lelli <juri.le...@gmail.com>
Signed-off-by: Claudio Scordino <clau...@evidence.eu.com>
Signed-off-by: Luca Abeni <luca.ab...@santannapisa.it>
Cc: Tommaso Cucinotta <tommaso.cucino...@sssup.it>
CC: Peter Zijlstra <pet...@infradead.org>
CC: Ingo Molnar <mi...@redhat.com>
CC: Thomas Gleixner <t...@linutronix.de>
Cc: Mathieu Poirier <mathieu.poir...@linaro.org>
---
 include/linux/sched.h          |  8 ++++++++
 include/uapi/linux/sched.h     |  2 ++
 kernel/sched/core.c            |  3 ++-
 kernel/sched/deadline.c        | 13 +++++++++++++
 kernel/time/posix-cpu-timers.c | 26 ++++++++++++++++++++++++++
 5 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0f897df..285d1b4 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -473,11 +473,19 @@ struct sched_dl_entity {
         * has not been executed yet. This flag is useful to avoid race
         * conditions between the inactive timer handler and the wakeup
         * code.
+        *
+        * @dl_overrun tells if the task asked to be informed about budget
+        * overruns.
+        *
+        * @dl_dmiss tells if the task asked to be informed about deadline
+        * misses.
         */
        int                             dl_throttled      : 1;
        int                             dl_boosted        : 1;
        int                             dl_yielded        : 1;
        int                             dl_non_contending : 1;
+       int                             dl_overrun        : 1;
+       int                             dl_dmiss          : 1;
 
        /*
         * Bandwidth enforcement timer. Each -deadline task has its
diff --git a/include/uapi/linux/sched.h b/include/uapi/linux/sched.h
index e2a6c7b..544be0c 100644
--- a/include/uapi/linux/sched.h
+++ b/include/uapi/linux/sched.h
@@ -48,5 +48,7 @@
  */
 #define SCHED_FLAG_RESET_ON_FORK       0x01
 #define SCHED_FLAG_RECLAIM             0x02
+#define SCHED_FLAG_DL_OVERRUN          0x04
+#define SCHED_FLAG_DL_DMISS            0x08
 
 #endif /* _UAPI_LINUX_SCHED_H */
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 97227df..d79df7a 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4041,7 +4041,8 @@ static int __sched_setscheduler(struct task_struct *p,
        }
 
        if (attr->sched_flags &
-               ~(SCHED_FLAG_RESET_ON_FORK | SCHED_FLAG_RECLAIM))
+               ~(SCHED_FLAG_RESET_ON_FORK | SCHED_FLAG_RECLAIM |
+                       SCHED_FLAG_DL_OVERRUN | SCHED_FLAG_DL_DMISS))
                return -EINVAL;
 
        /*
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 8d1b946..8c1aa61 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1154,6 +1154,17 @@ static void update_curr_dl(struct rq *rq)
 throttle:
        if (dl_runtime_exceeded(dl_se) || dl_se->dl_yielded) {
                dl_se->dl_throttled = 1;
+
+               /*
+                * If requested, inform the user about deadline misses and/or
+                * runtime overruns.
+                */
+               if (unlikely(dl_se->flags & SCHED_FLAG_DL_DMISS &&
+                            dl_time_before(dl_se->deadline, rq_clock(rq))))
+                       dl_se->dl_dmiss = 1;
+               if (dl_se->flags & SCHED_FLAG_DL_OVERRUN)
+                       dl_se->dl_overrun = 1;
+
                __dequeue_task_dl(rq, curr, 0);
                if (unlikely(dl_se->dl_boosted || !start_dl_timer(curr)))
                        enqueue_task_dl(rq, curr, ENQUEUE_REPLENISH);
@@ -2565,6 +2576,8 @@ void __dl_clear_params(struct task_struct *p)
        dl_se->dl_throttled = 0;
        dl_se->dl_yielded = 0;
        dl_se->dl_non_contending = 0;
+       dl_se->dl_overrun = 0;
+       dl_se->dl_dmiss = 0;
 }
 
 bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr)
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 8585ad6..f3616c5 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -13,6 +13,7 @@
 #include <linux/tick.h>
 #include <linux/workqueue.h>
 #include <linux/compat.h>
+#include <linux/sched/deadline.h>
 
 #include "posix-timers.h"
 
@@ -790,6 +791,22 @@ check_timers_list(struct list_head *timers,
        return 0;
 }
 
+static inline void check_dl_overrun(struct task_struct *tsk)
+{
+       if (tsk->dl.dl_overrun) {
+               tsk->dl.dl_overrun = 0;
+               pr_info("runtime overrun: %s[%d]\n",
+                               tsk->comm, task_pid_nr(tsk));
+               __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk);
+       }
+       if (tsk->dl.dl_dmiss) {
+               tsk->dl.dl_dmiss = 0;
+               pr_info("scheduling deadline miss: %s[%d]\n",
+                               tsk->comm, task_pid_nr(tsk));
+               __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk);
+       }
+}
+
 /*
  * Check for any per-thread CPU timers that have fired and move them off
  * the tsk->cpu_timers[N] list onto the firing list.  Here we update the
@@ -803,6 +820,9 @@ static void check_thread_timers(struct task_struct *tsk,
        u64 expires;
        unsigned long soft;
 
+       if (dl_task(tsk))
+               check_dl_overrun(tsk);
+
        /*
         * If cputime_expires is zero, then there are no active
         * per thread CPU timers.
@@ -905,6 +925,9 @@ static void check_process_timers(struct task_struct *tsk,
        struct task_cputime cputime;
        unsigned long soft;
 
+       if (dl_task(tsk))
+               check_dl_overrun(tsk);
+
        /*
         * If cputimer is not running, then there are no active
         * process wide timers (POSIX 1.b, itimers, RLIMIT_CPU).
@@ -1110,6 +1133,9 @@ static inline int fastpath_timer_check(struct task_struct 
*tsk)
                        return 1;
        }
 
+       if (dl_task(tsk) && (tsk->dl.dl_overrun || tsk->dl.dl_dmiss))
+               return 1;
+
        return 0;
 }
 
-- 
2.7.4

Reply via email to