From 31ed856e2e8dce5f579c97b41e136dc03c2a9319 Mon Sep 17 00:00:00 2001 From: Tanya Amert Date: Tue, 13 Oct 2020 22:26:16 -0400 Subject: Added (unused) inh_res field to extended reservations, to be used for priority inheritance. --- litmus/reservations/gedf_reservation.c | 143 ++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 3 deletions(-) (limited to 'litmus') diff --git a/litmus/reservations/gedf_reservation.c b/litmus/reservations/gedf_reservation.c index 6d713d95131b..e16be7de4902 100644 --- a/litmus/reservations/gedf_reservation.c +++ b/litmus/reservations/gedf_reservation.c @@ -694,6 +694,63 @@ static void gedf_env_release_jobs(rt_domain_t* rt, struct bheap* res) #include #include +/* called with IRQs off */ +static void set_priority_inheritance(struct task_struct* t, struct task_struct* prio_inh) +{ + struct gedf_cpu_entry* linked_on; + int check_preempt = 0; + + struct reservation *t_res = (struct reservation *) tsk_rt(t)->plugin_state; + struct reservation *prio_inh_res = (struct reservation *) tsk_rt(prio_inh)->plugin_state; + + struct reservation_environment *env = t_res->par_env; + + struct gedf_reservation_environment *gedf_env; + gedf_env = container_of(env, struct gedf_reservation_environment, env); + + raw_spin_lock(&gedf_env->domain.ready_lock); + + printk("Task %d had inherited prio=%llu, now will be prio=%llu\n", + t->pid, t_res->inh_res ? t_res->inh_res->priority : 0, + prio_inh_res->priority); + TRACE_TASK(t, "inherits priority from %s/%d\n", prio_inh->comm, prio_inh->pid); + t_res->inh_res = prio_inh_res; + + // TODO tamert: actually try and handle the change to the priority + + raw_spin_unlock(&gedf_env->domain.ready_lock); +} + +/* called with IRQs off */ +static void clear_priority_inheritance(struct task_struct* t) +{ + struct reservation *t_res = (struct reservation *) tsk_rt(t)->plugin_state; + + struct reservation_environment *env = t_res->par_env; + + struct gedf_reservation_environment *gedf_env; + gedf_env = container_of(env, struct gedf_reservation_environment, env); + + struct gedf_reservation *gedf_res; + gedf_res = container_of(t_res, struct gedf_reservation, res); + + raw_spin_lock(&gedf_env->domain.ready_lock); + + /* A job only stops inheriting a priority when it releases a + * resource. Thus we can make the following assumption.*/ + int cpu = smp_processor_id(); + struct gedf_cpu_entry *entry = &gedf_env->cpu_entries[cpu]; + BUG_ON(entry->scheduled != gedf_res); + + TRACE_TASK(t, "priority restored\n"); + t_res->inh_res = NULL; + + // TODO tamert: reschedule if necessary + // (the priority was effectively lowered) + + raw_spin_unlock(&gedf_env->domain.ready_lock); +} + /* ******************** OMLP support ********************** */ /* struct for semaphore with priority inheritance */ @@ -705,6 +762,7 @@ struct omlp_semaphore { /* highest-priority waiter */ struct task_struct *hp_waiter; + struct reservation *hp_waiter_res; /* FIFO queue of waiting tasks */ wait_queue_head_t fifo_wait; @@ -757,6 +815,43 @@ static struct task_struct* omlp_dequeue(struct omlp_semaphore *sem) return first; } +/* caller is responsible for locking */ +static struct task_struct* omlp_find_hp_waiter(struct omlp_semaphore *sem, + struct task_struct* skip) +{ + struct list_head *pos; + struct task_struct *queued, *found = NULL; + struct reservation *q_res, *f_res = NULL; + + /* check FIFO queue first */ + list_for_each(pos, &sem->fifo_wait.task_list) { + queued = (struct task_struct*) list_entry(pos, wait_queue_t, + task_list)->private; + + /* Compare task prios, find high prio task. */ + q_res = (struct reservation *) tsk_rt(queued)->plugin_state; + if (queued != skip && (!f_res || higher_res_prio(f_res, q_res))) { + f_res = q_res; + found = queued; + } + } + + /* check priority queue next */ + if (waitqueue_active(&sem->prio_wait)) { + /* first has highest priority */ + pos = sem->prio_wait.task_list.next; + queued = (struct task_struct*) list_entry(pos, wait_queue_t, + task_list)->private; + q_res = (struct reservation *) tsk_rt(queued)->plugin_state; + if (!f_res || (higher_res_prio(f_res, q_res))) { + f_res = q_res; + found = queued; + } + } + + return found; +} + int gedf_env_omlp_lock(struct litmus_lock* l) { struct task_struct* t = current; @@ -774,6 +869,9 @@ int gedf_env_omlp_lock(struct litmus_lock* l) struct reservation *t_res = (struct reservation *) tsk_rt(t)->plugin_state; + struct gedf_reservation *gedf_res = container_of(t_res, struct gedf_reservation, res); + BUG_ON(!gedf_res->linked_on && !bheap_node_in_heap(t_res->heap_node)); + spin_lock_irqsave(&sem->fifo_wait.lock, flags); if (sem->owner) { @@ -785,14 +883,25 @@ int gedf_env_omlp_lock(struct litmus_lock* l) omlp_enqueue(sem, &wait); - // TODO tamert: add priority inheritance + /* check if we need to activate priority inheritance */ + if (!sem->hp_waiter_res || higher_res_prio(sem->hp_waiter_res, t_res)) { + sem->hp_waiter = t; + sem->hp_waiter_res = t_res; + struct reservation *o_res = (struct reservation *) tsk_rt(sem->owner)->plugin_state; + if (higher_res_prio(o_res, t_res)) { + set_priority_inheritance(sem->owner, sem->hp_waiter); + } + } TS_LOCK_SUSPEND; /* release lock before sleeping */ spin_unlock_irqrestore(&sem->fifo_wait.lock, flags); - schedule(); + BUG_ON(!gedf_res->linked_on && !bheap_node_in_heap(t_res->heap_node)); + + schedule(); // will have issues if the reservation + // is not linked or on the ready queue (wtf?!) TS_LOCK_RESUME; @@ -835,7 +944,30 @@ static int gedf_env_omlp_unlock(struct litmus_lock* l) sem->owner = next; TRACE_CUR("lock ownership passed to %s/%d\n", next->comm, next->pid); - // TODO tamert: add priority inheritance + struct reservation *n_res = (struct reservation *) tsk_rt(next)->plugin_state; + + /* determine new hp_waiter if necessary */ + if (next == sem->hp_waiter) { + TRACE_TASK(next, "was highest-prio waiter\n"); + /* next has the highest priority --- it doesn't need to + * inherit. However, we need to make sure that the + * next-highest priority in the queue is reflected in + * hp_waiter. */ + sem->hp_waiter = omlp_find_hp_waiter(sem, next); + if (sem->hp_waiter) { + TRACE_TASK(sem->hp_waiter, "is new highest-prio waiter\n"); + sem->hp_waiter_res = (struct reservation *) tsk_rt(sem->hp_waiter)->plugin_state; + } + else { + TRACE("no further waiters\n"); + sem->hp_waiter_res = NULL; + } + } else { + /* Well, if next is not the highest-priority waiter, + * then it ought to inherit the highest-priority + * waiter's priority. */ + set_priority_inheritance(next, sem->hp_waiter); + } /* wake up next */ wake_up_process(next); @@ -843,6 +975,10 @@ static int gedf_env_omlp_unlock(struct litmus_lock* l) /* becomes available */ sem->owner = NULL; + /* we lose the benefit of priority inheritance (if any) */ + if (((struct reservation *)tsk_rt(t)->plugin_state)->inh_res) + clear_priority_inheritance(t); + out: spin_unlock_irqrestore(&sem->fifo_wait.lock, flags); @@ -891,6 +1027,7 @@ static struct litmus_lock* gedf_env_new_omlp(void) sem->owner = NULL; sem->hp_waiter = NULL; + sem->hp_waiter_res = NULL; init_waitqueue_head(&sem->fifo_wait); init_waitqueue_head(&sem->prio_wait); sem->litmus_lock.ops = &gedf_env_omlp_lock_ops; -- cgit v1.2.2