《操作系统原理》实验报告

Table of Contents

Don't forget to answer the sum up questions in your email message!

1 Approaching to the Linux kernel

1.2 实验步骤及思考题

1.2.1 proc file-system

  1. Questions
    1. What's the CPU type and model? /proc/cpuinfo

      cat /proc/cpuinfo | grep model | head -2
      model name      : 11th Gen Intel(R) Core(TM) i5-11400H @ 2.70GHz
      
    2. What version of the Linux kernel are you using? uname

      uname -r
      5.15.90.4-microsoft-standard-WSL2
      
    3. How long has it been since your PC last booted? uptime

      uptime -p
      up 49 minutes
      
    4. How much of the total CPU time has been spent executing in user mode? kernel mode? idle? top

      top
      
      top - 21:02:29 up 14:11,  1 user,  load average: 0.00, 0.02, 0.00
      %Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id.. 
      As above text I got, I should also find out how many cores my processor has and 
      how long has cpus been since your PC last booted. So we can got the total CPU time has been spent executing:
      user mode   : 0.1% * 7:32 * 12  = 5.4(minutes)
      kernel mode : 0.1% * 7:32 * 12  = 5.4(minutes)
      idle        : 99.7% * 7:32 * 12 = 441.1(minutes)
      
    5. How much memory is configured in your PC? top,free,/proc/meminfo

      free -m
      
        total used free shared buff/cache available
      Mem 7869 859 6261 3 747 6773
      Swap 2048 0 2048      
    6. How much memory is currently available? top,free,/proc/meminfo

      6773M
      
    7. How many disk read/write requests have been made? /proc/diskstats

      cat /proc/diskstats
      
      8  0  sda 1139  433  148122 312  0     0     0      0     0 520    312    0   0 0      0   0     0
      8  16 sdb 103   0    4712   35   2     0     8      12    0 70     56     0   0 0      0   1     8
      8  32 sdc 17949 2499 827194 5304 21834 14325 504136 89556 0 142210 123451 496 6 238608 140 15626 28449
      read requests  = 433 + 0 + 2499;  
      write requests = 0 + 0 + 14325;
      
    8. How many context switches has the kernel performed? /proc/stat

      grep ctxt  /proc/stat
      31663371
      
    9. How many context switches has a process had? /proc/[pid]/status

      I choose a process which pid equels 100383. 
      cat /proc/100383/status | grep ctxt
      voluntary_ctxt_switches:        331
      nonvoluntary_ctxt_switches:     7
      So we can get PID 100383 had *338* context switches
      
    10. How many processes have been created since the system was booted? /proc/stat

      cat stat | grep processes
      processes 129854
      
    11. How many processes are there in the ready queue? /proc/stat

      cat /proc/loadavg
      0.04 0.06 0.01 1/344 134664
      So there are *344* processes in the ready queue
      
    12. How many processes are blocked waiting for I/O to complete? /proc/stat

      cat stat | grep cpu | head -1
      cpu  91918 208 76901 46373253 15067 0 19846 0 0 0
      So *15067* processes are blocked waiting for I/O to complete.
      
    13. What does the following command do?

      cd /proc/`ps | head -2 | tail -1 | cut -f1 -d' '` && ls -l
      First look at words in single quotation marks:
      Commod 'ps' report a snapshot of the current processes.
      Commod 'head -2' and 'tail -1' get the first process --- bash.
      Commod 'cut -f5 -d' '' get the first fields --- PID of bash
      So we can make it simpler : *cd /​proc​/​[PID of bash]/ && ls -l*
      The purpose of this command is to enter the /​proc​/​[PID of bash]/ directory and list the detailed contents of the folder.
      
  2. Sum up

    In your email message, please answer the following questions.

    1. How many hours you spent in this section?
      • It took me about 12 hours to do this.
    2. What's the major difficulties you met in this section?
      1. Not being familiar with many commands is the major difficulty I met.
    3. How did you solve (or try solving) them?
      • Through Google, related manuals to solve this problem.
    4. Have you learnt anything? Or your time was just wasted?
      • I gradually understood 'Everything is a file'.

