Поясните как это сделать? знаю такие варианты - реализация подобия обычной спин-блокировки на HIGH_LEVEL (увы висит все почему-то, если кто знает поясните почему, ну и ждать освобождения блокировки в обработчике исключения как-то не красиво) - заморозка всех процессоров кроме текущего на котором выполняется ISR (не проблема, но уже нет времени разбираться) каким образом можно выкрутится еще?
Здесь есть два варианта - либо изобретать свою синхронизацию, либо организовать структуры так, чтобы синхронизация не требовалась. Если нет транзакций, конфликты могут происходить только на записи. Т.о. если пишет только один поток, то можно спокойно пользовать, к примеру, очередь
видать виснет по другой причине мож в коде ошибка, гляньте если у кого время есть https://privatepaste.com/960vsDnCUw http://paste2.org/p/339532 Код (Text): // //hdr // #if !defined(disklog) #define disklog #include"defs.h" #define DISK_LOG #define DISK_LOG_MAX (PAGE_SIZE*40) typedef struct _DISK_LOG_DATA { KSPIN_LOCK Lock; u32 ActualSize; u8 *Data; HANDLE File; HANDLE WorkThread; }DISK_LOG_DATA, *PDISK_LOG_DATA; bool DiskLogInitialize(Out DISK_LOG_DATA* DiskLogData, In wchar_t *FilePath); void DiskLogUninitialize(In DISK_LOG_DATA* DiskLogData); void DiskLogAppendStandard(In DISK_LOG_DATA *DiskLogData, In u8 *Data, In u32 Size); #if defined(DISK_LOG) #define LogInit(ctx, x) DiskLogInitialize(ctx, x) #define LogDeinit(ctx) DiskLogUninitialize(ctx) #define LogAppend(ctx, x, y) DiskLogAppendStandard(ctx, x, y) #else #define LogInit(ctx, x) #define LogDeinit(ctx) #define LogAppend(ctx, x, y) #endif #endif // //code // #include"cpu.h" #include"disklog.h" static bool DiskLogWrite(In DISK_LOG_DATA* DiskLogData, In u8 *Data, In u32 Size); static void LogThread(In DISK_LOG_DATA *DiskLogData); static void LogThread(In DISK_LOG_DATA *DiskLogData) { KIRQL OldIrql = KeGetCurrentIrql(); u32 NewDataSize = {0}; u8 *NewDataBuffer = {0}; LARGE_INTEGER ExecDelay = {0}; KdPrint("Working thread started\n"); __try { NewDataBuffer = ExAllocPool(NonPagedPool, DISK_LOG_MAX); if(!NewDataBuffer) { __leave; } do { while(InterlockedCompareExchange(&DiskLogData->Lock, 1, 0) != 0) PAUSE(); if(KeGetCurrentIrql() < HIGH_LEVEL) KeRaiseIrql(HIGH_LEVEL, &OldIrql); NewDataSize = DiskLogData->ActualSize; if(NewDataSize) { memcpy(NewDataBuffer, &DiskLogData->Data, NewDataSize); DiskLogData->ActualSize = 0; } InterlockedAnd(&DiskLogData->Lock, 0); if(OldIrql < KeGetCurrentIrql()) KeLowerIrql(OldIrql); if(DiskLogWrite(DiskLogData, NewDataBuffer, NewDataSize)) break; NewDataSize = 0; }while(1); } __except(EXCEPTION_EXECUTE_HANDLER) { ; } if(NewDataBuffer) { ExFreePool(NewDataBuffer); NewDataBuffer = 0; } KdPrint("Terminating\n"); PsTerminateSystemThread(STATUS_SUCCESS); } void DiskLogUninitialize(In DISK_LOG_DATA* DiskLogData) { NTSTATUS NtStatus = STATUS_SUCCESS; PKTHREAD WorkThreadObj = {0}; KdPrint("Log uninitialization\n"); if(DiskLogData->File) { ZwClose(DiskLogData->File); DiskLogData->File = 0; } if(DiskLogData->WorkThread) { ZwWaitForSingleObject(DiskLogData->WorkThread, FALSE, 0); ZwClose(DiskLogData->WorkThread); DiskLogData->WorkThread = 0; } if(DiskLogData->Data) { ExFreePool(DiskLogData->Data); DiskLogData->Data = 0; } } bool DiskLogInitialize(Out DISK_LOG_DATA* DiskLogData, In wchar_t *FilePath) { NTSTATUS NtStatus = STATUS_SUCCESS; bool Result = {0}; HANDLE Handle = {0}; HANDLE FileHandle = {0}; UNICODE_STRING UnicodeStr = {0}; OBJECT_ATTRIBUTES ObjAttr = {0}; IO_STATUS_BLOCK IoStatBlock = {0}; KdPrint("Log initialization\n"); do { memzero(DiskLogData, sizeof(*DiskLogData)); DiskLogData->Data = ExAllocPool(NonPagedPool, DISK_LOG_MAX); if(!DiskLogData->Data) { Result = TRUE; KdPrint("ExAllocatePool failed\n"); break; } RtlInitUnicodeString(&UnicodeStr, FilePath); InitializeObjectAttributes(&ObjAttr, &UnicodeStr, OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, 0, 0); NtStatus = ZwCreateFile(&FileHandle, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, &ObjAttr, &IoStatBlock, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, 0, 0); if(!NT_SUCCESS(NtStatus)) { Result = TRUE; KdPrint("ZwCreateFile failed with code %.08X\n", NtStatus); break; } DiskLogData->File = FileHandle; InterlockedAnd(&DiskLogData->Lock, 0); InitializeObjectAttributes(&ObjAttr, 0, OBJ_KERNEL_HANDLE, 0, 0); NtStatus = PsCreateSystemThread(&Handle, THREAD_ALL_ACCESS, &ObjAttr, NtCurrentProcess(), 0, (PKSTART_ROUTINE)LogThread, DiskLogData); if(!NT_SUCCESS(NtStatus)) { Result = TRUE; KdPrint("PsCreateSystemThread failed with code %.08X\n", NtStatus); break; } DiskLogData->WorkThread = Handle; }while(0); if(Result) { if(FileHandle) { ZwClose(FileHandle); FileHandle = 0; DiskLogData->File = 0; } } return Result; } static bool DiskLogWrite(In DISK_LOG_DATA* DiskLogData, In u8 *Data, In u32 Size) { IO_STATUS_BLOCK IoStatBlock = {0}; LARGE_INTEGER Off = {0}; NTSTATUS NtStatus = STATUS_SUCCESS; bool Result = {0}; if(DiskLogData->File) { if(Size) { Off.HighPart = -1; Off.LowPart = FILE_USE_FILE_POINTER_POSITION; NtStatus = ZwWriteFile(DiskLogData->File, 0, 0, 0, &IoStatBlock, Data, Size, &Off, 0); if(!NT_SUCCESS(NtStatus)) { Result = 1; } else { KdPrint("%d bytes written\n", IoStatBlock.Information); } } } else { Result = 1; } return Result; } void DiskLogAppendStandard(In DISK_LOG_DATA *DiskLogData, In u8 *Data, In u32 Size) { KIRQL OldIrql = {0}; while(InterlockedCompareExchange(&DiskLogData->Lock, 1, 0) != 0) PAUSE(); if(KeGetCurrentIrql() < HIGH_LEVEL) KeRaiseIrql(HIGH_LEVEL, &OldIrql); memcpy(&DiskLogData->Data[DiskLogData->ActualSize], Data, Size); DiskLogData->ActualSize += Size; KdPrint("Data appended, LogData.ActualSize = %d\n", DiskLogData->ActualSize); InterlockedAnd(&DiskLogData->Lock, 0); if(OldIrql < KeGetCurrentIrql()) KeLowerIrql(OldIrql); } // //call from isr // static void IsrHandler() { u8 Data = {0}; IsrRecvData(&Data); LogAppend(&LogIrq01, &Data, sizeof(Data)); }
IRQL это уже второстепенная проблема, главное что вы пытаетесь столь высокого уровня функции вызывать с запрещёнными прерываниями, поэтому и виснет. Формируйте трап-фрейм, разрешайте прерывания а затем уже вызывайте что нужно.
А зачем вручную юзать? Есть же KeAcquireSpinLockAtDpcLevel и KeReleaseSpinLockFromDpcLevel Где-где запрещенные вызовы? Не нашел ни одного, всё законно. Запись в файлы уже после KfLowerIrql идет
А вообще, название топика не особо понял. Кто на DIRQL, кто на PASSIVE? Краткость, конечно, сестра таланта, но не в этом случае.
Clerk Я спрашиваю где там IF=0? Функции записи вызываются из NewThread, который работает с разрешенными прерываними на PASSIVE_LEVEL, см.код
Great в название больше информации не влезло заменен обработчик аппаратного прерывания в idt нужно писать данные с устройства при прерывании схематично idt[id]::isr -> буффер <- рабочий поток -> файл глобальный объект в данном случае буффер и размер данных в нем irql isr DIRQL irql рабочего потока PASSIVE не обратил на них внимания если честно но и так кажется должно работать если проблема в этом то вместо своей блокировки был обычный KeAcquire(Release)SpinLock, висло все так же виснет именно в цикле рабочего потока он через какое то время не дает себя прервать, не знаю почему такой еще момент, если вставить задержку в цикле рабочего потока (KeDelayExecutionThread), то все ок вставил ее наугад, тобишь хак обычный, и без него теоретически должно работать, но увы Clerk то что ты говоришь это все ясно но дело в том что я использую стандартный механизм доступа к разделяемому ресурсу и проблем быть не должно жаль что ты код не глянул перед коментариями, может знаешь в чем проблема