免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3989 | 回复: 5
打印 上一主题 下一主题

kill掉进程时,若正持有内核的mutex,则不会立即生效? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-09-02 17:10 |只看该作者 |倒序浏览
假设进程A打开设备文件B,在B的驱动代码中持有mutex(mutex_lock, mutex_lock_interruptable),且正在访问设备。则此时在shell下用kill命令杀掉进程A时,好像不会立即生效,而是一直要等到驱动掉用了mutex_unlock后才会被kill掉。如果A一直不释放mutex的话,则永远不会被kill掉了。是不是有问题呀?

测试代码如下,以proc下的一个文件为例,读取时打开锁。

/*
# insmod mutex_debug.ko taskTime=10
# cat /proc/mutex_test
# kill  pid_of_cat
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/moduleparam.h>
#include <asm/param.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/timer.h>

/* Module Argument */
static int taskTime = 5;
module_param(taskTime, int, S_IRUGO);
MODULE_PARM_DESC(taskTime, "task running time, default is 5");

#define MUTEX_TEST_FILE                "mutex_test"
struct mutex gMutexLock;

#define printk_dbg(format, arg...)  \
    do{ \
            printk("%s:[cpu=%d, pid=%04d] " format, MUTEX_TEST_FILE, smp_processor_id(), current->pid, ##arg );   \
    }while(0)


//////////////////////////////////////////////////////////////////////////////////////
// 生成一个执行N秒的任务
static void foo(int seconds)
{
        unsigned long timeout = jiffies + HZ*seconds;
        unsigned long cur_time=0;
        int i=0;
       
        printk_dbg("i=%d, timeout=%u, jiffies=%u.\n", i++, timeout, jiffies);
       
        do{
//                printk_dbg("i=%d, timeout=%u, jiffies=%u.\n", i++, timeout, jiffies);
//                printk_dbg("goto sleep.\n");
//                udelay(500*1000);
//                delay(500);
//                printk_dbg("wake up.\n");
        }while(jiffies<timeout);
}


static int mutex_test_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
        printk_dbg("========== try to get mutext...\n");
        mutex_lock_interruptible(&gMutexLock);
        printk_dbg("---------- has got mutext.\n");
       
        foo(taskTime);        // work task
       
        printk_dbg("---------- try to release mutext...\n");
        mutex_unlock(&gMutexLock);
        printk_dbg("========== has released mutext.\n\n");

        {
                  int len;
                  if (off > 0) {
                    *eof = 1;
                    return 0;
                  }

                  len = sprintf(page, "taskTime=%d.\n\n", taskTime);
                  return len;
        }
}

ssize_t mutex_test_write( struct file *filp, const char __user *buff, unsigned long len, void *data )
{
        char buf[10]={0};
        printk_dbg( "Readonly file.\n");
       
        if (copy_from_user(buf, buff, 2))
        {
            return -EFAULT;
          }
  
        return len;
}


//////////////////////////////////////////////////////////////////////////////////////
static int __init  test_module_init(void)
{
        struct proc_dir_entry *mutex_test_dbg = NULL;
       
        mutex_init(&gMutexLock);
       
        mutex_test_dbg = create_proc_entry(MUTEX_TEST_FILE, 0666, NULL);
        if (!mutex_test_dbg)
        {
                printk_dbg( "Failed to creat /proc/%s!\n", MUTEX_TEST_FILE);
                return -1;
        }
        else
        {             
                mutex_test_dbg->read_proc  = mutex_test_read;
                mutex_test_dbg->write_proc = mutex_test_write;
                printk_dbg("/proc/%s created succeed.\n", MUTEX_TEST_FILE);
        }
       
        return 0;
}

static void __exit test_module_exit(void)
{
        remove_proc_entry(MUTEX_TEST_FILE, NULL);
        printk_dbg("/proc/%s removed.\n", MUTEX_TEST_FILE);
       
    return ;
}

module_init(test_module_init);
module_exit(test_module_exit);

MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");



不知道是不是本测试方法不对,各位有踫到过此问题吗?

论坛徽章:
0
2 [报告]
发表于 2011-09-03 00:09 |只看该作者
回复 1# coralonland
进程能不能退出和你是否持有锁无关,你的例子里kill不掉是驱动的逻辑决定的:
  1. do{
  2.                 udelay(500*1000);
  3.                 delay(500);
  4.                 printk_dbg("wake up.\n");
  5. }while(jiffies<timeout);
复制代码
从睡眠中醒来有可能是由于接收到信号,所以在从udelay/delay/schedule_timeout这样的函数返回之后要加上

  1. if (signal_pending(current)) {
  2.         /*
  3.           * Do sth
  4.          */

  5.         return -EINTR;
  6. }
复制代码
这样的处理(也可以简单判断一下睡眠时间是否为你指定的),然后向调用者返回 -EINTR 告知被信号中断,让调用者释放锁,然后返回用户空间。调用者不释放锁也不会导致进程无法退出,只会让所有其它等待这把锁的进程永久等待。

论坛徽章:
0
3 [报告]
发表于 2011-09-04 01:12 |只看该作者
回复 2# vupiggy


    您说的这种情况我考虑过,所以在测试中,发do{}while(...)中的内容全部注释掉了,也就是说实际上就是空循环着执行N秒钟而没有进入睡眠中。但结果正如前文所述,无法即时kill掉。

论坛徽章:
0
4 [报告]
发表于 2011-09-04 10:21 |只看该作者
本帖最后由 vupiggy 于 2011-09-04 03:26 编辑
回复  vupiggy


    您说的这种情况我考虑过,所以在测试中,发do{}while(...)中的内容全部注释掉 ...
coralonland 发表于 2011-09-03 18:12


你确切清楚 kill 命令做了什么?确切清楚信号是什么?确切清楚信号的递送和处理?你把 mutex_lock 去掉,只保留 do {} while() 循环,你的 kill 一样不能即时生效。

好吧,给你点提示,谷歌/百度/必应``linux 内核 信号 机制''。看两天还是认为 kill 不掉和持有锁有半毛钱关系再上来问。happy hacking.

论坛徽章:
0
5 [报告]
发表于 2011-09-04 10:30 |只看该作者
那是由于信号函数是在从内核态即将要返回用户态的时候调用的。
你在内核态长期不返回,信号函数得不到执行。

论坛徽章:
0
6 [报告]
发表于 2011-09-05 11:45 |只看该作者
非常感谢 奇门遁甲-lu  和 vupiggy 的指教。经过验证,确实如此。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP