/*! Post (release) a semaphore. If there are other tasks waiting for this semaphore, the highest-priority task in the semaphore wait list will claim the semaphore and run. \fn BOOL Semaphore_Post(SEMAPHORE_STRUCT *pstSem_) \param pstSem_ - pointer to the semaphore to post */ void Semaphore_Post(SEMAPHORE_STRUCT *pstSem_) { BOOL bTaskWait = FALSE; //!! Disable scheduler + interrupts (callable from ISR) CS_ENTER(); // Nothing is pending if (pstSem_->pstTask == NULL) { // Re-initialize the semaphore if (pstSem_->usSem < pstSem_->usMax) { pstSem_->usSem++; } } else { // Wake the highest priority task pending on the semaphore Semaphore_WakeNextPending(pstSem_); bTaskWait = TRUE; } CS_EXIT(); if (bTaskWait) { Task_YieldSWI(); } }
/*! Remove a task from the scheduler list. Before attempting to remove the task, the owner should ensure that all connections of this task to other objects (plumber, semaphore, etc.) are removed PRIOR to calling this function, otherwise system corruption will likely occur. \fn BOOL Task_Remove(TASK_STRUCT *pstTask_) \sa Task_Add() \param pstTask_ - pointer to the task structure to remove \return (BOOL) TRUE on success, FAIL on failure */ BOOL Task_Remove(TASK_STRUCT *pstTask_) { TASK_STRUCT *pstPrev; TASK_STRUCT *pstTarget; CS_ENTER(); // initialize the target pstPrev = pstTask_; pstTarget = pstTask_->pstNext; // Look through the circular list of tasks and find the connectors. while (pstTarget != pstTask_) { // iterate through... pstPrev = pstTarget; pstTarget = pstTarget->pstNext; } // Remove the target from the circularly linked list pstPrev->pstNext = pstTask_->pstNext; // De-initialize the "next" pointer in the task list. pstTask_->pstNext = NULL; // Set the task as uninitialized (require initialization before reuse) pstTask_->eState = TASK_UNINIT; CS_EXIT(); // Call a context switch. Task_YieldSWI(); // Will not return if the thread deletes itself. return FALSE; }
/*! Set a task to sleep for a period of time specified in the arguments \sa Task_Tick() \fn void Task_Sleep(USHORT usTime_) \param usTime_ - the time period in RTOS ticks to sleep through */ void Task_Sleep(USHORT usTime_) { // Do this in a scheduler-disabled context CS_ENTER(); pstCurrentTask->eState = TASK_SLEEP; pstCurrentTask->usTimeLeft = usTime_; CS_EXIT(); // Call the scheduler immediately. Task_YieldSWI(); }
/*! Signal a task to wait for a semaphore. If the semaphore is not available, the task will block and wait until the semaphore becomes available. \fn BOOL Semaphore_Pend(SEMAPHORE_STRUCT *pstSem_, USHORT usTime_) \param pstSem_ - pointer to the semaphore to pend on \param usTime_ - the time limit to wait for the semaphore. Integer number of ticks or TIME_FOREVER \return BOOL - TRUE on success, FALSE on timeout */ BOOL Semaphore_Pend(SEMAPHORE_STRUCT *pstSem_, USHORT usTime_) { BOOL bTaskWait = FALSE; BOOL bReturn = TRUE; TASK_STRUCT *pstTask; //!! Disable Scheduler !! CS_ENTER(); pstTask = Task_GetCurrentTask(); if (pstSem_->usSem != 0) { // Semaphore isn't claimed, claim it. pstSem_->usSem--; } else { // Remove the task from the ready state - blocking on semaphore pstTask->eState = TASK_BLOCKED; pstTask->usTimeLeft = usTime_; // Add the task to the semaphore's waiting list. Semaphore_AddToList(pstSem_, pstTask); bTaskWait = TRUE; } CS_EXIT(); if (bTaskWait) { // Switch tasks immediately Task_YieldSWI(); CS_ENTER(); if (pstTask->bTimeout) { // If there was a timeout waiting for the semaphore bReturn = FALSE; Semaphore_DeleteFromList(pstSem_, pstTask); pstTask->bTimeout = FALSE; // Reset the task timeout flag } CS_EXIT(); } return bReturn; }