Pages

Wednesday, June 8, 2011

wait() System Call

The wait() System Call

The system call wait() is easy. This function blocks the calling process until one of its child processes exits or a signal is received. For our purpose, we shall ignore signals. wait() takes the address of an integer variable and returns the process ID of the completed process. Some flags that indicate the completion status of the child process are passed back with the integer pointer. One of the main purposes of wait() is to wait for completion of child processes.
The execution of wait() could have two possible situations.
  1. If there are at least one child processes running when the call to wait() is made, the caller will be blocked until one of its child processes exits. At that moment, the caller resumes its execution.
  2. If there is no child process running when the call to wait() is made, then this wait() has no effect at all. That is, it is as if no wait() is there.
Consider the following program. Click here to download a copy of this file fork-03.c.

#include  <stdio.h>
#include  <string.h>
#include  <sys/types.h>

#define   MAX_COUNT  200
#define   BUF_SIZE   100

void  ChildProcess(char [], char []);    /* child process prototype  */

void  main(void)
{
     pid_t   pid1, pid2, pid;
     int     status;
     int     i;
     char    buf[BUF_SIZE];

     printf("*** Parent is about to fork process 1 ***\n");
     if ((pid1 = fork()) < 0) {
          printf("Failed to fork process 1\n");
          exit(1);
     }
     else if (pid1 == 0) 
          ChildProcess("First", "   ");

     printf("*** Parent is about to fork process 2 ***\n");
     if ((pid2 = fork()) < 0) {
          printf("Failed to fork process 2\n");
          exit(1);
     }
     else if (pid2 == 0) 
          ChildProcess("Second", "      ");

     sprintf(buf, "*** Parent enters waiting status .....\n");
     write(1, buf, strlen(buf));
     pid = wait(&status);
     sprintf(buf, "*** Parent detects process %d was done ***\n", pid);
     write(1, buf, strlen(buf));
     pid = wait(&status);
     printf("*** Parent detects process %d is done ***\n", pid);
     printf("*** Parent exits ***\n");
     exit(0);
}

void  ChildProcess(char *number, char *space)
{
     pid_t  pid;
     int    i;
     char   buf[BUF_SIZE];

     pid = getpid();
     sprintf(buf, "%s%s child process starts (pid = %d)\n", 
             space, number, pid);
     write(1, buf, strlen(buf));
     for (i = 1; i <= MAX_COUNT; i++) {
          sprintf(buf, "%s%s child's output, value = %d\n", space, number, i); 
          write(1, buf, strlen(buf));
     }
     sprintf(buf, "%s%s child (pid = %d) is about to exit\n", 
             space, number, pid);
     write(1, buf, strlen(buf));     
     exit(0);
}
This program shows some typical process programming techniques. The main program creates two child processes to execute the same printing loop and display a message before exit. For the parent process (i.e., the main program), after creating two child processes, it enters the wait state by executing the system call wait(). Once a child exits, the parent starts execution and the ID of the terminated child process is returned in pid so that it can be printed. There are two child processes and thus two wait()s, one for each child process. In this example, we do not use the returned information in variable status.However, the parent does not have to wait immediately after creating all child processes. It may do some other tasks. The following is an example. Click here for this file fork-04.c.

#include  <stdio.h>
#include  <string.h>
#include  <sys/types.h>

#define   MAX_COUNT  200
#define   BUF_SIZE   100

void  ChildProcess(char [], char []);    /* child process prototype  */
void  ParentProcess(void);               /* parent process prototype */

