int test_scen2_workerL(void *OS_UNUSED(param)) { int ret; /* take the ownership of mutex, as we would be owner of mtx H should boost * our prio during their lock for mtx */ ret = os_mtx_lock(&test_mtx[0]); test_assert(0 == ret); /* now signalize/wake up the H and M */ /* following call will cause context switch to H and prio boost of this task **/ os_sem_up(&test_sem[0]); /* once H will call os_mtx_lock we will return here (since it will block on * mtx). Since now we have effective prio equal to H (prio boost) following * call should not cause context switch to M */ os_sem_up(&test_sem[1]); /* unlock the mtx and reset the effective prio of this task to L * following call should switch context to H which ten will finish (exit the * task function). This should then cause context switch to M, which will * verify values in test_atomic[0] and also exit the task function. */ os_mtx_unlock(&test_mtx[0]); /* finally after yet another context switch we should return here * verify that M finished task function */ test_assert(2 == test_atomic[0]); return 0; }
static FFTW_WORKER worker(void *arg) { struct worker *ego = (struct worker *)arg; struct work *w; for (;;) { /* wait until work becomes available */ os_sem_down(&ego->ready); w = ego->w; /* !w->proc ==> terminate worker */ if (!w->proc) break; /* do the work */ w->proc(&w->d); /* signal that work is done */ os_sem_up(&ego->done); } /* termination protocol */ os_sem_up(&termination_semaphore); os_destroy_thread(); /* UNREACHABLE */ return 0; }
int test_scen4_workerL(void *OS_UNUSED(param)) { int ret; test_assert(0 == test_atomic[0]); test_atomic[0] = 1; /* lock mtx0 and mtx1 */ ret = os_mtx_lock(&test_mtx[0]); test_assert(0 == ret); ret = os_mtx_lock(&test_mtx[1]); test_assert(0 == ret); test_assert(1 == test_atomic[0]); test_atomic[0] = 2; /* switch context to M */ os_sem_up(&test_sem[0]); /* we will return from M */ test_assert(4 == test_atomic[0]); test_atomic[0] = 5; /* switch context to HM */ os_sem_up(&test_sem[1]); /* we will return from HM */ test_assert(6 == test_atomic[0]); test_atomic[0] = 7; /* switch context to H */ os_sem_up(&test_sem[2]); /* we will return from H */ test_assert(8 == test_atomic[0]); test_atomic[0] = 9; /* unlock mtx1, this should not cause switch to HM since we still holds mtx0 * on which M is blocked which in turn holds mtx2 on which H is blocked. So * following call should not make context switch since L should remain on * boosted prio = p(H) */ os_mtx_unlock(&test_mtx[1]); test_assert(9 == test_atomic[0]); test_atomic[0] = 10; /* the effective priority of this task should still be on H level */ test_assert(4 == task_worker[3].prio_current); /* unlock mtx0, there should be context switch to M */ os_mtx_unlock(&test_mtx[0]); /* we should switch from M */ test_assert(17 == test_atomic[0]); test_atomic[0] = 18; return 0; }
int test_scen3_workerL(void *OS_UNUSED(param)) { int ret; test_assert(0 == test_atomic[0]); test_atomic[0] = 1; /* lock mtx1 */ ret = os_mtx_lock(&test_mtx[1]); test_assert(0 == ret); test_assert(1 == test_atomic[0]); test_atomic[0] = 2; /* switch context to LM */ os_sem_up(&test_sem[1]); /* we will return here when LM will lock on mtx1 */ test_assert(4 == test_atomic[0]); test_atomic[0] = 5; /* also this means that L should now have p(LM) */ test_assert(2 == task_worker[3].prio_current); /* switch context to LM */ os_sem_up(&test_sem[0]); /* we will return here when H will lock on mtx1 */ test_assert(6 == test_atomic[0]); test_atomic[0] = 7; /* also this means that L should now have p(H) and LM also should have p(H) **/ test_assert(4 == task_worker[2].prio_current); test_assert(4 == task_worker[3].prio_current); /* try to woke up the M but this should not cause context switch */ os_sem_up(&test_sem[0]); test_assert(7 == test_atomic[0]); test_atomic[0] = 8; /* release mtx2, whis should cause switch to LM */ os_mtx_unlock(&test_mtx[1]); /* we will return here when all task will finish */ test_assert(13 == test_atomic[0]); test_atomic[0] = 14; /* also this means that L should now have original prio */ test_assert(1 == task_worker[3].prio_current); return 0; }
/** * test procedure for test1 task2 */ int test1_task_proc2(void *OS_UNUSED(param)) { int ret; /* wait until timeout - (if still exist the bug will not update the priomax * while wakup by timeout) */ ret = os_sem_down(&(worker_tasks[0].sem), 10); test_assert(OS_TIMEOUT == ret); /* signalize the same sem to wake up the task1 */ os_sem_up(&(worker_tasks[0].sem)); return 0; }
int task_proc(void* param) { int ret; unsigned idx = (unsigned)(size_t)param; while(task_data[idx].loop < TEST_CYCLES) { ++(task_data[idx].loop); os_sem_up(&(task_data[(idx + 1) % 2].sem)); ret = os_sem_down(&(task_data[idx].sem), OS_TIMEOUT_INFINITE); test_assert(0 == ret); } return 0; }
int test_scen6_workerM(void *OS_UNUSED(param)) { int ret; /* block on sem, allow L to progress */ ret = os_sem_down(&test_sem[0], OS_TIMEOUT_INFINITE); test_assert(0 == ret); test_assert(2 == test_atomic[0]); test_atomic[0] = 3; /* switch context to H */ os_sem_up(&test_sem[1]); /* finish test */ test_assert(7 == test_atomic[0]); test_atomic[0] = 8; return 0; }
int test_scen6_workerL(void *OS_UNUSED(param)) { int ret; test_assert(0 == test_atomic[0]); test_atomic[0] = 1; /* lock mtx0 and mtx1 */ ret = os_mtx_lock(&test_mtx[0]); test_assert(0 == ret); ret = os_mtx_lock(&test_mtx[1]); test_assert(0 == ret); test_assert(1 == test_atomic[0]); test_atomic[0] = 2; /* switch context to M */ os_sem_up(&test_sem[0]); /* we will return from H */ test_assert(4 == test_atomic[0]); test_atomic[0] = 5; /* unlock mtx0 we want to release mtx in the same order as we lock them (not * reverse order), in properly implemented priority inversion this should * wake up the task H since nothing more block it from running This is * allowed since mutex does not enforce any locking sequence. User should * prevent from making deadlock possible */ os_mtx_unlock(&test_mtx[0]); test_assert(8 == test_atomic[0]); test_atomic[0] = 9; /* finish test */ os_mtx_unlock(&test_mtx[1]); test_assert(9 == test_atomic[0]); test_atomic[0] = 10; return 0; }
int test_scen5_workerL(void *OS_UNUSED(param)) { int ret; test_assert(0 == test_atomic[0]); test_atomic[0] = 1; /* lock mtx0 and mtx1 */ ret = os_mtx_lock(&test_mtx[0]); test_assert(0 == ret); ret = os_mtx_lock(&test_mtx[1]); test_assert(0 == ret); test_assert(1 == test_atomic[0]); test_atomic[0] = 2; /* switch context to M */ os_sem_up(&test_sem[0]); /* we will return from H */ test_assert(4 == test_atomic[0]); test_atomic[0] = 5; /* unlock mtx1. In properly implemented priority inversion this should wake * up the task H since nothing more block it from running */ os_mtx_unlock(&test_mtx[1]); test_assert(8 == test_atomic[0]); test_atomic[0] = 9; /* finish test */ os_mtx_unlock(&test_mtx[0]); test_assert(9 == test_atomic[0]); test_atomic[0] = 10; return 0; }