Previous Page Next Page

18.2. Processes

Your Perl script is a program that resides on disk. When the program is placed in memory and starts execution, it is called a process. Each process has a number of attributes that are inherited from its parent, the calling process. Perl has a number of functions that will allow you to retrieve the information about the process. Before examining these functions, a short discussion about processes may help you to understand (or recall) the purpose of some of Perl's system calls.

18.2.1. UNIX Processes

Every process has a unique process ID, a positive integer called the pid. Every process has a parent except process 0, the swapper. The first process init, pid 1, is the ancestor of all future processes, called descendants, or more commonly, child processes.

In Figure 18.5, the Perl process is a descendant of the shell (sh).

Figure 18.5. The Perl process as a descendant of the shell.


Each process also belongs to a process group, a collection of one or more processes used for job control and signal handling. Each process group also has a unique pid and a process leader. When you log on, the process group leader may be your login shell. Any process created from your shell will be a member of this process group. The terminal opened by the process group leader is called the controlling terminal, and any processes it spawns inherit it. Any signals sent to the process will be sent to all processes in the group. That is why, when you press <Ctrl>-c, the process you are running and any of its children will terminate. Perl provides functions to obtain the process group ID and to set the process group.

When a process is created, it is assigned four numbers indicating who owns the process. They are the real and effective user ID and the real and effective group ID. The user ID, called the real uid, is a positive integer that is associated with your login name. The real uid is the third field in the /etc/passwd file. When you log on, the first process created is called the login shell, and it is assigned the user ID. Any processes spawned from the shell also inherit this uid. Any process running with the uid of zero is called a root, or superuser, process with special privileges.

There is also a group ID number, called the real gid, which associates a group with your login name. The default gid is the fourth field in the password file, and it is also inherited by any child process. The system administrator can allow users to become members of other groups by assigning entries in the /etc/group file.

The following is an entry from the passwd file, illustrating how the uid and gid values are stored (fields are separated by colons).

Example 18.32.

(Entry from /etc/passwd)
    john:aYD17IsSjBMyGg:9495:41:John Doe:/home/dolphin/john:/bin/ksh

Explanation

(The Fields)

  1. login name

  2. encrypted password

  3. uid

  4. gid

  5. gcos

  6. home directory

  7. login shell

The effective uid (euid) and effective guid (guid) of a process are normally set to the same number as the real uid and real gid of the user who is running the process. UNIX determines what permissions are available to a process by the effective uid and gid. If the euid or guid of a file is changed to that of another owner, when you execute a program, you essentially become that owner and get his access permissions. Programs in which the effective uid or effective gid have been set are called set user ID programs, or setuid programs. When you change your password, the /bin/passwd program has a setuid to root, giving you the privilege to change your password in the passwd file, which is owned by root.

18.2.2. Win32 Processes

The process model for Windows differs from UNIX systems, and since Perl was originally designed for UNIX, a number of library routines were added to the standard Perl library to accommodate the Windows world. The Win32 directory (C:/Perl/lib/Win32) is a Windows-specific directory that comes with Windows versions of Perl and contains a number of modules for creating, suspending, resuming, and killing processes. The Win32::Process module contains a number of functions to manipulate processes. Here is a listing from the Win32 directory:

AuthenticateUser.pm  Internet.pm         Registry.pm
ChangeNotify.pm      Mutex.pm            Semaphore.pm
Client.pl            NetAdmin.pm         Server.pl
Clipboard.pm         NetResource.pm      Service.pm
Console.pm           ODBC.pm             Shortcut.pm
Event.pm             OLE                 Sound.pm
EventLog.pm          OLE.pm              Test.pl
File.pm              PerfLib.pm          TieRegistry.pm
FileSecurity.pm      Pipe.pm             WinError.pm
IPC.pm               Process.pm          test-async.pl

18.2.3. The Environment (UNIX and Windows)

When you log on, your shell program inherits a set of environment variables initialized by either the login program or one of shell's startup files (.profile or .login). These variables contain useful information about the process, such as the search path, the home directory, the user name, and the terminal type. The information in environment variables, once set and exported, is inherited by any child processes that are spawned from the process (parent) in which they were initialized. The shell process will pass the environment information on to your Perl program.

The special associative array %ENV contains the environment settings. If you change the value of an environment setting in your Perl script, it is set for this process and any of its children. The environment variables in the parent process, normally the shell, will remain untouched.

Example 18.33.

(The Script)
(UNIX)
1   foreach $key (keys(%ENV)){
2          print "$key\n";}
3   print "Your login name is $ENV{'LOGNAME'}\n";
4   $pwd=$ENV{'PWD'};
    print "/The present working directory is $pwd, "\n";

(Output)
2   OPENWINHOME
    MANPATH
    FONTPATH
    LOGNAME
    USER
    TERMCAP
    TERM
    SHELL
    PWD
    HOME
    PATH
    WINDOW_PARENT
    WMGR_ENV_PLACEHOLDER
3   Your login name is ellie
4   The present working directory is /home/jody/ellie

					  

Explanation

  1. The keys function is used to get all the currently set environment variables from the %ENV array. These variables were inherited from the parent process, the shell.

  2. Each environment variable is printed.

  3. The value of LOGNAME, the user name, is printed.

  4. The value of PWD, the present working directory, is assigned to $pwd and printed.

Example 18.34.

(Windows)
    while(($key,$value)=each(%ENV)){
        print "$key: $value\n" if $key =~ /^P/;
    }

(Output)
1   PROMPT: $p$g
    PROCESSOR_IDENTIFIER: x86 Family 6 Model 5 Stepping 2,
        GenuineIntel
    PATH: c:\Oracle\Ora81\bin;"C:\PROGRAM FILES
        \OCLE\JRE\1.1.7\BIN";C:\ORAWIN95\BIN;C:\PERL\BIN\;
        C:\MKSNT;C:\WINDOWS;C:\WINDOW
    PATHEXT: .pl;.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
    PROGRAMFILES: C:\PROGRA~1
    PROCESSOR_ARCHITECTURE: x86
    PROCESSOR_REVISION: 0502
    PERL5LIB: C:\Perl\lib
    PROCESSOR_LEVEL: 6

Explanation

  1. The each function is used to get all the currently set environment variables from the %ENV array. These variables were inherited from the parent process, the MS-DOS shell.

18.2.4. Processes and Filehandles

As discussed in Chapter 10, "Getting a Handle on Files," processes can be opened in Perl via either an input or output filehandle. For example, if you want to see all the currently running processes on your machine, you could create a filehandle for the UNIX ps command. (See Chapter 10 for details. See also "The system Function" on page 750.)

Example 18.35.

      (The Script)
          # UNIX ps command
      1   open(PROC, "ps -aux |" ) || die "$!\n";
                        # If running System V, use ps -ef
      2   print STDOUT <PROC>;

      (Output)
2  ellie  3825  6.4  4.5  212  464 p5  R 12:18  0:00 ps –aux
   root      1  0.0  0.0   52    0 ?  IW Feb 5  0:02 /sbin/init
   root     51 10.0  0.0   52    0 ?  IW Feb 5  0:02 portmap
   root      2 10.0  0.0   52    0 ?   D Feb 5  0:02 pagedaemon
   root     90 10.0  0.0   52    0 ?  IW Feb 5  0:02 rpc.statd
                               <more processes here>

   ellie  1383  0.8  8.4  360  876 p4  S Dec 26 11:34 /usr/local/OW3/bin/xview
   ellie   173  0.8 13.4 1932 1392 co  S Dec 20389:19 /usr/local/OW3/bin/xnews
   ellie   164  0.0  0.0  100    0 co IW Dec 20  0:00 –c

                     <some of the output was cut to save space>

   ellie  3822  0.0  0.0    0    0 p5  Z Dec 20 0:00 <defunct>
   ellie  3823  0.0  1.1   28  112 p5  S 12:18  0:00 sh –c ps –aux | grep '^'
   ellie  3821  0.0  5.6  144  580 p5  S 12:18  0:00 /bin/perl checkon ellie
   ellie  3824  0.0  1.8   32  192 p5  S 12:18  0:00 grep ^ellie

					  

Explanation

  1. The PROC filehandle is opened for reading. It is called an input filter. The output from the ps command is piped to Perl via the PROC filehandle.

  2. The contents of the filter are printed to STDOUT.

Login Information—The getlogin Function

The getlogin function returns the current login from /etc/utmp. If null is returned from getlogin, use getpwuid. The getpwuid function takes the uid of the user as an argument and returns an entry from the password file associated with that uid.

The $< variable evaluates to the real uid of this process.

Format

getlogin;

Example 18.36.

(The Script)
1   $loginname=getlogin || (getpwuid($<))[0]|| die "Not a user here!!";
2   print "Your loginname is $loginname.\n";

(Output)
2   Your loginname is john.

Explanation

  1. The getlogin function returns the login name from /etc/utmp and, if that fails, retrieves it from the password file with the getpwuid function. The $< variable contains the real uid of this process.

  2. The scalar $loginname contains the user's login name, the first entry of the password file.


Special Process Variables (pid, uid, euid, gid, euid)

Perl provides some special variables that store information about the Perl process executing your script. If you want to make your program more readable, you can use the English module in the standard Perl library to represent these variables in English.

$$The process ID of the Perl program running this script
$<The real uid of this process
$>The effective uid of this process
$(The real gid of this process
$)The effective gid of this process


