简体   繁体   English

系统调用是线程安全的吗?

[英]Are system calls thread-safe?

I have wrote a kernel module, It is a Character device driver something like this Link .The driver has an internal structure like:我写了一个内核模块,它是一个类似于Link的字符设备驱动程序。驱动程序具有如下内部结构:

struct {
    str[500];
}channelData;

static channelData chData[4];

So I have a multi-threaded application which uses this driver, I currently use this driver in following way:所以我有一个使用这个驱动程序的多线程应用程序,我目前以下列方式使用这个驱动程序:

typedef struct
{
        int channelId;
        int len;
        char arg[100];
} driverArgs;

class DevDrv{
    static void STR_READ(int channelId, char *data);
    static void STR_SEND(int channelId, char *data,int len);
};

void DevDrv::STR_READ(int channelId, char *data)
{
    driverArgs arg= {-1,0, {0}};
    arg.channelId = channelId;
    ioctl(mfilehandler,IOCTL_STR_READ,&arg);
    memcpy(data,arg.arg,arg.len)

}
void DevDrv::STR_SEND(int channelId, char *data,int len)
{
    driverArgs arg= {-1,0, {0}};
    arg.channelId = channelId;
    arg.len=len;
    memcpy(arg.arg,data,len);
    ioctl(mfilehandler,IOCTL_STR_SEND,&arg);
}

So, The question is if 4 threads in my application call these functions to read or write into their own ChannelId like this to read from or write into driver:所以,问题是我的应用程序中的 4 个线程是否调用这些函数来读取或写入他们自己的 ChannelId 像这样读取或写入驱动程序:

thread1:
   DevDrv::STR_READ(0,&localdst);
thread2:
   DevDrv::STR_READ(1,&localdst);
thread3:
   DevDrv::STR_READ(2,&localdst);
thread4:
   DevDrv::STR_READ(3,&localdst);

is there data-racing or something like that happen?是否有数据竞赛或类似的事情发生?

Your channelData structure is not guaranteed to be cache-aligned, so unless you explicitly synchronize chData , you're still subject to data races.您的channelData结构不能保证缓存对齐,因此除非您明确同步chData ,否则您仍然会受到数据chData

Here's a sketch of a race:这是一场比赛的草图:

  1. System call wants to read into channel 2 on CPU 0.系统调用想要读入 CPU 0 上的通道 2。
  2. CPU 0 fetches all the cache lines containing channel 2, which means: CPU 0 获取包含通道 2 的所有缓存行,这意味着:
    • All the bytes in channel 2通道 2 中的所有字节
    • A few bytes from the end of channel 1距离通道 1 末尾的几个字节
    • A few bytes from the beginning of channel 3从通道 3 开始的几个字节
  3. The read goes as usual.阅读照常进行。
  4. CPU 1 writes 500 bytes to channel 1. CPU 1 将 500 字节写入通道 1。
  5. System call wants to read 500 bytes into channel 1 on CPU 0.系统调用想要将 500 个字节读入 CPU 0 上的通道 1。
  6. CPU 0 fetches all the bytes from channel 1 which weren't previously fetched. CPU 0 从通道 1 中获取之前未获取的所有字节。
    • The few bytes from the end of channel 1 are not re-fetched通道 1 末尾的几个字节不会重新获取

In this scenario, those few bytes are stale on CPU 0, because they were overwritten by CPU 1, and CPU 0 wasn't aware.在这种情况下,这几个字节在 CPU 0 上是陈旧的,因为它们被 CPU 1 覆盖,而 CPU 0 不知道。

It wasn't aware, because there wasn't a memory barrier telling it its cache might be stale.它不知道,因为没有内存屏障告诉它它的缓存可能已经过时。

Now, in many instances, a system call triggers a memory barrier, BUT it is not guaranteed.现在,在许多情况下,系统调用会触发内存屏障,但不能保证。

Your userspace program is fine, and a character device is the canonical way to communicate with a kernel module, but your kernel module has to synchronize properly.您的用户空间程序很好,字符设备是与内核模块通信的规范方式,但您的内核模块必须正确同步。 Even the example in your link seems to be trying to be very introductory and does things like Device_Open++ without using atomics.甚至您链接中的示例似乎也试图非常具有介绍性,并且在不使用原子的情况下执行Device_Open++类的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM