SA8155@ posix_spawn概率性执行失败导致串口无法通信的问题,strerror打印出失败的原因定位解决,if/while/break

665 阅读5分钟

​ 本文已参与「新人创作礼」活动,一起开启掘金创作之路

 前言:

我们调用 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 的信息如下,信息量比较小:

www.qnx.com/developers/… https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/strerror.html

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;
}