void  main(void)
{
     pid_t   pid1, pid2, pid;
     int     status;
     int     i;
     char    buf[BUF_SIZE];

     printf("*** Parent is about to fork process 1 ***\n");
     if ((pid1 = fork()) < 0) {
          printf("Failed to fork process 1\n");
          exit(1);
     }
     else if (pid1 == 0) 
          ChildProcess("First", "   ");

     printf("*** Parent is about to fork process 2 ***\n");
     if ((pid2 = fork()) < 0) {
          printf("Failed to fork process 2\n");
          exit(1);
     }
     else if (pid2 == 0) 
          ChildProcess("Second", "      ");

     ParentProcess();
     sprintf(buf, "*** Parent enters waiting status .....\n");
     write(1, buf, strlen(buf));
     pid = wait(&status);
     sprintf(buf, "*** Parent detects process %d was done ***\n", pid);
     write(1, buf, strlen(buf));
     pid = wait(&status);
     printf("*** Parent detects process %d is done ***\n", pid);
     printf("*** Parent exits ***\n");
     exit(0);
}

#define  QUAD(x)  (x*x*x*x)

void  ParentProcess(void)
{
     int  a, b, c, d;
     int  abcd, a4b4c4d4;
     int  count = 0;
     char buf[BUF_SIZE];

     sprintf(buf, "Parent is about to compute the Armstrong numbers\n");
     write(1, buf, strlen(buf));
     for (a = 0; a <= 9; a++)
          for (b = 0; b <= 9; b++)
               for (c = 0; c <= 9; c++)
                    for (d = 0; d <= 9; d++) {
                         abcd     = a*1000 + b*100 + c*10 + d;
                         a4b4c4d4 = QUAD(a) + QUAD(b) + QUAD(c) + QUAD(d);
                         if (abcd == a4b4c4d4) {
                              sprintf(buf, "From parent: "
                                      "the %d Armstrong number is %d\n",
                                      ++count, abcd);
                              write(1, buf, strlen(buf));
                         }
                    }
     sprintf(buf, "From parent: there are %d Armstrong numbers\n", count);
     write(1, buf, strlen(buf));
}

void  ChildProcess(char *number, char *space)
{
     pid_t  pid;
     int    i;
     char   buf[BUF_SIZE];

     pid = getpid();
     sprintf(buf, "%s%s child process starts (pid = %d)\n", 
             space, number, pid);
     write(1, buf, strlen(buf));
     for (i = 1; i <= MAX_COUNT; i++) {
          sprintf(buf, "%s%s child's output, value = %d\n", 
                  space, number, i); 
          write(1, buf, strlen(buf));
     }
     sprintf(buf, "%s%s child (pid = %d) is about to exit\n", 
             space, number, pid);
     write(1, buf, strlen(buf));
     exit(0);
}
The main program creates two child processes. Both processes call function ChildProcess(). The main program, the parent process, calls function ParentProcess(). This function computes all Armstrong numbers in the range of 0 and 9999. An Armstrong number in the range of 0 and 9999 is an integer whose value is equal to the sum of its digits raised to the fourth power. After this, the parent enters the wait state, waiting for the completion of its child processes. Note that since we have two processes running concurrently, we have no way to predict which one will terminate first and hence waiting for a specific child process is a risky move. This is why we don't have a "specific" wait in all of the previous programs.Warning: Although theoretically you can create as many processes as you want, systems always have some limits. Therefore, always check to see if the returned value of fork() is negative and report the result. If this does happen, try to reduce the number of child processes, or re-organize your program.
If the returned pid is unimportant, we can treat function wait() as a procedure. The following code is a simple modification to the last few statements (in the main function) of the previous example.

sprintf(buf, "*** Parent enters waiting status .....\n");
write(1, buf, strlen(buf));
wait(&status);
sprintf(buf, "*** Parent detects a child process was done ***\n");
write(1, buf, strlen(buf));
wait(&status);
printf("*** Parent detects another child process was done ***\n");
printf("*** Parent exits ***\n");
Click here to download a copy of this modified program (file fork-05.c).

execvp() System call

Execute a Program: the execvp() System Call

The created child process does not have to run the same program as the parent process does. The exec type system calls allow a process to run any program files, which include a binary executable or a shell script. On this page, we only discuss one such system call: execvp(). The execvp() system call requires two arguments:
  1. The first argument is a character string that contains the name of a file to be executed.
  2. The second argument is a pointer to an array of character strings. More precisely, its type is char **, which is exactly identical to the argv array used in the main program:

    int  main(int argc, char **argv)
    
    Note that this argument must be terminated by a zero.
