Sherry Hsia CS 354 Spring 2000 Midterm Solutions 1. A real-time system is used when there is a rigid time requirement in the operation. For example, for medical equipment, traffic lights, computer systems for cars, etc. There are two types of real-time systems. A hard real-time systems deal with critical tasks that should be completed on time while soft real-time systems deal with critical tasks that get the highest priority until completion. 2. In kernel mode, the system has access to an extended set of instructions, it can modify the interrupt vector, and can modify any section of memory. In user mode, the system has access to only a restricted set of instructions, cannot modify the interrupt vector, and has access to a restricted range of memory. 3. Modern CPU's have kernel and user mode because of reliability and security. Reliability because the user program can crash without crashing other programs. Security because different user processes are kept separate, and resources can be protected by unwanted users. 4. System calls use software interrupts because software interrupts allow switching from user to kernel mode. System calls is the way to access operating system services and need to run in kernel mode. In kernel mode, the system will have access to the interrupt vector and the memory it will need to perform its operations. 5. Steps for servicing an interrupt a. interrupt b. save registers, program counter, return address, etc. c. go to interrupt vector and jump to address corresponding to that interrupt d. execute driver e. restore all registers and other memory saved in b. f. return to place in code where interrupt was executed -> to return address 6. There is one program counter and one set of registers for each thread in the process. 7. Processes are in the "waiting" state most of the time. The exception are numerical analysis programs and screen-savers that are CPU intensive and do not require to wait for input. 8. The advantages of using threads are that process creation is more expensive than thread creation and context switch among threads are less expensive. The communication among threads are also very fast. The disadvantages of threads vs. processes are that with threads there is more chance for a deadlock and that multiple threads are less robust than multiple processes. If one thread crashes, the entire process and all the threads will have to exit. 9. When choosing a quantum, you have to consider whether you want a short quantum or a long quantum. A short quantum produces a short response time, a high context switch overhead, is good for interactive programs, and produces longer total time for programs. A long quantum produces longer response time, lower context switch overhead, is good for batch programs, and produces shorter total time for programs. 10. The advantages of using spinlock vs. disable/enable interrupts are that the CPU does not need to disable interrupts and that spinlocks can be done in user space. Disable interrupts is a privileged command done in the kernel. The disadvantage of spinlock include the CPU being consumed by spinning. 11. Int test_and_set ( int *v ) { int oldval = *v; *v = 1; return oldval; } void spinlock ( int *lock ) { while (test_and_set(lock)); } void spinunlock ( int *lock ) { *lock = 0; } This works because lock is initially set to 0. When the first process calls spinlock, test_and_set will set lock to 1 and cause the while loop to terminate. Then, when another process calls spinlock, the lock is already taken and the new process will continue "spinning" in the while loop until the first process calls spinunlock which will reset lock to 0. 12. FCFS: 0 + 40 + 45 / 3 = 28.3 ms SJF: 0 + 5 + 35 / 3 = 13.3 ms Round Robin: 0 + 10 + 15 / 3 = 8.3 ms 13. Expressions that are equivalent to a[j] - *(a + j) - *(&a[0] + j) - *(&a[j]) - ((char *)&a[0] + j *sizeof(a[0])) 14. typedef void (*FuncPtr) (void * arg) void arrayMapper ( void *a, FuncPtr func, int n, int elementSize ) { for ( int h = 0; h < n ; h++ ) { (*func) ( (void*)( (char *) a + (h * elementSize)) ); } } 15. int stackPointer; int stack [ MaxStack ]; sema_t full, empty; mutex_t mutex; void push (int a) { sema_wait (&empty); mutex_lock (&mutex); stack[ stackPointer ] = a; stackPointer++; mutex_unlock (&mutex); sema_post (&full); } int pop() { sema_wait (&full); mutex_lock (&mutex); stackPointer--; int tmp = stack[ stackPointer ]; mutex_unlock (&mutex); sema_post (&empty); return tmp; } main() { sema_init ( empty, 0 ); sema_init ( full, MaxStack ); } 16. client_thread() { while(1) { a = input(); b = input(); sema_post(&input); sema_wait(&print); print c; } } server_thread() { while(1) { sema_wait(&input); c = a + b; sema_post(&print); } } main( ) { sema_init( input, 0 ); sema_init( print, 0 ); } 17. int redirectStdin ( char *filename) { int fd = open (filename, O_CREAT | O_TRUNC | O_RDRW, 0666); if ( fd < 0 ) { return -1; } int err = dup2 ( fd, 0 ); close( fd ); if (err) { return -1; } return 0; } main() { if (redirectStdin ("myfile") < 0 ) { perror ( "redirectStdout" ); exit (-1); } int n = scanf ( "%d", &j ); if ( n == 1 ) { printf ( "Read j = %d from myfile\n"); } else { printf ( "Error reading j from myfile\n"); } } 18. int redirectStdinFromPipe ( char *command, char *arg1) { int fdpipe[2]; pipe(fdpipe); int pid = fork(); if (pid < 0 ) { close(fdpipe[0]); close(fdpipe[1]); return -1; } if ( pid == 0 ) { dup2(fdpipe[0],1); // redirects output to the // pipe close(fdpipe[0]); close(fdpipe[1]); // execute commands char *args[3]; args[0] = command; args[1] = arg1; args[2] = 0; execvp(command, args); return -1; } // redirects stdin from the pipe dup2(fdpipe[1],0); close(fdpipe[0]); close(fdpipe[1]); return 0; } int main() { if (redirectStdinFromPipe ( "ls", "/") { perror( "redirectStdinFromPipe"); exit(-1); } const int bufferSize = 1024; char buffer[bufferSize]; read ( 1, buffer, bufferSize ); } 19. void zombie_process(int x) { int killed_process; killed_process = wait3(NULL, 0, NULL); if (BACKGROUND == 1) { printf("%d Child Exited...\n", killed_process); BACKGROUND = 0; } } struct sigaction z; int main() { sigignore(SIGINT); z.sa_handler = zombie_process; sigemtypset(&z.sa_mask); z.sa_flags = SA_RESTART; sigaction(SIGCHLD, &z, NULL); } 20. char *strcpy ( char *dest, char *src ) { char *tmp = dest; while (*src) { *dest = *src; dest++; src++; } *dest = 0; return (tmp); }