1.2.2 Play with the kernel

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-2-2
实验环境
  • OS version: Linux 5.15.123.1-microsoft-standard-WSL2
  • Kernel source version: WSL2-Linux-Kernel-linux-msft-wsl-5.15.y
  • GCC version: gcc version 11.4.0
  1. Sum up

    In your email message, please answer the following questions.

    1. How many hours you spent in this section?
      • In lab 2 I spent about 6 hours finishing.
    2. What's the major difficulties you met in this section?
      1. It's hard to find the following "famous" code.
    3. How did you solve (or try solving) them?
      • Google, someone's blog and the 'pahole' command helped me a lot.
    4. Have you learnt anything? Or your time was just wasted?
      • I learned the meaning of the 'famous' code, and why they're famous.

1.2.3 Hello, kernel Module!

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-2-3
实验环境
  • OS version: Linux 5.15.123.1-microsoft-standard-WSL2
  • Kernel source version: WSL2-Linux-Kernel-linux-msft-wsl-5.15.y
  • GCC version: gcc version 11.4.0
  1. 实验步骤
    1. Input command

      sudo apt-get dist-upgrade
      sudo apt-get install linux-generic
      sudo apt-get install linux-headers-generic
      mkdir hello-lkm && cd hello-lkm
      
    2. Write code

      write a hello-1.c
      write Makefile
      
    3. make Makefile

      make 
      
    4. Install the module into the running kernel

      sudo insmod hello-1.ko
      
  2. Questions
    1. What's a kernel module?

      Kernel modules are pieces of code that can be loaded and unloaded into the kernel upon demand. They extend the functionality of the kernel without the need to reboot the system.
      
    2. How do modules get into the kernel?

      In this lab, 'make' command generate file calls hello-1.ko. Than, install the module into the kernel
      sudo insmod hello-1.ko
      
    3. How do you know a kernel module is loaded?

      I can see what modules are already loaded into the kernel by running 'lsmod'.
      lsmod
      
      Module Size Used by
      hello_1 16384 0
    4. How do you know a module is working properly or not?

      By running 'lsmod | grep moduleName'
      lsmod | grep moduleName
      
    5. How do you unload a module?

      By running 'sudo rmmod moduleName'
      sudo rmmod moduleName
      
    6. in hello-1.c, what does ​_​_init, _​_exit mean? (include/linux/init.h)

      The kernel can take _​_init as hint that the function is used only during the initialization phase and free up used memory resources after.
      

      :_​_exit sections will be used only if module support is disabled.

    7. why printk()? why not printf()?

      printf() is a function in the GNU C Library. Kernel Space is not directly accessible to user space. So,  The kernel cannot use printf(). 
      
  3. Sum up

    In your email message, please answer the following questions.

    1. How many hours you spent in this section?
      • I spent about 7 hours in lab 3.
    2. What's the major difficulties you met in this section?
      1. When I enter the command sudo install linux-headers-`uname -r`, there is an error in my terminal.
    3. How did you solve (or try solving) them?
      • I searched for this in Stackoverflow. Fortunately, this problem has been solved.
    4. Have you learnt anything? Or your time was just wasted?
      • I have learned the knowledge of kernel modules and writing a simple kernel module.

