You are expected to understand this. CS 111 Operating Systems Principles, Spring 2007
You are here: CS111: [[2007spring:lab2functions]]
 
 
 

Useful Kernel Functions

Descriptions of kernel functions you may be unfamiliar with and may find helpful in implementing your lab. Implementation files are given as a helpful pointer for authoritative information on the workings of the functions, their locations are given relative to a linux kernel source tree, e.g. /usr/src/linux/. You may also find the Linux Cross Reference a helpful reference for Linux types and functions (search: Linux Cross Reference identifier search).

1. Mutex locking and unlocking. We provide our own version of Linux's spin_lock mutex type, because on the lab machines, Linux's implementation won't help you find bugs. But for Linux's implementation, see include/linux/spinlock.h.

void osp_spin_lock_init(osp_spinlock_t *mutex); Initialize a mutex
void osp_spin_lock(osp_spinlock_t *lock); Acquire a mutex (lock the mutex)
void osp_spin_unlock(osp_spinlock_t *lock); Release (unlock) the mutex

Do not call a scheduling function, such as schedule(), while holding a spin lock! That is a recipe for disaster: your entire kernel might deadlock.

2. Signals, implementation in include/linux/sched.h and kernel/signal.c.

int signal_pending(struct task_struct *process); Returns boolean indicating whether the given process has any pending signals. You will probably pass current for the process argument; current is Linux's name for the current process structure.
int send_sig(int sig, struct task_struct *p, int priv); Send a signal sig to the process specified by p (the linux kernel has a task_struct for each process), we'll set priv to 0. Returns < 0 on error.

3. Wait queues, implementation in kernel/wait.c and include/linux/wait.h. These functions change a process's state from TASK_RUNNABLE to a blocked state, and allow other processes or kernel code to wake up blocked processes.

DEFINE_WAIT(wait); Defines a wait_queue_t object named wait. This object will be passed to prepare_to_wait and finish_wait.
void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state); Add the current task to the wait queue, using the named wait_queue_t object. The state member is the process's new state. Use TASK_INTERRUPTIBLE, which is a type of blocking that can be interrupted by signals. This function only adds the task to the queue; a later call to schedule will actually block. This allows you to avoid sleep/wakeup races: first, add the task to the wait queue; second, release any mutexes; and third, call schedule.
void finish_wait(wait_queue_head_t *q, wait_queue_t *wait); Remove the current task from the wait queue.
void wake_up_all(wait_queue_head_t *q); Wake up all tasks in the wait queue by setting their states to TASK_RUNNABLE.

4. CPU releasing/scheduling, implementation in kernel/timer.c.

void schedule(void); Release control of the CPU. If the current task's state is TASK_RUNNABLE, then the task might run again soon. If it is TASK_INTERRUPTIBLE, then the task will block until it is woken up by a signal or by wake_up_all.
long schedule_timeout(long timeout); Release control of the CPU for at most timeout time, which is measured in "jiffies". (There are HZ jiffies per second; often HZ is 1000.) Returns the amount of time remaining until timeout is returned, 0 is returned if the call timed out.

5. Block device requests, implementation in include/linux/blkdev.h.

unsigned int rq_data_dir(struct request *req); Returns the value indicating the given request's type, 0 for reads and 1 for writes.

6. File flags.

Your osprd_open and osprd_release functions will need to check whether your device file was opened for reading or writing. Given a struct file *filp variable:

(filp->f_mode & FMODE_WRITE) This expression is true (non-zero) if the file was opened for writing (O_WRONLY or O_RDWR).

If you'd like to check other file flags specified at open time, such as O_EXCL, for a design problem or something, do so like this:

(filp->f_flags & O_EXCL) This expression is true (non-zero) if the file was opened with the O_EXCL flag.

7. Helper functions for Lab 2.

osprd_device_t *file2osprd(struct file *filp); Linux's struct file object type corresponds to open files. This function takes an open file and returns the corresponding OSP ramdisk structure, osprd_device_t. This type is defined at the top of osprd.c. If filp is not actually an OSP ramdisk file, returns NULL.
void for_each_open_file(struct task_struct *task, void (*hook)(struct file *filp, osprd_info_t *d), osprd_info_t *d); Calls the hook function for each of task's open files. The function is called like hook(filp, d), where filp is the open file and d is the 3rd argument to for_each_open_file. You will probably pass current for the task argument; current is Linux's name for the current process structure.

The following example shows how to use for_each_open_file to count the number of ramdisk files that the current process, current, has open.

   typedef struct osprd_info {
       // ...
       int num_ramdisks_open;   // we add this variable for use by for_each_file
   } osprd_info_t;
 
   void count_ramdisks_hook(struct file *filp, osprd_info_t *d) {
       // This hook function will be passed to for_each_file.
       if (file2osprd(filp) != NULL)
           d->num_ramdisks_open++;
   }
 
   // ... somewhere else in the code, for example in osprd_open:
   d->num_ramdisks_open = 0;
   for_each_open_file(current, count_ramdisks_hook, d);
   eprintk("Number of ramdisks = %d\n", d->num_ramdisks_open);
 
2007spring/lab2functions.txt · Last modified: 2007/09/28 00:27 (external edit)
 
Recent changes RSS feed Driven by DokuWiki