threadx 信号量 应用_threadx学习笔记(二)

本文深入解析threadx操作系统的初始化过程,包括_low_level_和_high_level_两个阶段,详细介绍了如何设置堆栈指针、中断处理及线程调度。此外,还探讨了信号量在threadx中的应用,以及线程、定时器和系统资源的初始化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tx_kernel_enter();进入threadx核

tx_kernel_enter()

void tx_kernel_enter(void)

所属文件    调用者    开关量

demo.C    启动代码    无

操作系统首先从从量表直接进入该函数,在函数以前没有进行任何的硬件及软件的初始化!该函数主要包含_tx_initialize_low_level(),_tx_initialize_high_level(),tx_application_define(_tx_initialize_unused_memory),_tx_thread_schedule()。

VOID _tx_initialize_kernel_enter(VOID)

{

/*确定编译器是否已经初始化过 */

if (_tx_thread_system_state != TX_INITIALIZE_ALMOST_DONE)

{

/* 没有初始化的话执行下面程序 */

/* 设置系统状态变量来表示现正在处理过程中 注意该变量在后边的中断嵌套中会使用    */

_tx_thread_system_state = TX_INITIALIZE_IN_PROGRESS;

/* 进行一些基本硬件设置,启动程序等 */

_tx_initialize_low_level();

/*进行一些高级的初始化*/

_tx_initialize_high_level();

}

/*设置系统状态变量来表示现正在处理过程中 注意该变量在后边的中断嵌套中会使用*/

_tx_thread_system_state = TX_INITIALIZE_IN_PROGRESS;

/* 调用初始化中提供的应用程序 把第一个未使用的变量地址传送给它 */

tx_application_define(_tx_initialize_unused_memory);

/*设置系统壮伟进入线程调度做准备*/

_tx_thread_system_state = TX_INITIALIZE_IS_FINISHED;

/* 进入线程循环开始执行线程 */

_tx_thread_schedule();

}

_tx_initialize_low_level()

void tx_kernel_enter(void)

所属文件    调用者    开关量

tx_till.s    启动代码    无

该函数实现对FIQ、IRQ和SVC模式下的sp寄存器的初始化,并对定时堆栈的基地址、大小和定时优先级变量进行初始化。

/* 进行一些基本硬件设置,启动程序等 */

/*该函数在文件tx_ill.s文件中*/

_tx_initialize_low_level();

;/* VOID _tx_initialize_low_level(VOID)

;{

EXPORT _tx_initialize_low_level

_tx_initialize_low_level

; /* 保存系统堆栈指针. */

; /* _tx_thread_system_stack_ptr = (VOID_PTR) A7 (SP); */

;    /*设置各个模式下的sp(堆栈指针)*/

; /* We must be in SVC mode at this point! */

;

LDR a2, =|Image$$ZI$$Limit| ; Get end of non-initialized RAM area

