section notes 2/22/2007 PROJECT 2B Discuss grading guidelines preemption: (Graded on 0-15 scale) -8 non-compilation -5 not turning on the timer in the first place -3 splx(LOW) before sthread_switch() -3 disabling interrupts in user_yield before switch -3 not using proper stack-like behavior of splx() -3 start function needs splx(LOW) -2 atomic_test_and_sets in places not required. -2 sthread_enqueue requires synchronization. -2 improper interaction between yield/join with splx() -2 mutex functions need splx() in some areas. -1 superfluous interrupt disable/enabling in same function -1 sthread_exit should not need extra splx(LOW) -1 (misc. bad style) And for the burgers problem: (Graded on 0-10 scale) -5 non-compilation -2 program segfaults -2 not implementing a stack. -2 use of shared mem without synchronization in producer -2 use of shared mem without synchronization in consumer -2 no condition variables to mediate access to stack (possible starvation) -1 main() does not join children; instead looks at variables w/o synchronization to determine finish condition -1 main() only joins last child spawned instead of all children Go over example of burger problem done correctly: mutex stack_lock; condition_var not_empty; int burgers_to_make = N; int next_burger = 0; int num_consumed = 0; int producer(void *arg) { int my_id = (int) arg; while(true) { mutex_lock(stack_lock); if(last_made == burgers_to_make) break; else { printf("Cook %i made burger %i\n", my_id, next_burger); stack_push(next_burger++); notify(not_empty); } mutex_unlock(stack_lock); } mutex_unlock(stack_lock); broadcast(not_empty); return 0; } int consumer(void *arg) { int my_id = (int) arg; int burger; while(true) { mutex_lock(stack_lock); if(num_consumed == burgers_to_make) break; while(stack_size() == 0) { if(num_consumed == burgers_to_make) { mutex_unlock(stack_lock); thread_exit(0); } cv_wait(stack_lock, not_empty); } burger = stack_pop(); num_consumed++; printf("Student %i ate burger %i\n", my_id, burger); mutex_unlock(stack_lock); } mutex_unlock(stack_lock); return 0; } int main() { thread *allthreads = malloc(sizeof(thread) * (num_producers + num_consumers)); for(i = 0; i < num_producers; i++) allthreads[i] = create_thread(producer, (void*)i, 1); for(j = 0; j < num_consumers; j++) allthreads[i+j] = create_thread(consumer, (void*)i, 1); //wait on all threads. for(i = 0; i < num_producers + num_consumers; i++) thread_join(allthreads[i]); } alternate ending: while(true) { mutex_lock(stack_lock); if(num_consumed == burgers_to_make) exit(0); //terminate the program. mutex_unlock(stack_lock); thread_yield(); } Important note: If your stack had a max height, then you also needed a *SECOND* condition variable that was named not_full which is signaled each time a consumer eats one.. PROJECT 3 SYSTEM SET UP: - note that we're using /cse451/projects/FC4-451-2Disk.tar.bz2 this time ** this image is persistent! How to get your setup compiling: ~$ cd /cse451/username /cse451/username$ mkdir proj4 /cse451/username$ cd proj4 /cse451/username/proj4$ cp /cse451/projects/linux-2.6.13.2-cse451fs.tar.bz2 . /cse451/username/proj4$ tar vjxf linux-2.6.13.2-cse451fs.tar.bz2 (wait for it to unpack) /cse451/username/proj4$ cp /cse451/projects/projFS.tar.bz2 . /cse451/username/proj4$ tar vjxf projFS.tar.bz2 (wait for it to unpack) /cse451/username/proj4$ ls linux-2.6.13.2/ projFS/ (and the tar files) /cse451/username/proj4$ cd linux-2.6.13.2/fs /cse451/username/proj4/linux-2.6.13.2/fs$ ln -s ../../projFS/cse451_2.6/ cse451fs /cse451/username/proj4/linux-2.6.13.2/fs$ ls -la cse* lrwxrwxrwx 1 ak grad_cs 24 Feb 21 21:19 cse451fs -> ../../projFS/cse451_2.6/ To build mk451fs: $ cd /cse451/username/proj4/projFS/mkfs $ make (This will build 'mk451fs') To build the kernel (arch/i386/boot/bzImage) and cse451fs.ko: $ cd /cse451/username/proj4/linux-2.6.13.2/ $ make cse451fs.ko will be in /cse451/username/proj4/projFS/cse451_2.6 bzImage will be in /cse451/username/proj3/linux-2.6.13.2/arch/i386/boot/