执行线程可以调用_tx_thread_suspend自我挂起,
或者调用_tx_thread_suspend挂起某个线程
线程挂起前,先设置tx_state 或tx_suspending
/* Set the suspending flag. */
thread_ptr -> tx_suspending = TX_TRUE;
如果挂起线程是当前执行线程(自我挂起),需要从就绪队列中选择出下一个最高优先级线程为执行线程,自我挂起说明当前线程是最高优先级线程:
1,如果当前线程就绪队列还有其它线程,那么选择同一个就绪队列中下一个线程.
2, 如果当前线程是就绪队列中唯一线程,那么找出下一个最高优先级就绪队列,选择其中第一个线程为执行线程。
3,选择下一个最高级就绪队列时,需要考虑基于tx_preempt_threshold抢占门限的抢占
VOID _tx_thread_suspend(TX_THREAD *thread_ptr)
{
TX_INTERRUPT_SAVE_AREA
REG_1 UINT priority; /* Thread priority */
REG_2 ULONG priority_map; /* Working priority map */
REG_3 UCHAR priority_group; /* Priority group */
/* Lockout interrupts while the thread is being suspended. */
#def 关中断,防止被抢占
TX_DISABLE
/* Decrement the preemption disable variable. */
#def 已经关中断,禁止抢占--, 调用这个函数的外部函数进行了++
_tx_thread_preempt_disable--;
/* Check to make sure the thread suspending flag is still set. If not, it
has already been resumed. */
#def 调用这个函数的函数设置tx_suspending为TX_TRUE,如果不为TX_TRUE,说明线程已经resume,比如中断处理以及高优先级线程又恢复了这个要挂起的线程
if (thread_ptr -> tx_suspending)
{
#def 继续挂起过程
/* Log the thread status change. */
TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr -> tx_state);
/* Actually suspend this thread. But first, clear the suspending flag. */
thread_ptr -> tx_suspending = TX_FALSE;
/* Pickup priority of thread. */
priority = thread_ptr -> tx_priority;
/* Determine if there are other threads at this priority that are
ready. */
#def 同优先级就绪队列中还有其它线程;把挂起线程从队列中删除
if (thread_ptr -> tx_ready_next != thread_ptr)
{
/* Yes, there are other threads at this priority ready. */
/* Just remove this thread from the priority list. */
(thread_ptr -> tx_ready_next) -> tx_ready_previous = thread_ptr -> tx_ready_previous;
(thread_ptr -> tx_ready_previous) -> tx_ready_next = thread_ptr -> tx_ready_next;
/* Determine if this is the head of the priority list. */
#def 挂起线程是就绪队列中第一个线程,那么可能是当前正执行的线程。 只有就绪队列中第一个线程才可能是当前执行线程。
if (_tx_thread_priority_list[priority] == thread_ptr)
{
/* Update the head pointer of this priority list. */
_tx_thread_priority_list[priority] = thread_ptr -> tx_ready_next;
/* Check for a thread preempted that had preemption threshold set. */
#def 如果之前这个线程被抢占过,并设置了_tx_thread_preempted_map,这里清除掉
if (_tx_thread_preempted_map)
{
/* Ensure that this thread's priority is clear in the preempt
map. */
_tx_thread_preempted_map = _tx_thread_preempted_map &
~(thread_ptr -> tx_priority_bit);
}
/* Determine if this thread is the thread designated to execute. */
#def 挂起线程为执行线程,需要重新选择最高优先级线程为执行线程,由于挂起线程为执行线程,说明所在的就绪队列为最高优先级,那么这里实际选择的就是就绪队列中下一个线程
if (thread_ptr == _tx_thread_execute_ptr)
{
/* Pickup the highest priority thread to execute. */
_tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
}
}
/* Restore interrupts. */
#def 中断使能
TX_RESTORE
/* Determine if we need to return to the system. This needs to happen if a self suspension
takes place or if a higher-priority thread was resumed by an ISR in the part of the
suspension process that has interrupts enabled. */
#def 选择出的执行线程不再是当前线程,进行调度
#def 1,如果是自己挂起(挂起线程就是当前线程),那么选择出的线程肯定不是当前线程
#def 2,上面中断使能了,执行下面代码前,有可能来了中断,中断处理中唤醒了高优先级线程,并且挂起当前执行线程
if ((_tx_thread_current_ptr != _tx_thread_execute_ptr) && (_tx_thread_system_state == 0))
{
/* Return control to the system. */
#def 调度切换线程
_tx_thread_system_return();
}
/* Return to caller. */
return;
}
else
{
#def 挂起线程所在就绪队列没有其它线程
#def 1 如果是其它线程调用挂起线程,那只需要删除需要挂起的线程就可以了
#def 2 如果是自我挂起,那么当前执行线程是最高优先级线程,需要选出下一个最高优先级线程
/* This is the only thread at this priority ready to run. Set the head
pointer to NULL. */
_tx_thread_priority_list[priority] = TX_NULL;
/* Clear this priority bit in the ready priority bit map. */
#def 就绪队列只有一个挂起线程,所以需要清除对应位图bit
_tx_thread_priority_map = _tx_thread_priority_map & ~(thread_ptr -> tx_priority_bit);
/* Check for a thread preempted that had preemption threshold set. */
if (_tx_thread_preempted_map)
{
/* Ensure that this thread's priority is clear in the preempt
map. */
_tx_thread_preempted_map = _tx_thread_preempted_map &
~(thread_ptr -> tx_priority_bit);
}
/* Put the priority map in a working copy. */
priority_map = _tx_thread_priority_map;
/* Find the next highest priority. */
#def 选择出下一个最高优先级线程,为了减少计算,采用了分组方式进行判断,_tx_thread_lowest_bit[]数组存储了索引0-255个整数最低位1的偏移,例如 _tx_thread_lowest_bit[0], 索引0没有1,所以_tx_thread_lowest_bit[0]为0,_tx_thread_lowest_bit[1],索引1的最低位1在bit0,所以_tx_thread_lowest_bit[1]为0,_tx_thread_lowest_bit[2],索引2(0b0010)的最低位1在bit1,所以_tx_thread_lowest_bit[1]为1,_tx_thread_lowest_bit[3],索引3(0b0011)的最低位1在bit0,所以_tx_thread_lowest_bit[1]为0
/* Check for priorities 0-7. */
#def 先计算priority_map 优先级中bit0-bit7最低位为1的偏移,也就是最高优先级
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
if (priority_group)
_tx_thread_highest_priority = _tx_thread_lowest_bit[priority_group];
else
{
/* Check for priorities 8-15. */
priority_map = priority_map >> TX_THREAD_GROUP_SIZE;
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
if (priority_group)
_tx_thread_highest_priority =
TX_THREAD_GROUP_1 + _tx_thread_lowest_bit[priority_group];
else
{
/* Check for priorities 16-23. */
priority_map = priority_map >> TX_THREAD_GROUP_SIZE;
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
if (priority_group)
_tx_thread_highest_priority =
TX_THREAD_GROUP_2 + _tx_thread_lowest_bit[priority_group];
else
{
priority_map = priority_map >> TX_THREAD_GROUP_SIZE;
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
if (priority_group)
_tx_thread_highest_priority =
TX_THREAD_GROUP_3 + _tx_thread_lowest_bit[priority_group];
else
{
/* Nothing else is ready. Set highest priority and execute thread
accordingly. */
_tx_thread_highest_priority = TX_MAX_PRIORITIES;
_tx_thread_execute_ptr = TX_NULL;
/* Restore interrupts. */
TX_RESTORE
/* Return control to the system. */
_tx_thread_system_return();
/* Return to caller. */
return;
}
}
}
}
/* Determine if this thread is the thread designated to execute. */
#def 自我挂起
if (thread_ptr == _tx_thread_execute_ptr)
{
/* Pickup the highest priority thread to execute. */
#def 先设置最高优先级(前面计算出来的)线程为执行线程
_tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
/* Determine if a previous thread with preemption threshold was
preempted. */
#def 如果_tx_thread_preempted_map不为0,说明之前发生了基于preemption threshold门限值的抢占,那么下一个执行线程选择必须考虑preemption threshold门限值
if (_tx_thread_preempted_map)
{
/* Disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Interrupts are enabled briefly here to keep the interrupt
lockout time deterministic. */
/* Disable interrupts again. */
TX_DISABLE
/* Decrement the preemption disable variable. */
_tx_thread_preempt_disable--;
/* Calculate the thread with preemption threshold set that
was interrupted by a thread above the preemption level. */
/* Put the preempt map in a working copy. */
priority_map = _tx_thread_preempted_map;
/* Find the highest priority preempted thread. */
#def 选择出被抢占的最高优先级
/* Check for priorities 0-7. */
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
if (priority_group)
priority = _tx_thread_lowest_bit[priority_group];
else
{
/* Check for priorities 8-15. */
priority_map = priority_map >> TX_THREAD_GROUP_SIZE;
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
if (priority_group)
priority =
TX_THREAD_GROUP_1 + _tx_thread_lowest_bit[priority_group];
else
{
/* Check for priorities 16-23. */
priority_map = priority_map >> TX_THREAD_GROUP_SIZE;
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
if (priority_group)
priority =
TX_THREAD_GROUP_2 + _tx_thread_lowest_bit[priority_group];
else
{
priority_map = priority_map >> TX_THREAD_GROUP_SIZE;
priority_group = (UCHAR) (priority_map & TX_THREAD_PRIORITY_GROUP_MASK);
priority =
TX_THREAD_GROUP_3 + _tx_thread_lowest_bit[priority_group];
}
}
}
/* Determine if the next highest priority thread is above the highest
priority threshold value. */
#def 如果选择出的被抢占的最高优先级抢占门限小于最高优先级,那么设置执行线程为被抢占的最高优先级线程
if (_tx_thread_highest_priority >=
(_tx_thread_priority_list[priority] -> tx_preempt_threshold))
{
/* Thread not allowed to execute until earlier preempted thread
finishes or lowers its preemption threshold. */
_tx_thread_execute_ptr = _tx_thread_priority_list[priority];
/* Clear the corresponding bit in the preempted map, since the
preemption has been restored. */
_tx_thread_preempted_map =
_tx_thread_preempted_map & ~(_tx_thread_execute_ptr -> tx_priority_bit);
}
}
}
/* Restore interrupts. */
TX_RESTORE
/* Determine if we need to return to the system. This needs to happen if a self suspension
takes place or if a higher-priority thread was resumed by an ISR in the part of the
suspension process that has interrupts enabled. */
if ((_tx_thread_current_ptr != _tx_thread_execute_ptr) && (_tx_thread_system_state == 0))
{
/* Return control to the system. */
_tx_thread_system_return();
}
/* Return to caller. */
return;
}
}
else
{
#def 不在需要挂起,直接返回。
/* Thread not still suspending... Restore interrupts. */
TX_RESTORE
/* Check for a preemption condition that might have occurred from an ISR. */
if ((_tx_thread_current_ptr != _tx_thread_execute_ptr) && (_tx_thread_system_state == 0))
/* Return control to the system. */
_tx_thread_system_return();
}
}
来源:CSDN
作者:osnet
链接:https://blog.csdn.net/qq_45683435/article/details/104172088