1.2.4 System calls

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-2-4
实验环境
  • OS version: Linux 5.15.123.1-microsoft-standard-WSL2
  • Kernel source version: WSL2-Linux-Kernel-linux-msft-wsl-5.15.y
  • GCC version: gcc version 9.4.0
  1. 实验步骤
    1. Download the source code of the latest stable version of the Linux kernel (which is https://github.com/microsoft/WSL2-Linux-Kernel/tree/linux-msft-wsl-5.15.y) to the home folder.

      cd /usr/src
      git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
      cd /WSL2-Linux-Kernel-linux-msft-wsl-5.15.y
      
    2. Write a basic system call in C and integrate it into the new kernel.

      mkdir identity
      

      Create a C file for the system call.

      vim identity/identity.c
      

      Write the following code in it.

      #include <linux/kernel.h>
      #include <linux/syscalls.h>
      
      SYSCALL_DEFINE0(identity)
      
      {
         printk("I am Jihan Jasper Al-rashid.\n");
         return 0;
      }
      

      Create a Makefile.

      vim identity/Makefile
      

      Write the following code in it.

      obj-y := identity.o
      

      Add the home directory of the system call to the main Makefile of the kernel.

      vim Makefile
      

      Search for core-y. In the second result, see a series of directories. kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ Add the home directory of my system call at the end like the following.

      kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ identity/
      

      Add a corresponding function prototype for my system call to the header file of system calls.

      include/linux/syscalls.h 
      

      Navigate to the bottom of it and write the following code just above #endif.

      asmlinkage long sys_identity(void);
      

      Add my system call to the kernel's system call table.

      vim arch/x86/entry/syscalls/syscall_64.tbl
      

      Go to the bottom of the first group (it ends at syscall 447 in linux-msft-wsl-5.15), and add the following line:

      448   common   identity   sys_identity
      
    3. Installation the new kernel and prepare your operating system to boot into it.

      Compile the kernel's source code.

      make KCONFIG_CONFIG=Microsoft/config-wsl 
      

      Prepare the installer of the kernel.

      sudo make modules_install -j4
      

      Install the kernel.

      sudo make install -j4
      

      then wait. When the compilation done, copy the compiled image to somewhere on the Windows filesystem (i.e., outside WSL).

      cp arch/x86/boot/bzImage /mnt/c/Users/luoju/bzImage
      

      Exit WSL and reboot it

    4. write a C program to check whether the system call works or not.

      vim report.c
      
      #include <linux/kernel.h>
      #include <sys/syscall.h>
      #include <stdio.h>
      #include <unistd.h>
      #include <string.h>
      #include <errno.h>
      
      #define __NR_identity 440
      
      long identity_syscall(void)
      {
         return syscall(__NR_identity);
      }
      
      int main(int argc, char *argv[])
      {
         long activity;
         activity = identity_syscall();
      
         if(activity < 0)
         {
            perror("Sorry, Jasper. Your system call appears to have failed.");
         }
      
         else
         {
            printf("Congratulations, Jasper! Your system call is functional. Run the command dmesg in the terminal and find out!\n");
         }
      
         return 0;
      }
      

      Compile the C file.

      gcc -o report report.c
      

      Run the C file you just compiled

      ./report
      

      it displays the following Congratulations, Jasper! Your system call is functional. Run the command dmesg in the terminal and find out! Check the last line of the dmesg output.

      dmesg | tail -1
      

      see the following [ 4273.313106] I am Jihan Jasper Al-rashid.

  2. Sum up

    In your email message, please answer the following questions.

    1. How many hours you spent in this section?
      • About 7 or 8 hours
    2. What's the major difficulties you met in this section?
      1. When I try to update the bootloader of the operating system with the new kernel by using "sudo update-grub", but Ubuntu on metal while WSL2 is a lightweight virtual machine and doesn't even need it to boot.
    3. How did you solve (or try solving) them?
    4. Have you learnt anything? Or your time was just wasted?
      • I become more clear about 'image' in linux, although still abstract. Also, learned making my syscall.

2 Process management

2.1 Process creation

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-3-1-1
实验环境
  • OS version: (Linux 5.15.123.1-microsoft-standard-WSL2)
  • Kernel source version: (WSL2-Linux-Kernel-linux-msft-wsl-5.15.y)
  • GCC version: (gcc version 11.4.0)

2.1.1 实验步骤

  1. Using man command to get a sense of the command;

2.1.2 Questions

  1. Both exit() and _exit() are used in the program. What's the difference?

    _exit() terminates the calling process "immediately". Any open file descriptors belonging to the process are closed.     
    exit() flushes io buffers and removes tempfile.
    
  2. Tell me about the following line of code:

    w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);

    Parent process wait for state changes in a child of the calling process. Function of waitpid will return  the pid of 
    the child whose state has change, if a child has stopped or a stopped child has been resumed by delivery of SIGCONT.
    The status for traced children which have stopped is provided even if this option is not specified.
    
  3. Compile and run the following 4 programs. Tell me what they do? And their differences:

    1. To see every process on the system using BSD syntax.
    2. It did the same thing as No.1. But it used execlp function to execute without system().
    3. It used 2 processes to print every process on the system using BSD syntax.
    4. it used child process to execute.
    
  4. more on fork() and wait()

    Compile and run this program. Tell me why the output is weird (mixed with the $ prompt)? And fix it with the wait() system call.

    $ ./fork_blp
    
    fork program starting
    This is the parent
    This is the child
    This is the child
    This is the parent
    This is the child
    This is the parent
    This is the child
    This is the child
    This is the child
    This is the child
    
    Parent process created child process. But we don't know who has control over the CPU.
    

    Fixed code

    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    int main()
    {
        pid_t pid;
        char *message;
        int n;
           int status;
        printf("fork program starting\n");
        pid = fork();
        switch(pid)
        {
        case -1:
    	perror("fork failed");
    	exit(1);
        case 0:
    	message = "This is the child";
    	n = 7;
    	break;
        default:
    	message = "This is the parent";
    	n = 3;
    	       wait(&status);
    	break;
        }
        for(; n > 0; n--) {
    	puts(message);
    	sleep(1);
        }
    
           /* It's not necessasry to have both parent and child process do wait() though it doesn't hurt.*/
           // wait(&status);
    
           exit(0);
    }
    
  5. zombies and waitpid()
    • Read the NOTES section in the wait manual page (man 2 wait) to get a clear idea about zombie processes. And tell me why zombie is not welcomed.

      As long as a zombie is not removed from the system via a wait, it will consume a slot in the kernel process table, 
      and if this table fills, it will not be possible to create further processes.       
      
    • At the end of wait manual page (man 2 wait), there is an example program. Play with it, and tell me about WUNTRACED, WCONTINUED, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WIFSTOPPED, WSTOPSIG, WIFCONTINUED, pause().
      • WUNTRACED

        return if child has stopped.
        
      • WCONTINUED

        return if a stopped child has been resumed by delivery of SIGCONT.
        
      • WIFEXITED

        returns true if the child terminated normall
        
      • WEXITSTATUS

        returns the exit status of the child.
        
      • WIFSIGNALED

        returns true if the child process was terminated by a signal.
        
      • WTERMSIG

        returns the number of the signal that caused the child process to terminate.
        
      • WIFSTOPPED

        returns true if the child process was stopped by delivery of a signal.
        
      • WSTOPSIG

        returns the number of the signal which caused the child to stop.
        
      • WIFCONTINUED

        returns true if the child process was resumed by delivery of SIGCONT.
        
      • pause()

        causes the calling process to sleep until a signal is delivered.
        
    • Compile and run this small program. This program can leave a zombie process in the system. You can see it with
      • Write a similar program that leaves 5 zombies.

        #include <sys/wait.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        
        int main(void) {
            pid_t pids[5];
            for (int i = 4; i >= 0; --i) {
        	pids[i] = fork();
        	if (pids[i] == 0) {
        	    printf("Child%d\n", i);
        	    _exit(0);
        	}
            }
            sleep(60); return 0;
        }
        
      • Tell me what's the difference between a zombie process and a orphan process?

        A child that terminates, but has not been waited  becomes a "zombie".
        Parent process has finished or terminated, though child process remains running itself.
        
      • Read Beginning Linux Programming (last visited: [2020-11-20 Fri]), Chapter 11, page 503 to learn how to avoid zombies with waitpid() system call. And correct the above program.

        #include <sys/wait.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        
        int main(void) {
            pid_t pids[5];
            int status;
            for (int i = 4; i >= 0; --i) {
        	pids[i] = fork();
        	if (pids[i] == 0) {
        	    printf("Child%d\n", i);
        	    _exit(0);
        	} else {
        	    waitpid(pids[i], &status, WNOHANG);
        	}
            }
            return 0;
        }
        
      • Tell me the difference between exit() and return.

        return returns from the current function.
        exit() terminates the whole process.
        

