CS161 Day 3 In-Class Exercise
Defining Threads and Processes
Question 1: Where does OS/161 define the
structures that represent a process and a thread?
Question 2: In OS/161's definition for a
thread, you'll find this field:
struct cpu *t_cpu; /* CPU thread runs on */
Why isn't this field in the definition for a process?
In other words, why isn't a process associated with
a CPU?
Copying Data Between the Kernel and the User-level
Consider the Linux implementation of the
gethostname(char *name, int len)
system call:
struct rw_semaphore{
long count;
spinlock_t wait_lock;
struct list_head wait_list;
};
struct rw_semaphore uts_sem;
int gethostname(char *name, int len)
{
int i, errno;
struct new_utsname *u;
if (len < 0)
return -EINVAL;
------->down_read(&uts_sem);
------->u = utsname(); //Call a kernel function to
//get the hostname.
i = 1 + strlen(u->nodename);
if (i > len)
i = len;
errno = 0;
if (copy_to_user(name, u->nodename, i))
errno = -EFAULT;
up_read(&uts_sem);
return errno;
}
A corresponding system call named
sethostname(const char *name, size_t len)
allows the hostname to be written.
Question 3: If the order of the two arrowed
lines were swapped, what problems might arise?
Question 4: Suppose that interrupts are not
disabled when the kernel invokes sethostname().
What ramifications does this have for the ways in
which interrupt handlers can read and write to
hostname-related kernel data? Does it matter whether
a piece of hostname-related kernel data is greater
than the size of a word (e.g., 32 bits on a 32-bit
machine)?
Question 5: In Linux, the operating system is
mapped into the top of each process’s virtual address
space:
The Linux copy_to_user() function copies
kernel data to a user-supplied buffer. Give two
concrete examples of how a malicious or buggy program
can pass improper data to gethostname(char *name, int len),
and describe how copy_to_user() would
detect those errors and prevent the kernel from
possible corruption.
File Descriptors
Question 6: What is the difference between
the FILE * returned by fopen(),
and the int fd returned by open()?
When would one be more useful than the other to an
application? To help answer those questions, draw
an architectural diagram which shows the relationship
between application code, libc, and the operating system.
Question 7: After a fork(), both
the parent and the child should possess file
descriptors with the same numbers and which
point to the same files. However, imagine that
the child and the parent write to the same
location in the same file at the same time--which
write should “win”? What if one process reads
from the same offset in a file that the other
process is writing--what data should the reading
process read, and what data should the writing
process write (if any)? Devise a high-level conflict
management policy that the kernel can use to
provide “reasonable” results in both scenarios, for
some definition of “reasonable.” Then describe
at a high-level how the kernel could implement
such a policy.