static void *initproc_run(int arg1, void *arg2) { switch(curtest) { case 0: return NULL; case 1: processSetUp(); break; case 2: processSetUp(); break; case 3: processSetUp(); break; case 4: processSetUp(); break; case 5: processSetUp(); break; case 6: producer_consumer();break; case 7: deadlock();break; case 8: reader_writer();break; case 9: shellTest();break; case 10: dead_own(); break; case 11: vfs_test_setup(); break; case 12: add_tests(); break; case 13: ut_vmmap(); break; } int status; while(!list_empty(&curproc->p_children)) { pid_t child = do_waitpid(-1, 0, &status); /*dbg(DBG_INIT,"Process %d cleaned successfully\n", child);*/ } return NULL; }
/************************************************************************************************** * msg_send ************************************************************************************************** * <Ring 0> Send a message to the dest proc. If dest is blocked waiting for the message, * copy the message to it and unblock dest. * Otherwise the caller will be blocked and appended to the dest's sending queue. * * @param current The caller, the sender. * @param dest To whom the message is sent. * @param msg Pointer to the MESSAGE struct. * * @return 0 if success. *************************************************************************************************/ PRIVATE int msg_send(PROCESS* current, int dest, MESSAGE* msg){ PROCESS* sender = current; PROCESS* p_dest = proc_table + dest; assert(proc2pid(sender) != dest); if(deadlock(proc2pid(sender), dest)){ /* Is there deadlock chain? */ panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); } /* dest is waiting for that msg or ANY msg. */ if((p_dest->flags & RECEIVING) && (p_dest->recv_from == proc2pid(sender) || p_dest->recv_from == ANY)){ assert(p_dest->p_msg); assert(msg); phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), msg), sizeof(MESSAGE)); p_dest->p_msg = 0; p_dest->flags &= ~RECEIVING; /* dest has received the message */ p_dest->recv_from = NO_TASK; unblock(p_dest); assert(p_dest->flags == 0); assert(p_dest->p_msg == 0); assert(p_dest->recv_from == NO_TASK); assert(p_dest->send_to == NO_TASK); assert(sender->flags == 0); assert(sender->p_msg == 0); assert(sender->recv_from == NO_TASK); assert(sender->send_to == NO_TASK); }else{ /* However, dest is not waiting for the message */ sender->flags |= SENDING; assert(sender->flags == SENDING); sender->send_to = dest; sender->p_msg = msg; /* append to the sending queue */ PROCESS* p; if(p_dest->q_sending){ p = p_dest->q_sending; while(p->next_sending){ p = p->next_sending; } p->next_sending = sender; }else{ p_dest->q_sending = sender; } sender->next_sending = 0; block(sender); assert(sender->flags == SENDING); assert(sender->p_msg != 0); assert(sender->recv_from == NO_TASK); assert(sender->send_to == dest); } return 0; }
/** * <Ring 0> Send a message to the dest proc. If dest is blocked waiting for * the message, copy the message to it and unblock dest. Otherwise the caller * will be blocked and appended to the dest's sending queue. * * @param current The caller, the sender. * @param dest To whom the message is sent. * @param m The message. * * @return Zero if success. *****************************************************************************/ PRIVATE int msg_send(struct proc* current, int dest, MESSAGE* m) { struct proc* sender = current; struct proc* p_dest = proc_table + dest; /* proc dest */ assert(proc2pid(sender) != dest); /* check for deadlock here */ if (deadlock(proc2pid(sender), dest)) { panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); } if ((p_dest->p_flags & RECEIVING) && /* dest is waiting for the msg */ (p_dest->p_recvfrom == proc2pid(sender) || p_dest->p_recvfrom == ANY)) { assert(p_dest->p_msg); assert(m); phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), m), sizeof(MESSAGE)); p_dest->p_msg = 0; p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */ p_dest->p_recvfrom = NO_TASK; unblock(p_dest); assert(p_dest->p_flags == 0); assert(p_dest->p_msg == 0); assert(p_dest->p_recvfrom == NO_TASK); assert(p_dest->p_sendto == NO_TASK); assert(sender->p_flags == 0); assert(sender->p_msg == 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == NO_TASK); } else { /* dest is not waiting for the msg */ sender->p_flags |= SENDING; assert(sender->p_flags == SENDING); sender->p_sendto = dest; sender->p_msg = m; /* append to the sending queue */ struct proc * p; if (p_dest->q_sending) { p = p_dest->q_sending; while (p->next_sending) p = p->next_sending; p->next_sending = sender; } else { p_dest->q_sending = sender; } sender->next_sending = 0; block(sender); assert(sender->p_flags == SENDING); assert(sender->p_msg != 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == dest); } return 0; }
/* The main method, as called by the main ('host') thread. */ int main(int argc, char** argv) { printf("[ The Blue Lotus ]\n\n\n"); /* Read input arguments. */ int nPatrons = 8; char eattype = 'e'; typelist = ""; int n; if (argc > 1) { if ((n = atoi(argv[1])) && n >= 2) { nPatrons = n; if (argv[2] && strlen(argv[2]) >= 1) { eattype = argv[2][0]; } } else if ((typelist = argv[1]) && (n = strlen(typelist)) && n >= 2) { nPatrons = n; } else { printf("{ warning } '%s' is not a valid number of patrons or a valid" " set of patron types.\n" "\tExamples of valid patron definitions:\n" "\t\t./bluelotus n\n\t\t./bluelotus n x\n\t\t./bluelotus xy...z\n" "\twhere n >= 2 and x, y and z are patron types:\n" "\t\t'e':\t evenhanded\n" "\t\t'l':\t lefthanded\n" "\t\t'r':\t righthanded\n" "\t\t'a', 'o': aggressive (opportunistic)\n" "\t\t'p', 's': polite (shy)\n" "\t\t'h':\t hungry\n" "\t\t'n':\t not hungry\n" "\tBy default, there will be 8 evenhanded patrons.\n\n", argv[1]); typelist = ""; } } if (strlen(typelist) < 2) { typelist = malloc((nPatrons + 1) * sizeof(char)); for (int i = 0; i < nPatrons; i++) { typelist[i] = eattype; } typelist[nPatrons] = '\0'; } #ifndef VERBOSE printf("Patron eating methods: %s.\n", typelist); #endif /* Initialise pthreads. */ pthread_t PT[nPatrons]; pthread_attr_t ptattr; pthread_attr_init(&ptattr); pthread_attr_setscope(&ptattr, PTHREAD_SCOPE_SYSTEM); init_table(nPatrons); /* The restaurant is not yet opened. */ IsOpen = -1; #ifdef VERBOSE printf("Welcome to our wonderful restaurant. There are %d patrons dining" " this evening. Please take a seat.\n", nPatrons); #endif /* All is ready. Start creating threads. */ for (int i = 0; i < nPatrons; i++) { if (pthread_create(&PT[i], &ptattr, &dine, typelist)) { printf("{ fatal error } Could not create pthread #%d.\n", i); return -1; } } #ifdef VERBOSE printf("Don't worry, there is more than enough rice to go around!\n"); #endif /* All threads created. Keep serving rice until deadlock occurs. */ IsOpen = 1; time_t starttime, runtime; struct timespec naptime; naptime.tv_sec = 0; naptime.tv_nsec = INTERVAL * 1000000; starttime = time(NULL); /* There will be 2 * RUNTIME / INTERVAL checks for deadlock, each seperated * by a INTERVAL milliseconds sleep. The total runtime will therefore be * at least 10 seconds. */ for (int i = 0; i < 2 * RUNTIME / INTERVAL; i++) { if ((runtime = time(NULL) - starttime) > 10) { #ifndef VERBOSE printf("Simulation succesfully ran for 10 seconds.\n"); #endif break; } if (nanosleep(&naptime, NULL)) { perror("nanosleep"); } #ifdef INTERPRINT print_table(); #endif if (deadlock()) { #ifndef VERBOSE printf("Deadlock after running for %lld seconds.\n", (long long) runtime); #endif #ifdef VERBOSE printf("Oh no, what a mess we made!\n"); print_table(); #endif IsOpen = 0; break; } } IsOpen = 0; #ifdef VERBOSE printf("It's time to leave.\n"); #endif /* All is done. Start joining threads. */ for (int i = 0; i < nPatrons; i++) { if (pthread_join(PT[i], NULL)) { printf("{ error } Could not join pthread #%d.\n", i); } } #ifdef VERBOSE printf("We hope to see you again soon. Goodbye!\n"); #endif /* Clean up. */ #ifndef VERBOSE printf("Results:\n"); for (int i = 0; i < nChairsTaken; i++) { if (sitter[i]) { if (sitter[i]->bowls > 10000) printf("%d:\t(%c)\t%.2f million\n", sitter[i]->seat, typelist[sitter[i]->seat], sitter[i]->bowls / 1000000.0); else printf("%d:\t(%c)\t%d\n", sitter[i]->seat, typelist[sitter[i]->seat], sitter[i]->bowls); } } #endif #ifdef VERBOSE print_table(); #endif pthread_attr_destroy(&ptattr); free_table(); /* Done. */ printf("\n\n[ done ]\n"); return 0; }
PRIVATE int msg_send(PROCESS *current, int dest, MESSAGE *m) { PROCESS *sender = current; PROCESS *p_dest = proc_table + dest; assert(proc2pid(sender) != dest); // 不能自己给自己发消息 if (deadlock(proc2pid(sender), dest)) panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); if ((p_dest->p_flags & RECEIVING) && // 如果目的进程正在等待接受消息 (p_dest->p_recvfrom == proc2pid(sender) || // 并且指定发送者为本进程 p_dest->p_recvfrom == ANY)) { // 或任何进程 assert(p_dest->p_msg); assert(m); phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), m), sizeof(MESSAGE)); p_dest->p_msg = 0; p_dest->p_flags &= ~RECEIVING; p_dest->p_recvfrom = NO_TASK; unblock(p_dest); assert(p_dest->p_flags == 0); assert(p_dest->p_msg == 0); assert(p_dest->p_recvfrom == NO_TASK); assert(p_dest->p_sendto == NO_TASK); assert(sender->p_flags == 0); assert(sender->p_msg == 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == NO_TASK); } else { // 如果目的进程没有等待接受本进程的消息 sender->p_flags |= SENDING; // 标志位置位,只有 p_flags == 0 该进程才会被调度 assert(sender->p_flags == SENDING); sender->p_sendto = dest; sender->p_msg = m; /* 将自己添加到目的进程的发送者队列中去 */ PROCESS *p; if (p_dest->q_sending) { // 如果队列不为空 p = p_dest->q_sending; while (p->next_sending) p = p->next_sending; p->next_sending = sender; } else { // 如果队列为空 p_dest->q_sending = sender; } sender->next_sending = NULL; block(sender); assert(sender->p_flags == SENDING); assert(sender->p_msg != 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == dest); } return 0; }