diff --git a/desktop/syscall.cpp b/desktop/syscall.cpp index 7b86ede..ab9d991 100644 --- a/desktop/syscall.cpp +++ b/desktop/syscall.cpp @@ -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; diff --git a/kernel/cache.cpp b/kernel/cache.cpp index e26018e..7a5fa2f 100644 --- a/kernel/cache.cpp +++ b/kernel/cache.cpp @@ -43,7 +43,7 @@ struct MMActiveSectionManager { KMutex mutex; LinkedList lruList; LinkedList 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; diff --git a/kernel/kernel.h b/kernel/kernel.h index 8208d4a..6057596 100644 --- a/kernel/kernel.h +++ b/kernel/kernel.h @@ -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) diff --git a/kernel/windows.cpp b/kernel/windows.cpp index 6ddf33a..4e06049 100644 --- a/kernel/windows.cpp +++ b/kernel/windows.cpp @@ -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); } diff --git a/util/build.c b/util/build.c index 708c3f6..a3dae43 100644 --- a/util/build.c +++ b/util/build.c @@ -286,7 +286,7 @@ void Compile(uint32_t flags, int partitionSize, const char *volumeLabel) { fileIndex++; } - if (noRequiredFiles) { + if (requiredFontsOnly && noRequiredFiles) { continue; }