/* Run command CMD and return statistics on it. Put the statistics in *RESP. */ static void run_command(char *const *cmd, resource_t *resp) { pid_t pid; /* Pid of child. */ void (*interrupt_signal)(int); void (*quit_signal)(int); resp->elapsed_ms = monotonic_ms(); pid = vfork(); /* Run CMD as child process. */ if (pid < 0) bb_perror_msg_and_die("fork"); if (pid == 0) { /* If child. */ /* Don't cast execvp arguments; that causes errors on some systems, versus merely warnings if the cast is left off. */ BB_EXECVP(cmd[0], cmd); xfunc_error_retval = (errno == ENOENT ? 127 : 126); bb_error_msg_and_die("can't run %s", cmd[0]); } /* Have signals kill the child but not self (if possible). */ //TODO: just block all sigs? and reenable them in the very end in main? interrupt_signal = signal(SIGINT, SIG_IGN); quit_signal = signal(SIGQUIT, SIG_IGN); resuse_end(pid, resp); /* Re-enable signals. */ signal(SIGINT, interrupt_signal); signal(SIGQUIT, quit_signal); }
/* Run command CMD and return statistics on it. Put the statistics in *RESP. */ static void run_command(char *const *cmd, resource_t * resp) { pid_t pid; /* Pid of child. */ __sighandler_t interrupt_signal, quit_signal; gettimeofday(&resp->start, (struct timezone *) 0); pid = vfork(); /* Run CMD as child process. */ if (pid < 0) bb_error_msg_and_die("cannot fork"); else if (pid == 0) { /* If child. */ /* Don't cast execvp arguments; that causes errors on some systems, versus merely warnings if the cast is left off. */ execvp(cmd[0], cmd); bb_error_msg("cannot run %s", cmd[0]); _exit(errno == ENOENT ? 127 : 126); } /* Have signals kill the child but not self (if possible). */ interrupt_signal = signal(SIGINT, SIG_IGN); quit_signal = signal(SIGQUIT, SIG_IGN); if (resuse_end(pid, resp) == 0) bb_error_msg("error waiting for child process"); /* Re-enable signals. */ signal(SIGINT, interrupt_signal); signal(SIGQUIT, quit_signal); }
/* Run command CMD and return statistics on it. Put the statistics in *RESP. */ static void run_command(char *const *cmd, resource_t *resp) { pid_t pid; void (*interrupt_signal)(int); void (*quit_signal)(int); resp->elapsed_ms = monotonic_ms(); pid = xvfork(); if (pid == 0) { /* Child */ BB_EXECVP_or_die((char**)cmd); } /* Have signals kill the child but not self (if possible). */ //TODO: just block all sigs? and reenable them in the very end in main? interrupt_signal = signal(SIGINT, SIG_IGN); quit_signal = signal(SIGQUIT, SIG_IGN); resuse_end(pid, resp); /* Re-enable signals. */ signal(SIGINT, interrupt_signal); signal(SIGQUIT, quit_signal); }
int main(int argc, char* argv[]) { int i; int c; int solution_count = 0; int num_threads; struct thread_param * params; struct resuse resuse; pthread_t * thread_handles; // Star collecting resource information about the entire proccess resuse_start(&resuse, RESUSE_SCOPE_PROC); // parse the command line arguments while((c = getopt(argc, argv, "n:t:vd")) != -1) { // for each argument switch(c) { // n = The number of queens case 'n': num_queens = atoi(optarg); break; // t = The number of threads case 't': threaded_flag = 1; num_threads = atoi(optarg); break; // v = Turn on verbose output case 'v': verbose_flag = 1; break; // d = Display the chess boards case 'd': display_flag = 1; break; case '?': if (optopt == 'c') fprintf(stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf(stderr, "Unknown option `-%c'.\n", optopt); else fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); return -1; default: abort(); } } // print out information about the program printf("# Queens = %d, # Threads = %d, Threaded = %s, Verbose = %s, Display = %s\n", num_queens, threaded_flag ? num_threads : 1, threaded_flag ? "TRUE" : "FALSE", verbose_flag ? "TRUE" : "FALSE", display_flag ? "TRUE" : "FALSE"); // If the threaded option is true if(threaded_flag) { // Dynamically allocate the the thread parameter objects params = calloc(num_queens, sizeof(struct thread_param)); if (params == NULL) { perror("calloc"); exit(1); } thread_handles = calloc(num_queens, sizeof(pthread_t)); if (thread_handles == NULL) { perror("calloc"); exit(1); } } // for each column of the chess board if(!threaded_flag) { for(i=0;i<num_queens;i++) { int rows[num_queens]; int tmp_solution_count = 0; rows[0] = i; queens_helper(rows, 1, &tmp_solution_count); solution_count += tmp_solution_count; } } else { /* Count down from highest column to lowest. * This allows for the longest threads to run * first, and causes the threads to finish more * at the same time, which increases CPU usage * for better run time */ next_column = num_queens - 1; for(i = 0; i < num_threads; i++) { params[i].thread_num = i; int err = pthread_create(&(thread_handles[i]), NULL, thread, &(params[i])); if (err) { fprintf(stderr, "ERR: pthread_create returned %d\n", err); exit(1); } } solution_count = 0; for (i = 0; i < num_threads; i++) { int err = pthread_join(thread_handles[i], NULL); if (err) { fprintf(stderr, "ERR: pthread_join returned %d\n", err); } solution_count += params[i].solution_count; } } // Stop collecting resource usage information resuse_end(&resuse); // Print out the collected information resuse_fprint(stdout, resuse_fmt, &resuse); // Print out the final number of solutions that were found printf("Solution Count = %d\n", solution_count); if (threaded_flag) { free(params); free(thread_handles); } return 0; }
/** * The thread created by the student. * @param p * A struct thread_param object cast to void * * @return A pointer to an int containing the number of solutions found * cast to a void *. */ void* thread(void* p) { struct thread_param * param = (struct thread_param *) p; struct resuse resuse; int rows[num_queens]; int column; // star collecting resource information about this thread resuse_start(&resuse, RESUSE_SCOPE_THREAD); // print debug information dprintf("Thread %d Starting\n", param->thread_num); while(1) { /* Obtain the mutex for the next column */ int err = pthread_mutex_lock(&nc_mutex); if (err) { fprintf(stderr, "ERR: pthread_mutex_lock returned %d\n", err); exit(1); } /* Take the next column */ column = next_column; /* Decrement the next column */ next_column--; /* NOTE: Even though it *looks* atomic, * local = global++ is anything but. * Without the mutex, two threads * could end up grabbing * the same column, then * both incrementing it and * skipping a column, or any * other sort of weirdness. */ /* Release mutex */ err = pthread_mutex_unlock(&nc_mutex); if (err) { fprintf(stderr, "ERR: pthread_mutex_lock returned %d\n", err); exit(1); } if (column < 0) { break; } dprintf("Thread %d kicking off column %d\n", param->thread_num, column); rows[0] = param->thread_num; queens_helper(rows, 1, &(param->solution_count)); dprintf("Thread %d finished column %d, looking for new work...\n", param->thread_num, column); } // print debug information dprintf("Thread %d Finished, found %d solutions\n", param->thread_num, param->solution_count); // finish collecting resource information about this thread resuse_end(&resuse); // print the resource information to stdout flockfile(stdout); fprintf(stdout, "Thread %02d: ", param->thread_num); resuse_fprint(stdout, resuse_fmt, &resuse); fflush(stdout); funlockfile(stdout); // return the number of solutions this thread found return (void*) ¶m->solution_count; }