【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
typedef struct RAW_MUTEX { RAW_COMMON_BLOCK_OBJECT common_block_obj; RAW_U8 count; /*ponit to occupy task*/ RAW_TASK_OBJ *occupy; /*occupy task original priority*/ RAW_U8 occupy_original_priority; } RAW_MUTEX;
RAW_U16 raw_mutex_create(RAW_MUTEX *mutex_ptr, RAW_U8 *name_ptr) { #if (RAW_MUTEX_FUNCTION_CHECK > 0) if (mutex_ptr == 0) return RAW_NULL_OBJECT; #endif /*Init the list*/ list_init(&mutex_ptr->common_block_obj.block_list); mutex_ptr->common_block_obj.block_way = 0; mutex_ptr->common_block_obj.name = name_ptr; /*No one occupy mutex yet*/ mutex_ptr->occupy = 0; /*resource is available at init state*/ mutex_ptr->count = 1; mutex_ptr->occupy_original_priority = 0; return RAW_SUCCESS; }初始化的函数还是比较简单的,主要做了下面的流程,
RAW_U16 raw_mutex_get(RAW_MUTEX *mutex_ptr, RAW_U32 wait_option) { RAW_U16 error_status; RAW_SR_ALLOC(); #if (RAW_MUTEX_FUNCTION_CHECK > 0) if (mutex_ptr == 0) { return RAW_NULL_OBJECT; } if (raw_int_nesting) { return RAW_NOT_CALLED_BY_ISR; } #endif RAW_CRITICAL_ENTER(); /* mutex is available */ if (mutex_ptr->count) { mutex_ptr->occupy = raw_task_active; mutex_ptr->occupy_original_priority = raw_task_active->priority; mutex_ptr->count = 0; RAW_CRITICAL_EXIT(); return RAW_SUCCESS; } /*if the same task get the same mutex again, it causes deadlock*/ if (raw_task_active == mutex_ptr->occupy) { #if (CONFIG_RAW_ASSERT > 0) RAW_ASSERT(0); #endif RAW_CRITICAL_EXIT(); return RAW_MUTEX_DEADLOCK; } /*Cann't get mutex, and return immediately if wait_option is RAW_NO_WAIT*/ if (wait_option == RAW_NO_WAIT) { RAW_CRITICAL_EXIT(); return RAW_NO_PEND_WAIT; } /*system is locked so task can not be blocked just return immediately*/ if (raw_sched_lock) { RAW_CRITICAL_EXIT(); return RAW_SCHED_DISABLE; } /*if current task is a higher priority task and block on the mutex *priority inverse condition happened, priority inherit method is used here*/ if (raw_task_active->priority < mutex_ptr->occupy->priority) { switch (mutex_ptr->occupy->task_state) { case RAW_RDY: /*remove from the ready list*/ remove_ready_list(&raw_ready_queue, mutex_ptr->occupy); /*raise the occupy task priority*/ mutex_ptr->occupy->priority = raw_task_active->priority; /*readd to the ready list head*/ add_ready_list_head(&raw_ready_queue, mutex_ptr->occupy); break; case RAW_DLY: case RAW_DLY_SUSPENDED: case RAW_SUSPENDED: /*occupy task is not on any list, so just change the priority*/ mutex_ptr->occupy->priority = raw_task_active->priority; break; case RAW_PEND: /* Change the position of the task in the wait list */ case RAW_PEND_TIMEOUT: case RAW_PEND_SUSPENDED: case RAW_PEND_TIMEOUT_SUSPENDED: /*occupy task is on the block list so change the priority on the block list*/ mutex_ptr->occupy->priority = raw_task_active->priority; change_pend_list_priority(mutex_ptr->occupy); break; default: RAW_CRITICAL_EXIT(); return RAW_INVALID_STATE; } } /*Any way block the current task*/ raw_pend_object(&mutex_ptr->common_block_obj, raw_task_active, wait_option); RAW_CRITICAL_EXIT(); /*find the next highest priority task ready to run*/ raw_sched(); /*So the task is waked up, need know which reason cause wake up.*/ error_status = block_state_post_process(raw_task_active, 0); return error_status; }这段代码其实开头都还好,关键是末尾要结束的时候有一段代码比较费解。我想,这就是我前面说过的优先级反转问题。为了解决这一问题,在rawos版本中采取了优先级继承的方法。我们还是详细看一下逻辑本身是怎么样的,
RAW_U16 raw_mutex_put(RAW_MUTEX *mutex_ptr) { LIST *block_list_head; RAW_SR_ALLOC(); #if (RAW_MUTEX_FUNCTION_CHECK > 0) if (mutex_ptr == 0) { return RAW_NULL_OBJECT; } #endif block_list_head = &mutex_ptr->common_block_obj.block_list; RAW_CRITICAL_ENTER(); /*Must release the mutex by self*/ if (raw_task_active != mutex_ptr->occupy) { RAW_CRITICAL_EXIT(); return RAW_MUTEX_NOT_RELEASE_BY_OCCYPY; } /*if no block task on this list just return*/ if (is_list_empty(block_list_head)) { mutex_ptr->count = 1; RAW_CRITICAL_EXIT(); return RAW_SUCCESS; } /*if priority was changed, just change it back to original priority*/ if (raw_task_active->priority != mutex_ptr->occupy_original_priority) { remove_ready_list(&raw_ready_queue, raw_task_active); raw_task_active->priority = mutex_ptr->occupy_original_priority; add_ready_list_end(&raw_ready_queue, raw_task_active); } /* there must have task blocked on this mutex object*/ mutex_ptr->occupy = list_entry(block_list_head->next, RAW_TASK_OBJ, task_list); /*the first blocked task became the occupy task*/ mutex_ptr->occupy_original_priority = mutex_ptr->occupy->priority; /*mutex resource is occupied*/ mutex_ptr->count = 0; /*Wake up the occupy task, which is the highst priority task on the list*/ raw_wake_object(mutex_ptr->occupy); RAW_CRITICAL_EXIT(); raw_sched(); return RAW_SUCCESS; }和之前的信号量释放相比,互斥量的释放要复杂一切,关键就在于修改优先级的问题。我们来梳理一下,
RAW_U16 raw_mutex_delete(RAW_MUTEX *mutex_ptr) { LIST *block_list_head; RAW_TASK_OBJ *mutex_occupy; RAW_SR_ALLOC(); #if (RAW_MUTEX_FUNCTION_CHECK > 0) if (mutex_ptr == 0) { return RAW_NULL_OBJECT; } #endif block_list_head = &mutex_ptr->common_block_obj.block_list; RAW_CRITICAL_ENTER(); mutex_occupy = mutex_ptr->occupy; /*if mutex is occupied and occupy priority is not the original priority*/ if ((mutex_occupy) && (mutex_occupy->priority != mutex_ptr->occupy_original_priority)) { switch (mutex_occupy->task_state) { case RAW_RDY: /*remove from the ready list*/ remove_ready_list(&raw_ready_queue, mutex_ptr->occupy); /*raise the occupy task priority*/ mutex_occupy->priority = mutex_ptr->occupy_original_priority; /*readd to the ready list head*/ add_ready_list_end(&raw_ready_queue, mutex_ptr->occupy); break; case RAW_DLY: case RAW_SUSPENDED: case RAW_DLY_SUSPENDED: /*occupy task is not on any list, so just change the priority*/ mutex_occupy->priority = mutex_ptr->occupy_original_priority; break; case RAW_PEND: case RAW_PEND_TIMEOUT: case RAW_PEND_SUSPENDED: case RAW_PEND_TIMEOUT_SUSPENDED: /*occupy task is on the block list so change the priority on the block list*/ mutex_occupy->priority = mutex_ptr->occupy_original_priority; change_pend_list_priority(mutex_occupy); break; default: RAW_CRITICAL_EXIT(); return RAW_STATE_UNKNOWN; } } /*All task blocked on this queue is waken up*/ while (!is_list_empty(block_list_head)) { delete_pend_obj(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list)); } RAW_CRITICAL_EXIT(); raw_sched(); return RAW_SUCCESS; }