Tuesday, June 25, 2013

Semaphore Vs Mutex: Signal Semaphore/Unlock Mutex

① Releasing lock or signalling semaphore
The Mutex can be unlocked only by the task which locked it. Unlocking the mutex involves the following two things:
1) bringing the task which is locking, back to the state before locking the mutex. The task is returned to its base priority or if the task is locking other mutexes, highest ceiling priority or highest priority of tasks waiting for such mutexes will be assigned. If the task's priority is lowered down, then the task will call scheduler. Otherwise, it will continue holding the CPU.
2) One of the waiting tasks is granted the lock. The task waiting on the highest priority level of the queue of the mutex is checked as if it called loc_mtx(). If eligible, it is removed from wait queue and lock is granted. If not eligible, error code is posted to that task and next waiting task is considered. If the mutex is with CEILING attribute and the ceiling priority is higher than the task priority, the task priority is raised. Otherwise, the task's priority is set as current highest priority locking the mutex. If the new locking task's priority is higher than the current task's priority, then the scheduler will be called.

But, Semaphore can be signaled from any context. (This may cause accidential release.) And, it just increments the semaphore resource count, if no task is waiting for it. But, if the semaphore is signaled when resource count is at its maximum limit, E_QOVR error is returned and its resource count is set at its maximum value.



② iTRON implementation to signal semaphore

ER sig_sem(ID semid)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        If (Semaphore resource count == 0){
                /* then some tasks should be waiting */
                Check semaphore queue till queue tail is reached
                If there is valid task id {
                        if task is waiting in Timeout
                                remove from timer queue
                        Set task status ad Ready
                        if the task is NOT suspended {
                                Change the task to the Ready Queue of priority
                                If (the task priority is higher than the current){
                                        call scheduler
                                        return error code from scheduler
                                } else {
                                        Exit critical section and return error code from it (E_OK)
                                        (return E_OK)
                                }
                        } else {
                                Just delete the task from the Semaphore queue
                                Exit critical section and return the error code from it (E_OK)
                                (return E_OK)
                        }
                }
        }
        If (Semaphore resource count reached maximum) {
                Exit critical section
                return E_QOVR;
        } else {
                Increment semaphore resource count
                Exit critical section and return the error code from it (E_OK)
                return E_OK;
        }
}

③ iTRON implementation to unlock mutex

ER unl_mtx(ID mtxid)
{
        Sanity check on arguments
        If (this function is called from interrupt context) or
        If (called from task independent state ex: timer handlers) or
        If (called from dispatch disabled state)
                Return E_CTX;
        Enter critical section (Interrupt Disable)
        If (this task has NOT locked this mutex)
                Return E_ILUSE;
        Take the tasks's base priority
        For all mutexes locked by this task {
                If (mutex ID is same as this mutex) {
                        Release it from queue by assigning the next mutex ID in
                            place of this mutex
                        If this is not FIFO based, continue checking to get back the original priority
                        Otherwise, break the loop
                }
                Does any mutex have higher priority than the base priority?
                Keep it as new priority
        }
        If (new priority is not equal to the current running priority){
                Assign the new priority to the tcb
                Change the tcb to Ready queue with new priority level
                If (new priority is lower than the current running priority)
                        Set to call scheduler when quitting this function
        } else {
                No need to call scheduler
        }
        /* Grant lock to one waiting task and wake it up */
        For all tasks waiting in this mutex's queue (from head having highest priority tasks) {
                Take a task.
                If it is waiting as Timeout, remove it from timer queue
                Remove the task from the mutex's queue
                Set tcb status as Ready
                /* Sanity check and lock assignment as if it called loc_mtx */
                If the mutex attribute is Ceiling and the task has higher base priority {
                /* When ths task is waiting, base priority is changed by chg_pri() */
                        Error code parameter of tcb = E_ILUSE
                        Add the task to the Ready queue
                        If the task's priority is higher than the current task's priority
                                Set to call scheduler when quitting this function
                        Take next task and continue checking from first
                } else {
                        If the mutex has CEILING attribute and
                         the ceiling priority is higher than the task priority{
                                the task (tcb) priority is set to the ceiling priority
                        } else {
                                the task's priority is set as current highest
                                    priority locking the mutex
                        }
                        Set the task as locking task
                        Add the mutex in the task's queue of mutexes
                        If the task's priority is higher than the current task's priority
                                Set to call scheduler when quitting this function
                }
        }
        If to call scheduler {
                Call scheduler
                return error code that is set in scheduler
        }
        Otherwise, exit critical section and return error code from it (E_OK)
}


Please have a look at other posts under RTOS label.

No comments: