From 5914c817a348ea330bd186e313fbb187ce2adf56 Mon Sep 17 00:00:00 2001 From: vczh Date: Tue, 16 Jun 2026 18:06:22 -0700 Subject: [PATCH] Sync copilot knowledge base --- .github/KnowledgeBase/Index.md | 2 ++ .../KnowledgeBase/KB_VlppOS_MultiThreading.md | 30 ++++++++++++++++--- .../KB_VlppOS_SynchronizationPrimitives.md | 3 +- .../KB_Vlpp_ConsoleOperations.md | 30 +++++++++++++++++-- .github/KnowledgeBase/Learning.md | 16 +++++++--- .../manual/vlppos/using-threads.md | 2 +- 6 files changed, 71 insertions(+), 12 deletions(-) diff --git a/.github/KnowledgeBase/Index.md b/.github/KnowledgeBase/Index.md index 94585046..701037d1 100644 --- a/.github/KnowledgeBase/Index.md +++ b/.github/KnowledgeBase/Index.md @@ -155,6 +155,7 @@ Algorithms for arranging data with support for both total and partial ordering r Basic input/output operations for console applications. - Use `Console::Write` and `Console::WriteLine` for console output in CLI applications +- Use `Console::TryRead` for nullable line input that handles console input, redirection, and EOF [API Explanation](./KB_Vlpp_ConsoleOperations.md) @@ -285,6 +286,7 @@ Specialized stream types for caching, recording, and broadcasting data operation Cross-platform threading primitives and synchronization mechanisms for concurrent programming. - Use `ThreadPoolLite::Queue` and `ThreadPoolLite::QueueLambda` for thread pool execution +- Use `TaskQueue` when queued work must run on one blocking task loop instead of the thread pool - Use `Thread::Sleep` for thread pausing - Use `Thread::GetCurrentThreadId` for thread identification - Use `Thread::CreateAndStart` only when thread pool is insufficient diff --git a/.github/KnowledgeBase/KB_VlppOS_MultiThreading.md b/.github/KnowledgeBase/KB_VlppOS_MultiThreading.md index 1d165ef1..7cc87535 100644 --- a/.github/KnowledgeBase/KB_VlppOS_MultiThreading.md +++ b/.github/KnowledgeBase/KB_VlppOS_MultiThreading.md @@ -8,6 +8,8 @@ Use `ThreadPoolLite::Queue` and `ThreadPoolLite::QueueLambda` for thread pool ex Use static functions `ThreadPoolLite::Queue` or `ThreadPoolLite::QueueLambda` to run a function in another thread. +Use `TaskQueue` when work must be queued from multiple threads but executed by one blocking task loop. + ### ThreadPoolLite Benefits The thread pool provides several advantages over manual thread creation: @@ -28,6 +30,26 @@ ThreadPoolLite::QueueLambda([]() { }); ``` +## Task Queue Operations + +`TaskQueue` owns a FIFO task list and a semaphore-backed blocking loop. Call `QueueTask` from any thread, run `RunTaskQueue` on the thread that should execute the work, and call `QueueExitTask` to leave the loop after already queued tasks are complete. + +```cpp +auto queue = Ptr(new TaskQueue); +auto thread = Ptr(Thread::CreateAndStart([=]() +{ + queue->RunTaskQueue(); +}, false)); + +queue->QueueTask([]() +{ + // Runs on the task queue thread +}); +queue->QueueExitTask(); +``` + +Use `TaskQueue` instead of `ThreadPoolLite` when the order and single-threaded execution context of tasks matters. + ## Thread Control Operations ### Thread Pausing @@ -47,7 +69,7 @@ Use static function `Thread::GetCurrentThreadId` to get an identifier for the OS Use `Thread::CreateAndStart` only when thread pool is insufficient. `Thread::CreateAndStart` could be used to run a function in another thread while returning a `Thread*` to control it, but this is not recommended. -Always use `ThreadPoolLite` if possible. +Always use `ThreadPoolLite` if possible. Use `TaskQueue` when a long-lived single-threaded task loop is required. ### When to Use Manual Threads @@ -59,7 +81,7 @@ Manual thread creation should only be considered when: ## Thread Pool with Synchronization -A `ThreadPoolLite` call with an `EventObject` is a better version of `Thread::Wait`. +A `ThreadPoolLite` call with an `EventObject` is a better version of `Thread::Wait`. `TaskQueue` is the alternative when multiple callers should enqueue work to one owner thread. This approach provides better resource management and avoids the complexities of manual thread synchronization. @@ -67,7 +89,7 @@ This approach provides better resource management and avoids the complexities of ### Threading Best Practices -1. **Prefer Thread Pool**: Use `ThreadPoolLite` for most concurrent operations +1. **Prefer Thread Pool**: Use `ThreadPoolLite` for most concurrent operations, and use `TaskQueue` for serialized owner-thread work 2. **Avoid Thread Creation**: Manual thread creation adds overhead and complexity 3. **Use Synchronization Primitives**: Combine threading with proper synchronization objects 4. **Handle Exceptions**: Ensure proper exception handling in threaded code @@ -109,4 +131,4 @@ Multi-threading works best when combined with appropriate synchronization primit - Use with `Mutex` for cross-process synchronization - Combine with `CriticalSection` for in-process protection - Integrate with `EventObject` for thread coordination -- Apply `ConditionVariable` for complex waiting scenarios \ No newline at end of file +- Apply `ConditionVariable` for complex waiting scenarios diff --git a/.github/KnowledgeBase/KB_VlppOS_SynchronizationPrimitives.md b/.github/KnowledgeBase/KB_VlppOS_SynchronizationPrimitives.md index 1f653d5e..798cb6bb 100644 --- a/.github/KnowledgeBase/KB_VlppOS_SynchronizationPrimitives.md +++ b/.github/KnowledgeBase/KB_VlppOS_SynchronizationPrimitives.md @@ -172,5 +172,6 @@ Tips for optimal synchronization performance: Synchronization primitives work best when combined with the multi-threading APIs: - Use with `ThreadPoolLite` for concurrent task execution +- Use with `TaskQueue` when synchronized producers feed a single-threaded task loop - Combine with `ConditionVariable` for complex coordination scenarios -- Apply appropriate synchronization for shared data structures \ No newline at end of file +- Apply appropriate synchronization for shared data structures diff --git a/.github/KnowledgeBase/KB_Vlpp_ConsoleOperations.md b/.github/KnowledgeBase/KB_Vlpp_ConsoleOperations.md index 866b90ca..1dea4c83 100644 --- a/.github/KnowledgeBase/KB_Vlpp_ConsoleOperations.md +++ b/.github/KnowledgeBase/KB_Vlpp_ConsoleOperations.md @@ -1,4 +1,4 @@ -# Console Operations +# Console Operations ## Overview @@ -50,6 +50,31 @@ Console::WriteLine(const WString& text); - **Cross-platform compatibility**: Consistent behavior across operating systems - **Sequential output**: Each call produces a new line of output +## Basic Input Functions + +### Console::TryRead Function + +Use `Console::TryRead` for line input from either an attached console or redirected stdin. It returns `Nullable`, with null meaning no line is available, such as EOF or an unavailable input handle. + +```cpp +auto line = Console::TryRead(); +if (line) +{ + Console::WriteLine(L"Input: " + line.Value()); +} +``` + +**Function usage:** +```cpp +Nullable Console::TryRead(); +``` + +**Key characteristics:** +- **Redirection aware**: Handles both interactive console input and stdin redirection +- **EOF aware**: Returns null instead of forcing callers to treat EOF as an empty line +- **Wide string result**: Produces `WString` so it composes with console output APIs +- **Console::Read compatibility**: `Console::Read` calls `TryRead` and returns `WString::Empty` when `TryRead` returns null + ## Usage Patterns ### Simple Text Output @@ -209,6 +234,7 @@ Console operations assume a console window is available: - **Console applications**: Always have console access - **GUI applications**: May not have console access on some platforms - **Service applications**: May redirect console output to logs +- **Redirected input**: Use `Console::TryRead` when stdin may be redirected or may reach EOF ## Extra Content @@ -268,4 +294,4 @@ Console::WriteLine(L"Japanese: こんにちは世界"); Console::WriteLine(L"Arabic: مرحبا بالعالم"); ``` -The actual display depends on the console's font and locale settings, but the framework properly handles the character encoding. \ No newline at end of file +The actual display depends on the console's font and locale settings, but the framework properly handles the character encoding. diff --git a/.github/KnowledgeBase/Learning.md b/.github/KnowledgeBase/Learning.md index 0dc1c901..9a3ed04e 100644 --- a/.github/KnowledgeBase/Learning.md +++ b/.github/KnowledgeBase/Learning.md @@ -3,11 +3,11 @@ # Orders - Process staged tasks one by one with verification [15] -- Port fixes from imports to source repositories [7] -- Verify generated artifacts with downstream consumer checks [7] +- Verify generated artifacts with downstream consumer checks [8] +- Port fixes from imports to source repositories [8] - Crash early instead of adding error-tolerance fallbacks [6] -- Make `Stop()` drain asynchronous work before returning [5] -- Proactively remove code made redundant by refactoring [5] +- Proactively remove code made redundant by refactoring [6] +- Make `Stop()` drain asynchronous work before returning [6] - Use `WString::IndexOf` with `wchar_t` (not `const wchar_t*`) [4] - Use `collections::BinarySearchLambda` on contiguous buffers (guard empty) [4] - Use `vl::Exception` for expected semantic failures and `CHECK_ERROR` for invariants [3] @@ -95,6 +95,8 @@ Use the platform's final callback boundary when available. For WinHTTP async req Renderer clients should explicitly stop their network transport before stack-owned channel wrappers are destroyed, so callback shutdown completes before local wrapper storage goes out of scope. +Named-pipe shutdown should cancel pending overlapped pipe I/O before waiting for read callbacks to drain, especially when the remote side closes the pipe first. Channel-client destruction should also avoid stopping an already-disconnected transport connection. + ## Port fixes from imports to source repositories Do not treat files copied into `Import` or generated release files as the source of truth. When a fix affects imported `Vlpp` files, make the upstream change in `Vlpp`, regenerate its release output, and then copy the generated files downstream. When a `.github` instruction or script fix is needed, port it through `Tools/Copilot`. @@ -105,6 +107,8 @@ When validating GacUI remoting reveals a transport issue, keep the same source-o For dependency release syncs, copy generated files from the upstream `Release` folder into the downstream `Import` folder and exclude `IncludeOnly` unless the task explicitly requires it. Do not hand-edit the downstream import copy. +When importing multiple dependency releases into GacUI, keep the chain explicit: regenerate and import `VlppOS` and `Workflow` release artifacts, then validate the GacUI remoting scenarios that consume both imported APIs. + If a Workflow task exposes a `VlppReflection` collection-wrapper issue, fix the wrapper behavior in `VlppReflection`, regenerate and verify its release output, then update the Workflow import from that release instead of patching Workflow's imported copy. ## Validate expectations against implementation and existing tests @@ -201,6 +205,8 @@ When generated RPC JSON values or request/response transcripts are part of the c When a generator produces runnable sample applications, verify the generated output through the actual app workflow too. For example, generated ChatBot RPC code should be checked by running the server and multiple clients through joins, chat messages, client exit, and server shutdown, not only by confirming generation succeeds. +When a shared dispatcher schema such as `Rpc.d.ts` changes, type-check the shared schema itself as well as generated fixtures so envelope changes are caught even before concrete generated values instantiate every request shape. + ## `vl::regex` separator regex: `L"[\\/\\\\]+"` In `vl::regex::Regex`, both `/` and `\\` are escaping characters, and incorrect escaping inside `[]` can throw errors like `Illegal character set definition.` @@ -237,6 +243,8 @@ When a destructor only resets `Ptr`, shared-pointer, or similar owning members t When splitting a monolithic implementation into focused files, delete empty source stubs and duplicate state fields in the same cleanup. Update project metadata and includes immediately so the old file names do not remain as stale references. +For application refactors, remove helper wrappers that only duplicate an already-clear direct call. For example, direct `GetChannels()[WString::Unmanaged(RpcChannel)]` access is preferable to a `GetRpcChannel` helper when the intended behavior is still to fail if the channel is missing. + ## Keep design documentation aligned with code after refactoring When a refactoring changes architecture or behavior, update the corresponding design documents in the same task rather than deferring it. After a structural change, re-read the related documents and reconcile anything that became misaligned (for example, descriptions of a transport path that no longer exists). Treat documentation drift left by a previous refactoring as part of the current cleanup. diff --git a/.github/KnowledgeBase/manual/vlppos/using-threads.md b/.github/KnowledgeBase/manual/vlppos/using-threads.md index d9dc8ee8..f3c6f678 100644 --- a/.github/KnowledgeBase/manual/vlppos/using-threads.md +++ b/.github/KnowledgeBase/manual/vlppos/using-threads.md @@ -6,7 +6,7 @@ ## Thread and thread pool -**ThreadPoolLite**is always recommended to use whenever possible, instead of using**Thread**. Waiting for a thread to exit is a little bit tricky, it is much safer to use**EventObject**for this purpose. This is why you are not recommended to use**Thread**directly. +**ThreadPoolLite**is always recommended to use whenever possible, instead of using**Thread**. Waiting for a thread to exit is a little bit tricky, it is much safer to use**EventObject**for this purpose. This is why you are not recommended to use**Thread**directly. Use**TaskQueue**when work must be posted from multiple threads but executed in order on one blocking task loop. To start a background task, this is the easiest way: ```