mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-03 07:23:20 +00:00

Many Microsoft employees have contributed to the Windows Subsystem for Linux, this commit is the result of their work since 2016. The entire history of the Windows Subsystem for Linux can't be shared here, but here's an overview of WSL's history after it moved to it own repository in 2021: Number of commits on the main branch: 2930 Number of contributors: 31 Head over https://github.com/microsoft/WSL/releases for a more detailed history of the features added to WSL since 2021.
512 lines
14 KiB
C
512 lines
14 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
Ioprio.c
|
|
|
|
Abstract:
|
|
|
|
This file is a ioprio test.
|
|
|
|
--*/
|
|
|
|
#include "lxtcommon.h"
|
|
#include "unittests.h"
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/prctl.h>
|
|
#include "lxtutil.h"
|
|
|
|
#if !defined(__amd64__) && !defined(__aarch64__)
|
|
|
|
#include <sys/capability.h>
|
|
|
|
#else
|
|
|
|
#include <sys/cdefs.h>
|
|
#include <linux/capability.h>
|
|
|
|
#define _LINUX_CAPABILITY_VERSION_3 0x20080522
|
|
|
|
#ifndef O_PATH
|
|
#define O_PATH 010000000
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#define IOPRIO_UID 1007
|
|
#define IOPRIO_GID 1007
|
|
|
|
//
|
|
// When the ioprio.h header is available, these types can be removed.
|
|
//
|
|
|
|
#define LX_IOPRIO_WHO_PROCESS 1
|
|
#define LX_IOPRIO_WHO_PGRP 2
|
|
#define LX_IOPRIO_WHO_USER 3
|
|
|
|
#define LX_IOPRIO_CLASS_NONE 0
|
|
#define LX_IOPRIO_CLASS_RT 1
|
|
#define LX_IOPRIO_CLASS_BE 2
|
|
#define LX_IOPRIO_CLASS_IDLE 3
|
|
|
|
#define LX_IOPRIO_CLASS_SHIFT 13
|
|
#define LX_IOPRIO_PRIO_MASK ((1 << LX_IOPRIO_CLASS_SHIFT) - 1)
|
|
#define LX_IOPRIO_PRIO_CLASS(_mask) ((_mask) >> LX_IOPRIO_CLASS_SHIFT)
|
|
#define LX_IOPRIO_PRIO_DATA(_mask) ((_mask) & LX_IOPRIO_PRIO_MASK)
|
|
#define LX_IOPRIO_PRIO_VALUE(_class, _data) (((_class) << LX_IOPRIO_CLASS_SHIFT) | (_data))
|
|
#define LX_IO_DEFAULT_PRIORITY 4
|
|
|
|
#define LXT_NAME "Ioprio"
|
|
|
|
int IoprioVariationGetProcess(PLXT_ARGS Args);
|
|
|
|
int IoprioVariationSetProcess(PLXT_ARGS Args);
|
|
|
|
int IoprioVariationGetSetPriority(PLXT_ARGS Args);
|
|
|
|
//
|
|
// Global constants
|
|
//
|
|
|
|
static const LXT_VARIATION g_LxtVariations[] = {
|
|
{"ioprio_get process", IoprioVariationGetProcess},
|
|
{"getpriority / setpriority", IoprioVariationGetSetPriority},
|
|
{"ioprio_set process", IoprioVariationSetProcess}};
|
|
|
|
int IoprioTestEntry(int Argc, char* Argv[])
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
LXT_ARGS Args;
|
|
int Result;
|
|
|
|
LxtInitialize(Argc, Argv, &Args, LXT_NAME);
|
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
|
|
|
ErrorExit:
|
|
LxtUninitialize();
|
|
return !LXT_SUCCESS(Result);
|
|
}
|
|
|
|
int IoprioVariationGetProcess(PLXT_ARGS Args)
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
int DefaultPriority;
|
|
int IoPrio;
|
|
int Result;
|
|
|
|
//
|
|
// Negative variations.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, -1), ESRCH);
|
|
LxtCheckErrnoFailure(IoPrio = LxtIoprio_get(0, 0), EINVAL);
|
|
|
|
//
|
|
// Get the default priority for the current and parent thread.
|
|
//
|
|
|
|
LxtCheckErrno(DefaultPriority = getpriority(PRIO_PROCESS, 0));
|
|
LxtLogInfo("DefaultPriority: %d", DefaultPriority);
|
|
LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckEqual(IoPrio, LX_IO_DEFAULT_PRIORITY, "%d");
|
|
LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, getpid()));
|
|
LxtCheckEqual(IoPrio, LX_IO_DEFAULT_PRIORITY, "%d");
|
|
LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, getppid()));
|
|
LxtCheckEqual(IoPrio, LX_IO_DEFAULT_PRIORITY, "%d");
|
|
|
|
//
|
|
// Set the priority of the current thread and check that it does not change
|
|
// the io priority.
|
|
//
|
|
|
|
LxtCheckErrno(setpriority(PRIO_PROCESS, 0, LX_IO_DEFAULT_PRIORITY + 1));
|
|
LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckNotEqual(IoPrio, LX_IO_DEFAULT_PRIORITY + 1, "%d");
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
setpriority(PRIO_PROCESS, 0, LX_IO_DEFAULT_PRIORITY);
|
|
return Result;
|
|
}
|
|
|
|
int IoprioVariationSetProcess(PLXT_ARGS Args)
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
struct __user_cap_data_struct CapData[2];
|
|
struct __user_cap_header_struct CapHeader;
|
|
int ChildPid;
|
|
int DefaultPriority;
|
|
int Index;
|
|
int InitialIoPrio;
|
|
int IoPrio;
|
|
int NewIoPrio;
|
|
int Result;
|
|
|
|
ChildPid = -1;
|
|
|
|
//
|
|
// Get the default priority for the current and parent thread.
|
|
//
|
|
// N.B. Setting the IO priority to this default value fails.
|
|
//
|
|
|
|
LxtCheckErrno(InitialIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtLogInfo("InitialIoPrio = %d", InitialIoPrio);
|
|
IoPrio = InitialIoPrio;
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
|
|
//
|
|
// LX_IOPRIO_CLASS_NONE
|
|
//
|
|
|
|
for (Index = 0; Index < 1; Index += 1)
|
|
{
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, Index);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
|
|
LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckEqual(IoPrio, NewIoPrio, "%d");
|
|
}
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, Index);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
|
|
//
|
|
// LX_IOPRIO_CLASS_RT
|
|
//
|
|
|
|
for (Index = 0; Index < 8; Index += 1)
|
|
{
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
|
|
LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckEqual(IoPrio, NewIoPrio, "%d");
|
|
}
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
|
|
//
|
|
// LX_IOPRIO_CLASS_BE
|
|
//
|
|
|
|
for (Index = 0; Index < 8; Index += 1)
|
|
{
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
|
|
LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckEqual(IoPrio, NewIoPrio, "%d");
|
|
}
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
|
|
//
|
|
// LX_IOPRIO_CLASS_IDLE
|
|
//
|
|
|
|
for (Index = 0; Index < 0x8000; Index += 1)
|
|
{
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_IDLE, Index);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
|
|
LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckEqual(IoPrio, NewIoPrio, "%d");
|
|
}
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_IDLE, Index);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, getppid(), IoPrio));
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SYS_ADMIN)].permitted |= CAP_TO_MASK(CAP_SYS_ADMIN);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
|
|
//
|
|
// Drop all privileges but CAP_SYS_ADMIN.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
LxtCheckErrno(setgid(IOPRIO_UID));
|
|
LxtCheckErrno(setuid(IOPRIO_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
|
|
//
|
|
// Attempt to change parent's io priority now that UID / GID do not match.
|
|
//
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, getppid(), IoPrio), EPERM);
|
|
|
|
for (Index = 0; Index < 8; Index += 1)
|
|
{
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
|
|
LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckEqual(IoPrio, NewIoPrio, "%d");
|
|
}
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
|
|
//
|
|
// Drop all privileges.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, 0);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EPERM);
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, 8);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EPERM);
|
|
|
|
//
|
|
// LX_IOPRIO_CLASS_NONE
|
|
//
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 1);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
|
|
//
|
|
// LX_IOPRIO_CLASS_BE
|
|
//
|
|
|
|
for (Index = 0; Index < 8; Index += 1)
|
|
{
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
|
|
LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
|
|
LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
|
|
LxtCheckEqual(IoPrio, NewIoPrio, "%d");
|
|
}
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Negative variations.
|
|
//
|
|
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, -1, IoPrio), ESRCH);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(0, 0, IoPrio), EINVAL);
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_IDLE + 1, 0);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(-1, 0);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(0, 0, IoPrio), EINVAL);
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, 0, IoPrio), EINVAL);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, -1, IoPrio), EINVAL);
|
|
IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 1);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, 0, IoPrio), EINVAL);
|
|
LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, -1, IoPrio), EINVAL);
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int IoprioSetPriority(int Which, int Who, int Priority, int ExpectedPriority)
|
|
|
|
{
|
|
|
|
int Result;
|
|
|
|
LxtCheckErrno(setpriority(Which, Who, Priority));
|
|
errno = 0;
|
|
Result = getpriority(Which, Who);
|
|
if ((Result != ExpectedPriority) || (errno != 0))
|
|
{
|
|
LxtLogError("getpriority returned %d expected %d - errno %d", Result, ExpectedPriority, errno);
|
|
|
|
Result = LXT_RESULT_FAILURE;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
return Result;
|
|
}
|
|
|
|
int IoprioVariationGetSetPriority(PLXT_ARGS Args)
|
|
|
|
{
|
|
int ChildPid;
|
|
int OriginalPriority;
|
|
pid_t ParentPid;
|
|
int Result;
|
|
struct rlimit Rlimit;
|
|
|
|
ChildPid = -1;
|
|
errno = 0;
|
|
OriginalPriority = getpriority(PRIO_PROCESS, 0);
|
|
LxtLogInfo("OriginalPriority %d", OriginalPriority);
|
|
|
|
//
|
|
// Validate setting the priority to a negative number.
|
|
//
|
|
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -1, -1));
|
|
|
|
//
|
|
// Validate setting the priority to a positive number.
|
|
//
|
|
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 5, 5));
|
|
|
|
//
|
|
// Validate the lower bound of the priority (-20).
|
|
//
|
|
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -20, -20));
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -21, -20));
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -444, -20));
|
|
|
|
//
|
|
// Validate the upper bound of the priority (19).
|
|
//
|
|
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 19, 19));
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 20, 19));
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 444, 19));
|
|
|
|
//
|
|
// Invalid parameter variations.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(getpriority(-1, 0), EINVAL);
|
|
|
|
//
|
|
// Permissions checks. Reset the priority to a known value.
|
|
//
|
|
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 5, 5));
|
|
ParentPid = getpid();
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Change the UID to drop CAP_SYS_NICE and verify that the priority can
|
|
// be set to the same value.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(1000));
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 5, 5));
|
|
|
|
//
|
|
// Attempt to lower the priority.
|
|
//
|
|
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 6, 6));
|
|
|
|
//
|
|
// Attempt to raise the priority (should fail).
|
|
//
|
|
|
|
LxtCheckErrnoFailure(setpriority(PRIO_PROCESS, 0, 4), EACCES);
|
|
|
|
//
|
|
// Attempt to modify the parent's priority (should fail).
|
|
//
|
|
|
|
LxtCheckErrnoFailure(setpriority(PRIO_PROCESS, ParentPid, 5), EPERM);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Change the nice rlimit value.
|
|
//
|
|
|
|
Rlimit.rlim_cur = 19;
|
|
Rlimit.rlim_max = 19;
|
|
LxtCheckErrno(setrlimit(RLIMIT_NICE, &Rlimit));
|
|
|
|
//
|
|
// Change the UID to drop CAP_SYS_NICE.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(1000));
|
|
|
|
//
|
|
// Setting the priority to 1 should succeed.
|
|
//
|
|
LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 1, 1));
|
|
|
|
//
|
|
// Setting the priority to 0 should fail.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(setpriority(PRIO_PROCESS, 0, 0), EACCES);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
if (OriginalPriority > 0)
|
|
{
|
|
setpriority(PRIO_PROCESS, 0, OriginalPriority);
|
|
}
|
|
|
|
return Result;
|
|
}
|