The Parent Process ID—The getppid Function and the $$ Variable

Each process on the system is identified by its process identification number (pid), a positive integer. The special variable $$ holds the value of the pid for this process. This variable is also used by the shell to hold the process ID number of the current process.

The getppid function returns the process ID of the parent process.

Example 18.37.

(The Script)
1   print "The pid of this process is $$\n";
2   print "The parent pid of this process is ", getppid,"\n";

(Output)
1   The pid of this process is 3304
2   The parent pid of this process is 2340

(At the Command Line)
3   $ echo $$
    2340

Explanation

  1. The process identification number (pid) for this process, this Perl script, is printed.

  2. The process that spawned this process is ordinarily the shell, the parent process. The parent's pid is called the ppid.

  3. After the Perl script exits, the $$ is used to print the pid of the shell. The ppid for the Perl script was 2340; the value of its parent's pid, that of the shell.

The Process Group ID—The pgrp Function

The pgrp function returns the current group process for a specified pid. Without an argument or with an argument of 0, the process group ID of the current process is returned.

Format

getpgrp(PID);
getpgrp PID;
getpgrp;

Example 18.38.

(The Script)
1   print "The pid of the Perl program running this script is ", $$;
2   printf "The ppid, parent's pid (Shell) , is %d\n", getppid;
3   printf "The process group's pid is %d\n", getpgrp(0);

(Output)
1   The pid of the Perl program running this script is 6671
2   The ppid, parent's pid (Shell), is 6344
3   The process group's pid is 6671

 


18.2.5. Process Priorities and Niceness

The kernel maintains the scheduling priority selected for each process. Most interactive and short-running jobs are favored with a higher priority. The UNIX nice command allows you to modify the scheduling priority of processes (BSD, pre-System V). On moderately or heavily loaded systems, it may be to your advantage to make CPU-intensive jobs run slower so that jobs needing higher priority get faster access to the CPU. Those jobs that don't hog the processor are called nice.

The nice value is used in calculating the priority of a process. A process with a positive nice value runs at a low priority, meaning that it receives less than its share of the CPU time. A process with a negative nice value runs at a high priority, receiving more than its share of the processor. The nice values range from –20 to 19. Most processes run at priority zero, balancing their access to the CPU. (Only the superuser can set negative nice values.)

The following functions, getpriority and setpriority, are named for the corresponding system calls, found in Section 2 of the UNIX man pages.

The getpriority Function

The getpriority function returns the current priority (nice value) for a process, a process group, or a user. Not all systems support this function. If not implemented, getpriority produces a fatal error. WHICH is one of three values: 0 for the process priority, 1 for the process group priority, and 2 for the user priority. WHO is interpreted relative to the process identifier for the process priority, process group priority, or user priority. A value of zero represents the current process, process group, or user.

Format

getpriority(WHICH, WHO);

Example 18.39.

(The Script)
1   $niceval = getpriority( 0,0);
2   print "The priority, nice value, for this process is $niceval\n";

(Output)
2   The priority, nice value, for this process is 0.

Explanation

  1. The getpriority function will return the nice value for the current process.

  2. The nice value for this process is zero. This gives the process no special favor when taking its share of time from the CPU.


The setpriority Function (nice)

The setpriority function sets the current priority (nice value) for a process, a process group, or a user. It modifies the scheduling priority for processes. If the setpriority system call is not implemented on your system, setpriority will return an error.

WHICH is one of three values: 0 for the process priority, 1 for the process group priority, and 2 for the user priority. WHO is interpreted relative to the process identifier for the process priority, process group priority, or user priority. A value of zero represents the current process, process group, or user. NICEVALUE is the nice value. A low nice value raises the priority of the process and a high nice value decreases the priority of the process. (Confusing!)

Unless you have superuser privileges, you cannot use a negative nice value. Doing so will not change the current nice value.

Format

setpriority(WHICH, WHO, NICEVALUE);

Example 18.40.

(The Script)
1   $niceval = getpriority(0,0);
2   print "The nice value for this process is $niceval.\n";
3   setpriority(0,0, ( $niceval + 5 ));
4   print "The nice value for this process is now", getpriority(0,0);

(Output)
2   The nice value for this process is 0.
4   The nice value for this process is now 5.

Explanation

  1. The getpriority function will return the nice value for the current process.

  2. The nice value is printed.

  3. The setpriority function adds 5 to the nice value of the current process. The process will have a lower priority. It is being "nice."

  4. The new nice value returned by the getpriority function is 5.


18.2.6. Password Information

UNIX

The following functions iterate through the /etc/passwd file and retrieve information from that file into an array. These functions are named for the same functions found in the system library (Section 3 of the UNIX manual) and perform the same tasks. If you are interested in obtaining information about the /etc/group file, the Perl functions getgrent, getgrgid, and getgrnam all return a four-element array with information about group entries. A description of these functions can be found in the UNIX manual pages. Here is an example of an /etc/passwd file:

root:YhTLR4heBdxfw:0:1:Operator:/:/bin/csh
nobody:*:65534:65534::/:
sys:*:2:2::/:/bin/csh
bin:*:3:3::/bin
uucp:*:4:8::/var/spool/uucppublic:
news:*:6:6::/var/spool/news:/bin/csh
sync::1:1::/:/bin/sync
ellie:aVD17TSsBMfYg:9496:40:Ellie Shellie:/home/jody/ellie:/bin/ksh

Windows

Windows 2000 and NT store information about users in a binary database called SAM (Security Accounts Manager), part of the Registry. Because the data is stored in binary format, normal Perl read operations won't work. It is better to use the Win32 extensions to get user information. Win32::NetAdmin is bundled with ActiveState under \perl\site\lib\win32. (See Table 18.9.) A user account can be manipulated with two functions of this module: UserGetAttributes() and UserSetAttributes. Another good extension is David Roth's Win32::AdminMisc found at www.roth.net.

Table 18.9. Win32::NetAdmin Extensions
Win32::NetAdmin::UserGetAttributes($Machine,
                                                                $UserName,
                                                                $Password,
                                                                $PasswordAge,
                                                                $Privilege,
                                                                $Homedir,
                                                                $Comment,
                                                                $Flags,
                                                                $ScriptPath);
Win32::NetAdmin::UserSetAttributes( $Machine,
                                                                $UserName,
                                                                $Password,
                                                                $PasswordAge,
                                                                $Privilege,
                                                                $Homedir,
                                                                $Comment,
                                                                $Flags,
                                                                $ScriptPath);


The Win 32 net.exe command also displays information about the user and the system.

Example 18.41.

1   C:\  net help
    The syntax of this command is:

    NET HELP command
       -or-
    NET command /HELP

    Commands available are:

    NET ACCOUNTS             NET HELP          NET SHARE
    NET COMPUTER             NET HC:\ELPMSG    NET START
    NET CONFIG               NET LOCALGROUP    NET STATISTICS
    NET CONFIG SERVER        NET NAME          NET STOP
    NET CONFIG WORKSTATION   NET PAUSE         NET TIME
    NET CONTINUE             NET PRINT         NET USE
    NET FILE                 NET SEND          NET USER
    NET GROUP                NET SESSION       NET VIEW
    NET HELP SERVICES lists the network services you can start.
    NET HELP SYNTAX explains how to read NET HELP syntax lines.
    NET HELP command | MORE displays Help one screen at a time.

2   C:\ net user

    User accounts for \\HOMEBOUND

    -----------------------------------------------------------------

    Administrator            Ellie Quigley            Guest
    SQLAgentCmdExec
    The command completed successfully.

					  

Example 18.42.

1   use Win32::NetAdmin qw(GetUsers UserGetAttributes) ;
2   GetUsers("", FILTER_NORMAL_ACCOUNT,\%hash)or die;
3   foreach $key(sort keys %hash){
       print "$key\n";
    }
(Output)
Administrator
Ellie Quigley
Guest
SQLAgentCmdExec

Encrypted passwords cannot be transferred from UNIX to Win32 systems and vice versa. They are cryptologically incompatible. To manage passwords, use the Win32::AdminMisc or the Win32::NetAdmin module extension.

Table 18.10. Win32 Password Extensions
Win32::AdminMisc::UserCheckPassword($Machine, $User, $Password)

Win32::AdminMisc::SetPassword($Machine | $Domain), $User, $NewPassword);

Win32::AdminMisc::UserChangePassword($Machine | $Domain), $User, $OldPassword, $NewPassword);

Win32::NetAdmin::UserChangePassword(($Machine | $Domain), $User, $OldPassword, $NewPassword);


For Windows users, the following functions for obtaining group and user information have not been implemented by ActiveState as of this printing:

endgrent(), endpwent(), getgrent(), getgrgid(), getgrnam(),
getpwent(), getpwnam(), getpwuid(), setgrent(), setpwent()

Getting a Password Entry (UNIX)—The getpwent Function

The getpwent function retrieves information from the /etc/passwd file. The return value from getpwent is a nine-element array consisting of:

  1. Login name

  2. Encrypted password

  3. User ID

  4. Group ID

  5. Quota

  6. Comment

  7. Gcos (user information)

  8. Home directory

  9. Login shell

Format

($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir,
        $shell )=getpwent;

Example 18.43.

(The Script)
1   while( @info=getpwent) {
2       print "$info[0] \n" if $info[1]= ~/ \*+/;
    }

