申請互斥量 _tx_mutex_get
_tx_mutex_get用於申請互斥量:
1,如果是系統中第一個申請互斥量線程,tx_mutex_ownership_count 設置爲1,申請成功。
2,如果是擁有互斥量的線程再次申請,那麼只需tx_mutex_ownership_count 計數器加一,申請成功。
3,如果申請互斥量的當前線程不是擁有互斥量的線程,需要把當前線程掛入tx_mutex_suspension_list隊列:
(1)如果設置了優先級繼承,並且當前線程優先級高於擁有互斥量線程的優先級,那麼設置擁有互斥量線程的優先級
爲當前線程優先級;
4,掛起隊列中線程優先級一定大於擁有者線程優先級,因爲只有高優先級才能夠打斷擁有者線程,嘗試申請互斥量
UINT _tx_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option)
{
TX_INTERRUPT_SAVE_AREA
REG_1 UINT status; /* Return status */
REG_2 TX_THREAD *thread_ptr; /* Working thread pointer */
/* Disable interrupts to get an instance from the mutex. */
TX_DISABLE
/* Determine if there is an instance of the mutex. */
if (!mutex_ptr -> tx_mutex_ownership_count)
{
#def 第一次線程申請互斥量
/* Set the ownership count to 1. */
mutex_ptr -> tx_mutex_ownership_count = 1;
/* Remember that the calling thread owns the mutex. */
mutex_ptr -> tx_mutex_owner = _tx_thread_current_ptr;
/* Determine if priority inheritance is required. */
if ((mutex_ptr -> tx_mutex_inherit) && (_tx_thread_current_ptr))
{
#def 設置了優先級繼承,保存原始的優先級和搶佔門限
/* Remember the current priority and threshold of thread. */
mutex_ptr -> tx_mutex_original_priority = _tx_thread_current_ptr -> tx_priority;
mutex_ptr -> tx_mutex_original_threshold = _tx_thread_current_ptr -> tx_preempt_threshold;
}
/* Set status to success. */
status = TX_SUCCESS;
}
else if (mutex_ptr -> tx_mutex_owner == _tx_thread_current_ptr)
{
#def 本線程已經擁有了這個互斥量,已經申請過。再次申請,只需tx_mutex_ownership_count計數器加一
/* The owning thread is requesting the mutex again, just
increment the ownership count. */
mutex_ptr -> tx_mutex_ownership_count++;
/* Set status to success. */
status = TX_SUCCESS;
}
else
{
#def 互斥量已經被其他線程申請成功; 本線程進行申請
#def 1,wait_option =0 本線程不等待互斥量釋放,直接返回
#def 2,wait_option 不爲0,本線程掛入tx_mutex_suspension_list隊列,自我掛起
/* Determine if the request specifies suspension. */
if (wait_option)
{
/* Prepare for suspension of this thread. */
/* Pickup thread pointer. */
thread_ptr = _tx_thread_current_ptr;
/* Setup cleanup routine pointer. */
#def 由於是等待互斥量時掛起的,所以設置清除函數爲_tx_mutex_cleanup,如果後續這個線程不再等待信號量,會回調tx_suspend_cleanup ,清除互斥量相關的data struct
thread_ptr -> tx_suspend_cleanup = _tx_mutex_cleanup;
/* Setup cleanup information, i.e. this mutex control
block. */
thread_ptr -> tx_suspend_control_block = (VOID_PTR) mutex_ptr;
#def 插入到互斥量掛起隊列tx_mutex_suspension_list,這裏掛入了尾部,也就是FIFO。這裏並沒有按照線程優先級,把最高優先級插入到最前面
/* Setup suspension list. */
if (mutex_ptr -> tx_mutex_suspension_list)
{
/* This list is not NULL, add current thread to the end. */
thread_ptr -> tx_suspended_next =
mutex_ptr -> tx_mutex_suspension_list;
thread_ptr -> tx_suspended_previous =
(mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_previous;
((mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_previous) -> tx_suspended_next =
thread_ptr;
(mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_previous = thread_ptr;
}
else
{
/* No other threads are suspended. Setup the head pointer and
just setup this threads pointers to itself. */
mutex_ptr -> tx_mutex_suspension_list = thread_ptr;
thread_ptr -> tx_suspended_next = thread_ptr;
thread_ptr -> tx_suspended_previous = thread_ptr;
}
/* Increment the suspended thread count. */
mutex_ptr -> tx_mutex_suspended_count++;
/* Set the state to suspended. */
#def 設置爲掛起狀態
thread_ptr -> tx_state = TX_MUTEX_SUSP;
/* Set the suspending flag. */
#def 設置爲true,表示正在掛起過程;_tx_thread_suspend或resume中用到這個標誌
thread_ptr -> tx_suspending = TX_TRUE;
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Save the timeout value. */
#def wait_option爲線程等待互斥量時間,需要開啓定時器;定時器超時就調用前面設置的tx_suspend_cleanup
thread_ptr -> tx_thread_timer.tx_remaining_ticks = wait_option;
/* Restore interrupts. */
TX_RESTORE
/* Determine if we need to raise the priority of the thread
owning the mutex. */
#def 如果設置了優先級繼承標誌,
if ((mutex_ptr -> tx_mutex_inherit) && (mutex_ptr -> tx_mutex_owner)
&& (_tx_thread_current_ptr))
{
/* Priority inheritance is requested, check to see if the
thread that owns the mutex is lower priority. */
#def 如果當前申請互斥量線程優先級高於 互斥量擁有者的線程,那麼把互斥量擁有者的線程設置爲當前線程優先級,搶佔門限也設置爲當前線程優先級。 這樣保證了擁有互斥量線程優先級最高,防止了中等優先級線程搶佔, 這樣高優先級等待互斥量時間 由 擁有互斥量線程 佔用互斥量的時間。把不確定變爲了確定。
if ((mutex_ptr -> tx_mutex_owner) -> tx_priority >
_tx_thread_current_ptr -> tx_priority)
{
/* Yes, raise the suspended, owning thread's priority to that
of the current thread. */
_tx_mutex_priority_change(mutex_ptr -> tx_mutex_owner, _tx_thread_current_ptr -> tx_priority, _tx_thread_current_ptr -> tx_priority);
}
}
/* See if we need to start a timer. */
#def wait_option 不是永久等待時,啓動等待定時器
if (wait_option != TX_WAIT_FOREVER)
{
/* A timeout is required. */
_tx_timer_activate(&(thread_ptr -> tx_thread_timer));
}
/* Call actual thread suspension routine. */
#def 掛起當前線程
_tx_thread_suspend(thread_ptr);
/* Return the completion status. */
return (thread_ptr -> tx_suspend_status);
}
else
/* Immediate return, return error completion. */
status = TX_NOT_AVAILABLE;
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return (status);
}
_tx_mutex_prioritize
_tx_mutex_prioritize把最高優先級線程掛到tx_mutex_suspension_list最前面
UINT _tx_mutex_prioritize(TX_MUTEX *mutex_ptr)
{
TX_INTERRUPT_SAVE_AREA
REG_1 TX_THREAD *thread_ptr; /* Working thread pointer */
REG_2 TX_THREAD *priority_thread_ptr; /* Highest priority thread */
/* Disable interrupts. */
TX_DISABLE
/* Determine if there how many threads are suspended on this mutex. */
if (mutex_ptr -> tx_mutex_suspended_count == 2)
{
#def list中只有兩個線程,只需要把tx_mutex_suspension_list指向優先級最高線程
/* Determine if the next suspended thread has a higher priority. */
if (((mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_next) -> tx_priority <
((mutex_ptr -> tx_mutex_suspension_list) -> tx_priority))
{
/* Yes, move the list head to the next thread. */
mutex_ptr -> tx_mutex_suspension_list =
(mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_next;
}
}
else if (mutex_ptr -> tx_mutex_suspended_count > 2)
{
/* Default the highest priority thread to the thread at the front of the list. */
priority_thread_ptr = mutex_ptr -> tx_mutex_suspension_list;
/* Setup search pointer. */
thread_ptr = priority_thread_ptr -> tx_suspended_next;
#def 從tx_mutex_suspension_list隊列中找出優先級最高的線程
/* Search through the list to find the highest priority thread. */
do
{
/* Is the current thread higher priority? */
if (thread_ptr -> tx_priority < priority_thread_ptr -> tx_priority)
{
/* Yes, remember that this thread is the highest priority. */
priority_thread_ptr = thread_ptr;
}
/* Move the thread pointer to the next thread. */
thread_ptr = thread_ptr -> tx_suspended_next;
}
while (thread_ptr != mutex_ptr -> tx_mutex_suspension_list);
/* Now determine if the highest priority thread is at the front
of the list. */
#def 如果優先級最高線程不是在隊列最前面,那麼先從隊列中remove 最高優先級線程,再插入到隊列最前面
if (priority_thread_ptr != mutex_ptr -> tx_mutex_suspension_list)
{
/* No, we need to move the highest priority suspended thread to the
front of the list. */
/* First, remove the highest priority thread by updating the
adjacent suspended threads. */
(priority_thread_ptr -> tx_suspended_next) -> tx_suspended_previous =
priority_thread_ptr -> tx_suspended_previous;
(priority_thread_ptr -> tx_suspended_previous) -> tx_suspended_next =
priority_thread_ptr -> tx_suspended_next;
/* Now, link the highest priority thread at the front of the list. */
priority_thread_ptr -> tx_suspended_next =
mutex_ptr -> tx_mutex_suspension_list;
priority_thread_ptr -> tx_suspended_previous =
(mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_previous;
((mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_previous) -> tx_suspended_next =
priority_thread_ptr;
(mutex_ptr -> tx_mutex_suspension_list) -> tx_suspended_previous = priority_thread_ptr;
/* Move the list head pointer to the highest priority suspended thread. */
mutex_ptr -> tx_mutex_suspension_list = priority_thread_ptr;
}
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return (TX_SUCCESS);
}