Системные вызовы поточно-ориентированы? - PullRequest
0 голосов
/ 14 марта 2020

Я написал модуль ядра. Это драйвер устройства для символов, например, this Link . Драйвер имеет внутреннюю структуру, такую ​​как:

struct {
    str[500];
}channelData;

static channelData chData[4];

. потоковое приложение, которое использует этот драйвер, в настоящее время я использую этот драйвер следующим образом:

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);
}

Итак, вопрос в том, вызывают ли 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);

Есть ли гонки данных или что-то подобное?

1 Ответ

1 голос
/ 15 марта 2020

Ваша структура channelData не обязательно будет выровнена по кешу, поэтому, если вы явно не синхронизируете chData, вы все равно подвергаетесь гонкам данных.

Вот эскиз гонки:

  1. Системный вызов хочет выполнить чтение в канал 2 на ЦП 0.
  2. ЦП 0 извлекает все строки кэша, содержащие канал 2, что означает:
    • Все байты в канале 2
    • Несколько байтов от конца канала 1
    • Несколько байтов от начала канала 3
  3. Считывание идет как обычно.
  4. CPU 1 записывает 500 байтов в канал 1.
  5. Системный вызов хочет прочитать 500 байтов в канал 1 в CPU 0.
  6. CPU 0 выбирает все байты из канала 1, которые ранее не были получены
    • Несколько байтов с конца канала 1 не выбираются повторно

В этом сценарии эти несколько байтов устарели на ЦП 0, поскольку они были перезаписаны ЦП 1, а ЦП 0 не знал.

Он не знал, потому что не было барьера памяти , сообщающего, что его кэш может быть устаревшим.

Теперь во многих случаях системный вызов вызывает барьер памяти, НО это не гарантируется.

Ваша пользовательская программа в порядке, а символьное устройство - это канонический способ связи с модулем ядра. , но ваш модуль ядра должен синхронизироваться правильно. Даже пример в вашей ссылке, кажется, пытается быть очень вводным и делает что-то вроде Device_Open++ без использования атомарности.

...