简体   繁体   中英

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:

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:

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.

Here's a sketch of a race:

  1. System call wants to read into channel 2 on CPU 0.
  2. CPU 0 fetches all the cache lines containing channel 2, which means:
    • All the bytes in channel 2
    • A few bytes from the end of channel 1
    • A few bytes from the beginning of channel 3
  3. The read goes as usual.
  4. CPU 1 writes 500 bytes to channel 1.
  5. System call wants to read 500 bytes into channel 1 on CPU 0.
  6. CPU 0 fetches all the bytes from channel 1 which weren't previously fetched.
    • The few bytes from the end of channel 1 are not re-fetched

In this scenario, those few bytes are stale on CPU 0, because they were overwritten by CPU 1, and CPU 0 wasn't aware.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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