summaryrefslogtreecommitdiffstats
path: root/litmus/sched_gsn_edf.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/sched_gsn_edf.c')
-rw-r--r--litmus/sched_gsn_edf.c390
1 files changed, 384 insertions, 6 deletions
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c
index b76e46372c6a..d4635c74df1c 100644
--- a/litmus/sched_gsn_edf.c
+++ b/litmus/sched_gsn_edf.c
@@ -14,6 +14,7 @@
14#include <linux/sched/signal.h> 14#include <linux/sched/signal.h>
15#include <linux/sched/topology.h> 15#include <linux/sched/topology.h>
16#include <linux/slab.h> 16#include <linux/slab.h>
17#include <linux/sched/signal.h>
17 18
18#include <litmus/debug_trace.h> 19#include <litmus/debug_trace.h>
19#include <litmus/litmus.h> 20#include <litmus/litmus.h>
@@ -22,6 +23,7 @@
22#include <litmus/edf_common.h> 23#include <litmus/edf_common.h>
23#include <litmus/sched_trace.h> 24#include <litmus/sched_trace.h>
24#include <litmus/trace.h> 25#include <litmus/trace.h>
26#include <litmus/wait.h>
25 27
26#include <litmus/preempt.h> 28#include <litmus/preempt.h>
27#include <litmus/budget.h> 29#include <litmus/budget.h>
@@ -757,6 +759,9 @@ struct fmlp_semaphore {
757 759
758 /* FIFO queue of waiting tasks */ 760 /* FIFO queue of waiting tasks */
759 wait_queue_head_t wait; 761 wait_queue_head_t wait;
762
763 struct hrtimer budgeting_timer;
764 lt_t enforce_time;
760}; 765};
761 766
762static inline struct fmlp_semaphore* fmlp_from_lock(struct litmus_lock* lock) 767static inline struct fmlp_semaphore* fmlp_from_lock(struct litmus_lock* lock)
@@ -764,6 +769,27 @@ static inline struct fmlp_semaphore* fmlp_from_lock(struct litmus_lock* lock)
764 return container_of(lock, struct fmlp_semaphore, litmus_lock); 769 return container_of(lock, struct fmlp_semaphore, litmus_lock);
765} 770}
766 771
772static enum hrtimer_restart bfmlp_budget_enforce(struct hrtimer *timer)
773{
774 struct fmlp_semaphore* sem =
775 container_of(timer, struct fmlp_semaphore, budgeting_timer);
776 struct task_struct* t = sem->owner;
777
778
779 if (t == current)
780 send_sig(31, t, 0);
781 /* up to the task to:
782 * -detect if CS completed
783 * -perform fix_state if needed
784 * -unlock
785 * -set job to preemptive again
786 * -decide what to do next
787 */
788 TS_TIMER_LATENCY(sem->enforce_time);
789
790 return HRTIMER_NORESTART;
791}
792
767/* caller is responsible for locking */ 793/* caller is responsible for locking */
768struct task_struct* find_hp_waiter(struct fmlp_semaphore *sem, 794struct task_struct* find_hp_waiter(struct fmlp_semaphore *sem,
769 struct task_struct* skip) 795 struct task_struct* skip)
@@ -903,6 +929,25 @@ out:
903 return err; 929 return err;
904} 930}
905 931
932int gsnedf_fmlp_tstart(struct litmus_lock* l, lt_t budget)
933{
934 struct fmlp_semaphore* sem = fmlp_from_lock(l);
935
936 sem->enforce_time = litmus_clock() + budget;
937 hrtimer_start(&sem->budgeting_timer,
938 ns_to_ktime(sem->enforce_time),
939 HRTIMER_MODE_ABS_PINNED_HARD);
940 return 0;
941}
942
943int gsnedf_fmlp_tstop(struct litmus_lock* l)
944{
945 struct fmlp_semaphore* sem = fmlp_from_lock(l);
946
947 hrtimer_cancel(&sem->budgeting_timer);
948 return 0;
949}
950
906int gsnedf_fmlp_close(struct litmus_lock* l) 951int gsnedf_fmlp_close(struct litmus_lock* l)
907{ 952{
908 struct task_struct *t = current; 953 struct task_struct *t = current;
@@ -929,10 +974,12 @@ void gsnedf_fmlp_free(struct litmus_lock* lock)
929} 974}
930 975
931static struct litmus_lock_ops gsnedf_fmlp_lock_ops = { 976static struct litmus_lock_ops gsnedf_fmlp_lock_ops = {
932 .close = gsnedf_fmlp_close, 977 .close = gsnedf_fmlp_close,
933 .lock = gsnedf_fmlp_lock, 978 .lock = gsnedf_fmlp_lock,
934 .unlock = gsnedf_fmlp_unlock, 979 .unlock = gsnedf_fmlp_unlock,
935 .deallocate = gsnedf_fmlp_free, 980 .timer_start = gsnedf_fmlp_tstart,
981 .timer_stop = gsnedf_fmlp_tstop,
982 .deallocate = gsnedf_fmlp_free,
936}; 983};
937 984
938static struct litmus_lock* gsnedf_new_fmlp(void) 985static struct litmus_lock* gsnedf_new_fmlp(void)
@@ -947,6 +994,331 @@ static struct litmus_lock* gsnedf_new_fmlp(void)
947 sem->hp_waiter = NULL; 994 sem->hp_waiter = NULL;
948 init_waitqueue_head(&sem->wait); 995 init_waitqueue_head(&sem->wait);
949 sem->litmus_lock.ops = &gsnedf_fmlp_lock_ops; 996 sem->litmus_lock.ops = &gsnedf_fmlp_lock_ops;
997 hrtimer_init(&sem->budgeting_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
998 sem->budgeting_timer.function = bfmlp_budget_enforce;
999
1000 return &sem->litmus_lock;
1001}
1002
1003/* ****************************** B-OMLP support ************************** */
1004
1005struct omlp_semaphore {
1006 struct litmus_lock litmus_lock;
1007
1008 /* current resource holder */
1009 struct task_struct *owner;
1010
1011 /* highest-priority waiter */
1012 struct task_struct *hp_waiter;
1013
1014 /* FIFO queue of waiting tasks */
1015 wait_queue_head_t fifo_wait;
1016 /* Prio queue of waiting tasks */
1017 wait_queue_head_t prio_wait;
1018
1019 /* How many slots remaining in FIFO queue? */
1020 unsigned int num_free;
1021
1022 /* budgeting support */
1023 struct hrtimer budgeting_timer;
1024 lt_t enforce_time;
1025};
1026
1027static inline struct omlp_semaphore* omlp_from_lock(struct litmus_lock* lock)
1028{
1029 return container_of(lock, struct omlp_semaphore, litmus_lock);
1030}
1031
1032static enum hrtimer_restart bomlp_budget_enforce(struct hrtimer *timer)
1033{
1034 struct omlp_semaphore* sem =
1035 container_of(timer, struct omlp_semaphore, budgeting_timer);
1036 struct task_struct* t = sem->owner;
1037
1038 if (t == current)
1039 send_sig(31, t, 0);
1040 /* up to the task to:
1041 * -detect if CS completed
1042 * -perform fix_state if needed
1043 * -unlock
1044 * -set job to preemptive again
1045 * -decide what to do next
1046 */
1047 TS_TIMER_LATENCY(sem->enforce_time);
1048
1049 return HRTIMER_NORESTART;
1050}
1051
1052/* caller is responsible for locking */
1053static struct task_struct* omlp_find_hp_waiter(struct omlp_semaphore* sem,
1054 struct task_struct* skip)
1055{
1056 struct list_head* pos;
1057 struct task_struct *queued, *found = NULL;
1058
1059 /* check FIFO queue first */
1060 list_for_each(pos, &sem->fifo_wait.head) {
1061 queued = (struct task_struct*) list_entry(pos, wait_queue_entry_t,
1062 entry)->private;
1063
1064 /* Compare task prios, find high prio task. */
1065 if (queued != skip && edf_higher_prio(queued, found))
1066 found = queued;
1067 }
1068
1069 /* check priority queue next */
1070 if (waitqueue_active(&sem->prio_wait)) {
1071 /* first has highest priority */
1072 pos = sem->prio_wait.head.next;
1073 queued = (struct task_struct*) list_entry(pos, wait_queue_entry_t,
1074 entry)->private;
1075 if (edf_higher_prio(queued, found))
1076 found = queued;
1077 }
1078
1079 return found;
1080}
1081
1082/* already locked */
1083static void omlp_enqueue(struct omlp_semaphore* sem, prio_wait_queue_t* wait)
1084{
1085 if (sem->num_free > 0) {
1086 /* there is space in the FIFO queue */
1087 sem->num_free--;
1088 __add_wait_queue_entry_tail_exclusive(&sem->fifo_wait, &wait->wq);
1089 } else {
1090 /* nope, gotta go to the priority queue */
1091 __add_wait_queue_prio_exclusive(&sem->prio_wait, wait);
1092 }
1093}
1094
1095/* already locked */
1096static int omlp_move(struct omlp_semaphore* sem)
1097{
1098 struct list_head* first;
1099
1100 if (waitqueue_active(&sem->prio_wait)) {
1101 first = sem->prio_wait.head.next;
1102 list_move_tail(first, &sem->fifo_wait.head);
1103 return 1;
1104 }
1105 return 0;
1106}
1107
1108/* already locked */
1109static struct task_struct* omlp_dequeue(struct omlp_semaphore* sem)
1110{
1111 struct task_struct* first = __waitqueue_remove_first(&sem->fifo_wait);
1112
1113 /* don't replace tmp with omlp_move! shortcircuiting will break omlp for m=1 */
1114 int tmp = omlp_move(sem);
1115 if (first && !tmp)
1116 sem->num_free++;
1117 if (!first && tmp)
1118 first = __waitqueue_remove_first(&sem->fifo_wait);
1119 return first;
1120}
1121
1122int gsnedf_omlp_budgeted_lock(struct litmus_lock* l, lt_t fz_len)
1123{
1124 struct task_struct* t = current;
1125 struct omlp_semaphore* sem = omlp_from_lock(l);
1126 unsigned long flags;
1127 lt_t budget_used;
1128 lt_t budget_remaining;
1129 prio_wait_queue_t pwq;
1130
1131 if (!is_realtime(t))
1132 return -EPERM;
1133
1134 /* prevent nested lock acquisition -- not supported by global OMLP by default */
1135 if (tsk_rt(t)->num_locks_held)
1136 return -EBUSY;
1137
1138 spin_lock_irqsave(&sem->fifo_wait.lock, flags);
1139
1140 if (sem->owner) {
1141 /* resource is not free => must suspend and wait */
1142 litmus_current_budget(&budget_used, &budget_remaining);
1143 if (fz_len < budget_remaining) {
1144 /* Not enough budget for the CS => deny forbidden zone access */
1145 TRACE_CUR("failed forbidden zone check, %llu / %llu budget needed\n",
1146 budget_remaining, fz_len);
1147 spin_unlock_irqrestore(&sem->fifo_wait.lock, flags);
1148 return -EACCES;
1149 }
1150
1151 init_prio_waitqueue_entry(&pwq, t, get_deadline(t));
1152
1153 omlp_enqueue(sem, &pwq);
1154
1155 /* check if we need to activate priority inheritance */
1156 if (edf_higher_prio(t, sem->hp_waiter)) {
1157 sem->hp_waiter = t;
1158 if (edf_higher_prio(sem->hp_waiter, sem->owner))
1159 set_priority_inheritance(sem->owner, sem->hp_waiter);
1160 }
1161
1162 set_current_state(TASK_UNINTERRUPTIBLE);
1163
1164 TS_LOCK_SUSPEND;
1165
1166 /* release lock before sleeping */
1167 spin_unlock_irqrestore(&sem->fifo_wait.lock, flags);
1168
1169 schedule();
1170
1171 TS_LOCK_RESUME;
1172 } else {
1173 /* we now have lock */
1174 sem->owner = t;
1175 spin_unlock_irqrestore(&sem->fifo_wait.lock, flags);
1176 }
1177
1178 make_np(t);
1179 tsk_rt(t)->num_locks_held++;
1180
1181 return 0;
1182}
1183
1184int gsnedf_omlp_lock(struct litmus_lock* l)
1185{
1186 return gsnedf_omlp_budgeted_lock(l, ULLONG_MAX);
1187}
1188
1189int gsnedf_omlp_unlock(struct litmus_lock* l)
1190{
1191 struct task_struct* t = current;
1192 struct omlp_semaphore* sem = omlp_from_lock(l);
1193 struct task_struct* next;
1194 unsigned long flags;
1195
1196 if (sem->owner != t)
1197 return -EINVAL;
1198
1199 hrtimer_cancel(&sem->budgeting_timer);
1200
1201 spin_lock_irqsave(&sem->fifo_wait.lock, flags);
1202
1203 tsk_rt(t)->num_locks_held--;
1204
1205 next = omlp_dequeue(sem);
1206 /* check if there are jobs waiting for this resource */
1207 if (next) {
1208 /* next becomes the resource holder */
1209 sem->owner = next;
1210 TRACE_CUR("lock ownership passed to %s/%d\n", next->comm, next->pid);
1211
1212 if (next == sem->hp_waiter) {
1213 TRACE_TASK(next, "was highest-prio waiter\n");
1214 /* next has the highest priority --- it doesn't need to
1215 * inherit. However, we need to make sure that the
1216 * next-highest priority in the queue is reflected in
1217 * hp_waiter. */
1218 sem->hp_waiter = omlp_find_hp_waiter(sem, next);
1219 if (sem->hp_waiter)
1220 TRACE_TASK(sem->hp_waiter, "is new highest-prio waiter\n");
1221 else
1222 TRACE("no further waiters\n");
1223 } else {
1224 /* Well, if next is not the highest-priority waiter,
1225 * then it ought to inherit the highest-priority
1226 * waiter's priority. */
1227 set_priority_inheritance(next, sem->hp_waiter);
1228 }
1229
1230 /* wake up next */
1231 wake_up_process(next);
1232 } else {
1233 /* become available */
1234 sem->owner = NULL;
1235 }
1236
1237 /* we make ourself preemptive again and lose priority inheritance (if any) */
1238 take_np(t);
1239 clear_priority_inheritance(t);
1240
1241 spin_unlock_irqrestore(&sem->fifo_wait.lock, flags);
1242
1243 return 0;
1244}
1245
1246int gsnedf_omlp_tstart(struct litmus_lock* l, lt_t budget)
1247{
1248 struct omlp_semaphore* sem = omlp_from_lock(l);
1249
1250 sem->enforce_time = litmus_clock() + budget;
1251 hrtimer_start(&sem->budgeting_timer,
1252 ns_to_ktime(sem->enforce_time),
1253 HRTIMER_MODE_ABS_PINNED_HARD);
1254 return 0;
1255}
1256
1257int gsnedf_omlp_tstop(struct litmus_lock* l)
1258{
1259 struct omlp_semaphore* sem = omlp_from_lock(l);
1260
1261 hrtimer_cancel(&sem->budgeting_timer);
1262 return 0;
1263}
1264
1265int gsnedf_omlp_close(struct litmus_lock* l)
1266{
1267 struct task_struct* t = current;
1268 struct omlp_semaphore* sem = omlp_from_lock(l);
1269 unsigned long flags;
1270 int owner;
1271
1272 spin_lock_irqsave(&sem->fifo_wait.lock, flags);
1273
1274 owner = sem->owner == t;
1275
1276 spin_unlock_irqrestore(&sem->fifo_wait.lock, flags);
1277
1278 if (owner)
1279 gsnedf_omlp_unlock(l);
1280
1281 return 0;
1282}
1283
1284void gsnedf_omlp_free(struct litmus_lock* l)
1285{
1286 kfree(omlp_from_lock(l));
1287}
1288
1289static struct litmus_lock_ops gsnedf_omlp_lock_ops = {
1290 .close = gsnedf_omlp_close,
1291 .lock = gsnedf_omlp_lock,
1292 .budgeted_lock = gsnedf_omlp_budgeted_lock,
1293 .unlock = gsnedf_omlp_unlock,
1294 .timer_start = gsnedf_omlp_tstart,
1295 .timer_stop = gsnedf_omlp_tstop,
1296 .deallocate = gsnedf_omlp_free,
1297};
1298
1299static struct litmus_lock* gsnedf_new_omlp(void)
1300{
1301 struct omlp_semaphore* sem;
1302 int release_master =
1303#ifdef CONFIG_RELEASE_MASTER
1304 atomic_read(&release_master_cpu);
1305#else
1306 NO_CPU;
1307#endif
1308 int num_rt_cpus = num_online_cpus() - (release_master != NO_CPU);
1309
1310 sem = kmalloc(sizeof(*sem), GFP_KERNEL);
1311 if (!sem)
1312 return NULL;
1313
1314 sem->owner = NULL;
1315 sem->hp_waiter = NULL;
1316 init_waitqueue_head(&sem->fifo_wait);
1317 init_waitqueue_head(&sem->prio_wait);
1318 sem->litmus_lock.ops = &gsnedf_omlp_lock_ops;
1319 sem->num_free = num_rt_cpus;
1320 hrtimer_init(&sem->budgeting_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
1321 sem->budgeting_timer.function = bomlp_budget_enforce;
950 1322
951 return &sem->litmus_lock; 1323 return &sem->litmus_lock;
952} 1324}
@@ -970,7 +1342,13 @@ static long gsnedf_allocate_lock(struct litmus_lock **lock, int type,
970 else 1342 else
971 err = -ENOMEM; 1343 err = -ENOMEM;
972 break; 1344 break;
973 1345 case OMLP_SEM:
1346 /* Optimal Multiprocessor Locking Protocol */
1347 *lock = gsnedf_new_omlp();
1348 if (*lock)
1349 err = 0;
1350 else
1351 err = -ENOMEM;
974 }; 1352 };
975 1353
976 return err; 1354 return err;
@@ -1057,7 +1435,7 @@ static long gsnedf_deactivate_plugin(void)
1057 1435
1058/* Plugin object */ 1436/* Plugin object */
1059static struct sched_plugin gsn_edf_plugin __cacheline_aligned_in_smp = { 1437static struct sched_plugin gsn_edf_plugin __cacheline_aligned_in_smp = {
1060 .plugin_name = "GSN-EDF", 1438 .plugin_name = "GSN-EDF-BUDGETED",
1061 .finish_switch = gsnedf_finish_switch, 1439 .finish_switch = gsnedf_finish_switch,
1062 .task_new = gsnedf_task_new, 1440 .task_new = gsnedf_task_new,
1063 .complete_job = complete_job, 1441 .complete_job = complete_job,