(Output)
2   nobody
    daemon
    sys
    bin
    uucp

Explanation

  1. The getpwent function gets a line from the /etc/passwd file and stores it in the array @info. The loop continues until getpwent cannot read another entry from /etc/passwd.

  2. If the second element of the array contains at least one star (*), the first element, the user name, is printed.


Getting a Password Entry by Username—The getpwnam Function

The getpwnam function takes the user name as an argument and returns a nine-element array corresponding to that user's name field in the /etc/passwd file.

Format

getpwnam(loginname);

Example 18.44.

(The Script)
    #!/bin/perl
1   foreach $name ( "root", "bin", "ellie" ){
2       if (($login, $passwd, $uid)=getpwnam($name)){
3          print "$login--$uid\n";
        }
    }

(Output)
3   root--0
    ellie--9496
    bin--3

Explanation

  1. The foreach loop contains login names in its list, each to be processed in turn.

  2. The getpwnam function retrieves information from /etc/passwd and stores the first three fields of information in the array elements $login, $passwd, and $uid, respectively.

  3. The login name and the uid are printed.


Getting a Password Entry by uid—The getpwuid Function

The getpwuid function takes a numeric user ID (uid) as an argument and returns a nine-element array corresponding to that user's uid entry in the /etc/passwd file.

Format

getpuid(UID)

Example 18.45.

(The Script)
1   foreach $num ( 1 .. 10 ){
2       if (($login, $passwd, $uid)=getpwuid($num)){
3       print "$login--$uid\n";}
    }

(Output)
3   daemon--1
    sys--2
    bin--3
    uucp--4
    news--6
    ingres--7
    audit--9

Explanation

  1. The foreach loop contains a range of uid numbers from 1 to 10 in its list, each to be processed in turn.

  2. The getpwuid function retrieves information from /etc/passwd and stores the first three fields of information in the array elements $login, $passwd, and $uid, respectively.

  3. The login name and its corresponding uid are printed.


18.2.7. Time and Processes

When working in a computer environment, programs often need to obtain and manipulate the current date and time. UNIX systems maintain two types of time values: calendar time and process time.

The calendar time counts the number of seconds since 00:00:00 January 1, 1970, UTC (Coordinated Universal Time, which is a new name for Greenwich Mean Time).

The process time, also called CPU time, measures the resources a process utilizes in clock time, user CPU time, and system CPU time. The CPU time is measured in clock ticks per second.

Perl has a number of time functions that interface with the system to retrieve time information.

The times function

The times function returns a four-element array consisting of the CPU time for a process, measured in:

Format

($user, $system, $cuser, $csystem) = times;

Example 18.46.

(The Script)
    #!/bin/perl
1   printf "User time in this program %2.3f seconds\n", (times)[0];
2   printf "System time in this program %2.3f seconds\n", (times)[1];

(Output)
3   User time in this program 0.217 seconds
4   System time in this program 0.600 seconds

Explanation

  1. The times function returns a four-element array and the first element is printed, the user time.

  2. The times function returns a four-element array and the second element is printed, the system time.


The time Function (UNIX and Windows)

The time function returns the number of nonleap seconds since January 1, 1970, UTC. Its return value is used with the gmtime and localtime functions to put the time in a human-readable format. The stat and utime functions also use the time functions when comparing file modification and access times.

The gmtime Function

The gmtime function converts the return value of the time function to a nine-element array consisting of the numeric values for the UTC. If you are a C programmer, you will recognize that these values are taken directly from the tm structure found in the header file /usr/include/time.h. (See Table 18.11.)

Table 18.11. Return Values for the gmtime Function
List ElementMeaning
$secSeconds after the minute: [0, 59]
$minMinutes after the hour: [0, 59]
$hourHour since midnight: [0, 23]
$monthdayDay of the month: [1, 31]
$monthMonths since January: [0, 11]
$yearYears since 1900
$weekdayDays since Sunday: [0, 6]
yeardayDays since January 1: [0, 365]
isdaylightFlag for daylight savings time


Format

gmtime(EXPR);
gmtime EXPR;
($sec, $min, $hour, $monthday, $month, $year, $weekday,
          $yearday, $isdaylight)=gmtime;


Example 18.47.

(The Script)
    #!/bin/perl
1   ($sec, $min, $hour, $monthday, $month, $year, $weekday, $yearday,
         $isdaylight) = gmtime;
2   print "The weekday is $weekday and the month is $month.\n";
3   print "The time in California since midnight is ",
         `date "+%H:%M"`;
4   print "The Coordinated Univeral Time is $hour:$min
          since midnight\n";
5   print "Daylight saving is in effect.\n" if $isdaylight;
(Output)
2   The weekday is 2 and the month is 6.
3   The time in California since midnight is 20:35.
4   The Coordinated Univeral Time is 3:35 since midnight.
5   <no output>