LDR a3, [pc, #FIQ_STACK_SIZE-.-8] ; 获得FIO堆栈地址(这里没有弄明白,有待?)

MOV a1, #FIQ_MODE ; 设置FIQ_MODE

MSR CPSR_c, a1 ; 进入FIQ模式

ADD a2, a2, a3 ;计算FIQ堆栈的开始

BIC a2, a2, #3 ; 将a2的低两位清零确保堆栈的的开始为long对齐

SUB a2, a2, #4 ; 往回退一个字

MOV sp, a2 ; 建立FIQ 堆栈指针(即FIQ模式的sp)

MOV sl, #0 ; Clear sl(R10)

MOV fp, #0 ; Clear fp(R11)

LDR a3, [pc, #SYS_STACK_SIZE-.-8]     ;获得 IRQ (system stack size)

MOV a1, #IRQ_MODE ; 建立IRQ模式的 CPSR

MSR CPSR_c, a1 ; 进入IRQ模式

ADD a2, a2, a3 ; 计算IRQ stack的开始

BIC a2, a2, #3 ; 将a2的低两位清零确保堆栈的的开始为long对齐

SUB a2, a2, #4 ; 往回退一个字

MOV sp, a2 ; 建立 IRQ 堆栈指针

MOV a1, #SVC_MODE ; 建立SVC模式的CPSR

MSR CPSR_c, a1 ; 进入 SVC模式

LDR a4, [pc, #SYS_STACK_PTR-.-8] ; 获得stack 指针

STR a2, [a4, #0] ; 保存系统堆栈

;

; /* Save the system stack pointer. */

; _tx_thread_system_stack_ptr = (VOID_PTR) (sp);

;

LDR a2, [pc, #SYS_STACK_PTR-.-8] ; 获得系统堆栈指针的地址

LDR a1, [a2, #0] ; 获得系统堆栈指针

ADD a1, a1, #4 ; 增加一个long长度

;

; /* Pickup the first available memory address. */

;

; /* Allocate space for the timer thread's stack. */

; _tx_timer_stack_start = first_available_memory;

; _tx_timer_stack_size = stack_size;

; _tx_timer_priority = 0;

;

LDR a2, [pc, #TIMER_STACK-.-8] ; 获得定时堆栈指针地址

LDR a4, [pc, #TIMER_STACK_SIZE-.-8] ; 获得定时堆栈大小地址

LDR a3, [pc, #TIM_STACK_SIZE-.-8] ; 获得实际定时堆栈大小

STR a1, [a2, #0] ;将定时堆栈的基地址放在堆栈指针地址所对应的内存中

STR a3, [a4, #0] ; 存储定时器堆栈大小

ADD a1, a1, a3 ; 新的空内存地址

LDR a2, [pc, #TIMER_PRIORITY-.-8] ; 获得定时器优先级地址

MOV a3, #0 ; 获得定时器线程优先级

STR a3, [a2, #0] ; 存储定时器线程优先级

; /*保存第一个变量内存地址. */

; _tx_initialize_unused_memory = (VOID_PTR) System Stack + Timer Stack;

;

LDR a3, [pc, #UNUSED_MEMORY-.-8] ;获得没有使用的内存指针地址

STR a1, [a3, #0] ; 保存第一个空内存地址

; /* 建立周期性的定时中断. */

STMDB {LR}            //让lr入栈,保护lr

BL    TargetInit                //TargetInit()为C语言编写的中断定时函数

LDMIA {lr}            //让lr出栈

在这里加上ARM定时器已实现周期性的中断

; /* Done, return to caller. */

;

MOV pc, lr ; Return to caller

;}

__tx_irq_handler

所属文件    调用者    开关量

tx_till.s     IRQ中断    无

该函数是在定时中断后调用,该函数调用了_tx_thread_context_save函数(包含在tx_tcs.s中),该函数又调用到__tx_irq_processing_return函数处(包含在tx_till.s)

EXPORT __tx_irq_handler

EXPORT __tx_irq_processing_return

__tx_irq_handler

;

; /* 调用函数保存线程上下文环境. */

B _tx_thread_context_save

__tx_irq_processing_return

;

; /* At this point execution is still in the IRQ mode. The CPSR, point of

; interrupt, and all C scratch registers are available for use. In

; addition, IRQ interrupts may be re-enabled - with certain restrictions -

; if nested IRQ interrupts are desired. Interrupts may be re-enabled over

; small code sequences where lr is saved before enabling interrupts and

; restored after interrupts are again disabled. */

;

; /* For debug purpose, execute the timer interrupt processing here. In

; a real system, some kind of status indication would have to be checked

; before the timer interrupt handler could be called. */

;

BL         clearflag        ;清除中断标志位很重要(自己移植时加的,位置是否恰当?)

BL _tx_timer_interrupt ; 定时中断处理函数

;

; /* 系统线程上下文环境恢复函数 */

B _tx_thread_context_restore

_tx_timer_interrupt

所属文件    调用者    开关量

tx_timin.s    启动代码    无

该函数主要是中断后将系统时钟加1,时间切片减1。定时部分比较多,没有完全看明白。

IMPORT _tx_timer_time_slice

IMPORT _tx_timer_system_clock

IMPORT _tx_timer_current_ptr

IMPORT _tx_timer_list_start

IMPORT _tx_timer_list_end

IMPORT _tx_timer_expired_time_slice

IMPORT _tx_timer_expired

IMPORT _tx_timer_thread

IMPORT _tx_thread_current_ptr

IMPORT _tx_thread_time_slice

IMPORT _tx_thread_resume

IMPORT _tx_thread_preempt_disable

;

PRESERVE8

AREA |C$$code|, CODE, READONLY

|x$codeseg| DATA

;VOID _tx_timer_interrupt(VOID)

;{

EXPORT _tx_timer_interrupt

_tx_timer_interrupt

;

; /* Upon entry to this routine, it is assumed that context save has already

; been called, and therefore the compiler scratch registers are available

; for use. */

;

; /* Increment the system clock. */

; _tx_timer_system_clock++;

;

LDR a2, [pc, #SYSTEM_CLOCK-.-8] ; 获得系统时钟地址

LDR a1, [a2, #0] ; 获得系统时钟

ADD a1, a1, #1 ; 将系统时钟加1

STR a1, [a2, #0] ; 存储新的系统时钟时间

;

; /* Test for time-slice expiration. */

; if (_tx_timer_time_slice)

; {

;

LDR a4, [pc, #TIME_SLICE-.-8] ; 获得链表中的定时切片数地址

LDR a3, [a4, #0] ; 获得定时切片数的值

CMP a3, #0 ; 定时切片是否有效,>0有效,=0无效

BEQ __tx_timer_no_time_slice ; =0时,跳到__tx_timer_no_time_slice处

; /* 时间切片减1. */

; _tx_timer_time_slice--;

;

SUB a3, a3, #1 ; 时间切片值减1

STR a3, [a4, #0] ; 存储新的时间切片值

;

; /* 检查是否到期. */

; if (__tx_timer_time_slice == 0)

;

CMP a3, #0 ; >0还是=0?

BNE __tx_timer_no_time_slice ; 如果>0,

;当没有定时切片时,将定时切片数标志位置1,表示链表中没有切片了。

; /* Set the time-slice expired flag. */

; _tx_timer_expired_time_slice = TX_TRUE;

;

LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; 获得定时切片数是否为0标志地址

MOV a1, #1 ; 将标志设为1

STR a1, [a4, #0] ; 设立到时标志

;

; }

;

__tx_timer_no_time_slice

;

; /* Test for timer expiration. */

; if (*_tx_timer_current_ptr)

; {

;

LDR a2, [pc, #TIMER_CURRENT_PTR-.-8] ; 获得的是_tx_timer_current_ptr的地址

;而TIMER_DECLARE TX_INTERNAL_TIMER **_tx_timer_current_ptr

;

LDR a1, [a2, #0] ; 获得当前的_tx_timer_current_ptr

LDR a3, [a1, #0] ; 获得定时列表的入口定时切片指针

CMP a3, #0 ;链表中是否有定时切片存在

BEQ __tx_timer_no_timer ; 不存在, 调用__tx_timer_no_time将

;_tx_timer_current_ptr++

;

; /* Set expiration flag. */

; _tx_timer_expired = TX_TRUE;

;

LDR a4, [pc, #EXPIRED-.-8] ; Pickup expriation flag address

MOV a3, #1 ; Build expired value

STR a3, [a4, #0] ; Set expired flag

B __tx_timer_done ; Finished timer processing

;

; }

; else

; {

__tx_timer_no_timer

;

; /* No timer expired, increment the timer pointer. */

; _tx_timer_current_ptr++;

;

ADD a1, a1, #4 ; Move to next timer

;

; /* Check for wrap-around. */

; if (_tx_timer_current_ptr == _tx_timer_list_end)

;

LDR a4, [pc, #LIST_END-.-8] ; Pickup addr of timer list end

LDR a3, [a4, #0] ; Pickup list end

CMP a1, a3 ; Are we at list end?

BNE __tx_timer_skip_wrap ; No, skip wrap-around logic

;

; /* Wrap to beginning of list. */

; _tx_timer_current_ptr = _tx_timer_list_start;

;

LDR a4, [pc, #LIST_START-.-8] ; Pickup addr of timer list start

LDR a1, [a4, #0] ; Set current pointer to list start

;

__tx_timer_skip_wrap

;

STR a1, [a2, #0] ; Store new current timer pointer

; }

;

__tx_timer_done

;

;

; /* See if anything has expired. */

; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))

; {

;

LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; Pickup addr of expired flag

LDR a3, [a4, #0] ; Pickup time-slice expired flag

CMP a3, #0 ; Did a time-slice expire?

BNE __tx_something_expired ; If non-zero, time-slice expired

LDR a2, [pc, #EXPIRED-.-8] ; Pickup addr of other expired flag

LDR a1, [a2, #0] ; Pickup timer expired flag

CMP a1, #0 ; Did a timer expire?

BEQ __tx_timer_nothing_expired ; No, nothing expired

;

__tx_something_expired

;

;

STR lr, [sp, #-4]! ; Save the lr register on the stack

;

; /* Did a timer expire? */

; if (_tx_timer_expired)

; {

;

LDR a2, [pc, #EXPIRED-.-8] ; Pickup addr of expired flag

LDR a1, [a2, #0] ; Pickup timer expired flag

CMP a1, #0 ; Check for timer expiration

BEQ __tx_timer_dont_activate ; If not set, skip timer activation

;

; /* Increment the preempt disable counter in preparation for

; thread resumption. */

; _tx_thread_preempt_disable++;

;

LDR a4, [pc, #PREEMPT_DISABLE-.-8] ; Pickup addr of preempt disable

LDR a3, [a4, #0] ; Pickup actual flag

ADD a3, a3, #1 ; Incrment the preempt disable count

STR a3, [a4, #0] ; Store it back

;

; /* Activate the system timer thread. */

; _tx_thread_resume(&_tx_timer_thread);

;

LDR a1, [pc, #TIMER_THREAD-.-8] ; Get timer thread control block addr

BL _tx_thread_resume ; Call thread resume to wake up the

; timer thread

;

; }

__tx_timer_dont_activate

;

; /* Did time slice expire? */

; if (_tx_timer_expired_time_slice)

; {

;

LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; Pickup addr of time-slice expired

LDR a3, [a4, #0] ; Pickup the actual flag

CMP a3, #0 ; See if the flag is set

BEQ __tx_timer_not_ts_expiration ; No, skip time-slice processing

;

; /* Time slice interrupted thread. */

; if (!_tx_thread_time_slice())

; _tx_timer_time_slice = _tx_thread_current_ptr -> tx_time_slice;

;

BL _tx_thread_time_slice ; Call time-slice processing

CMP a1, #0 ; Check return status

BNE __tx_timer_not_ts_expiration ; If time-sliced, skip reset processing

LDR a2, [pc, #CURRENT_PTR-.-8] ; Pickup addr of current thread pointer

LDR a1, [a2, #0] ; Pickup thread pointer

LDR a3, [a1, #24] ; Pickup fresh time-slice for thread

; (a fresh time slice was setup in

; the _tx_thread_time_slice function)

LDR a4, [pc, #TIME_SLICE-.-8] ; Pickup addr of time-slice variable

STR a3, [a4, #0] ; Setup new time-slice

;

; }

;

__tx_timer_not_ts_expiration

;

LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; Pickup address of expired time-slice flag

MOV a1, #0 ; Clear value

STR a1, [a4, #0] ; Clear time-slice expired flag

;

LDR lr, [sp], #4 ; Recover lr register

;

; }

;

__tx_timer_nothing_expired

;

MOV pc, lr ; Return to caller

;

;}

TIME_SLICE

DCD _tx_timer_time_slice

SYSTEM_CLOCK

DCD _tx_timer_system_clock

TIMER_CURRENT_PTR

DCD _tx_timer_current_ptr

LIST_START

DCD _tx_timer_list_start

LIST_END

DCD _tx_timer_list_end

EXPIRED_TIME_SLICE

DCD _tx_timer_expired_time_slice

EXPIRED

DCD _tx_timer_expired

TIMER_THREAD

DCD _tx_timer_thread

CURRENT_PTR

DCD _tx_thread_current_ptr

THREAD_TIME_SLICE

DCD _tx_thread_time_slice

RESUME

DCD _tx_thread_resume

PREEMPT_DISABLE

DCD _tx_thread_preempt_disable

END

_tx_initialize_high_level()

VOID _tx_initialize_high_level(VOID)

所属文件    调用者    开关量

tx_ihl.c    启动代码    无

主要时对一些与硬件无关的变量进行初始化,其中主要实现了线程的初始化;定时的初始化,这里定时也是一个线程,且优先级为最高0;还有对信号量、队列、时间标志、块池、和字节池的初始化。

/*进行一些高级的初始化*/

_tx_initialize_high_level();

VOID _tx_initialize_high_level(VOID)

{

/* Initialize the event log, if enabled. */

TX_EL_INITIALIZE

/* 调用线程初始化函数. */

_tx_thread_initialize();

/* 调用定时初始化函数 */

_tx_timer_initialize();

/* 调用信号量初始化函数 */

_tx_semaphore_initialize();

/* 调用队列初始化函数 */

_tx_queue_initialize();

/* 调用事件标志初始化函数. */

_tx_event_flags_initialize();

/* 调用block pool 初始化函数. */

_tx_block_pool_initialize();

/* 调用byte pool初始化函数. */

_tx_byte_pool_initialize();

}

/* 调用线程初始化函数. */

_tx_thread_initialize();

VOID _tx_thread_initialize(VOID)

所属文件    调用者    开关量

tx_ti.c    启动代码    无

此函数主要实现对与线程有关的一些变量进行初始化。

VOID _tx_thread_initialize(VOID)

{

REG_1 UINT i; /* Working index variable */

REG_2 UCHAR set_bit; /* Lowest set bit          */ H

REG_3 UINT temp; /* Working shift variable     */

REG_4 UCHAR *lowest_set_ptr; /* Pointer in set bit array     */

REG_5 TX_THREAD_PTR    *priority_list_ptr; /* Pointer in priority list */

/* Note: the system stack pointer and the system state variables are

initialized by the low and high-level initialization functions,

respectively. */

/* 初始化当前线程指针为空 */

_tx_thread_current_ptr = TX_NULL;

/* 初始化要执行线程指针为空. */

_tx_thread_execute_ptr = TX_NULL;

/* 初始化优先级信息 */

_tx_thread_priority_map = 0;

_tx_thread_preempted_map = 0;

_tx_thread_highest_priority = TX_MAX_PRIORITIES;

/* 初始化the lowest-set bit 表. 这被用来当线程被挂起和从新启动时寻找下一个准备执行的线程 */

_tx_thread_lowest_bit[0] = 0;

lowest_set_ptr = &_tx_thread_lowest_bit[1];

for (i = 1; i < TX_THREAD_MAX_BYTE_VALUES; i++)

{

/*将当前序号给临时变量 */

temp = i;

/* 寻找字节中的最低比特位设置,即在一个字节中的最高优先级 */ r

set_bit = 0;

while (!(temp & 1))

{

/*把序号往右移动一位.并且增加set-bit 的位置. */

temp = temp >> 1;

set_bit++;

}

/* 预先求出对应的线程优先级byte值所对应的优先级最高的的bit位*/ *(lowest_set_ptr++) = set_bit;

/*例如priorityb_byte的值为5即0x101那么所对应的优先级最高为0,则

lowest_set_ptr[priorityb_byte]=0*/

}

/*当优先级字节的值为i时,我们很快可以知道该字节的高优先级为第_tx_thread_lowest_bit[i]bit位。*/

/* 初始化优先级头指针队列. 即将线程块对应的空间都初始化为空 */

priority_list_ptr = &_tx_thread_priority_list[0];

for (i = 0; i < TX_MAX_PRIORITIES; i++)

*(priority_list_ptr++) = TX_NULL;

/* I初始化以创建线程列表的头指针和以创建线程的个数*/

_tx_thread_created_ptr = TX_NULL;

_tx_thread_created_count = 0;

/* Clear the global preempt disable variable. ???*/

_tx_thread_preempt_disable = 0;

}

VOID _tx_timer_initialize(VOID)

所属文件    调用者    开关量

tx_timi.c    启动代码    无

主要实现有定时器有关的一些变量的初始化,并建立了一个线程专门由于定时管理。

/* 调用定时初始化函数 */

_tx_timer_initialize();

VOID _tx_timer_initialize(VOID)

{

REG_1 UINT i; /* Working index variable */

REG_2 TX_INTERNAL_TIMER **timer_ptr; /* Working timer pointer */

/* 初始化系统时钟为 0. */

_tx_timer_system_clock = 0;

/*初始化时间切片的值为0以确保它是无效的 ?? */

_tx_timer_time_slice = 0;

/* 清除时间期限终止标志位 */

_tx_timer_expired_time_slice = TX_FALSE;

_tx_timer_expired = TX_FALSE;

/* 初始化线程并且定时管理控制结构的应用 */

/*首先初始化定时指针列表,即将列表中存储的指针都赋为空 */

timer_ptr = &_tx_timer_list[0];

for (i = 0; i < TX_TIMER_ENTRIES; i++)

*timer_ptr++ = TX_NULL;

/* 初始化所有列表指针. */

_tx_timer_list_start = &_tx_timer_list[0];

_tx_timer_current_ptr = &_tx_timer_list[0];

/* 设置定时列表的尾指针为实际定时列表的的指针再加1, 事件中断处理在前面的汇编语言中已经定义过了 (就是_tx_irq_handler) */

_tx_timer_list_end = &_tx_timer_list[TX_TIMER_ENTRIES-1];

_tx_timer_list_end = _tx_timer_list_end + 1;

/* 创建一个系统定时线程 这个线程处理所有的定时期限终止和从新调度. 它的堆栈和优先级在前面的low-level initialization component已经定义过了(从新回去看)*/

_tx_thread_create(&_tx_timer_thread, "System Timer Thread", _tx_timer_thread_entry,

(ULONG) TX_TIMER_ID, _tx_timer_stack_start, _tx_timer_stack_size,

_tx_timer_priority, _tx_timer_priority, TX_NO_TIME_SLICE,TX_DONT_START);

/*_tx_timer_stack_start, _tx_timer_stack_size,_tx_timer_priority,是在tx_ill.s中进行了初始化,其中_timer_stack_size=1024,_tx_timer_priority=0*/

/*初始化已建定时列表的指针 */

_tx_timer_created_ptr = TX_NULL;

/* 初始化已建定时数为0 */

_tx_timer_created_count = 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值