mirror of https://gitlab.com/nakst/essence
new cache write back algorithm; fix single key press with key repeat
This commit is contained in:
parent
2e457eb792
commit
411ff15698
|
@ -475,6 +475,12 @@ ptrdiff_t EsDirectoryEnumerateChildren(const char *path, ptrdiff_t pathBytes, Es
|
|||
node.directoryChildren = 4194304 / sizeof(EsDirectoryChild); // TODO Grow the buffer until all entries fit.
|
||||
}
|
||||
|
||||
if (node.directoryChildren == 0) {
|
||||
// Empty directory.
|
||||
*buffer = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*buffer = (EsDirectoryChild *) EsHeapAllocate(sizeof(EsDirectoryChild) * node.directoryChildren, true);
|
||||
ptrdiff_t result;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ struct MMActiveSectionManager {
|
|||
KMutex mutex;
|
||||
LinkedList<CCActiveSection> lruList;
|
||||
LinkedList<CCActiveSection> modifiedList;
|
||||
KEvent modifiedNonEmpty, modifiedNonFull;
|
||||
KEvent modifiedNonEmpty, modifiedNonFull, modifiedGettingFull;
|
||||
Thread *writeBackThread;
|
||||
};
|
||||
|
||||
|
@ -245,6 +245,9 @@ void CCWriteSectionPrepare(CCActiveSection *section) {
|
|||
section->flush = false;
|
||||
KEventReset(§ion->writeCompleteEvent);
|
||||
section->accessors = 1;
|
||||
if (!activeSectionManager.modifiedList.count) KEventReset(&activeSectionManager.modifiedNonEmpty);
|
||||
if (activeSectionManager.modifiedList.count < CC_MODIFIED_GETTING_FULL) KEventReset(&activeSectionManager.modifiedGettingFull);
|
||||
KEventSet(&activeSectionManager.modifiedNonFull, false, true);
|
||||
}
|
||||
|
||||
void CCWriteSection(CCActiveSection *section) {
|
||||
|
@ -368,12 +371,19 @@ void CCActiveSectionReturnToLists(CCActiveSection *section, bool writeBack) {
|
|||
if (activeSectionManager.modifiedList.count > CC_MAX_MODIFIED) {
|
||||
waitNonFull = true;
|
||||
continue;
|
||||
} else if (activeSectionManager.modifiedList.count == CC_MAX_MODIFIED) {
|
||||
}
|
||||
|
||||
if (activeSectionManager.modifiedList.count == CC_MAX_MODIFIED) {
|
||||
KEventReset(&activeSectionManager.modifiedNonFull);
|
||||
}
|
||||
|
||||
activeSectionManager.modifiedList.InsertEnd(§ion->listItem);
|
||||
if (activeSectionManager.modifiedList.count >= CC_MODIFIED_GETTING_FULL) {
|
||||
KEventSet(&activeSectionManager.modifiedGettingFull, false, true);
|
||||
}
|
||||
|
||||
KEventSet(&activeSectionManager.modifiedNonEmpty, false, true);
|
||||
|
||||
activeSectionManager.modifiedList.InsertEnd(§ion->listItem);
|
||||
} else {
|
||||
activeSectionManager.lruList.InsertEnd(§ion->listItem);
|
||||
}
|
||||
|
@ -1156,10 +1166,30 @@ EsError CCSpaceAccess(CCSpace *cache, K_USER_BUFFER void *_buffer, EsFileOffset
|
|||
return ES_SUCCESS;
|
||||
}
|
||||
|
||||
void CCWriteBehindThread() {
|
||||
while (true) {
|
||||
// Wait for an active section to be modified, and have no accessors.
|
||||
bool CCWriteBehindSection() {
|
||||
CCActiveSection *section = nullptr;
|
||||
KMutexAcquire(&activeSectionManager.mutex);
|
||||
|
||||
if (activeSectionManager.modifiedList.count) {
|
||||
section = activeSectionManager.modifiedList.firstItem->thisItem;
|
||||
CCWriteSectionPrepare(section);
|
||||
}
|
||||
|
||||
KMutexRelease(&activeSectionManager.mutex);
|
||||
|
||||
if (section) {
|
||||
CCWriteSection(section);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CCWriteBehindThread() {
|
||||
uintptr_t lastWriteMs = 0;
|
||||
|
||||
while (true) {
|
||||
#if 0
|
||||
KEventWait(&activeSectionManager.modifiedNonEmpty);
|
||||
|
||||
if (MM_AVAILABLE_PAGES() > MM_LOW_AVAILABLE_PAGES_THRESHOLD && !scheduler.shutdown) {
|
||||
|
@ -1167,26 +1197,32 @@ void CCWriteBehindThread() {
|
|||
KEventWait(&pmm.availableLow, CC_WAIT_FOR_WRITE_BEHIND);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// Take a section, and mark it as being written.
|
||||
while (CCWriteBehindSection());
|
||||
#else
|
||||
// Wait until the modified list is non-empty.
|
||||
KEventWait(&activeSectionManager.modifiedNonEmpty);
|
||||
|
||||
CCActiveSection *section = nullptr;
|
||||
KMutexAcquire(&activeSectionManager.mutex);
|
||||
|
||||
if (activeSectionManager.modifiedList.count) {
|
||||
section = activeSectionManager.modifiedList.firstItem->thisItem;
|
||||
CCWriteSectionPrepare(section);
|
||||
}
|
||||
|
||||
KEventSet(&activeSectionManager.modifiedNonFull, false, true);
|
||||
KMutexRelease(&activeSectionManager.mutex);
|
||||
|
||||
if (!section) {
|
||||
break;
|
||||
} else {
|
||||
CCWriteSection(section);
|
||||
}
|
||||
if (lastWriteMs < CC_WAIT_FOR_WRITE_BEHIND) {
|
||||
// Wait for a reason to want to write behind.
|
||||
// - The CC_WAIT_FOR_WRITE_BEHIND timer expires.
|
||||
// - The number of available page frames is low (pmm.availableLow).
|
||||
// - The system is shutting down and so the cache must be flushed (scheduler.killedEvent).
|
||||
// - The modified list is getting full (activeSectionManager.modifiedGettingFull).
|
||||
KTimer timer = {};
|
||||
KTimerSet(&timer, CC_WAIT_FOR_WRITE_BEHIND - lastWriteMs);
|
||||
KEvent *events[] = { &timer.event, &pmm.availableLow, &scheduler.killedEvent, &activeSectionManager.modifiedGettingFull };
|
||||
scheduler.WaitEvents(events, sizeof(events) / sizeof(events[0]));
|
||||
KTimerRemove(&timer);
|
||||
}
|
||||
|
||||
// Write back 1/CC_WRITE_BACK_DIVISORth of the modified list.
|
||||
lastWriteMs = scheduler.timeMs;
|
||||
KMutexAcquire(&activeSectionManager.mutex);
|
||||
uintptr_t writeCount = (activeSectionManager.modifiedList.count + CC_WRITE_BACK_DIVISOR - 1) / CC_WRITE_BACK_DIVISOR;
|
||||
KMutexRelease(&activeSectionManager.mutex);
|
||||
while (writeCount && CCWriteBehindSection()) writeCount--;
|
||||
lastWriteMs = scheduler.timeMs - lastWriteMs;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1206,7 +1242,6 @@ void CCInitialise() {
|
|||
KernelLog(LOG_INFO, "Memory", "cache initialised", "MMInitialise - Active section manager initialised with a maximum of %d of entries.\n",
|
||||
activeSectionManager.sectionCount);
|
||||
|
||||
activeSectionManager.modifiedNonEmpty.autoReset = true;
|
||||
KEventSet(&activeSectionManager.modifiedNonFull);
|
||||
activeSectionManager.writeBackThread = scheduler.SpawnThread("CCWriteBehind", (uintptr_t) CCWriteBehindThread, 0, ES_FLAGS_DEFAULT);
|
||||
activeSectionManager.writeBackThread->isPageGenerator = true;
|
||||
|
|
|
@ -8,8 +8,12 @@
|
|||
|
||||
// TODO Determine the best values for these constants.
|
||||
|
||||
// Wait 1 second before running the write behind thread. (Ignored if MM_AVAILABLE_PAGES() is below the low threshold.)
|
||||
// Interval between write behinds. (Assuming no low memory conditions are in effect.)
|
||||
#define CC_WAIT_FOR_WRITE_BEHIND (1000)
|
||||
|
||||
// Divisor of the modified list size for each write behind batch.
|
||||
// That is, every CC_WAIT_FOR_WRITE_BEHIND ms, 1/CC_WRITE_BACK_DIVISORth of the modified list is written back.
|
||||
#define CC_WRITE_BACK_DIVISOR (8)
|
||||
|
||||
// Describes the virtual memory covering a section of a file.
|
||||
#define CC_ACTIVE_SECTION_SIZE ((EsFileOffset) 262144)
|
||||
|
@ -17,6 +21,10 @@
|
|||
// Maximum number of active sections on the modified list. If exceeded, writers will wait for it to drop before retrying.
|
||||
// TODO This should based off the amount of physical memory.
|
||||
#define CC_MAX_MODIFIED (67108864 / CC_ACTIVE_SECTION_SIZE)
|
||||
|
||||
// The size at which the modified list is determined to be getting worryingly full;
|
||||
// passing this threshold causes the write back thread to immediately start working.
|
||||
#define CC_MODIFIED_GETTING_FULL (CC_MAX_MODIFIED * 2 / 3)
|
||||
|
||||
// The size of the kernel's address space used for mapping active sections.
|
||||
#if defined(ARCH_32)
|
||||
|
|
|
@ -319,26 +319,20 @@ void WindowManager::PressKey(unsigned scancode) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool moveCursorNone = false;
|
||||
|
||||
KMutexAcquire(&mutex);
|
||||
|
||||
if (scancode == ES_SCANCODE_NUM_DIVIDE) {
|
||||
KernelPanic("WindowManager::PressKey - Panic key pressed.\n");
|
||||
}
|
||||
|
||||
bool single = (scancode & K_SCANCODE_KEY_RELEASED) && maximumKeysHeld == 1;
|
||||
keysHeld += (scancode & K_SCANCODE_KEY_RELEASED) ? -1 : 1;
|
||||
keysHeld = MaximumInteger(keysHeld, 0); // Prevent negative keys held count.
|
||||
maximumKeysHeld = (!keysHeld || keysHeld > maximumKeysHeld) ? keysHeld : maximumKeysHeld;
|
||||
|
||||
if (eyedropping) {
|
||||
if (scancode == (ES_SCANCODE_ESCAPE | K_SCANCODE_KEY_RELEASED)) {
|
||||
EndEyedrop(true);
|
||||
moveCursorNone = true;
|
||||
}
|
||||
|
||||
goto done;
|
||||
MoveCursor(0, 0);
|
||||
KMutexRelease(&mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Caps lock.
|
||||
|
@ -372,43 +366,43 @@ void WindowManager::PressKey(unsigned scancode) {
|
|||
| ((shift | shift2) ? ES_MODIFIER_SHIFT : 0)
|
||||
| ((flag | flag2) ? ES_MODIFIER_FLAG : 0);
|
||||
|
||||
KernelLog(LOG_VERBOSE, "WM", "press key", "WindowManager::PressKey - Received key press %x. Modifiers are %X. Keys held: %d/%d%z.\n",
|
||||
scancode, modifiers, keysHeld, maximumKeysHeld, single ? " (single)" : "");
|
||||
EsMessage message;
|
||||
EsMemoryZero(&message, sizeof(EsMessage));
|
||||
message.type = (scancode & K_SCANCODE_KEY_RELEASED) ? ES_MSG_KEY_UP : ES_MSG_KEY_DOWN;
|
||||
message.keyboard.modifiers = modifiers;
|
||||
message.keyboard.scancode = scancode & ~K_SCANCODE_KEY_RELEASED;
|
||||
message.keyboard.numlock = numlock;
|
||||
|
||||
{
|
||||
EsMessage message;
|
||||
EsMemoryZero(&message, sizeof(EsMessage));
|
||||
message.type = (scancode & K_SCANCODE_KEY_RELEASED) ? ES_MSG_KEY_UP : ES_MSG_KEY_DOWN;
|
||||
message.keyboard.modifiers = modifiers;
|
||||
message.keyboard.scancode = scancode & ~K_SCANCODE_KEY_RELEASED;
|
||||
message.keyboard.numlock = numlock;
|
||||
message.keyboard.single = single;
|
||||
|
||||
if (message.keyboard.scancode >= 512) {
|
||||
KernelPanic("WindowManager::PressKey - Scancode outside valid range.\n");
|
||||
}
|
||||
|
||||
if (message.type == ES_MSG_KEY_DOWN && (keysHeldBitSet[message.keyboard.scancode / 8] & (1 << (message.keyboard.scancode % 8)))) {
|
||||
message.keyboard.repeat = true;
|
||||
}
|
||||
|
||||
if (message.type == ES_MSG_KEY_DOWN) {
|
||||
keysHeldBitSet[message.keyboard.scancode / 8] |= (1 << (message.keyboard.scancode % 8));
|
||||
} else {
|
||||
keysHeldBitSet[message.keyboard.scancode / 8] &= ~(1 << (message.keyboard.scancode % 8));
|
||||
}
|
||||
|
||||
if ((modifiers & ES_MODIFIER_CTRL) && (modifiers & ES_MODIFIER_FLAG)) {
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &message);
|
||||
} else if (activeWindow) {
|
||||
SendMessageToWindow(activeWindow, &message);
|
||||
} else {
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &message);
|
||||
}
|
||||
if (message.keyboard.scancode >= 512) {
|
||||
KernelPanic("WindowManager::PressKey - Scancode outside valid range.\n");
|
||||
}
|
||||
|
||||
if (message.type == ES_MSG_KEY_DOWN && (keysHeldBitSet[message.keyboard.scancode / 8] & (1 << (message.keyboard.scancode % 8)))) {
|
||||
message.keyboard.repeat = true;
|
||||
}
|
||||
|
||||
if (message.type == ES_MSG_KEY_DOWN) {
|
||||
keysHeldBitSet[message.keyboard.scancode / 8] |= (1 << (message.keyboard.scancode % 8));
|
||||
} else {
|
||||
keysHeldBitSet[message.keyboard.scancode / 8] &= ~(1 << (message.keyboard.scancode % 8));
|
||||
}
|
||||
|
||||
message.keyboard.single = (scancode & K_SCANCODE_KEY_RELEASED) && maximumKeysHeld == 1;
|
||||
if (!message.keyboard.repeat) keysHeld += (scancode & K_SCANCODE_KEY_RELEASED) ? -1 : 1;
|
||||
keysHeld = MaximumInteger(keysHeld, 0); // Prevent negative keys held count.
|
||||
maximumKeysHeld = (!keysHeld || keysHeld > maximumKeysHeld) ? keysHeld : maximumKeysHeld;
|
||||
|
||||
KernelLog(LOG_VERBOSE, "WM", "press key", "WindowManager::PressKey - Received key press %x. Modifiers are %X. Keys held: %d/%d%z.\n",
|
||||
scancode, modifiers, keysHeld, maximumKeysHeld, message.keyboard.single ? " (single)" : "");
|
||||
|
||||
if ((modifiers & ES_MODIFIER_CTRL) && (modifiers & ES_MODIFIER_FLAG)) {
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &message);
|
||||
} else if (activeWindow) {
|
||||
SendMessageToWindow(activeWindow, &message);
|
||||
} else {
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &message);
|
||||
}
|
||||
|
||||
done:;
|
||||
if (moveCursorNone) MoveCursor(0, 0);
|
||||
KMutexRelease(&mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -286,7 +286,7 @@ void Compile(uint32_t flags, int partitionSize, const char *volumeLabel) {
|
|||
fileIndex++;
|
||||
}
|
||||
|
||||
if (noRequiredFiles) {
|
||||
if (requiredFontsOnly && noRequiredFiles) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue