CS360 Lecture notes -- More about Process

  • Jian Huang
  • Directory: ~huangj/cs360/notes/ProcMisc
  • Lecture notes: http://www.cs.utk.edu/~huangj/cs360/360/notes/ProcMisc/lecture.html

    Unix provides fork, exec and wait. These are all the process controls you have. In fact, these are very sufficient. Here we use a widely used ANSI C standard function as a final example about Unix process control.


    System

    In ANSI C, system was defined in stdlib.h to execute a command string from within a program. For instance, system("ps x"). However, the exact operation of system is strongly system dependent.

         int system(const char *cmdstring);
    

    On Unix, system is implemented by calling fork, exec and wait. The only extra things that system does include error checking and signal handling. Since we have not talked about signal yet, let's focus here what errors may occur during the process that system is called.

    First, fork may fail or wait may return with an error. In this case, system returns -1 with errorno set to indicate the error. Second, the exec may fail (implying that shell cannot be executed), the return value is 127. Otherwise, if all succeed, then the return value of system is the termination status of the shell. Below is a sample implementation of system without considering signals.

    
         #include < sys/types.h >
         #include < sys/wait.h >
         #include < errno.h >
         #include < unistd.h >
    
         int system (const char * cmdstring)
         {
           pid_t pid;
           int   status;
    
           if (cmdstring == NULL)
              return (1);   /* always do a command */
      
           if ( (pid = fork() ) < 0) {
               status = -1;  /* probably out of processes */
           }
           else if (pid == 0) {  /* child process */
               execlp("/bin/sh","-c",cmdstring, (char *)0);
               _exit(127);      /* exec error */
           }
           else {
               /* all is well */
               while (wait(&status) < 0)
                 if (errno != EINTR) {
                     /* not a normal interrupt */
                     status = -1;
                     break;
                 }
           }
    
           return (status);
         }
    
    

    Process Time

    To date, all timing measurements we have talked about falls under the category of calendar time, that is the number of seconds maintained by the system since the Epoch, 00:00:00 January 1, 1970, Coordinated Universal Time (UTC). UTC is also known as Greenwich Mean Time.

    After knowing all about process, let's talk about process time, which is also called CPU time. Process time is a concept that refers to how much central processor resources is used by a process. Just like calendar time, process time is also measured in clock ticks, historically with 50, 60 or 100 ticks per second.

    For each process, the system maintains three values:

      - clock time (wall clock time)
      - user CPU time
      - system CPU time
    

    On Unix, process time is collected by calling

      #include < sys/times.h >
      clock_t times (struct tms * buf);
    
    The tms structure has the following definition:
      struct tms {
        clock_t tms_utime;  /* user CPU time */
        clock_t tms_stime;  /* system CPU time */
        clock_t tms_cutime; /* user CPU time, terminated children */
        clock_t tms_cstime; /* system CPU time, terminated children */
      }
    

    Note, the return value of times is the wall clock time, measured from a arbitrary point in the past. One does not use that absolute value, but rather use the relative. That is, taking the difference between two return values obtained at two points in the program to get the wall clock execution time of that segment of the code. The ANSI C standard time.h can be used to measure wall clock time as well, but not the CPU time.

    The u/stime measures the CPU time that the current process spent in user space or system calls, respectively. cu/stime measures the same quantities for all children processes of the current processes that have been wait'ed for.

    To find out how many ticks there are in each second, use

    
      #include < unistd.h >
      long clktck = 0;
      clktck = sysconf(_SC_CLK_TCK);