Home > Articles > Programming > Windows Programming

  • Print
  • + Share This
This chapter is from the book

Example: Using Job Objects

Program 6-7, JobObjectShell, illustrates using job objects to limit process execution time and to obtain user time statistics. JobObjectShell is a simple extension of JobShell that adds a command line time limit argument, in seconds. This limit applies to every process that JobObjectShell manages.

Program 6-7. JobObjectShell: Monitoring Processes with a Job Object

/* Chapter 6 */
/* JobObjectShell.c JobShell extension
   Enhances JobShell with a time limit on each process.
   The process time limit (seconds) is argv[1] (if present)
       0 or omitted means no process time limit
*/

#include "Everything.h"
#include "JobManagement.h"

#define MILLION 1000000
HANDLE hJobObject = NULL;

JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits =
          {0, 0, JOB_OBJECT_LIMIT_PROCESS_TIME};

int _tmain (int argc, LPTSTR argv[])
{
   LARGE_INTEGER processTimeLimit;
   . . .
   hJobObject = NULL;
   processTimeLimit.QuadPart = 0;
   if (argc >= 2) processTimeLimit.QuadPart = atoi(argv[1]);
   basicLimits.PerProcessUserTimeLimit.QuadPart =
      processTimeLimit.QuadPart * 10 * MILLION;

   hJobObject = CreateJobObject(NULL, NULL);
   SetInformationJobObject(hJobObject,
      JobObjectBasicLimitInformation, &basicLimits,
      sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION));
   . . .
   /* Process commands. Call Jobbg, Jobs, etc. - listed below */
   CloseHandle (hJobObject);

   return 0;
}

/* Jobbg: Execute a command line in the background, put
   the job identity in the user's job file, and exit.
*/
int Jobbg (int argc, LPTSTR argv[], LPTSTR command)
{
   /* Execute the command line (targv) and store the job id,
      the process id, and the handle in the jobs file. */

      DWORD fCreate;
      LONG jobNumber;
      BOOL flags[2];

      STARTUPINFO startUp;
      PROCESS_INFORMATION processInfo;
      LPTSTR targv = SkipArg (command);

      GetStartupInfo (&startUp);

         /* Determine the options. */
      Options (argc, argv, _T ("cd"), &flags[0], &flags[1], NULL);

         /* Skip over the option field as well, if it exists. */
      if (argv[1][0] == '-')
         targv = SkipArg (targv);

      fCreate = flags[0] ? CREATE_NEW_CONSOLE : flags[1] ?
            DETACHED_PROCESS : 0;

      /* Create the job/thread suspended.
         Resume it once the job is entered properly. */
      CreateProcess (NULL, targv, NULL, NULL, TRUE,
             fCreate | CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP,
             NULL, NULL, &startUp, &processInfo);

      AssignProcessToJobObject(hJobObject, processInfo.hProcess);

      jobNumber = GetJobNumber (&processInfo, targv);
      if (jobNumber >= 0)
         ResumeThread (processInfo.hThread);
      else {
         TerminateProcess (processInfo.hProcess, 3);
         CloseHandle (processInfo.hThread);
         CloseHandle (processInfo.hProcess);
         return 5;
      }

      CloseHandle (processInfo.hThread);
      CloseHandle (processInfo.hProcess);
      _tprintf (_T (" [%d] %d\n"), jobNumber, processInfo.dwProcessId);
      return 0;
   }

   /* Jobs: List all running or stopped jobs that have
      been created by this user under job management;
      that is, have been started with the jobbg command.
      List summary process count and user time information.
   */
int Jobs (int argc, LPTSTR argv[], LPTSTR command)
{
   JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;

   DisplayJobs (); /* Not job objects, but jobbg created processes */

   /* Dispaly the job object information */
   QueryInformationJobObject(hJobObject,
      JobObjectBasicAccountingInformation, &BasicInfo,
      sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION), NULL);
   _tprintf (_T("Total Processes: %d, Active: %d, Terminated: %d.\n"),
      BasicInfo.TotalProcesses, BasicInfo.ActiveProcesses,
      BasicInfo.TotalTerminatedProcesses);
   _tprintf (_T("User time all processes: %d.%03d\n"),
      BasicInfo.TotalUserTime.QuadPart / MILLION,
      (BasicInfo.TotalUserTime.QuadPart % MILLION) / 10000);

   return 0;
}

When you list the running processes, you will also see the total number of processes and the total user time on a four-processor computer.

First, we'll modify the usual order and show Run 6-7, which runs the command:

JobObjectShell 60
Run 6-7

Run 6-7 JobObjectShell Monitoring Processes with a Job Object

to limit each process to a minute. The example then runs to shell commands:

timep grep 1234561 l2.txt l3.txt l4.txt
timep grepMP 1234561 l2.txt l3.txt l4.txt

as in Run 6-6. Note how the jobs command counts the processes that timep creates as well as those that grepMP creates to search the files, resulting in seven processes total. There is also a lot of contention for the console, mixing output from several processes, so you might want to run this example with the -c option.

There are also a few unexpected results, which are described for further investigation in Exercise 6–12.

Program 6-7 gives the JobObjectShell listing; it's an extension of JobShell (Program 6-3), so the listing is shortened to show the new code. There are some deviations from the MSDN documentation, which are described in Exercise 6–12 for investigation.

  • + Share This
  • 🔖 Save To Your Account