void customer_function(void *arg) { customer_data *customer = (customer_data *)arg; syscall_lock_acquire(&barber_lock); printf("Customer #%d arrives\n", customer->id); if (sitting + standing >= MAX_WAITING) { printf("Barbershop full. Customer #%d leaving\n", customer->id); syscall_lock_release(&barber_lock); syscall_exit(0); } if (sitting >= MAX_SITTING) { printf("Chairs occupied. Customer #%d standing in line\n", customer->id); standing++; syscall_condition_wait(&standing_cond, &barber_lock); standing--; } if (sitting <= MAX_SITTING && next_customer != NULL) { printf("Customer #%d takes a seat\n", customer->id); sitting++; syscall_condition_wait(&sitting_cond, &barber_lock); sitting--; } printf("Customer #%d is being serviced\n", customer->id); next_customer = customer; syscall_condition_signal(&barber_cond, &barber_lock); syscall_condition_wait(&customer->cond, &barber_lock); syscall_lock_release(&barber_lock); syscall_exit(0); }
void barber_function(void *arg) { barber_data *barber = (barber_data *)arg; customer_data *customer; syscall_lock_acquire(&barber_lock); while (1) { printf("Barber #%d looking for new customers\n", barber->id); if (next_customer == NULL) { syscall_condition_signal(&sitting_cond, &barber_lock); syscall_condition_signal(&standing_cond, &barber_lock); printf("Barber #%d sleeping\n", barber->id); syscall_condition_wait(&barber_cond, &barber_lock); printf("Barber #%d got woken up!\n", barber->id); } customer = next_customer; next_customer = NULL; printf("Barber #%d servicing customer #%d\n", barber->id, customer->id); syscall_lock_release(&barber_lock); simulatedwait(100000); syscall_lock_acquire(&barber_lock); printf("Barber #%d done servicing customer #%d\n", barber->id, customer->id); syscall_condition_signal(&customer->cond, &barber_lock); } }
/*-----------------------------------------------------------------------------------*/ static u32_t cond_wait(cond_t *cond, mutex_t *mutex, u32_t timeout) { int tdiff; /* unsigned long sec, usec; */ /* struct timeval rtime1, rtime2; */ /* struct timespec ts; */ /* struct timezone tz; */ intptr_t retval; uint64_t start, end; if (timeout > 0) { /* Get a timestamp and add the timeout value. */ /* gettimeofday(&rtime1, &tz); */ /* sec = rtime1.tv_sec; */ /* usec = rtime1.tv_usec; */ /* usec += timeout % 1000 * 1000; */ /* sec += (int)(timeout / 1000) + (int)(usec / 1000000); */ /* usec = usec % 1000000; */ /* ts.tv_nsec = usec * 1000; */ /* ts.tv_sec = sec; */ start = syscall_now_in_nanosec(); retval = syscall_condition_wait_timeout(cond, mutex, timeout); if (retval == M_TIMED_OUT) { return SYS_ARCH_TIMEOUT; } else { /* Calculate for how long we waited for the cond. */ end = syscall_now_in_nanosec(); /* gettimeofday(&rtime2, &tz); */ /* tdiff = (rtime2.tv_sec - rtime1.tv_sec) * 1000 + */ /* (rtime2.tv_usec - rtime1.tv_usec) / 1000; */ tdiff = (end - start) / 1000 / 1000; if (tdiff <= 0) { return 0; } return tdiff; } } else { syscall_condition_wait(cond, mutex); return SYS_ARCH_TIMEOUT; } }
void thread_function(void *arg){ thread_data *data = (thread_data *)arg; while(1) { syscall_lock_acquire(&baton_lock); // Wait until baton is non-zero (meaning that the thread // has the baton) while(data->baton == 0) { syscall_condition_wait(&data->cond, &baton_lock); } // First thread should perform countdown if(data->id == 0) { printf("\n%d: New round\n", data->id); if(--data->countdown == 0) { data->baton = -1; // create a stop baton } } // Pass the baton on to the next thread printf("%d: passing the baton on to %d\n", data->id, data->next->id); data->next->baton = data->baton; // Quit if the baton was a stop baton if(data->baton < 0){ printf("%d: I quit.\n",data->id); syscall_condition_signal(&data->next->cond, &baton_lock); syscall_lock_release(&baton_lock); syscall_exit(0); } //Remove baton from self and signal the next thread data->baton = 0; syscall_condition_signal(&data->next->cond, &baton_lock); syscall_lock_release(&baton_lock); } }
/** * Handle system calls. Interrupts are enabled when this function is * called. * * @param user_context The userland context (CPU registers as they * where when system call instruction was called in userland) */ void syscall_handle(context_t *user_context) { /* When a syscall is executed in userland, register a0 contains * the number of the syscall. Registers a1, a2 and a3 contain the * arguments of the syscall. The userland code expects that after * returning from the syscall instruction the return value of the * syscall is found in register v0. Before entering this function * the userland context has been saved to user_context and after * returning from this function the userland context will be * restored from user_context. */ switch(user_context->cpu_regs[MIPS_REGISTER_A0]) { case SYSCALL_HALT: halt_kernel(); break; case SYSCALL_EXIT: syscall_exit(user_context->cpu_regs[MIPS_REGISTER_A1]); break; case SYSCALL_WRITE: user_context->cpu_regs[MIPS_REGISTER_V0] = syscall_write(user_context->cpu_regs[MIPS_REGISTER_A1], (char*)user_context->cpu_regs[MIPS_REGISTER_A2], (user_context->cpu_regs[MIPS_REGISTER_A3])); break; case SYSCALL_READ: user_context->cpu_regs[MIPS_REGISTER_V0] = syscall_read(user_context->cpu_regs[MIPS_REGISTER_A1], (char*)user_context->cpu_regs[MIPS_REGISTER_A2], (user_context->cpu_regs[MIPS_REGISTER_A3])); break; case SYSCALL_JOIN: user_context->cpu_regs[MIPS_REGISTER_V0] = syscall_join(user_context->cpu_regs[MIPS_REGISTER_A1]); break; case SYSCALL_EXEC: user_context->cpu_regs[MIPS_REGISTER_V0] = syscall_exec((char*)user_context->cpu_regs[MIPS_REGISTER_A1]); break; case SYSCALL_FORK: user_context->cpu_regs[MIPS_REGISTER_V0] = syscall_fork((void (*)(int))user_context->cpu_regs[MIPS_REGISTER_A1], user_context->cpu_regs[MIPS_REGISTER_A2]); break; case SYSCALL_LOCK_CREATE: user_context->cpu_regs[MIPS_REGISTER_V0] = syscall_lock_create((lock_t*) user_context->cpu_regs[MIPS_REGISTER_A1]); break; case SYSCALL_LOCK_ACQUIRE: syscall_lock_acquire((lock_t*) user_context->cpu_regs[MIPS_REGISTER_A1]); break; case SYSCALL_LOCK_RELEASE: syscall_lock_release((lock_t*) user_context->cpu_regs[MIPS_REGISTER_A1]); break; case SYSCALL_CONDITION_CREATE: user_context->cpu_regs[MIPS_REGISTER_V0] = syscall_condition_create((cond_t*) user_context->cpu_regs[MIPS_REGISTER_A1]); break; case SYSCALL_CONDITION_WAIT: syscall_condition_wait((cond_t*) user_context->cpu_regs[MIPS_REGISTER_A1], (lock_t*) user_context->cpu_regs[MIPS_REGISTER_A2]); break; case SYSCALL_CONDITION_SIGNAL: syscall_condition_signal((cond_t*) user_context->cpu_regs[MIPS_REGISTER_A1], (lock_t*) user_context->cpu_regs[MIPS_REGISTER_A2]); break; case SYSCALL_CONDITION_BROADCAST: syscall_condition_broadcast((cond_t*) user_context->cpu_regs[MIPS_REGISTER_A1], (lock_t*) user_context->cpu_regs[MIPS_REGISTER_A2]); break; default: KERNEL_PANIC("Unhandled system call\n"); } /* Move to next instruction after system call */ user_context->pc += 4; }