ALL〜!
在linux系统中, 共享数据应该是互斥的。 并且,mmap在内核空间和用户空间之间共享该数据。 所以我编程如下。
///////////// USER SPACE
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);
}<
///////////// KERNEL SPACE
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用于用户空间。
问题:在原子上下文中是否存在在用户和内核之间共享数据的任何解决方案?
答案 0 :(得分:2)
如果您只想增加或减少或以其他方式修改单个整数类型值,那么您可以使用锁定操作。它应该可以很好地在内核中使用atomic_t
,在用户模式应用程序中使用atmoic builtins。
显然,如果您需要在字符串中执行更复杂的操作,例如strcpy
或“将所有A替换为B”,请修改二进制树或其他一些“不容易变成”的工作单一操作“,然后解决方案是使用信号量。但正如你所说,这不会起作用于IRQ(或调度程序“锁定”时的其他情况)。
此外,你真的不想“在IRQ中等待用户模式重新平衡树”。
我认为从IRQ中解决这个问题并不容易解决 - 基本上,你不应该这样做。您可以在IRQ中使用down_trylock
- 这不会导致IRQ进入睡眠状态,如果信号量不可用,则在成功获取锁定时返回0,如果锁定已被保持,则返回非零值别的什么。
现在,棘手的部分当然是“如果锁定不可用你会怎么做” - 而且我无法为你的具体情况给出正确答案。典型的解决方案是排队工作项并在以后处理它。
编辑:执行“排队工作和稍后处理”的标准方法是使用tasklet
答案 1 :(得分:0)
亲爱的Mats,
感谢您的回答
我认为,down_trylock是解决我的程序的最佳解决方案。
实际上,在调用原子conterxt的情况下,我无条件地尝试在access_shared_data_kernel函数中返回失败。
但是当我使用down_trylock时,它不一定是无条件返回,而且效率更高。
所以,我修改了以下代码
void access_shared_data_kernel(void)
{
//剪断..
如果(down_trylock(安培; mmclog_sem)){
if(in_atomic()|| in_interrupt()|| irqs_disabled()){
printk(“无法在原子上下文中获取信号量..!\ n”);
返回-1;
}
否则
向下(安培; mmclog_sem);
}
shared_data ++;
//对shared_data的一些访问权限
向上(安培; test_sem);
}
感谢Mats,