2.1.3 Sum up

In your email message, please answer the following questions.

  1. How many hours you spent in this section?
    • About 5 hours.
  2. What's the major difficulties you met in this section?
    1. Poor knowledge of fork makes it difficult to program.
  3. How did you solve (or try solving) them?
  4. Have you learnt anything? Or your time was just wasted?
    • Learn how to use fork(), waitpid(), and various options of waitpid.

2.2 Thread

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-3-2
实验环境
  • OS version: (Linux 5.15.123.1-microsoft-standard-WSL2)
  • Kernel source version: (WSL2-Linux-Kernel-linux-msft-wsl-5.15.y)
  • GCC version: (gcc version 11.4.0)

2.2.1 Questions

  1. At the end of pthread_create manual page (man 3 pthread_create), there is an example program. Play with it, and then tell me:
    • What's the tinfo[]?

      List of tread infomation.
      
    • What's the res?

      Return the value of thread_start.
      
  2. At the end of pthread_attr_init manual page (man 3 pthread_attr_init), there is an example program. Compile and run it.
  3. Compile and run this program. Now, remove the pthread_join call, i.e. comment out line 29-32. Compile and run it again for multiple times. Tell me the difference, and why?

    In the original code, the two threads will keep running unless there is an interrupt signal. 
    When removing the pthread_join call in the code, the process will return soon without waiting 
    for threads and kill threads which it created.
    

