线程控制块(TCB)
typedef struct TX_THREAD_STRUCT
{
/* The first section of the control block contains critical
information that is referenced by the port-specific
assembly language code. Any changes in this section could
necessitate changes in the assembly language. */
ULONG tx_thread_id; /* Control block ID */
ULONG tx_run_count; /* Thread's run counter */
VOID_PTR tx_stack_ptr; /* Thread's stack pointer */
VOID_PTR tx_stack_start; /* Stack starting address */
VOID_PTR tx_stack_end; /* Stack ending address */
ULONG tx_stack_size; /* Stack size */
ULONG tx_time_slice; /* Current time-slice */
ULONG tx_new_time_slice; /* New time-slice */
/* Define pointers to the next and previous ready threads. */
struct TX_THREAD_STRUCT
*tx_ready_next,
*tx_ready_previous;
/* Define the port extension field. This typically is defined
to white space, but some ports of ThreadX may need to have
additional fields in the thread control block. This is
defined in the file tx_port.h. */
TX_THREAD_PORT_EXTENSION
/***************************************************************/
/* Nothing after this point is referenced by the target-specific
assembly language. Hence, information after this point can
be added to the control block providing the complete system
is recompiled. */
CHAR_PTR tx_thread_name; /* Pointer to thread's name */
UINT tx_priority; /* Priority of thread (0-31)*/
UINT tx_state; /* Thread's execution state */
UINT tx_delayed_suspend; /* Delayed suspend flag */
UINT tx_suspending; /* Thread suspending flag */
UINT tx_preempt_threshold; /* Preemption threshold */
ULONG tx_priority_bit; /* Priority ID bit */
/* Define the thread's entry point and input parameter. */
VOID (*tx_thread_entry)(ULONG);
ULONG tx_entry_parameter;
/* Define the thread's timer block. This is used for thread
sleep and timeout requests. */
TX_INTERNAL_TIMER
tx_thread_timer;
/* Define the thread's cleanup function and associated data. This
is used to cleanup various data structures when a thread
suspension is lifted or terminated either by the user or
a timeout. */
VOID (*tx_suspend_cleanup)(struct TX_THREAD_STRUCT *);
VOID_PTR tx_suspend_control_block;
struct TX_THREAD_STRUCT
*tx_suspended_next,
*tx_suspended_previous;
ULONG tx_suspend_info;
VOID_PTR tx_additional_suspend_info;
UINT tx_suspend_option;
UINT tx_suspend_status;
/* Define a pointer for Green Hills use. */
VOID_PTR tx_eh_globals;
/* Define pointers to the next and previous threads in the
created list. */
struct TX_THREAD_STRUCT
*tx_created_next,
*tx_created_previous;
} TX_THREAD;
_tx_thread_create
UINT _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name,
VOID (*entry_function)(ULONG), ULONG entry_input,
VOID *stack_start, ULONG stack_size,
UINT priority, UINT preempt_threshold,
ULONG time_slice, UINT auto_start)
参数 | 意义 |
---|---|
thread_ptr | 线程控制块指针 |
name | 线程名字 |
entry_function | 线程入口函数 |
entry_input | 线程入口函数参数 |
stack_start | 线程使用的栈起始地址 |
stack_size | 线程栈大小 |
priority | 线程优先级 |
preempt_threshold | 线程抢占优先级(小于此值线程才能够抢占) |
time_slice | 时间片 (0表示不使用时间片轮转调度) |
auto_start | 线程创建后是否自动执行选项 |
UINT _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name,
VOID (*entry_function)(ULONG), ULONG entry_input,
VOID *stack_start, ULONG stack_size,
UINT priority, UINT preempt_threshold,
ULONG time_slice, UINT auto_start)
{
TX_INTERRUPT_SAVE_AREA
REG_1 TX_THREAD_PTR tail_ptr; /* Created list tail pointer */
#def 定义局部变量,放在寄存器中
#ifndef TX_DISABLE_STACK_CHECKING
/* Set the thread stack to a pattern prior to creating the initial
stack frame. This pattern is used by the stack checking routines
to see how much has been used. */
memset(stack_start, TX_STACK_FILL, stack_size);
#endif
/* Prepare the thread control block prior to placing it on the created
list. */
#def 设置线程控制块中变量值
/* Place the supplied parameters into the thread's control block. */
thread_ptr -> tx_thread_name = name;
thread_ptr -> tx_thread_entry = entry_function;
thread_ptr -> tx_entry_parameter = entry_input;
thread_ptr -> tx_stack_ptr = TX_NULL;
thread_ptr -> tx_stack_start = stack_start;
thread_ptr -> tx_stack_size = stack_size;
thread_ptr -> tx_stack_end = (VOID_PTR) (((CHAR_PTR) stack_start) + (stack_size-1));
thread_ptr -> tx_priority = priority & TX_THREAD_PRIORITY_MASK;
thread_ptr -> tx_preempt_threshold= preempt_threshold & TX_THREAD_PRIORITY_MASK;
thread_ptr -> tx_time_slice = time_slice;
thread_ptr -> tx_new_time_slice = time_slice;
/* Now fill in the values that are required for thread initialization. */
thread_ptr -> tx_run_count = 0;
#def 初始为挂起状态
thread_ptr -> tx_state = TX_SUSPENDED;
thread_ptr -> tx_delayed_suspend = TX_FALSE;
thread_ptr -> tx_suspending = TX_FALSE;
/* Setup the necessary fields in the thread timer block. */
thread_ptr -> tx_thread_timer.tx_timeout_function = _tx_thread_timeout;
thread_ptr -> tx_thread_timer.tx_timeout_param = (ULONG) thread_ptr;
thread_ptr -> tx_thread_timer.tx_list_head = TX_NULL;
thread_ptr -> tx_thread_timer.tx_re_initialize_ticks = 0;
/* Clear the suspension information. */
thread_ptr -> tx_suspend_cleanup = TX_NULL;
thread_ptr -> tx_suspend_control_block = TX_NULL;
thread_ptr -> tx_suspended_next = TX_NULL;
thread_ptr -> tx_suspended_previous= TX_NULL;
/* Setup the priority bit. */
thread_ptr -> tx_priority_bit = (((ULONG) 1) << (priority & TX_THREAD_PRIORITY_MASK));
/* Call the target specific stack frame building routine to build the
thread's initial stack and to setup the actual stack pointer in the
control block. */
#def 为这个线程创建栈空间,初始化栈内存,设置栈指针tx_stack_ptr
_tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);
/* Prepare to make this thread a member of the created thread list. */
#def 禁止中断,保证了操作下面全局变量临界资源;禁止中断可以让当前线程不被抢占;当前线程执行,说明当前线程现在是所有就绪队列中优先级最高的,其他更高优先级线程可能被挂起了。中断可能唤醒更高优先级线程
TX_DISABLE
/* Load the thread ID field in the thread control block. */
thread_ptr -> tx_thread_id = TX_THREAD_ID;
/* Place the thread on the list of created threads. First,
check for an empty list. */
#def 插入到_tx_thread_created_ptr 线程list
if (_tx_thread_created_ptr)
{
/* Pickup tail pointer. */
tail_ptr = _tx_thread_created_ptr -> tx_created_previous;
/* Place the new thread in the list. */
_tx_thread_created_ptr -> tx_created_previous = thread_ptr;
tail_ptr -> tx_created_next = thread_ptr;
/* Setup this thread's created links. */
thread_ptr -> tx_created_previous = tail_ptr;
thread_ptr -> tx_created_next = _tx_thread_created_ptr;
}
else
{
/* The created thread list is empty. Add thread to empty list. */
_tx_thread_created_ptr = thread_ptr;
thread_ptr -> tx_created_next = thread_ptr;
thread_ptr -> tx_created_previous = thread_ptr;
}
/* Increment the created thread counter. */
_tx_thread_created_count++;
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Register thread in the thread array structure. */
TX_EL_THREAD_REGISTER(thread_ptr);
/* Log this kernel call. */
TX_EL_THREAD_CREATE_INSERT
/* Green Hills specific code. */
{
#pragma weak __cpp_exception_init
extern void __cpp_exception_init(void **);
static void (*const cpp_init_funcp)(void **) = __cpp_exception_init;
if (cpp_init_funcp)
__cpp_exception_init(&(thread_ptr->tx_eh_globals));
}
/* End of Green Hills specific code. */
/* Restore previous interrupt posture. */
TX_RESTORE
/* Determine if an automatic start was requested. If so, call the resume
thread function and then check for a preemption condition. */
#def 入参为自动执行线程
if (auto_start)
{
/* Call the resume thread function to make this thread ready. Upon
return, check for a preemption condition caused by creating
a thread of higher priority. */
#def 把线程放入就绪对应优先级list,如果这个新线程需要立马执行(例如优先级最高),返回true,并设置了_tx_thread_execute_ptr线程
if (_tx_thread_resume(thread_ptr))
/* A preemption condition exists, pass control back to the
system in order to get the higher priority thread running. */
#def 调度进行线程切换,从_tx_thread_current_ptr当前执行前程切换到执行_tx_thread_execute_ptr线程,有汇编实现,与具体cpu体系相关
_tx_thread_system_return();
}
else
{
#def 不在动执行线程
/* Disable interrupts. */
TX_DISABLE
/* Remove temporary disable preemption. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
}
/* Always return a success. */
return(TX_SUCCESS);
}
示例
void tx_application_define(void *first_unused_memory)
{
CHAR *pointer;
/* Put first available memory address into a character pointer. */
pointer = (CHAR *) first_unused_memory;
/* Put system definition stuff in here, e.g. thread creates and other assorted
create information. */
/* Create the main thread. */
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
pointer, DEMO_STACK_SIZE,
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
/* Create threads 1 and 2. These threads pass information through a ThreadX
message queue. It is also interesting to note that these threads have a time
slice. */
tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
pointer, DEMO_STACK_SIZE,
16, 16, 4, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
pointer, DEMO_STACK_SIZE,
16, 16, 4, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
/* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
An interesting thing here is that both threads share the same instruction area. */
tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
pointer, DEMO_STACK_SIZE,
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
pointer, DEMO_STACK_SIZE,
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
/* Create thread 5. This thread simply pends on an event flag which will be set
by thread_0. */
tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
pointer, DEMO_STACK_SIZE,
4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
/* Create the message queue shared by threads 1 and 2. */
tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, 100*sizeof(ULONG));
pointer = pointer + (100*sizeof(ULONG));
/* Create the semaphore used by threads 3 and 4. */
tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
/* Create the event flags group used by threads 1 and 5. */
tx_event_flags_create(&event_flags_0, "event flags 0");
}