Explanation

  1. The gmtime function returns an array as defined in Table 18.11.

  2. The weekday and the month are printed for Coordinated Universal Time.

  3. The time in California is printed by utilizing the UNIX date command.

  4. The Coordinated Universal Time is printed.

  5. If daylight savings is in effect, the value of $isdaylight is set to nonzero. Daylight saving time is not in effect, so nothing prints.

The localtime Function

The localtime function converts the UTC to a nine-element array with the local time zone.

Format

localtime(EXPR);
localtime EXPR;
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday,
          $isdst)=localtime(time);

Example 18.48.

(At the Command Line)
1   $ perl -e "print scalar (localtime);"
    Wed May 30 15:26:16 2007

(In Script)
2   $localtime=localtime;
    print $localtime;

Explanation

  1. If the localtime function is use in scalar context, its return value is output similar to the UNIX/Win32 date command. The scalar function forces scalar context.

  2. Assigning the return value of localtime to a scalar.


Example 18.49.

(The Script)
    #!/bin/perl
1   ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)=
           localtime(time);
2      % weekday=(
       "0"=>"Sunday",
       "1"=>"Monday",
       "2"=>"Tuesday",
       "3"=>"Wednesday",
       "4"=>"Thursday",
       "5"=>"Friday",
       "6"=>"Saturday",
    );
     if ( $hour > 12 ){
3       print "The hour is ", $hour - 12 ," o'clock.\n";
    }
    else {
        print "The hour is $hour o'clock.\n";
    }
4  print qq/Today is $weekday{"$wday"}.\n/; # day starts at zero
5  print "It is ",$mon + 1, "/$mday/" , 1900+$year,".\n";
6  print "The isdst is $isdst.\n";

(Output)
3  The hour is 1 o'clock.
4  Today is Wednesday.
5  It is 5/30/2007.
6  The isdst is 1.

					  

Explanation

  1. The localtime function converts the return of the time function to the local time.

  2. An associative array, %weekday, associates a number of the weekday with the string for the day of the week.

  3. The hour and the minutes are printed.

  4. The scalar $wday returned from the localtime function represents the number of the weekday starting at 0. It is used to key into the associative array %weekday to get the value of the string Wednesday.

  5. The month, day of the month, and year are printed.

  6. The $isdt element of the array prints 1 if daylight savings is in effect, and 0 if not.

18.2.8. Process Creation UNIX

What happens when your Perl program starts executing? Here is a brief sketch of what goes on. Normally, the Perl program is executed from the shell command line. You type the name of your script (and its arguments) and then press the Enter key. At that point, the shell starts working. It first creates (forks) a new process called the child process. The child is essentially a copy of the shell that created it. There are now two processes running, the parent and child shells. After the child process is created, the parent shell normally sleeps (waits) while its child process gets everything ready for your Perl program; that is, handles redirection (if necessary) pipes, background processing, etc. When the child shell has completed its tasks, it then executes (execs) your Perl program in place of itself. When the Perl process completes, it exits (exits), and its exit status is returned to the waiting parent process, the shell. The shell wakes up, and a prompt appears on the screen. If you type in a UNIX command, this whole process is repeated.

It's conceivable that your Perl program may want to start up a child process to handle a specific task; for example, a database application or a client/server program.

The fork Function

The fork function is used to create processes on UNIX systems. The fork function is called once and returns twice. It creates a duplicate of the parent (calling) process. The new process is called the child process. The child process inherits its environment, open files, real and user IDs, masks, current working directory, signals, and so on. Both processes, parent and child, execute the same code, starting with the instruction right after the fork function call.

The fork function lets you differentiate between the parent and child because it returns a different value to each process. It returns 0 to the child process and the pid of the child to the parent process. It is not guaranteed which process will execute first after the call to the fork function.

Normally, the wait, exec, and exit functions work in conjunction with the fork function so that you can control what both the parent and the child are doing. The parent, for example, waits for the child to finish performing some task, and after the child exits, the parent resumes where it left off.

Figure 18.6 illustrates how the UNIX shell uses the fork system call to create a new process. After you type the name of your Perl program at the shell prompt, the shell forks, creating a copy of itself called the child process. The parent shell sleeps (waits). The child shell executes (execs) the Perl process in its place. The child never returns. Note that ENV variables, standard input, output, and standard error are inherited. When the Perl program completes, it exits and the parent shell wakes up. The shell prompt reappears on your screen. The Perl program could use the fork function to spawn off another application program.

Figure 18.6. Perl process creation from the shell.


Format

fork;

Example 18.50.

(The Script)
1   $return_val=fork;
2   if ( $return_val == 0 ){
       print "This is the child process; return value
             is $return_val.\n";
    }
