/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** ThreadX Component                                                     */
/**                                                                       */
/**   Thread                                                              */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/

#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE


/* Include necessary system files.  */

#include "tx_api.h"
#include "tx_thread.h"


#ifdef TX_DISABLE_INLINE

/* Define the routine to calculate the lowest set bit.  */

UINT  _tx_thread_lowest_set_bit_calculate(ULONG map)
{
UINT    bit_set;

    if ((map & ((ULONG) 0x1)) != ((ULONG) 0))
    {
        bit_set = ((UINT) 0);
    }
    else
    {
        map =  map & (ULONG) ((~map) + ((ULONG) 1));
        if (map < ((ULONG) 0x100))
        {
            bit_set = ((UINT) 1);
        }
        else if (map < ((ULONG) 0x10000))
        {
            bit_set =  ((UINT) 9);
            map =  map >> ((UINT) 8);
        }
        else if (map < ((ULONG) 0x01000000))
        {
            bit_set = ((UINT) 17);
            map = map >> ((UINT) 16);
        }
        else
        {
            bit_set = ((UINT) 25);
            map = map >> ((UINT) 24);
        }
        if (map >= ((ULONG) 0x10))
        {
            map = map >> ((UINT) 4);
            bit_set = bit_set + ((UINT) 4);
        }
        if (map >= ((ULONG) 0x4))
        {
            map = map >> ((UINT) 2);
            bit_set = bit_set + ((UINT) 2);
        }
        bit_set = bit_set - (UINT) (map & (ULONG) 0x1);
    }

    return(bit_set);
}


/* Define the next priority macro. Note, that this may be overridden
   by a port specific definition.  */

#if TX_MAX_PRIORITIES > 32

UINT _tx_thread_smp_next_priority_find(UINT priority)
{
ULONG           map_index;
ULONG           local_priority_map_active;
ULONG           local_priority_map;
ULONG           priority_bit;
ULONG           first_bit_set;
ULONG           found_priority;

    found_priority =  ((UINT) TX_MAX_PRIORITIES);
    if (priority < ((UINT) TX_MAX_PRIORITIES))
    {
        map_index =  priority/((UINT) 32);
        local_priority_map =  _tx_thread_priority_maps[map_index];
        priority_bit =        (((ULONG) 1) << (priority % ((UINT) 32)));
        local_priority_map =  local_priority_map & ~(priority_bit - ((UINT)1));
        if (local_priority_map != ((ULONG) 0))
        {
            TX_LOWEST_SET_BIT_CALCULATE(local_priority_map, first_bit_set)
            found_priority =  (map_index * ((UINT) 32)) + first_bit_set;
        }
        else
        {
            /* Move to next map index.  */
            map_index++;
            if (map_index < (((UINT) TX_MAX_PRIORITIES)/((UINT) 32)))
            {
                priority_bit =               (((ULONG) 1) << (map_index));
                local_priority_map_active =  _tx_thread_priority_map_active & ~(priority_bit - ((UINT) 1));
                if (local_priority_map_active != ((ULONG) 0))
                {
                    TX_LOWEST_SET_BIT_CALCULATE(local_priority_map_active, map_index)
                    local_priority_map =  _tx_thread_priority_maps[map_index];
                    TX_LOWEST_SET_BIT_CALCULATE(local_priority_map, first_bit_set)
                    found_priority =  (map_index * ((UINT) 32)) + first_bit_set;
                }
            }
        }
    }
    return(found_priority);
}
#else

UINT _tx_thread_smp_next_priority_find(UINT priority)
{
UINT            first_bit_set;
ULONG           local_priority_map;
UINT            next_priority;

    local_priority_map =  _tx_thread_priority_maps[0];
    local_priority_map =  local_priority_map >> priority;
    next_priority =  priority;
    if (local_priority_map == ((ULONG) 0))
    {
        next_priority =  ((UINT) TX_MAX_PRIORITIES);
    }
    else
    {
        if (next_priority >= ((UINT) TX_MAX_PRIORITIES))
        {
            next_priority =  ((UINT) TX_MAX_PRIORITIES);
        }
        else
        {
            TX_LOWEST_SET_BIT_CALCULATE(local_priority_map, first_bit_set)
            next_priority =  priority + first_bit_set;
        }
    }

    return(next_priority);
}
#endif


