-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathScanFile.h
74 lines (56 loc) · 2.98 KB
/
ScanFile.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#pragma once
#include <atomic> // this is STL, but it does not need exceptions
#include <mutex> // this is STL, but it does not need exceptions
#include <new> // for std::hardware_constructive_interference_size
#include <optional> // this is STL, but it does not need exceptions
#include <string_view> // this is STL, but it does not need exceptions
#include <wchar.h> // for size_t, wchar_t
#include <windows.h>
class CScanFile
{
public:
~CScanFile();
bool Open(const wchar_t* const filename, const bool asyncMode);
void Close();
std::optional<std::string_view> MapToMemory();
bool Read(char* const buffer, const size_t bufferLength, size_t& readBytes);
// Current limitation: only one async operation can be in progress.
// You will need to have multiple OVERLAPPED structures and multiple events to handle few requests simultaneously.
bool AsyncReadStart(char* const buffer, const size_t bufferLength);
bool AsyncReadWait(size_t& readBytes);
// Current limitation: only one async operation can be in progress.
bool SpinlockInit();
void SpinlockClean();
bool SpinlockReadStart(char* const buffer, const size_t bufferLength);
bool SpinlockReadWait(size_t& readBytes);
void SpinlockThreadProc();
protected:
alignas(std::hardware_constructive_interference_size) // small speedup to get a bunch of variables into single cache line
HANDLE _hFile = nullptr;
// For memory mapping:
HANDLE _hFileMapping = nullptr;
void* _pViewOfFile = nullptr;
// For async IO:
HANDLE _hAsyncEvent = nullptr;
LARGE_INTEGER _asyncFileOffset = {};
OVERLAPPED _asyncOverlapped = {};
bool _asyncOperationInProgress = false;
// Separate thread + spin locks:
HANDLE _hThread = nullptr;
// for protection against wrong API usage, not for use in a worker thread, no memory protection:
// this is not about synchronization, but about correct class method call sequence
bool _threadOperationInProgress = false;
// other data protected by spin locks:
char* _pThreadReadBuffer = nullptr;
size_t _threadReadBufferSize = 0;
size_t _threadActuallyReadBytes = 0;
bool _threadReadSucceeded = false;
// Spin lock variables:
// We could use kernel-mode events instead of spin locks, it will save CPU, but will loose time during synchronization (switch to kernel).
alignas(std::hardware_destructive_interference_size)
std::atomic<bool> _threadFinishSpinlock = ATOMIC_VAR_INIT(false);
alignas(std::hardware_destructive_interference_size)
std::atomic<bool> _threadOperationReadStartSpinlock = ATOMIC_VAR_INIT(false);
alignas(std::hardware_destructive_interference_size)
std::atomic<bool> _threadOperationReadCompletedSpinlock = ATOMIC_VAR_INIT(false);
};