1. (6 pts.) Assume the following program. Write the memory section in the program that corresponds to each of the following memory addresses:
Memory Address Memory Section &a BSS &b DATA &c STACK &d STACK &e STACK e HEAP &main TEXT &printf SHARED LIBARY or TEXT
int a[300];
int b = 25;void foo()
{
int d;
}int
main()(
int c;
int * e = new int;
}
2. (4 pts.) Describe the steps of an interrupt routine
1. Save registers and return address
2. Jump to the address in the interrupt vector that corresponds to this interrupt
3. Service the interrupt
4. Retry the offending instruction if necessary
5. Restore the registers and return to the saved return address.
3. (4 pts.) What is protected and unprotected CPU mode?
In the CPU protected mode (kernel mode) the CPU is able to execute an extended set of instructions, such as writing to devices. In this mode the CPU is also able to write to any address in physical memory and to change the interrupt vector.4. (4 pts.) Which CPU mode do interrupts run in and why?In unprotected mode (user mode), the CPU is able to execute a reduced set of instructions and it is only allowed to acces a restricted range of memory.
Interrupts run in protected mode (kernel mode) to be able to access device registers and kernel memory.
5. (4 pts.) Why do system calls use software interrupts instead
of procedure calls?
System calls is the way to access operating system services and need to run in kernel mode. Software interrupts allow to switch from user to kernel mode.6. (4 pts.) Why do modern operating systems use preemptive scheduling?
A non-preemptive operating system has the danger of being hang if one of the applications never gives up the processor. Modern operating systems have preemptive scheduling to prevent this problem, giving a fair share of time to each ready process.7. (4 pts.) How many processes can be in running state at any given time?
One for each CPU in the system.8. (4 pts.) Describe how a small quantum affects the response time and the total execution time.
The shorter the quantum, the faster the response time. But also the shorter the quantum the longer the execution time due to excesive context switching.
9. (6 pts.) Assume that a computer executes the following jobs:
Process | Estimated Time (ms) |
P1 | 80 |
P2 | 40 |
P3 | 20 |
Compute the average waiting time if the following scheduling algorithms are used:
FCFS:
(80+120)/3 = 200/3 = 66.67msSJF:
(20 + 60)/3 = 80/3 = 26.67msRound Robin (Quantum=10ms):
(10 + 20)/3 = 10ms
10. (4 pts.) What are the differences between a thread and a process.
A thread is a path of execution. A process can have multiple threads but not vice versa. A process has at least one thread. Multiple threads may share the same address space, but each process will have its own independent address space.
11. (4 pts.) What are the differences between a user-level thread
and a kernel thread.
The context switch between two user level threads is performed entirely in user space. If one use-level thread has to wait inside the kernel, other user-level threads that run on top of the same kernel thread will block as well. Multiple user level threads can run on top of one kernel-level thread but not vice versa. The management of kernel-level threads is done by the kernel. The management of user-level threads is done by the user-level thread library.12. (7 pts.) The following multi-threaded circular queue implementation has a serious flaw. Explain what is the flaw and the repercussion.
const int MAXQUEUE = 10;
int queue[ MAXQUEUE ]; int tail = 0; int head = 0; sem_t empty, full; mutex_t mutex; void enqueue( int a )
int dequeue()
main()
|
The flaw is that lock() is called before wait() in both enqueue and dequeue. The repercusion is that if the queue is full and enqueue() is called, wait(full) will block while holding the mutex lock. This will cause that any other thread that calls dequeue() will block when calling lock() and the queue will remain full, causing the threads to deadlock.The same happens in the queue is empty and dequeue() is called.
13. (15 pts.) Complete the following procedures. sendBroadcast()
sends a message to N threads that will call receiveBroadcast().
sendBroadcast()
will block until the N threads have called receiveBroadcast(). receiveBroadcast()
will block until a thread has called sendBroadcast()
and the variable
theMessage
has a valid value.
const int N = 5;
int theMessage; void sendBroadcast( int msg )
theMessage = msg; for ( int i = 0; i < N; i++ ) signal( sem-wakeup-receiver );
for (int i = 0; i < N; i++) wait( sem-wait-until-all-received );
int receiveBroadcast()
wait( sem-wakeup-receiver ) int tmp = theMessage; signal( sem-wait-until-all-received ); return tmp;
main()
}
|
14. (15 pts.) Complete the procedure redirectStdout( fileName )
to redirect the standard output to a file fileName. The procedure
will return -1 if any error occurrs or 0 if it succeeds. Look at main()
to see how redirectStdout( ) is used. NOTE: ERROR CHECKING IS
IMPORTANT.
int redirectStdout( char * fileName )
{ int fd = open( filenam, O_CREATE | O_RDWR|O_TRUNC, 0644 ); if ( fd < 0 ) return -1;
// Redirect standard out to fle
// We don't need fd anymore
if ( err ) return -1;
return 0;
main()
// "Hello world" will be written to "myfile"
|
15. (15 pts.) Complete the procedure redirectStdoutToPipe( command,
arg1) that will 1.redirect the standard output to a pipe. 2. fork a
process that will execute a command with argument arg1
that
will read the input from the pipe. redirectStdoutToPipe()
will return
-1 if an error occurrs or 0 if it succeeds. Look at main() to see
how redirectStdoutToPipe( ) is used. NOTE: ERROR CHECKING IS
IMPORTANT.
int
redirectStdoutToPipe( char * command, char * arg1) { int fdpipe[2]; // Create pipe
//Create child process
if ( pid < 0 ) {
if ( pid == 0 ) {
//
Redirect the standard input to come from pipe
//
Close file descriptors
//Execute
command
// If returns,
something went wrong
// This is the parent
// Close pipe
return 0;
int
printf("Hello world\n");
|