/* Start threads. */ int start_threads (size_t option_P, guestfs_h *options_handle, work_fn work) { const int trace = options_handle ? guestfs_get_trace (options_handle) : 0; const int verbose = options_handle ? guestfs_get_verbose (options_handle) : 0; size_t i, nr_threads; int err, errors; void *status; CLEANUP_FREE struct thread_data *thread_data = NULL; CLEANUP_FREE pthread_t *threads = NULL; if (nr_domains == 0) /* Nothing to do. */ return 0; /* If the user selected the -P option, then we use up to that many threads. */ if (option_P > 0) nr_threads = MIN (nr_domains, option_P); else nr_threads = MIN (nr_domains, MIN (MAX_THREADS, estimate_max_threads ())); if (verbose) fprintf (stderr, "parallel: creating %zu threads\n", nr_threads); thread_data = malloc (sizeof (struct thread_data) * nr_threads); threads = malloc (sizeof (pthread_t) * nr_threads); if (thread_data == NULL || threads == NULL) error (EXIT_FAILURE, errno, "malloc"); for (i = 0; i < nr_threads; ++i) { thread_data[i].thread_num = i; thread_data[i].trace = trace; thread_data[i].verbose = verbose; thread_data[i].work = work; } /* Start the worker threads. */ for (i = 0; i < nr_threads; ++i) { err = pthread_create (&threads[i], NULL, worker_thread, &thread_data[i]); if (err != 0) error (EXIT_FAILURE, err, "pthread_create [%zu]", i); } /* Wait for the threads to exit. */ errors = 0; for (i = 0; i < nr_threads; ++i) { err = pthread_join (threads[i], &status); if (err != 0) { error (0, err, "pthread_join [%zu]", i); errors++; } if (*(int *)status == -1) errors++; } return errors == 0 ? 0 : -1; }
int main (int argc, char *argv[]) { enum { HELP_OPTION = CHAR_MAX + 1 }; static const char *options = "in:P:vx"; static const struct option long_options[] = { { "help", 0, 0, HELP_OPTION }, { "ignore", 0, 0, 'i' }, { "number", 1, 0, 'n' }, { "processes", 1, 0, 'P' }, { "trace", 0, 0, 'x' }, { "verbose", 0, 0, 'v' }, { 0, 0, 0, 0 } }; size_t P = 0, i, errors; int c, option_index; int err; void *status; for (;;) { c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* Options which are long only. */ fprintf (stderr, "%s: unknown long option: %s (%d)\n", guestfs_int_program_name, long_options[option_index].name, option_index); exit (EXIT_FAILURE); case 'i': ignore_errors = 1; break; case 'n': if (sscanf (optarg, "%zu", &n) != 1 || n == 0) { fprintf (stderr, "%s: -n option not numeric and greater than 0\n", guestfs_int_program_name); exit (EXIT_FAILURE); } break; case 'P': if (sscanf (optarg, "%zu", &P) != 1) { fprintf (stderr, "%s: -P option not numeric\n", guestfs_int_program_name); exit (EXIT_FAILURE); } break; case 'v': verbose = 1; break; case 'x': trace = 1; break; case HELP_OPTION: usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } if (n == 0) { fprintf (stderr, "%s: must specify number of processes to run (-n option)\n", guestfs_int_program_name); exit (EXIT_FAILURE); } if (optind != argc) { fprintf (stderr, "%s: extra arguments found on the command line\n", guestfs_int_program_name); exit (EXIT_FAILURE); } /* Calculate the number of threads to use. */ if (P > 0) P = MIN (n, P); else P = MIN (n, MIN (MAX_THREADS, estimate_max_threads ())); /* Start the worker threads. */ struct thread_data thread_data[P]; pthread_t threads[P]; for (i = 0; i < P; ++i) { thread_data[i].thread_num = i; err = pthread_create (&threads[i], NULL, start_thread, &thread_data[i]); if (err != 0) { fprintf (stderr, "%s: pthread_create[%zu]: %s\n", guestfs_int_program_name, i, strerror (err)); exit (EXIT_FAILURE); } } /* Wait for the threads to exit. */ errors = 0; for (i = 0; i < P; ++i) { err = pthread_join (threads[i], &status); if (err != 0) { fprintf (stderr, "%s: pthread_join[%zu]: %s\n", guestfs_int_program_name, i, strerror (err)); errors++; } if (*(int *)status == -1) errors++; } exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
int main (int argc, char *argv[]) { enum { HELP_OPTION = CHAR_MAX + 1 }; static const char *options = "in:P:vx"; static const struct option long_options[] = { { "help", 0, 0, HELP_OPTION }, { "ignore", 0, 0, 'i' }, { "log", 1, 0, 0 }, { "number", 1, 0, 'n' }, { "processes", 1, 0, 'P' }, { "trace", 0, 0, 'x' }, { "verbose", 0, 0, 'v' }, { 0, 0, 0, 0 } }; size_t P = 0, i; int c, option_index; for (;;) { c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* Options which are long only. */ if (STREQ (long_options[option_index].name, "log")) { log_template = optarg; log_file_size = strlen (log_template); for (i = 0; i < strlen (log_template); ++i) { if (log_template[i] == '%') log_file_size += 64; } } else error (EXIT_FAILURE, 0, "unknown long option: %s (%d)", long_options[option_index].name, option_index); break; case 'i': ignore_errors = 1; break; case 'n': if (sscanf (optarg, "%zu", &n) != 1 || n == 0) error (EXIT_FAILURE, 0, "-n option not numeric and greater than 0"); break; case 'P': if (sscanf (optarg, "%zu", &P) != 1) error (EXIT_FAILURE, 0, "-P option not numeric"); break; case 'v': verbose = 1; break; case 'x': trace = 1; break; case HELP_OPTION: usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } if (n == 0) error (EXIT_FAILURE, 0, "must specify number of processes to run (-n option)"); if (optind != argc) error (EXIT_FAILURE, 0, "extra arguments found on the command line"); /* Calculate the number of threads to use. */ if (P > 0) P = MIN (n, P); else P = MIN (n, MIN (MAX_THREADS, estimate_max_threads ())); run_test (P); exit (EXIT_SUCCESS); }