diff --git a/reactos/ntoskrnl/ex/dbgctrl.c b/reactos/ntoskrnl/ex/dbgctrl.c index f3f25125a79..f72774e3220 100644 --- a/reactos/ntoskrnl/ex/dbgctrl.c +++ b/reactos/ntoskrnl/ex/dbgctrl.c @@ -16,7 +16,7 @@ // #ifdef _WINKD_ /* - * WinDBG Debugger Worker Thread data + * WinDBG Debugger Worker State Machine data */ WORK_QUEUE_ITEM ExpDebuggerWorkItem; /* @@ -33,19 +33,22 @@ ULONG_PTR ExpDebuggerPageIn; // #ifdef _WINKD_ /* - * WinDBG Debugger Worker Thread + * WinDBG Debugger Worker State Machine * - * A worker thread is queued whenever WinDBG wants to attach or kill a user-mode + * This functionality is used whenever WinDBG wants to attach or kill a user-mode * process from within live kernel-mode session, and/or page-in an address region. + * It is implemented as a state machine: when it is in "Ready" state, WinDBG can + * initialize the data for the state machine, then switch its state to "Start". + * The worker thread balance manager detects this, switches the state to "Initialized" + * and queues a worker thread. As long as the state is not "Ready" again, WinDBG + * prevents from requeuing a new thread. When the thread is started, it captures + * all the data, then resets the machine state to "Ready", thus allowing WinDBG + * to requeue another worker thread. * * WinDBG commands: * .process /i (where is the address of the EPROCESS block for this process) * .kill ( " " " " ) * .pagein (where is the address to page in) - * - * The implementation is very naive because the same data is reused, so that if - * the worker thread has not started before WinDBG sends fresh new data again, - * then only the latest data is taken into account. */ VOID NTAPI @@ -59,22 +62,25 @@ ExpDebuggerWorker(IN PVOID Context) UNREFERENCED_PARAMETER(Context); /* Be sure we were started in an initialized state */ - ASSERTMSG("ExpDebuggerWorker being entered with state != 2\n", + ASSERTMSG("ExpDebuggerWorker being entered in non-initialized state!\n", ExpDebuggerWork == WinKdWorkerInitialized); - if (ExpDebuggerWork != WinKdWorkerInitialized) return; - - /* Reset the worker flag to the disabled state */ - ExpDebuggerWork = WinKdWorkerDisabled; + if (ExpDebuggerWork != WinKdWorkerInitialized) + { + /* An error happened, so get a chance to restart proper */ + ExpDebuggerWork = WinKdWorkerReady; + return; + } /* Get the processes to be attached or killed, and the address to page in */ ProcessToAttach = ExpDebuggerProcessAttach; ProcessToKill = ExpDebuggerProcessKill; PageInAddress = ExpDebuggerPageIn; - /* Reset to their default values */ + /* Reset the state machine to its ready state */ ExpDebuggerProcessAttach = NULL; ExpDebuggerProcessKill = NULL; ExpDebuggerPageIn = (ULONG_PTR)NULL; + ExpDebuggerWork = WinKdWorkerReady; /* Default to the current process if we don't find the process to be attached or killed */ Process = NULL; diff --git a/reactos/ntoskrnl/ex/work.c b/reactos/ntoskrnl/ex/work.c index 7d27bbef294..fe5b27b2c7c 100644 --- a/reactos/ntoskrnl/ex/work.c +++ b/reactos/ntoskrnl/ex/work.c @@ -491,7 +491,7 @@ ExpWorkerThreadBalanceManager(IN PVOID Context) * If WinDBG wants to attach or kill a user-mode process, and/or * page-in an address region, queue a debugger worker thread. */ - if (ExpDebuggerWork == WinKdWorkerActivate) + if (ExpDebuggerWork == WinKdWorkerStart) { ExInitializeWorkItem(&ExpDebuggerWorkItem, ExpDebuggerWorker, NULL); ExpDebuggerWork = WinKdWorkerInitialized; diff --git a/reactos/ntoskrnl/include/internal/ex.h b/reactos/ntoskrnl/include/internal/ex.h index 59502f6ba59..3c08885de7f 100644 --- a/reactos/ntoskrnl/include/internal/ex.h +++ b/reactos/ntoskrnl/include/internal/ex.h @@ -44,12 +44,12 @@ extern CHAR NtBuildLab[]; // #ifdef _WINKD_ /* - * WinDBG Debugger Worker Thread data (see dbgctrl.c) + * WinDBG Debugger Worker State Machine data (see dbgctrl.c) */ typedef enum _WINKD_WORKER_STATE { - WinKdWorkerDisabled = 0, - WinKdWorkerActivate, + WinKdWorkerReady = 0, + WinKdWorkerStart, WinKdWorkerInitialized } WINKD_WORKER_STATE;