2.2.2 Sum up

In your email message, please answer the following questions.

  1. How many hours you spent in this section?
    • About 3 hours.
  2. What's the major difficulties you met in this section?
    1. Reading example code is difficulty.
  3. How did you solve (or try solving) them?
    • Using Google and relevant manule page.
  4. Have you learnt anything? Or your time was just wasted?
    • The konwleage about thread.

2.3 IPC

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-3-3
实验环境
  • OS version: (Linux 5.15.123.1-microsoft-standard-WSL2)
  • Kernel source version: (WSL2-Linux-Kernel-linux-msft-wsl-5.15.y)
  • GCC version: (gcc version 11.4.0)

2.3.1 Questions

  1. Signals
    • Now, tell me your understanding about the following function prototype:

      void (*signal(int sig, void (*func)(int)))(int)
      signal(...) is a function pointer.
      For using the signal function, we need input a integer 
      and a funtion pointer as arguments.
      
    • Following Beej's Guide to Unix IPC, section 3 to play with signals. And then tell me details about the following code:

      int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)

      "signum" specifies the signal, except SIGKILL and SIGINT...
      A new action is defined at "act" to handle the situation that something traps the signal.
      "oldact" has saved the previous action.
      
  2. Pipe
    • Modify pipe3.c in Beej's Guide to Unix IPC, section 4 to make the child does the wc -l, and the parent does the ls.

      if (!fork()) {
         // parent 
         close(1);       /* close normal stdout */
         dup(pfds[1]);   /* make stdout same as pfds[1] */
         close(pfds[0]); /* we don't need this */
         execlp("ls", "ls", NULL);
      } else {
         // child 
         close(0);       /* close normal stdin */
         dup(pfds[0]);   /* make stdin same as pfds[0] */
         close(pfds[1]); /* we don't need this */
         execlp("wc", "wc", "-l", NULL);
      }
      
    • At the end of pipe manual page (man 2 pipe), there is an example program. Compile it, run it, understand it, and then, modify the program, let parent do read, and child do write.

      if (!cpid) {    
           // parent
           close(pipefd[1]);
           while (read(pipefd[0], &buf, 1) > 0)
      	 write(STDOUT_FILENO, &buf, 1);
      
           write(STDOUT_FILENO, "\n", 1);
           close(pipefd[0]);
           _exit(EXIT_SUCCESS);
      
       } else {            
           // child
           close(pipefd[0]);          
           write(pipefd[1], argv[1], strlen(argv[1]));
           close(pipefd[1]);          
           wait(NULL);                
           exit(EXIT_SUCCESS);
       }
      
  3. FIFO
    • When you run the example programs (speak and tick), there should be a new file named american_maid appear in your working directory ($PWD). What will happen if you delete this FIFO file while the two programs running? Why?

      The speak and tick will continue working.
      When I delete the FIFO file while the two programs running, the file still lie in the file desciptor table. 
      I use lsof to list open files of speak, after removing american_maid.
      
      COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
      s       8744    a  cwd    DIR   8,32     4096 19889 /home/a/.../20211152002_lab7/fifo
      ...
      s       8744    a    3w  FIFO   8,32      0t0 19646 /home/a/.../20211152002_lab7/fifo/american_maid (deleted)
      	    #+end_src c
      
             - Modify the example programs to use mkfifo instead of mknod.
      	 Modifed the example programs:
      	  #+begin_src c
      int  main(int argc, char *argv[])
      {
         ...
      	char * FIFO_NAME = argv[1];
         ...
      }
      

      than

      $ mkfifo a
      $ gcc speakModified.c -o sM & ./sM a 
      $ gcc tickModified.c  -o tM & ./tM a
      
    • Extend the example programs, and make it have 3 writers.

      #include <stdio.h>
      #include <stdlib.h>
      #include <errno.h>
      #include <string.h>
      #include <fcntl.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <unistd.h>
      #include <pthread.h> 
      
      pthread_mutex_t lock; 
      char s[300];
      int num, fd;
      
      #define FIFO_NAME "american_maid"
      
      int cnt = 0;
      void* fun() {
      	pthread_mutex_lock(&lock);
      	int n = ++cnt;
      	pthread_mutex_unlock(&lock); 
      
      	printf("%d \n", n);
      	while(1){
      		gets(s);
      		feof(stdin);
      		num = write(fd, s, strlen(s));
      		printf("%d-th speak: wrote %d bytes\n", n, num);
      	}
      }
      
      int main(void)
      {
      	mknod(FIFO_NAME, S_IFIFO | 0666, 0);
      	printf("waiting for readers...\n");
      	fd = open(FIFO_NAME, O_WRONLY);
      	printf("got a reader--type some stuff\n");
      	pthread_mutex_unlock(&lock); 
      
      	pthread_t pids[3];
      	int number[1];
      	for (int i = 0; i < 3; ++i) {
      		// printf("%d \n", i);
      		number[0] = i;
      		pthread_create(&pids[i], NULL, *fun, NULL);
      	}
      	for (int i = 2; i >= 0; --i) pthread_join(pids[i], NULL);
      	return 0;
      }
      
  4. File Locking
    • Tell me whether the locked file, e.g. lockdemo.c can be delete while the programs are running? And why?

      The file name won’t be visible in the file system, but our file handle will point to 
      the inode, which still exists.
      refence https://www.baeldung.com/linux/open-file-handle-after-move-delete
      
  5. Message Queues
    • What happens when you're running both in separate windows and you kill one or the other?

      When killing kirk, spock will not stop. 
      When killing spock, kirk still be able to write massages. 
      Then we restart spock, the massage will be sent suceessfully.
      
    • Also try running two copies of kirk or two copies of spock to get an idea of what happens when you have two readers or two writers.

      spock will accept massages which be sent from two copies of kirk.
      Two copies of spock will compete to accept massages which be sent from kirk.
      
    • Another interesting demonstration is to run kirk, enter a bunch of messages, then run spock and see it retrieve all the messages in one swoop. Just messing around with these toy programs will help you gain an understanding of what is really going on.

      In this case, if the size of message exceeds buffer(200B), the massage will be spilted mutil-parts.  
      
    • What happens if you ipcrm the queue while it's in use? Why?

      If I remove the message queue by msgid, there are some errors(terminal will print "msgrcv: Identifier removed"). 
      I try to send some massage by inputing words in kirk, but the terminal will print "msgsnd: Invalid argument".
      
    • Create a message queue with ipcmk , and use it in your programs.

      To create and get message queue id by using

      $ ipcmk -Q
      Message queue id: 6
      

      In my programs, the Message queue id is from argv[1].

      int msqid = atoi((char *)argv[1]);
      
  6. Semaphores
    • Semaphores are used to lock some shared resources to enforce mutual-exclusion. In the demo program semdemo.c, what's locked?

      Semaphore value is a locker.If sem_op is negative, its absolute value is subtracted from the semaphore value. 
      If sem_op is positive, the value is added to the semaphore value.
      If the result would become negative, the call blocks till the time semaphore value increases to a level that 
      the calculation would result in non-negative semaphore value.
      
    • Draw a flow chart to show how the demo program works.
      Create and initialize semaphore
      try to get lock
      yes
      no
      get the lock
      release the lock
      start
      struct sembuf sb;
      sb.sem_num = 0;
      sb.sem_op = -1;
      sb.sem_flg = SEM_UNDO;
      semaphore value > 0
      semaphore value -= |sb.sem_op|
      wait until semaphore value > 0
      do something
      semaphore value += sb.sem_op

