System Call Project: Examples
CS 273 (OS), Spring 2022
For the project, think up some new service or feature for a kernel to provide, and implement it in terms of system calls. The new calls should:
Provide a service or feature that is not possible with the standard kernel.
- Yes: A
mean
system call that makes it possible for a non-root process to improve its scheduling priority. With standard kernels, onlyroot
processes can improve their priority (using the existingnice()
system call), so this is a new feature that is impossible with standard kernels. - No: A
dupclose()
system call that performs adup
of a file descriptor followed by aclose
of that descriptor, and returns the result of thedup
. Thisdupclose()
behavior could be implemented at the user level with standard system calls.
- Yes: A
Choose a service or feature whose effects can be verified.
- Yes: A
mean()
system call can be demostrated by writing a user program that prints its priority (e.g., usinggetpriority()
), then callsmean()
and prints its priority again. - No: A system call getcounter() that prints the
value of the field
counter
in the process table entry for the caller process cannot be verified for correctness.
- Yes: A
Your system call should satisfy the usual calling conventions for system calls. Thus, your system call handler should return a negative value between -125 and -1 for errors (so that your library function will return -1 and set
errno
as usual), and should return a non-negative integer on success.
Examples of ideas for added system calls
The following examples suggest some ideas that satisfy the two
criteria above. These are to get your imagination started only.
Don't feel constrained by these examples: be creative!
However, start conservatively, because modifying the
kernel can (not surprisingly) get complex in a hurry.
Recommendation: Start with a modest idea, such as
idea 1 below, then add more ambitious ideas after you have that
experince.
Submit all your successful added system
calls for your project.
Write a pair of system calls, one of which writes a value into a new field of your own in the process table entry, and the other which reads that value for a process.
- For example, one new system call
rab_putval
with oneint
argument might assign that integer value to a new fieldrab_val
added to the end of thetask_struct
structure (except using your own initials or email). A second system callrab_getval
with one integer argument might return theint
value of the fieldrab_val
for a (potentially different) process whose PID is passed as that argument. These two calls would represent a new capability for your kernel, enabling a process to share anint
value of its choice with all other processes. - Be sure to add your field at the end of the
task_struct
structure, not near the beginning, for reasons discussed in class. - As an additional feature, you could figure out how to assign an
initial value to the field
rab_val
, such as 0, or the process's PID, or the PID of the parent process.
- For example, one new system call
- You could write a system call that copies
the value of some kernel data structure onto a region of user space
provided by the user.
- Thus, for example, a user-level program with code excerpted below
might store the data in the i-node for a file with inode 123456
in the variable
ei
using a new system callrab_getinode()
(note that the user must allocate the space forei
, not the kernel).struct ext2_inode { __u16 i_mode; /* File mode */ __u16 i_uid; /* Low 16 bits of Owner Uid */ __u32 i_size; /* Size in bytes */ ... }; struct ext2_inode ei; /* allocate a variable of the i-node type */ ... rab_getinode(123456, &ei);
- To test this idea with a user-level program, you could print fields such
the three appearing above that could also be
seen in
ls -lsi
output. Note that thei
flag forls
prints i-node numbers, needed for your system call. - You could extend this idea by passing a pathname to the file instead of an i-node number (which would require learning how paths are converted to i-node numbers in the kernel).
- Can you think of other system data structures that you could provide to the user in other added system calls, whose values could be verified?
- Thus, for example, a user-level program with code excerpted below
might store the data in the i-node for a file with inode 123456
in the variable
Write a
mean
system call as suggested above, enabling a user process to improve it's own scheduling priority (unlikenice
, which can only lower priorities for non-root
processes).- This will involve a little research, because
nice()
shares implementation with other related system calls. - You may think of other superuser privileges that you could extend to ordinary users through a system call that you add.
- This will involve a little research, because
Write one system call that enables a user process to disable interrupts, and another system call for re-enabling interrupts.
- This would require learning about spin locks, which are used to disable interrupts in multicore Linux
- You could demonstrate this by booting your user-mode kernel and
logging in at both of the
xterm
windows. Run a program that disables interrupts in one login; this will freeze the other login (and many other things), since it the first program will keep its time slice until it enables interrupts again, because clock interrupts will also be disabled. - This is hardly a desirable addition to a kernel in a practical sense, but it does satisfy the criteria above for this project.
- Alternatively, you could use spin locks to implement some new synchronization feature for the user, such as a "test and set lock" feature for the C language.
Create a new system call that modifies
setitimer()
(for theITIMER_REAL
timer) to deliver a signal other thanSIG_ALRM
at a specified time in the future.- This would involve learning about how signals are implemented, and how to substitute a different signal handler that is a slight modification of the default one.
- To test, write a user level program that sets up a signal handler
for
SIG_INT
(or some other chosen signal) but not forSIG_ALRM
or any other signals, then uses your new system call to arrange forSIG_INT
to be sent a few seconds later, andpause()
s. Have the signal handler print a message when the signal is received, and have the program print a message after thepause()
. - Alternatively, you could write a system call that allows a process
to handle the uncatchable signal 9 (
SIG_KILL
).
Note: These are just suggestions to get you started: use your imagination! But develop your project incrementally. For example, if you are interested in the i-node idea above, it's wise to
- First implement a system call that is a clone of another system call, as discussed in class.
- Next, add another system call that reports some integer field value in the process table entry that you can verify (even if it might be available through another system call, at least your system call will report it in a way that you can check).
- Now, instead of simply returning that field value from your system
call, try requiring the user to allocate an integer variable and pass
that (user-space) memory location to the kernel through an argument
of your system call (like the
status
argument forwait()
), and write that integer value on the user's variable; have the test program print the resulting value of that variable. - Finally, write another system call that copies i-node information onto a user-provided variable of the right type.
- For extra features, you could create another system call that accepts a path instead of an i-node number as an argument, or additional system calls for providing other system data structures, etc.