Cygwin: get/setrlimit: move RLIMIT_AS handling into static functions

To keep getrlimit/setrlimit clean, move the RLIMIT_AS code into
local static functions __set_rlimit_as and __get_rlimit_as.

Also, make adding process to the job the last step, to be able to
close and release the job resources if anything failed.  Add matching
comment.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2021-11-30 12:54:03 +01:00
parent 670beaed02
commit 3edea7cd55
1 changed files with 84 additions and 73 deletions

View File

@ -174,6 +174,87 @@ job_shared_name (PWCHAR buf, LONG num)
return buf;
}
static void
__get_rlimit_as (struct rlimit *rlp)
{
UNICODE_STRING uname;
WCHAR jobname[32];
OBJECT_ATTRIBUTES attr;
HANDLE job = NULL;
NTSTATUS status;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobinfo;
if (cygheap->rlim_as_id)
{
RtlInitUnicodeString (&uname,
job_shared_name (jobname,
cygheap->rlim_as_id));
InitializeObjectAttributes (&attr, &uname, 0,
get_session_parent_dir (), NULL);
/* May fail, just check NULL job in that case. */
NtOpenJobObject (&job, JOB_OBJECT_QUERY, &attr);
}
status = NtQueryInformationJobObject (job,
JobObjectExtendedLimitInformation,
&jobinfo, sizeof jobinfo, NULL);
if (NT_SUCCESS (status)
&& (jobinfo.BasicLimitInformation.LimitFlags
& JOB_OBJECT_LIMIT_PROCESS_MEMORY))
rlp->rlim_cur = rlp->rlim_max = jobinfo.ProcessMemoryLimit;
if (job)
NtClose (job);
}
static int
__set_rlimit_as (unsigned long new_as_limit)
{
LONG new_as_id = 0;
UNICODE_STRING uname;
WCHAR jobname[32];
OBJECT_ATTRIBUTES attr;
NTSTATUS status = STATUS_SUCCESS;
HANDLE job = NULL;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobinfo = { 0 };
/* If we already have a limit, we must not change it because that
would potentially influence already running child processes.
Just try to create another, nested job. On systems prior to
Windows 8 / Server 2012 this will fail, but that's ok. */
while (new_as_id == 0)
new_as_id = InterlockedIncrement (&job_serial_number);
RtlInitUnicodeString (&uname,
job_shared_name (jobname, new_as_id));
InitializeObjectAttributes (&attr, &uname, 0,
get_session_parent_dir (), NULL);
status = NtCreateJobObject (&job, JOB_OBJECT_ALL_ACCESS, &attr);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
return -1;
}
jobinfo.BasicLimitInformation.LimitFlags
= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
/* Per Linux man page, round down to system pagesize. */
jobinfo.ProcessMemoryLimit
= rounddown (new_as_limit, wincap.allocation_granularity ());
status = NtSetInformationJobObject (job,
JobObjectExtendedLimitInformation,
&jobinfo, sizeof jobinfo);
/* If creating the job and setting up the job limits succeeded,
try to add the process to the job. This must be the last step,
otherwise we couldn't remove the job if anything failed. */
if (NT_SUCCESS (status))
status = NtAssignProcessToJobObject (job, NtCurrentProcess ());
NtClose (job);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
return -1;
}
cygheap->rlim_as_id = new_as_id;
return 0;
}
extern "C" int
getrlimit (int resource, struct rlimit *rlp)
{
@ -189,34 +270,7 @@ getrlimit (int resource, struct rlimit *rlp)
case RLIMIT_DATA:
break;
case RLIMIT_AS:
{
UNICODE_STRING uname;
WCHAR jobname[32];
OBJECT_ATTRIBUTES attr;
HANDLE job = NULL;
NTSTATUS status;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobinfo;
if (cygheap->rlim_as_id)
{
RtlInitUnicodeString (&uname,
job_shared_name (jobname,
cygheap->rlim_as_id));
InitializeObjectAttributes (&attr, &uname, 0,
get_session_parent_dir (), NULL);
/* May fail, just check NULL job in that case. */
NtOpenJobObject (&job, JOB_OBJECT_QUERY, &attr);
}
status = NtQueryInformationJobObject (job,
JobObjectExtendedLimitInformation,
&jobinfo, sizeof jobinfo, NULL);
if (!NT_SUCCESS (status))
break;
if (jobinfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_PROCESS_MEMORY)
rlp->rlim_cur = rlp->rlim_max = jobinfo.ProcessMemoryLimit;
if (job)
NtClose (job);
}
__get_rlimit_as (rlp);
break;
case RLIMIT_STACK:
__get_rlimit_stack (rlp);
@ -270,51 +324,8 @@ setrlimit (int resource, const struct rlimit *rlp)
switch (resource)
{
case RLIMIT_AS:
{
LONG new_as_id = 0;
UNICODE_STRING uname;
WCHAR jobname[32];
OBJECT_ATTRIBUTES attr;
NTSTATUS status = STATUS_SUCCESS;
HANDLE job = NULL;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobinfo = { 0 };
/* If we already have a limit, we must not change it because that
would potentially influence already running child processes.
Just try to create another, nested job. On systems prior to
Windows 8 / Server 2012 this will fail, but that's ok. */
while (new_as_id == 0)
new_as_id = InterlockedIncrement (&job_serial_number);
RtlInitUnicodeString (&uname,
job_shared_name (jobname, new_as_id));
InitializeObjectAttributes (&attr, &uname, 0,
get_session_parent_dir (), NULL);
status = NtCreateJobObject (&job, JOB_OBJECT_ALL_ACCESS, &attr);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
__leave;
}
status = NtAssignProcessToJobObject (job, NtCurrentProcess ());
if (NT_SUCCESS (status))
{
jobinfo.BasicLimitInformation.LimitFlags
= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
/* Per Linux man page, round down to system pagesize. */
jobinfo.ProcessMemoryLimit
= rounddown (rlp->rlim_cur, wincap.allocation_granularity ());
status = NtSetInformationJobObject (job,
JobObjectExtendedLimitInformation,
&jobinfo, sizeof jobinfo);
}
NtClose (job);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
__leave;
}
cygheap->rlim_as_id = new_as_id;
}
if (rlp->rlim_cur != RLIM_INFINITY)
return __set_rlimit_as (rlp->rlim_cur);
break;
case RLIMIT_CORE:
cygheap->rlim_core = rlp->rlim_cur;