When execvp() is executed, the program file given by the first argument will be loaded into the caller's address space and over-write the program there. Then, the second argument will be provided to the program and starts the execution. As a result, once the specified program file starts its execution, the original program in the caller's address space is gone and is replaced by the new program.
execvp() returns a negative value if the execution fails (e.g., the request file does not exist).
The following is an example (in file shell.c). Click here to download a copy.

#include  <stdio.h>
#include  <sys/types.h>

void  parse(char *line, char **argv)
{
     while (*line != '\0') {       /* if not the end of line ....... */ 
          while (*line == ' ' || *line == '\t' || *line == '\n')
               *line++ = '\0';     /* replace white spaces with 0    */
          *argv++ = line;          /* save the argument position     */
          while (*line != '\0' && *line != ' ' && 
                 *line != '\t' && *line != '\n') 
               line++;             /* skip the argument until ...    */
     }
     *argv = '\0';                 /* mark the end of argument list  */
}

void  execute(char **argv)
{
     pid_t  pid;
     int    status;

     if ((pid = fork()) < 0) {     /* fork a child process           */
          printf("*** ERROR: forking child process failed\n");
          exit(1);
     }
     else if (pid == 0) {          /* for the child process:         */
          if (execvp(*argv, argv) < 0) {     /* execute the command  */
               printf("*** ERROR: exec failed\n");
               exit(1);
          }
     }
     else {                                  /* for the parent:      */
          while (wait(&status) != pid)       /* wait for completion  */
               ;
     }
}

void  main(void)
{
     char  line[1024];             /* the input line                 */
     char  *argv[64];              /* the command line argument      */

     while (1) {                   /* repeat until done ....         */
          printf("Shell -> ");     /*   display a prompt             */
          gets(line);              /*   read in the command line     */
          printf("\n");
          parse(line, argv);       /*   parse the line               */
          if (strcmp(argv[0], "exit") == 0)  /* is it an "exit"?     */
               exit(0);            /*   exit if it is                */
          execute(argv);           /* otherwise, execute the command */
     }
}
Function parse() takes an input line and returns a zero-terminated array of char pointers, each of which points to a zero-terminated character string. This function loops until a binary zero is found, which means the end of the input line line is reached. If the current character of line is not a binary zero, parse() skips all white spaces and replaces them with binary zeros so that a string is effectively terminated. Once parse() finds a non-white space, the address of that location is saved to the current position of argv and the index is advanced. Then, parse() skips all non-whtitespace characters. This process repeats until the end of string line is reached and at that moment argv is terminated with a zero.
For example, if the input line is a string as follows:

"cp  abc.CC   xyz.TT"
Function parse() will return array argv[] with the following content:

Function execute() takes array argv[], treats it as a command line arguments with the program name in argv[0], forks a child process, and executes the indicated program in that child process. While the child process is executing the command, the parent executes a wait(), waiting for the completion of the child. In this special case, the parent knows the child's process ID and therefore is able to wait a specific child to complete.
The main program is very simple. It prints out a command prompt, reads in a line, parses it using function parse(), and determines if the name is "exit". If it is "exit", use exit() to terminate the execution of this program; otherwise, the main uses execute() to execute the command.

Monday, June 6, 2011

香港網友揭穿64大騙局系列(3)


何謂「平反64」?
http://hk.myblog.yahoo.com/64-truth/article?mid=4
個人認為, 支聯會叫囂近20年「平反64」, 是法、理基礎並未足夠

在西方國家, 當政者從來也甚少會為反思自己的歷史錯誤反思、認錯、或道歉;  例如﹕英國不會為自己過去二百多年來的侵略殖民行為道歉, 美國也不會為當年派遣八國聯軍侵略中國進行反思, 亦不曾對攻略伊拉克道歉。

