* Copyright (c) 2007 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include "share.h"
#define FP stderr
#ifndef USING_SDK
typedef struct _IO_COUNTERS {
ULONGLONG ReadOperationCount;
ULONGLONG WriteOperationCount;
ULONGLONG OtherOperationCount;
ULONGLONG ReadTransferCount;
ULONGLONG WriteTransferCount;
ULONGLONG OtherTransferCount;
} IO_COUNTERS;
typedef IO_COUNTERS *PIO_COUNTERS;
* object and
* LastErrorValue: (Win32) 0x18 (24) - The program issued a command but the command length
* is incorrect.
*/
typedef struct _NEW_JOBOBJECT_BASIC_LIMIT_INFORMATION {
LARGE_INTEGER PerProcessUserTimeLimit;
LARGE_INTEGER PerJobUserTimeLimit;
DWORD LimitFlags;
SIZE_T MinimumWorkingSetSize;
SIZE_T MaximumWorkingSetSize;
DWORD ActiveProcessLimit;
ULONG *Affinity;
DWORD PriorityClass;
DWORD SchedulingClass;
} NEW_JOBOBJECT_BASIC_LIMIT_INFORMATION;
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
NEW_JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
IO_COUNTERS IoInfo;
SIZE_T ProcessMemoryLimit;
SIZE_T JobMemoryLimit;
SIZE_T PeakProcessMemoryUsed;
SIZE_T PeakJobMemoryUsed;
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;
#endif
void
StartRestrictedProcess(LPTSTR app_name, LPTSTR app_cmdline, SIZE_T pagefile_limit)
{
HANDLE hjob = CreateJobObject(NULL, NULL);
NEW_JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = { 0 };
JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobext = { 0 };
BOOL ok;
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
jobli.PerJobUserTimeLimit.QuadPart = 10 * 10000000;
jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS | JOB_OBJECT_LIMIT_JOB_TIME;
ok = SetInformationJobObject(hjob, JobObjectBasicLimitInformation, &jobli,
sizeof(jobli));
if (!ok) {
fprintf(FP, "GLE %d", GetLastError());
}
jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
ok = SetInformationJobObject(hjob, JobObjectBasicUIRestrictions, &jobuir,
sizeof(jobuir));
if (!ok) {
fprintf(FP, "GLE %d", GetLastError());
}
jobext.ProcessMemoryLimit = pagefile_limit;
jobext.BasicLimitInformation.LimitFlags =
0x00000100 ;
ok = SetInformationJobObject(hjob, 9 ,
&jobext, sizeof(jobext));
if (!ok) {
fprintf(FP, "GLE %d", GetLastError());
}
CreateProcess(app_name, app_cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL,
&si, &pi);
AssignProcessToJobObject(hjob, pi.hProcess);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
{
DWORD dw;
HANDLE h[2];
h[0] = pi.hProcess;
h[1] = hjob;
dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);
switch (dw - WAIT_OBJECT_0) {
case 0:
break;
case 1:
fprintf(stderr, "job limit reached\n");
break;
}
}
CloseHandle(pi.hProcess);
CloseHandle(hjob);
}
int
usage(char *us)
{
fprintf(FP, "Usage: %s [-p page_limit in MB] [-kb] <program> <args...>\n", us);
fflush(FP);
return 0;
}
int __cdecl main(int argc, char *argv[], char *envp[])
{
LPTSTR app_name = NULL;
TCHAR full_app_name[2 * MAX_PATH];
TCHAR app_cmdline[2 * MAX_PATH];
int arg_offs = 1;
int allocation_unit = 1024 * 1024;
int pagelimit = 10 * allocation_unit;
if (argc < 2) {
return usage(argv[0]);
}
while (argv[arg_offs][0] == '-') {
if (strcmp(argv[arg_offs], "-p") == 0) {
if (argc <= arg_offs + 1)
return usage(argv[0]);
pagelimit = atoi(argv[arg_offs + 1]) * allocation_unit;
arg_offs += 2;
} else if (strcmp(argv[arg_offs], "-kb") == 0) {
allocation_unit = 1024;
arg_offs += 1;
}
}
_snwprintf(full_app_name, BUFFER_SIZE_ELEMENTS(full_app_name), L"%hs",
argv[arg_offs]);
_snwprintf(app_cmdline, BUFFER_SIZE_ELEMENTS(app_cmdline), L"%hs %hs", argv[arg_offs],
argv[arg_offs + 1]);
StartRestrictedProcess(NULL , app_cmdline, pagelimit);
fprintf(FP, "done\n");
fflush(FP);
return 0;
}