3   elsif ( defined $return_val ){
       print "This is the parent process; return value
             is $return_val.\n";
    }
    else{
4       die "fork error: $!\n";
    }

(Output)
2   This is the child process; return value is 0.
3   This is the parent process; return value is 3512.

Explanation

  1. The fork function is called to create a copy of this process.

  2. The return value is checked. If the return value is 0, the child's code is in execution.

  3. If the return value is nonzero, the parent process is executing.

  4. This statement is executed if the fork function fails. It might fail if the process table is full; that is, if the system has reached its maximum number of allowed processes.


The exec Function

Whereas fork creates a brand new process, the exec function is used to initiate a new program in place of the currently running program. Normally, the exec function is called after fork. Perl inherits attributes from the shell, and a process that is executed from within Perl also inherits Perl's attributes, such as pid, gid, uid, signals, directories, etc. If, then, the exec function is called directly (no fork) from within a Perl script, the new program executes in place of the currently running Perl program. When that program completes, you do not return to your Perl program. Since exec does not flush the output buffer, the $| variable needs to be set to ensure command buffering.

The filehandles STDIN, STDOUT, and STDERR remain open following a call to the exec function.

At the system level there are six different exec functions used to initiate new programs. Perl calls the C library function execvp if more than one argument is passed to the exec function. The arguments are the name of the program to execute and any other arguments that will be passed to that program. If a single scalar is passed to the exec function and it contains any shell metacharacters, the shell command /bin/sh -c is passed the command for interpretation.

Format

exec(UNIX COMMAND);
exec UNIX COMMAND;

Example 18.51.

(The Script)
1   exec 'echo hi there you!';
2   print "hello";

(Output)
1   hi there you

(The Script)
1   exec 'ls *.c';
2   print "hello.";

(Output)
file1.c file2.c file3.c

Explanation

  1. In both examples, the exec function will execute the UNIX command.

  2. In both examples, the print statement will not be executed, because exec never returns. The UNIX commands were executed in place of the Perl program.


The wait and waitpid Functions

The wait function waits for a child process to finish execution. After a fork call, both processes, parent and child, execute. The wait function forces the parent to wait until its child is finished and returns the pid of the child process to the parent. If there are no child processes, wait returns a –1.[11]

[11] The waitpid function also waits for a child process to finish execution, but it can specify which child it will wait for, and it has special flags that control blocking.

Format

wait;

Example 18.52.

(The Script)
1   $return_val=fork;
2   if ( $return_val == 0 ){        # In child
       print "This is the child process; return value
           is $return_val.\n";
3      exec "/bin/date" || die "exec failed: $!\n";
    }
4   elsif ( defined $return_val ){   # In parent
       print "This is the parent process; return value is $pid.\n";
5      $pid = wait;
       print "Back in parent process.\n";
       print "The deceased child's pid is $pid.\n";
    }
    else{
6      die "fork error: $!\n";
    }

(Output)
4   This is the parent process; return value is 3530.
2   This is the child process; return value is 0.
3   Wed May 30 23:57:18 PST 2007.
5   Back in the parent process.
    The deceased child's pid is 3530.

					  

Explanation

  1. The fork function creates a copy of the current process. Now there are two processes running, the parent Perl process and the child Perl process. They are both executing the code directly following the fork call. The return value is assigned 0 in the child and the pid of the child in the parent.

  2. If in the child process, the if statement block is executed.

  3. The exec function executes the UNIX date command and does not return.

  4. If in the parent process, the elsif statement block is executed. The value of $return_val is the pid of the child process.

  5. The wait function is called by the parent, which waits for the child to finish. The pid of the deceased child is returned.

  6. If the fork failed (no more processes?), the die function will print the error message and the program will exit.


The exit Function

The exit function causes the program to exit. It can be given an integer argument ranging from values between zero and 255. The exit value is returned to the parent process via the wait function call. By convention, UNIX programs exiting with a zero status are successful, and those exiting with nonzero failed in some way. (Of course, the criteria for success for one programmer may not be the same as those for another.)

Format

exit (Integer);
exit Integer;

Example 18.53.

(The Script)
    # The name of the script is args.p
1   exit 12 if $#ARGV == 0;

(Output)
1   $ args.p
2   $ echo $?
    12

Explanation

  1. The script is missing an argument.

  2. The shell's $? variable contains the exit status of the Perl program. If using C shell, the exit status is stored in $status.


18.2.9. Process Creation Win32

You can use the system and exec functions and backquotes on Win32 systems just the same as you would with UNIX.

The start Command

The Perl system function is used by both Windows and UNIX to start an operating system command. The system function executes a program and doesn't return until that program finishes. If the Windows start command is given as an argument to the Perl system function, a new application will run, and your script will also continue to run.