所謂平反一件歷史事件, 是一件非常重大的政治行為,  支聯會叫「平反六四」背後亦有一套政治邏輯﹐就是認為六四是「愛國民主運動」, 不是「暴亂」, 所以宣佈戒嚴的決定是錯的,  武力清場的決定是錯的﹐而武力清場的本質就是「鎮壓」﹐一些人更用上「屠殺」一字。

但是, 要將一件歷史事件定性, 每一件歷史事件爆發的發展、過程, 亦是不能被忽略的, 而平反過程也須要按法理程序進行, 並非能夠透過感情渲染、叫囂就能達到

因此, 首要條件是, 大家就須要分析64的「愛國民主」成份


香港網友揭穿64大騙局系列(2)


平反六四的謬誤
http://hk.myblog.yahoo.com/standfortruth8964/article?mid=199
關於平反六四, 支聯會存在著很多荒謬:


«中國系列» ‹六四睇真D› 司徒華講六四真相
http://www.youtube.com/watch?v=7-oum_9YcNk



1) 平反六四~~> 要求公開真相

早在20年前大陸已公開的調查報告及有關錄影資料(我都係最近先睇到), 那裡不公開?

問題是香港人不相信? 那就不要虛偽地說: 沒公開真相, 不如講白d, 不相信中共的調查報告



香港網友揭穿64大騙局系列(1)

( ref: http://www.atlanta168.com/forum/simple/?t3280.html )



為何89年「香港電視新聞」不報導真相, 隱瞞真相?
http://hk.myblog.yahoo.com/standfortruth8964/article?mid=70


有網友陸續發現, 64當年在香港播出的電視新聞, 都有一迅間的錄影顯示, 是拍得在天安門廣場內的真相, 為何香港的傳媒一律報導「天安門廣場內屠殺3000學生」的假消息???

為何要報導假消息?






Saturday, June 4, 2011

Intro to Processes, Forks & Exec

ref: http://www.cs.uregina.ca/Links/class-info/330/Fork/fork.html

Highlights of this lab:

Preamble
Shell Commands for Process Control
System Calls for Process Control
References
Preamble

The following is taken from page 1 of Interprocess Communications in Unix:

Fundamental to all operating systems is the concept of a process. While somewhat abstract, a process consists of an executing (running) program, its current values, state information, and the resources used by the operating system to manage the execution of the process. A process is a dynamic entity. In a UNIX-based operating system, at any given point in time, multiple processes appear to be executing concurrently. From the viewpoint of each of the processes involved it appears they have access to, and control of, all system resources as if they were in their own stand-alone setting. Both viewpoints are an illusion. The majority of UNIX operating systems run on platforms that have a single processing unit capable of supporting many active processes. However, at any point in time only one process is actually being worked upon. By rapidly changing the process it is currently executing, the UNIX operating system gives the appearance of concurrent process execution. The ability of the operating system to multiplex its resources among multiple processes in various stages of execution is called multiprogramming (or multitasking). Systems with multiple processing units, which by definition can support true concurrent processing are called multiprocessing.

With the exception of some initial processes, all processes in UNIX are created by the fork system call. The initiating process is termed the parent and the newly generated process the child.

In fact, our shell is constantly forking processes.

The fork() System Call

System call fork() is used to create processes. It takes no arguments and returns a process ID. The purpose of fork() is to create a new process, which becomes the child process of the caller. After a new child process is created, both processes will execute the next instruction following the fork() system call. Therefore, we have to distinguish the parent from the child. This can be done by testing the returned value of fork():
  • If fork() returns a negative value, the creation of a child process was unsuccessful.
  • fork() returns a zero to the newly created child process.
  • fork() returns a positive value, the process ID of the child process, to the parent. The returned process ID is of type pid_t defined in sys/types.h. Normally, the process ID is an integer. Moreover, a process can use function getpid() to retrieve the process ID assigned to this process.