点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!
6.2.2 Xenomai3:创建实时线程第一弹之改头换面pthread_create
按照《6.2.1 Xenomai3: hello world演示线程创建》演示的例子,“helloworld”线程是由pthread_create创建的。pthread_create 是 POSIX 线程(pthread)库中的一个函数,用于创建一个新的线程。
使用gdb ./hello进行调试,执行break 56在第56行设置断点。执行run开始运行,在第56行中断。
执行break pthread_create,在pthread库的pthread_create.c中第625行即pthread_create函数设置中断断点。
执行c,触发中断。
执行bt命令,得到当前的函数执行堆栈。
在hello.c的第56行,原先是直接调用libpthread库的pthread_create函数,但是从堆栈信息来看,反而改头换面,调用了libcobalt库的__wrap_pthread_create函数。这是如何做到的?
从《6.2.1 Xenomai3: hello world演示线程创建》的makefile可知,编译链接时使用了Xenomai posix skin:
获取编译参数
root@u2204:~/ipipe-arm64/xenomai_install# DESTDIR=$(pwd) usr/xenomai/bin/xeno-config --skin=posix --cflags
-I/root/ipipe-arm64/xenomai_install/usr/xenomai/include/cobalt -I/root/ipipe-arm64/xenomai_install/usr/xenomai/include -march=armv8-a -D_GNU_SOURCE -D_REENTRANT -fasynchronous-unwind-tables -D__COBALT__ -D__COBALT_WRAP__
获取链接参数
root@u2204:~/ipipe-arm64/xenomai_install# DESTDIR=$(pwd) usr/xenomai/bin/xeno-config --skin=posix --ldflags
-Wl,--no-as-needed -Wl,@/root/ipipe-arm64/xenomai_install/usr/xenomai/lib/cobalt.wrappers -Wl,@/root/ipipe-arm64/xenomai_install/usr/xenomai/lib/modechk.wrappers /root/ipipe-arm64/xenomai_install/usr/xenomai/lib/xenomai/bootstrap.o -Wl,--wrap=main -Wl,--dynamic-list=/root/ipipe-arm64/xenomai_install/usr/xenomai/lib/dynlist.ld -L/root/ipipe-arm64/xenomai_install/usr/xenomai/lib -lcobalt -lmodechk -lpthread -lrt -march=armv8-a
关键点,是链接参数中的一个标志:
-Wl,@/root/xenomai/xenomai-v3.2.1/lib/cobalt/cobalt.wrappers
-Wl,@/root/xenomai/xenomai-v3.2.1/lib/cobalt/cobalt.wrappers
//文件内容
# cat lib/cobalt/cobalt.wrappers
--wrap pthread_attr_init
--wrap pthread_create
--wrap pthread_setschedparam
--wrap pthread_getschedparam
--wrap pthread_setschedprio
--wrap pthread_yield
--wrap sched_yield
--wrap sched_get_priority_min
--wrap sched_get_priority_max
--wrap sched_setscheduler
--wrap sched_getscheduler
--wrap pthread_kill
--wrap pthread_join
--wrap pthread_setname_np
--wrap sem_init
--wrap sem_destroy
--wrap sem_post
--wrap sem_timedwait
--wrap sem_wait
--wrap sem_trywait
--wrap sem_getvalue
--wrap sem_open
--wrap sem_close
--wrap sem_unlink
--wrap clock_getres
--wrap clock_gettime
--wrap clock_settime
--wrap clock_adjtime
--wrap clock_nanosleep
--wrap nanosleep
--wrap pthread_mutex_init
--wrap pthread_mutex_destroy
--wrap pthread_mutex_lock
--wrap pthread_mutex_trylock
--wrap pthread_mutex_timedlock
--wrap pthread_mutex_unlock
--wrap pthread_mutex_setprioceiling
--wrap pthread_mutex_getprioceiling
--wrap pthread_cond_init
--wrap pthread_cond_destroy
--wrap pthread_cond_wait
--wrap pthread_cond_timedwait
--wrap pthread_cond_signal
--wrap pthread_cond_broadcast
--wrap mq_open
--wrap mq_close
--wrap mq_unlink
--wrap mq_getattr
--wrap mq_setattr
--wrap mq_send
--wrap mq_timedsend
--wrap mq_receive
--wrap mq_timedreceive
--wrap mq_notify
--wrap open
--wrap open64
--wrap __open_2
--wrap __open64_2
--wrap socket
--wrap close
--wrap ioctl
--wrap read
--wrap write
--wrap recvmsg
--wrap recvmmsg
--wrap sendmsg
--wrap sendmmsg
--wrap recvfrom
--wrap sendto
--wrap recv
--wrap send
--wrap getsockopt
--wrap setsockopt
--wrap bind
--wrap connect
--wrap listen
--wrap accept
--wrap getsockname
--wrap getpeername
--wrap shutdown
--wrap timer_create
--wrap timer_delete
--wrap timer_settime
--wrap timer_getoverrun
--wrap timer_gettime
--wrap timerfd_create
--wrap timerfd_gettime
--wrap timerfd_settime
--wrap select
--wrap vfprintf
--wrap vprintf
--wrap fprintf
--wrap printf
--wrap puts
--wrap fputs
--wrap fputc
--wrap putchar
--wrap fwrite
--wrap fclose
--wrap syslog
--wrap vsyslog
--wrap gettimeofday
--wrap __vfprintf_chk
--wrap __vprintf_chk
--wrap __fprintf_chk
--wrap __printf_chk
--wrap __vsyslog_chk
--wrap __syslog_chk
--wrap sigwait
--wrap sigwaitinfo
--wrap sigtimedwait
--wrap sigpending
--wrap sigqueue
--wrap kill
--wrap sleep
--wrap usleep
--wrap mmap
--wrap mmap64
--wrap time
--wrap fcntl
查看cobalt.wrappers的内容,以–wrap pthread_create为例,将应用程序中对 pthread_create函数的所有引用重定向到名为 __wrap_pthread_create 的函数,并将 pthread_create函数本身重命名或重新定义为 __real_pthread_create。最终的调用堆栈为:
Application->pthread_create
->重定向到__wrap_pthread_create //lib/cobalt/thread.c
->pthread_create_ex //lib/cobalt/thread.c
->__real_pthread_create //lib/cobalt/wrappers.c
->pthread_create //回归到标准libpthread库函数
__wrap_pthread_create 函数是由宏定义COBALT_IMPL来定义的,在xenomai源码中的具体定义如下:
逐行解释这段代码,以下是详细的逐行解析:
COBALT_IMPL(int, pthread_create, (pthread_t *ptid_r,
const pthread_attr_t *attr,
void *(*start) (void *), void *arg))
- 函数声明:
COBALT_IMPL
是一个宏,用于定义Cobalt库中的实现函数。这个特定的实现是pthread_create
,它接受四个参数:pthread_t *ptid_r
: 指向新创建线程ID的指针。const pthread_attr_t *attr
: 线程属性(可以为NULL
)。void *(*start) (void *)
: 新线程的启动例程。void *arg
: 传递给启动例程的参数。
{
pthread_attr_ex_t attr_ex;
struct sched_param param;
int policy;
- 局部变量声明:
pthread_attr_ex_t attr_ex;
: 扩展的线程属性结构体,用于存储标准和非标准属性。struct sched_param param;
: 调度参数结构体,用于获取调度优先级。int policy;
: 存储调度策略。
if (attr == NULL)
attr = &default_attr_ex.std; // 如果传入的属性为NULL,则使用默认属性
- 默认属性处理:
- 如果传入的
attr
指针为NULL
,则将其设置为默认属性&default_attr_ex.std
。这确保了即使没有提供自定义属性,也能使用一组合理的默认值。
- 如果传入的
memcpy(&attr_ex.std, attr, sizeof(*attr)); // 将传入的属性复制到扩展属性结构体中
- 属性复制:
- 使用
memcpy
将标准属性结构体的内容复制到扩展属性结构体的std
部分。这样做的目的是保留原始属性,并在此基础上进行必要的扩展。
- 使用
pthread_attr_getschedpolicy(attr, &policy); // 获取调度策略
attr_ex.nonstd.sched_policy = policy; // 设置扩展属性中的调度策略
- 获取并设置调度策略:
pthread_attr_getschedpolicy(attr, &policy);
:从传入的属性中获取调度策略,并存储在policy
变量中。attr_ex.nonstd.sched_policy = policy;
:将获取到的调度策略存储到扩展属性结构体的非标准部分。
pthread_attr_getschedparam(attr, ¶m); // 获取调度参数
attr_ex.nonstd.sched_param.sched_priority = param.sched_priority; // 设置扩展属性中的优先级
- 获取并设置调度参数:
pthread_attr_getschedparam(attr, ¶m);
:从传入的属性中获取调度参数,并存储在param
结构体中。attr_ex.nonstd.sched_param.sched_priority = param.sched_priority;
:将获取到的调度优先级存储到扩展属性结构体的非标准部分。
attr_ex.nonstd.personality = 0; // 默认使用Cobalt
- 设置个性字段:
attr_ex.nonstd.personality = 0;
:设置扩展属性结构体的个性字段为0,表示使用Cobalt库的默认行为。
return pthread_create_ex(ptid_r, &attr_ex, start, arg); // 调用扩展的线程创建函数
}
- 调用扩展的线程创建函数:
return pthread_create_ex(ptid_r, &attr_ex, start, arg);
:最终调用pthread_create_ex
来创建线程,传递扩展后的属性结构体以及其他参数。
点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!