1. Answer True/False (T/F) (1 point each)
____ The call dup2() will show in the truss output.
____ There is a set of registers for every kernel level thread in
the process table.
____ The cost of a multiprocessor computer grows linearly with
the number of CPUs.
____ A parent and a child process may communicate by a pipe created
by the child.
____ If "a" is a local variable, then &a is a memory address
in the data section
____ The function strcat(a,b) allocates strlen(a) + strlen(b) +
1 bytes of memory using malloc.
____ Disabling interrupts could be used to enforce mutual exclusion.
____ A program that runs with non- preemptive scheduling may deadlock.
____ The user time in the time command may be smaller than the system
time.
____ An exit code of 1 in UNIX means success.
____ When a process calls fork, the number of open file objects
in the kernel remain the same.
____ Programs that run preemptive scheduling finish sooner than programs
that run with non-preemptive scheduling.
____ A program needs to run in kernel mode to install an interrupt
handler in the interrupt vector.
____ The size in bytes of a variable of type (char *) is 1 byte.
____ Kernel threads in the same process share the same file descriptors.
____ The time command in mentor could show that the user time is larger
than the real time in a multi-threaded program.
____ After forking a process, if an environment variable is modified
in the parent it will be modified in the child.
____ The counter of a semaphore could have a negative value.
____ A moving average with an alpha=.5 gives the same weight to the
previous two samples.
____ In a soft real time system jobs will always finish on time.
2. (3 pts.) What is the consequence of substituting the thread_yield()
call by an empty statement in the spinlock locking code?
3. (3 pts.) What factors have to be considered when choosing the length
of a quantum time?
4. (3 pts.) What are the advantages and disadvantages of using threads
vs. using processes?
5. (3 pts.) Write the pseudocode of sema_wait and sema_post
7. (10 pts.) Write the code for the function
char *strstr(const char *s1, const char *s2) The strstr() function locates the first occurrence of the string s2 (excluding the terminating null character) in string s1. The strstr() function returns a pointer to the located string, or a null pointer if the string is not found. If s2 points to a string with zero length (that is, the string ""), the function returns s1. |
char *strstr(const char *s1, const char *s2) { } |
8. (10 pts.) Write the implementation of the procedure unsetenv() that removes an environment variable from the process environment. unsetenv() will return if the environment variable does not exist. Implement unsetenv as it should be implemented in the shell project. |
extern char ** environ; void unsetenv( char * variable ) { } |
9. (15 pts.) The following class implements a multi-threaded single-linked list queue of names. The enqueue() function waits if there are already maxQueueItems in the list and then adds a name to the queue. dequeue() will wait if the list is empty and then it will remove the oldest name in the queue. The enqueue() and dequeue() calls can be called simultaneously by different threads. Add the body of these functions and member variables so multiple threads can run the operations simultaneously without corrupting the name queue. The NameQueue constructor receives as parameter maxQueueItems . Important: The queue has to be implemented as a single-linked list. |
struct NameNode { }; class NameQueue { // Extra variables here public: NameQueue( int maxQueueItems ) { //Initialization code here } void enqueue( char * name ) { // Enqueues a name in the queue. Waits if queue is full } char * dequeue() { // Dequeues a name from the queue. Waits if queue is empty. } }; |
10. (15 pts.) Write a function runPipe(command1, command2)
that executes command1 and command2 connected through a pipe
. Command1 and command2 are arrays of arguments that are
NULL terminated. The output of command1 will be connected to the input of
command2 using a pipe. Both command1 and command2 will run in different
child processes. The process calling runPipe will wait until the child process
that runs command2 terminates. command1 will have the same standard input
of the parent process and command2 will have the same standard output of
the caller process. See how runPipe is used in main() below. |
int runPipe( char ** command1, char ** command2 ) { } main() { char * command1[] = {"ls", NULL}; char * command2[] = {"grep", "aaa", NULL}; //Prints the files in the current directory that contain the substring "aaa" runPipe( command1, command2 ); } |
11. (15 pts.) Implement a message system with the following characteristics. void msgSendPrio( int msg, int priority) will send a message with the given priority and it will block until the receiver gets the message. The method int msgRecvPrio( int minPriority ) will remove and return the oldest message with a priority larger or equal to minPriority. msgRecvPrio() will wait until there is such message. Hint. You may need a linked list of waiting sender/receivers with semaphores in each list node. |
// Data structures needed void msgSendPrio( int msg, int priority) { } int msgRecvPrio( int minPriority ){ } |