This page lists all official clarifications and some hints for lab 2:

Setting errno

Each of the _syscallX stub generation macros end by calling this bit of code:

#define __syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-125)) { \
errno = -(res); \
res = -1; \
} \
return (type) (res); \
} while (0)

Reading this, you should notice that this *automatically* sets the errno value for you, if the return value of the function was < 0. So, when the comments in barrier_create and barrier_join say to "set errno", this means you simply need to return the appropriate error value. The stub you write for your system call will take this return value and convert it to properly set errno and return -1, as you can see in the __syscall_return macro above.

So, if in barrier_join I want to return the error EINVAL because a user gave an illegal num_processes value, I simply do:

return -EINVAL;

Note it is -EINVAL. The error code constants are all positive values (see their definitions in include/asm-generic/errno-base.h), but the __syscall_return macro interprets values < 0 as errors.

Comment about return values from barrier_join

The comment above barrier_join has the return values mixed up with respect to what the code does. To match the behavior of the code, the comment should say:

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.

Your code should match this behavior and not what the original comment said. Resuming due to meeting the threshold is considered the "usual" or "successful" case, so it should return 0 to match standard programming conventions.

Writing test programs

The user-level test programs are written like any regular C program, just as you did for the shell in lab 1. You need to write C-code with the usual main function to test your system calls. We are expecting at least the following things:

  1. Test program testing single barrier.
  2. Test program testing multiple barriers.
  3. Test program testing timeouts.
  4. Test program testing error conitions (and you will have to figure out all the error conditions )
  5. Test program testing any optional features you implement.

There are two ways to call the system calls that you have implemented in your kernel (for more info read the Gary Nutt lab manual):

  1. By using the syscall(...) function with the appropriate system call number and parameters
  2. By writing and using stubs and then calling barrier_join and barrier_create functions.

The second one is, of course, preferable.

To write stubs, you'll need to include the unistd.h file that you modified when adding the system call. If you #include <linux/unistd.h>, you will include the unmodified version (assuming you are not modifying the kernel source that was already on your system, which you're should not be doing!). You will need to include the modified file directly into your user programs, so use something like:

#include "/usr/src/linux-cs111/linux-2.6.8/include/linux/unistd.h"

You may find it helpful to write additional system calls to aid with debugging. See the suggested additions page for details.

printk statement for joining process

In case you were wondering why in the log file it seems like every process has the same identifier, the printk statement in barrier_join is incorrectly printing the user id for the process, not pid. The line:

printk(KERN_WARNING "Adding process %d to the barrier queue\n", current->uid)

should be:

printk(KERN_WARNING "Adding process %d to the barrier queue\n", current->pid)

The same bug is found on the printk for barriers with timeouts as well.

No timeout value in barrier_create should be -1

In the comments for barrier_create we have the following comments:

/* barrier_create:
* int num_processes: the threshold for this barrier (must be >= 1)
* long timeout: the maximum amount of time to hold a process at the barrier,
* or 0 if there is no timeout (must be >= 0)
*/

It should actually be:
or -1 if there is no timeout.

You should call barrier_create with timeout = -1 to indicate there is no timeout, and anything >= 0 is considered a valid timeout value. The EINVAL error should be set if timeout < -1.

Initializing wait_queue_head_t variables

For initializing the wait_queue_head you can use the following function:

wait_queue_head_t q;
init_waitqueue_head(q);

ENOMOEM = ENOMEM

In barrier.c, ENOMEM is accidently spelled as ENOMOEM.

updated 5/11/05