?? joblab.cpp
字號:
/******************************************************************************
Module: JobLab.cpp
Notices: Copyright (c) 2000 Jeffrey Richter
******************************************************************************/
#include "..\CmnHdr.h"
#include <windowsx.h>
#include <process.h> // for _beginthreadex
#include <tchar.h>
#include <stdio.h>
#include "Resource.h"
#include "Job.h"
///////////////////////////////////////////////////////////////////////////////
CJob g_job; // Job object
HWND g_hwnd; // Handle to dialog box (accessible by all threads)
HANDLE g_hIOCP; // Completion port that receives Job notifications
HANDLE g_hThreadIOCP; // Completion port thread
// Completion keys for the completion port
#define COMPKEY_TERMINATE ((UINT_PTR) 0)
#define COMPKEY_STATUS ((UINT_PTR) 1)
#define COMPKEY_JOBOBJECT ((UINT_PTR) 2)
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI JobNotify(PVOID)
{
TCHAR sz[2000];
BOOL fDone = FALSE;
while (!fDone)
{
DWORD dwBytesXferred;
ULONG_PTR CompKey;
LPOVERLAPPED po;
GetQueuedCompletionStatus(g_hIOCP,
&dwBytesXferred, &CompKey, &po, INFINITE);
// The app is shutting down, exit this thread
fDone = (CompKey == COMPKEY_TERMINATE);
HWND hwndLB = FindWindow(NULL, TEXT("Job Lab"));
hwndLB = GetDlgItem(hwndLB, IDC_STATUS);
if (CompKey == COMPKEY_JOBOBJECT) {
lstrcpy(sz, TEXT("--> Notification: "));
PTSTR psz = sz + lstrlen(sz);
switch (dwBytesXferred) {
case JOB_OBJECT_MSG_END_OF_JOB_TIME:
wsprintf(psz, TEXT("Job time limit reached"));
break;
case JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
wsprintf(psz, TEXT("Job process (Id=%d) time limit reached"), po);
break;
case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
wsprintf(psz, TEXT("Too many active processes in job"));
break;
case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
wsprintf(psz, TEXT("Job contains no active processes"));
break;
case JOB_OBJECT_MSG_NEW_PROCESS:
wsprintf(psz, TEXT("New process (Id=%d) in Job"), po);
break;
case JOB_OBJECT_MSG_EXIT_PROCESS:
wsprintf(psz, TEXT("Process (Id=%d) terminated"), po);
break;
case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
wsprintf(psz, TEXT("Process (Id=%d) terminated abnormally"), po);
break;
case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT:
wsprintf(psz, TEXT("Process (Id=%d) exceeded memory limit"), po);
break;
case JOB_OBJECT_MSG_JOB_MEMORY_LIMIT:
wsprintf(psz, TEXT("Process (Id=%d) exceeded job memory limit"), po);
break;
default:
wsprintf(psz, TEXT("Unknown notification: %d"), dwBytesXferred);
break;
}
ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
CompKey = 1; // Force a status update when a notification arrives
}
if (CompKey == COMPKEY_STATUS) {
static int s_nStatusCount = 0;
_stprintf(sz, TEXT("--> Status Update (%u)"), s_nStatusCount++);
ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
// Show the basic accounting information
JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION jobai;
g_job.QueryBasicAccountingInfo(&jobai);
_stprintf(sz, TEXT("Total Time: User=%I64u, Kernel=%I64u ")
TEXT("Period Time: User=%I64u, Kernel=%I64u"),
jobai.BasicInfo.TotalUserTime.QuadPart,
jobai.BasicInfo.TotalKernelTime.QuadPart,
jobai.BasicInfo.ThisPeriodTotalUserTime.QuadPart,
jobai.BasicInfo.ThisPeriodTotalKernelTime.QuadPart);
ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
_stprintf(sz, TEXT("Page Faults=%u, Total Processes=%u, ")
TEXT("Active Processes=%u, Terminated Processes=%u"),
jobai.BasicInfo.TotalPageFaultCount,
jobai.BasicInfo.TotalProcesses,
jobai.BasicInfo.ActiveProcesses,
jobai.BasicInfo.TotalTerminatedProcesses);
ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
// Show the I/O accounting information
_stprintf(sz, TEXT("Reads=%I64u (%I64u bytes), ")
TEXT("Write=%I64u (%I64u bytes), Other=%I64u (%I64u bytes)"),
jobai.IoInfo.ReadOperationCount, jobai.IoInfo.ReadTransferCount,
jobai.IoInfo.WriteOperationCount, jobai.IoInfo.WriteTransferCount,
jobai.IoInfo.OtherOperationCount, jobai.IoInfo.OtherTransferCount);
ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
// Show the peak per-process and job memory usage
JOBOBJECT_EXTENDED_LIMIT_INFORMATION joeli;
g_job.QueryExtendedLimitInfo(&joeli);
_stprintf(sz, TEXT("Peak memory used: Process=%I64u, Job=%I64u"),
(__int64) joeli.PeakProcessMemoryUsed,
(__int64) joeli.PeakJobMemoryUsed);
ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
// Show the set of Process IDs
DWORD dwNumProcesses = 50, dwProcessIdList[50];
g_job.QueryBasicProcessIdList(dwNumProcesses,
dwProcessIdList, &dwNumProcesses);
_stprintf(sz, TEXT("PIDs: %s"),
(dwNumProcesses == 0) ? TEXT("(none)") : TEXT(""));
for (DWORD x = 0; x < dwNumProcesses; x++) {
_stprintf(_tcschr(sz, 0), TEXT("%d "), dwProcessIdList[x]);
}
ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
}
}
return(0);
}
///////////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_JOBLAB);
// Save our window handle so that the completion port thread can access it
g_hwnd = hwnd;
HWND hwndPriorityClass = GetDlgItem(hwnd, IDC_PRIORITYCLASS);
ComboBox_AddString(hwndPriorityClass, TEXT("No limit"));
ComboBox_AddString(hwndPriorityClass, TEXT("Idle"));
ComboBox_AddString(hwndPriorityClass, TEXT("Below normal"));
ComboBox_AddString(hwndPriorityClass, TEXT("Normal"));
ComboBox_AddString(hwndPriorityClass, TEXT("Above normal"));
ComboBox_AddString(hwndPriorityClass, TEXT("High"));
ComboBox_AddString(hwndPriorityClass, TEXT("Realtime"));
ComboBox_SetCurSel(hwndPriorityClass, 0); // Default to "No Limit"
HWND hwndSchedulingClass = GetDlgItem(hwnd, IDC_SCHEDULINGCLASS);
ComboBox_AddString(hwndSchedulingClass, TEXT("No limit"));
for (int n = 0; n <= 9; n++) {
TCHAR szSchedulingClass[2] = { (TCHAR) (TEXT('0') + n), 0 };
ComboBox_AddString(hwndSchedulingClass, szSchedulingClass);
}
ComboBox_SetCurSel(hwndSchedulingClass, 0); // Default to "No Limit"
SetTimer(hwnd, 1, 10000, NULL); // 10 second accounting update
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
void Dlg_ApplyLimits(HWND hwnd)
{
const int nNanosecondsPerSecond = 100000000;
const int nMillisecondsPerSecond = 1000;
const int nNanosecondsPerMillisecond = nNanosecondsPerSecond / nMillisecondsPerSecond;
BOOL f;
__int64 q;
SIZE_T s;
DWORD d;
// Set Basic and Extended Limits
JOBOBJECT_EXTENDED_LIMIT_INFORMATION joeli = { 0 };
joeli.BasicLimitInformation.LimitFlags = 0;
q = GetDlgItemInt(hwnd, IDC_PERPROCESSUSERTIMELIMIT, &f, FALSE);
if (f)
{
joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_TIME;
joeli.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart =
q * nNanosecondsPerMillisecond / 100;
}
q = GetDlgItemInt(hwnd, IDC_PERJOBUSERTIMELIMIT, &f, FALSE);
if (f)
{
joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_TIME;
joeli.BasicLimitInformation.PerJobUserTimeLimit.QuadPart =
q * nNanosecondsPerMillisecond / 100;
}
s = GetDlgItemInt(hwnd, IDC_MINWORKINGSETSIZE, &f, FALSE);
if (f)
{
joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET;
joeli.BasicLimitInformation.MinimumWorkingSetSize = s * 1024 * 1024;
s = GetDlgItemInt(hwnd, IDC_MAXWORKINGSETSIZE, &f, FALSE);
if (f)
{
joeli.BasicLimitInformation.MaximumWorkingSetSize = s * 1024 * 1024;
}
else
{
joeli.BasicLimitInformation.LimitFlags &=~JOB_OBJECT_LIMIT_WORKINGSET;
chMB("Both minimum and maximum working set sizes must be set.\n"
"The working set limits will NOT be in effect.");
}
}
d = GetDlgItemInt(hwnd, IDC_ACTIVEPROCESSLIMIT, &f, FALSE);
if (f)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -