ThreadX * TX * thread * suspend thread

The execution thread can call "TX" thread "suspend itself,
Or call "TX" thread "suspend to suspend a thread

Set TX? State or TX? Suspending before thread suspending

    /* Set the suspending flag.  */
    thread_ptr -> tx_suspending =  TX_TRUE;

If the suspended thread is the current execution thread (self suspended), you need to select the next highest priority thread from the ready queue as the execution thread. Self suspension indicates that the current thread is the highest priority thread:
1. If there are other threads in the current thread ready queue, select the next thread in the same ready queue
2. If the current thread is the only thread in the ready queue, find the next highest priority ready queue, and select the first thread as the execution thread.
3. When selecting the next highest level ready queue, it is necessary to consider the preemption based on the 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 off interrupt to prevent preemption
    TX_DISABLE

    /* Decrement the preemption disable variable.  */
    #def has turned off interrupt. Preemption is forbidden. Call the external function of this function++
    _tx_thread_preempt_disable--;

    /* Check to make sure the thread suspending flag is still set.  If not, it
       has already been resumed.  */
    #def calls the function of this function to set TX ﹣ suspending to TX ﹣ true. If it is not TX ﹣ true, the thread has been resumed. For example, interrupt processing and high priority thread have resumed the thread to be suspended
    if (thread_ptr -> tx_suspending)
    {
	#def continue pending process
	
        /* 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 there are other threads in the same priority ready queue; remove the suspended thread from the queue
        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 suspend thread is the first thread in the ready queue, so it may be the currently executing thread. Only the first thread in the ready queue can be the current executing thread.
            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 if this thread has been preempted and the "TX" thread "preempted" map is set, clear it here
                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 the suspended thread is the execution thread, and the highest priority thread needs to be re selected as the execution thread. Because the suspended thread is the execution thread, it means that the ready queue is the highest priority, so the next thread in the ready queue is actually selected here
                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 interrupt enable
            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.  */
               #The execution thread selected by def is no longer the current thread for scheduling
               #def 1. If the thread is suspended by itself (the suspended thread is the current thread), the selected thread must not be the current thread
               #def 2, the above interrupt is enabled. Before executing the following code, there may be an interrupt. In the interrupt processing, the high priority thread is awakened and the current executing thread is suspended
            if ((_tx_thread_current_ptr != _tx_thread_execute_ptr) && (_tx_thread_system_state == 0))
            {
                /* Return control to the system.  */
                #def schedule switch thread
                _tx_thread_system_return();
            }

            /* Return to caller.  */
            return;
        }
        else
        {
	#def suspend thread is in the ready queue without other threads
	#def 1 if another thread calls a suspended thread, you only need to delete the thread that needs to be suspended
	#If def 2 is self suspend, the current execution thread is the highest priority thread, and the next highest priority thread needs to be selected
	
            /* 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 ready queue has only one pending thread, so you need to clear the corresponding bitmap 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.  */
		#ABCD low_ Bit [1] is 0, bit [2], the lowest bit 1 of index 2 (0b0010) is bit1, so bit [1] is 1, bit [3], the lowest bit 1 of index 3 (0b0011) is bit0, so bit [1] is 0
		
            /* Check for priorities 0-7.  */
            #def first calculates the offset of bit0-bit7 with the lowest bit 1 in priority map priority, that is, the highest priority
            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 self suspend
            if (thread_ptr == _tx_thread_execute_ptr)
            {

                /* Pickup the highest priority thread to execute.  */
                #def first set the highest priority (calculated earlier) thread as the execution thread
                _tx_thread_execute_ptr =  _tx_thread_priority_list[_tx_thread_highest_priority];

                /* Determine if a previous thread with preemption threshold was 
                   preempted.  */
                #If the "TX" thread "preempted" map is not 0, it means that preemption based on the preemption threshold has occurred before, then the next execution thread selection must consider the 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 selects the highest priority to be preempted
                    /* 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 the selected highest priority preemption threshold is lower than the highest priority, the execution thread is set to the highest priority preempted thread
                    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 doesn't need to be suspended anymore, it returns directly.
        /* 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();
    }
}
27 original articles published, praised 2, visits 2414
Private letter follow

Posted on Tue, 04 Feb 2020 13:47:01 -0500 by Duswa