Based on a patch by Qian Hong.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44812 Signed-off-by: Gijs Vermeulen gijsvrm@gmail.com
Refer to !5269
From: Vijay Kiran Kamuju infyquest@gmail.com
Based on a patch by Qian Hong.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44812 Signed-off-by: Gijs Vermeulen gijsvrm@gmail.com --- dlls/ntdll/unix/process.c | 30 +++++++++++++++++++++++++++++- dlls/wow64/process.c | 24 ++++++++++++++++++++++++ dlls/wow64/struct32.h | 10 ++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index 2c6dc1b43cc..09e38572cf2 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1124,7 +1124,6 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
switch (class) { - UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits); UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority); UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority); UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort); @@ -1580,6 +1579,35 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class else ret = STATUS_INVALID_PARAMETER; break;
+ case ProcessQuotaLimits: + { + QUOTA_LIMITS qlimits; + + FIXME( "ProcessQuotaLimits (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len ); + + len = sizeof(QUOTA_LIMITS); + if (size == len) + { + if (!info || !handle) ret = STATUS_INVALID_HANDLE; + else + { + /* FIXME: SetProcessWorkingSetSize can also set the quota values. + Quota Limits should be stored inside the process. */ + qlimits.PagedPoolLimit = (SIZE_T)-1; + qlimits.NonPagedPoolLimit = (SIZE_T)-1; + /* Default minimum working set size is 204800 bytes (50 Pages) */ + qlimits.MinimumWorkingSetSize = 204800; + /* Default maximum working set size is 1413120 bytes (345 Pages) */ + qlimits.MaximumWorkingSetSize = 1413120; + qlimits.PagefileLimit = (SIZE_T)-1; + qlimits.TimeLimit.QuadPart = -1; + memcpy(info, &qlimits, len); + } + } + else ret = STATUS_INFO_LENGTH_MISMATCH; + break; + } + default: FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n", handle, class, info, (int)size, ret_len ); diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index 8b543d2a859..359f0d398eb 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -252,6 +252,15 @@ static void put_ps_attributes( PS_ATTRIBUTE_LIST32 *attr32, const PS_ATTRIBUTE_L } }
+void put_quota_limits( QUOTA_LIMITS32 *info32, const QUOTA_LIMITS *info ) +{ + info32->PagedPoolLimit = info->PagedPoolLimit; + info32->NonPagedPoolLimit = info->NonPagedPoolLimit; + info32->MinimumWorkingSetSize = info->MinimumWorkingSetSize; + info32->MaximumWorkingSetSize = info->MaximumWorkingSetSize; + info32->PagefileLimit = info->PagefileLimit; + info32->TimeLimit = info->TimeLimit; +}
void put_vm_counters( VM_COUNTERS_EX32 *info32, const VM_COUNTERS_EX *info, ULONG size ) { @@ -566,6 +575,21 @@ NTSTATUS WINAPI wow64_NtQueryInformationProcess( UINT *args ) /* FIXME: check buffer alignment */ return NtQueryInformationProcess( handle, class, ptr, len, retlen );
+ case ProcessQuotaLimits: /* QUOTA_LIMITS */ + if (len == sizeof(QUOTA_LIMITS32)) + { + QUOTA_LIMITS info; + QUOTA_LIMITS32 *info32 = ptr; + if (!(status = NtQueryInformationProcess( handle, class, &info, sizeof(info), NULL ))) + { + put_quota_limits( info32, &info ); + if (retlen) *retlen = len; + } + return status; + } + if (retlen) *retlen = sizeof(QUOTA_LIMITS32); + return STATUS_INFO_LENGTH_MISMATCH; + case ProcessVmCounters: /* VM_COUNTERS_EX */ if (len == sizeof(VM_COUNTERS32) || len == sizeof(VM_COUNTERS_EX32)) { diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index 2c4cf4f9e3c..9535fba3a84 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -728,4 +728,14 @@ typedef struct ULONG Thread; } PROCESS_ACCESS_TOKEN32;
+typedef struct +{ + ULONG PagedPoolLimit; + ULONG NonPagedPoolLimit; + ULONG MinimumWorkingSetSize; + ULONG MaximumWorkingSetSize; + ULONG PagefileLimit; + LARGE_INTEGER TimeLimit; +} QUOTA_LIMITS32; + #endif /* __WOW64_STRUCT32_H */
From: Vijay Kiran Kamuju infyquest@gmail.com
Signed-off-by: Gijs Vermeulen gijsvrm@gmail.com --- dlls/ntdll/tests/info.c | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 6771bbe4e3f..6151bb02800 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -2677,6 +2677,59 @@ static void test_query_process_debug_flags(int argc, char **argv) } }
+static void test_query_process_quota_limits(void) +{ + QUOTA_LIMITS qlimits; + NTSTATUS status; + HANDLE process; + ULONG ret_len; + + status = NtQueryInformationProcess(NULL, ProcessQuotaLimits, NULL, sizeof(qlimits), NULL); + ok(status == STATUS_INVALID_HANDLE, "NtQueryInformationProcess failed, status %#lx.\n", status); + + status = NtQueryInformationProcess(NULL, ProcessQuotaLimits, &qlimits, sizeof(qlimits), NULL); + ok(status == STATUS_INVALID_HANDLE, "NtQueryInformationProcess failed, status %#lx.\n", status); + + process = GetCurrentProcess(); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, 2, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits), &ret_len); + ok(status == STATUS_SUCCESS, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); + ok(qlimits.MinimumWorkingSetSize == 204800,"Expected MinimumWorkingSetSize = 204800, got %s\n", + wine_dbgstr_longlong(qlimits.MinimumWorkingSetSize)); + ok(qlimits.MaximumWorkingSetSize == 1413120,"Expected MaximumWorkingSetSize = 1413120, got %s\n", + wine_dbgstr_longlong(qlimits.MaximumWorkingSetSize)); + ok(qlimits.PagefileLimit == ~0,"Expected PagefileLimit = ~0, got %s\n", + wine_dbgstr_longlong(qlimits.PagefileLimit)); + ok(qlimits.TimeLimit.QuadPart == ~0,"Expected TimeLimit = ~0, got %s\n", + wine_dbgstr_longlong(qlimits.TimeLimit.QuadPart)); + + if (winetest_debug > 1) + { + trace("Quota Limits:\n"); + trace("PagedPoolLimit: %s\n", wine_dbgstr_longlong(qlimits.PagedPoolLimit)); + trace("NonPagedPoolLimit: %s\n", wine_dbgstr_longlong(qlimits.NonPagedPoolLimit)); + } + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits) * 2, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits) - 1, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits) + 1, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); +} + static void test_readvirtualmemory(void) { HANDLE process; @@ -3886,6 +3939,7 @@ START_TEST(info) test_query_process_debug_object_handle(argc, argv); test_query_process_debug_flags(argc, argv); test_query_process_image_info(); + test_query_process_quota_limits(); test_mapprotection(); test_threadstack();
This merge request was approved by Gijs Vermeulen.
Unless an app relies on *these* specific values, I think it makes more sense to maintain consistency across APIs.
You have two options:
**Option 1: Make GetProcessWorkingSetSizeEx() a wrapper that calls NtQueryInformationProcess(ProcessQuotaLimits).** I prefer this option, since we don't have to break any tests.
**Option 2: Make ProcessQuotaLimits consistent with GetProcessWorkingSetSizeEx().** This will need some `todo_wine` in the newly introduced tests, but needs no further work other than:
```suggestion:-3+0 /* 32 MB working set size (see GetProcessWorkingSetSizeEx) */ qlimits.MinimumWorkingSetSize = 32*1024*1024; qlimits.MaximumWorkingSetSize = 32*1024*1024; ```
On Mon Apr 15 12:40:06 2024 +0000, Jinoh Kang wrote:
Unless an app relies on *these* specific values, I think it makes more sense to maintain consistency across APIs. You have two options: **Option 1: Make GetProcessWorkingSetSizeEx() a wrapper that calls NtQueryInformationProcess(ProcessQuotaLimits).** I prefer this option, since we don't have to break any tests. **Option 2: Make ProcessQuotaLimits consistent with GetProcessWorkingSetSizeEx().** This will need some `todo_wine` in the newly introduced tests, but needs no further work other than:
/* 32 MB working set size (see GetProcessWorkingSetSizeEx) */ qlimits.MinimumWorkingSetSize = 32*1024*1024; qlimits.MaximumWorkingSetSize = 32*1024*1024;
I would go with option 1, but this needs QUOTA_LIMITS_EX implementation. That might need to wait after this patch.
On Mon Apr 15 12:40:06 2024 +0000, Vijay Kiran Kamuju wrote:
I would go with option 1, but this needs QUOTA_LIMITS_EX implementation. That might need to wait after this patch.
Then what about option 2?
On Mon Apr 15 12:40:06 2024 +0000, Jinoh Kang wrote:
Then what about option 2?
I probably will have to write some tests to verify the exact values the windows 10/11 throws for GetProcessWorkingSetSizeEx.
update: I have tested it, it returns 204800 for minsize and 1413120 for maxsize, I dont know why we are returning incorrect value of 32 x 1024 x 1024.
On Mon Apr 15 12:40:06 2024 +0000, Vijay Kiran Kamuju wrote:
I probably will have to write some tests to verify the exact values the windows 10/11 throws for GetProcessWorkingSetSizeEx. update: I have tested it, it returns 204800 for minsize and 1413120 for maxsize, I dont know why we are returning incorrect value of 32 x 1024 x 1024.
I'd assume that `32*1024*1024` was just a dummy value, and it stayed that way for decades because no app cared about the exact value. Going back to my original comment, do you have an app that relies on *these* specific values (204800, 1413120)?
On Mon Apr 15 12:40:06 2024 +0000, Jinoh Kang wrote:
I'd assume that `32*1024*1024` was just a dummy value, and it stayed that way for decades because no app cared about the exact value. Going back to my original comment, do you have an app that relies on *these* specific values (204800, 1413120)?
Oh, I didn't notice the FIXME. Yeah, since we clearly indicate a stub, we don't need to provide a consistent view like native Windows does, I think.