本文已参与「新人创作礼」活动,一起开启掘金创作之路
前言:
我们调用 posix_spawn 函数执行高通的daemon bin创建 /dev/ser3 节点,概率性不成功,从google 上搜索 qnx posix_spawn 后得到如下信息如果log是Bad file descriptor 则
行 1188: Jan 01 08:00:05.022 AIS.45107 ais_server 415 uart_device_main:475 HIGH fail: Bad file descriptor
行 1675: Jan 01 08:00:05.764 AIS.45107 ais_server 415 uart_device_main:486 WARN failed to wait for /dev/ser3
开发网站链接:
https://www.qnx.com/developers/docs/7.0.0/index.html#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
开发网站官方信息,大致意思就是 如果有其它进程打开关闭 daemon 的时候会出问题,建议我们retry
Returns:
EBADF
A problem occurred when posix_spawn() was duplicating a file descriptor. For example, another thread might have opened or closed a file descriptor while the posix_spawn() was occurring. You can add synchronization around the operations that involve file descriptors, or try calling posix_spawn() again.
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
如下函数 strerror 成功打印出来错误的原因,基于 EBADF 也就是 Bad file descriptor 定位了 posix_spawn 函数失败的原因。
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
所以我们不能只执行一次命令,建议做retry 几次,如果retry 成功返回则跳出,不再执行posix_spawn 函数,否则会创建太多的pid 进程。
串口中输入测试命令:
ls -l /dev/ser* && pidin | grep devc && apaota_test
reset 热重启,电源冷启动验证
1:
这个代码只会执行1次,因为 /bin/devc-quipv3在开机过程中至少被2-3个进程调用过,所以这个创建/dev/ser3的操作可能就会冲突
// create "/dev/ser3", if "/dev/ser3" no exist
if(access(dev->devname, F_OK)== -1)
{
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if (ret == 0)
{
if (waitpid(pid, &ret, 0) != -1) {
AIS_LOG_UART_HIGH("Wait uart status %i", ret);
} else {
AIS_LOG_UART_HIGH("Wait Uart status %i", ret);
}
} else {
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
{
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
}
有时候没有成功创建 /dev/ser3 ,最终无法执行
# ls -l /dev/ser*
crw-rw-rw- 1 devc_quipv3 18 3, 1 Jan 01 10:05 /dev/ser1
crw-rw-rw- 1 devc_quipv3 18 3, 2 Jan 01 10:05 /dev/ser2
//前面有 20486 和 45088 调用了 dev-quipv3 导致 我们执行命令的时候有冲突,所以无法成功生成/dev/ser3
# pidin | grep -i devc
20486 1 bin/devc-quipv3 10r RECEIVE 1
20486 2 bin/devc-quipv3 10r SIGWAITINFO
20486 4 bin/devc-quipv3 10r RECEIVE 5
20486 5 bin/devc-quipv3 21r INTR
40982 1 bin/devc-pty 10r RECEIVE 1
45088 1 bin/devc-quipv3 24r RECEIVE 1
45088 2 bin/devc-quipv3 10r SIGWAITINFO
45088 3 bin/devc-quipv3 10r RECEIVE 4
45088 4 bin/devc-quipv3 21r INTR
# apaota_test
open & init /lib64/libapa_ota.so success
usage: apaota_test
example: ./apaota_test
i2c init fail
json: #
2:用retry 10次进行操作
while 和if break 组合
// create "/dev/ser3", if "/dev/ser3" no exist
// retry 10 times to solve low probability "/dev/ser3" create fail
if(access(dev->devname, F_OK)== -1)
{
while(retry--)
{
usleep(50);
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if(ret==0)
break;
else
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
上面的代码不需要真正跑10次,实际执行1-2次创建成功即break 出来。
# ls -l /dev/ser*
crw-rw-rw- 1 devc_quipv3 18 3, 1 Jan 01 09:57 /dev/ser1
crw-rw-rw- 1 devc_quipv3 18 3, 2 Jan 01 09:57 /dev/ser2
crw-rw-rw- 1 ais_server ais_server 3, 3 Jan 01 09:57 /dev/ser3
#
#
# pidin | grep devc
20486 1 bin/devc-quipv3 10r RECEIVE 1
20486 2 bin/devc-quipv3 10r SIGWAITINFO
20486 4 bin/devc-quipv3 10r RECEIVE 5
20486 5 bin/devc-quipv3 21r INTR
40983 1 bin/devc-pty 10r RECEIVE 1
45088 1 bin/devc-quipv3 24r RECEIVE 1
45088 2 bin/devc-quipv3 10r SIGWAITINFO
45088 3 bin/devc-quipv3 10r RECEIVE 4
45088 4 bin/devc-quipv3 21r INTR
45110 1 bin/devc-quipv3 10r RECEIVE 1
45110 2 bin/devc-quipv3 20r SIGWAITINFO
45110 3 bin/devc-quipv3 20r RECEIVE 4
45110 4 bin/devc-quipv3 21r INTR
#
#
# apaota_test
open & init /lib64/libapa_ota.so success
usage: apaota_test
example: ./apaota_test
[568] apa_get_software_version
version_apa [full-SN] : CG019028 357 81875*704000604AA*00.02.00_13.00.03*9BJ*
[578] apa_get_software_version sn: CG019028 357 81875
[584] apa_get_software_version part_number: 704000604AA
[590] apa_get_software_version sf version: 00.02.00
[592] apa_get_software_version hw version: 13.00.03
[599] apa_get_software_version Supplier_number: 9BJ
json: {"sn":"CG019028 357 81875","part_no":"704000604AA","vendor_id":"9BJ","calib_version":""}#
3:
// create "/dev/ser3", if "/dev/ser3" no exist
// retry 10 times to solve low probability "/dev/ser3" create fail
if(access(dev->devname, F_OK)== -1)
{
//ret ==0表示成功,要跳出来,所以如果这样写,就挑不出来了。
while( (0==ret) && (retry--) )//运算符应该可以不加括号
{
usleep(50);
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if(ret!=0)
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
节点创建成功了,但是 retry 了10次, 命令也无法执行,和 方案4是一样的结果。所以运算符不需要括号,结果一致的。
# ls -l /dev/ser*
crw-rw-rw- 1 devc_quipv3 18 3, 1 Jan 01 09:45 /dev/ser1
crw-rw-rw- 1 devc_quipv3 18 3, 2 Jan 01 09:45 /dev/ser2
crw-rw-rw- 1 ais_server ais_server 3, 3 Jan 01 09:45 /dev/ser3
#
#
#
# pidin | gStop 345Quit qplayer after 30 secs of playing
repStop 345qplayer: [Result] >> test succeeded
ksh: gre: cannot execute - No such file or directory
#
#
#
#
# pidin | grep devc
20486 1 bin/devc-quipv3 10r RECEIVE 1
20486 2 bin/devc-quipv3 10r SIGWAITINFO
20486 4 bin/devc-quipv3 10r RECEIVE 6
20486 5 bin/devc-quipv3 21r INTR
40982 1 bin/devc-pty 10r RECEIVE 1
49184 1 bin/devc-quipv3 24r RECEIVE 1
49184 2 bin/devc-quipv3 10r SIGWAITINFO
49184 3 bin/devc-quipv3 10r RECEIVE 4
49184 4 bin/devc-quipv3 21r INTR
53302 1 bin/devc-quipv3 10r RECEIVE 1
53302 2 bin/devc-quipv3 20r SIGWAITINFO
53302 3 bin/devc-quipv3 20r RECEIVE 4
53302 4 bin/devc-quipv3 21r INTR
53303 1 bin/devc-quipv3 20r RECEIVE 1
53303 2 bin/devc-quipv3 20r SIGWAITINFO
53303 3 bin/devc-quipv3 20r RECEIVE 4
53303 4 bin/devc-quipv3 21r INTR
53308 1 bin/devc-quipv3 20r RECEIVE 1
53308 2 bin/devc-quipv3 20r SIGWAITINFO
53308 3 bin/devc-quipv3 20r RECEIVE 4
53308 4 bin/devc-quipv3 21r INTR
53309 1 bin/devc-quipv3 20r RECEIVE 1
53309 2 bin/devc-quipv3 20r SIGWAITINFO
53309 3 bin/devc-quipv3 20r RECEIVE 4
53309 4 bin/devc-quipv3 21r INTR
53311 1 bin/devc-quipv3 20r RECEIVE 1
53311 2 bin/devc-quipv3 20r SIGWAITINFO
53311 3 bin/devc-quipv3 20r RECEIVE 4
53311 4 bin/devc-quipv3 21r INTR
53312 1 bin/devc-quipv3 20r RECEIVE 1
53312 2 bin/devc-quipv3 20r SIGWAITINFO
53312 3 bin/devc-quipv3 20r RECEIVE 4
53312 4 bin/devc-quipv3 21r INTR
53313 1 bin/devc-quipv3 20r RECEIVE 1
53313 2 bin/devc-quipv3 20r SIGWAITINFO
53313 3 bin/devc-quipv3 20r RECEIVE 4
53313 4 bin/devc-quipv3 21r INTR
53314 1 bin/devc-quipv3 20r RECEIVE 1
53314 2 bin/devc-quipv3 20r SIGWAITINFO
53314 3 bin/devc-quipv3 20r RECEIVE 4
53314 4 bin/devc-quipv3 21r INTR
53315 1 bin/devc-quipv3 20r RECEIVE 1
53315 2 bin/devc-quipv3 20r SIGWAITINFO
53315 3 bin/devc-quipv3 20r RECEIVE 4
53315 4 bin/devc-quipv3 21r INTR
53316 1 bin/devc-quipv3 24r RECEIVE 1
53316 2 bin/devc-quipv3 20r SIGWAITINFO
53316 3 bin/devc-quipv3 20r RECEIVE 4
53316 4 bin/devc-quipv3 21r INTR
无法成功运行,获取 sn号
# apaota_test
open & init /lib64/libapa_ota.so success
usage: apaota_test
example: ./apaota_test
4:
// create "/dev/ser3", if "/dev/ser3" no exist
// retry 10 times to solve low probability "/dev/ser3" create fail
if(access(dev->devname, F_OK)== -1)
{
while( 0==ret && retry-- )//0==ret 的时候是成功的要跳出
{
usleep(50);
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if(ret!=0)
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
执行结果如下所示:
节点创建成功:
# ls -l /dev/ser*
crw-rw-rw- 1 devc_quipv3 18 3, 1 Jan 01 09:34 /dev/ser1
crw-rw-rw- 1 devc_quipv3 18 3, 2 Jan 01 09:34 /dev/ser2
crw-rw-rw- 1 ais_server ais_server 3, 3 Jan 01 09:34 /dev/ser3
很奇怪,为啥执行了 retry 10次 ,以及最初的 20486 和40982 45088 和10retry进程。
# pidin | grep devc
20486 1 bin/devc-quipv3 10r RECEIVE 1
20486 2 bin/devc-quipv3 10r SIGWAITINFO
20486 4 bin/devc-quipv3 10r RECEIVE 7
20486 5 bin/devc-quipv3 21r INTR
40982 1 bin/devc-pty 10r RECEIVE 1
45088 1 bin/devc-quipv3 24r RECEIVE 1
45088 2 bin/devc-quipv3 10r SIGWAITINFO
45088 3 bin/devc-quipv3 10r RECEIVE 4
45088 4 bin/devc-quipv3 21r INTR
45110 1 bin/devc-quipv3 10r RECEIVE 1
45110 2 bin/devc-quipv3 20r SIGWAITINFO
45110 3 bin/devc-quipv3 20r RECEIVE 4
45110 4 bin/devc-quipv3 21r INTR
45111 1 bin/devc-quipv3 20r RECEIVE 1
45111 2 bin/devc-quipv3 20r SIGWAITINFO
45111 3 bin/devc-quipv3 20r RECEIVE 4
45111 4 bin/devc-quipv3 21r INTR
45116 1 bin/devc-quipv3 20r RECEIVE 1
45116 2 bin/devc-quipv3 20r SIGWAITINFO
45116 3 bin/devc-quipv3 20r RECEIVE 4
45116 4 bin/devc-quipv3 21r INTR
45117 1 bin/devc-quipv3 20r RECEIVE 1
45117 2 bin/devc-quipv3 20r SIGWAITINFO
45117 3 bin/devc-quipv3 20r RECEIVE 4
45117 4 bin/devc-quipv3 21r INTR
45119 1 bin/devc-quipv3 20r RECEIVE 1
45119 2 bin/devc-quipv3 20r SIGWAITINFO
45119 3 bin/devc-quipv3 20r RECEIVE 4
45119 4 bin/devc-quipv3 21r INTR
45120 1 bin/devc-quipv3 20r RECEIVE 1
45120 2 bin/devc-quipv3 20r SIGWAITINFO
45120 3 bin/devc-quipv3 20r RECEIVE 4
45120 4 bin/devc-quipv3 21r INTR
45121 1 bin/devc-quipv3 20r RECEIVE 1
45121 2 bin/devc-quipv3 20r SIGWAITINFO
45121 3 bin/devc-quipv3 20r RECEIVE 4
45121 4 bin/devc-quipv3 21r INTR
45122 1 bin/devc-quipv3 24r RECEIVE 1
45122 2 bin/devc-quipv3 20r SIGWAITINFO
45122 3 bin/devc-quipv3 20r RECEIVE 4
45122 4 bin/devc-quipv3 21r INTR
45123 1 bin/devc-quipv3 24r RECEIVE 1
45123 2 bin/devc-quipv3 20r SIGWAITINFO
45123 3 bin/devc-quipv3 20r RECEIVE 4
45123 4 bin/devc-quipv3 21r INTR
45124 1 bin/devc-quipv3 24r RECEIVE 1
45124 2 bin/devc-quipv3 20r SIGWAITINFO
45124 3 bin/devc-quipv3 20r RECEIVE 4
45124 4 bin/devc-quipv3 21r INTR
无法成功运行
#
# apaota_test
open & init /lib64/libapa_ota.so success
usage: apaota_test
example: ./apaota_test
定位问题的关键是,如下部分成功打印了错误的 return 返回值。
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
打印的log为:
uart_device_main:475 HIGH fail: Bad file descriptor
如下是linux 中 strerror 返回值用法,
google搜索 qnx strerror 的信息如下,信息量比较小:
strerror函数的总结 - 爱学习Linux - 博客园
以下来自linux 2.4.20-18的内核代码中的/usr/include/asm/errno.h
#ifndef _I386_ERRNO_H
#define _I386_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
3:完整代码:
int uart_device_main(uart_dev_t * dev)
{
AIS_LOG_UART_HIGH("This program updates last time at %s %s",__TIME__,__DATE__);
char *argv[] = {"devc-quipv3", "-E", "-F", "-b921600", "9", NULL};
int32_t fd = -1;
extern char **environ;
pid_t pid;
long in_buad = 921600L;
boolean isEmpty = TRUE;
int ret;
int retry=10;
uart_pm_init();
ret = waitfor(UART2_DEVNAME, 5000, 10);
if(ret != 0)
{
AIS_LOG_UART_WARN("failed to wait for %s", dev->devname);
return -1;
}
#if 0
// create "/dev/ser3", if "/dev/ser3" no exist
if(access(dev->devname, F_OK)== -1)
{
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if (ret == 0)
{
if (waitpid(pid, &ret, 0) != -1) {
AIS_LOG_UART_HIGH("Wait uart status %i", ret);
} else {
AIS_LOG_UART_HIGH("Wait Uart status %i", ret);
}
} else {
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
{
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
}
#endif
#if 0
// create "/dev/ser3", if "/dev/ser3" no exist
// retry 10 times to solve low probability "/dev/ser3" create fail
if(access(dev->devname, F_OK)== -1)
{
while(retry--)
{
usleep(50);
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if(ret==0)
break;
else
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
#endif
#if 1
// create "/dev/ser3", if "/dev/ser3" no exist
// retry 10 times to solve low probability "/dev/ser3" create fail
if(access(dev->devname, F_OK)== -1)
{
while( (0==ret) && (retry--) )
{
usleep(50);
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if(ret!=0)
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
#endif
#if 0
// create "/dev/ser3", if "/dev/ser3" no exist
// retry 10 times to solve low probability "/dev/ser3" create fail
if(access(dev->devname, F_OK)== -1)
{
while( 0==ret && retry-- )
{
usleep(50);
ret = posix_spawn(&pid, "/bin/devc-quipv3", NULL, NULL, argv, environ);
if(ret!=0)
AIS_LOG_UART_HIGH("fail: %s", strerror(ret));
}
}
else
AIS_LOG_UART_HIGH("uart %s is exist", dev->devname);
#endif
ret = waitfor(dev->devname, 5000, 10);
if(ret != 0)
{
AIS_LOG_UART_WARN("failed to wait for %s", dev->devname);
return -1;
}
fd = open(dev->devname,O_RDWR);
dev->fd = fd;
if(fd < 0)
{
AIS_LOG_UART_WARN("open device error!");
return -1;
}
if(fcntl(fd, F_SETFL, 0)<0)
AIS_LOG_UART_WARN("fcntl failed!");
setBaudRate(fd,in_buad);
if(setParity(fd,8,1,'E') == FALSE)
{
AIS_LOG_UART_WARN("Set Parity Error");
return -1;
}
while(1)
{
usleep(50);// 这里为何一直while 循环执行 ?
}
close(fd);
return 0;
}