Синхронизация доступа к глобальному объекту:ISR(DIRQL) и PASSIVE_LEVEL

Тема в разделе "WASM.NT.KERNEL", создана пользователем o14189, 22 июл 2009.

  1. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    Поясните как это сделать?

    знаю такие варианты

    - реализация подобия обычной спин-блокировки на HIGH_LEVEL (увы висит все почему-то, если кто знает поясните почему, ну и ждать освобождения блокировки в обработчике исключения как-то не красиво)
    - заморозка всех процессоров кроме текущего на котором выполняется ISR (не проблема, но уже нет времени разбираться)

    каким образом можно выкрутится еще?
     
  2. Dian

    Dian Member

    Публикаций:
    0
    Регистрация:
    19 июн 2008
    Сообщения:
    222
    Здесь есть два варианта - либо изобретать свою синхронизацию, либо организовать структуры так, чтобы синхронизация не требовалась. Если нет транзакций, конфликты могут происходить только на записи. Т.о. если пишет только один поток, то можно спокойно пользовать, к примеру, очередь
     
  3. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    видать виснет по другой причине
    мож в коде ошибка, гляньте если у кого время есть

    https://privatepaste.com/960vsDnCUw
    http://paste2.org/p/339532

    Код (Text):
    1. //
    2. //hdr
    3. //
    4.  
    5. #if !defined(disklog)
    6. #define disklog
    7.  
    8. #include"defs.h"
    9.  
    10. #define DISK_LOG
    11.  
    12. #define DISK_LOG_MAX (PAGE_SIZE*40)
    13.  
    14. typedef struct _DISK_LOG_DATA
    15. {
    16.     KSPIN_LOCK Lock;
    17.     u32 ActualSize;
    18.     u8 *Data;
    19.     HANDLE File;
    20.     HANDLE WorkThread;
    21. }DISK_LOG_DATA,
    22. *PDISK_LOG_DATA;
    23.  
    24. bool
    25. DiskLogInitialize(Out DISK_LOG_DATA* DiskLogData,
    26.                 In wchar_t *FilePath);
    27.  
    28. void
    29. DiskLogUninitialize(In DISK_LOG_DATA* DiskLogData);
    30.  
    31. void
    32. DiskLogAppendStandard(In DISK_LOG_DATA *DiskLogData,
    33.                       In u8 *Data,
    34.                       In u32 Size);
    35.  
    36. #if defined(DISK_LOG)
    37. #define LogInit(ctx, x) DiskLogInitialize(ctx, x)
    38. #define LogDeinit(ctx) DiskLogUninitialize(ctx)
    39. #define LogAppend(ctx, x, y) DiskLogAppendStandard(ctx, x, y)
    40. #else
    41. #define LogInit(ctx, x)
    42. #define LogDeinit(ctx)
    43. #define LogAppend(ctx, x, y)
    44. #endif
    45.  
    46. #endif
    47.  
    48. //
    49. //code
    50. //
    51.  
    52. #include"cpu.h"
    53. #include"disklog.h"
    54.  
    55. static
    56. bool
    57. DiskLogWrite(In DISK_LOG_DATA* DiskLogData,
    58.              In u8 *Data,
    59.              In u32 Size);
    60. static
    61. void
    62. LogThread(In DISK_LOG_DATA *DiskLogData);
    63.  
    64. static
    65. void
    66. LogThread(In DISK_LOG_DATA *DiskLogData)
    67. {
    68.     KIRQL OldIrql = KeGetCurrentIrql();
    69.     u32 NewDataSize = {0};
    70.     u8 *NewDataBuffer = {0};
    71.     LARGE_INTEGER ExecDelay = {0};
    72.  
    73.     KdPrint("Working thread started\n");
    74.     __try
    75.     {
    76.         NewDataBuffer = ExAllocPool(NonPagedPool, DISK_LOG_MAX);
    77.         if(!NewDataBuffer)
    78.         {
    79.             __leave;
    80.         }
    81.         do
    82.         {
    83.             while(InterlockedCompareExchange(&DiskLogData->Lock, 1, 0) != 0)
    84.                 PAUSE();
    85.             if(KeGetCurrentIrql() < HIGH_LEVEL)
    86.                 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
    87.             NewDataSize = DiskLogData->ActualSize;
    88.             if(NewDataSize)
    89.             {
    90.                 memcpy(NewDataBuffer, &DiskLogData->Data, NewDataSize);
    91.                 DiskLogData->ActualSize = 0;
    92.             }
    93.             InterlockedAnd(&DiskLogData->Lock, 0);
    94.             if(OldIrql < KeGetCurrentIrql())
    95.                 KeLowerIrql(OldIrql);
    96.             if(DiskLogWrite(DiskLogData, NewDataBuffer, NewDataSize))
    97.                 break;
    98.             NewDataSize = 0;
    99.         }while(1);
    100.     }
    101.     __except(EXCEPTION_EXECUTE_HANDLER)
    102.     {
    103.         ;
    104.     }
    105.     if(NewDataBuffer)
    106.     {
    107.         ExFreePool(NewDataBuffer);
    108.         NewDataBuffer = 0;
    109.     }
    110.     KdPrint("Terminating\n");
    111.     PsTerminateSystemThread(STATUS_SUCCESS);
    112. }
    113.  
    114. void
    115. DiskLogUninitialize(In DISK_LOG_DATA* DiskLogData)
    116. {
    117.     NTSTATUS NtStatus = STATUS_SUCCESS;
    118.     PKTHREAD WorkThreadObj = {0};
    119.  
    120.     KdPrint("Log uninitialization\n");
    121.  
    122.     if(DiskLogData->File)
    123.     {
    124.         ZwClose(DiskLogData->File);
    125.         DiskLogData->File = 0;
    126.     }
    127.     if(DiskLogData->WorkThread)
    128.     {
    129.         ZwWaitForSingleObject(DiskLogData->WorkThread, FALSE, 0);
    130.         ZwClose(DiskLogData->WorkThread);
    131.         DiskLogData->WorkThread = 0;
    132.     }
    133.     if(DiskLogData->Data)
    134.     {
    135.         ExFreePool(DiskLogData->Data);
    136.         DiskLogData->Data = 0;
    137.     }
    138. }
    139.  
    140. bool
    141. DiskLogInitialize(Out DISK_LOG_DATA* DiskLogData,
    142.                   In wchar_t *FilePath)
    143. {
    144.     NTSTATUS NtStatus = STATUS_SUCCESS;
    145.     bool Result = {0};
    146.     HANDLE Handle = {0};
    147.     HANDLE FileHandle = {0};
    148.     UNICODE_STRING UnicodeStr = {0};
    149.     OBJECT_ATTRIBUTES ObjAttr = {0};
    150.     IO_STATUS_BLOCK IoStatBlock = {0};
    151.  
    152.     KdPrint("Log initialization\n");
    153.     do
    154.     {
    155.         memzero(DiskLogData, sizeof(*DiskLogData));
    156.         DiskLogData->Data = ExAllocPool(NonPagedPool, DISK_LOG_MAX);
    157.         if(!DiskLogData->Data)
    158.         {
    159.             Result = TRUE;
    160.             KdPrint("ExAllocatePool failed\n");
    161.             break;
    162.         }
    163.         RtlInitUnicodeString(&UnicodeStr, FilePath);
    164.         InitializeObjectAttributes(&ObjAttr, &UnicodeStr, OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, 0, 0);
    165.         NtStatus = ZwCreateFile(&FileHandle,
    166.                                 GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,
    167.                                 &ObjAttr,
    168.                                 &IoStatBlock,
    169.                                 0, FILE_ATTRIBUTE_NORMAL,
    170.                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
    171.                                 FILE_OVERWRITE_IF,
    172.                                 FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);
    173.         if(!NT_SUCCESS(NtStatus))
    174.         {
    175.             Result = TRUE;
    176.             KdPrint("ZwCreateFile failed with code %.08X\n", NtStatus);
    177.             break;
    178.         }
    179.         DiskLogData->File = FileHandle;
    180.         InterlockedAnd(&DiskLogData->Lock, 0);
    181.         InitializeObjectAttributes(&ObjAttr, 0, OBJ_KERNEL_HANDLE, 0, 0);
    182.         NtStatus = PsCreateSystemThread(&Handle,
    183.                                         THREAD_ALL_ACCESS,
    184.                                         &ObjAttr,
    185.                                         NtCurrentProcess(), 0,
    186.                                         (PKSTART_ROUTINE)LogThread, DiskLogData);
    187.         if(!NT_SUCCESS(NtStatus))
    188.         {
    189.             Result = TRUE;
    190.             KdPrint("PsCreateSystemThread failed with code %.08X\n", NtStatus);
    191.             break;
    192.         }
    193.         DiskLogData->WorkThread = Handle;
    194.     }while(0);
    195.     if(Result)
    196.     {
    197.         if(FileHandle)
    198.         {
    199.             ZwClose(FileHandle);
    200.             FileHandle = 0;
    201.             DiskLogData->File = 0;
    202.         }
    203.     }
    204.    
    205.     return Result;
    206. }
    207.  
    208. static
    209. bool
    210. DiskLogWrite(In DISK_LOG_DATA* DiskLogData,
    211.              In u8 *Data,
    212.              In u32 Size)
    213. {
    214.     IO_STATUS_BLOCK IoStatBlock = {0};
    215.     LARGE_INTEGER Off = {0};
    216.     NTSTATUS NtStatus = STATUS_SUCCESS;
    217.     bool Result = {0};
    218.  
    219.     if(DiskLogData->File)
    220.     {
    221.         if(Size)
    222.         {
    223.             Off.HighPart = -1;
    224.             Off.LowPart = FILE_USE_FILE_POINTER_POSITION;
    225.             NtStatus = ZwWriteFile(DiskLogData->File, 0, 0, 0,
    226.                                     &IoStatBlock, Data,
    227.                                     Size, &Off, 0);
    228.             if(!NT_SUCCESS(NtStatus))
    229.             {
    230.                 Result = 1;
    231.             }
    232.             else
    233.             {
    234.                 KdPrint("%d bytes written\n", IoStatBlock.Information);
    235.             }
    236.         }
    237.     }
    238.     else
    239.     {
    240.         Result = 1;
    241.     }
    242.  
    243.     return Result;
    244. }
    245.  
    246. void
    247. DiskLogAppendStandard(In DISK_LOG_DATA *DiskLogData,
    248.                     In u8 *Data,
    249.                     In u32 Size)
    250. {
    251.     KIRQL OldIrql = {0};
    252.  
    253.     while(InterlockedCompareExchange(&DiskLogData->Lock, 1, 0) != 0)
    254.         PAUSE();
    255.     if(KeGetCurrentIrql() < HIGH_LEVEL)
    256.         KeRaiseIrql(HIGH_LEVEL, &OldIrql);
    257.     memcpy(&DiskLogData->Data[DiskLogData->ActualSize], Data, Size);
    258.     DiskLogData->ActualSize += Size;
    259.     KdPrint("Data appended, LogData.ActualSize = %d\n", DiskLogData->ActualSize);
    260.     InterlockedAnd(&DiskLogData->Lock, 0);
    261.     if(OldIrql < KeGetCurrentIrql())
    262.         KeLowerIrql(OldIrql);
    263. }
    264.  
    265. //
    266. //call from isr
    267. //
    268.  
    269. static
    270. void
    271. IsrHandler()
    272. {
    273.     u8 Data = {0};
    274.  
    275.     IsrRecvData(&Data);
    276.     LogAppend(&LogIrq01, &Data, sizeof(Data));
    277. }
     
  4. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    IRQL это уже второстепенная проблема, главное что вы пытаетесь столь высокого уровня функции вызывать с запрещёнными прерываниями, поэтому и виснет. Формируйте трап-фрейм, разрешайте прерывания а затем уже вызывайте что нужно.
     
  5. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    А зачем вручную юзать? Есть же KeAcquireSpinLockAtDpcLevel и KeReleaseSpinLockFromDpcLevel
    Где-где запрещенные вызовы? Не нашел ни одного, всё законно. Запись в файлы уже после KfLowerIrql идет
     
  6. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    А вообще, название топика не особо понял. Кто на DIRQL, кто на PASSIVE?
    Краткость, конечно, сестра таланта, но не в этом случае.
     
  7. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    <здесь клерк смачно выпендрился про то, что при IF=0 нельзя вызывать апи>
     
  8. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Clerk
    Я спрашиваю где там IF=0?
    Функции записи вызываются из NewThread, который работает с разрешенными прерываними на PASSIVE_LEVEL, см.код
     
  9. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    Great
    в название больше информации не влезло
    заменен обработчик аппаратного прерывания в idt
    нужно писать данные с устройства при прерывании

    схематично
    idt[id]::isr -> буффер <- рабочий поток -> файл

    глобальный объект в данном случае буффер и размер данных в нем
    irql isr DIRQL
    irql рабочего потока PASSIVE

    не обратил на них внимания если честно
    но и так кажется должно работать
    если проблема в этом
    то вместо своей блокировки был обычный KeAcquire(Release)SpinLock, висло все так же

    виснет именно в цикле рабочего потока
    он через какое то время не дает себя прервать, не знаю почему
    такой еще момент, если вставить задержку в цикле рабочего потока (KeDelayExecutionThread), то все ок
    вставил ее наугад, тобишь хак обычный, и без него теоретически должно работать, но увы

    Clerk
    то что ты говоришь это все ясно
    но дело в том что я использую стандартный механизм доступа к разделяемому ресурсу и проблем быть не должно
    жаль что ты код не глянул перед коментариями, может знаешь в чем проблема
     
  10. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    *
    PAUSE(); это __asm pause
     
  11. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    и заморозка тоже не прокатит, т.к. непосредственно перед изменением, могла быть считана часть данных
     
  12. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    имеется ввиду задержка на PASSIVE_LEVEL
     
  13. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    имеется ввиду задержка на PASSIVE_LEVEL
     
  14. DriversDeveloper

    DriversDeveloper Виктор Фисюк

    Публикаций:
    0
    Регистрация:
    15 мар 2008
    Сообщения:
    6
    Адрес:
    Kiev, Ukraine
    KeSynchronizeExecution
     
  15. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    я не использую IoConnectInterrupt вместо него патч в IDTR->IDT