2.3.2 Sum up

In your email message, please answer the following questions.

  1. How many hours you spent in this section?
    • About 12 hours.
  2. What's the major difficulties you met in this section?
    1. In the task of 3 writers, it's difficult for me to code multithreading program.
    2. Reading code and relevant information is hard.
  3. How did you solve (or try solving) them?
    • Conduct a search on Google and enhance my understanding of multithreading programming by studying examples of code. Reading slowly and understanding each function is my best solution. I have to say, Google has been incredibly helpful to me. It’s the perfect tool for my needs.
  4. Have you learnt anything? Or your time was just wasted?
    • I establish preliminary understanding of IPC and know more clearly about relationship of c program and linux.

3 Memory management

3.1 Basic commands

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-4-1
实验环境
  • OS version: (Linux 5.15.123.1-microsoft-standard-WSL2)
  • Kernel source version: (WSL2-Linux-Kernel-linux-msft-wsl-5.15.y)
  • GCC version: (gcc version 11.4.0)

3.1.1 Questions

  1. If you exam its size with ls -l, you should get something similar to the following line

    -rwxr-xr-x 1 wx672 wx672 6627 Oct 18 18:05 a.out What does the 6627 mean?

    this means size of a.out is 6627 byte
    
  2. Then, use size to see the size of its text, data, and bss segments.

    size a.out

    The output should be something like

    text   data   bss        dec         hex    filename
    1200   520    1024032    1025752     fa6d8      a.out
    

    What do the 1200, 520, 1024032, and 1025752 mean?

    the size of the text segment is 1200 bytes.
    the size of the data segment is 520 bytes.
    the size of the block started by symbol segmen is 1024032 bytes.
    the sum of the "text", "data", and "bss" columns in decimal is 1025752 bytes.
    

