int mutex_lock_syscall(int mutex __attribute__((unused))) { //printf("mutex_lock, %d\n", mutex); // if mutex invalid if (mutex >= OS_NUM_MUTEX || gtMutex[mutex].bAvailable == 1) { return EINVAL; } if (gtMutex[mutex].pHolding_Tcb == get_cur_tcb()) return EDEADLOCK; // if blocked if (gtMutex[mutex].bLock == 1) { tcb_t** tmp = &(gtMutex[mutex].pSleep_queue); while (1) { if (*tmp == (void *)0) { gtMutex[mutex].pSleep_queue = runqueue_remove(get_cur_prio()); break; } if((*tmp)->sleep_queue == (void *)0) { (*tmp)->sleep_queue = runqueue_remove(get_cur_prio()); ((*tmp)->sleep_queue) = (void *)0; break; } tmp = (tcb_t **)&((*tmp)->sleep_queue); } //printf("blocked!!!!!!!!!\n"); //printf("mutex holding tcb: %d\n", (gtMutex[mutex].pHolding_Tcb)->native_prio); dispatch_save(); } // if not blocked gtMutex[mutex].bLock = 1; gtMutex[mutex].pHolding_Tcb = get_cur_tcb(); //printf("mutex holding tcb: %d\n", (gtMutex[mutex].pHolding_Tcb)->native_prio); //printf("mutex sleep queue\n"); /* tcb_t* tmp = gtMutex[mutex].pSleep_queue; while (tmp != (void *)0) { printf("sleep %d\n", tmp->native_prio); tmp = tmp->sleep_queue; } */ return 0; }
/** * @brief Context switch to the highest priority task that is not this task -- * and save the current task but don't mark is runnable. * * There is always an idle task to switch to. */ void dispatch_sleep(void) { tcb_t *dest, *temp; temp = cur_tcb; uint8_t cp = get_cur_prio(); /* i.e task that was just put to sleep */ uint8_t hp = highest_prio(); /* next task to run */ /* Run idle task if there are no other */ if(cp == hp) dest = runqueue_remove(IDLE_PRIO); else dest = runqueue_remove(hp); /* Set cur_tcb to the task that we are about to run */ cur_tcb = dest; /* Set the cur_kstack var of the task that we are about to run */ cur_kstack = (int)dest->kstack_high; ctx_switch_full(&(dest->context), &(temp->context)); }
int mutex_unlock(int mutex __attribute__((unused))) { tcb_t* temp; disable_interrupts(); // if the provided mutex identifier if invalid if(mutex > OS_NUM_MUTEX || gtMutex[mutex].bAvailable == TRUE) { enable_interrupts(); return -EINVAL; } if(gtMutex[mutex].pHolding_Tcb != get_cur_tcb()) { // if the urrent task does not hold the mutex enable_interrupts(); return -EPERM; } else { temp = gtMutex[mutex].pHolding_Tcb; temp->holds_lock = 0; #ifdef HLP temp->cur_prio = temp->native_prio; #endif // HLP // if there is no element in sleep queue if(gtMutex[mutex].pSleep_queue == 0) { gtMutex[mutex].bLock = 0; gtMutex[mutex].pHolding_Tcb = 0; enable_interrupts(); return 0; } else { // if the sleep queue have tasks waiting for the mutex // first tcb in sleeping queue gets the mutex gtMutex[mutex].pHolding_Tcb = gtMutex[mutex].pSleep_queue; // move the head of mutex sleeping queue to next gtMutex[mutex].pSleep_queue = gtMutex[mutex].pSleep_queue->sleep_queue; // clear the sleeping queue of the holding tcb gtMutex[mutex].pHolding_Tcb->sleep_queue = 0; gtMutex[mutex].pHolding_Tcb->holds_lock = 1; #ifdef HLP gtMutex[mutex].pHolding_Tcb->cur_prio = 0; #endif // HLP // put the wake up task into runqueue runqueue_add(gtMutex[mutex].pHolding_Tcb, gtMutex[mutex].pHolding_Tcb->cur_prio); // check the wake up task's priority and current running task's priority if(highest_prio() < get_cur_prio()) { // switch to the highest task dispatch_save(); } else { // stay the same enable_interrupts(); return 0; } } } // the function will not get here return 1; }
int mutex_lock(int mutex __attribute__((unused))) { disable_interrupts(); tcb_t* cur_tcb = get_cur_tcb(); uint8_t cur_prio = get_cur_prio(); tcb_t* sleep_queue, *temp; mutex_t *cur_mutex = &(gtMutex[mutex]); /* check if provided mutex identifier is valid */ if(mutex > num_mutices) { enable_interrupts(); return EINVAL; } /* check if current task is holding the mutex */ if(cur_mutex->pHolding_Tcb == cur_tcb) { enable_interrupts(); return EDEADLOCK; } /* check if sleep queue is empty */ if(cur_mutex->pSleep_queue == 0) { cur_mutex->pSleep_queue = cur_tcb; cur_tcb->sleep_queue = 0; } /* insert task at appropriate location in sleep queue */ else { sleep_queue = cur_mutex->pSleep_queue; temp = sleep_queue; /* insert at front of the list */ if(cur_prio < (sleep_queue->cur_prio)) { cur_tcb->sleep_queue = cur_mutex->pSleep_queue; cur_mutex->pSleep_queue = cur_tcb; } else { sleep_queue = sleep_queue->sleep_queue; while(sleep_queue != 0) { if(cur_prio < (sleep_queue->cur_prio)) { cur_tcb->sleep_queue = sleep_queue; temp->sleep_queue = cur_tcb; break; } temp = sleep_queue; sleep_queue = sleep_queue->sleep_queue; } } } disable_interrupts(); dispatch_sleep(); enable_interrupts(); return 0; }