ReactOS 0.4.15-dev-8614-gbc76250
power.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Win32k subsystem
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Power management of the Win32 kernel-mode subsystem
5 * COPYRIGHT: Copyright 2024 George Bișoc <george.bisoc@reactos.org>
6 */
7
8/* INCLUDES ******************************************************************/
9
10#include <win32k.h>
11DBG_DEFAULT_CHANNEL(UserPowerManager);
12
13/* GLOBALS *******************************************************************/
14
19
20/* PRIVATE FUNCTIONS *********************************************************/
21
32static
33VOID
36{
37 PSPOWEREVENTTYPE PwrEventType;
38 ULONG Code;
39
40 /* Cache the power event parameters and handle the power callout */
41 PwrEventType = pParameters->EventNumber;
42 Code = pParameters->Code;
43 switch (PwrEventType)
44 {
45 case PsW32SystemTime:
46 {
47 /*
48 * The power manager of the kernel notified us of an impending
49 * time change, broadcast this notification to all present windows.
50 */
53 0,
54 0);
55 break;
56 }
57
58 default:
59 {
60 TRACE("Power event of type %d is currently UNIMPLEMENTED (code %lu)\n", PwrEventType, Code);
61 break;
62 }
63 }
64}
65
80static
84{
85 PSPOWEREVENTTYPE PwrEventType;
86
87 /* Capture the event number and check if it is within bounds */
88 PwrEventType = pParameters->EventNumber;
89 if (PwrEventType < PsW32FullWake || PwrEventType > PsW32MonitorOff)
90 {
91 TRACE("Unknown event number found -> %d\n", PwrEventType);
93 }
94
95 return STATUS_SUCCESS;
96}
97
119static
122 _In_ PWIN32POWERCALLOUT pPowerCallout)
123{
125 PWIN32POWERCALLOUT pPowerCalloutEntry = NULL;
126
127 /* Ensure the current calling thread owns the power callout lock */
129
130 /* This list is empty, acknowledge the caller */
132 {
133 return NULL;
134 }
135
136 /* The caller supplied a NULL argument, give them the first entry */
137 if (!pPowerCallout)
138 {
140 }
141 else
142 {
143 /* Otherwise give the caller the next power callout entry from the list */
144 Entry = pPowerCallout->Link.Flink;
145 }
146
147 /* Delist the power callout entry from the list and give it to caller */
148 pPowerCalloutEntry = CONTAINING_RECORD(Entry, WIN32POWERCALLOUT, Link);
149 RemoveEntryList(&pPowerCalloutEntry->Link);
150 return pPowerCalloutEntry;
151}
152
158static
159VOID
161{
162 PWIN32POWERCALLOUT pWin32PwrCallout;
163
164 /* Lock the entire USER subsystem down as we do particular stuff */
166
167 /*
168 * FIXME: While we did indeed lock the USER subsystem, there is a risk
169 * of the current calling thread might die or hang, so we should probably
170 * lock the thread while we deploy our power callout. The thread info
171 * provides a thread lock field for this purpose (see the ptl member from
172 * the _THREADINFO structure) but ReactOS lacks implementation to handle
173 * this. Suppose a thread happens to get into this fate, the power callout
174 * would never get signaled...
175 */
176
177 /* Deploy all the pending power callouts to the appropriate callout workers */
179 for (pWin32PwrCallout = IntGetNextPowerCallout(NULL);
180 pWin32PwrCallout != NULL;
181 pWin32PwrCallout = IntGetNextPowerCallout(pWin32PwrCallout))
182 {
183 if (pWin32PwrCallout->Type == POWER_CALLOUT_EVENT)
184 {
185 IntHandlePowerEventWorker(&pWin32PwrCallout->Params);
186 }
187 else // POWER_CALLOUT_STATE
188 {
189 ERR("Power state callout management is currently not implemented!\n");
190 }
191
192 /* We are done with this power callout */
193 ExFreePoolWithTag(pWin32PwrCallout, USERTAG_POWER);
194 }
195
196 /* Release what we locked */
198 UserLeave();
199}
200
210static
211VOID
213 _In_ PWIN32POWERCALLOUT pPowerCallout)
214{
215 PETHREAD CurrentThread;
216
217 /* Enlist it to the queue already */
219 InsertTailList(&gPowerCalloutsQueueList, &pPowerCallout->Link);
221
222 /*
223 * We have to let CSRSS process this power callout if one of the
224 * following conditions is TRUE for the current calling thread:
225 *
226 * - The process of the calling thread is a system process;
227 * - The process of the calling thread is attached;
228 * - The current calling thread is not a Win32 thread.
229 *
230 * For the second point, we cannot process the power callout ourselves
231 * as we must lock down USER exclusively for our own purpose, which requires
232 * us to be in a critical section. So we do not want to fiddle with a process
233 * that is attached with others.
234 */
235 CurrentThread = PsGetCurrentThread();
236 if (PsIsSystemThread(CurrentThread) ||
238 !IntIsThreadWin32Thread(CurrentThread))
239 {
240 /* Alert CSRSS of the presence of an enqueued power callout */
242 return;
243 }
244
245 /* Handle this power callout ourselves */
247}
248
249/* PUBLIC FUNCTIONS **********************************************************/
250
270NTAPI
272 _In_ HANDLE hPowerRequestEvent)
273{
275
276 /* Allocate memory pool for the power callout mutex */
278 sizeof(FAST_MUTEX),
281 {
282 ERR("Failed to allocate pool of memory for the power callout mutex\n");
284 }
285
286 /* Initialize the mutex and owner thread */
289
290 /* Initialize the global queue list and the power callout (aka request) event object */
292 Status = ObReferenceObjectByHandle(hPowerRequestEvent,
297 NULL);
298 if (!NT_SUCCESS(Status))
299 {
300 ERR("Failed to reference the power callout event handle (Status 0x%08lx)\n", Status);
302 return Status;
303 }
304
305 return STATUS_SUCCESS;
306}
307
314NTAPI
316{
317 PWIN32POWERCALLOUT pWin32PwrCallout;
318
319 /* Dereference the power request event */
322
323 /*
324 * Enumerate all pending power callouts and free them. We do not
325 * need to do this with the lock held as the CSR process is tore
326 * apart during Win32k cleanup, so future power callouts would not
327 * be allowed anyway, therefore we are safe.
328 */
329 for (pWin32PwrCallout = IntGetNextPowerCallout(NULL);
330 pWin32PwrCallout != NULL;
331 pWin32PwrCallout = IntGetNextPowerCallout(pWin32PwrCallout))
332 {
333 ExFreePoolWithTag(pWin32PwrCallout, USERTAG_POWER);
334 }
335
336 /* Tear apart the power callout lock mutex */
339 return STATUS_SUCCESS;
340}
341
361NTAPI
363 _In_ PWIN32_POWEREVENT_PARAMETERS pWin32PwrEventParams)
364{
365 PWIN32POWERCALLOUT pWin32PwrCallout;
367
368 /*
369 * CSRSS is not running. As a consequence, the USER subsystem is neither
370 * up and running as the Client/Server subsystem is responsible to fire
371 * up other subsystems. Another case is that the system undergoes shutdown
372 * and Win32k cleanup is currently in effect. Either way, just quit.
373 */
374 if (!gpepCSRSS)
375 {
376 TRACE("CSRSS is not running, bailing out\n");
377 return STATUS_UNSUCCESSFUL;
378 }
379
380 /* Validate the power event parameters, just to be sure we have not gotten anything else */
381 Status = IntValidateWin32PowerParams(pWin32PwrEventParams);
382 if (!NT_SUCCESS(Status))
383 {
384 ERR("Could not deploy power callout, invalid Win32 power parameters!\n");
385 return Status;
386 }
387
388 /* Allocate pool of memory for this power callout */
389 pWin32PwrCallout = ExAllocatePoolZero(NonPagedPool,
390 sizeof(WIN32POWERCALLOUT),
392 if (pWin32PwrCallout == NULL)
393 {
394 ERR("Allocating memory for Win32 power callout failed\n");
396 }
397
398 /* Fill the necessary power datum */
399 pWin32PwrCallout->Type = POWER_CALLOUT_EVENT;
400 pWin32PwrCallout->Params.EventNumber = pWin32PwrEventParams->EventNumber;
401 pWin32PwrCallout->Params.Code = pWin32PwrEventParams->Code;
402
403 /* Enqueue this power request for later processing */
404 IntEnlistPowerCallout(pWin32PwrCallout);
405 return STATUS_SUCCESS;
406}
407
418NTAPI
420 _In_ PWIN32_POWERSTATE_PARAMETERS pWin32PwrStateParams)
421{
422 /* FIXME */
423 ERR("IntHandlePowerState is UNIMPLEMENTED\n");
425}
426
427/* EOF */
LONG NTSTATUS
Definition: precomp.h:26
#define ERR(fmt,...)
Definition: precomp.h:57
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
PEPROCESS gpepCSRSS
Definition: csr.c:15
#define Code
Definition: deflate.h:80
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define NonPagedPool
Definition: env_spec_w32.h:307
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
Status
Definition: gdiplustypes.h:25
@ PsW32MonitorOff
Definition: pstypes.h:458
@ PsW32SystemTime
Definition: pstypes.h:450
enum _PSPOWEREVENTTYPE PSPOWEREVENTTYPE
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
FORCEINLINE PVOID ExAllocatePoolZero(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
Definition: precomp.h:45
#define _In_
Definition: ms_sal.h:308
#define KernelMode
Definition: asm.h:34
POBJECT_TYPE ExEventObjectType
Definition: event.c:18
BOOLEAN NTAPI PsIsSystemThread(IN PETHREAD Thread)
Definition: thread.c:878
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
VOID FASTCALL UserLeave(VOID)
Definition: ntuser.c:258
VOID FASTCALL UserEnterExclusive(VOID)
Definition: ntuser.c:249
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
@ POWER_CALLOUT_EVENT
Definition: power.h:15
#define ASSERT_POWER_CALLOUT_LOCK_ACQUIRED()
Definition: power.h:40
FORCEINLINE VOID IntReleasePowerCalloutLock(VOID)
Definition: power.h:87
FORCEINLINE BOOL IntIsThreadWin32Thread(_In_ PETHREAD Thread)
Definition: power.h:99
FORCEINLINE VOID IntAcquirePowerCalloutLock(VOID)
Definition: power.h:78
BOOLEAN NTAPI KeIsAttachedProcess(VOID)
Definition: procobj.c:693
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE(s)
Definition: solgame.cpp:4
base of all file and directory entries
Definition: entries.h:83
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
PSPOWEREVENTTYPE EventNumber
Definition: pstypes.h:1616
POWER_CALLOUT_TYPE Type
Definition: power.h:31
LIST_ENTRY Link
Definition: power.h:25
WIN32_POWEREVENT_PARAMETERS Params
Definition: power.h:34
#define NTAPI
Definition: typedefs.h:36
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
static int Link(const char **args)
Definition: vfdcmd.c:2414
_In_ UCHAR _In_ UCHAR _In_ ULONG Code
Definition: wdfdevice.h:1701
BOOL FASTCALL UserSendNotifyMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
Definition: message.c:2090
static PWIN32POWERCALLOUT IntGetNextPowerCallout(_In_ PWIN32POWERCALLOUT pPowerCallout)
Gets the next pending power callout from the global queue list and returns it to the caller....
Definition: power.c:121
LIST_ENTRY gPowerCalloutsQueueList
Definition: power.c:15
PFAST_MUTEX gpPowerCalloutMutexLock
Definition: power.c:16
static VOID IntEnlistPowerCallout(_In_ PWIN32POWERCALLOUT pPowerCallout)
Enlists a newly allocated power callout into the queue list for later processing.
Definition: power.c:212
NTSTATUS NTAPI IntWin32PowerManagementCleanup(VOID)
Cleanup procedure that frees all the allocated resources by the power manager. It is triggered during...
Definition: power.c:315
static VOID IntHandlePowerEventWorker(_In_ PWIN32_POWEREVENT_PARAMETERS pParameters)
Handles a power event as a result from an incoming power callout from the kernel power manager.
Definition: power.c:34
NTSTATUS NTAPI IntHandlePowerState(_In_ PWIN32_POWERSTATE_PARAMETERS pWin32PwrStateParams)
Handles an incoming power state callout from the NT power manager.
Definition: power.c:419
NTSTATUS NTAPI IntInitWin32PowerManagement(_In_ HANDLE hPowerRequestEvent)
Initializes the power management side of Win32 kernel-mode subsystem component. This enables communic...
Definition: power.c:271
static NTSTATUS IntValidateWin32PowerParams(_In_ PWIN32_POWEREVENT_PARAMETERS pParameters)
Validates the power event parameters that come from a power callout from the kernel power manager.
Definition: power.c:82
static VOID IntDeployPowerCallout(VOID)
Deploys all pending power callouts to appropriate power callout workers.
Definition: power.c:160
NTSTATUS NTAPI IntHandlePowerEvent(_In_ PWIN32_POWEREVENT_PARAMETERS pWin32PwrEventParams)
Handles an incoming power event callout from the NT power manager.
Definition: power.c:362
PKTHREAD gpPowerCalloutMutexOwnerThread
Definition: power.c:18
PKEVENT gpPowerRequestCalloutEvent
Definition: power.c:17
#define USERTAG_POWER
Definition: tags.h:263
#define HWND_BROADCAST
Definition: winuser.h:1207
#define WM_TIMECHANGE
Definition: winuser.h:1637
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
* PFAST_MUTEX
Definition: extypes.h:17
FAST_MUTEX
Definition: extypes.h:17
#define EVENT_INCREMENT
Definition: iotypes.h:597
#define ObDereferenceObject
Definition: obfuncs.h:203