在驱动开发中,有时候配合app测试之后,使用ts等命令发现只能打印出头部信息,主体信息无法打印,如下:
原因:驱动中锁使用不规范导致系统死锁。
驱动测试代码:
#define __SYLIXOS_KERNEL #include <SylixOS.h> #include <module.h> LW_DEV_HDR __GdevHdr; LW_OBJECT_HANDLE ulSem; static LONG __devOpen(PLW_DEV_HDR pdevhdrHdr, PCHAR pcName, INT iFlag, INT iMode) { ulSem = API_SemaphoreBCreate("test_sem", LW_TRUE, LW_OPTION_OBJECT_GLOBAL, LW_NULL); return 0; } static INT __devClose(PLW_FD_ENTRY pFdEntry) { API_SemaphoreBPend(ulSem, LW_OPTION_WAIT_INFINITE); /* * some code */ API_SemaphoreBPost(ulSem); return 0; } static INT __devIoctl (PLW_FD_ENTRY pFdEntry, INT iCmd, LONG lArg) { API_SemaphoreBPend(ulSem, LW_OPTION_WAIT_INFINITE); /* * some code */ while(1); API_SemaphoreBPost(ulSem); return 0; } struct file_operations __GdevOps = { .fo_open = __devOpen, .fo_close = __devClose, .fo_ioctl = __devIoctl }; static INT __devRegister(VOID) { INT iDrvNum = iosDrvInstallEx2(&__GdevOps, LW_DRV_TYPE_NEW_1); /* 安装驱动程序 */ return (iosDevAddEx(&__GdevHdr, "/dev/testdev", iDrvNum, DT_CHR)); /* 创建设备 */ } static INT __devUnregister(VOID) { PLW_DEV_HDR pDev; pDev = &__GdevHdr; if (pDev) { iosDevDelete(pDev); /* 卸载设备 */ return (iosDrvRemove(pDev->DEVHDR_usDrvNum, 0)); /* 卸载驱动程序 */ } else { return (PX_ERROR); } } int module_init (void) { __devRegister(); return 0; } void module_exit (void) { __devUnregister(); }
APP测试代码:
#include <stdio.h> int main (int argc, char **argv) { INT iFbFd; iFbFd = open("/dev/testdev", O_RDWR); if (iFbFd < 0) { fprintf(stderr, "open /dev/testdev failed.\n"); return (-1); } ioctl(iFbFd, NULL, NULL); return (0); }
分析:
- ioctl中使用信号量保护了一段资源,使用while(1)模拟当进程还在执行资源区代码时被用户CTRL+C终止
- 进程的资源回收工作是由t_reclaim线程负责的
- t_reclaim线程会通过vprocIoReclaim函数回收进程打开的文件,主体回收代码使用_G_ulVProcMutex互斥锁保护
- 在回收由驱动创建的设备文件资源时,最终会调用到驱动里的close函数
- close函数中的ulSem信号量在ioctl中被用户进程持有,所以t_reclaim线程此时被阻塞,但是注意!此时t_reclaim线程还持有_G_ulVProcMutex互斥锁!
- 这时使用ts查看线程信息,会调用vprocGetPidByTcbdesc函数以获取进程 id,这个函数中同样使用_G_ulVProcMutex互斥锁保护获取过程,但是此时_G_ulVProcMutex互斥锁是被t_reclaim线程持有的,所以当前线程阻塞,不会再输出信息
建议:
通过此案例可以看出,资源回收不当的话,会给系统带来负面影响。所以在驱动和应用开发中要注意进程结束时,资源该如何正确的回收,比如上面的测试用例如果能保证在ioctl执行完后再结束进程,就不会有死锁产生了。
评论