/* Operations and structures for dealing with generic priority inheritance. */ #include <litmus/litmus.h> #include <litmus/prio_sem.h> #include <litmus/sched_plugin.h> /* Add a record to the pi sem history stack. * * Recommend that inh == tsk for "no inheritance", though this * is up to the pi sem protocol implementation. inh could be * NULL as long as the protocol implementation expects it. */ void push_pi_sem( struct task_struct *tsk, struct task_struct *inh, struct pi_semaphore *sem) { sem->stack_node.inh_task = inh; /* list_add() needs node to be initialized properly. Node may * not be initialized yet. */ INIT_LIST_HEAD(&sem->stack_node.list); list_add_tail(&tsk->rt_param.pi_sem_stack, &sem->stack_node.list); TRACE_TASK(tsk, "Pushed semaphore %p with inheritance from task %d\n", sem, inh->pid); } /* Removes the last semaphore record. */ void pop_pi_sem(struct task_struct *tsk) { int empty = list_empty(&tsk->rt_param.pi_sem_stack); WARN_ON(empty); if(!empty) { pi_sem_record_t *rec = list_entry(tsk->rt_param.pi_sem_stack.prev, pi_sem_record_t, list); list_del(&rec->list); TRACE_TASK(tsk, "Popped sem/inh record %p / %d.\n", container_of(rec, struct pi_semaphore, stack_node), rec->inh_task->pid); } } /* Get a pointer to the last semaphore pushed on to the stack. * Returns NULL if there is no record. */ pi_sem_record_t* peek_pi_sem(struct task_struct *tsk) { if(!list_empty(&tsk->rt_param.pi_sem_stack)) { pi_sem_record_t *rec = list_entry(tsk->rt_param.pi_sem_stack.prev, pi_sem_record_t, list); return rec; } return NULL; } /* Update priority inheritance. */ int update_pi_sem( struct task_struct *tsk, struct task_struct *inh, struct pi_semaphore *sem) { int success = 0; struct list_head *pos, *next; pi_sem_record_t *rec; /* Though we have a reference to the semaphore (sem), we need * to search through tsk's stack to validate that tsk actually * holds sem. If tsk holds sem, then sem will be in its stack. * * TODO: Add function pointer hooks to pi_semaphore for operations * such as "int is_holder(struct task_struct *tsk)". pi_semaphore * does not track its holder(s), though concrete protocols may, * providing more efficient validation methods than this stack search. * Another function may be "pi_sem_record_t* get_record(...)" if the * semaphore protocol supports multiple holders (though * pi_semaphore.stack_node will probably go unused or replaced in * such cases). */ /* Assuming a sane locking order, the lock we're looking for * is probably towards (at) the end. */ list_for_each_prev_safe(pos, next, &tsk->rt_param.pi_sem_stack) { struct pi_semaphore* which_sem; rec = list_entry(pos, pi_sem_record_t, list); which_sem = container_of(rec, struct pi_semaphore, stack_node); if(which_sem == sem) { TRACE_TASK(tsk, "Updating inheritance from %d to %d on sem %p\n", rec->inh_task->pid, inh->pid, sem); rec->inh_task = inh; success = 1; break; } } if(!success) { TRACE_TASK(tsk, "Could not find record for sem %p to update inheritance.\n", sem); } return success; } /* Removes a record from the semaphore stack if it exists. * * Note: pop_pi_sem() may be more appropriate if total ordering can be * guaranteed. */ int remove_pi_sem(struct task_struct *tsk, struct pi_semaphore *sem) { int success = 0; struct list_head *pos, *next; pi_sem_record_t *rec; /* Though we have a reference to the semaphore (sem), we need * to search through tsk's stack to validate that tsk actually * holds sem. If tsk holds sem, then sem will be in its stack. * * TODO: Add function pointer hooks to pi_semaphore for operations * such as "int is_holder(struct task_struct *tsk)". pi_semaphore * does not track its holder(s), though concrete protocols may, * providing more efficient validation methods than this stack search. * Another function may be "pi_sem_record_t* get_record(...)" if the * semaphore protocol supports multiple holders (though * pi_semaphore.stack_node will probably go unused or replaced in * such cases). */ /* Assuming a sane locking order, the lock we're looking for * is probably towards (at) the end. */ list_for_each_prev_safe(pos, next, &tsk->rt_param.pi_sem_stack) { struct pi_semaphore* which_sem; rec = list_entry(pos, pi_sem_record_t, list); which_sem = container_of(rec, struct pi_semaphore, stack_node); if(which_sem == sem) { TRACE_TASK(tsk, "Removing semaphore stack record from %d with sem %p\n", rec->inh_task->pid, sem); list_del(&rec->list); success = 1; break; } } if(!success) { TRACE_TASK(tsk, "Could not find record for sem %p to remove.\n", sem); } return success; } /* Returns true of tsk holds ANY pi semaphores (as reportable by the stack). * Function will return false if the protocol in use does not use the stack, * such as FMLP-Long, which uses rt_params.eff_priority. */ int has_pi_sem(struct task_struct *tsk) { return !list_empty(&tsk->rt_param.pi_sem_stack); }