0

全部~!

在linux系统中,有一个共享数据应该是互斥的。而且,这些数据通过 mmap 在内核空间和用户空间之间共享。所以我编程如下。

////////////用户空间

void access_shared_data_user(void)
{
 //snip..
 ioctl(test_fd, IOCTL_DOWN_SEM);
 shared_data++;
 //some access to shared_data
 ioctl(test_fd, IOCTL_UP_SEM);
}<

////////////内核空间

static DEFINE_SEMAPHORE(test_sem);

static long test_ioctl(struct file *file, unsigned int cmd, unsigned long arg)<br>
{
 //snip..
 switch(cmd)
 {
    case IOCTL_DOWN_SEM:
      down(&test_sem);
    break;
    case IOCTL_UP_SEM:
      up(&test_sem);
    break;
    //snip..
}

void access_shared_data_kernel(void)
{
  //snip..
  down(&test_sem);
  shared_data++;
  //some access to shared_data
  up(&test_sem);
}

上面的程序运行良好,正如我预期的那样,共享数据受到许多线程的保护。

顺便说一句,上面的程序有问题。如果在原子上下文(例如 IRQ 处理程序)中调用 access_shared_data_kernel,则该程序有可能发生死锁,因为信号量使用睡眠等待方法。

所以我尝试使用 spinlock(spin_lock_irqsave) 但似乎没有办法在用户空间中使用 spinlock。

问题:有什么解决方案可以在原子上下文中在用户和内核之间共享数据?

4

2 回答 2

2

如果您只想增加或减少或以其他方式简单地修改单个整数类型值,那么您可以使用锁定操作。它应该可以很好地atomic_t在内核中使用,并且在用户模式应用程序中使用atmoic 内置函数。

显然,如果你需要做更复杂的事情,比如strcpy或者在一个字符串中“用B替换所有A”,修改一棵二叉树或者其他一些“不容易做成单个操作”的工作,那么解决方案是使用信号量。但是正如您所说,这不适用于 IRQ(或调度程序“锁定”的其他情况)。

此外,您真的不想“在 IRQ 中等待用户模式重新平衡树”。

我认为没有任何简单的解决方案可以从 IRQ 解决此问题 - 基本上,您不应该这样做。您可以down_trylock在您的 IRQ 中使用 - 这不会导致您的 IRQ 休眠,并且如果信号量不可用,则如果成功获取锁则返回 0,如果锁已被其他东西持有则返回非零。

现在,棘手的部分当然是“如果锁不可用,你会怎么做”——对于你的具体情况,我真的无法给出正确的答案。典型的解决方案是将工作项排队并在稍后处理它。

编辑:执行“排队工作站点并稍后处理”的标准方法是使用tasklet

于 2013-09-06T13:39:37.727 回答
0


亲爱的垫子,

谢谢您的回答。
我认为,down_trylock 是修复我的程序的最佳解决方案。

实际上,在调用原子上下文的情况下,我无条件地尝试在 access_shared_data_kernel 函数中返回失败。
但是当我使用down_trylock时,不一定非要无条件返回,效率更高。

所以,我修改了如下代码。
void access_shared_data_kernel(void)
{
//snip..
if(down_trylock(&mmclog_sem)){
if(in_atomic() || in_interrupt() || irqs_disabled()){
printk("在原子上下文中获取信号量失败..!\ n");
返回-1;
}
否则
下来(&mmclog_sem);
}
共享数据++;
//对 shared_data 的一些访问
up(&test_sem);
}

谢谢垫子,

于 2013-09-09T02:21:45.147 回答