|
@@ -160,27 +160,21 @@ static void dfree(void *ptr) {
|
|
free(*(char**)ptr);
|
|
free(*(char**)ptr);
|
|
}
|
|
}
|
|
|
|
|
|
-static void lock_mutex(void *mut) {
|
|
|
|
- int k = pthread_mutex_lock(mut);
|
|
|
|
|
|
+static void thread_stop(void *index) {
|
|
|
|
+ int k = pthread_mutex_lock(&thread_is_running_guard);
|
|
if(k) {
|
|
if(k) {
|
|
fprintf(stderr, "Failed to lock mutex: %s\n", strerror(k));
|
|
fprintf(stderr, "Failed to lock mutex: %s\n", strerror(k));
|
|
abort();
|
|
abort();
|
|
}
|
|
}
|
|
-}
|
|
|
|
-
|
|
|
|
-static void unlock_mutex(void *mut) {
|
|
|
|
- int k = pthread_mutex_unlock(mut);
|
|
|
|
|
|
+ assert(thread_is_running[*(const int*)index]);
|
|
|
|
+ thread_is_running[*(const int*)index] = false;
|
|
|
|
+ k = pthread_mutex_unlock(&thread_is_running_guard);
|
|
if(k) {
|
|
if(k) {
|
|
fprintf(stderr, "Failed to unlock mutex: %s\n", strerror(k));
|
|
fprintf(stderr, "Failed to unlock mutex: %s\n", strerror(k));
|
|
abort();
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void thread_stop(void *index) {
|
|
|
|
- assert(thread_is_running[*(const int*)index]);
|
|
|
|
- thread_is_running[*(const int*)index] = false;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* According to the command-line options, print the count of
|
|
/* According to the command-line options, print the count of
|
|
* what was found with an optional filename, which may be omitted. */
|
|
* what was found with an optional filename, which may be omitted. */
|
|
static bool show_count(const struct count a[restrict static 1], const char *restrict filename) {
|
|
static bool show_count(const struct count a[restrict static 1], const char *restrict filename) {
|
|
@@ -240,16 +234,23 @@ void *do_count(void *filename) {
|
|
abort();
|
|
abort();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ int k = pthread_mutex_lock(&thread_is_running_guard);
|
|
|
|
+ if(k) {
|
|
|
|
+ fprintf(stderr, "Failed to lock mutex: %s\n", strerror(k));
|
|
|
|
+ abort();
|
|
|
|
+ }
|
|
|
|
+ assert(!thread_is_running[my_seq_thread_id]);
|
|
|
|
+ thread_is_running[my_seq_thread_id] = true;
|
|
|
|
+ k = pthread_mutex_unlock(&thread_is_running_guard);
|
|
|
|
+ if(k) {
|
|
|
|
+ fprintf(stderr, "Failed to unlock mutex: %s\n", strerror(k));
|
|
|
|
+ abort();
|
|
|
|
+ }
|
|
|
|
+
|
|
/* This has to be declared up here because we want c to
|
|
/* This has to be declared up here because we want c to
|
|
* have scope outside of all of the pthread_cleanup_{push, pop} calls. */
|
|
* have scope outside of all of the pthread_cleanup_{push, pop} calls. */
|
|
struct count *c;
|
|
struct count *c;
|
|
-
|
|
|
|
- lock_mutex(&thread_is_running_guard);
|
|
|
|
- thread_is_running[my_seq_thread_id] = true;
|
|
|
|
- unlock_mutex(&thread_is_running_guard);
|
|
|
|
- pthread_cleanup_push(unlock_mutex, &thread_is_running_guard);
|
|
|
|
pthread_cleanup_push(thread_stop, &my_seq_thread_id);
|
|
pthread_cleanup_push(thread_stop, &my_seq_thread_id);
|
|
- pthread_cleanup_push(lock_mutex, &thread_is_running_guard);
|
|
|
|
|
|
|
|
c = calloc(1, sizeof(*c));
|
|
c = calloc(1, sizeof(*c));
|
|
if(!c) {
|
|
if(!c) {
|
|
@@ -294,18 +295,13 @@ void *do_count(void *filename) {
|
|
}
|
|
}
|
|
|
|
|
|
yyset_in(stream, scanner);
|
|
yyset_in(stream, scanner);
|
|
- if(yylex(scanner)) {
|
|
|
|
- pthread_exit(NULL);
|
|
|
|
- }
|
|
|
|
- if(!show_count(c, filename)) {
|
|
|
|
|
|
+ if(yylex(scanner) || !show_count(c, filename)) {
|
|
pthread_exit(NULL);
|
|
pthread_exit(NULL);
|
|
}
|
|
}
|
|
pthread_cleanup_pop(true); /* destroy_file(stream) */
|
|
pthread_cleanup_pop(true); /* destroy_file(stream) */
|
|
pthread_cleanup_pop(true); /* destroy_scanner(scanner) */
|
|
pthread_cleanup_pop(true); /* destroy_scanner(scanner) */
|
|
pthread_cleanup_pop(false); /* DO NOT free(c) */
|
|
pthread_cleanup_pop(false); /* DO NOT free(c) */
|
|
- pthread_cleanup_pop(true); /* lock thread_is_running_guard */
|
|
|
|
- pthread_cleanup_pop(true); /* thread_is_running[my_seq_thread_id] = false */
|
|
|
|
- pthread_cleanup_pop(true); /* unlock thread_is_running_guard */
|
|
|
|
|
|
+ pthread_cleanup_pop(true); /* thread_stop(&my_seq_thread_id) */
|
|
pthread_exit(c);
|
|
pthread_exit(c);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -351,6 +347,11 @@ int main(int argc, char *argv[]) {
|
|
* when creating the child thread. */
|
|
* when creating the child thread. */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(setvbuf(stdout, NULL, _IONBF, 0)) {
|
|
|
|
+ fputs("Failed to disable buffering on standard output\n", stderr);
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+
|
|
/* To make cleanup easier, we do all of our dynamic memory
|
|
/* To make cleanup easier, we do all of our dynamic memory
|
|
* allocations before we get any threads started. */
|
|
* allocations before we get any threads started. */
|
|
pthread_t *ids = calloc(argc, sizeof(*ids));
|
|
pthread_t *ids = calloc(argc, sizeof(*ids));
|
|
@@ -454,14 +455,14 @@ tryagain:
|
|
if(argc >= 2) {
|
|
if(argc >= 2) {
|
|
exit(show_count(&total, "total") ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
exit(show_count(&total, "total") ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
}
|
|
}
|
|
- if(fflush(stdout) == EOF) {
|
|
|
|
- perror("Failed to flush standard output");
|
|
|
|
- exit(EXIT_FAILURE);
|
|
|
|
- }
|
|
|
|
exit(EXIT_SUCCESS);
|
|
exit(EXIT_SUCCESS);
|
|
|
|
|
|
bail:
|
|
bail:
|
|
- lock_mutex(&thread_is_running_guard);
|
|
|
|
|
|
+ k = pthread_mutex_lock(&thread_is_running_guard);
|
|
|
|
+ if(k) {
|
|
|
|
+ fprintf(stderr, "Failed to lock mutex: %s\n", strerror(k));
|
|
|
|
+ abort();
|
|
|
|
+ }
|
|
for(int i = 0; i < argc; i++) {
|
|
for(int i = 0; i < argc; i++) {
|
|
if(thread_is_running[i]) {
|
|
if(thread_is_running[i]) {
|
|
int k = pthread_cancel(ids[i]);
|
|
int k = pthread_cancel(ids[i]);
|
|
@@ -471,11 +472,15 @@ bail:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- unlock_mutex(&thread_is_running_guard);
|
|
|
|
|
|
+ k = pthread_mutex_unlock(&thread_is_running_guard);
|
|
|
|
+ if(k) {
|
|
|
|
+ fprintf(stderr, "Failed to unlock mutex: %s\n", strerror(k));
|
|
|
|
+ abort();
|
|
|
|
+ }
|
|
|
|
|
|
void *retval;
|
|
void *retval;
|
|
for(int i = 0; i < argc; i++) {
|
|
for(int i = 0; i < argc; i++) {
|
|
- int k = pthread_join(ids[i], &retval);
|
|
|
|
|
|
+ k = pthread_join(ids[i], &retval);
|
|
if(k) {
|
|
if(k) {
|
|
fprintf(stderr, "Failed to join with thread: %s\n", strerror(k));
|
|
fprintf(stderr, "Failed to join with thread: %s\n", strerror(k));
|
|
abort();
|
|
abort();
|