3.2 Shared Memory Segments

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-4-2
实验环境
  • OS version: (Linux 5.15.123.1-microsoft-standard-WSL2)
  • Kernel source version: (WSL2-Linux-Kernel-linux-msft-wsl-5.15.y)
  • GCC version: (gcc version 11.4.0)

3.2.1 实验步骤

  1. Use ipcrm to remove the segment you just created while running the example code. Add some c program sentence in shmdemo.c

    printf("%d", shmid);
    fflush(stdout);
    sleep(10);
    

    When running the example code, input

    ipcrm -m shmid
    

    The terminal will print

    shmat: Invalid argument
    

    And specific share memory will fail.

  2. Add semaphore mechanism into the sample program ( shmdemo.c ) to enforce mutual-exclusive access to the shared data area.

    Here’s the code for shmdemo_semaphore.c

    ...
    int initsem(key_t key, int nsems);
    int main(int argc, char *argv[])
    {
    	...
    	if ((semid = initsem(key, 1)) == -1) {
    		perror("initsem");
    		exit(1);
    	}
    
    	if (semop(semid, &sb, 1) == -1) {
    		perror("semop");
    		exit(1);
    	}
    
    	int shmid4shdemo;
    	char *data;
    
    	if (argc > 2) {
    		fprintf(stderr, "usage: shmdemo [data_to_write]\n");
    		exit(1);
    	}
    
    	if ((shmid4shdemo = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
    		perror("shmget");
    		exit(1);
    	}
    
    	data = shmat(shmid4shdemo, (void *)0, 0);
    
    	if (data == (void *)(-1)) {
    		perror("shmat");
    		exit(1);
    	}
    	if (argc == 2) {
    		printf("writing to segment: \"%s\"\n", argv[1]);
    		strncpy(data, argv[1], SHM_SIZE);
    		data[SHM_SIZE-1] = '\0';
    	} else
    		printf("segment contains: \"%s\"\n", data);
    
    	if (shmdt(data) == -1) {
    		perror("shmdt");
    		exit(1);
    	}
    
    	sleep(10);
    
    	sb.sem_op = 1; /* free resource */
    
    	if (semop(semid, &sb, 1) == -1) {
    		perror("semop");
    		exit(1);
    	}
    
    	return 0;
    }
    

3.3 Memory Mapped Files

实验内容
http://cs6.swfu.edu.cn/~wx672/lecture_notes/os/lab.html#sec-4-3
实验环境
  • OS version: (Linux 5.15.123.1-microsoft-standard-WSL2)
  • Kernel source version: (WSL2-Linux-Kernel-linux-msft-wsl-5.15.y)
  • GCC version: (gcc version 11.4.0)

3.3.1 实验步骤

  1. Write a small program to find out the page size of your Linux PC.

    #include <stdio.h>
    #include <unistd.h>
    
    void main()
    {
        printf("Page size (sysconf) %ld\n", sysconf(_SC_PAGESIZE));
        printf("Page size (getpagesize) %d\n", getpagesize());
        return ;
    }
    
  2. Add semaphore mechanism into the sample program (mmapdemo.c) to enforce mutual-exclusive access to the shared data area.

    Here’s the code for mmapdemo.c

    ...
    int main(){
      ...
      struct sembuf sb = {.sem_num = 0, .sem_op = -1, .sem_flg = SEM_UNDO};
      key = ftok("mmapdemo.c", 'J');
      semid = initsem(key, 1);
      semop(semid, &sb, 1);
      fd = open("mmapdemo.c", O_RDONLY);
      ...
      data = mmap((void*)0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)
      sb.sem_op = 1; 
      semop(semid, &sb, 1);
    }
    

3.3.2 Sum up

In your email message, please answer the following questions.

  1. How many hours you spent in this section?
    • 3 hours.
  2. What's the major difficulties you met in this section?
    1. Engilsh is major difficulty.
  3. How did you solve (or try solving) them?
    • I tried my best to read and comprehend it.

4 File system

4.1 实验步骤

  1. Create a initialized file

    dd if=/dev/zero of=fs.img bs=1k count=10000
    
  2. Creating an ext2 file system

    mkfs.ext2 my.img
    
  3. Creating a directory on where the img mount

    mkdir mymount
    
  4. Mount the newly created file system onto /mymount directory

    sudo mount my.img mymount/
    

4.2 Questions

  1. Plug your USB disk into your PC's USB port, and check what file system it is and which directory it's mounted on?

    I mount usb disk on /mnt/luo/

    sudo mount -t drvfs D: /mnt/luo
    

    Using df command to check

    $ df -Th 
    Filesystem Type Size  Used  Avail  Use%  Mounted on
    ...
    D:         9p   30G   837M  29G    3%    /mnt/luo
    
  2. After you do cat hello at the command line, you will see on the screen the content of file hello, in our case it is helloworld . Now give me a detailed picture about what is happened in the OS from cat hello to helloworld is shown on the screen.

    In my new file system, the block size is 4k (0x1000) and the inode size is 256 (0x0100) byte.

    root_Inode
    inode = 0x02
    0x4100 - 0x41ff
    Pointer to first data block = 0xa1
    root_First_Data_Block
    start = 0xa1000
    -
    inode = 0x02
    File type = 0x02
    --
    inode = 0x02
    File type = 0x02
    hello
    inode = 0x0c
    File type = 0x01
    lost_found
    inode = 0x0b
    File type = 0x02
    helloInode
    inode = 0x0c
    0x4b00 - 0x4bff
    Pointer to first data block = 0x0200
    hellloFirstDataBlock
    start = 0x200000
    data = 68 65 6c 6c 6f 77 6f 72 6c 64 0a
    dataConvert = helloworld

4.2.1 Sum up

In your email message, please answer the following questions.

  1. How many hours you spent in this section?
    • About 6 hours
  2. What's the major difficulties you met in this section?
    1. When I first met 'mount' , it's too abstract to understand for me.
  3. How did you solve (or try solving) them?
    • I do a lot practice to make 'mount' more specific.
  4. Have you learnt anything? Or your time was just wasted?
    • I've learnt the definition of 'mount' in cs. And how ext2 find file datas.

Author: 罗俊博(20211152002)

Created: 2023-12-18 Mon 11:10

Validate