/** * * @param mutex * * @return TN_BOOL */ TN_BOOL do_unlock_mutex (TN_MUTEX_S *mutex) { CDLL_QUEUE_S *curr_que; TN_MUTEX_S *tmp_mutex; TN_TCB_S *task; TN_TCB_S *hi_pri_task = TN_NULL; TN_TCB_S *blk_task; TN_TCB_S *tmp_task; TN_UWORD priority; TN_UWORD pr; TN_BOOL need_switch_context = TN_FALSE; queue_remove_entry(&(mutex->mutex_queue)); queue_remove_entry(&(mutex->lock_mutex_queue)); if (is_queue_empty(&(tn_curr_run_task->mutex_queue))) { need_switch_context = set_current_priority(tn_curr_run_task, tn_curr_run_task->base_priority); } else { if (mutex->attr == TN_MUTEX_ATTR_INHERIT || mutex->attr == TN_MUTEX_ATTR_CEILING ) { pr = tn_curr_run_task->base_priority; curr_que = tn_curr_run_task->mutex_queue.next; for (;;) { tmp_mutex = get_mutex_by_mutex_queue(curr_que); pr = find_max_blocked_priority(tmp_mutex,pr); if (curr_que->next == &(tn_curr_run_task->mutex_queue)) break; else { curr_que = curr_que->next; } } if (pr != tn_curr_run_task->priority) { need_switch_context = set_current_priority(tn_curr_run_task,pr); } } } if (is_queue_empty(&(mutex->wait_queue))) { mutex->holder = TN_NULL; hi_pri_task = tn_curr_run_task; } else { if (mutex->attr == TN_MUTEX_ATTR_CEILING) { priority = TN_NUM_PRIORITY - 1; curr_que = mutex->wait_queue.next; for (;;) { task = get_task_by_tsk_queue(curr_que); if (task->priority < priority) { hi_pri_task = task; priority = task->priority; } if (curr_que->next == &(mutex->wait_queue)) break; else curr_que = curr_que->next; } if (enable_lock_mutex(hi_pri_task,&blk_task)) { queue_remove_entry(&(hi_pri_task->task_queue)); remove_task_from_blocked_list(hi_pri_task); if (task_wait_complete(hi_pri_task, TN_FALSE)) need_switch_context = TN_TRUE; mutex->holder = hi_pri_task; hi_pri_task->blk_task = TN_NULL; queue_add_tail(&(hi_pri_task->mutex_queue),&(mutex->mutex_queue)); queue_add_tail(&tn_locked_mutexes_list,&(mutex->lock_mutex_queue)); } else { if (!queue_contains_entry(&tn_blocked_tasks_list, &(hi_pri_task->block_queue))) { queue_add_tail(&tn_blocked_tasks_list,&(hi_pri_task->block_queue)); hi_pri_task->task_wait_reason = TSK_WAIT_REASON_MUTEX_C_BLK; hi_pri_task->blk_task = blk_task; } } } else if (mutex->attr == TN_MUTEX_ATTR_INHERIT) { curr_que = queue_remove_head(&(mutex->wait_queue)); task = get_task_by_tsk_queue(curr_que); if (task_wait_complete(task, TN_FALSE)) need_switch_context = TN_TRUE; mutex->holder = task; queue_add_tail(&(task->mutex_queue),&(mutex->mutex_queue)); /*--- v.2.3 */ queue_add_tail(&tn_locked_mutexes_list,&(mutex->lock_mutex_queue)); /*--- */ } } if (mutex->holder == TN_NULL && mutex->attr == TN_MUTEX_ATTR_CEILING) { if (!is_queue_empty(&tn_blocked_tasks_list)) { curr_que = tn_blocked_tasks_list.next; for (;;) { tmp_task = get_task_by_block_queue(curr_que); if (tmp_task != hi_pri_task) { if (try_lock_mutex(tmp_task)) { need_switch_context = TN_TRUE; } } if (curr_que->next == &tn_blocked_tasks_list) break; else curr_que = curr_que->next; } } } return need_switch_context; }
//---------------------------------------------------------------------------- int task_wait_complete(TN_TCB * task) //-- v. 2.6 { #ifdef USE_MUTEXES int fmutex; int curr_priority; TN_MUTEX * mutex; TN_TCB * mt_holder_task; CDLL_QUEUE * t_que; #endif int rc = FALSE; if(task == NULL) return 0; #ifdef USE_MUTEXES t_que = NULL; if(task->task_wait_reason == TSK_WAIT_REASON_MUTEX_I || task->task_wait_reason == TSK_WAIT_REASON_MUTEX_C) { fmutex = TRUE; t_que = task->pwait_queue; } else fmutex = FALSE; #endif task->pwait_queue = NULL; task->task_wait_rc = TERR_NO_ERR; if(task->tick_count != TN_WAIT_INFINITE) queue_remove_entry(&(task->timer_queue)); task->tick_count = TN_WAIT_INFINITE; if(!(task->task_state & TSK_STATE_SUSPEND)) { task_to_runnable(task); rc = TRUE; } else //-- remove WAIT state task->task_state = TSK_STATE_SUSPEND; #ifdef USE_MUTEXES if(fmutex) { mutex = get_mutex_by_wait_queque(t_que); mt_holder_task = mutex->holder; if(mt_holder_task != NULL) { //-- if task was blocked by another task and its pri was changed //-- - recalc current priority if(mt_holder_task->priority != mt_holder_task->base_priority && mt_holder_task->priority == task->priority) { curr_priority = find_max_blocked_priority(mutex, mt_holder_task->base_priority); set_current_priority(mt_holder_task, curr_priority); rc = TRUE; } } } #endif task->task_wait_reason = 0; //-- Clear wait reason return rc; }
/** * * @param mutex * @param timeout * * @return TN_RETVAL */ TN_RETVAL tnec_mutex_lock (TN_MUTEX_S *mutex, TN_TIMEOUT timeout) { TN_UWORD tn_save_status_reg TN_UNUSED; /* for SR save */ TN_TCB_S *blk_task; TN_RETVAL rc; if (mutex == TN_NULL || timeout == 0) return TERR_WRONG_PARAM; if (mutex->id_mutex != TN_ID_MUTEX) return TERR_NOEXS; if (tn_is_non_task_context()) { return TERR_WCONTEXT; } tn_disable_interrupt(); rc = TERR_NO_ERR; for (;;) { if (tn_curr_run_task == mutex->holder) { rc = TERR_ILUSE; break; } if (mutex->attr == TN_MUTEX_ATTR_CEILING && tn_curr_run_task->base_priority < mutex->ceil_priority) { rc = TERR_ILUSE; break; } if (mutex->attr == TN_MUTEX_ATTR_CEILING) { if (mutex->holder == TN_NULL) { if (enable_lock_mutex(tn_curr_run_task, &blk_task)) { mutex->holder = tn_curr_run_task; tn_curr_run_task->blk_task = TN_NULL; queue_add_tail(&(tn_curr_run_task->mutex_queue), &(mutex->mutex_queue)); queue_add_tail(&tn_locked_mutexes_list, &(mutex->lock_mutex_queue)); } else { /* Невозможно заблокировать мютекс Протокол наследования: Если текущий приоритет выполняемой задачи больше приоритета задачи, которая блокирует текущую (удерживает мютекс), то блокирующая задача наследует приоритет текущей */ if (blk_task != TN_NULL) { if (tn_curr_run_task->priority < blk_task->priority) { set_current_priority(blk_task, tn_curr_run_task->priority); } } queue_add_tail(&tn_blocked_tasks_list, &(tn_curr_run_task->block_queue)); tn_curr_run_task->blk_task = blk_task; task_curr_to_wait_action(&(mutex->wait_queue), TSK_WAIT_REASON_MUTEX_C_BLK, timeout); tn_enable_interrupt(); tn_switch_context(); return tn_curr_run_task->task_wait_rc; } } else { if (tn_curr_run_task->priority < mutex->holder->priority) { set_current_priority(mutex->holder,tn_curr_run_task->priority); } task_curr_to_wait_action(&(mutex->wait_queue), TSK_WAIT_REASON_MUTEX_C, timeout); tn_enable_interrupt(); tn_switch_context(); return tn_curr_run_task->task_wait_rc; } } else if (mutex->attr == TN_MUTEX_ATTR_INHERIT) { if (mutex->holder == TN_NULL) { mutex->holder = tn_curr_run_task; queue_add_tail(&(tn_curr_run_task->mutex_queue),&(mutex->mutex_queue)); /* --- v.2.3 */ queue_add_tail(&tn_locked_mutexes_list,&(mutex->lock_mutex_queue)); /* --- */ rc = TERR_NO_ERR; } else { if (tn_curr_run_task->priority < mutex->holder->priority) { set_current_priority(mutex->holder, tn_curr_run_task->priority); } task_curr_to_wait_action(&(mutex->wait_queue), TSK_WAIT_REASON_MUTEX_I,timeout); tn_enable_interrupt(); tn_switch_context(); return tn_curr_run_task->task_wait_rc; } } break; } tn_enable_interrupt(); return rc; }