• web pages for usp and its programs
  • GNU make document
  • note of activation record
  • exercise 1: summing numbers in arguments
    • Figure out the sum of numbers in arguments.
    • For example:
            $ ./a.out  
            0
            $ ./a.out 1 2 3 
            6
            $ ./a.out 1 2 3 4
            10
            $ ./a.out 1 2 3 klim
            6
            $ ./a.out 1 2 3 klim 3 -1
            8
            $ ./a.out 1 2 3 klim 3 -1 9klim
            8
            $ 
          
    • deadline: 2017/Mar/1, 00:05
    • Put your files under ~/usp-1052/exer1
    • You may use strtol().
  • exercise 2: probing argv[] and environ[]
    • Write a program which prints the values of argc, argv[], and environ[]. Also their addresses are printed. Based on the printed information, one can figure out the memory layout of argc, argv[], and environ[].
    • For example:
            $ gcc ex2-argv-env.c 
            $ env -i A=99 B=101 ./a.out "Klim is milk" is wrong
            argc is 4
            argv[0]: ./a.out
            argv[1]: Klim is milk
            argv[2]: is
            argv[3]: wrong
            environ[0]: A=99
            environ[1]: B=101
            
            argc      is at 0x7fff1c6f8fbc
            argv      is at 0x7fff1c6f8fb0
            environ   is at 0x600d98
            argv[]    is at 0x7fff1c6f90b8
            environ[] is at 0x7fff1c6f90e0
            value of argv[ 0] is 0x7fff1c6fafc7
            value of argv[ 1] is 0x7fff1c6fafcf
            value of argv[ 2] is 0x7fff1c6fafdc
            value of argv[ 3] is 0x7fff1c6fafdf
            value of env [ 0] is 0x7fff1c6fafe5
            value of env [ 1] is 0x7fff1c6fafea
            $ 
          
    • deadline: 2017/Mar/08, 00:05
    • Put your files under ~/usp-1052/exer2
  • exercise 3: creating processes with fork()
    • Write a program which will create a process tree.
    • The tree is a fully binary tree. The argv[1] denotes the number of internal nodes. The internal nodes form a zig-zag line, first skew left, then right, etc.
    • For example:
            $ ./a.out 3
            I am internal 15205. My left and right are 15206 and 15207.
            I am external 15207. My parent is 15205.
            I am internal 15206. My left and right are 15208 and 15209.
            I am internal 15209. My left and right are 15210 and 15211.
            I am external 15208. My parent is 15206.
            I am external 15211. My parent is 15209.
            I am external 15210. My parent is 15209.
            ^C
            $ 
          
      Using pstree in another window to show the result.
            $ pstree -p 15205     
            a.out(15205)-+-a.out(15206)-+-a.out(15208)
                         |              `-a.out(15209)-+-a.out(15210)
                         |                             `-a.out(15211)
                         `-a.out(15207)
            $ 
          
    • To prevent the parent processes from exiting too early, put the following code into your program.
              while(1) pause();
          
    • deadline: 2017/Mar/22, 00:05
    • Put your files under ~/usp-1052/exer3
  • exercise 4: simulating `sed'
    • Simulate sed -e 's/\$/$$/g' -e 's/S/$/g' file1 file2 ......
       
            $ cat k1
            S is $. and $ is $.
            No, $ is $ but S is not $.
            $ cat k2
            $ is S and SS is $$.
            Sure! Sure. $$
            $ ./a.out k1
            $ is $$. and $$ is $$.
            No, $$ is $$ but $ is not $$.
            $ ./a.out k1 k2
            $ is $$. and $$ is $$.
            No, $$ is $$ but $ is not $$.
            $$ is $ and $$ is $$$$.
            $ure! $ure. $$$$
            $ ./a.out < k1
            $ is $$. and $$ is $$.
            No, $$ is $$ but $ is not $$.
            $
            
    • Deadline: 2017 Mar 29 00:05am
    • Put your file(s) under ~/usp-1052/exer4
    • Only read(), write() and the functions defined in text are allowed.
  • exercise 5: practicing pipe()
    • Refer to the description of exercise 2 (usp-982) for explanation of code .
    • Use the code shown above to build a process tree, 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.
    • After created, each process will do something as follows.
            loop
              if root then  ch = get a char from stdin
                      else  ch = get a char from parent
      
              rep = FAIL
              if ch == label then
                rep = OK
              else
                for child in children do
                  send ch to child
                  retcode = get the response from child
                  if retcode == OK then
                    rep = OK
      
              if rep == OK then  show the line
              if not root  then  send rep to parent
            forever
            
    • For example:
            $ ./a.out ddudduduuduu abcefd
            a
            I'm a, my pid=7155, and my ppid=6036
            f
            I'm f, my pid=7160, and my ppid=7157
            I'm c, my pid=7157, and my ppid=7155
            I'm a, my pid=7155, and my ppid=6036
            e
            I'm e, my pid=7159, and my ppid=7157
            I'm c, my pid=7157, and my ppid=7155
            I'm a, my pid=7155, and my ppid=6036
            d
            I'm d, my pid=7158, and my ppid=7155
            I'm a, my pid=7155, and my ppid=6036
            q
            b
            I'm b, my pid=7156, and my ppid=7155
            I'm a, my pid=7155, and my ppid=6036
            ^C
            $
            
    • Deadline: 2017 Apr 5 00:05am
    • Put your file(s) under ~/usp-1052/exer5
  • exercise 6: traversing directories
    • Refer to Chapter 5.8, example 5.37.
    • Only depth first version is required. For example,
            $ tree /var/tmp/test-dir-usp-ex6/
            /var/tmp/test-dir-usp-ex6/
            |-- garden
            |   |-- flower
            |   |-- grass
            |   `-- kitty
            |-- milk
            `-- pool
                |-- fish
                |   |-- dragon
                |   `-- salmon
                `-- frog
            
            3 directories, 7 files
            $ ./a.out /var/tmp/test-dir-usp-ex6 
            /var/tmp/test-dir-usp-ex6
                garden
                    grass
                    kitty
                    flower
                pool
                    fish
                        dragon
                        salmon
                    frog
                milk
            $  
            
    • Deadline: 2017 Apr 12 00:05am
    • Put your file(s) under ~/usp-1052/exer6
  • exercise 7: 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 'f' then 
                    send 0 1 to the clockwise next process
                    read two numbers from clockwise previous process
                    write them out
                  if got 'p' then 
                    write a token to the anti-clockwise next process
                    read a token from anti-clockwise previous process
                    show pid
                end loop
             
      Each child does
               loop
                 monitor two inputs simultaneously 
                 (one clockwise and another anti-clockwise)
                 if clockwise input is ready then 
                   read two numbers, a and b, from clockwise previous process
                   show them
                   write b (a+b) to clockwise next process
                 if anti-clockwise input is ready then
                   read a token from anti-clockwise previous process
                   show pid
               end loop
             
    • You may design a method with which all process can be terminated gracefully.
    • Due: 2017/Apr/26, 00:05
    • For example:
              $ ./a.out 8
              p
              I'am  598
              I'am  596
              I'am  594
              I'am  593
              I'am  591
              I'am  590
              I'am  589
              I'am  588, the root
              f
              I am  589, I got   0   1
              I am  590, I got   1   1
              I am  591, I got   1   2
              I am  593, I got   2   3
              I am  594, I got   3   5
              I am  596, I got   5   8
              I am  598, I got   8  13
              I am root. I got  13  21
              q
              $ ./a.out 3
              p
              I'am  607
              I'am  606
              I'am  600, the root
              f
              I am  606, I got   0   1
              I am  607, I got   1   1
              I am root. I got   1   2
              q
              $ 
             
  • exercise 8: practicing sigaction()
    • Do the same thing as exercise 7. But instead of initiating operating from the root process, the 'p' or 'f' operation is initiated from any process when it is received a signal.
    • Due: 2017/May/3, 00:05
    • For example:
               $ ./a.out 8
               I am the root 17277   <---- the root shows its pid first.
               I'am 17284            <---- kill -USR2 17277, Do 'p' from 17277.
               I'am 17283
               I'am 17282
               I'am 17281
               I'am 17280
               I'am 17279
               I'am 17278
               I'am 17277.
               I am 17282, I got   0   1 <---- kill -USR1 17281, Do 'f' from 17281
               I am 17283, I got   1   1
               I am 17284, I got   1   2
               I am 17277, I got   2   3
               I am 17278, I got   3   5
               I am 17279, I got   5   8
               I am 17280, I got   8  13
               I am 17281. I got  13  21
               I'am 17278            <--- kill -USR2 17279, Do 'p' from 17278
               I'am 17277
               I'am 17284
               I'am 17283
               I'am 17282
               I'am 17281
               I'am 17280
               I'am 17279.
               $ 
             
    • To handle signals and two inputs, you may create a pipe. When a signal arrives, write something to the pipe. In the main thread, you can check the pipe to know the command. That is, you may have to listen to three fds.
  • exercise 9: asynchrous read and write
    • Refer to 8.10. This exercise asks you to use aio_read and aio_write.
    • 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: 2017/May/17 00:05
    • Check the man page of aio_read. An additional library is required.
  • exercise 10: 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. For example, if the pair of numbers is 3,7, then num[3]num[7] are swapped. 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-10.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: 2017/05/31 00:05
  • exercise 11: pthread synchronizing(mutex and cond)
    • Refer to Chapter 13.
    • The main thread first creates 6 threads and then 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 should 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-11.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: 2017/Jun/07 00:05