Example 18.54.

    use warnings;
1   $return_value = system ("start /Program
Files/Netscape/Communicator/Program/netscape.exe");

2   print "Program continues; Netscape is running.\n";
3   print "The return_value from system is $return_value.\n";

(Output)
Program continues; Netscape is running.
The return_value from system is 0.

Explanation

  1. The Perl system function starts a new process. By using the Win32 start command, you can start a new process, and the Perl script will continue to run rather than waiting for the new process to complete. If the process starts up successfully, a return value of 0 is returned by the system function.

  2. Netscape Communicator has started up and will continue to run until its window is closed.

  3. The return value from the system function is printed.

The Win32::Spawn Module

The Win32::Spawn function behaves like the system function and the Windows Start menu.

Format

use Win32;
Win32::Spawn($ProgramName, $CommandLine,$ProcessID);

Example 18.55.

1   use warnings;
2   use Win32;
3   $|=1;
4   $Application="C:/mksnt/date.exe";
5   $CommandLine="date +%D";
6   $status=Win32::Spawn($Application, $CommandLine, $ProcessID);
7   if ($status != 0){
8      print "pid is $ProcessID.\n";
    }
    else{
9      print "Didn't spawn $Application.\n";
10     print Win32::FormatMessage(Win32::GetLastError);
    }

(Output)
8 pid is 448.
11/01/00

Explanation

  1. The warnings pragma will send syntactic warnings, unitialized values, etc., to help with possible problems that may occur in the program.

  2. The Win32 module is loaded. This is a module that comes with ActiveState and is found in the standard Perl library under the site/lib/Win32 directory. It contains a number of useful modules for Windows programmers to handle servers, clients, registries, events, network administration, processes, and more.

  3. The special scalar $| is assigned the value 1. It ensures that the output buffers will be flushed immediately when the print function is used.

  4. The application is the MSK toolkit,[a] found on the C:\ drive. This toolkit contains .exe files that emulate UNIX commands. The date.exe file produces today's date.

  5. The command line consists of any arguments that will be passed to the application.

  6. The Win32::Spawn function is called with three arguments. Two of them have been given values, but $ProcessID is not known. It will be given a value after the application is started.

  7. If the status returned from the Win32::Spawn function is not 0, the process ID number will be printed.

  8. The process ID number is 448.

  9. Didn't spawn C:/mksnt/date.exe. is displayed if the .exe file doesn't exist.

  10. If the process couldn't be started because the application doesn't exist, the GetLastError function prints:

    The system cannot find the file specified.
    Program continues to run....

    This is a Windows-generated error caused when the operating system failed to start the program. The FormatMessage function creates a readable printout of the error.

[a] MSK Toolkit for Windows NT and Windows 95 Release 6.1, Mortice Kern Systems Inc.


[a] MSK Toolkit for Windows NT and Windows 95 Release 6.1, Mortice Kern Systems Inc.

The Win32::Process Module

Another extension you can use to launch Windows applications is the object-oriented Win32::Process module. It provides a number of methods for creating and managing processes. Processes can be suspended, resumed, and killed with this module.

Table 18.12. Win32::Process Methods
MethodWhat It Does
Create($Obj, $AppName, $CommandLine, $Inherit, $CreateFlags, $InitialDir);Creates the process object
$Obj–>GetExitCode($ExitCode);Gets the exit code of the process
$Obj–>GetPriorityClass($Class);Gets the process priority class
$ProcessObj–>GetProcessID()Returns the process ID
$Obj–>Kill($ExitCode);Kills the process with exit code
$Obj–>Resume();Resumes a suspended process
$Obj–>SetPriorityClass($Class);Sets the process affinity mask (NT)
$Obj–>Suspend();Suspends the process
$Obj–>Wait($Timeout);Waits for the process to die


Example 18.56.

1   use Win32::Process;
2   use Win32;
3   sub ErrorReport{
        print Win32::FormatMessage( Win32::GetLastError() );
    }

4   Win32::Process::Create($ProcessObj,
        "C:\\windows\\notepad.exe", "notepad myfile.txt", 0,
        NORMAL_PRIORITY_CLASS, ".") || die ErrorReport();
    print "Notepad has started\n";
5   print "The exit code is:
        ",$ProcessObj->GetExitCode($ExitCode),"\n";

(Output)
Notepad has started
The exit code is: 1

Explanation

  1. The Win32::Process module is loaded. It is used to launch Windows applications.

  2. The Win32 module is loaded.

  3. The ErrorReport function will send a formatted error message for the last system error that occurred, if there was one.

  4. The Create function creates a process. The first argument, $ProcessObj, is a container for the process object, followed by the full pathname of the application, command-line arguments, and required flags.

  5. The exit code of the process is returned.

Previous Page Next Page