Lau*_*Man 5 c multithreading freeze linux-kernel
编辑:我想我解决了这个问题.我明天再次上班时会立即添加自己的答案/解决方案.
我正在为Linux内核3.16.x开发内核模块.我的模块应该接收和发送以太网帧,所以我创建了两个线程.一个用于接收部分,一个用于发送部分.它工作正常.
当我尝试关闭模块的设备文件并卸载它时出现我的问题.确切地说,它在尝试杀死我的线程时发生.机器(我在虚拟机上测试,使用Ubuntu 14.04)在任何输出之前冻结.但是,当我从代码中删除"线程杀死部分"时,它不再冻结.这就是为什么我很确定,这个问题源于我处理kthreads杀戮的方式.
这是我的两个主题:
TX THREAD:信号量tx_sem在代码的另一部分中被提升.
static int tx_task(void *par)
{
device->tx_task_running = 1;
allow_signal(SIGTERM);
while (!signal_pending(current) && device->tx_task_running) {
/* wait until there is something to send */
down_interruptible(&device->tx_sem);
if (signal_pending(current)) {
PRINTD("device_TX_task(): Received kill signal\n");
break;
}
/* check if device is still initialized before continuing*/
if (!device->init_flag) {
break;
}
}
device->tx_task_running = 0;
return DEVICE_RET_OK;
}
Run Code Online (Sandbox Code Playgroud)
RX THREAD
static int device_rx_task(void *par)
{
device->rx_task_running = 1;
/* task loop */
allow_signal(SIGTERM);
while (!signal_pending(current) && device->rx_task_running) {
rxlen = kernel_recvmsg(device->sock, &msg,
(struct kvec *)&iov, 1, DEVICE_PAY_SIZE, 0);
if (signal_pending(current)) {
PRINTD("device_rx_task(): Received kill signal\n");
break;
}
if(rxlen < 0) {
PRINTD("device_RX_task(): Got error when receiving\n");
break;
}
/* check if device is still initialized before continuing*/
if (!device->init_flag) {
break;
}
}
device->rx_task_running = 0;
return DEVICE_RET_OK;
}
Run Code Online (Sandbox Code Playgroud)
这些家伙一直运行,直到我试图关闭我的设备.关闭内核模块时,会调用此函数,这就是它崩溃的时候.例如,如果我将"send_sig"函数注释掉,它就不会崩溃.当我尝试手动杀死线程时它也会崩溃:
int Device_DevTerm(int dev)
{
device->init_flag = 0;
send_sig(SIGTERM, device->rx_thread, 0);
send_sig(SIGTERM, device->tx_thread, 0);
device->rx_task_running = 0;
device->tx_task_running = 0;
return DEVICE_RET_OK;
}
Run Code Online (Sandbox Code Playgroud)
为了找到问题,我用Google搜索并搜索了很长时间,但到目前为止我还没有成功.由于我已经花了很多时间来解决这个问题,所以我决定问你们.
我在这做错了什么?
ps我不认为我曾经发布过这里,我只是阅读了很多.我希望我的问题清楚简明.可能不是.
所以,看来我发现了我的问题。
当为 kernel_recvmsg() 函数设置 msghdr 时,我曾经这样做:
struct sockaddr_in client;
MEM_SET(&client, 0x00, sizeof(struct sockaddr_in));
/* setup receive parameter */
msg.msg_name = &client;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
Run Code Online (Sandbox Code Playgroud)
现在我将例行程序更改为:
struct sockaddr_in client[3];
MEM_SET(&client[0], 0x00, 3 *sizeof(struct sockaddr_in));
/* setup receive parameter */
msg.msg_name = &client[1];
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
Run Code Online (Sandbox Code Playgroud)
这样它就不会再崩溃了。然后我在我们的代码库中发现了以下注释:
/*
* NOTE:
* use three times the size of struct sockaddr_in as workaround
* for a possible kernel bug which has been seen on a Ubuntu 64bit
* system
* after the call of kernel_recvmsg 2 bytes behind the structure
* client had been corrupted on the stack
*/
Run Code Online (Sandbox Code Playgroud)
我不确定这有多真实,也不知道这是否涵盖了我的整个问题,但它似乎解决了它。
| 归档时间: |
|
| 查看次数: |
325 次 |
| 最近记录: |