void  _tx_thread_smp_schedule_list_clear(void)
{
#if TX_THREAD_SMP_MAX_CORES > 6
UINT    i;
#endif


    /* Clear the schedule list.  */
    _tx_thread_smp_schedule_list[0] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 1
    _tx_thread_smp_schedule_list[1] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 2
    _tx_thread_smp_schedule_list[2] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 3
    _tx_thread_smp_schedule_list[3] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 4
    _tx_thread_smp_schedule_list[4] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 5
    _tx_thread_smp_schedule_list[5] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 6

    /* Loop to clear the remainder of the schedule list.  */
    i =  ((UINT) 6);

#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX

    while (i < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (i < _tx_thread_smp_max_cores)
#endif
    {
        /* Clear entry in schedule list.  */
        _tx_thread_smp_schedule_list[i] =  TX_NULL;

        /* Move to next index.  */
        i++;
    }
#endif
#endif
#endif
#endif
#endif
#endif
}

VOID  _tx_thread_smp_execute_list_clear(void)
{
#if TX_THREAD_SMP_MAX_CORES > 6
UINT    j;
#endif

    /* Clear the execute list.  */
    _tx_thread_execute_ptr[0] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 1
    _tx_thread_execute_ptr[1] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 2
    _tx_thread_execute_ptr[2] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 3
    _tx_thread_execute_ptr[3] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 4
    _tx_thread_execute_ptr[4] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 5
    _tx_thread_execute_ptr[5] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 6

    /* Loop to clear the remainder of the execute list.  */
    j =  ((UINT) 6);

#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX

    while (j < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (j < _tx_thread_smp_max_cores)
#endif
    {

        /* Clear entry in execute list.  */
        _tx_thread_execute_ptr[j] =  TX_NULL;

        /* Move to next index.  */
        j++;
    }
#endif
#endif
#endif
#endif
#endif
#endif
}


VOID  _tx_thread_smp_schedule_list_setup(void)
{
#if TX_THREAD_SMP_MAX_CORES > 6
UINT    j;
#endif

    _tx_thread_smp_schedule_list[0] =  _tx_thread_execute_ptr[0];
#if TX_THREAD_SMP_MAX_CORES > 1
    _tx_thread_smp_schedule_list[1] =  _tx_thread_execute_ptr[1];
#if TX_THREAD_SMP_MAX_CORES > 2
    _tx_thread_smp_schedule_list[2] =  _tx_thread_execute_ptr[2];
#if TX_THREAD_SMP_MAX_CORES > 3
    _tx_thread_smp_schedule_list[3] =  _tx_thread_execute_ptr[3];
#if TX_THREAD_SMP_MAX_CORES > 4
    _tx_thread_smp_schedule_list[4] =  _tx_thread_execute_ptr[4];
#if TX_THREAD_SMP_MAX_CORES > 5
    _tx_thread_smp_schedule_list[5] =  _tx_thread_execute_ptr[5];
#if TX_THREAD_SMP_MAX_CORES > 6

    /* Loop to setup the remainder of the schedule list.  */
    j =  ((UINT) 6);

#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
    while (j < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (j < _tx_thread_smp_max_cores)
#endif
    {

        /* Setup entry in schedule list.  */
        _tx_thread_smp_schedule_list[j] =  _tx_thread_execute_ptr[j];

        /* Move to next index.  */
        j++;
    }
#endif
#endif
#endif
#endif
#endif
#endif
}


#ifdef TX_THREAD_SMP_INTER_CORE_INTERRUPT
VOID  _tx_thread_smp_core_interrupt(TX_THREAD *thread_ptr, UINT current_core, UINT target_core)
{

TX_THREAD   *current_thread;


    /* Make sure this is a different core, since there is no need to interrupt the current core for
       a scheduling change.  */
    if (current_core != target_core)
    {

        /* Yes, a different core is present.  */

        /* Pickup the currently executing thread.  */
        current_thread =  _tx_thread_current_ptr[target_core];

        /* Determine if they are the same.  */
        if ((current_thread != TX_NULL) && (thread_ptr != current_thread))
        {

            /* Not the same and not NULL... determine if the core is running at thread level.  */
            if (_tx_thread_system_state[target_core] < TX_INITIALIZE_IN_PROGRESS)
            {

                /* Preempt the mapped thread.  */
                _tx_thread_smp_core_preempt(target_core);
            }
        }
    }
}
#endif


#ifdef TX_THREAD_SMP_WAKEUP_LOGIC
VOID  _tx_thread_smp_core_wakeup(UINT current_core, UINT target_core)
{

    /* Determine if the core specified is not the current core - no need to wakeup the
       current core.  */
    if (target_core != current_core)
    {

        /* Wakeup based on application's macro.  */
        TX_THREAD_SMP_WAKEUP(target_core);
    }
}
#endif


VOID  _tx_thread_smp_execute_list_setup(UINT core_index)
{

TX_THREAD   *schedule_thread;
UINT        i;


    /* Loop to copy the schedule list into the execution list.  */
    i =  ((UINT) 0);
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX

    while (i < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (i < _tx_thread_smp_max_cores)
#endif
    {

        /* Pickup the thread to schedule.  */
        schedule_thread =  _tx_thread_smp_schedule_list[i];

        /* Copy the schedule list into the execution list.  */
        _tx_thread_execute_ptr[i] =  schedule_thread;

        /* If necessary, interrupt the core with the new thread to schedule.  */
        _tx_thread_smp_core_interrupt(schedule_thread, core_index, i);

#ifdef TX_THREAD_SMP_WAKEUP_LOGIC

        /* Does this need to be waked up?  */
        if ((i != core_index) && (schedule_thread != TX_NULL))
        {

            /* Wakeup based on application's macro.  */
            TX_THREAD_SMP_WAKEUP(i);
        }
#endif
        /* Move to next index.  */
        i++;
    }
}


ULONG  _tx_thread_smp_available_cores_get(void)
{

#if TX_THREAD_SMP_MAX_CORES > 6
UINT    j;
#endif
ULONG   available_cores;

    available_cores =  ((ULONG) 0);
    if (_tx_thread_execute_ptr[0] == TX_NULL)
    {
        available_cores =  ((ULONG) 1);
    }
#if TX_THREAD_SMP_MAX_CORES > 1
    if (_tx_thread_execute_ptr[1] == TX_NULL)
    {
        available_cores =  available_cores | ((ULONG) 2);
    }
#if TX_THREAD_SMP_MAX_CORES > 2
    if (_tx_thread_execute_ptr[2] == TX_NULL)
    {
        available_cores =  available_cores | ((ULONG) 4);
    }
#if TX_THREAD_SMP_MAX_CORES > 3
    if (_tx_thread_execute_ptr[3] == TX_NULL)
    {
        available_cores =  available_cores | ((ULONG) 8);
    }
#if TX_THREAD_SMP_MAX_CORES > 4
    if (_tx_thread_execute_ptr[4] == TX_NULL)
    {
        available_cores =  available_cores | ((ULONG) 0x10);
    }
#if TX_THREAD_SMP_MAX_CORES > 5
    if (_tx_thread_execute_ptr[5] == TX_NULL)
    {
        available_cores =  available_cores | ((ULONG) 0x20);
    }
#if TX_THREAD_SMP_MAX_CORES > 6

    /* Loop to setup the remainder of the schedule list.  */
    j =  ((UINT) 6);

#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
    while (j < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (j < _tx_thread_smp_max_cores)
#endif
    {

        /* Determine if this core is available.  */
        if (_tx_thread_execute_ptr[j] == TX_NULL)
        {
            available_cores =  available_cores | (((ULONG) 1) << j);
        }

        /* Move to next core.  */
        j++;
    }
#endif
#endif
#endif
#endif
#endif
#endif
    return(available_cores);
}


ULONG  _tx_thread_smp_possible_cores_get(void)
{

#if TX_THREAD_SMP_MAX_CORES > 6
UINT    j;
#endif
ULONG       possible_cores;
TX_THREAD   *thread_ptr;

    possible_cores =  ((ULONG) 0);
    thread_ptr =  _tx_thread_execute_ptr[0];
    if (thread_ptr != TX_NULL)
    {
        possible_cores =  thread_ptr -> tx_thread_smp_cores_allowed;
    }
#if TX_THREAD_SMP_MAX_CORES > 1
    thread_ptr =  _tx_thread_execute_ptr[1];
    if (thread_ptr != TX_NULL)
    {
        possible_cores =  possible_cores | thread_ptr -> tx_thread_smp_cores_allowed;
    }
#if TX_THREAD_SMP_MAX_CORES > 2
    thread_ptr =  _tx_thread_execute_ptr[2];
    if (thread_ptr != TX_NULL)
    {
        possible_cores =  possible_cores | thread_ptr -> tx_thread_smp_cores_allowed;
    }
#if TX_THREAD_SMP_MAX_CORES > 3
    thread_ptr =  _tx_thread_execute_ptr[3];
    if (thread_ptr != TX_NULL)
    {
        possible_cores =  possible_cores | thread_ptr -> tx_thread_smp_cores_allowed;
    }
#if TX_THREAD_SMP_MAX_CORES > 4
    thread_ptr =  _tx_thread_execute_ptr[4];
    if (thread_ptr != TX_NULL)
    {
        possible_cores =  possible_cores | thread_ptr -> tx_thread_smp_cores_allowed;
    }
#if TX_THREAD_SMP_MAX_CORES > 5
    thread_ptr =  _tx_thread_execute_ptr[5];
    if (thread_ptr != TX_NULL)
    {
        possible_cores =  possible_cores | thread_ptr -> tx_thread_smp_cores_allowed;
    }
#if TX_THREAD_SMP_MAX_CORES > 6

    /* Loop to setup the remainder of the schedule list.  */
    j =  ((UINT) 6);

#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
    while (j < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (j < _tx_thread_smp_max_cores)
#endif
    {

        /* Determine if this core is available.  */
        thread_ptr =  _tx_thread_execute_ptr[j];
        if (thread_ptr != TX_NULL)
        {
            possible_cores =  possible_cores | thread_ptr -> tx_thread_smp_cores_allowed;
        }

        /* Move to next core.  */
        j++;
    }
#endif
#endif
#endif
#endif
#endif
#endif
    return(possible_cores);
}


UINT  _tx_thread_smp_lowest_priority_get(void)
{

#if TX_THREAD_SMP_MAX_CORES > 6
UINT    j;
#endif
TX_THREAD   *thread_ptr;
UINT        lowest_priority;

    lowest_priority =  ((UINT) 0);
    thread_ptr =  _tx_thread_execute_ptr[0];
    if (thread_ptr != TX_NULL)
    {
        if (thread_ptr -> tx_thread_priority > lowest_priority)
        {
            lowest_priority =  thread_ptr -> tx_thread_priority;
        }
    }
#if TX_THREAD_SMP_MAX_CORES > 1
    thread_ptr =  _tx_thread_execute_ptr[1];
    if (thread_ptr != TX_NULL)
    {
        if (thread_ptr -> tx_thread_priority > lowest_priority)
        {
            lowest_priority =  thread_ptr -> tx_thread_priority;
        }
    }
#if TX_THREAD_SMP_MAX_CORES > 2
    thread_ptr =  _tx_thread_execute_ptr[2];
    if (thread_ptr != TX_NULL)
    {
        if (thread_ptr -> tx_thread_priority > lowest_priority)
        {
            lowest_priority =  thread_ptr -> tx_thread_priority;
        }
    }
#if TX_THREAD_SMP_MAX_CORES > 3
    thread_ptr =  _tx_thread_execute_ptr[3];
    if (thread_ptr != TX_NULL)
    {
        if (thread_ptr -> tx_thread_priority > lowest_priority)
        {
            lowest_priority =  thread_ptr -> tx_thread_priority;
        }
    }
#if TX_THREAD_SMP_MAX_CORES > 4
    thread_ptr =  _tx_thread_execute_ptr[4];
    if (thread_ptr != TX_NULL)
    {
        if (thread_ptr -> tx_thread_priority > lowest_priority)
        {
            lowest_priority =  thread_ptr -> tx_thread_priority;
        }
    }
#if TX_THREAD_SMP_MAX_CORES > 5
    thread_ptr =  _tx_thread_execute_ptr[5];
    if (thread_ptr != TX_NULL)
    {
        if (thread_ptr -> tx_thread_priority > lowest_priority)
        {
            lowest_priority =  thread_ptr -> tx_thread_priority;
        }
    }
#if TX_THREAD_SMP_MAX_CORES > 6

    /* Loop to setup the remainder of the schedule list.  */
    j =  ((UINT) 6);

#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
    while (j < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (j < _tx_thread_smp_max_cores)
#endif
    {

        /* Determine if this core has a thread scheduled.  */
        thread_ptr =  _tx_thread_execute_ptr[j];
        if (thread_ptr != TX_NULL)
        {

            /* Is this the new lowest priority?  */
            if (thread_ptr -> tx_thread_priority > lowest_priority)
            {
                lowest_priority =  thread_ptr -> tx_thread_priority;
            }
        }

        /* Move to next core.  */
        j++;
    }
#endif
#endif
#endif
#endif
#endif
#endif
    return(lowest_priority);
}


UINT  _tx_thread_smp_remap_solution_find(TX_THREAD *schedule_thread, ULONG available_cores, ULONG thread_possible_cores, ULONG test_possible_cores)
{

UINT            core;
UINT            previous_core;
ULONG           test_cores;
ULONG           last_thread_cores;
UINT            queue_first, queue_last;
UINT            core_queue[TX_THREAD_SMP_MAX_CORES-1];
TX_THREAD       *thread_ptr;
TX_THREAD       *last_thread;
TX_THREAD       *thread_remap_list[TX_THREAD_SMP_MAX_CORES];


    /* Clear the last thread cores in the search.  */
    last_thread_cores =  ((ULONG) 0);

    /* Set the last thread pointer to NULL.  */
    last_thread =  TX_NULL;

    /* Setup the core queue indices.  */
    queue_first =  ((UINT) 0);
    queue_last =   ((UINT) 0);

    /* Build a list of possible cores for this thread to execute on, starting
       with the previously mapped core.  */
    core =  schedule_thread -> tx_thread_smp_core_mapped;
    if ((thread_possible_cores & (((ULONG) 1) << core)) != ((ULONG) 0))
    {

        /* Remember this potential mapping.  */
        thread_remap_list[core] =   schedule_thread;
        core_queue[queue_last] =    core;

        /* Move to next slot.  */
        queue_last++;

        /* Clear this core.  */
        thread_possible_cores =  thread_possible_cores & ~(((ULONG) 1) << core);
    }

    /* Loop to add additional possible cores.  */
    while (thread_possible_cores != ((ULONG) 0))
    {

        /* Determine the first possible core.  */
        test_cores =  thread_possible_cores;
        TX_LOWEST_SET_BIT_CALCULATE(test_cores, core)

        /* Clear this core.  */
        thread_possible_cores =  thread_possible_cores & ~(((ULONG) 1) << core);

        /* Remember this potential mapping.  */
        thread_remap_list[core] =  schedule_thread;
        core_queue[queue_last] =   core;

        /* Move to next slot.  */
        queue_last++;
    }

    /* Loop to evaluate the potential thread mappings, against what is already mapped.  */
    do
    {

        /* Pickup the next entry.  */
        core = core_queue[queue_first];

        /* Move to next slot.  */
        queue_first++;

        /* Retrieve the thread from the current mapping.  */
        thread_ptr =  _tx_thread_smp_schedule_list[core];

        /* Determine if there is a thread currently mapped to this core.  */
        if (thread_ptr != TX_NULL)
        {

            /* Determine the cores available for this thread.  */
            thread_possible_cores =  thread_ptr -> tx_thread_smp_cores_allowed;
            thread_possible_cores =  test_possible_cores & thread_possible_cores;

            /* Are there any possible cores for this thread?  */
            if (thread_possible_cores != ((ULONG) 0))
            {

                /* Determine if there are cores available for this thread.  */
                if ((thread_possible_cores & available_cores) != ((ULONG) 0))
                {

                    /* Yes, remember the final thread and cores that are valid for this thread.  */
                    last_thread_cores =  thread_possible_cores & available_cores;
                    last_thread =        thread_ptr;

                    /* We are done - get out of the loop!  */
                    break;
                }
                else
                {

                    /* Remove cores that will be added to the list.  */
                    test_possible_cores =  test_possible_cores & ~(thread_possible_cores);

                    /* Loop to add this thread to the potential mapping list.  */
                    do
                    {

                        /* Calculate the core.  */
                        test_cores =  thread_possible_cores;
                        TX_LOWEST_SET_BIT_CALCULATE(test_cores, core)

                        /* Clear this core.  */
                        thread_possible_cores =  thread_possible_cores & ~(((ULONG) 1) << core);

                        /* Remember this thread for remapping.  */
                        thread_remap_list[core] =  thread_ptr;

                        /* Remember this core.  */
                        core_queue[queue_last] =  core;

                        /* Move to next slot.  */
                        queue_last++;

                    } while (thread_possible_cores != ((ULONG) 0));
                }
            }
        }
    } while (queue_first != queue_last);

    /* Was a remapping solution found?  */
    if (last_thread != TX_NULL)
    {

        /* Pickup the core of the last thread to remap.  */
        core =  last_thread -> tx_thread_smp_core_mapped;

        /* Pickup the thread from the remapping list.  */
        thread_ptr =  thread_remap_list[core];

        /* Loop until we arrive at the thread we have been trying to map.  */
        while (thread_ptr != schedule_thread)
        {

            /* Move this thread in the schedule list.  */
            _tx_thread_smp_schedule_list[core] =  thread_ptr;

            /* Remember the previous core.  */
            previous_core =  core;

            /* Pickup the core of thread to remap.  */
            core =  thread_ptr -> tx_thread_smp_core_mapped;

            /* Save the new core mapping for this thread.  */
            thread_ptr -> tx_thread_smp_core_mapped =  previous_core;

            /* Move the next thread.  */
            thread_ptr =  thread_remap_list[core];
        }

        /* Save the remaining thread in the updated schedule list.  */
        _tx_thread_smp_schedule_list[core] =  thread_ptr;

        /* Update this thread's core mapping.  */
        thread_ptr -> tx_thread_smp_core_mapped =  core;

        /* Finally, setup the last thread in the remapping solution.  */
        test_cores =  last_thread_cores;
        TX_LOWEST_SET_BIT_CALCULATE(test_cores, core)

        /* Setup the last thread.  */
        _tx_thread_smp_schedule_list[core] =     last_thread;

        /* Remember the core mapping for this thread.  */
        last_thread -> tx_thread_smp_core_mapped =  core;
    }
    else
    {

        /* Set core to the maximum value in order to signal a remapping solution was not found.  */
        core =  ((UINT) TX_THREAD_SMP_MAX_CORES);
    }

    /* Return core to the caller.  */
    return(core);
}


ULONG  _tx_thread_smp_preemptable_threads_get(UINT priority, TX_THREAD *possible_preemption_list[TX_THREAD_SMP_MAX_CORES])
{

UINT        i, j, k;
TX_THREAD   *thread_ptr;
TX_THREAD   *next_thread;
TX_THREAD   *search_thread;
TX_THREAD   *list_head;
ULONG       possible_cores =  ((ULONG) 0);


    /* Clear the possible preemption list.  */
    possible_preemption_list[0] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 1
    possible_preemption_list[1] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 2
    possible_preemption_list[2] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 3
    possible_preemption_list[3] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 4
    possible_preemption_list[4] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 5
    possible_preemption_list[5] =  TX_NULL;
#if TX_THREAD_SMP_MAX_CORES > 6

    /* Loop to clear the remainder of the possible preemption list.  */
    j =  ((UINT) 6);

#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX

    while (j < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (j < _tx_thread_smp_max_cores)
#endif
    {

        /* Clear entry in possible preemption list.  */
        possible_preemption_list[j] =  TX_NULL;

        /* Move to next core.  */
        j++;
    }
#endif
#endif
#endif
#endif
#endif
#endif

    /* Loop to build a list of threads of less priority.  */
    i =  ((UINT) 0);
    j =  ((UINT) 0);
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
    while (i < ((UINT) TX_THREAD_SMP_MAX_CORES))
#else

    while (i < _tx_thread_smp_max_cores)
#endif
    {

        /* Pickup the currently mapped thread.  */
        thread_ptr =  _tx_thread_execute_ptr[i];

        /* Is there a thread scheduled for this core?  */
        if (thread_ptr != TX_NULL)
        {

            /* Update the possible cores bit map.  */
            possible_cores =  possible_cores | thread_ptr -> tx_thread_smp_cores_allowed;

            /* Can this thread be preempted?  */
            if (priority < thread_ptr -> tx_thread_priority)
            {

                /* Thread that can be added to the preemption possible list.  */

                /* Yes, this scheduled thread is lower priority, so add it to the preemption possible list.  */
                possible_preemption_list[j] =  thread_ptr;

                /* Move to next entry in preemption possible list.  */
                j++;
            }
        }

        /* Move to next core.  */
        i++;
    }

    /* Check to see if there are more than 2 threads that can be preempted.  */
    if (j > ((UINT) 1))
    {

        /* Yes, loop through the preemption possible list and sort by priority.  */
        i =  ((UINT) 0);
        do
        {

            /* Pickup preemptable thread.  */
            thread_ptr =  possible_preemption_list[i];

            /* Initialize the search index.  */
            k =  i + ((UINT) 1);

            /* Loop to get the lowest priority thread at the front of the list.  */
            while (k < j)
            {

                /* Pickup the next thread to evaluate.  */
                next_thread =  possible_preemption_list[k];

                /* Is this thread lower priority?  */
                if (next_thread -> tx_thread_priority > thread_ptr -> tx_thread_priority)
                {

                    /* Yes, swap the threads.  */
                    possible_preemption_list[i] =  next_thread;
                    possible_preemption_list[k] =  thread_ptr;
                    thread_ptr =  next_thread;
                }
                else
                {

                    /* Compare the thread priorities.  */
                    if (next_thread -> tx_thread_priority == thread_ptr -> tx_thread_priority)
                    {

                        /* Equal priority threads...  see which is in the ready list first.  */
                        search_thread =   thread_ptr -> tx_thread_ready_next;

                        /* Pickup the list head.  */
                        list_head =  _tx_thread_priority_list[thread_ptr -> tx_thread_priority];

                        /* Now loop to see if the next thread is after the current thread preemption.  */
                        while (search_thread != list_head)
                        {

                            /* Have we found the next thread?  */
                            if (search_thread == next_thread)
                            {

                                /* Yes, swap the threads.  */
                                possible_preemption_list[i] =  next_thread;
                                possible_preemption_list[k] =  thread_ptr;
                                thread_ptr =  next_thread;
                                break;
                            }

                            /* Move to the next thread.  */
                            search_thread =  search_thread -> tx_thread_ready_next;
                        }
                    }

                    /* Move to examine the next possible preemptable thread.  */
                    k++;
                }
            }

            /* We have found the lowest priority thread to preempt, now find the next lowest.  */
            i++;
        }
        while (i < (j-((UINT) 1)));
    }

    /* Return the possible cores.  */
    return(possible_cores);
}

VOID  _tx_thread_smp_simple_priority_change(TX_THREAD *thread_ptr, UINT new_priority)
{

UINT            priority;
ULONG           priority_bit;
TX_THREAD       *head_ptr;
TX_THREAD       *tail_ptr;
#if TX_MAX_PRIORITIES > 32
UINT            map_index;
#endif

    /* Pickup the priority.  */
    priority =  thread_ptr -> tx_thread_priority;

    /* Determine if there are other threads at this priority that are
       ready.  */
    if (thread_ptr -> tx_thread_ready_next != thread_ptr)
    {

        /* Yes, there are other threads at this priority ready.  */

        /* Just remove this thread from the priority list.  */
        (thread_ptr -> tx_thread_ready_next) -> tx_thread_ready_previous =    thread_ptr -> tx_thread_ready_previous;
        (thread_ptr -> tx_thread_ready_previous) -> tx_thread_ready_next =    thread_ptr -> tx_thread_ready_next;

        /* Determine if this is the head of the priority list.  */
        if (_tx_thread_priority_list[priority] == thread_ptr)
        {

            /* Update the head pointer of this priority list.  */
            _tx_thread_priority_list[priority] =  thread_ptr -> tx_thread_ready_next;
        }
    }
    else
    {

        /* This is the only thread at this priority ready to run.  Set the head
           pointer to NULL.  */
        _tx_thread_priority_list[priority] =    TX_NULL;

#if TX_MAX_PRIORITIES > 32

        /* Calculate the index into the bit map array.  */
        map_index =  priority/((UINT) 32);
#endif

        /* Clear this priority bit in the ready priority bit map.  */
        TX_MOD32_BIT_SET(priority, priority_bit)
        _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit));

#if TX_MAX_PRIORITIES > 32

        /* Determine if there are any other bits set in this priority map.  */
        if (_tx_thread_priority_maps[MAP_INDEX] == ((ULONG) 0))
        {

            /* No, clear the active bit to signify this priority map has nothing set.  */
            TX_DIV32_BIT_SET(priority, priority_bit)
            _tx_thread_priority_map_active =  _tx_thread_priority_map_active & (~(priority_bit));
        }
#endif
    }

    /* Determine if the actual thread priority should be setup, which is the
       case if the new priority is higher than the priority inheritance.  */
    if (new_priority < thread_ptr -> tx_thread_inherit_priority)
    {

        /* Change thread priority to the new user's priority.  */
        thread_ptr -> tx_thread_priority =           new_priority;
        thread_ptr -> tx_thread_preempt_threshold =  new_priority;
    }
    else
    {

        /* Change thread priority to the priority inheritance.  */
        thread_ptr -> tx_thread_priority =           thread_ptr -> tx_thread_inherit_priority;
        thread_ptr -> tx_thread_preempt_threshold =  thread_ptr -> tx_thread_inherit_priority;
    }

    /* Now, place the thread at the new priority level.  */

    /* Determine if there are other threads at this priority that are
       ready.  */
    head_ptr =  _tx_thread_priority_list[new_priority];
    if (head_ptr != TX_NULL)
    {

        /* Yes, there are other threads at this priority already ready.  */

        /* Just add this thread to the priority list.  */
        tail_ptr =                                 head_ptr -> tx_thread_ready_previous;
        tail_ptr -> tx_thread_ready_next =         thread_ptr;
        head_ptr -> tx_thread_ready_previous =     thread_ptr;
        thread_ptr -> tx_thread_ready_previous =   tail_ptr;
        thread_ptr -> tx_thread_ready_next =       head_ptr;
    }
    else
    {

        /* First thread at this priority ready.  Add to the front of the list.  */
        _tx_thread_priority_list[new_priority] =   thread_ptr;
        thread_ptr -> tx_thread_ready_next =       thread_ptr;
        thread_ptr -> tx_thread_ready_previous =   thread_ptr;

#if TX_MAX_PRIORITIES > 32

        /* Calculate the index into the bit map array.  */
        map_index =  new_priority/((UINT) 32);

        /* Set the active bit to remember that the priority map has something set.  */
        TX_DIV32_BIT_SET(new_priority, priority_bit)
        _tx_thread_priority_map_active =  _tx_thread_priority_map_active | priority_bit;
#endif

        /* Or in the thread's priority bit.  */
        TX_MOD32_BIT_SET(new_priority, priority_bit)
        _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] | priority_bit;
    }
}

#endif


