Chapter 7 of "Operating System" by Gary Nutt, especially: 251-256, 258, 269, 271-275
"Kernel Projects for Linux" by Gary Nutt: Project 5 and project8.
Resources: http://fossil.wpi.edu/docs/howto_add_systemcall.html
http://lxr.linux.no (browse and search kernel source)
In this project, you will create a basic synchronization mechanism called the “barrier.”
Mandatory Components:
--Design and code system calls (barrier_create and barrier join) that implements dynamically many barriers with timeouts.
--Write a user-space program that tests the functionality of barrier_create. This program should also create a stub for your new system call function.
--Write an application program to test the synchronization mechanism. It should test both the normal operation of the barrier as well as the case where a timeout occurs.
Challenge Components (all are optional):
--Support private/restricted barriers (e.g. only children of the creating pid can join)
--Add some other system calls to get info about a barrier (e.g. The number of procs it's waiting for, how many are currently waiting, the pids of those waiting, what pid created it, etc.)
Be sure to include a README file with the following:
* Both lab partner's names, email addresses, and ID numbers.
* A brief write-up describing your approach and details about your implementation, including which of the required challenge problems you choose.
* The status of the implementation, any known drawbacks, any unimplemented features, etc. This one is especially important and should match the behavior I see when testing the code.
* Discuss any additional features you implemented
Write this in a file in plain text, HTML, or PDF format. DO NOT submit MS WORD DOCS!
Design and implement a new system call function, barrier_create. The function should have the following prototype:
int barrier_create( int num_processes, long timeout); Returns: Barrier number on success, -1 on failure. Errors include: EINVAL if num_processes is 0 or negative. ENOMEM if too many barriers already exist.
Write a user-space program to test barrier_create. The program should also create a stub for your new system call function.
Design and implement a new kernel synchronization primitive that will allow multiple processes to block at the “barrier”. When the number of processes blocked at the barrier is equal to the number of processes specified by num_processes in “barrier_create”, all blocked processes that are unblocked. Implement the following system call in addition to the one in Part A.
int barrier_join(int barrier_number); Returns: 0 if the process resumed due to the barrier meeting the threshold, 1 if the process resumed due to timeout timeout, -1 on failure. Errors include: EINVAL if barrier_number is < 0. ENOENT if no barrier named barrier_number exists. CHALLENGE PROBLEM ONLY: EPERM if current process can't join this barrier.
In addition, processes will only remain blocked for the “timeout” period that is specified in the barrier_create system call. This period is measured from the time that the first process arrives at the barrier. On reaching the timeout period, if processes are still blocked, all processes should be unblocked.
Each barrier is used only one time. When the processes at a barrier are released, the barrier must be destroyed, and the corresponding memory freed. Further calls to barrier_join with that barrier id should return -1 and set errno to ENOENT.
Write an application program to test the synchronization mechanism. It should test both the normal operation as well as the case where the timeout occurs.
Review pages 116-117 in the Gary Nutt book.
In this course we will use the 2.6.8.1 kernel instead of a 2.4.26 kernel, hence some instructions have changed.
For the people working in the lab, DO NOT modify the original source tree. The directory /usr/src/linux-cs111 has been created and everybody has been given R/W access to. Create a directory there for your source tree, and chmod it to disallow any read access to everybody else. Make sure you keep a copy of your modified files on your SEASnet home directory. DO NOT use your SEASnet home directory for the full source tree, they will be very unhappy with us.
Pre-Build steps
Download the kernel source tarball from the CourseWeb page. This tarball will include a skeleton kernel/barrier.c, include/linux/barrier.h, and a modified Makefile. Make sure you use this source tarball.
Copy over the config file from /boot/config-$configversion to /usr/src/linux-$version/.config
Edit the Makefile to change the “EXTRAVERSION” to a name that is specific to your team.
The kernel is built with only two commands
# make clean (if you want to clean the code)
# make oldconfig
# make
Installing the kernel
DO NOT, DO NOT overwrite the existing kernel in /boot.
You will not be able to boot the machine up if you overwrite it with your kernel and your kernel has an error in it.
On a successful build, the kernel image can be found as the file
/usr/src/linux-$version/arch/i386/boot/bzImage.
Copy the kernel image into /boot and name it vmlinuz-$yourversion
(For people working in the lab you will have to copy it to /boot/cs111/bzImage)
run $make modules_install in /usr/src/linux-$version.
Create the ramdisk image using the mkinitrd command ( for more info. man mkinitrd)
$mkinitrd /boot/initrd-$yourversion /lib/modules/$kernel-version
(For people working in the lab you will use /boot/cs111/initrd-cs111.img)
Edit grub.conf to add your kernel to the list so that you will see it as an option when booting up. (For people working in the lab, there is already an entry in the grub.conf that point to a student kernel location)
Additional Seasnet details
3 additional commands are available for users working on the Seasnet machines
sudo /root/copyLog (makes a copy of /var/log/messages in the current directory)
sudo /root/cleanKernDir (removes files from /boot/cs111)
sudo /root/cleanSourceDir (removes files from /usr/src/linux-cs111)
Review Chapter 5 in the Gary Nutt book.
Things have changed slightly since we are using a new 2.6 kernel.
Edit files arch/i386/kernel/entry.S to add your system call to the sys_call_table
.data ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call*/ .long sys_exit .long sys_fork .long sys_read .long sys_write .long sys_open /* 5 */ .long sys_close .long sys_waitpid . . . .long sys_tgkill /* 270 */ .long sys_utimes .long sys_fadvise64_64 .long sys_ni_syscall /* sys_vserver */ .long sys_barrier_create /* cs111 project 2 */
Edit include/asm-i386/unistd.h
/* * This file contains the system call numbers. */ #define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 . . . #define __NR_tgkill 270 #define __NR_utimes 271 #define __NR_fadvise64_64 272 #define __NR_vserver 273 #define __NR_barrier_create 274 #define NR_syscalls 275 // remember to change this number
Add your system calls to kernel/barrier.c
asmlinkage int sys_barrier_create(int num_processes, long timeout);
asmlinkage int sys_barrier_join(int num_processes);
Using printk. Printk() is the kernel version of printf. The output of printk goes to /var/log/messages. This file can be quite long, to see the end of the file, use tail
printk(KERN_WARNING "This is how we use printk!!\n");
Part C: Useful calls for Barrier Synchronization
You will be calling interruptible_sleep_on to block a process
void interruptible_sleep_on( struct wait_queue **p) { SLEEP_ON_VAR current-state = TASK_INTERRUPTIBLE; SLEEP_ON_HEAD schedule(); SLEEP_ON_TAIL } #define SLEEP_ON_HEAD . __add_wait_queue (); . #define SLEEP_ON_TAIL . __remove_wait_queue (); .
For awakening a blocked process, you will use wake_up_interruptible. Also there are corresponding functions that handle timeouts.
Also, be aware of possible race conditions in the kernel. You can use the functions lock_kernel() and unlock_kernel() to use a kernel semaphore to prevent these conditions from occurring.