• web pages for usp and its programs
  • GNU make document
  • exercise 1: write a simple C program to sum the arguments
             $ cat ex1.c 
             #include <stdio.h>
             
             main(int argc, char *argv[])
             {
               int i, sum, n;
               sum = 0;
               for(i=1; i<argc; i++){
                 // ... omitted.  
               }
               printf("%d\n", sum);
             }
             $ gcc ex1.c 
             $ ./a.out 
             0
             $ ./a.out 1 2 3 100
             106
             $ ./a.out -1 1 200
             200
             $ 
             
    • Your program should be put under ~/usp-1022/exer1.
    • Deadline : 2014/Feb/25, 00:10 am
  • exercise 2: probing argv[] and environ[]
    • This exercise asks you to list the values of argc, argv[] and environ[]. Also show the addresses of argc, argv, and environ. And finally show the values of argv[] and environ[]. From the display results, you can draw a picture of how argc, argv[], and environ[] are stored.
              $ env -i A=2 B=3 ./a.out hello milk
              argc is 3
              argv[0]: ./a.out
              argv[1]: hello
              argv[2]: milk
              environ[0]: A=2
              environ[1]: B=3
              
              argc      is resided at ffbfff0c
              argv      is resided at ffbfff10
              environ   is resided at 20af8
              argv[]    is resided at ffbfff2c
              environ[] is resided at ffbfff3c
              value of argv[ 0] is ffbfffc8
              value of argv[ 1] is ffbfffd0
              value of argv[ 2] is ffbfffd6
              value of argv[ 3] is 0
              value of env [ 0] is ffbfffdb
              value of env [ 1] is ffbfffdf
              $
              
    • Your program should be put under ~/usp-1022/exer2.
    • Deadline : 2014/Mar/04, 00:10 am
  • exercise 3: simulating env
    • Refer to section 2.12.
    • You have to support at least the following four usages.
             $ env                  
             $ env cmd arg1 arg2 ....
             $ env -i
             $ env -i e1=v1 e2=v2 .... cmd arg1 arg2 ....
             
    • Note that there may be more than one environment string and there may be more than one argument for the cmd. To invoke system(), you have to combine `cmd' and all the `arg1 arg2 ....' to a single string, which is then passed to system().
    • Due: 2014/Mar/11,
      You have to put your files under ~/usp-1022/exer3.
  • exercise 4: forking a process tree
    • Use fork() to create a process tree. Each process of the tree shows one line and the lines are printed in post-order.
    • The order between message lines can be achieved by wait().
    • The first argument is a binary string which denotes the internal path of the tree. The O means traversing left and 1 right. For example, "101" means that from the root the path first traverses right, then left, and right. Since the length is 3, there are 4 internal nodes. Append 5 more external nodes and the tree is completed.
                            I
                           / \\  <--- (1)
                          E   I
                   (0) ---> // \
                            I   E
                           / \\ <-----(1)
                          E   I
                             / \
                            E   E
           
      Each internal node shows something like
             I'm ..., my two children is ... and  ....
           
      And each external nodes show something like
             I'm ..., my parent is ...
           
      Following is a sample output.
           $ ./a.out ""
           I'm 1054, my parent is 1053                  |     1053
           I'm 1055, my parent is 1053                  |     /  \
           I'm 1053, my two children is 1054 and 1055   |   1054 1055
           $ ./a.out "1"                                |    
           I'm 1057, my parent is 1056                  |      1056
           I'm 1059, my parent is 1058                  |       / \\
           I'm 1060, my parent is 1058                  |    1057  1058
           I'm 1058, my two children is 1059 and 1060   |           / \
           I'm 1056, my two children is 1057 and 1058   |        1059 1060
           $ ./a.out "10"                               |     
           I'm 1062, my parent is 1061                  |       1061
           I'm 1065, my parent is 1064                  |       /  \\
           I'm 1066, my parent is 1064                  |     1062 1063
           I'm 1064, my two children is 1065 and 1066   |         //  \
           I'm 1067, my parent is 1063                  |      1064  1067
           I'm 1063, my two children is 1064 and 1067   |        / \
           I'm 1061, my two children is 1062 and 1063   |     1065 1066
           $ 
           
    • Due day, 2014/March/18 00:05am
    • Please put your program under ~/usp-1022/exer4.
  • exercise 5: practicing wait()
    • Refer to the description of exercise 2 (usp-982) for explanation of the code .
    • Remove the wait(NULL) in the loop. After the line of printing a message to stderr, you should insert code like:
      If the process is a leaf,
                   while(1) pause();
                
      else (the process is an internal node)
                   while there are children alive do 
                      waiting..
                   exit(...);   
                
    • The internal node should wait for all children, and for each child, when waited, reports the signal number if it was terminated by a signal, or the value returned if it exited though exit(). In either case, a number is gained from the child. Those numbers from children are summed and the sum is used as the argument of exit(). This is to say the sum is the return value of this process.
      Refer to example 3.22 for the usage of wait().
    • To test your program, you have to open another window through which you can kill a process with the command `kill'.
      For example, to kill a process which pid is 12011 with signal 15, you can type 'kill -15 12011'.
    • Due: 2014/Mar/25, 00:05
    • For example:
              $ ./a.out ddduuduu abcd
              I'm c, my pid=3590, and my ppid=3589
              I'm b, my pid=3589, and my ppid=3588
              I'm d, my pid=3591, and my ppid=3588
              I'm a, my pid=3588, and my ppid=3295
              Child 3590 is terminated with signal 3.       $ kill -3 3590
              Child 3589 exits with value 3.
              Child 3591 is terminated with signal 2.       $ kill -2 3591
              $ echo $?                            # Check the return value of root.
              5                                    # It is the sum of 2 and 3.
              $ ./a.out ddduuduu abcd              # Run it agagin.
              I'm c, my pid=3594, and my ppid=3593 # This time we try to kill the 
              I'm b, my pid=3593, and my ppid=3592 # internal node. The leaf node will
              I'm d, my pid=3595, and my ppid=3592 # be an orphan and be adopted by init.
              I'm a, my pid=3592, and my ppid=3295 
              Child 3593 is terminated with signal 4.       $ kill -4 3593
              Child 3595 is terminated with signal 15.      $ kill -15 3595
              $ echo $?
              19
              $ ps -ef | grep a.out                # Find the orphan. Check its ppid.
              klim      3594     1  0 13:39 pts/0    00:00:00 ./a.out ddduuduu abcd
              klim      3597  3295  0 13:40 pts/0    00:00:00 grep a.out
              $ 
              
  • exercise 6: simulating `cat'
    • Description: Please refer to section 4.10.
      Your `cat' should be capable of being invoked as
       
             $ ./mycat file1 file2 file3 ..    # reading from files, files1..
             $ ./mycat                         # reading from stdin.
             
    • Deadline: 2014 Apr 1 00:05am
    • Put your file(s) under ~/usp-1022/exer6
    • Only read(), write() and the functions defined in text are allowed. You have to practice them.
  • exercise 7: practicing pipe()
    • Build a process tree like exercise 5, but two pipes are created between a parent and each one of its children. One pipe is for parent's sending to child, the other is for child's sending to the parent.
    • Each process will print two lines. The first line is printed in preorder and the second in post-order.
    • Due: 2014/Apr/15, 00:05
    • For example:
             $ ./a.out ddduduuduu abcde
             I'm a, my pid=27828, and my ppid=27682
             I'm b, my pid=27829, and my ppid=27828
             I'm c, my pid=27830, and my ppid=27829
             I'm d, my pid=27832, and my ppid=27829
             I'm e, my pid=27831, and my ppid=27828
             I'm c, my pid=27830, and my ppid=27829
             I'm d, my pid=27832, and my ppid=27829
             I'm b, my pid=27829, and my ppid=27828
             I'm e, my pid=27831, and my ppid=27828
             I'm a, my pid=27828, and my ppid=27682
             $ 
             
  • exercise 8: practicing select() or poll()
    • Generate a bidirectional ring. Refer to program 7.1. The argv[1] specified the number of processes.
    • After the ring is setup, the root process then does
                loop
                  read from stdin 
                  if got 'l' then 
                    generate 12 random numbers between 1 to 49
                    send them to the clockwise next process
                    read 12 numbers from clockwise previous process
                    write the first six out
                  if got 'p' then 
                    write a token to the anti-clockwise next process
                    read a token from anti-clockwise previous process
                end loop
             
      Each child does
               loop
                 monitor two inputs simultaneously 
                 (one clockwise and another anti-clockwise)
                 if clockwise input is ready then 
                   read 12 numbers from clockwise previous process
                   show them
                   randomly generate a, b
                   swap a-th and b-th numbers
                   write 12 numbers to clockwise next process
                 if anti-clockwise input is ready then
                   read a token from anti-clockwise previous process
                   show the a, b (previously generated random numbers)
                   write a token to the anti-clockwise next process
               end loop
             
    • Note that the seeds used to generate random sequences should be distinct.
    • You may design a method with which all process can be terminated gracefully.
    • Due: 2014/Apr/22, 00:05
    • For example:
             $ ./a.out 6     <----- one root, five children
             l
              29 48 41 21 31 16  4  7 33 20 30 10
              29 48 21 41 31 16  4  7 33 20 30 10
              31 48 21 41 29 16  4  7 33 20 30 10
              31  7 21 41 29 16  4 48 33 20 30 10
              31  7 21 41 29 16  4 48 33 30 20 10
             The six balls: 48  7 21 41 29 16
             p
             It is time to list the random numbers.
             I'am 11970 and my random numbers are  0 and  7
             I'am 11969 and my random numbers are  9 and 10
             I'am 11968 and my random numbers are  7 and  1
             I'am 11967 and my random numbers are  4 and  0
             I'am 11966 and my random numbers are  2 and  3
             l
              37 42 41  2  5 32 29 31 13 17 25 20
              37 42 41  2  5 25 29 31 13 17 32 20
              37 42 41  2  5 13 29 31 25 17 32 20
              37 42 41  2  5 13 29 31 20 17 32 25
              37 42  2 41  5 13 29 31 20 17 32 25
             The six balls: 37 42  2 13  5 41
             p
             It is time to list the random numbers.
             I'am 11970 and my random numbers are  3 and  5
             I'am 11969 and my random numbers are  3 and  2
             I'am 11968 and my random numbers are  8 and 11
             I'am 11967 and my random numbers are  8 and  5
             I'am 11966 and my random numbers are  5 and 10
             q
             $
             
  • exercise 9: writing signal handlers
    • Generate a ring. Refer to program 7.1. The argv[1] specified the number of processes.
    • After the ring is setup, each process then does
                loop
                  read from pipe the pid and message
                  write a line, showing the received pid and the message
                  if the received pid is not equal to myself then
                    write the pid and message to pipe
                end loop
             
    • Each process should handle three signals. When got a signal, the handler writes to pipe the process's pid and a message.
    • You may reserve a signal to terminate all processes gracefully.
    • Due: 2014/Apr/29, 00:05
    • For example:
             $ ./a.out 4                          ------ another window -------
             root pid is 13453
             I am 13456. I got 13453 with id a        $ kill -USR1 13453
             I am 13455. I got 13453 with id a
             I am 13454. I got 13453 with id a
             I am 13453. I got 13453 with id a
             I am 13453. I got 13454 with id b        $ kill -USR2 13454
             I am 13456. I got 13454 with id b
             I am 13455. I got 13454 with id b
             I am 13454. I got 13454 with id b
             I am 13454. I got 13455 with id a        $ kill -USR1 13455 13454
             I am 13453. I got 13454 with id a
             I am 13453. I got 13455 with id a
             I am 13456. I got 13454 with id a
             I am 13456. I got 13455 with id a
             I am 13455. I got 13454 with id a
             I am 13455. I got 13455 with id a
             I am 13454. I got 13454 with id a
             I am 13455. I got 13456 with id q        $ kill -INT  13456
             I am 13454. I got 13456 with id q
             I am 13453. I got 13456 with id q
             I am 13456. I got 13456 with id q
             $ 
             
  • exercise 10: waiting for signals
    • Generate a process tree, just like exercise 5.
    • Each process waits for three signals. One of them is for initiating a pre-order traversal. When the signal is received, the process shows its message and notifies its children to show their messages. The notification to and acknowledgement from children are handled by sending signals and receiving signals. That is, the notifying and acknowledging use another two signals.
    • Due: 2014/May/06 00:05
    • For example:
                                 a
                                / \
                               b   c
             the tree             / \
                                 d   e
                                    / \
                                   f   g
             $ ./a.out dduddudduduuuu abcdefg
             I'm root, my pid=18891
             I'm a, my pid=18891, and my ppid=18799        $ kill -INT 18891
             I'm b, my pid=18892, and my ppid=18891
             I'm c, my pid=18893, and my ppid=18891
             I'm d, my pid=18894, and my ppid=18893
             I'm e, my pid=18895, and my ppid=18893
             I'm f, my pid=18896, and my ppid=18895
             I'm g, my pid=18897, and my ppid=18895
             I'm e, my pid=18895, and my ppid=18893        $ kill -INT 18895
             I'm f, my pid=18896, and my ppid=18895
             I'm g, my pid=18897, and my ppid=18895
             I'm c, my pid=18893, and my ppid=18891        $ kill -INT 18893
             I'm d, my pid=18894, and my ppid=18893        
             I'm e, my pid=18895, and my ppid=18893
             I'm f, my pid=18896, and my ppid=18895
             I'm g, my pid=18897, and my ppid=18895
             I'm d, my pid=18894, and my ppid=18893        $ kill -INT 18894
             Terminated                                    $ kill -15 -18891
             $ 
             
  • exercise 11: asynchrous read and write
    • Refer to 8.10.
    • The main function just reads from stdin and writes to stdout while the signal handlers maintain the file copying. The scenario may be like:
      
             $ ./a.out  infile  outfile    <----- copy infile to outfile
             hello i'm klim                       with async read and async write
             hello i'm klim        <---- read stdin and echo it to stdout ...
             ...
             ...
             [Copy completed]      <------ when the copy is completed, show something 
             ..                            to screen
             ..
             ^D
             $
             
    • In order to simulate a slow device, I have modified the periodicasterisk.c in text such that it will read characters from stdin and write them to stdout in the rate of n characters per second.
      Through a fifo, this program can be used as follows.
       
             1st shell:
             $ ./periodicchars 12  < FIFO
             ....... <---- the contents of infile is shown here 
             in the rate of 12 chars per second
      
             2nd shell:
             $ ./a.out infile FIFO  <-----   the contents of infile is sent 
             hello klim                      to FIFO
             hello klim 
             .......
             
    • Due: 2014/May/13 00:05
    • Check the man page of aio_read. An additional library is required.
  • exercise 12: pthread creating and joining
    • Refer to Chapter 12.
    • The main thread creates 6 threads each of which will generate 100 numbers between 0 and 41. The main thread then joins them and collects the 600 numbers. The numbers are viewd as 300 pairs. Each pair of numbers is used to swap the elements of an array which is initialized as num[i]=i+1, i=0..41. Finally the main thread prints out the first six numbers.
    • Each thread should use different seeds and you should use thread-safe random functions, such as erand48() or nrand48().
             $ gcc ex-12.c -lpthread
             $ ./a.out 
             The balls are  29 42 35 37  5 14
             $ ./a.out 
             The balls are  12 10 15 22  9 34
             $ ./a.out 
             The balls are   6 20 28 35  2 11
             $ ./a.out 
             The balls are  39  4 22 41 17 14
             $ ./a.out 
             The balls are  39  1 20 26 42 13
             $ ./a.out 
             The balls are  11 42 28  2 26  9
             $ 
             
    • Due: 2014/May/27 00:05
  • exercise 13: pthread synchronizing(mutex and cond)
    • Refer to Chapter 13.
    • The main thread creates 6 threads. The main thread reads from stdin. When it reads a 'l', it will ask each of the six threads to generate a random number between 1 and 42. The main thread then check if they are all different. If some of them are equal, the main thread may ask again to get another numbers. Finally six distinct numbers are got and printed to stdout.
      The main thread continues until it reads a 'q'.
    • Each thread should use different seeds and you should use thread-safe random functions, such as erand48() or nrand48().
             $ gcc ex-13.c -lpthread
             $ ./a.out 
             l
             The balls are:  14 41 12 25 11 24
             l
             The balls are:  18 21 28 41 19 39
             l
             The balls are:  20 41 32 23 29 15
             l
             The balls are:  11 15 28 16  2 18
             q
             $ 
             
    • Due: 2014/Jun/03 00:05