From c8a89493664ec918160f47202b4fdcb9b2662280 Mon Sep 17 00:00:00 2001 From: Bassem Girgis Date: Wed, 17 Oct 2018 23:47:57 -0500 Subject: [PATCH] run clang-format --- .clang-format | 104 +++++ Makefile | 8 +- src/ch01/alarm.c | 43 +- src/ch01/alarm_fork.c | 86 ++-- src/ch01/alarm_thread.c | 81 ++-- src/ch01/thread_error.c | 35 +- src/ch02/hello.c | 28 +- src/ch02/lifecycle.c | 42 +- src/ch02/thread.c | 28 +- src/ch03/alarm_cond.c | 306 +++++++------- src/ch03/alarm_mutex.c | 269 ++++++------ src/ch03/alarm_mutex_cpp.cpp | 43 +- src/ch03/backoff.c | 295 +++++++------ src/ch03/cond.c | 129 +++--- src/ch03/cond_dynamic.c | 47 ++- src/ch03/cond_static.c | 14 +- src/ch03/mutex_dynamic.c | 33 +- src/ch03/mutex_static.c | 9 +- src/ch03/trylock.c | 41 +- src/ch04/crew.c | 773 +++++++++++++++++----------------- src/ch04/pipe.c | 351 +++++++-------- src/ch04/pipe_cpp.cpp | 99 +++-- src/ch04/server.c | 492 +++++++++++----------- src/ch05/cancel.c | 73 ++-- src/ch05/cancel_async.c | 168 ++++---- src/ch05/cancel_cleanup.c | 105 ++--- src/ch05/cancel_disable.c | 88 ++-- src/ch05/cancel_subcontract.c | 123 +++--- src/ch05/cond_attr.c | 28 +- src/ch05/mutex_attr.c | 28 +- src/ch05/once.c | 81 ++-- src/ch05/sched_attr.c | 188 ++++----- src/ch05/sched_thread.c | 110 ++--- src/ch05/thread_attr.c | 88 ++-- src/ch05/tsd_destructor.c | 148 +++---- src/ch05/tsd_once.c | 85 ++-- src/ch06/atfork.c | 169 ++++---- src/ch06/flock.c | 117 +++-- src/ch06/getlogin.c | 42 +- src/ch06/putchar.c | 80 ++-- src/ch06/semaphore_signal.c | 154 +++---- src/ch06/semaphore_wait.c | 103 ++--- src/ch06/sigev_thread.c | 114 +++-- src/ch06/sigwait.c | 151 +++---- src/ch06/susp.c | 464 ++++++++++---------- src/ch07/barrier.c | 180 ++++---- src/ch07/barrier.h | 28 +- src/ch07/barrier_main.c | 144 ++++--- src/ch07/rwlock.c | 341 +++++++-------- src/ch07/rwlock.h | 42 +- src/ch07/rwlock_main.c | 248 +++++------ src/ch07/rwlock_try_main.c | 232 +++++----- src/ch07/workq.c | 477 ++++++++++----------- src/ch07/workq.h | 37 +- src/ch07/workq_main.c | 194 +++++---- src/ch08/inertia.c | 67 +-- 56 files changed, 4153 insertions(+), 3900 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..3ed6866 --- /dev/null +++ b/.clang-format @@ -0,0 +1,104 @@ +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: TopLevelDefinitions +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BreakBeforeBraces : Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeInheritanceComma: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never diff --git a/Makefile b/Makefile index 0df7ee2..43226dc 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,13 @@ ch04/pipe_cpp.cpp NAMES_CXX=$(SOURCES_CXX:.cpp=) PROGRAMS_CXX=$(addprefix $(BIN)/, $(NAMES_CXX)) -all: dirs ${PROGRAMS_C} ${PROGRAMS_CXX} +all: format dirs ${PROGRAMS_C} ${PROGRAMS_CXX} + +format: + #clang-format -i $(SOURCE)/*.c* + #clang-format -i $(SOURCE)/*.h* + clang-format -i $(SOURCE)/*/*.c* + clang-format -i $(SOURCE)/*/*.h* dirs: mkdir -p $(BIN) diff --git a/src/ch01/alarm.c b/src/ch01/alarm.c index c1a572a..8d12c97 100644 --- a/src/ch01/alarm.c +++ b/src/ch01/alarm.c @@ -7,28 +7,31 @@ */ #include "errors.h" -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int seconds; - char line[128]; - char message[64]; + int seconds; + char line[128]; + char message[64]; - while (1) { - printf ("Alarm> "); - if (fgets (line, sizeof (line), stdin) == NULL) exit (0); - if (strlen (line) <= 1) continue; + while (1) { + printf("Alarm> "); + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); + if (strlen(line) <= 1) + continue; - /* - * Parse input line into seconds (%d) and a message - * (%64[^\n]), consisting of up to 64 characters - * separated from the seconds by whitespace. - */ - if (sscanf (line, "%d %64[^\n]", - &seconds, message) < 2) { - fprintf (stderr, "Bad command\n"); - } else { - sleep (seconds); - printf ("(%d) %s\n", seconds, message); - } + /* + * Parse input line into seconds (%d) and a message + * (%64[^\n]), consisting of up to 64 characters + * separated from the seconds by whitespace. + */ + if (sscanf(line, "%d %64[^\n]", &seconds, message) < 2) { + fprintf(stderr, "Bad command\n"); } + else { + sleep(seconds); + printf("(%d) %s\n", seconds, message); + } + } } diff --git a/src/ch01/alarm_fork.c b/src/ch01/alarm_fork.c index 2f0b7e4..7c8436f 100644 --- a/src/ch01/alarm_fork.c +++ b/src/ch01/alarm_fork.c @@ -8,49 +8,53 @@ #include #include "errors.h" -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int status; - char line[128]; - int seconds; - pid_t pid; - char message[64]; + int status; + char line[128]; + int seconds; + pid_t pid; + char message[64]; - while (1) { - printf ("Alarm> "); - if (fgets (line, sizeof (line), stdin) == NULL) exit (0); - if (strlen (line) <= 1) continue; + while (1) { + printf("Alarm> "); + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); + if (strlen(line) <= 1) + continue; - /* - * Parse input line into seconds (%d) and a message - * (%64[^\n]), consisting of up to 64 characters - * separated from the seconds by whitespace. - */ - if (sscanf (line, "%d %64[^\n]", - &seconds, message) < 2) { - fprintf (stderr, "Bad command\n"); - } else { - pid = fork (); - if (pid == (pid_t)-1) - errno_abort ("Fork"); - if (pid == (pid_t)0) { - /* - * If we're in the child, wait and then print a message - */ - sleep (seconds); - printf ("(%d) %s\n", seconds, message); - exit (0); - } else { - /* - * In the parent, call waitpid() to collect any children that - * have already terminated. - */ - do { - pid = waitpid ((pid_t)-1, NULL, WNOHANG); - if (pid == (pid_t)-1) - errno_abort ("Wait for child"); - } while (pid != (pid_t)0); - } - } + /* + * Parse input line into seconds (%d) and a message + * (%64[^\n]), consisting of up to 64 characters + * separated from the seconds by whitespace. + */ + if (sscanf(line, "%d %64[^\n]", &seconds, message) < 2) { + fprintf(stderr, "Bad command\n"); } + else { + pid = fork(); + if (pid == (pid_t) -1) + errno_abort("Fork"); + if (pid == (pid_t) 0) { + /* + * If we're in the child, wait and then print a message + */ + sleep(seconds); + printf("(%d) %s\n", seconds, message); + exit(0); + } + else { + /* + * In the parent, call waitpid() to collect any children that + * have already terminated. + */ + do { + pid = waitpid((pid_t) -1, NULL, WNOHANG); + if (pid == (pid_t) -1) + errno_abort("Wait for child"); + } while (pid != (pid_t) 0); + } + } + } } diff --git a/src/ch01/alarm_thread.c b/src/ch01/alarm_thread.c index 9dbc05f..b09e483 100644 --- a/src/ch01/alarm_thread.c +++ b/src/ch01/alarm_thread.c @@ -8,52 +8,55 @@ #include "errors.h" typedef struct alarm_tag { - int seconds; - char message[64]; + int seconds; + char message[64]; } alarm_t; -void *alarm_thread (void *arg) +void* +alarm_thread(void* arg) { - alarm_t *alarm = (alarm_t*)arg; - int status; + alarm_t* alarm = (alarm_t*) arg; + int status; - status = pthread_detach (pthread_self ()); - if (status != 0) - err_abort (status, "Detach thread"); - sleep (alarm->seconds); - printf ("(%d) %s\n", alarm->seconds, alarm->message); - free (alarm); - return NULL; + status = pthread_detach(pthread_self()); + if (status != 0) + err_abort(status, "Detach thread"); + sleep(alarm->seconds); + printf("(%d) %s\n", alarm->seconds, alarm->message); + free(alarm); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int status; - char line[128]; - alarm_t *alarm; - pthread_t thread; + int status; + char line[128]; + alarm_t* alarm; + pthread_t thread; - while (1) { - printf ("Alarm> "); - if (fgets (line, sizeof (line), stdin) == NULL) exit (0); - if (strlen (line) <= 1) continue; - alarm = (alarm_t*)malloc (sizeof (alarm_t)); - if (alarm == NULL) - errno_abort ("Allocate alarm"); + while (1) { + printf("Alarm> "); + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); + if (strlen(line) <= 1) + continue; + alarm = (alarm_t*) malloc(sizeof(alarm_t)); + if (alarm == NULL) + errno_abort("Allocate alarm"); - /* - * Parse input line into seconds (%d) and a message - * (%64[^\n]), consisting of up to 64 characters - * separated from the seconds by whitespace. - */ - if (sscanf (line, "%d %64[^\n]", - &alarm->seconds, alarm->message) < 2) { - fprintf (stderr, "Bad command\n"); - free (alarm); - } else { - status = pthread_create ( - &thread, NULL, alarm_thread, alarm); - if (status != 0) - err_abort (status, "Create alarm thread"); - } + /* + * Parse input line into seconds (%d) and a message + * (%64[^\n]), consisting of up to 64 characters + * separated from the seconds by whitespace. + */ + if (sscanf(line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2) { + fprintf(stderr, "Bad command\n"); + free(alarm); } + else { + status = pthread_create(&thread, NULL, alarm_thread, alarm); + if (status != 0) + err_abort(status, "Create alarm thread"); + } + } } diff --git a/src/ch01/thread_error.c b/src/ch01/thread_error.c index bd1e185..18a6a82 100644 --- a/src/ch01/thread_error.c +++ b/src/ch01/thread_error.c @@ -4,26 +4,27 @@ * Demonstrate detection of errors from a typical POSIX 1003.1c-1995 * function, pthread_join. */ +#include #include #include -#include -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread; - int status; + pthread_t thread; + int status; - /* - * Attempt to join with an uninitialized thread ID. On most - * implementations, this will return an ESRCH error code. If - * the local (and uninitialized) pthread_t happens to be a valid - * thread ID, it is almost certainly that of the initial thread, - * which is running main(). In that case, your Pthreads - * implementation may either return EDEADLK (self-deadlock), - * or it may hang. If it hangs, quit and try again. - */ - status = pthread_join (thread, NULL); - if (status != 0) - fprintf (stderr, "error %d: %s\n", status, strerror (status)); - return status; + /* + * Attempt to join with an uninitialized thread ID. On most + * implementations, this will return an ESRCH error code. If + * the local (and uninitialized) pthread_t happens to be a valid + * thread ID, it is almost certainly that of the initial thread, + * which is running main(). In that case, your Pthreads + * implementation may either return EDEADLK (self-deadlock), + * or it may hang. If it hangs, quit and try again. + */ + status = pthread_join(thread, NULL); + if (status != 0) + fprintf(stderr, "error %d: %s\n", status, strerror(status)); + return status; } diff --git a/src/ch02/hello.c b/src/ch02/hello.c index aa64515..4f530dc 100644 --- a/src/ch02/hello.c +++ b/src/ch02/hello.c @@ -7,22 +7,24 @@ #include #include "errors.h" -void *hello_world (void *arg) +void* +hello_world(void* arg) { - printf ("Hello world\n"); - return NULL; + printf("Hello world\n"); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t hello_id; - int status; + pthread_t hello_id; + int status; - status = pthread_create (&hello_id, NULL, hello_world, NULL); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_join (hello_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - return 0; + status = pthread_create(&hello_id, NULL, hello_world, NULL); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_join(hello_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + return 0; } diff --git a/src/ch02/lifecycle.c b/src/ch02/lifecycle.c index 78f772a..eda9d74 100644 --- a/src/ch02/lifecycle.c +++ b/src/ch02/lifecycle.c @@ -10,31 +10,31 @@ /* * Thread start routine. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - printf("Inside thread %i\n", pthread_self()); - return arg; + printf("Inside thread %i\n", pthread_self()); + return arg; } -main (int argc, char *argv[]) +main(int argc, char* argv[]) { - pthread_t thread_id; - void *thread_result; - int status; + pthread_t thread_id; + void* thread_result; + int status; - printf("Inside thread %i\n", pthread_self()); - status = pthread_create ( - &thread_id, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - sleep(1.0); - printf("Main thread created thread %i\n", thread_id); + printf("Inside thread %i\n", pthread_self()); + status = pthread_create(&thread_id, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + sleep(1.0); + printf("Main thread created thread %i\n", thread_id); - status = pthread_join (thread_id, &thread_result); - if (status != 0) - err_abort (status, "Join thread"); - if (thread_result == NULL) - return 0; - else - return 1; + status = pthread_join(thread_id, &thread_result); + if (status != 0) + err_abort(status, "Join thread"); + if (thread_result == NULL) + return 0; + else + return 1; } diff --git a/src/ch02/thread.c b/src/ch02/thread.c index 5033b63..09f21cd 100644 --- a/src/ch02/thread.c +++ b/src/ch02/thread.c @@ -10,22 +10,24 @@ /* * Thread start routine that writes a message. */ -void *writer_thread (void *arg) +void* +writer_thread(void* arg) { - sleep (5); - printf ("Thread I/O\n"); - return NULL; + sleep(5); + printf("Thread I/O\n"); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t writer_id; - char *input, buffer[64]; + pthread_t writer_id; + char *input, buffer[64]; - pthread_create (&writer_id, NULL, writer_thread, NULL); - input = fgets (buffer, 64, stdin); - if (input != NULL) - printf ("You said %s", buffer); - pthread_exit (NULL); - return 0; + pthread_create(&writer_id, NULL, writer_thread, NULL); + input = fgets(buffer, 64, stdin); + if (input != NULL) + printf("You said %s", buffer); + pthread_exit(NULL); + return 0; } diff --git a/src/ch03/alarm_cond.c b/src/ch03/alarm_cond.c index 243769a..d5ba818 100644 --- a/src/ch03/alarm_cond.c +++ b/src/ch03/alarm_cond.c @@ -22,177 +22,183 @@ * been on the list. */ typedef struct alarm_tag { - struct alarm_tag *link; - int seconds; - time_t time; /* seconds from EPOCH */ - char message[64]; + struct alarm_tag* link; + int seconds; + time_t time; /* seconds from EPOCH */ + char message[64]; } alarm_t; pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t alarm_cond = PTHREAD_COND_INITIALIZER; -alarm_t *alarm_list = NULL; -time_t current_alarm = 0; +pthread_cond_t alarm_cond = PTHREAD_COND_INITIALIZER; +alarm_t* alarm_list = NULL; +time_t current_alarm = 0; /* * Insert alarm entry on list, in order. */ -void alarm_insert (alarm_t *alarm) +void +alarm_insert(alarm_t* alarm) { - int status; - alarm_t **last, *next; + int status; + alarm_t **last, *next; - /* - * LOCKING PROTOCOL: - * - * This routine requires that the caller have locked the - * alarm_mutex! - */ - last = &alarm_list; - next = *last; - while (next != NULL) { - if (next->time >= alarm->time) { - alarm->link = next; - *last = alarm; - break; - } - last = &next->link; - next = next->link; - } - /* - * If we reached the end of the list, insert the new alarm - * there. ("next" is NULL, and "last" points to the link - * field of the last item, or to the list header.) - */ - if (next == NULL) { - *last = alarm; - alarm->link = NULL; + /* + * LOCKING PROTOCOL: + * + * This routine requires that the caller have locked the + * alarm_mutex! + */ + last = &alarm_list; + next = *last; + while (next != NULL) { + if (next->time >= alarm->time) { + alarm->link = next; + *last = alarm; + break; } + last = &next->link; + next = next->link; + } + /* + * If we reached the end of the list, insert the new alarm + * there. ("next" is NULL, and "last" points to the link + * field of the last item, or to the list header.) + */ + if (next == NULL) { + *last = alarm; + alarm->link = NULL; + } #ifdef DEBUG - printf ("[list: "); - for (next = alarm_list; next != NULL; next = next->link) - printf ("%d(%d)[\"%s\"] ", next->time, - next->time - time (NULL), next->message); - printf ("]\n"); + printf("[list: "); + for (next = alarm_list; next != NULL; next = next->link) + printf( + "%d(%d)[\"%s\"] ", next->time, next->time - time(NULL), next->message); + printf("]\n"); #endif - /* - * Wake the alarm thread if it is not busy (that is, if - * current_alarm is 0, signifying that it's waiting for - * work), or if the new alarm comes before the one on - * which the alarm thread is waiting. - */ - if (current_alarm == 0 || alarm->time < current_alarm) { - current_alarm = alarm->time; - status = pthread_cond_signal (&alarm_cond); - if (status != 0) - err_abort (status, "Signal cond"); - } + /* + * Wake the alarm thread if it is not busy (that is, if + * current_alarm is 0, signifying that it's waiting for + * work), or if the new alarm comes before the one on + * which the alarm thread is waiting. + */ + if (current_alarm == 0 || alarm->time < current_alarm) { + current_alarm = alarm->time; + status = pthread_cond_signal(&alarm_cond); + if (status != 0) + err_abort(status, "Signal cond"); + } } /* * The alarm thread's start routine. */ -void *alarm_thread (void *arg) +void* +alarm_thread(void* arg) { - alarm_t *alarm; - struct timespec cond_time; - time_t now; - int status, expired; + alarm_t* alarm; + struct timespec cond_time; + time_t now; + int status, expired; + + /* + * Loop forever, processing commands. The alarm thread will + * be disintegrated when the process exits. Lock the mutex + * at the start -- it will be unlocked during condition + * waits, so the main thread can insert alarms. + */ + status = pthread_mutex_lock(&alarm_mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + while (1) { + /* + * If the alarm list is empty, wait until an alarm is + * added. Setting current_alarm to 0 informs the insert + * routine that the thread is not busy. + */ + current_alarm = 0; + while (alarm_list == NULL) { + status = pthread_cond_wait(&alarm_cond, &alarm_mutex); + if (status != 0) + err_abort(status, "Wait on cond"); + } + alarm = alarm_list; + alarm_list = alarm->link; + now = time(NULL); + expired = 0; + if (alarm->time > now) { +#ifdef DEBUG + printf("[waiting: %d(%d)\"%s\"]\n", + alarm->time, + alarm->time - time(NULL), + alarm->message); +#endif + cond_time.tv_sec = alarm->time; + cond_time.tv_nsec = 0; + current_alarm = alarm->time; + while (current_alarm == alarm->time) { + status = pthread_cond_timedwait(&alarm_cond, &alarm_mutex, &cond_time); + if (status == ETIMEDOUT) { + expired = 1; + break; + } + if (status != 0) + err_abort(status, "Cond timedwait"); + } + if (!expired) + alarm_insert(alarm); + } + else + expired = 1; + if (expired) { + printf("(%d) %s\n", alarm->seconds, alarm->message); + free(alarm); + } + } +} + +int +main(int argc, char* argv[]) +{ + int status; + char line[128]; + alarm_t* alarm; + pthread_t thread; + + status = pthread_create(&thread, NULL, alarm_thread, NULL); + if (status != 0) + err_abort(status, "Create alarm thread"); + while (1) { + printf("Alarm> "); + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); + if (strlen(line) <= 1) + continue; + alarm = (alarm_t*) malloc(sizeof(alarm_t)); + if (alarm == NULL) + errno_abort("Allocate alarm"); /* - * Loop forever, processing commands. The alarm thread will - * be disintegrated when the process exits. Lock the mutex - * at the start -- it will be unlocked during condition - * waits, so the main thread can insert alarms. + * Parse input line into seconds (%d) and a message + * (%64[^\n]), consisting of up to 64 characters + * separated from the seconds by whitespace. */ - status = pthread_mutex_lock (&alarm_mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - while (1) { - /* - * If the alarm list is empty, wait until an alarm is - * added. Setting current_alarm to 0 informs the insert - * routine that the thread is not busy. - */ - current_alarm = 0; - while (alarm_list == NULL) { - status = pthread_cond_wait (&alarm_cond, &alarm_mutex); - if (status != 0) - err_abort (status, "Wait on cond"); - } - alarm = alarm_list; - alarm_list = alarm->link; - now = time (NULL); - expired = 0; - if (alarm->time > now) { -#ifdef DEBUG - printf ("[waiting: %d(%d)\"%s\"]\n", alarm->time, - alarm->time - time (NULL), alarm->message); -#endif - cond_time.tv_sec = alarm->time; - cond_time.tv_nsec = 0; - current_alarm = alarm->time; - while (current_alarm == alarm->time) { - status = pthread_cond_timedwait ( - &alarm_cond, &alarm_mutex, &cond_time); - if (status == ETIMEDOUT) { - expired = 1; - break; - } - if (status != 0) - err_abort (status, "Cond timedwait"); - } - if (!expired) - alarm_insert (alarm); - } else - expired = 1; - if (expired) { - printf ("(%d) %s\n", alarm->seconds, alarm->message); - free (alarm); - } + if (sscanf(line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2) { + fprintf(stderr, "Bad command\n"); + free(alarm); } -} - -int main (int argc, char *argv[]) -{ - int status; - char line[128]; - alarm_t *alarm; - pthread_t thread; - - status = pthread_create ( - &thread, NULL, alarm_thread, NULL); - if (status != 0) - err_abort (status, "Create alarm thread"); - while (1) { - printf ("Alarm> "); - if (fgets (line, sizeof (line), stdin) == NULL) exit (0); - if (strlen (line) <= 1) continue; - alarm = (alarm_t*)malloc (sizeof (alarm_t)); - if (alarm == NULL) - errno_abort ("Allocate alarm"); - - /* - * Parse input line into seconds (%d) and a message - * (%64[^\n]), consisting of up to 64 characters - * separated from the seconds by whitespace. - */ - if (sscanf (line, "%d %64[^\n]", - &alarm->seconds, alarm->message) < 2) { - fprintf (stderr, "Bad command\n"); - free (alarm); - } else { - status = pthread_mutex_lock (&alarm_mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - alarm->time = time (NULL) + alarm->seconds; - /* - * Insert the new alarm into the list of alarms, - * sorted by expiration time. - */ - alarm_insert (alarm); - status = pthread_mutex_unlock (&alarm_mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - } + else { + status = pthread_mutex_lock(&alarm_mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + alarm->time = time(NULL) + alarm->seconds; + /* + * Insert the new alarm into the list of alarms, + * sorted by expiration time. + */ + alarm_insert(alarm); + status = pthread_mutex_unlock(&alarm_mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); } + } } diff --git a/src/ch03/alarm_mutex.c b/src/ch03/alarm_mutex.c index 461bc82..1841346 100644 --- a/src/ch03/alarm_mutex.c +++ b/src/ch03/alarm_mutex.c @@ -22,154 +22,159 @@ * been on the list. */ typedef struct alarm_tag { - struct alarm_tag *link; - int seconds; - time_t time; /* seconds from EPOCH */ - char message[64]; + struct alarm_tag* link; + int seconds; + time_t time; /* seconds from EPOCH */ + char message[64]; } alarm_t; pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER; -alarm_t *alarm_list = NULL; +alarm_t* alarm_list = NULL; /* * The alarm thread's start routine. */ -void *alarm_thread (void *arg) +void* +alarm_thread(void* arg) { - alarm_t *alarm; - int sleep_time; - time_t now; - int status; + alarm_t* alarm; + int sleep_time; + time_t now; + int status; + + /* + * Loop forever, processing commands. The alarm thread will + * be disintegrated when the process exits. + */ + while (1) { + status = pthread_mutex_lock(&alarm_mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + alarm = alarm_list; /* - * Loop forever, processing commands. The alarm thread will - * be disintegrated when the process exits. + * If the alarm list is empty, wait for one second. This + * allows the main thread to run, and read another + * command. If the list is not empty, remove the first + * item. Compute the number of seconds to wait -- if the + * result is less than 0 (the time has passed), then set + * the sleep_time to 0. */ - while (1) { - status = pthread_mutex_lock (&alarm_mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - alarm = alarm_list; - - /* - * If the alarm list is empty, wait for one second. This - * allows the main thread to run, and read another - * command. If the list is not empty, remove the first - * item. Compute the number of seconds to wait -- if the - * result is less than 0 (the time has passed), then set - * the sleep_time to 0. - */ - if (alarm == NULL) - sleep_time = 1; - else { - alarm_list = alarm->link; - now = time (NULL); - if (alarm->time <= now) - sleep_time = 0; - else - sleep_time = alarm->time - now; + if (alarm == NULL) + sleep_time = 1; + else { + alarm_list = alarm->link; + now = time(NULL); + if (alarm->time <= now) + sleep_time = 0; + else + sleep_time = alarm->time - now; #ifdef DEBUG - printf ("[waiting: %d(%d)\"%s\"]\n", alarm->time, - sleep_time, alarm->message); + printf( + "[waiting: %d(%d)\"%s\"]\n", alarm->time, sleep_time, alarm->message); #endif - } - - /* - * Unlock the mutex before waiting, so that the main - * thread can lock it to insert a new alarm request. If - * the sleep_time is 0, then call sched_yield, giving - * the main thread a chance to run if it has been - * readied by user input, without delaying the message - * if there's no input. - */ - status = pthread_mutex_unlock (&alarm_mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - if (sleep_time > 0) - sleep (sleep_time); - else - sched_yield (); - - /* - * If a timer expired, print the message and free the - * structure. - */ - if (alarm != NULL) { - printf ("(%d) %s\n", alarm->seconds, alarm->message); - free (alarm); - } } -} -int main (int argc, char *argv[]) -{ - int status; - char line[128]; - alarm_t *alarm, **last, *next; - pthread_t thread; - - status = pthread_create ( - &thread, NULL, alarm_thread, NULL); + /* + * Unlock the mutex before waiting, so that the main + * thread can lock it to insert a new alarm request. If + * the sleep_time is 0, then call sched_yield, giving + * the main thread a chance to run if it has been + * readied by user input, without delaying the message + * if there's no input. + */ + status = pthread_mutex_unlock(&alarm_mutex); if (status != 0) - err_abort (status, "Create alarm thread"); - while (1) { - printf ("alarm> "); - if (fgets (line, sizeof (line), stdin) == NULL) exit (0); - if (strlen (line) <= 1) continue; - alarm = (alarm_t*)malloc (sizeof (alarm_t)); - if (alarm == NULL) - errno_abort ("Allocate alarm"); + err_abort(status, "Unlock mutex"); + if (sleep_time > 0) + sleep(sleep_time); + else + sched_yield(); - /* - * Parse input line into seconds (%d) and a message - * (%64[^\n]), consisting of up to 64 characters - * separated from the seconds by whitespace. - */ - if (sscanf (line, "%d %64[^\n]", - &alarm->seconds, alarm->message) < 2) { - fprintf (stderr, "Bad command\n"); - free (alarm); - } else { - status = pthread_mutex_lock (&alarm_mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - alarm->time = time (NULL) + alarm->seconds; - - /* - * Insert the new alarm into the list of alarms, - * sorted by expiration time. - */ - last = &alarm_list; - next = *last; - while (next != NULL) { - if (next->time >= alarm->time) { - alarm->link = next; - *last = alarm; - break; - } - last = &next->link; - next = next->link; - } - /* - * If we reached the end of the list, insert the new - * alarm there. ("next" is NULL, and "last" points - * to the link field of the last item, or to the - * list header). - */ - if (next == NULL) { - *last = alarm; - alarm->link = NULL; - } -#ifdef DEBUG - printf ("[list: "); - for (next = alarm_list; next != NULL; next = next->link) - printf ("%d(%d)[\"%s\"] ", next->time, - next->time - time (NULL), next->message); - printf ("]\n"); -#endif - status = pthread_mutex_unlock (&alarm_mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - } + /* + * If a timer expired, print the message and free the + * structure. + */ + if (alarm != NULL) { + printf("(%d) %s\n", alarm->seconds, alarm->message); + free(alarm); } + } +} + +int +main(int argc, char* argv[]) +{ + int status; + char line[128]; + alarm_t *alarm, **last, *next; + pthread_t thread; + + status = pthread_create(&thread, NULL, alarm_thread, NULL); + if (status != 0) + err_abort(status, "Create alarm thread"); + while (1) { + printf("alarm> "); + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); + if (strlen(line) <= 1) + continue; + alarm = (alarm_t*) malloc(sizeof(alarm_t)); + if (alarm == NULL) + errno_abort("Allocate alarm"); + + /* + * Parse input line into seconds (%d) and a message + * (%64[^\n]), consisting of up to 64 characters + * separated from the seconds by whitespace. + */ + if (sscanf(line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2) { + fprintf(stderr, "Bad command\n"); + free(alarm); + } + else { + status = pthread_mutex_lock(&alarm_mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + alarm->time = time(NULL) + alarm->seconds; + + /* + * Insert the new alarm into the list of alarms, + * sorted by expiration time. + */ + last = &alarm_list; + next = *last; + while (next != NULL) { + if (next->time >= alarm->time) { + alarm->link = next; + *last = alarm; + break; + } + last = &next->link; + next = next->link; + } + /* + * If we reached the end of the list, insert the new + * alarm there. ("next" is NULL, and "last" points + * to the link field of the last item, or to the + * list header). + */ + if (next == NULL) { + *last = alarm; + alarm->link = NULL; + } +#ifdef DEBUG + printf("[list: "); + for (next = alarm_list; next != NULL; next = next->link) + printf("%d(%d)[\"%s\"] ", + next->time, + next->time - time(NULL), + next->message); + printf("]\n"); +#endif + status = pthread_mutex_unlock(&alarm_mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + } + } } diff --git a/src/ch03/alarm_mutex_cpp.cpp b/src/ch03/alarm_mutex_cpp.cpp index a6222b1..9cd8c95 100644 --- a/src/ch03/alarm_mutex_cpp.cpp +++ b/src/ch03/alarm_mutex_cpp.cpp @@ -39,7 +39,9 @@ std::list alarm_list; /* * The alarm thread's start routine. */ -void *alarm_thread(void *arg) { +void* +alarm_thread(void* arg) +{ int sleep_time; time_t now; int status; @@ -50,16 +52,18 @@ void *alarm_thread(void *arg) { */ while (1) { status = pthread_mutex_lock(&alarm_mutex); - if (status != 0) err_abort(status, "Lock mutex"); + if (status != 0) + err_abort(status, "Lock mutex"); - now = time(NULL); + now = time(NULL); sleep_time = 0; for (auto it = alarm_list.begin(); it != alarm_list.end();) { if (it->time <= now) { printf("(%d) %s\n", it->seconds, it->message); it = alarm_list.erase(it); - } else { + } + else { sleep_time = MIN(it->time - now, sleep_time); ++it; } @@ -74,7 +78,8 @@ void *alarm_thread(void *arg) { * if there's no input. */ status = pthread_mutex_unlock(&alarm_mutex); - if (status != 0) err_abort(status, "Unlock mutex"); + if (status != 0) + err_abort(status, "Unlock mutex"); if (sleep_time > 0) sleep(sleep_time); else @@ -82,17 +87,22 @@ void *alarm_thread(void *arg) { } } -int main(int argc, char *argv[]) { +int +main(int argc, char* argv[]) +{ int status; char line[128]; pthread_t thread; status = pthread_create(&thread, NULL, alarm_thread, NULL); - if (status != 0) err_abort(status, "Create alarm thread"); + if (status != 0) + err_abort(status, "Create alarm thread"); while (1) { printf("alarm> "); - if (fgets(line, sizeof(line), stdin) == NULL) exit(0); - if (strlen(line) <= 1) continue; + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); + if (strlen(line) <= 1) + continue; alarm_t alarm; /* @@ -102,11 +112,13 @@ int main(int argc, char *argv[]) { */ if (sscanf(line, "%d %64[^\n]", &alarm.seconds, alarm.message) < 2) { fprintf(stderr, "Bad command\n"); - } else { + } + else { alarm.time = time(NULL) + alarm.seconds; status = pthread_mutex_lock(&alarm_mutex); - if (status != 0) err_abort(status, "Lock mutex"); + if (status != 0) + err_abort(status, "Lock mutex"); /* * Insert the new alarm into the list of alarms. @@ -115,13 +127,16 @@ int main(int argc, char *argv[]) { #ifdef DEBUG printf("[list: "); - for (const auto &iAlarm : alarm_list) - printf("%d(%d)[\"%s\"] ", iAlarm.time, iAlarm.time - time(NULL), + for (const auto& iAlarm : alarm_list) + printf("%d(%d)[\"%s\"] ", + iAlarm.time, + iAlarm.time - time(NULL), iAlarm.message); printf("]\n"); #endif status = pthread_mutex_unlock(&alarm_mutex); - if (status != 0) err_abort(status, "Unlock mutex"); + if (status != 0) + err_abort(status, "Unlock mutex"); } } } diff --git a/src/ch03/backoff.c b/src/ch03/backoff.c index 32438a3..b8e5169 100644 --- a/src/ch03/backoff.c +++ b/src/ch03/backoff.c @@ -17,75 +17,73 @@ /* * Initialize a static array of 3 mutexes. */ -pthread_mutex_t mutex[3] = { - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER - }; +pthread_mutex_t mutex[3] = {PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER}; -int backoff = 1; /* Whether to backoff or deadlock */ -int yield_flag = 0; /* 0: no yield, >0: yield, <0: sleep */ +int backoff = 1; /* Whether to backoff or deadlock */ +int yield_flag = 0; /* 0: no yield, >0: yield, <0: sleep */ /* * This is a thread start routine that locks all mutexes in * order, to ensure a conflict with lock_reverse, which does the * opposite. */ -void *lock_forward (void *arg) +void* +lock_forward(void* arg) { - int i, iterate, backoffs; - int status; + int i, iterate, backoffs; + int status; - for (iterate = 0; iterate < ITERATIONS; iterate++) { - backoffs = 0; - for (i = 0; i < 3; i++) { - if (i == 0) { - status = pthread_mutex_lock (&mutex[i]); - if (status != 0) - err_abort (status, "First lock"); - } else { - if (backoff) - status = pthread_mutex_trylock (&mutex[i]); - else - status = pthread_mutex_lock (&mutex[i]); - if (status == EBUSY) { - backoffs++; - DPRINTF (( - " [forward locker backing off at %d]\n", - i)); - for (; i >= 0; i--) { - status = pthread_mutex_unlock (&mutex[i]); - if (status != 0) - err_abort (status, "Backoff"); - } - } else { - if (status != 0) - err_abort (status, "Lock mutex"); - DPRINTF ((" forward locker got %d\n", i)); - } - } - /* - * Yield processor, if needed to be sure locks get - * interleaved on a uniprocessor. - */ - if (yield_flag) { - if (yield_flag > 0) - sched_yield (); - else - sleep (1); - } + for (iterate = 0; iterate < ITERATIONS; iterate++) { + backoffs = 0; + for (i = 0; i < 3; i++) { + if (i == 0) { + status = pthread_mutex_lock(&mutex[i]); + if (status != 0) + err_abort(status, "First lock"); + } + else { + if (backoff) + status = pthread_mutex_trylock(&mutex[i]); + else + status = pthread_mutex_lock(&mutex[i]); + if (status == EBUSY) { + backoffs++; + DPRINTF((" [forward locker backing off at %d]\n", i)); + for (; i >= 0; i--) { + status = pthread_mutex_unlock(&mutex[i]); + if (status != 0) + err_abort(status, "Backoff"); + } } - /* - * Report that we got 'em, and unlock to try again. - */ - printf ( - "lock forward got all locks, %d backoffs\n", backoffs); - pthread_mutex_unlock (&mutex[2]); - pthread_mutex_unlock (&mutex[1]); - pthread_mutex_unlock (&mutex[0]); - sched_yield (); + else { + if (status != 0) + err_abort(status, "Lock mutex"); + DPRINTF((" forward locker got %d\n", i)); + } + } + /* + * Yield processor, if needed to be sure locks get + * interleaved on a uniprocessor. + */ + if (yield_flag) { + if (yield_flag > 0) + sched_yield(); + else + sleep(1); + } } - return NULL; + /* + * Report that we got 'em, and unlock to try again. + */ + printf("lock forward got all locks, %d backoffs\n", backoffs); + pthread_mutex_unlock(&mutex[2]); + pthread_mutex_unlock(&mutex[1]); + pthread_mutex_unlock(&mutex[0]); + sched_yield(); + } + return NULL; } /* @@ -93,107 +91,106 @@ void *lock_forward (void *arg) * reverse order, to ensure a conflict with lock_forward, which * does the opposite. */ -void *lock_backward (void *arg) +void* +lock_backward(void* arg) { - int i, iterate, backoffs; - int status; + int i, iterate, backoffs; + int status; - for (iterate = 0; iterate < ITERATIONS; iterate++) { - backoffs = 0; - for (i = 2; i >= 0; i--) { - if (i == 2) { - status = pthread_mutex_lock (&mutex[i]); - if (status != 0) - err_abort (status, "First lock"); - } else { - if (backoff) - status = pthread_mutex_trylock (&mutex[i]); - else - status = pthread_mutex_lock (&mutex[i]); - if (status == EBUSY) { - backoffs++; - DPRINTF (( - " [backward locker backing off at %d]\n", - i)); - for (; i < 3; i++) { - status = pthread_mutex_unlock (&mutex[i]); - if (status != 0) - err_abort (status, "Backoff"); - } - } else { - if (status != 0) - err_abort (status, "Lock mutex"); - DPRINTF ((" backward locker got %d\n", i)); - } - } - /* - * Yield processor, if needed to be sure locks get - * interleaved on a uniprocessor. - */ - if (yield_flag) { - if (yield_flag > 0) - sched_yield (); - else - sleep (1); - } + for (iterate = 0; iterate < ITERATIONS; iterate++) { + backoffs = 0; + for (i = 2; i >= 0; i--) { + if (i == 2) { + status = pthread_mutex_lock(&mutex[i]); + if (status != 0) + err_abort(status, "First lock"); + } + else { + if (backoff) + status = pthread_mutex_trylock(&mutex[i]); + else + status = pthread_mutex_lock(&mutex[i]); + if (status == EBUSY) { + backoffs++; + DPRINTF((" [backward locker backing off at %d]\n", i)); + for (; i < 3; i++) { + status = pthread_mutex_unlock(&mutex[i]); + if (status != 0) + err_abort(status, "Backoff"); + } } - /* - * Report that we got 'em, and unlock to try again. - */ - printf ( - "lock backward got all locks, %d backoffs\n", backoffs); - pthread_mutex_unlock (&mutex[0]); - pthread_mutex_unlock (&mutex[1]); - pthread_mutex_unlock (&mutex[2]); - sched_yield (); + else { + if (status != 0) + err_abort(status, "Lock mutex"); + DPRINTF((" backward locker got %d\n", i)); + } + } + /* + * Yield processor, if needed to be sure locks get + * interleaved on a uniprocessor. + */ + if (yield_flag) { + if (yield_flag > 0) + sched_yield(); + else + sleep(1); + } } - return NULL; + /* + * Report that we got 'em, and unlock to try again. + */ + printf("lock backward got all locks, %d backoffs\n", backoffs); + pthread_mutex_unlock(&mutex[0]); + pthread_mutex_unlock(&mutex[1]); + pthread_mutex_unlock(&mutex[2]); + sched_yield(); + } + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t forward, backward; - int status; + pthread_t forward, backward; + int status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our threads can run concurrently, we need to - * increase the concurrency level. - */ - DPRINTF (("Setting concurrency level to 2\n")); - thr_setconcurrency (2); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level. + */ + DPRINTF(("Setting concurrency level to 2\n")); + thr_setconcurrency(2); #endif - /* - * If the first argument is absent, or nonzero, a backoff - * algorithm will be used to avoid deadlock. If the first - * argument is zero, the program will deadlock on a lock - * "collision." - */ - if (argc > 1) - backoff = atoi (argv[1]); + /* + * If the first argument is absent, or nonzero, a backoff + * algorithm will be used to avoid deadlock. If the first + * argument is zero, the program will deadlock on a lock + * "collision." + */ + if (argc > 1) + backoff = atoi(argv[1]); - /* - * If the second argument is absent, or zero, the two - * threads run "at speed." On some systems, especially - * uniprocessors, one thread may complete before the other - * has a chance to run, and you won't see a deadlock or - * backoffs. In that case, try running with the argument set - * to a positive number to cause the threads to call - * sched_yield() at each lock; or, to make it even more - * obvious, set to a negative number to cause the threads to - * call sleep(1) instead. - */ - if (argc > 2) - yield_flag = atoi (argv[2]); - status = pthread_create ( - &forward, NULL, lock_forward, NULL); - if (status != 0) - err_abort (status, "Create forward"); - status = pthread_create ( - &backward, NULL, lock_backward, NULL); - if (status != 0) - err_abort (status, "Create backward"); - pthread_exit (NULL); + /* + * If the second argument is absent, or zero, the two + * threads run "at speed." On some systems, especially + * uniprocessors, one thread may complete before the other + * has a chance to run, and you won't see a deadlock or + * backoffs. In that case, try running with the argument set + * to a positive number to cause the threads to call + * sched_yield() at each lock; or, to make it even more + * obvious, set to a negative number to cause the threads to + * call sleep(1) instead. + */ + if (argc > 2) + yield_flag = atoi(argv[2]); + status = pthread_create(&forward, NULL, lock_forward, NULL); + if (status != 0) + err_abort(status, "Create forward"); + status = pthread_create(&backward, NULL, lock_backward, NULL); + if (status != 0) + err_abort(status, "Create backward"); + pthread_exit(NULL); } diff --git a/src/ch03/cond.c b/src/ch03/cond.c index 6ffbc0f..6653ac5 100644 --- a/src/ch03/cond.c +++ b/src/ch03/cond.c @@ -8,88 +8,87 @@ #include "errors.h" typedef struct my_struct_tag { - pthread_mutex_t mutex; /* Protects access to value */ - pthread_cond_t cond; /* Signals change to value */ - int value; /* Access protected by mutex */ + pthread_mutex_t mutex; /* Protects access to value */ + pthread_cond_t cond; /* Signals change to value */ + int value; /* Access protected by mutex */ } my_struct_t; -my_struct_t data = { - PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0}; +my_struct_t data = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0}; -int hibernation = 1; /* Default to 1 second */ +int hibernation = 1; /* Default to 1 second */ /* * Thread start routine. It will set the main thread's predicate * and signal the condition variable. */ -void * -wait_thread (void *arg) +void* +wait_thread(void* arg) { - int status; + int status; - sleep (hibernation); - status = pthread_mutex_lock (&data.mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - data.value = 1; /* Set predicate */ - status = pthread_cond_signal (&data.cond); - if (status != 0) - err_abort (status, "Signal condition"); - status = pthread_mutex_unlock (&data.mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - return NULL; + sleep(hibernation); + status = pthread_mutex_lock(&data.mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + data.value = 1; /* Set predicate */ + status = pthread_cond_signal(&data.cond); + if (status != 0) + err_abort(status, "Signal condition"); + status = pthread_mutex_unlock(&data.mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int status; - pthread_t wait_thread_id; - struct timespec timeout; + int status; + pthread_t wait_thread_id; + struct timespec timeout; - /* - * If an argument is specified, interpret it as the number - * of seconds for wait_thread to sleep before signaling the - * condition variable. You can play with this to see the - * condition wait below time out or wake normally. - */ - if (argc > 1) - hibernation = atoi (argv[1]); + /* + * If an argument is specified, interpret it as the number + * of seconds for wait_thread to sleep before signaling the + * condition variable. You can play with this to see the + * condition wait below time out or wake normally. + */ + if (argc > 1) + hibernation = atoi(argv[1]); - /* - * Create wait_thread. - */ - status = pthread_create (&wait_thread_id, NULL, wait_thread, NULL); - if (status != 0) - err_abort (status, "Create wait thread"); + /* + * Create wait_thread. + */ + status = pthread_create(&wait_thread_id, NULL, wait_thread, NULL); + if (status != 0) + err_abort(status, "Create wait thread"); - /* - * Wait on the condition variable for 2 seconds, or until - * signaled by the wait_thread. Normally, wait_thread - * should signal. If you raise "hibernation" above 2 - * seconds, it will time out. - */ - timeout.tv_sec = time (NULL) + 2; - timeout.tv_nsec = 0; - status = pthread_mutex_lock (&data.mutex); - if (status != 0) - err_abort (status, "Lock mutex"); + /* + * Wait on the condition variable for 2 seconds, or until + * signaled by the wait_thread. Normally, wait_thread + * should signal. If you raise "hibernation" above 2 + * seconds, it will time out. + */ + timeout.tv_sec = time(NULL) + 2; + timeout.tv_nsec = 0; + status = pthread_mutex_lock(&data.mutex); + if (status != 0) + err_abort(status, "Lock mutex"); - while (data.value == 0) { - status = pthread_cond_timedwait ( - &data.cond, &data.mutex, &timeout); - if (status == ETIMEDOUT) { - printf ("Condition wait timed out.\n"); - break; - } - else if (status != 0) - err_abort (status, "Wait on condition"); + while (data.value == 0) { + status = pthread_cond_timedwait(&data.cond, &data.mutex, &timeout); + if (status == ETIMEDOUT) { + printf("Condition wait timed out.\n"); + break; } + else if (status != 0) + err_abort(status, "Wait on condition"); + } - if (data.value != 0) - printf ("Condition was signaled.\n"); - status = pthread_mutex_unlock (&data.mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - return 0; + if (data.value != 0) + printf("Condition was signaled.\n"); + status = pthread_mutex_unlock(&data.mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + return 0; } diff --git a/src/ch03/cond_dynamic.c b/src/ch03/cond_dynamic.c index 49a8be1..924556d 100644 --- a/src/ch03/cond_dynamic.c +++ b/src/ch03/cond_dynamic.c @@ -10,31 +10,32 @@ * Define a structure, with a mutex and condition variable. */ typedef struct my_struct_tag { - pthread_mutex_t mutex; /* Protects access to value */ - pthread_cond_t cond; /* Signals change to value */ - int value; /* Access protected by mutex */ + pthread_mutex_t mutex; /* Protects access to value */ + pthread_cond_t cond; /* Signals change to value */ + int value; /* Access protected by mutex */ } my_struct_t; -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - my_struct_t *data; - int status; + my_struct_t* data; + int status; - data = malloc (sizeof (my_struct_t)); - if (data == NULL) - errno_abort ("Allocate structure"); - status = pthread_mutex_init (&data->mutex, NULL); - if (status != 0) - err_abort (status, "Init mutex"); - status = pthread_cond_init (&data->cond, NULL); - if (status != 0) - err_abort (status, "Init condition"); - status = pthread_cond_destroy (&data->cond); - if (status != 0) - err_abort (status, "Destroy condition"); - status = pthread_mutex_destroy (&data->mutex); - if (status != 0) - err_abort (status, "Destroy mutex"); - (void)free (data); - return status; + data = malloc(sizeof(my_struct_t)); + if (data == NULL) + errno_abort("Allocate structure"); + status = pthread_mutex_init(&data->mutex, NULL); + if (status != 0) + err_abort(status, "Init mutex"); + status = pthread_cond_init(&data->cond, NULL); + if (status != 0) + err_abort(status, "Init condition"); + status = pthread_cond_destroy(&data->cond); + if (status != 0) + err_abort(status, "Destroy condition"); + status = pthread_mutex_destroy(&data->mutex); + if (status != 0) + err_abort(status, "Destroy mutex"); + (void) free(data); + return status; } diff --git a/src/ch03/cond_static.c b/src/ch03/cond_static.c index 1da6cfd..9e43f88 100644 --- a/src/ch03/cond_static.c +++ b/src/ch03/cond_static.c @@ -13,15 +13,15 @@ * attributes. */ typedef struct my_struct_tag { - pthread_mutex_t mutex; /* Protects access to value */ - pthread_cond_t cond; /* Signals change to value */ - int value; /* Access protected by mutex */ + pthread_mutex_t mutex; /* Protects access to value */ + pthread_cond_t cond; /* Signals change to value */ + int value; /* Access protected by mutex */ } my_struct_t; -my_struct_t data = { - PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0}; +my_struct_t data = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0}; -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - return 0; + return 0; } diff --git a/src/ch03/mutex_dynamic.c b/src/ch03/mutex_dynamic.c index 5289502..f0749bc 100644 --- a/src/ch03/mutex_dynamic.c +++ b/src/ch03/mutex_dynamic.c @@ -10,24 +10,25 @@ * Define a structure, with a mutex. */ typedef struct my_struct_tag { - pthread_mutex_t mutex; /* Protects access to value */ - int value; /* Access protected by mutex */ + pthread_mutex_t mutex; /* Protects access to value */ + int value; /* Access protected by mutex */ } my_struct_t; -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - my_struct_t *data; - int status; + my_struct_t* data; + int status; - data = malloc (sizeof (my_struct_t)); - if (data == NULL) - errno_abort ("Allocate structure"); - status = pthread_mutex_init (&data->mutex, NULL); - if (status != 0) - err_abort (status, "Init mutex"); - status = pthread_mutex_destroy (&data->mutex); - if (status != 0) - err_abort (status, "Destroy mutex"); - (void)free (data); - return status; + data = malloc(sizeof(my_struct_t)); + if (data == NULL) + errno_abort("Allocate structure"); + status = pthread_mutex_init(&data->mutex, NULL); + if (status != 0) + err_abort(status, "Init mutex"); + status = pthread_mutex_destroy(&data->mutex); + if (status != 0) + err_abort(status, "Destroy mutex"); + (void) free(data); + return status; } diff --git a/src/ch03/mutex_static.c b/src/ch03/mutex_static.c index 41f5685..8c43310 100644 --- a/src/ch03/mutex_static.c +++ b/src/ch03/mutex_static.c @@ -11,13 +11,14 @@ * same as using pthread_mutex_init, with the default attributes. */ typedef struct my_struct_tag { - pthread_mutex_t mutex; /* Protects access to value */ - int value; /* Access protected by mutex */ + pthread_mutex_t mutex; /* Protects access to value */ + int value; /* Access protected by mutex */ } my_struct_t; my_struct_t data = {PTHREAD_MUTEX_INITIALIZER, 0}; -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - return 0; + return 0; } diff --git a/src/ch03/trylock.c b/src/ch03/trylock.c index 4d2421f..bf719e1 100644 --- a/src/ch03/trylock.c +++ b/src/ch03/trylock.c @@ -24,7 +24,9 @@ time_t end_time; * Thread start routine that repeatedly locks a mutex and * increments a counter. */ -void *counter_thread(void *arg) { +void* +counter_thread(void* arg) +{ int status; int spin; @@ -36,11 +38,13 @@ void *counter_thread(void *arg) { */ while (time(NULL) < end_time) { status = pthread_mutex_lock(&mutex); - if (status != 0) err_abort(status, "Lock mutex"); + if (status != 0) + err_abort(status, "Lock mutex"); for (spin = 0; spin < SPIN; spin++) counter++; sleep(4); status = pthread_mutex_unlock(&mutex); - if (status != 0) err_abort(status, "Unlock mutex"); + if (status != 0) + err_abort(status, "Unlock mutex"); sleep(1); } printf("Counter is %#lx\n", counter); @@ -52,7 +56,9 @@ void *counter_thread(void *arg) { * seconds, try to lock the mutex and read the counter. If the * trylock fails, skip this cycle. */ -void *monitor_thread(void *arg) { +void* +monitor_thread(void* arg) +{ int status; int misses = 0; @@ -64,18 +70,23 @@ void *monitor_thread(void *arg) { sleep(3); status = pthread_mutex_trylock(&mutex); if (status != EBUSY) { - if (status != 0) err_abort(status, "Trylock mutex"); + if (status != 0) + err_abort(status, "Trylock mutex"); printf("Counter is %ld\n", counter / SPIN); status = pthread_mutex_unlock(&mutex); - if (status != 0) err_abort(status, "Unlock mutex"); - } else + if (status != 0) + err_abort(status, "Unlock mutex"); + } + else misses++; /* Count "misses" on the lock */ } printf("Monitor thread missed update %d times.\n", misses); return NULL; } -int main(int argc, char *argv[]) { +int +main(int argc, char* argv[]) +{ int status; pthread_t counter_thread_id; pthread_t monitor_thread_id; @@ -91,13 +102,17 @@ int main(int argc, char *argv[]) { #endif end_time = time(NULL) + 60; /* Run for 1 minute */ - status = pthread_create(&counter_thread_id, NULL, counter_thread, NULL); - if (status != 0) err_abort(status, "Create counter thread"); + status = pthread_create(&counter_thread_id, NULL, counter_thread, NULL); + if (status != 0) + err_abort(status, "Create counter thread"); status = pthread_create(&monitor_thread_id, NULL, monitor_thread, NULL); - if (status != 0) err_abort(status, "Create monitor thread"); + if (status != 0) + err_abort(status, "Create monitor thread"); status = pthread_join(counter_thread_id, NULL); - if (status != 0) err_abort(status, "Join counter thread"); + if (status != 0) + err_abort(status, "Join counter thread"); status = pthread_join(monitor_thread_id, NULL); - if (status != 0) err_abort(status, "Join monitor thread"); + if (status != 0) + err_abort(status, "Join monitor thread"); return 0; } diff --git a/src/ch04/crew.c b/src/ch04/crew.c index be4564f..963de19 100644 --- a/src/ch04/crew.c +++ b/src/ch04/crew.c @@ -9,22 +9,22 @@ * by calling thr_setconcurrency(), because threads are not * timesliced. */ -#include +#include #include #include -#include +#include #include "errors.h" -#define CREW_SIZE 4 +#define CREW_SIZE 4 /* * Queued items of work for the crew. One is queued by * crew_start, and each worker may queue additional items. */ typedef struct work_tag { - struct work_tag *next; /* Next work item */ - char *path; /* Directory or file */ - char *string; /* Search string */ + struct work_tag* next; /* Next work item */ + char* path; /* Directory or file */ + char* string; /* Search string */ } work_t, *work_p; /* @@ -32,9 +32,9 @@ typedef struct work_tag { * crew. It contains the "identity" of each worker. */ typedef struct worker_tag { - int index; /* Thread's index */ - pthread_t thread; /* Thread for stage */ - struct crew_tag *crew; /* Pointer to crew */ + int index; /* Thread's index */ + pthread_t thread; /* Thread for stage */ + struct crew_tag* crew; /* Pointer to crew */ } worker_t, *worker_p; /* @@ -42,444 +42,459 @@ typedef struct worker_tag { * crew synchronization state and staging area. */ typedef struct crew_tag { - int crew_size; /* Size of array */ - worker_t crew[CREW_SIZE];/* Crew members */ - long work_count; /* Count of work items */ - work_t *first, *last; /* First & last work item */ - pthread_mutex_t mutex; /* Mutex for crew data */ - pthread_cond_t done; /* Wait for crew done */ - pthread_cond_t go; /* Wait for work */ + int crew_size; /* Size of array */ + worker_t crew[CREW_SIZE]; /* Crew members */ + long work_count; /* Count of work items */ + work_t *first, *last; /* First & last work item */ + pthread_mutex_t mutex; /* Mutex for crew data */ + pthread_cond_t done; /* Wait for crew done */ + pthread_cond_t go; /* Wait for work */ } crew_t, *crew_p; -size_t path_max; /* Filepath length */ -size_t name_max; /* Name length */ +size_t path_max; /* Filepath length */ +size_t name_max; /* Name length */ /* * The thread start routine for crew threads. Waits until "go" * command, processes work items until requested to shut down. */ -void *worker_routine (void *arg) +void* +worker_routine(void* arg) { - worker_p mine = (worker_t*)arg; - crew_p crew = mine->crew; - work_p work, new_work; - struct stat filestat; - struct dirent *entry; - int status; + worker_p mine = (worker_t*) arg; + crew_p crew = mine->crew; + work_p work, new_work; + struct stat filestat; + struct dirent* entry; + int status; - /* - * "struct dirent" is funny, because POSIX doesn't require - * the definition to be more than a header for a variable - * buffer. Thus, allocate a "big chunk" of memory, and use - * it as a buffer. - */ - entry = (struct dirent*)malloc ( - sizeof (struct dirent) + name_max); - if (entry == NULL) - errno_abort ("Allocating dirent"); - - status = pthread_mutex_lock (&crew->mutex); + /* + * "struct dirent" is funny, because POSIX doesn't require + * the definition to be more than a header for a variable + * buffer. Thus, allocate a "big chunk" of memory, and use + * it as a buffer. + */ + entry = (struct dirent*) malloc(sizeof(struct dirent) + name_max); + if (entry == NULL) + errno_abort("Allocating dirent"); + + status = pthread_mutex_lock(&crew->mutex); + if (status != 0) + err_abort(status, "Lock crew mutex"); + + /* + * There won't be any work when the crew is created, so wait + * until something's put on the queue. + */ + while (crew->work_count == 0) { + status = pthread_cond_wait(&crew->go, &crew->mutex); if (status != 0) - err_abort (status, "Lock crew mutex"); + err_abort(status, "Wait for go"); + } + status = pthread_mutex_unlock(&crew->mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + + DPRINTF(("Crew %d starting\n", mine->index)); + + /* + * Now, as long as there's work, keep doing it. + */ + while (1) { /* - * There won't be any work when the crew is created, so wait - * until something's put on the queue. + * Wait while there is nothing to do, and + * the hope of something coming along later. If + * crew->first is NULL, there's no work. But if + * crew->work_count goes to zero, we're done. */ - while (crew->work_count == 0) { - status = pthread_cond_wait (&crew->go, &crew->mutex); - if (status != 0) - err_abort (status, "Wait for go"); + status = pthread_mutex_lock(&crew->mutex); + if (status != 0) + err_abort(status, "Lock crew mutex"); + + DPRINTF(("Crew %d top: first is %#lx, count is %d\n", + mine->index, + crew->first, + crew->work_count)); + while (crew->first == NULL) { + status = pthread_cond_wait(&crew->go, &crew->mutex); + if (status != 0) + err_abort(status, "Wait for work"); } - status = pthread_mutex_unlock (&crew->mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - - DPRINTF (("Crew %d starting\n", mine->index)); + DPRINTF(("Crew %d woke: %#lx, %d\n", + mine->index, + crew->first, + crew->work_count)); /* - * Now, as long as there's work, keep doing it. + * Remove and process a work item */ - while (1) { - /* - * Wait while there is nothing to do, and - * the hope of something coming along later. If - * crew->first is NULL, there's no work. But if - * crew->work_count goes to zero, we're done. - */ - status = pthread_mutex_lock (&crew->mutex); - if (status != 0) - err_abort (status, "Lock crew mutex"); + work = crew->first; + crew->first = work->next; + if (crew->first == NULL) + crew->last = NULL; - DPRINTF (("Crew %d top: first is %#lx, count is %d\n", - mine->index, crew->first, crew->work_count)); - while (crew->first == NULL) { - status = pthread_cond_wait (&crew->go, &crew->mutex); - if (status != 0) - err_abort (status, "Wait for work"); + DPRINTF(("Crew %d took %#lx, leaves first %#lx, last %#lx\n", + mine->index, + work, + crew->first, + crew->last)); + + status = pthread_mutex_unlock(&crew->mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + + /* + * We have a work item. Process it, which may involve + * queuing new work items. + */ + status = lstat(work->path, &filestat); + + if (S_ISLNK(filestat.st_mode)) + printf("Thread %d: %s is a link, skipping.\n", mine->index, work->path); + else if (S_ISDIR(filestat.st_mode)) { + DIR* directory; + struct dirent* result; + + /* + * If the file is a directory, search it and place + * all files onto the queue as new work items. + */ + directory = opendir(work->path); + if (directory == NULL) { + fprintf(stderr, + "Unable to open directory %s: %d (%s)\n", + work->path, + errno, + strerror(errno)); + continue; + } + + while (1) { + status = readdir_r(directory, entry, &result); + if (status != 0) { + fprintf(stderr, + "Unable to read directory %s: %d (%s)\n", + work->path, + status, + strerror(status)); + break; } - - DPRINTF (("Crew %d woke: %#lx, %d\n", - mine->index, crew->first, crew->work_count)); + if (result == NULL) + break; /* End of directory */ /* - * Remove and process a work item + * Ignore "." and ".." entries. */ - work = crew->first; - crew->first = work->next; - if (crew->first == NULL) - crew->last = NULL; - - DPRINTF (("Crew %d took %#lx, leaves first %#lx, last %#lx\n", - mine->index, work, crew->first, crew->last)); - - status = pthread_mutex_unlock (&crew->mutex); + if (strcmp(entry->d_name, ".") == 0) + continue; + if (strcmp(entry->d_name, "..") == 0) + continue; + new_work = (work_p) malloc(sizeof(work_t)); + if (new_work == NULL) + errno_abort("Unable to allocate space"); + new_work->path = (char*) malloc(path_max); + if (new_work->path == NULL) + errno_abort("Unable to allocate path"); + strcpy(new_work->path, work->path); + strcat(new_work->path, "/"); + strcat(new_work->path, entry->d_name); + new_work->string = work->string; + new_work->next = NULL; + status = pthread_mutex_lock(&crew->mutex); if (status != 0) - err_abort (status, "Unlock mutex"); + err_abort(status, "Lock mutex"); + if (crew->first == NULL) { + crew->first = new_work; + crew->last = new_work; + } + else { + crew->last->next = new_work; + crew->last = new_work; + } + crew->work_count++; + DPRINTF(("Crew %d: add work %#lx, first %#lx, last %#lx, %d\n", + mine->index, + new_work, + crew->first, + crew->last, + crew->work_count)); + status = pthread_cond_signal(&crew->go); + status = pthread_mutex_unlock(&crew->mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + } - /* - * We have a work item. Process it, which may involve - * queuing new work items. - */ - status = lstat (work->path, &filestat); + closedir(directory); + } + else if (S_ISREG(filestat.st_mode)) { + FILE* search; + char buffer[256], *bufptr, *search_ptr; - if (S_ISLNK (filestat.st_mode)) - printf ( - "Thread %d: %s is a link, skipping.\n", - mine->index, - work->path); - else if (S_ISDIR (filestat.st_mode)) { - DIR *directory; - struct dirent *result; - - /* - * If the file is a directory, search it and place - * all files onto the queue as new work items. - */ - directory = opendir (work->path); - if (directory == NULL) { - fprintf ( - stderr, "Unable to open directory %s: %d (%s)\n", - work->path, - errno, strerror (errno)); - continue; + /* + * If this is a file, not a directory, then search + * it for the string. + */ + search = fopen(work->path, "r"); + if (search == NULL) + fprintf(stderr, + "Unable to open %s: %d (%s)\n", + work->path, + errno, + strerror(errno)); + else { + while (1) { + bufptr = fgets(buffer, sizeof(buffer), search); + if (bufptr == NULL) { + if (feof(search)) + break; + if (ferror(search)) { + fprintf(stderr, + "Unable to read %s: %d (%s)\n", + work->path, + errno, + strerror(errno)); + break; } - - while (1) { - status = readdir_r (directory, entry, &result); - if (status != 0) { - fprintf ( - stderr, - "Unable to read directory %s: %d (%s)\n", - work->path, - status, strerror (status)); - break; - } - if (result == NULL) - break; /* End of directory */ - - /* - * Ignore "." and ".." entries. - */ - if (strcmp (entry->d_name, ".") == 0) - continue; - if (strcmp (entry->d_name, "..") == 0) - continue; - new_work = (work_p)malloc (sizeof (work_t)); - if (new_work == NULL) - errno_abort ("Unable to allocate space"); - new_work->path = (char*)malloc (path_max); - if (new_work->path == NULL) - errno_abort ("Unable to allocate path"); - strcpy (new_work->path, work->path); - strcat (new_work->path, "/"); - strcat (new_work->path, entry->d_name); - new_work->string = work->string; - new_work->next = NULL; - status = pthread_mutex_lock (&crew->mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - if (crew->first == NULL) { - crew->first = new_work; - crew->last = new_work; - } else { - crew->last->next = new_work; - crew->last = new_work; - } - crew->work_count++; - DPRINTF (( - "Crew %d: add work %#lx, first %#lx, last %#lx, %d\n", - mine->index, new_work, crew->first, - crew->last, crew->work_count)); - status = pthread_cond_signal (&crew->go); - status = pthread_mutex_unlock (&crew->mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - } - - closedir (directory); - } else if (S_ISREG (filestat.st_mode)) { - FILE *search; - char buffer[256], *bufptr, *search_ptr; - - /* - * If this is a file, not a directory, then search - * it for the string. - */ - search = fopen (work->path, "r"); - if (search == NULL) - fprintf ( - stderr, "Unable to open %s: %d (%s)\n", - work->path, - errno, strerror (errno)); - else { - - while (1) { - bufptr = fgets ( - buffer, sizeof (buffer), search); - if (bufptr == NULL) { - if (feof (search)) - break; - if (ferror (search)) { - fprintf ( - stderr, - "Unable to read %s: %d (%s)\n", - work->path, - errno, strerror (errno)); - break; - } - } - search_ptr = strstr (buffer, work->string); - if (search_ptr != NULL) { - flockfile (stdout); - printf ( - "Thread %d found \"%s\" in %s\n", - mine->index, work->string, work->path); + } + search_ptr = strstr(buffer, work->string); + if (search_ptr != NULL) { + flockfile(stdout); + printf("Thread %d found \"%s\" in %s\n", + mine->index, + work->string, + work->path); #if 0 printf ("%s\n", buffer); #endif - funlockfile (stdout); - break; - } - } - fclose (search); - } - } else - fprintf ( - stderr, - "Thread %d: %s is type %o (%s))\n", - mine->index, - work->path, - filestat.st_mode & S_IFMT, - (S_ISFIFO (filestat.st_mode) ? "FIFO" - : (S_ISCHR (filestat.st_mode) ? "CHR" - : (S_ISBLK (filestat.st_mode) ? "BLK" - : (S_ISSOCK (filestat.st_mode) ? "SOCK" - : "unknown"))))); - - free (work->path); /* Free path buffer */ - free (work); /* We're done with this */ - - /* - * Decrement count of outstanding work items, and wake - * waiters (trying to collect results or start a new - * calculation) if the crew is now idle. - * - * It's important that the count be decremented AFTER - * processing the current work item. That ensures the - * count won't go to 0 until we're really done. - */ - status = pthread_mutex_lock (&crew->mutex); - if (status != 0) - err_abort (status, "Lock crew mutex"); - - crew->work_count--; - DPRINTF (("Crew %d decremented work to %d\n", mine->index, - crew->work_count)); - if (crew->work_count <= 0) { - DPRINTF (("Crew thread %d done\n", mine->index)); - status = pthread_cond_broadcast (&crew->done); - if (status != 0) - err_abort (status, "Wake waiters"); - status = pthread_mutex_unlock (&crew->mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); + funlockfile(stdout); break; + } } + fclose(search); + } + } + else + fprintf(stderr, + "Thread %d: %s is type %o (%s))\n", + mine->index, + work->path, + filestat.st_mode & S_IFMT, + (S_ISFIFO(filestat.st_mode) + ? "FIFO" + : (S_ISCHR(filestat.st_mode) + ? "CHR" + : (S_ISBLK(filestat.st_mode) + ? "BLK" + : (S_ISSOCK(filestat.st_mode) ? "SOCK" + : "unknown"))))); - status = pthread_mutex_unlock (&crew->mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); + free(work->path); /* Free path buffer */ + free(work); /* We're done with this */ + /* + * Decrement count of outstanding work items, and wake + * waiters (trying to collect results or start a new + * calculation) if the crew is now idle. + * + * It's important that the count be decremented AFTER + * processing the current work item. That ensures the + * count won't go to 0 until we're really done. + */ + status = pthread_mutex_lock(&crew->mutex); + if (status != 0) + err_abort(status, "Lock crew mutex"); + + crew->work_count--; + DPRINTF( + ("Crew %d decremented work to %d\n", mine->index, crew->work_count)); + if (crew->work_count <= 0) { + DPRINTF(("Crew thread %d done\n", mine->index)); + status = pthread_cond_broadcast(&crew->done); + if (status != 0) + err_abort(status, "Wake waiters"); + status = pthread_mutex_unlock(&crew->mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + break; } - free (entry); - return NULL; + status = pthread_mutex_unlock(&crew->mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + } + + free(entry); + return NULL; } /* * Create a work crew. */ -int crew_create (crew_t *crew, int crew_size) +int +crew_create(crew_t* crew, int crew_size) { - int crew_index; - int status; + int crew_index; + int status; - /* - * We won't create more than CREW_SIZE members - */ - if (crew_size > CREW_SIZE) - return EINVAL; + /* + * We won't create more than CREW_SIZE members + */ + if (crew_size > CREW_SIZE) + return EINVAL; - crew->crew_size = crew_size; - crew->work_count = 0; - crew->first = NULL; - crew->last = NULL; + crew->crew_size = crew_size; + crew->work_count = 0; + crew->first = NULL; + crew->last = NULL; - /* - * Initialize synchronization objects - */ - status = pthread_mutex_init (&crew->mutex, NULL); + /* + * Initialize synchronization objects + */ + status = pthread_mutex_init(&crew->mutex, NULL); + if (status != 0) + return status; + status = pthread_cond_init(&crew->done, NULL); + if (status != 0) + return status; + status = pthread_cond_init(&crew->go, NULL); + if (status != 0) + return status; + + /* + * Create the worker threads. + */ + for (crew_index = 0; crew_index < CREW_SIZE; crew_index++) { + crew->crew[crew_index].index = crew_index; + crew->crew[crew_index].crew = crew; + status = pthread_create(&crew->crew[crew_index].thread, + NULL, + worker_routine, + (void*) &crew->crew[crew_index]); if (status != 0) - return status; - status = pthread_cond_init (&crew->done, NULL); - if (status != 0) - return status; - status = pthread_cond_init (&crew->go, NULL); - if (status != 0) - return status; - - /* - * Create the worker threads. - */ - for (crew_index = 0; crew_index < CREW_SIZE; crew_index++) { - crew->crew[crew_index].index = crew_index; - crew->crew[crew_index].crew = crew; - status = pthread_create (&crew->crew[crew_index].thread, - NULL, worker_routine, (void*)&crew->crew[crew_index]); - if (status != 0) - err_abort (status, "Create worker"); - } - return 0; + err_abort(status, "Create worker"); + } + return 0; } /* * Pass a file path to a work crew previously created * using crew_create */ -int crew_start ( - crew_p crew, - char *filepath, - char *search) +int +crew_start(crew_p crew, char* filepath, char* search) { - work_p request; - int status; + work_p request; + int status; - status = pthread_mutex_lock (&crew->mutex); - if (status != 0) - return status; + status = pthread_mutex_lock(&crew->mutex); + if (status != 0) + return status; - /* - * If the crew is busy, wait for them to finish. - */ - while (crew->work_count > 0) { - status = pthread_cond_wait (&crew->done, &crew->mutex); - if (status != 0) { - pthread_mutex_unlock (&crew->mutex); - return status; - } - } - - errno = 0; - path_max = pathconf (filepath, _PC_PATH_MAX); - if (path_max == -1) { - if (errno == 0) - path_max = 1024; /* "No limit" */ - else - errno_abort ("Unable to get PATH_MAX"); - } - errno = 0; - name_max = pathconf (filepath, _PC_NAME_MAX); - if (name_max == -1) { - if (errno == 0) - name_max = 256; /* "No limit" */ - else - errno_abort ("Unable to get NAME_MAX"); - } - DPRINTF (( - "PATH_MAX for %s is %ld, NAME_MAX is %ld\n", - filepath, path_max, name_max)); - path_max++; /* Add null byte */ - name_max++; /* Add null byte */ - request = (work_p)malloc (sizeof (work_t)); - if (request == NULL) - errno_abort ("Unable to allocate request"); - DPRINTF (("Requesting %s\n", filepath)); - request->path = (char*)malloc (path_max); - if (request->path == NULL) - errno_abort ("Unable to allocate path"); - strcpy (request->path, filepath); - request->string = search; - request->next = NULL; - if (crew->first == NULL) { - crew->first = request; - crew->last = request; - } else { - crew->last->next = request; - crew->last = request; - } - - crew->work_count++; - status = pthread_cond_signal (&crew->go); + /* + * If the crew is busy, wait for them to finish. + */ + while (crew->work_count > 0) { + status = pthread_cond_wait(&crew->done, &crew->mutex); if (status != 0) { - free (crew->first); - crew->first = NULL; - crew->work_count = 0; - pthread_mutex_unlock (&crew->mutex); - return status; + pthread_mutex_unlock(&crew->mutex); + return status; } - while (crew->work_count > 0) { - status = pthread_cond_wait (&crew->done, &crew->mutex); - if (status != 0) - err_abort (status, "waiting for crew to finish"); - } - status = pthread_mutex_unlock (&crew->mutex); + } + + errno = 0; + path_max = pathconf(filepath, _PC_PATH_MAX); + if (path_max == -1) { + if (errno == 0) + path_max = 1024; /* "No limit" */ + else + errno_abort("Unable to get PATH_MAX"); + } + errno = 0; + name_max = pathconf(filepath, _PC_NAME_MAX); + if (name_max == -1) { + if (errno == 0) + name_max = 256; /* "No limit" */ + else + errno_abort("Unable to get NAME_MAX"); + } + DPRINTF(("PATH_MAX for %s is %ld, NAME_MAX is %ld\n", + filepath, + path_max, + name_max)); + path_max++; /* Add null byte */ + name_max++; /* Add null byte */ + request = (work_p) malloc(sizeof(work_t)); + if (request == NULL) + errno_abort("Unable to allocate request"); + DPRINTF(("Requesting %s\n", filepath)); + request->path = (char*) malloc(path_max); + if (request->path == NULL) + errno_abort("Unable to allocate path"); + strcpy(request->path, filepath); + request->string = search; + request->next = NULL; + if (crew->first == NULL) { + crew->first = request; + crew->last = request; + } + else { + crew->last->next = request; + crew->last = request; + } + + crew->work_count++; + status = pthread_cond_signal(&crew->go); + if (status != 0) { + free(crew->first); + crew->first = NULL; + crew->work_count = 0; + pthread_mutex_unlock(&crew->mutex); + return status; + } + while (crew->work_count > 0) { + status = pthread_cond_wait(&crew->done, &crew->mutex); if (status != 0) - err_abort (status, "Unlock crew mutex"); - return 0; + err_abort(status, "waiting for crew to finish"); + } + status = pthread_mutex_unlock(&crew->mutex); + if (status != 0) + err_abort(status, "Unlock crew mutex"); + return 0; } /* * The main program to "drive" the crew... */ -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - crew_t my_crew; - char line[128], *next; - int status; + crew_t my_crew; + char line[128], *next; + int status; - if (argc < 3) { - fprintf (stderr, "Usage: %s string path\n", argv[0]); - return -1; - } + if (argc < 3) { + fprintf(stderr, "Usage: %s string path\n", argv[0]); + return -1; + } #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our threads can run concurrently, we need to - * increase the concurrency level to CREW_SIZE. - */ - DPRINTF (("Setting concurrency level to %d\n", CREW_SIZE)); - thr_setconcurrency (CREW_SIZE); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level to CREW_SIZE. + */ + DPRINTF(("Setting concurrency level to %d\n", CREW_SIZE)); + thr_setconcurrency(CREW_SIZE); #endif - status = crew_create (&my_crew, CREW_SIZE); - if (status != 0) - err_abort (status, "Create crew"); + status = crew_create(&my_crew, CREW_SIZE); + if (status != 0) + err_abort(status, "Create crew"); - status = crew_start (&my_crew, argv[2], argv[1]); - if (status != 0) - err_abort (status, "Start crew"); + status = crew_start(&my_crew, argv[2], argv[1]); + if (status != 0) + err_abort(status, "Start crew"); - return 0; + return 0; } diff --git a/src/ch04/pipe.c b/src/ch04/pipe.c index cf3a23e..e79a98e 100644 --- a/src/ch04/pipe.c +++ b/src/ch04/pipe.c @@ -16,13 +16,13 @@ * stage" where the final thread can stash the value. */ typedef struct stage_tag { - pthread_mutex_t mutex; /* Protect data */ - pthread_cond_t avail; /* Data available */ - pthread_cond_t ready; /* Ready for data */ - int data_ready; /* Data present */ - long data; /* Data to process */ - pthread_t thread; /* Thread for stage */ - struct stage_tag *next; /* Next stage */ + pthread_mutex_t mutex; /* Protect data */ + pthread_cond_t avail; /* Data available */ + pthread_cond_t ready; /* Ready for data */ + int data_ready; /* Data present */ + long data; /* Data to process */ + pthread_t thread; /* Thread for stage */ + struct stage_tag* next; /* Next stage */ } stage_t; /* @@ -30,11 +30,11 @@ typedef struct stage_tag { * pipeline. */ typedef struct pipe_tag { - pthread_mutex_t mutex; /* Mutex to protect pipe */ - stage_t *head; /* First stage */ - stage_t *tail; /* Final stage */ - int stages; /* Number of stages */ - int active; /* Active data elements */ + pthread_mutex_t mutex; /* Mutex to protect pipe */ + stage_t* head; /* First stage */ + stage_t* tail; /* Final stage */ + int stages; /* Number of stages */ + int active; /* Active data elements */ } pipe_t; /* @@ -42,37 +42,38 @@ typedef struct pipe_tag { * specified pipe stage. Threads use this to pass * along the modified data item. */ -int pipe_send (stage_t *stage, long data) +int +pipe_send(stage_t* stage, long data) { - int status; + int status; - status = pthread_mutex_lock (&stage->mutex); - if (status != 0) - return status; - /* - * If there's data in the pipe stage, wait for it - * to be consumed. - */ - while (stage->data_ready) { - status = pthread_cond_wait (&stage->ready, &stage->mutex); - if (status != 0) { - pthread_mutex_unlock (&stage->mutex); - return status; - } - } - - /* - * Send the new data - */ - stage->data = data; - stage->data_ready = 1; - status = pthread_cond_signal (&stage->avail); - if (status != 0) { - pthread_mutex_unlock (&stage->mutex); - return status; - } - status = pthread_mutex_unlock (&stage->mutex); + status = pthread_mutex_lock(&stage->mutex); + if (status != 0) return status; + /* + * If there's data in the pipe stage, wait for it + * to be consumed. + */ + while (stage->data_ready) { + status = pthread_cond_wait(&stage->ready, &stage->mutex); + if (status != 0) { + pthread_mutex_unlock(&stage->mutex); + return status; + } + } + + /* + * Send the new data + */ + stage->data = data; + stage->data_ready = 1; + status = pthread_cond_signal(&stage->avail); + if (status != 0) { + pthread_mutex_unlock(&stage->mutex); + return status; + } + status = pthread_mutex_unlock(&stage->mutex); + return status; } /* @@ -81,34 +82,35 @@ int pipe_send (stage_t *stage, long data) * caller or the previous stage, modify the data * and pass it along to the next (or final) stage. */ -void *pipe_stage (void *arg) +void* +pipe_stage(void* arg) { - stage_t *stage = (stage_t*)arg; - stage_t *next_stage = stage->next; - int status; + stage_t* stage = (stage_t*) arg; + stage_t* next_stage = stage->next; + int status; - status = pthread_mutex_lock (&stage->mutex); - if (status != 0) - err_abort (status, "Lock pipe stage"); - while (1) { - while (stage->data_ready != 1) { - status = pthread_cond_wait (&stage->avail, &stage->mutex); - if (status != 0) - err_abort (status, "Wait for previous stage"); - } - pipe_send (next_stage, stage->data + 1); - stage->data_ready = 0; - status = pthread_cond_signal (&stage->ready); - if (status != 0) - err_abort (status, "Wake next stage"); + status = pthread_mutex_lock(&stage->mutex); + if (status != 0) + err_abort(status, "Lock pipe stage"); + while (1) { + while (stage->data_ready != 1) { + status = pthread_cond_wait(&stage->avail, &stage->mutex); + if (status != 0) + err_abort(status, "Wait for previous stage"); } - /* - * Notice that the routine never unlocks the stage->mutex. - * The call to pthread_cond_wait implicitly unlocks the - * mutex while the thread is waiting, allowing other threads - * to make progress. Because the loop never terminates, this - * function has no need to unlock the mutex explicitly. - */ + pipe_send(next_stage, stage->data + 1); + stage->data_ready = 0; + status = pthread_cond_signal(&stage->ready); + if (status != 0) + err_abort(status, "Wake next stage"); + } + /* + * Notice that the routine never unlocks the stage->mutex. + * The call to pthread_cond_wait implicitly unlocks the + * mutex while the thread is waiting, allowing other threads + * to make progress. Because the loop never terminates, this + * function has no need to unlock the mutex explicitly. + */ } /* @@ -116,61 +118,59 @@ void *pipe_stage (void *arg) * data is initialized and the threads created. They'll * wait for data. */ -int pipe_create (pipe_t *pipe, int stages) +int +pipe_create(pipe_t* pipe, int stages) { - int pipe_index; - stage_t **link = &pipe->head, *new_stage, *stage; - int status; + int pipe_index; + stage_t **link = &pipe->head, *new_stage, *stage; + int status; - status = pthread_mutex_init (&pipe->mutex, NULL); + status = pthread_mutex_init(&pipe->mutex, NULL); + if (status != 0) + err_abort(status, "Init pipe mutex"); + pipe->stages = stages; + pipe->active = 0; + + for (pipe_index = 0; pipe_index <= stages; pipe_index++) { + new_stage = (stage_t*) malloc(sizeof(stage_t)); + if (new_stage == NULL) + errno_abort("Allocate stage"); + status = pthread_mutex_init(&new_stage->mutex, NULL); if (status != 0) - err_abort (status, "Init pipe mutex"); - pipe->stages = stages; - pipe->active = 0; + err_abort(status, "Init stage mutex"); + status = pthread_cond_init(&new_stage->avail, NULL); + if (status != 0) + err_abort(status, "Init avail condition"); + status = pthread_cond_init(&new_stage->ready, NULL); + if (status != 0) + err_abort(status, "Init ready condition"); + new_stage->data_ready = 0; + *link = new_stage; + link = &new_stage->next; + } - for (pipe_index = 0; pipe_index <= stages; pipe_index++) { - new_stage = (stage_t*)malloc (sizeof (stage_t)); - if (new_stage == NULL) - errno_abort ("Allocate stage"); - status = pthread_mutex_init (&new_stage->mutex, NULL); - if (status != 0) - err_abort (status, "Init stage mutex"); - status = pthread_cond_init (&new_stage->avail, NULL); - if (status != 0) - err_abort (status, "Init avail condition"); - status = pthread_cond_init (&new_stage->ready, NULL); - if (status != 0) - err_abort (status, "Init ready condition"); - new_stage->data_ready = 0; - *link = new_stage; - link = &new_stage->next; - } + *link = (stage_t*) NULL; /* Terminate list */ + pipe->tail = new_stage; /* Record the tail */ - *link = (stage_t*)NULL; /* Terminate list */ - pipe->tail = new_stage; /* Record the tail */ - - /* - * Create the threads for the pipe stages only after all - * the data is initialized (including all links). Note - * that the last stage doesn't get a thread, it's just - * a receptacle for the final pipeline value. - * - * At this point, proper cleanup on an error would take up - * more space than worthwhile in a "simple example", so - * instead of cancelling and detaching all the threads - * already created, plus the synchronization object and - * memory cleanup done for earlier errors, it will simply - * abort. - */ - for ( stage = pipe->head; - stage->next != NULL; - stage = stage->next) { - status = pthread_create ( - &stage->thread, NULL, pipe_stage, (void*)stage); - if (status != 0) - err_abort (status, "Create pipe stage"); - } - return 0; + /* + * Create the threads for the pipe stages only after all + * the data is initialized (including all links). Note + * that the last stage doesn't get a thread, it's just + * a receptacle for the final pipeline value. + * + * At this point, proper cleanup on an error would take up + * more space than worthwhile in a "simple example", so + * instead of cancelling and detaching all the threads + * already created, plus the synchronization object and + * memory cleanup done for earlier errors, it will simply + * abort. + */ + for (stage = pipe->head; stage->next != NULL; stage = stage->next) { + status = pthread_create(&stage->thread, NULL, pipe_stage, (void*) stage); + if (status != 0) + err_abort(status, "Create pipe stage"); + } + return 0; } /* @@ -181,83 +181,88 @@ int pipe_create (pipe_t *pipe, int stages) * (note that the pipe will stall when each stage fills, * until the result is collected). */ -int pipe_start (pipe_t *pipe, long value) +int +pipe_start(pipe_t* pipe, long value) { - int status; + int status; - status = pthread_mutex_lock (&pipe->mutex); - if (status != 0) - err_abort (status, "Lock pipe mutex"); - pipe->active++; - status = pthread_mutex_unlock (&pipe->mutex); - if (status != 0) - err_abort (status, "Unlock pipe mutex"); - pipe_send (pipe->head, value); - return 0; + status = pthread_mutex_lock(&pipe->mutex); + if (status != 0) + err_abort(status, "Lock pipe mutex"); + pipe->active++; + status = pthread_mutex_unlock(&pipe->mutex); + if (status != 0) + err_abort(status, "Unlock pipe mutex"); + pipe_send(pipe->head, value); + return 0; } /* * Collect the result of the pipeline. Wait for a * result if the pipeline hasn't produced one. */ -int pipe_result (pipe_t *pipe, long *result) +int +pipe_result(pipe_t* pipe, long* result) { - stage_t *tail = pipe->tail; - long value; - int empty = 0; - int status; + stage_t* tail = pipe->tail; + long value; + int empty = 0; + int status; - status = pthread_mutex_lock (&pipe->mutex); - if (status != 0) - err_abort (status, "Lock pipe mutex"); - if (pipe->active <= 0) - empty = 1; - else - pipe->active--; + status = pthread_mutex_lock(&pipe->mutex); + if (status != 0) + err_abort(status, "Lock pipe mutex"); + if (pipe->active <= 0) + empty = 1; + else + pipe->active--; - status = pthread_mutex_unlock (&pipe->mutex); - if (status != 0) - err_abort (status, "Unlock pipe mutex"); - if (empty) - return 0; + status = pthread_mutex_unlock(&pipe->mutex); + if (status != 0) + err_abort(status, "Unlock pipe mutex"); + if (empty) + return 0; - pthread_mutex_lock (&tail->mutex); - while (!tail->data_ready) - pthread_cond_wait (&tail->avail, &tail->mutex); - *result = tail->data; - tail->data_ready = 0; - pthread_cond_signal (&tail->ready); - pthread_mutex_unlock (&tail->mutex); - return 1; + pthread_mutex_lock(&tail->mutex); + while (!tail->data_ready) pthread_cond_wait(&tail->avail, &tail->mutex); + *result = tail->data; + tail->data_ready = 0; + pthread_cond_signal(&tail->ready); + pthread_mutex_unlock(&tail->mutex); + return 1; } /* * The main program to "drive" the pipeline... */ -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pipe_t my_pipe; - long value, result; - int status; - char line[128]; + pipe_t my_pipe; + long value, result; + int status; + char line[128]; - pipe_create (&my_pipe, 10); - printf ("Enter integer values, or \"=\" for next result\n"); + pipe_create(&my_pipe, 10); + printf("Enter integer values, or \"=\" for next result\n"); - while (1) { - printf ("Data> "); - if (fgets (line, sizeof (line), stdin) == NULL) exit (0); - if (strlen (line) <= 1) continue; - if (strlen (line) <= 2 && line[0] == '=') { - if (pipe_result (&my_pipe, &result)) - printf ("Result is %ld\n", result); - else - printf ("Pipe is empty\n"); - } else { - if (sscanf (line, "%ld", &value) < 1) - fprintf (stderr, "Enter an integer value\n"); - else - pipe_start (&my_pipe, value); - } + while (1) { + printf("Data> "); + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); + if (strlen(line) <= 1) + continue; + if (strlen(line) <= 2 && line[0] == '=') { + if (pipe_result(&my_pipe, &result)) + printf("Result is %ld\n", result); + else + printf("Pipe is empty\n"); } + else { + if (sscanf(line, "%ld", &value) < 1) + fprintf(stderr, "Enter an integer value\n"); + else + pipe_start(&my_pipe, value); + } + } } diff --git a/src/ch04/pipe_cpp.cpp b/src/ch04/pipe_cpp.cpp index 338b445..d482c4b 100644 --- a/src/ch04/pipe_cpp.cpp +++ b/src/ch04/pipe_cpp.cpp @@ -26,7 +26,7 @@ struct stage_tag { bool isDataAvail; /* Data present */ long data; /* Data to process */ pthread_t thread; /* Thread for stage */ - stage_tag *next; + stage_tag* next; }; using stage_t = stage_tag; @@ -50,11 +50,14 @@ using pipe_t = pipe_tag; * specified pipe stage. Threads use this to pass * along the modified data item. */ -int pipe_send(stage_t &stage, long data) { +int +pipe_send(stage_t& stage, long data) +{ int status; status = pthread_mutex_lock(&stage.mutex); - if (status != 0) return status; + if (status != 0) + return status; /* * If there's data in the pipe stage, wait for it @@ -71,7 +74,7 @@ int pipe_send(stage_t &stage, long data) { /* * Send the new data */ - stage.data = data; + stage.data = data; stage.isDataAvail = true; status = pthread_cond_signal(&stage.dataIsAvail); @@ -90,18 +93,22 @@ int pipe_send(stage_t &stage, long data) { * caller or the previous stage, modify the data * and pass it along to the next (or final) stage. */ -void *pipe_stage(void *arg) { - stage_t &stage = *(stage_t *)arg; - stage_t &nextStage = *stage.next; +void* +pipe_stage(void* arg) +{ + stage_t& stage = *(stage_t*) arg; + stage_t& nextStage = *stage.next; int status; status = pthread_mutex_lock(&stage.mutex); - if (status != 0) err_abort(status, "Lock pipe stage"); + if (status != 0) + err_abort(status, "Lock pipe stage"); while (1) { while (!stage.isDataAvail) { status = pthread_cond_wait(&stage.dataIsAvail, &stage.mutex); - if (status != 0) err_abort(status, "Wait for previous stage"); + if (status != 0) + err_abort(status, "Wait for previous stage"); } pipe_send(nextStage, stage.data + 1); @@ -109,7 +116,8 @@ void *pipe_stage(void *arg) { stage.isDataAvail = false; status = pthread_cond_signal(&stage.threadIsIdle); - if (status != 0) err_abort(status, "Wake next stage"); + if (status != 0) + err_abort(status, "Wake next stage"); } /* @@ -126,20 +134,26 @@ void *pipe_stage(void *arg) { * data is initialized and the threads created. They'll * wait for data. */ -int pipe_create(pipe_t &pipe, size_t nStages) { +int +pipe_create(pipe_t& pipe, size_t nStages) +{ int status = pthread_mutex_init(&pipe.mutex, NULL); - if (status != 0) err_abort(status, "Init pipe mutex"); + if (status != 0) + err_abort(status, "Init pipe mutex"); pipe.stageList.resize(nStages); pipe.nActive = 0; - for (auto &iStage : pipe.stageList) { + for (auto& iStage : pipe.stageList) { status = pthread_mutex_init(&iStage.mutex, NULL); - if (status != 0) err_abort(status, "Init stage mutex"); + if (status != 0) + err_abort(status, "Init stage mutex"); status = pthread_cond_init(&iStage.dataIsAvail, NULL); - if (status != 0) err_abort(status, "Init dataIsAvail condition"); + if (status != 0) + err_abort(status, "Init dataIsAvail condition"); status = pthread_cond_init(&iStage.threadIsIdle, NULL); - if (status != 0) err_abort(status, "Init threadIsIdle condition"); + if (status != 0) + err_abort(status, "Init threadIsIdle condition"); iStage.isDataAvail = false; } @@ -158,11 +172,12 @@ int pipe_create(pipe_t &pipe, size_t nStages) { */ for (auto it = pipe.stageList.begin(), ite = --pipe.stageList.end(); it != ite;) { - auto iit = it++; + auto iit = it++; iit->next = &(*it); - status = pthread_create(&iit->thread, NULL, pipe_stage, (void *)&*iit); - if (status != 0) err_abort(status, "Create pipe stage"); + status = pthread_create(&iit->thread, NULL, pipe_stage, (void*) &*iit); + if (status != 0) + err_abort(status, "Create pipe stage"); } return 0; } @@ -171,11 +186,14 @@ int pipe_create(pipe_t &pipe, size_t nStages) { * Collect the result of the pipeline. Wait for a * result if the pipeline hasn't produced one. */ -int pipe_result(pipe_t &pipe) { +int +pipe_result(pipe_t& pipe) +{ int status; status = pthread_mutex_lock(&pipe.mutex); - if (status != 0) err_abort(status, "Lock pipe mutex"); + if (status != 0) + err_abort(status, "Lock pipe mutex"); bool isEmpty = false; if (pipe.nActive <= 0) @@ -184,30 +202,34 @@ int pipe_result(pipe_t &pipe) { pipe.nActive--; status = pthread_mutex_unlock(&pipe.mutex); - if (status != 0) err_abort(status, "Unlock pipe mutex"); + if (status != 0) + err_abort(status, "Unlock pipe mutex"); if (isEmpty) { printf("Pipe is empty\n"); return 0; } - auto &tail = pipe.stageList.back(); + auto& tail = pipe.stageList.back(); status = pthread_mutex_lock(&tail.mutex); - if (status != 0) err_abort(status, "Lock pipe tail mutex"); + if (status != 0) + err_abort(status, "Lock pipe tail mutex"); while (!tail.isDataAvail) { pthread_cond_wait(&tail.dataIsAvail, &tail.mutex); } - long result = tail.data; + long result = tail.data; tail.isDataAvail = false; status = pthread_cond_signal(&tail.threadIsIdle); - if (status != 0) err_abort(status, "Signal pipe tail threadIsIdle"); + if (status != 0) + err_abort(status, "Signal pipe tail threadIsIdle"); status = pthread_mutex_unlock(&tail.mutex); - if (status != 0) err_abort(status, "Unlock pipe tail mutex"); + if (status != 0) + err_abort(status, "Unlock pipe tail mutex"); printf("Result is %ld\n", result); @@ -222,9 +244,12 @@ int pipe_result(pipe_t &pipe) { * (note that the pipe will stall when each stage fills, * until the result is collected). */ -void pipe_start(pipe_t &pipe, long value) { +void +pipe_start(pipe_t& pipe, long value) +{ int status = pthread_mutex_lock(&pipe.mutex); - if (status != 0) err_abort(status, "Lock pipe mutex"); + if (status != 0) + err_abort(status, "Lock pipe mutex"); if (pipe.nActive > pipe.stageList.size() - 1) { status = pthread_mutex_unlock(&pipe.mutex); @@ -235,7 +260,8 @@ void pipe_start(pipe_t &pipe, long value) { pipe.nActive++; status = pthread_mutex_unlock(&pipe.mutex); - if (status != 0) err_abort(status, "Unlock pipe mutex"); + if (status != 0) + err_abort(status, "Unlock pipe mutex"); pipe_send(pipe.stageList.front(), value); } @@ -243,7 +269,9 @@ void pipe_start(pipe_t &pipe, long value) { /* * The main program to "drive" the pipeline... */ -int main(int argc, char *argv[]) { +int +main(int argc, char* argv[]) +{ pipe_t my_pipe; pipe_create(my_pipe, 2); @@ -252,12 +280,15 @@ int main(int argc, char *argv[]) { char line[128]; while (1) { printf("Data> "); - if (fgets(line, sizeof(line), stdin) == NULL) exit(0); + if (fgets(line, sizeof(line), stdin) == NULL) + exit(0); printf(line); - if (strlen(line) <= 1) continue; + if (strlen(line) <= 1) + continue; if (strlen(line) <= 2 && line[0] == '=') { pipe_result(my_pipe); - } else { + } + else { long value; if (sscanf(line, "%ld", &value) < 1) fprintf(stderr, "Enter an integer value\n"); diff --git a/src/ch04/server.c b/src/ch04/server.c index 9f54685..65d492c 100644 --- a/src/ch04/server.c +++ b/src/ch04/server.c @@ -7,43 +7,42 @@ * to allow interleaved thread execution, since threads are not * timesliced. */ -#include #include +#include #include "errors.h" -#define CLIENT_THREADS 4 /* Number of clients */ +#define CLIENT_THREADS 4 /* Number of clients */ -#define REQ_READ 1 /* Read with prompt */ -#define REQ_WRITE 2 /* Write */ -#define REQ_QUIT 3 /* Quit server */ +#define REQ_READ 1 /* Read with prompt */ +#define REQ_WRITE 2 /* Write */ +#define REQ_QUIT 3 /* Quit server */ /* * Internal to server "package" -- one for each request. */ typedef struct request_tag { - struct request_tag *next; /* Link to next */ - int operation; /* Function code */ - int synchronous; /* Non-zero if synchronous */ - int done_flag; /* Predicate for wait */ - pthread_cond_t done; /* Wait for completion */ - char prompt[32]; /* Prompt string for reads */ - char text[128]; /* Read/write text */ + struct request_tag* next; /* Link to next */ + int operation; /* Function code */ + int synchronous; /* Non-zero if synchronous */ + int done_flag; /* Predicate for wait */ + pthread_cond_t done; /* Wait for completion */ + char prompt[32]; /* Prompt string for reads */ + char text[128]; /* Read/write text */ } request_t; /* * Static context for the server */ typedef struct tty_server_tag { - request_t *first; - request_t *last; - int running; - pthread_mutex_t mutex; - pthread_cond_t request; + request_t* first; + request_t* last; + int running; + pthread_mutex_t mutex; + pthread_cond_t request; } tty_server_t; tty_server_t tty_server = { - NULL, NULL, 0, - PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER}; + NULL, NULL, 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER}; /* * Main program data @@ -51,7 +50,7 @@ tty_server_t tty_server = { int client_threads; pthread_mutex_t client_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t clients_done = PTHREAD_COND_INITIALIZER; +pthread_cond_t clients_done = PTHREAD_COND_INITIALIZER; /* * The server start routine. It waits for a request to appear @@ -62,267 +61,264 @@ pthread_cond_t clients_done = PTHREAD_COND_INITIALIZER; * responsible for freeing the request. If the request was not * synchronous, the server will free the request on completion. */ -void *tty_server_routine (void *arg) +void* +tty_server_routine(void* arg) { - static pthread_mutex_t prompt_mutex = PTHREAD_MUTEX_INITIALIZER; - request_t *request; - int operation, len; - int status; + static pthread_mutex_t prompt_mutex = PTHREAD_MUTEX_INITIALIZER; + request_t* request; + int operation, len; + int status; - while (1) { - status = pthread_mutex_lock (&tty_server.mutex); - if (status != 0) - err_abort (status, "Lock server mutex"); + while (1) { + status = pthread_mutex_lock(&tty_server.mutex); + if (status != 0) + err_abort(status, "Lock server mutex"); - /* - * Wait for data - */ - while (tty_server.first == NULL) { - status = pthread_cond_wait ( - &tty_server.request, &tty_server.mutex); - if (status != 0) - err_abort (status, "Wait for request"); - } - request = tty_server.first; - tty_server.first = request->next; - if (tty_server.first == NULL) - tty_server.last = NULL; - status = pthread_mutex_unlock (&tty_server.mutex); - if (status != 0) - err_abort (status, "Unlock server mutex"); - - /* - * Process the data - */ - operation = request->operation; - switch (operation) { - case REQ_QUIT: - break; - case REQ_READ: - if (strlen (request->prompt) > 0) - printf (request->prompt); - if (fgets (request->text, 128, stdin) == NULL) - request->text[0] = '\0'; - /* - * Because fgets returns the newline, and we don't want it, - * we look for it, and turn it into a null (truncating the - * input) if found. It should be the last character, if it is - * there. - */ - len = strlen (request->text); - if (len > 0 && request->text[len-1] == '\n') - request->text[len-1] = '\0'; - break; - case REQ_WRITE: - puts (request->text); - break; - default: - break; - } - if (request->synchronous) { - status = pthread_mutex_lock (&tty_server.mutex); - if (status != 0) - err_abort (status, "Lock server mutex"); - request->done_flag = 1; - status = pthread_cond_signal (&request->done); - if (status != 0) - err_abort (status, "Signal server condition"); - status = pthread_mutex_unlock (&tty_server.mutex); - if (status != 0) - err_abort (status, "Unlock server mutex"); - } else - free (request); - if (operation == REQ_QUIT) - break; + /* + * Wait for data + */ + while (tty_server.first == NULL) { + status = pthread_cond_wait(&tty_server.request, &tty_server.mutex); + if (status != 0) + err_abort(status, "Wait for request"); } - return NULL; + request = tty_server.first; + tty_server.first = request->next; + if (tty_server.first == NULL) + tty_server.last = NULL; + status = pthread_mutex_unlock(&tty_server.mutex); + if (status != 0) + err_abort(status, "Unlock server mutex"); + + /* + * Process the data + */ + operation = request->operation; + switch (operation) { + case REQ_QUIT: + break; + case REQ_READ: + if (strlen(request->prompt) > 0) + printf(request->prompt); + if (fgets(request->text, 128, stdin) == NULL) + request->text[0] = '\0'; + /* + * Because fgets returns the newline, and we don't want it, + * we look for it, and turn it into a null (truncating the + * input) if found. It should be the last character, if it is + * there. + */ + len = strlen(request->text); + if (len > 0 && request->text[len - 1] == '\n') + request->text[len - 1] = '\0'; + break; + case REQ_WRITE: + puts(request->text); + break; + default: + break; + } + if (request->synchronous) { + status = pthread_mutex_lock(&tty_server.mutex); + if (status != 0) + err_abort(status, "Lock server mutex"); + request->done_flag = 1; + status = pthread_cond_signal(&request->done); + if (status != 0) + err_abort(status, "Signal server condition"); + status = pthread_mutex_unlock(&tty_server.mutex); + if (status != 0) + err_abort(status, "Unlock server mutex"); + } + else + free(request); + if (operation == REQ_QUIT) + break; + } + return NULL; } /* * Request an operation */ -void tty_server_request ( - int operation, - int sync, - const char *prompt, - char *string) +void +tty_server_request(int operation, int sync, const char* prompt, char* string) { - request_t *request; - int status; + request_t* request; + int status; - status = pthread_mutex_lock (&tty_server.mutex); + status = pthread_mutex_lock(&tty_server.mutex); + if (status != 0) + err_abort(status, "Lock server mutex"); + if (!tty_server.running) { + pthread_t thread; + pthread_attr_t detached_attr; + + status = pthread_attr_init(&detached_attr); if (status != 0) - err_abort (status, "Lock server mutex"); - if (!tty_server.running) { - pthread_t thread; - pthread_attr_t detached_attr; - - status = pthread_attr_init (&detached_attr); - if (status != 0) - err_abort (status, "Init attributes object"); - status = pthread_attr_setdetachstate ( - &detached_attr, PTHREAD_CREATE_DETACHED); - if (status != 0) - err_abort (status, "Set detach state"); - tty_server.running = 1; - status = pthread_create (&thread, &detached_attr, - tty_server_routine, NULL); - if (status != 0) - err_abort (status, "Create server"); - - /* - * Ignore an error in destroying the attributes object. - * It's unlikely to fail, there's nothing useful we can - * do about it, and it's not worth aborting the program - * over it. - */ - pthread_attr_destroy (&detached_attr); - } - - /* - * Create and initialize a request structure. - */ - request = (request_t*)malloc (sizeof (request_t)); - if (request == NULL) - errno_abort ("Allocate request"); - request->next = NULL; - request->operation = operation; - request->synchronous = sync; - if (sync) { - request->done_flag = 0; - status = pthread_cond_init (&request->done, NULL); - if (status != 0) - err_abort (status, "Init request condition"); - } - if (prompt != NULL) - strncpy (request->prompt, prompt, 32); - else - request->prompt[0] = '\0'; - if (operation == REQ_WRITE && string != NULL) - strncpy (request->text, string, 128); - else - request->text[0] = '\0'; - - /* - * Add the request to the queue, maintaining the first and - * last pointers. - */ - if (tty_server.first == NULL) { - tty_server.first = request; - tty_server.last = request; - } else { - (tty_server.last)->next = request; - tty_server.last = request; - } - - /* - * Tell the server that a request is available. - */ - status = pthread_cond_signal (&tty_server.request); + err_abort(status, "Init attributes object"); + status = + pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED); if (status != 0) - err_abort (status, "Wake server"); + err_abort(status, "Set detach state"); + tty_server.running = 1; + status = pthread_create(&thread, &detached_attr, tty_server_routine, NULL); + if (status != 0) + err_abort(status, "Create server"); /* - * If the request was "synchronous", then wait for a reply. + * Ignore an error in destroying the attributes object. + * It's unlikely to fail, there's nothing useful we can + * do about it, and it's not worth aborting the program + * over it. */ - if (sync) { - while (!request->done_flag) { - status = pthread_cond_wait ( - &request->done, &tty_server.mutex); - if (status != 0) - err_abort (status, "Wait for sync request"); - } - if (operation == REQ_READ) { - if (strlen (request->text) > 0) - strcpy (string, request->text); - else - string[0] = '\0'; - } - status = pthread_cond_destroy (&request->done); - if (status != 0) - err_abort (status, "Destroy request condition"); - free (request); - } - status = pthread_mutex_unlock (&tty_server.mutex); + pthread_attr_destroy(&detached_attr); + } + + /* + * Create and initialize a request structure. + */ + request = (request_t*) malloc(sizeof(request_t)); + if (request == NULL) + errno_abort("Allocate request"); + request->next = NULL; + request->operation = operation; + request->synchronous = sync; + if (sync) { + request->done_flag = 0; + status = pthread_cond_init(&request->done, NULL); if (status != 0) - err_abort (status, "Unlock mutex"); + err_abort(status, "Init request condition"); + } + if (prompt != NULL) + strncpy(request->prompt, prompt, 32); + else + request->prompt[0] = '\0'; + if (operation == REQ_WRITE && string != NULL) + strncpy(request->text, string, 128); + else + request->text[0] = '\0'; + + /* + * Add the request to the queue, maintaining the first and + * last pointers. + */ + if (tty_server.first == NULL) { + tty_server.first = request; + tty_server.last = request; + } + else { + (tty_server.last)->next = request; + tty_server.last = request; + } + + /* + * Tell the server that a request is available. + */ + status = pthread_cond_signal(&tty_server.request); + if (status != 0) + err_abort(status, "Wake server"); + + /* + * If the request was "synchronous", then wait for a reply. + */ + if (sync) { + while (!request->done_flag) { + status = pthread_cond_wait(&request->done, &tty_server.mutex); + if (status != 0) + err_abort(status, "Wait for sync request"); + } + if (operation == REQ_READ) { + if (strlen(request->text) > 0) + strcpy(string, request->text); + else + string[0] = '\0'; + } + status = pthread_cond_destroy(&request->done); + if (status != 0) + err_abort(status, "Destroy request condition"); + free(request); + } + status = pthread_mutex_unlock(&tty_server.mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); } /* * Client routine -- multiple copies will request server. */ -void *client_routine (void *arg) +void* +client_routine(void* arg) { - int my_number = (int)arg, loops; - char prompt[32]; - char string[128], formatted[128]; - int status; + int my_number = (int) arg, loops; + char prompt[32]; + char string[128], formatted[128]; + int status; - sprintf (prompt, "Client %d> ", my_number); - while (1) { - tty_server_request (REQ_READ, 1, prompt, string); - if (strlen (string) == 0) - break; - for (loops = 0; loops < 4; loops++) { - sprintf ( - formatted, "(%d#%d) %s", my_number, loops, string); - tty_server_request (REQ_WRITE, 0, NULL, formatted); - sleep (1); - } + sprintf(prompt, "Client %d> ", my_number); + while (1) { + tty_server_request(REQ_READ, 1, prompt, string); + if (strlen(string) == 0) + break; + for (loops = 0; loops < 4; loops++) { + sprintf(formatted, "(%d#%d) %s", my_number, loops, string); + tty_server_request(REQ_WRITE, 0, NULL, formatted); + sleep(1); } - status = pthread_mutex_lock (&client_mutex); + } + status = pthread_mutex_lock(&client_mutex); + if (status != 0) + err_abort(status, "Lock client mutex"); + client_threads--; + if (client_threads <= 0) { + status = pthread_cond_signal(&clients_done); if (status != 0) - err_abort (status, "Lock client mutex"); - client_threads--; - if (client_threads <= 0) { - status = pthread_cond_signal (&clients_done); - if (status != 0) - err_abort (status, "Signal clients done"); - } - status = pthread_mutex_unlock (&client_mutex); - if (status != 0) - err_abort (status, "Unlock client mutex"); - return NULL; + err_abort(status, "Signal clients done"); + } + status = pthread_mutex_unlock(&client_mutex); + if (status != 0) + err_abort(status, "Unlock client mutex"); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread; - int count; - int status; + pthread_t thread; + int count; + int status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our threads can run concurrently, we need to - * increase the concurrency level to CLIENT_THREADS. - */ - DPRINTF (("Setting concurrency level to %d\n", CLIENT_THREADS)); - thr_setconcurrency (CLIENT_THREADS); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level to CLIENT_THREADS. + */ + DPRINTF(("Setting concurrency level to %d\n", CLIENT_THREADS)); + thr_setconcurrency(CLIENT_THREADS); #endif - /* - * Create CLIENT_THREADS clients. - */ - client_threads = CLIENT_THREADS; - for (count = 0; count < client_threads; count++) { - status = pthread_create (&thread, NULL, - client_routine, (void*)count); - if (status != 0) - err_abort (status, "Create client thread"); - } - status = pthread_mutex_lock (&client_mutex); + /* + * Create CLIENT_THREADS clients. + */ + client_threads = CLIENT_THREADS; + for (count = 0; count < client_threads; count++) { + status = pthread_create(&thread, NULL, client_routine, (void*) count); if (status != 0) - err_abort (status, "Lock client mutex"); - while (client_threads > 0) { - status = pthread_cond_wait (&clients_done, &client_mutex); - if (status != 0) - err_abort (status, "Wait for clients to finish"); - } - status = pthread_mutex_unlock (&client_mutex); + err_abort(status, "Create client thread"); + } + status = pthread_mutex_lock(&client_mutex); + if (status != 0) + err_abort(status, "Lock client mutex"); + while (client_threads > 0) { + status = pthread_cond_wait(&clients_done, &client_mutex); if (status != 0) - err_abort (status, "Unlock client mutex"); - printf ("All clients done\n"); - tty_server_request (REQ_QUIT, 1, NULL, NULL); - return 0; + err_abort(status, "Wait for clients to finish"); + } + status = pthread_mutex_unlock(&client_mutex); + if (status != 0) + err_abort(status, "Unlock client mutex"); + printf("All clients done\n"); + tty_server_request(REQ_QUIT, 1, NULL, NULL); + return 0; } diff --git a/src/ch05/cancel.c b/src/ch05/cancel.c index 8e07090..25cd867 100644 --- a/src/ch05/cancel.c +++ b/src/ch05/cancel.c @@ -18,49 +18,50 @@ static int counter; * when it calls pthread_testcancel, which it does each 1000 * iterations. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - DPRINTF (("thread_routine starting\n")); - for (counter = 0; ; counter++) - if ((counter % 1000) == 0) { - DPRINTF (("calling testcancel\n")); - pthread_testcancel (); - } + DPRINTF(("thread_routine starting\n")); + for (counter = 0;; counter++) + if ((counter % 1000) == 0) { + DPRINTF(("calling testcancel\n")); + pthread_testcancel(); + } } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - void *result; - int status; + pthread_t thread_id; + void* result; + int status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our two threads can run concurrently, we need to - * increase the concurrency level to 2. - */ - DPRINTF (("Setting concurrency level to 2\n")); - thr_setconcurrency (2); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our two threads can run concurrently, we need to + * increase the concurrency level to 2. + */ + DPRINTF(("Setting concurrency level to 2\n")); + thr_setconcurrency(2); #endif - status = pthread_create ( - &thread_id, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - sleep (2); + status = pthread_create(&thread_id, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + sleep(2); - DPRINTF (("calling cancel\n")); - status = pthread_cancel (thread_id); - if (status != 0) - err_abort (status, "Cancel thread"); + DPRINTF(("calling cancel\n")); + status = pthread_cancel(thread_id); + if (status != 0) + err_abort(status, "Cancel thread"); - DPRINTF (("calling join\n")); - status = pthread_join (thread_id, &result); - if (status != 0) - err_abort (status, "Join thread"); - if (result == PTHREAD_CANCELED) - printf ("Thread cancelled at iteration %d\n", counter); - else - printf ("Thread was not cancelled\n"); - return 0; + DPRINTF(("calling join\n")); + status = pthread_join(thread_id, &result); + if (status != 0) + err_abort(status, "Join thread"); + if (result == PTHREAD_CANCELED) + printf("Thread cancelled at iteration %d\n", counter); + else + printf("Thread was not cancelled\n"); + return 0; } diff --git a/src/ch05/cancel_async.c b/src/ch05/cancel_async.c index a808ea5..846333a 100644 --- a/src/ch05/cancel_async.c +++ b/src/ch05/cancel_async.c @@ -11,30 +11,30 @@ #include #include "errors.h" -#define SIZE 10 /* array size */ +#define SIZE 10 /* array size */ static int matrixa[SIZE][SIZE]; static int matrixb[SIZE][SIZE]; static int matrixc[SIZE][SIZE]; #ifdef DEBUG -void print_array (int matrix[SIZE][SIZE]) +void +print_array(int matrix[SIZE][SIZE]) { - int i, j; - int first; + int i, j; + int first; - for (i = 0; i < SIZE; i++) { - printf ("["); - first = 1; - for (j = 0; j < SIZE; j++) { - if (!first) - printf (","); - printf ("%x", matrix[i][j]); - first = 0; - } - printf ("]\n"); + for (i = 0; i < SIZE; i++) { + printf("["); + first = 1; + for (j = 0; j < SIZE; j++) { + if (!first) + printf(","); + printf("%x", matrix[i][j]); + first = 0; } - + printf("]\n"); + } } #endif @@ -44,87 +44,83 @@ void print_array (int matrix[SIZE][SIZE]) * is enabled. The loop multiplies the two matrices matrixa * and matrixb. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - int cancel_type, status; - int i, j, k, value = 1; - + int cancel_type, status; + int i, j, k, value = 1; + + /* + * Initialize the matrices to something arbitrary. + */ + for (i = 0; i < SIZE; i++) + for (j = 0; j < SIZE; j++) { + matrixa[i][j] = i; + matrixb[i][j] = j; + } + + while (1) { /* - * Initialize the matrices to something arbitrary. + * Compute the matrix product of matrixa and matrixb. + */ + status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &cancel_type); + if (status != 0) + err_abort(status, "Set cancel type"); + for (i = 0; i < SIZE; i++) + for (j = 0; j < SIZE; j++) { + matrixc[i][j] = 0; + for (k = 0; k < SIZE; k++) + matrixc[i][j] += matrixa[i][k] * matrixb[k][j]; + } + status = pthread_setcanceltype(cancel_type, &cancel_type); + if (status != 0) + err_abort(status, "Set cancel type"); + + /* + * Copy the result (matrixc) into matrixa to start again */ for (i = 0; i < SIZE; i++) - for (j = 0; j < SIZE; j++) { - matrixa[i][j] = i; - matrixb[i][j] = j; - } - - while (1) { - /* - * Compute the matrix product of matrixa and matrixb. - */ - status = pthread_setcanceltype ( - PTHREAD_CANCEL_ASYNCHRONOUS, - &cancel_type); - if (status != 0) - err_abort (status, "Set cancel type"); - for (i = 0; i < SIZE; i++) - for (j = 0; j < SIZE; j++) { - matrixc[i][j] = 0; - for (k = 0; k < SIZE; k++) - matrixc[i][j] += matrixa[i][k] * matrixb[k][j]; - } - status = pthread_setcanceltype ( - cancel_type, - &cancel_type); - if (status != 0) - err_abort (status, "Set cancel type"); - - /* - * Copy the result (matrixc) into matrixa to start again - */ - for (i = 0; i < SIZE; i++) - for (j = 0; j < SIZE; j++) - matrixa[i][j] = matrixc[i][j]; - } + for (j = 0; j < SIZE; j++) matrixa[i][j] = matrixc[i][j]; + } } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - void *result; - int status; + pthread_t thread_id; + void* result; + int status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our two threads can run concurrently, we need to - * increase the concurrency level to 2. - */ - DPRINTF (("Setting concurrency level to 2\n")); - thr_setconcurrency (2); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our two threads can run concurrently, we need to + * increase the concurrency level to 2. + */ + DPRINTF(("Setting concurrency level to 2\n")); + thr_setconcurrency(2); #endif - status = pthread_create ( - &thread_id, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - sleep (1); - status = pthread_cancel (thread_id); - if (status != 0) - err_abort (status, "Cancel thread"); - status = pthread_join (thread_id, &result); - if (status != 0) - err_abort (status, "Join thread"); - if (result == PTHREAD_CANCELED) - printf ("Thread cancelled\n"); - else - printf ("Thread was not cancelled\n"); + status = pthread_create(&thread_id, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + sleep(1); + status = pthread_cancel(thread_id); + if (status != 0) + err_abort(status, "Cancel thread"); + status = pthread_join(thread_id, &result); + if (status != 0) + err_abort(status, "Join thread"); + if (result == PTHREAD_CANCELED) + printf("Thread cancelled\n"); + else + printf("Thread was not cancelled\n"); #ifdef DEBUG - printf ("Matrix a:\n"); - print_array (matrixa); - printf ("\nMatrix b:\n"); - print_array (matrixb); - printf ("\nMatrix c:\n"); - print_array (matrixc); + printf("Matrix a:\n"); + print_array(matrixa); + printf("\nMatrix b:\n"); + print_array(matrixb); + printf("\nMatrix c:\n"); + print_array(matrixc); #endif - return 0; + return 0; } diff --git a/src/ch05/cancel_cleanup.c b/src/ch05/cancel_cleanup.c index b7c6220..d970532 100644 --- a/src/ch05/cancel_cleanup.c +++ b/src/ch05/cancel_cleanup.c @@ -14,29 +14,29 @@ * the synchronization and invariant data. */ typedef struct control_tag { - int counter, busy; - pthread_mutex_t mutex; - pthread_cond_t cv; + int counter, busy; + pthread_mutex_t mutex; + pthread_cond_t cv; } control_t; -control_t control = - {0, 1, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER}; +control_t control = {0, 1, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER}; /* * This routine is installed as the cancellation cleanup * handler around the cancellable condition wait. It will * be called by the system when the thread is cancelled. */ -void cleanup_handler (void *arg) +void +cleanup_handler(void* arg) { - control_t *st = (control_t *)arg; - int status; + control_t* st = (control_t*) arg; + int status; - st->counter--; - printf ("cleanup_handler: counter == %d\n", st->counter); - status = pthread_mutex_unlock (&st->mutex); - if (status != 0) - err_abort (status, "Unlock in cleanup handler"); + st->counter--; + printf("cleanup_handler: counter == %d\n", st->counter); + status = pthread_mutex_unlock(&st->mutex); + if (status != 0) + err_abort(status, "Unlock in cleanup handler"); } /* @@ -46,55 +46,56 @@ void cleanup_handler (void *arg) * nonzero value to pthread_cleanup_pop to run the same * "finalization" action when cancellation does not occur. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - int status; + int status; - pthread_cleanup_push (cleanup_handler, (void*)&control); + pthread_cleanup_push(cleanup_handler, (void*) &control); - status = pthread_mutex_lock (&control.mutex); + status = pthread_mutex_lock(&control.mutex); + if (status != 0) + err_abort(status, "Mutex lock"); + control.counter++; + + while (control.busy) { + status = pthread_cond_wait(&control.cv, &control.mutex); if (status != 0) - err_abort (status, "Mutex lock"); - control.counter++; + err_abort(status, "Wait on condition"); + } - while (control.busy) { - status = pthread_cond_wait (&control.cv, &control.mutex); - if (status != 0) - err_abort (status, "Wait on condition"); - } - - pthread_cleanup_pop (1); - return NULL; + pthread_cleanup_pop(1); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id[THREADS]; - int count; - void *result; - int status; + pthread_t thread_id[THREADS]; + int count; + void* result; + int status; - for (count = 0; count < THREADS; count++) { - status = pthread_create ( - &thread_id[count], NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - } + for (count = 0; count < THREADS; count++) { + status = pthread_create(&thread_id[count], NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + } - sleep (2); + sleep(2); - for (count = 0; count < THREADS; count++) { - status = pthread_cancel (thread_id[count]); - if (status != 0) - err_abort (status, "Cancel thread"); + for (count = 0; count < THREADS; count++) { + status = pthread_cancel(thread_id[count]); + if (status != 0) + err_abort(status, "Cancel thread"); - status = pthread_join (thread_id[count], &result); - if (status != 0) - err_abort (status, "Join thread"); - if (result == PTHREAD_CANCELED) - printf ("thread %d cancelled\n", count); - else - printf ("thread %d was not cancelled\n", count); - } - return 0; + status = pthread_join(thread_id[count], &result); + if (status != 0) + err_abort(status, "Join thread"); + if (result == PTHREAD_CANCELED) + printf("thread %d cancelled\n", count); + else + printf("thread %d was not cancelled\n", count); + } + return 0; } diff --git a/src/ch05/cancel_disable.c b/src/ch05/cancel_disable.c index 5f473fe..6bf51e9 100644 --- a/src/ch05/cancel_disable.c +++ b/src/ch05/cancel_disable.c @@ -12,57 +12,55 @@ static int counter; /* * Thread start routine. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - int state; - int status; + int state; + int status; - for (counter = 0; ; counter++) { - - /* - * Each 755 iterations, disable cancellation and sleep - * for one second. - * - * Each 1000 iterations, test for a pending cancel by - * calling pthread_testcancel(). - */ - if ((counter % 755) == 0) { - status = pthread_setcancelstate ( - PTHREAD_CANCEL_DISABLE, &state); - if (status != 0) - err_abort (status, "Disable cancel"); - sleep (1); - status = pthread_setcancelstate ( - state, &state); - if (status != 0) - err_abort (status, "Restore cancel"); - } else - if ((counter % 1000) == 0) - pthread_testcancel (); + for (counter = 0;; counter++) { + /* + * Each 755 iterations, disable cancellation and sleep + * for one second. + * + * Each 1000 iterations, test for a pending cancel by + * calling pthread_testcancel(). + */ + if ((counter % 755) == 0) { + status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + if (status != 0) + err_abort(status, "Disable cancel"); + sleep(1); + status = pthread_setcancelstate(state, &state); + if (status != 0) + err_abort(status, "Restore cancel"); } + else if ((counter % 1000) == 0) + pthread_testcancel(); + } } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - void *result; - int status; + pthread_t thread_id; + void* result; + int status; - status = pthread_create ( - &thread_id, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - sleep (2); - status = pthread_cancel (thread_id); - if (status != 0) - err_abort (status, "Cancel thread"); + status = pthread_create(&thread_id, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + sleep(2); + status = pthread_cancel(thread_id); + if (status != 0) + err_abort(status, "Cancel thread"); - status = pthread_join (thread_id, &result); - if (status != 0) - err_abort (status, "Join thread"); - if (result == PTHREAD_CANCELED) - printf ("Thread cancelled at iteration %d\n", counter); - else - printf ("Thread was not cancelled\n"); - return 0; + status = pthread_join(thread_id, &result); + if (status != 0) + err_abort(status, "Join thread"); + if (result == PTHREAD_CANCELED) + printf("Thread cancelled at iteration %d\n", counter); + else + printf("Thread was not cancelled\n"); + return 0; } diff --git a/src/ch05/cancel_subcontract.c b/src/ch05/cancel_subcontract.c index bc3294f..4589d1a 100644 --- a/src/ch05/cancel_subcontract.c +++ b/src/ch05/cancel_subcontract.c @@ -18,42 +18,44 @@ * Structure that defines the threads in a "team". */ typedef struct team_tag { - int join_i; /* join index */ - pthread_t workers[THREADS]; /* thread identifiers */ + int join_i; /* join index */ + pthread_t workers[THREADS]; /* thread identifiers */ } team_t; /* * Start routine for worker threads. They loop waiting for a * cancellation request. */ -void *worker_routine (void *arg) +void* +worker_routine(void* arg) { - int counter; + int counter; - for (counter = 0; ; counter++) - if ((counter % 1000) == 0) - pthread_testcancel (); + for (counter = 0;; counter++) + if ((counter % 1000) == 0) + pthread_testcancel(); } /* * Cancellation cleanup handler for the contractor thread. It * will cancel and detach each worker in the team. */ -void cleanup (void *arg) +void +cleanup(void* arg) { - team_t *team = (team_t *)arg; - int count, status; + team_t* team = (team_t*) arg; + int count, status; - for (count = team->join_i; count < THREADS; count++) { - status = pthread_cancel (team->workers[count]); - if (status != 0) - err_abort (status, "Cancel worker"); + for (count = team->join_i; count < THREADS; count++) { + status = pthread_cancel(team->workers[count]); + if (status != 0) + err_abort(status, "Cancel worker"); - status = pthread_detach (team->workers[count]); - if (status != 0) - err_abort (status, "Detach worker"); - printf ("Cleanup: cancelled %d\n", count); - } + status = pthread_detach(team->workers[count]); + if (status != 0) + err_abort(status, "Detach worker"); + printf("Cleanup: cancelled %d\n", count); + } } /* @@ -61,55 +63,56 @@ void cleanup (void *arg) * worker threads, and then joins with them. When cancelled, the * cleanup handler will cancel and detach the remaining threads. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - team_t team; /* team info */ - int count; - void *result; /* Return status */ - int status; + team_t team; /* team info */ + int count; + void* result; /* Return status */ + int status; - for (count = 0; count < THREADS; count++) { - status = pthread_create ( - &team.workers[count], NULL, worker_routine, NULL); - if (status != 0) - err_abort (status, "Create worker"); - } - pthread_cleanup_push (cleanup, (void*)&team); + for (count = 0; count < THREADS; count++) { + status = pthread_create(&team.workers[count], NULL, worker_routine, NULL); + if (status != 0) + err_abort(status, "Create worker"); + } + pthread_cleanup_push(cleanup, (void*) &team); - for (team.join_i = 0; team.join_i < THREADS; team.join_i++) { - status = pthread_join (team.workers[team.join_i], &result); - if (status != 0) - err_abort (status, "Join worker"); - } + for (team.join_i = 0; team.join_i < THREADS; team.join_i++) { + status = pthread_join(team.workers[team.join_i], &result); + if (status != 0) + err_abort(status, "Join worker"); + } - pthread_cleanup_pop (0); - return NULL; + pthread_cleanup_pop(0); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - int status; + pthread_t thread_id; + int status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our threads can run concurrently, we need to - * increase the concurrency level to at least 2 plus THREADS - * (the number of workers). - */ - DPRINTF (("Setting concurrency level to %d\n", THREADS+2)); - thr_setconcurrency (THREADS+2); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level to at least 2 plus THREADS + * (the number of workers). + */ + DPRINTF(("Setting concurrency level to %d\n", THREADS + 2)); + thr_setconcurrency(THREADS + 2); #endif - status = pthread_create (&thread_id, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create team"); - sleep (5); - printf ("Cancelling...\n"); - status = pthread_cancel (thread_id); - if (status != 0) - err_abort (status, "Cancel team"); - status = pthread_join (thread_id, NULL); - if (status != 0) - err_abort (status, "Join team"); + status = pthread_create(&thread_id, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create team"); + sleep(5); + printf("Cancelling...\n"); + status = pthread_cancel(thread_id); + if (status != 0) + err_abort(status, "Cancel team"); + status = pthread_join(thread_id, NULL); + if (status != 0) + err_abort(status, "Join team"); } diff --git a/src/ch05/cond_attr.c b/src/ch05/cond_attr.c index c96e5ce..25ad27c 100644 --- a/src/ch05/cond_attr.c +++ b/src/ch05/cond_attr.c @@ -13,22 +13,22 @@ pthread_cond_t cond; -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_condattr_t cond_attr; - int status; + pthread_condattr_t cond_attr; + int status; - status = pthread_condattr_init (&cond_attr); - if (status != 0) - err_abort (status, "Create attr"); + status = pthread_condattr_init(&cond_attr); + if (status != 0) + err_abort(status, "Create attr"); #ifdef _POSIX_THREAD_PROCESS_SHARED - status = pthread_condattr_setpshared ( - &cond_attr, PTHREAD_PROCESS_PRIVATE); - if (status != 0) - err_abort (status, "Set pshared"); + status = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_PRIVATE); + if (status != 0) + err_abort(status, "Set pshared"); #endif - status = pthread_cond_init (&cond, &cond_attr); - if (status != 0) - err_abort (status, "Init cond"); - return 0; + status = pthread_cond_init(&cond, &cond_attr); + if (status != 0) + err_abort(status, "Init cond"); + return 0; } diff --git a/src/ch05/mutex_attr.c b/src/ch05/mutex_attr.c index 5b038a8..5aa1e41 100644 --- a/src/ch05/mutex_attr.c +++ b/src/ch05/mutex_attr.c @@ -14,22 +14,22 @@ pthread_mutex_t mutex; -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_mutexattr_t mutex_attr; - int status; + pthread_mutexattr_t mutex_attr; + int status; - status = pthread_mutexattr_init (&mutex_attr); - if (status != 0) - err_abort (status, "Create attr"); + status = pthread_mutexattr_init(&mutex_attr); + if (status != 0) + err_abort(status, "Create attr"); #ifdef _POSIX_THREAD_PROCESS_SHARED - status = pthread_mutexattr_setpshared ( - &mutex_attr, PTHREAD_PROCESS_PRIVATE); - if (status != 0) - err_abort (status, "Set pshared"); + status = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_PRIVATE); + if (status != 0) + err_abort(status, "Set pshared"); #endif - status = pthread_mutex_init (&mutex, &mutex_attr); - if (status != 0) - err_abort (status, "Init mutex"); - return 0; + status = pthread_mutex_init(&mutex, &mutex_attr); + if (status != 0) + err_abort(status, "Init mutex"); + return 0; } diff --git a/src/ch05/once.c b/src/ch05/once.c index a6e104e..f9a1532 100644 --- a/src/ch05/once.c +++ b/src/ch05/once.c @@ -16,56 +16,59 @@ pthread_mutex_t mutex; * with the same control structure are made during the course of * the program. */ -void once_init_routine (void) +void +once_init_routine(void) { - int status; + int status; - status = pthread_mutex_init (&mutex, NULL); - if (status != 0) - err_abort (status, "Init Mutex"); + status = pthread_mutex_init(&mutex, NULL); + if (status != 0) + err_abort(status, "Init Mutex"); } /* * Thread start routine that calls pthread_once. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - int status; + int status; - status = pthread_once (&once_block, once_init_routine); - if (status != 0) - err_abort (status, "Once init"); - status = pthread_mutex_lock (&mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - printf ("thread_routine has locked the mutex.\n"); - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - return NULL; + status = pthread_once(&once_block, once_init_routine); + if (status != 0) + err_abort(status, "Once init"); + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + printf("thread_routine has locked the mutex.\n"); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - char *input, buffer[64]; - int status; + pthread_t thread_id; + char *input, buffer[64]; + int status; - status = pthread_create (&thread_id, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_once (&once_block, once_init_routine); - if (status != 0) - err_abort (status, "Once init"); - status = pthread_mutex_lock (&mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - printf ("Main has locked the mutex.\n"); - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - status = pthread_join (thread_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - return 0; + status = pthread_create(&thread_id, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_once(&once_block, once_init_routine); + if (status != 0) + err_abort(status, "Once init"); + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + printf("Main has locked the mutex.\n"); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + status = pthread_join(thread_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + return 0; } diff --git a/src/ch05/sched_attr.c b/src/ch05/sched_attr.c index 51fa9c6..0704338 100644 --- a/src/ch05/sched_attr.c +++ b/src/ch05/sched_attr.c @@ -9,54 +9,56 @@ * _POSIX_THREAD_PRIORITY_SCHEDULING, it does not support the * SCHED_RR policy for threads. */ -#include #include #include +#include #include "errors.h" /* * Thread start routine. If priority scheduling is supported, * report the thread's scheduling attributes. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - int my_policy; - struct sched_param my_param; - int status; + int my_policy; + struct sched_param my_param; + int status; - /* - * If the priority scheduling option is not defined, then we - * can do nothing with the output of pthread_getschedparam, - * so just report that the thread ran, and exit. - */ -#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined (sun) - status = pthread_getschedparam ( - pthread_self (), &my_policy, &my_param); - if (status != 0) - err_abort (status, "Get sched"); - printf ("thread_routine running at %s/%d\n", - (my_policy == SCHED_FIFO ? "FIFO" - : (my_policy == SCHED_RR ? "RR" - : (my_policy == SCHED_OTHER ? "OTHER" - : "unknown"))), - my_param.sched_priority); + /* + * If the priority scheduling option is not defined, then we + * can do nothing with the output of pthread_getschedparam, + * so just report that the thread ran, and exit. + */ +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined(sun) + status = pthread_getschedparam(pthread_self(), &my_policy, &my_param); + if (status != 0) + err_abort(status, "Get sched"); + printf("thread_routine running at %s/%d\n", + (my_policy == SCHED_FIFO + ? "FIFO" + : (my_policy == SCHED_RR + ? "RR" + : (my_policy == SCHED_OTHER ? "OTHER" : "unknown"))), + my_param.sched_priority); #else - printf ("thread_routine running\n"); + printf("thread_routine running\n"); #endif - return NULL; + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - pthread_attr_t thread_attr; - int thread_policy; - struct sched_param thread_param; - int status, rr_min_priority, rr_max_priority; + pthread_t thread_id; + pthread_attr_t thread_attr; + int thread_policy; + struct sched_param thread_param; + int status, rr_min_priority, rr_max_priority; - status = pthread_attr_init (&thread_attr); - if (status != 0) - err_abort (status, "Init attr"); + status = pthread_attr_init(&thread_attr); + if (status != 0) + err_abort(status, "Init attr"); /* * If the priority scheduling option is defined, set various scheduling @@ -66,74 +68,64 @@ int main (int argc, char *argv[]) * behavior is to inherit scheduling information from the creating * thread. */ -#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined (sun) - status = pthread_attr_getschedpolicy ( - &thread_attr, &thread_policy); - if (status != 0) - err_abort (status, "Get policy"); - status = pthread_attr_getschedparam ( - &thread_attr, &thread_param); - if (status != 0) - err_abort (status, "Get sched param"); - printf ( - "Default policy is %s, priority is %d\n", - (thread_policy == SCHED_FIFO ? "FIFO" - : (thread_policy == SCHED_RR ? "RR" - : (thread_policy == SCHED_OTHER ? "OTHER" - : "unknown"))), - thread_param.sched_priority); +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined(sun) + status = pthread_attr_getschedpolicy(&thread_attr, &thread_policy); + if (status != 0) + err_abort(status, "Get policy"); + status = pthread_attr_getschedparam(&thread_attr, &thread_param); + if (status != 0) + err_abort(status, "Get sched param"); + printf("Default policy is %s, priority is %d\n", + (thread_policy == SCHED_FIFO + ? "FIFO" + : (thread_policy == SCHED_RR + ? "RR" + : (thread_policy == SCHED_OTHER ? "OTHER" : "unknown"))), + thread_param.sched_priority); - status = pthread_attr_setschedpolicy ( - &thread_attr, SCHED_RR); + status = pthread_attr_setschedpolicy(&thread_attr, SCHED_RR); + if (status != 0) + printf("Unable to set SCHED_RR policy.\n"); + else { + /* + * Just for the sake of the exercise, we'll use the + * middle of the priority range allowed for + * SCHED_RR. This should ensure that the thread will be + * run, without blocking everything else. Because any + * assumptions about how a thread's priority interacts + * with other threads (even in other processes) are + * nonportable, especially on an implementation that + * defaults to System contention scope, you may have to + * adjust this code before it will work on some systems. + */ + rr_min_priority = sched_get_priority_min(SCHED_RR); + if (rr_min_priority == -1) + errno_abort("Get SCHED_RR min priority"); + rr_max_priority = sched_get_priority_max(SCHED_RR); + if (rr_max_priority == -1) + errno_abort("Get SCHED_RR max priority"); + thread_param.sched_priority = (rr_min_priority + rr_max_priority) / 2; + printf("SCHED_RR priority range is %d to %d: using %d\n", + rr_min_priority, + rr_max_priority, + thread_param.sched_priority); + status = pthread_attr_setschedparam(&thread_attr, &thread_param); if (status != 0) - printf ("Unable to set SCHED_RR policy.\n"); - else { - /* - * Just for the sake of the exercise, we'll use the - * middle of the priority range allowed for - * SCHED_RR. This should ensure that the thread will be - * run, without blocking everything else. Because any - * assumptions about how a thread's priority interacts - * with other threads (even in other processes) are - * nonportable, especially on an implementation that - * defaults to System contention scope, you may have to - * adjust this code before it will work on some systems. - */ - rr_min_priority = sched_get_priority_min (SCHED_RR); - if (rr_min_priority == -1) - errno_abort ("Get SCHED_RR min priority"); - rr_max_priority = sched_get_priority_max (SCHED_RR); - if (rr_max_priority == -1) - errno_abort ("Get SCHED_RR max priority"); - thread_param.sched_priority = - (rr_min_priority + rr_max_priority)/2; - printf ( - "SCHED_RR priority range is %d to %d: using %d\n", - rr_min_priority, - rr_max_priority, - thread_param.sched_priority); - status = pthread_attr_setschedparam ( - &thread_attr, &thread_param); - if (status != 0) - err_abort (status, "Set params"); - printf ( - "Creating thread at RR/%d\n", - thread_param.sched_priority); - status = pthread_attr_setinheritsched ( - &thread_attr, PTHREAD_EXPLICIT_SCHED); - if (status != 0) - err_abort (status, "Set inherit"); - } + err_abort(status, "Set params"); + printf("Creating thread at RR/%d\n", thread_param.sched_priority); + status = pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED); + if (status != 0) + err_abort(status, "Set inherit"); + } #else - printf ("Priority scheduling not supported\n"); + printf("Priority scheduling not supported\n"); #endif - status = pthread_create ( - &thread_id, &thread_attr, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_join (thread_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - printf ("Main exiting\n"); - return 0; + status = pthread_create(&thread_id, &thread_attr, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_join(thread_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + printf("Main exiting\n"); + return 0; } diff --git a/src/ch05/sched_thread.c b/src/ch05/sched_thread.c index 0190384..9f6d8f2 100644 --- a/src/ch05/sched_thread.c +++ b/src/ch05/sched_thread.c @@ -6,9 +6,9 @@ * Special note: This demonstration will fail on Solaris 2.5 * because it does not implement SCHED_RR. */ -#include #include #include +#include #include "errors.h" #define THREADS 5 @@ -17,72 +17,72 @@ * Structure describing each thread. */ typedef struct thread_tag { - int index; - pthread_t id; + int index; + pthread_t id; } thread_t; -thread_t threads[THREADS]; -int rr_min_priority; +thread_t threads[THREADS]; +int rr_min_priority; /* * Thread start routine that will set its own priority */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - thread_t *self = (thread_t*)arg; - int my_policy; - struct sched_param my_param; - int status; + thread_t* self = (thread_t*) arg; + int my_policy; + struct sched_param my_param; + int status; - my_param.sched_priority = rr_min_priority + self->index; - DPRINTF (( - "Thread %d will set SCHED_FIFO, priority %d\n", - self->index, my_param.sched_priority)); - status = pthread_setschedparam ( - self->id, SCHED_RR, &my_param); - if (status != 0) - err_abort (status, "Set sched"); - status = pthread_getschedparam ( - self->id, &my_policy, &my_param); - if (status != 0) - err_abort (status, "Get sched"); - printf ("thread_routine %d running at %s/%d\n", - self->index, - (my_policy == SCHED_FIFO ? "FIFO" - : (my_policy == SCHED_RR ? "RR" - : (my_policy == SCHED_OTHER ? "OTHER" - : "unknown"))), - my_param.sched_priority); - return NULL; + my_param.sched_priority = rr_min_priority + self->index; + DPRINTF(("Thread %d will set SCHED_FIFO, priority %d\n", + self->index, + my_param.sched_priority)); + status = pthread_setschedparam(self->id, SCHED_RR, &my_param); + if (status != 0) + err_abort(status, "Set sched"); + status = pthread_getschedparam(self->id, &my_policy, &my_param); + if (status != 0) + err_abort(status, "Get sched"); + printf("thread_routine %d running at %s/%d\n", + self->index, + (my_policy == SCHED_FIFO + ? "FIFO" + : (my_policy == SCHED_RR + ? "RR" + : (my_policy == SCHED_OTHER ? "OTHER" : "unknown"))), + my_param.sched_priority); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int count, status; + int count, status; - rr_min_priority = sched_get_priority_min (SCHED_RR); - if (rr_min_priority == -1) { + rr_min_priority = sched_get_priority_min(SCHED_RR); + if (rr_min_priority == -1) { #ifdef sun - if (errno == ENOSYS) { - fprintf (stderr, "SCHED_RR is not supported.\n"); - exit (0); - } + if (errno == ENOSYS) { + fprintf(stderr, "SCHED_RR is not supported.\n"); + exit(0); + } #endif - errno_abort ("Get SCHED_RR min priority"); - } - for (count = 0; count < THREADS; count++) { - threads[count].index = count; - status = pthread_create ( - &threads[count].id, NULL, - thread_routine, (void*)&threads[count]); - if (status != 0) - err_abort (status, "Create thread"); - } - for (count = 0; count < THREADS; count++) { - status = pthread_join (threads[count].id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - } - printf ("Main exiting\n"); - return 0; + errno_abort("Get SCHED_RR min priority"); + } + for (count = 0; count < THREADS; count++) { + threads[count].index = count; + status = pthread_create( + &threads[count].id, NULL, thread_routine, (void*) &threads[count]); + if (status != 0) + err_abort(status, "Create thread"); + } + for (count = 0; count < THREADS; count++) { + status = pthread_join(threads[count].id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + } + printf("Main exiting\n"); + return 0; } diff --git a/src/ch05/thread_attr.c b/src/ch05/thread_attr.c index 1917727..aa3313c 100644 --- a/src/ch05/thread_attr.c +++ b/src/ch05/thread_attr.c @@ -14,56 +14,56 @@ /* * Thread start routine that reports it ran, and then exits. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - printf ("The thread is here\n"); - return NULL; + printf("The thread is here\n"); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - pthread_attr_t thread_attr; - struct sched_param thread_param; - size_t stack_size; - int status; + pthread_t thread_id; + pthread_attr_t thread_attr; + struct sched_param thread_param; + size_t stack_size; + int status; - status = pthread_attr_init (&thread_attr); - if (status != 0) - err_abort (status, "Create attr"); + status = pthread_attr_init(&thread_attr); + if (status != 0) + err_abort(status, "Create attr"); - /* - * Create a detached thread. - */ - status = pthread_attr_setdetachstate ( - &thread_attr, PTHREAD_CREATE_DETACHED); - if (status != 0) - err_abort (status, "Set detach"); + /* + * Create a detached thread. + */ + status = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + if (status != 0) + err_abort(status, "Set detach"); #ifdef _POSIX_THREAD_ATTR_STACKSIZE - /* - * If supported, determine the default stack size and report - * it, and then select a stack size for the new thread. - * - * Note that the standard does not specify the default stack - * size, and the default value in an attributes object need - * not be the size that will actually be used. Solaris 2.5 - * uses a value of 0 to indicate the default. - */ - status = pthread_attr_getstacksize (&thread_attr, &stack_size); - if (status != 0) - err_abort (status, "Get stack size"); - printf ("Default stack size is %u; minimum is %u\n", - stack_size, PTHREAD_STACK_MIN); - status = pthread_attr_setstacksize ( - &thread_attr, PTHREAD_STACK_MIN*2); - if (status != 0) - err_abort (status, "Set stack size"); + /* + * If supported, determine the default stack size and report + * it, and then select a stack size for the new thread. + * + * Note that the standard does not specify the default stack + * size, and the default value in an attributes object need + * not be the size that will actually be used. Solaris 2.5 + * uses a value of 0 to indicate the default. + */ + status = pthread_attr_getstacksize(&thread_attr, &stack_size); + if (status != 0) + err_abort(status, "Get stack size"); + printf("Default stack size is %u; minimum is %u\n", + stack_size, + PTHREAD_STACK_MIN); + status = pthread_attr_setstacksize(&thread_attr, PTHREAD_STACK_MIN * 2); + if (status != 0) + err_abort(status, "Set stack size"); #endif - status = pthread_create ( - &thread_id, &thread_attr, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - printf ("Main exiting\n"); - pthread_exit (NULL); - return 0; + status = pthread_create(&thread_id, &thread_attr, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + printf("Main exiting\n"); + pthread_exit(NULL); + return 0; } diff --git a/src/ch05/tsd_destructor.c b/src/ch05/tsd_destructor.c index 42fcbf5..02ed126 100644 --- a/src/ch05/tsd_destructor.c +++ b/src/ch05/tsd_destructor.c @@ -10,13 +10,13 @@ * Structure used as value of thread-specific data key. */ typedef struct private_tag { - pthread_t thread_id; - char *string; + pthread_t thread_id; + char* string; } private_t; -pthread_key_t identity_key; /* Thread-specific data key */ +pthread_key_t identity_key; /* Thread-specific data key */ pthread_mutex_t identity_key_mutex = PTHREAD_MUTEX_INITIALIZER; -long identity_key_counter = 0; +long identity_key_counter = 0; /* * This routine is called as each thread terminates with a value @@ -24,95 +24,97 @@ long identity_key_counter = 0; * threads still have values, and deletes the key when there are * no more references. */ -void identity_key_destructor (void *value) +void +identity_key_destructor(void* value) { - private_t *private = (private_t*)value; - int status; + private_t* private = (private_t*) value; + int status; - printf ("thread \"%s\" exiting...\n", private->string); - free (value); - status = pthread_mutex_lock (&identity_key_mutex); + printf("thread \"%s\" exiting...\n", private->string); + free(value); + status = pthread_mutex_lock(&identity_key_mutex); + if (status != 0) + err_abort(status, "Lock key mutex"); + identity_key_counter--; + if (identity_key_counter <= 0) { + status = pthread_key_delete(identity_key); if (status != 0) - err_abort (status, "Lock key mutex"); - identity_key_counter--; - if (identity_key_counter <= 0) { - status = pthread_key_delete (identity_key); - if (status != 0) - err_abort (status, "Delete key"); - printf ("key deleted...\n"); - } - status = pthread_mutex_unlock (&identity_key_mutex); - if (status != 0) - err_abort (status, "Unlock key mutex"); + err_abort(status, "Delete key"); + printf("key deleted...\n"); + } + status = pthread_mutex_unlock(&identity_key_mutex); + if (status != 0) + err_abort(status, "Unlock key mutex"); } /* * Helper routine to allocate a new value for thread-specific * data key if the thread doesn't already have one. */ -void *identity_key_get (void) +void* +identity_key_get(void) { - void *value; - int status; + void* value; + int status; - value = pthread_getspecific (identity_key); - if (value == NULL) { - value = malloc (sizeof (private_t)); - if (value == NULL) - errno_abort ("Allocate key value"); - status = pthread_setspecific (identity_key, (void*)value); - if (status != 0) - err_abort (status, "Set TSD"); - } - return value; + value = pthread_getspecific(identity_key); + if (value == NULL) { + value = malloc(sizeof(private_t)); + if (value == NULL) + errno_abort("Allocate key value"); + status = pthread_setspecific(identity_key, (void*) value); + if (status != 0) + err_abort(status, "Set TSD"); + } + return value; } /* * Thread start routine to use thread-specific data. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - private_t *value; + private_t* value; - value = (private_t*)identity_key_get (); - value->thread_id = pthread_self (); - value->string = (char*)arg; - printf ("thread \"%s\" starting...\n", value->string); - sleep (2); - return NULL; + value = (private_t*) identity_key_get(); + value->thread_id = pthread_self(); + value->string = (char*) arg; + printf("thread \"%s\" starting...\n", value->string); + sleep(2); + return NULL; } -void main (int argc, char *argv[]) +void +main(int argc, char* argv[]) { - pthread_t thread_1, thread_2; - private_t *value; - int status; + pthread_t thread_1, thread_2; + private_t* value; + int status; - /* - * Create the TSD key, and set the reference counter to - * the number of threads that will use it (two thread_routine - * threads plus main). This must be done before creating - * the threads! Otherwise, if one thread runs the key's - * destructor before any other thread uses the key, it will - * be deleted. - * - * Note that there's rarely any good reason to delete a - * thread-specific data key. - */ - status = pthread_key_create (&identity_key, identity_key_destructor); - if (status != 0) - err_abort (status, "Create key"); - identity_key_counter = 3; - value = (private_t*)identity_key_get (); - value->thread_id = pthread_self (); - value->string = "Main thread"; - status = pthread_create (&thread_1, NULL, - thread_routine, "Thread 1"); - if (status != 0) - err_abort (status, "Create thread 1"); - status = pthread_create (&thread_2, NULL, - thread_routine, "Thread 2"); - if (status != 0) - err_abort (status, "Create thread 2"); - pthread_exit (NULL); + /* + * Create the TSD key, and set the reference counter to + * the number of threads that will use it (two thread_routine + * threads plus main). This must be done before creating + * the threads! Otherwise, if one thread runs the key's + * destructor before any other thread uses the key, it will + * be deleted. + * + * Note that there's rarely any good reason to delete a + * thread-specific data key. + */ + status = pthread_key_create(&identity_key, identity_key_destructor); + if (status != 0) + err_abort(status, "Create key"); + identity_key_counter = 3; + value = (private_t*) identity_key_get(); + value->thread_id = pthread_self(); + value->string = "Main thread"; + status = pthread_create(&thread_1, NULL, thread_routine, "Thread 1"); + if (status != 0) + err_abort(status, "Create thread 1"); + status = pthread_create(&thread_2, NULL, thread_routine, "Thread 2"); + if (status != 0) + err_abort(status, "Create thread 2"); + pthread_exit(NULL); } diff --git a/src/ch05/tsd_once.c b/src/ch05/tsd_once.c index c6f9ada..88a8d16 100644 --- a/src/ch05/tsd_once.c +++ b/src/ch05/tsd_once.c @@ -14,68 +14,69 @@ * Structure used as the value for thread-specific data key. */ typedef struct tsd_tag { - pthread_t thread_id; - char *string; + pthread_t thread_id; + char* string; } tsd_t; -pthread_key_t tsd_key; /* Thread-specific data key */ +pthread_key_t tsd_key; /* Thread-specific data key */ pthread_once_t key_once = PTHREAD_ONCE_INIT; /* * One-time initialization routine used with the pthread_once * control block. */ -void once_routine (void) +void +once_routine(void) { - int status; + int status; - printf ("initializing key\n"); - status = pthread_key_create (&tsd_key, NULL); - if (status != 0) - err_abort (status, "Create key"); + printf("initializing key\n"); + status = pthread_key_create(&tsd_key, NULL); + if (status != 0) + err_abort(status, "Create key"); } /* * Thread start routine that uses pthread_once to dynamically * create a thread-specific data key. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - tsd_t *value; - int status; + tsd_t* value; + int status; - status = pthread_once (&key_once, once_routine); - if (status != 0) - err_abort (status, "Once init"); - value = (tsd_t*)malloc (sizeof (tsd_t)); - if (value == NULL) - errno_abort ("Allocate key value"); - status = pthread_setspecific (tsd_key, value); - if (status != 0) - err_abort (status, "Set tsd"); - printf ("%s set tsd value %p\n", arg, value); - value->thread_id = pthread_self (); - value->string = (char*)arg; - value = (tsd_t*)pthread_getspecific (tsd_key); - printf ("%s starting...\n", value->string); - sleep (2); - value = (tsd_t*)pthread_getspecific (tsd_key); - printf ("%s done...\n", value->string); - return NULL; + status = pthread_once(&key_once, once_routine); + if (status != 0) + err_abort(status, "Once init"); + value = (tsd_t*) malloc(sizeof(tsd_t)); + if (value == NULL) + errno_abort("Allocate key value"); + status = pthread_setspecific(tsd_key, value); + if (status != 0) + err_abort(status, "Set tsd"); + printf("%s set tsd value %p\n", arg, value); + value->thread_id = pthread_self(); + value->string = (char*) arg; + value = (tsd_t*) pthread_getspecific(tsd_key); + printf("%s starting...\n", value->string); + sleep(2); + value = (tsd_t*) pthread_getspecific(tsd_key); + printf("%s done...\n", value->string); + return NULL; } -void main (int argc, char *argv[]) +void +main(int argc, char* argv[]) { - pthread_t thread1, thread2; - int status; + pthread_t thread1, thread2; + int status; - status = pthread_create ( - &thread1, NULL, thread_routine, "thread 1"); - if (status != 0) - err_abort (status, "Create thread 1"); - status = pthread_create ( - &thread2, NULL, thread_routine, "thread 2"); - if (status != 0) - err_abort (status, "Create thread 2"); - pthread_exit (NULL); + status = pthread_create(&thread1, NULL, thread_routine, "thread 1"); + if (status != 0) + err_abort(status, "Create thread 1"); + status = pthread_create(&thread2, NULL, thread_routine, "thread 2"); + if (status != 0) + err_abort(status, "Create thread 2"); + pthread_exit(NULL); } diff --git a/src/ch06/atfork.c b/src/ch06/atfork.c index 2e36594..1e6b973 100644 --- a/src/ch06/atfork.c +++ b/src/ch06/atfork.c @@ -4,127 +4,132 @@ * Demonstrate the use of "fork handlers" to protect data * invariants across a fork. */ -#include #include +#include #include #include "errors.h" -pid_t self_pid; /* pid of current process */ +pid_t self_pid; /* pid of current process */ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* * This routine will be called prior to executing the fork, * within the parent process. */ -void fork_prepare (void) +void +fork_prepare(void) { - int status; + int status; - /* - * Lock the mutex in the parent before creating the child, - * to ensure that no other thread can lock it (or change any - * associated shared state) until after the fork completes. - */ - status = pthread_mutex_lock (&mutex); - if (status != 0) - err_abort (status, "Lock in prepare handler"); + /* + * Lock the mutex in the parent before creating the child, + * to ensure that no other thread can lock it (or change any + * associated shared state) until after the fork completes. + */ + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock in prepare handler"); } /* * This routine will be called after executing the fork, within * the parent process */ -void fork_parent (void) +void +fork_parent(void) { - int status; + int status; - /* - * Unlock the mutex in the parent after the child has been created. - */ - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock in parent handler"); + /* + * Unlock the mutex in the parent after the child has been created. + */ + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock in parent handler"); } /* * This routine will be called after executing the fork, within * the child process */ -void fork_child (void) +void +fork_child(void) { - int status; + int status; - /* - * Update the file scope "self_pid" within the child process, and unlock - * the mutex. - */ - self_pid = getpid (); - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock in child handler"); + /* + * Update the file scope "self_pid" within the child process, and unlock + * the mutex. + */ + self_pid = getpid(); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock in child handler"); } /* * Thread start routine, which will fork a new child process. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - pid_t child_pid; - int status; + pid_t child_pid; + int status; - child_pid = fork (); - if (child_pid == (pid_t)-1) - errno_abort ("Fork"); + child_pid = fork(); + if (child_pid == (pid_t) -1) + errno_abort("Fork"); - /* - * Lock the mutex -- without the atfork handlers, the mutex will remain - * locked in the child process and this lock attempt will hang (or fail - * with EDEADLK) in the child. - */ - status = pthread_mutex_lock (&mutex); - if (status != 0) - err_abort (status, "Lock in child"); - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock in child"); - printf ("After fork: %d (%d)\n", child_pid, self_pid); - if (child_pid != 0) { - if ((pid_t)-1 == waitpid (child_pid, (int*)0, 0)) - errno_abort ("Wait for child"); - } - return NULL; + /* + * Lock the mutex -- without the atfork handlers, the mutex will remain + * locked in the child process and this lock attempt will hang (or fail + * with EDEADLK) in the child. + */ + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock in child"); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock in child"); + printf("After fork: %d (%d)\n", child_pid, self_pid); + if (child_pid != 0) { + if ((pid_t) -1 == waitpid(child_pid, (int*) 0, 0)) + errno_abort("Wait for child"); + } + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t fork_thread; - int atfork_flag = 1; - int status; + pthread_t fork_thread; + int atfork_flag = 1; + int status; - if (argc > 1) - atfork_flag = atoi (argv[1]); - if (atfork_flag) { - status = pthread_atfork (fork_prepare, fork_parent, fork_child); - if (status != 0) - err_abort (status, "Register fork handlers"); - } - self_pid = getpid (); - status = pthread_mutex_lock (&mutex); + if (argc > 1) + atfork_flag = atoi(argv[1]); + if (atfork_flag) { + status = pthread_atfork(fork_prepare, fork_parent, fork_child); if (status != 0) - err_abort (status, "Lock mutex"); - /* - * Create a thread while the mutex is locked. It will fork a process, - * which (without atfork handlers) will run with the mutex locked. - */ - status = pthread_create (&fork_thread, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - sleep (5); - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - status = pthread_join (fork_thread, NULL); - if (status != 0) - err_abort (status, "Join thread"); - return 0; + err_abort(status, "Register fork handlers"); + } + self_pid = getpid(); + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + /* + * Create a thread while the mutex is locked. It will fork a process, + * which (without atfork handlers) will run with the mutex locked. + */ + status = pthread_create(&fork_thread, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + sleep(5); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + status = pthread_join(fork_thread, NULL); + if (status != 0) + err_abort(status, "Join thread"); + return 0; } diff --git a/src/ch06/flock.c b/src/ch06/flock.c index 3b459f7..a4bb399 100644 --- a/src/ch06/flock.c +++ b/src/ch06/flock.c @@ -14,71 +14,70 @@ * is prevented by the file locks until both prompt and fgets are * complete. */ -void *prompt_routine (void *arg) +void* +prompt_routine(void* arg) { - char *prompt = (char*)arg; - char *string; - int len; + char* prompt = (char*) arg; + char* string; + int len; - string = (char*)malloc (128); - if (string == NULL) - errno_abort ("Alloc string"); - flockfile (stdin); - flockfile (stdout); - printf (prompt); - if (fgets (string, 128, stdin) == NULL) - string[0] = '\0'; - else { - len = strlen (string); - if (len > 0 && string[len-1] == '\n') - string[len-1] = '\0'; - } - funlockfile (stdout); - funlockfile (stdin); - return (void*)string; + string = (char*) malloc(128); + if (string == NULL) + errno_abort("Alloc string"); + flockfile(stdin); + flockfile(stdout); + printf(prompt); + if (fgets(string, 128, stdin) == NULL) + string[0] = '\0'; + else { + len = strlen(string); + if (len > 0 && string[len - 1] == '\n') + string[len - 1] = '\0'; + } + funlockfile(stdout); + funlockfile(stdin); + return (void*) string; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread1, thread2, thread3; - char *string; - int status; + pthread_t thread1, thread2, thread3; + char* string; + int status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our threads can run concurrently, we need to - * increase the concurrency level. - */ - DPRINTF (("Setting concurrency level to 4\n")); - thr_setconcurrency (4); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level. + */ + DPRINTF(("Setting concurrency level to 4\n")); + thr_setconcurrency(4); #endif - status = pthread_create ( - &thread1, NULL, prompt_routine, "Thread 1> "); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_create ( - &thread2, NULL, prompt_routine, "Thread 2> "); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_create ( - &thread3, NULL, prompt_routine, "Thread 3> "); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_join (thread1, (void**)&string); - if (status != 0) - err_abort (status, "Join thread"); - printf ("Thread 1: \"%s\"\n", string); - free (string); - status = pthread_join (thread2, (void**)&string); - if (status != 0) - err_abort (status, "Join thread"); - printf ("Thread 1: \"%s\"\n", string); - free (string); - status = pthread_join (thread3, (void**)&string); - if (status != 0) - err_abort (status, "Join thread"); - printf ("Thread 1: \"%s\"\n", string); - free (string); - return 0; + status = pthread_create(&thread1, NULL, prompt_routine, "Thread 1> "); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_create(&thread2, NULL, prompt_routine, "Thread 2> "); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_create(&thread3, NULL, prompt_routine, "Thread 3> "); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_join(thread1, (void**) &string); + if (status != 0) + err_abort(status, "Join thread"); + printf("Thread 1: \"%s\"\n", string); + free(string); + status = pthread_join(thread2, (void**) &string); + if (status != 0) + err_abort(status, "Join thread"); + printf("Thread 1: \"%s\"\n", string); + free(string); + status = pthread_join(thread3, (void**) &string); + if (status != 0) + err_abort(status, "Join thread"); + printf("Thread 1: \"%s\"\n", string); + free(string); + return 0; } diff --git a/src/ch06/getlogin.c b/src/ch06/getlogin.c index 829ef66..5054d30 100644 --- a/src/ch06/getlogin.c +++ b/src/ch06/getlogin.c @@ -14,29 +14,29 @@ * and dynamically allocating the buffers. */ #ifndef TTY_NAME_MAX -# define TTY_NAME_MAX 128 +#define TTY_NAME_MAX 128 #endif #ifndef LOGIN_NAME_MAX -# define LOGIN_NAME_MAX 32 +#define LOGIN_NAME_MAX 32 #endif - -int main (int argc, char *argv[]) -{ - char login_str[LOGIN_NAME_MAX]; - char stdin_str[TTY_NAME_MAX]; - char cterm_str[L_ctermid], *cterm_str_ptr; - int status; - status = getlogin_r (login_str, sizeof (login_str)); - if (status != 0) - err_abort (status, "Get login"); - cterm_str_ptr = ctermid (cterm_str); - if (cterm_str_ptr == NULL) - errno_abort ("Get cterm"); - status = ttyname_r (0, stdin_str, sizeof (stdin_str)); - if (status != 0) - err_abort (status, "Get stdin"); - printf ("User: %s, cterm: %s, fd 0: %s\n", - login_str, cterm_str, stdin_str); - return 0; +int +main(int argc, char* argv[]) +{ + char login_str[LOGIN_NAME_MAX]; + char stdin_str[TTY_NAME_MAX]; + char cterm_str[L_ctermid], *cterm_str_ptr; + int status; + + status = getlogin_r(login_str, sizeof(login_str)); + if (status != 0) + err_abort(status, "Get login"); + cterm_str_ptr = ctermid(cterm_str); + if (cterm_str_ptr == NULL) + errno_abort("Get cterm"); + status = ttyname_r(0, stdin_str, sizeof(stdin_str)); + if (status != 0) + err_abort(status, "Get stdin"); + printf("User: %s, cterm: %s, fd 0: %s\n", login_str, cterm_str, stdin_str); + return 0; } diff --git a/src/ch06/putchar.c b/src/ch06/putchar.c index b871498..16ecdd2 100644 --- a/src/ch06/putchar.c +++ b/src/ch06/putchar.c @@ -37,17 +37,18 @@ * by locking the file stream and using putchar_unlocked to * write each character individually. */ -void *lock_routine (void *arg) +void* +lock_routine(void* arg) { - char *pointer; + char* pointer; - flockfile (stdout); - for (pointer = arg; *pointer != '\0'; pointer++) { - putchar_unlocked (*pointer); - sleep (1); - } - funlockfile (stdout); - return NULL; + flockfile(stdout); + for (pointer = arg; *pointer != '\0'; pointer++) { + putchar_unlocked(*pointer); + sleep(1); + } + funlockfile(stdout); + return NULL; } /* @@ -56,41 +57,40 @@ void *lock_routine (void *arg) * Although the internal locking of putchar prevents file stream * corruption, the writes of various threads may be interleaved. */ -void *unlock_routine (void *arg) +void* +unlock_routine(void* arg) { - char *pointer; + char* pointer; - for (pointer = arg; *pointer != '\0'; pointer++) { - putchar (*pointer); - sleep (1); - } - return NULL; + for (pointer = arg; *pointer != '\0'; pointer++) { + putchar(*pointer); + sleep(1); + } + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread1, thread2, thread3; - int flock_flag = 1; - void *(*thread_func)(void *); - int status; + pthread_t thread1, thread2, thread3; + int flock_flag = 1; + void* (*thread_func)(void*); + int status; - if (argc > 1) - flock_flag = atoi (argv[1]); - if (flock_flag) - thread_func = lock_routine; - else - thread_func = unlock_routine; - status = pthread_create ( - &thread1, NULL, thread_func, "this is thread 1\n"); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_create ( - &thread2, NULL, thread_func, "this is thread 2\n"); - if (status != 0) - err_abort (status, "Create thread"); - status = pthread_create ( - &thread3, NULL, thread_func, "this is thread 3\n"); - if (status != 0) - err_abort (status, "Create thread"); - pthread_exit (NULL); + if (argc > 1) + flock_flag = atoi(argv[1]); + if (flock_flag) + thread_func = lock_routine; + else + thread_func = unlock_routine; + status = pthread_create(&thread1, NULL, thread_func, "this is thread 1\n"); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_create(&thread2, NULL, thread_func, "this is thread 2\n"); + if (status != 0) + err_abort(status, "Create thread"); + status = pthread_create(&thread3, NULL, thread_func, "this is thread 3\n"); + if (status != 0) + err_abort(status, "Create thread"); + pthread_exit(NULL); } diff --git a/src/ch06/semaphore_signal.c b/src/ch06/semaphore_signal.c index 6c7422d..c237970 100644 --- a/src/ch06/semaphore_signal.c +++ b/src/ch06/semaphore_signal.c @@ -8,109 +8,111 @@ * and _POSIX_SEMAPHORES features of POSIX 1003.1b-1993. It will * not run (and may not compile) without them. */ -#include -#include #include #include #include +#include #include +#include #include "errors.h" -sem_t semaphore; +sem_t semaphore; /* * Signal catching function. */ -void signal_catcher (int sig) +void +signal_catcher(int sig) { - if (sem_post (&semaphore) == -1) - errno_abort ("Post semaphore"); + if (sem_post(&semaphore) == -1) + errno_abort("Post semaphore"); } /* * Thread start routine which waits on the semaphore. */ -void *sem_waiter (void *arg) +void* +sem_waiter(void* arg) { - int number = (int)arg; - int counter; + int number = (int) arg; + int counter; - /* - * Each thread waits 5 times. - */ - for (counter = 1; counter <= 5; counter++) { - while (sem_wait (&semaphore) == -1) { - if (errno != EINTR) - errno_abort ("Wait on semaphore"); - } - printf ("%d waking (%d)...\n", number, counter); + /* + * Each thread waits 5 times. + */ + for (counter = 1; counter <= 5; counter++) { + while (sem_wait(&semaphore) == -1) { + if (errno != EINTR) + errno_abort("Wait on semaphore"); } - return NULL; + printf("%d waking (%d)...\n", number, counter); + } + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int thread_count, status; - struct sigevent sig_event; - struct sigaction sig_action; - sigset_t sig_mask; - timer_t timer_id; - struct itimerspec timer_val; - pthread_t sem_waiters[5]; + int thread_count, status; + struct sigevent sig_event; + struct sigaction sig_action; + sigset_t sig_mask; + timer_t timer_id; + struct itimerspec timer_val; + pthread_t sem_waiters[5]; #if !defined(_POSIX_SEMAPHORES) || !defined(_POSIX_TIMERS) -# if !defined(_POSIX_SEMAPHORES) - printf ("This system does not support POSIX semaphores\n"); -# endif -# if !defined(_POSIX_TIMERS) - printf ("This system does not support POSIX timers\n"); -# endif - return -1; +#if !defined(_POSIX_SEMAPHORES) + printf("This system does not support POSIX semaphores\n"); +#endif +#if !defined(_POSIX_TIMERS) + printf("This system does not support POSIX timers\n"); +#endif + return -1; #else - sem_init (&semaphore, 0, 0); + sem_init(&semaphore, 0, 0); - /* - * Create 5 threads to wait on a semaphore. - */ - for (thread_count = 0; thread_count < 5; thread_count++) { - status = pthread_create ( - &sem_waiters[thread_count], NULL, - sem_waiter, (void*)thread_count); - if (status != 0) - err_abort (status, "Create thread"); - } + /* + * Create 5 threads to wait on a semaphore. + */ + for (thread_count = 0; thread_count < 5; thread_count++) { + status = pthread_create( + &sem_waiters[thread_count], NULL, sem_waiter, (void*) thread_count); + if (status != 0) + err_abort(status, "Create thread"); + } - /* - * Set up a repeating timer using signal number SIGRTMIN, - * set to occur every 2 seconds. - */ - sig_event.sigev_value.sival_int = 0; - sig_event.sigev_signo = SIGRTMIN; - sig_event.sigev_notify = SIGEV_SIGNAL; - if (timer_create (CLOCK_REALTIME, &sig_event, &timer_id) == -1) - errno_abort ("Create timer"); - sigemptyset (&sig_mask); - sigaddset (&sig_mask, SIGRTMIN); - sig_action.sa_handler = signal_catcher; - sig_action.sa_mask = sig_mask; - sig_action.sa_flags = 0; - if (sigaction (SIGRTMIN, &sig_action, NULL) == -1) - errno_abort ("Set signal action"); - timer_val.it_interval.tv_sec = 2; - timer_val.it_interval.tv_nsec = 0; - timer_val.it_value.tv_sec = 2; - timer_val.it_value.tv_nsec = 0; - if (timer_settime (timer_id, 0, &timer_val, NULL) == -1) - errno_abort ("Set timer"); + /* + * Set up a repeating timer using signal number SIGRTMIN, + * set to occur every 2 seconds. + */ + sig_event.sigev_value.sival_int = 0; + sig_event.sigev_signo = SIGRTMIN; + sig_event.sigev_notify = SIGEV_SIGNAL; + if (timer_create(CLOCK_REALTIME, &sig_event, &timer_id) == -1) + errno_abort("Create timer"); + sigemptyset(&sig_mask); + sigaddset(&sig_mask, SIGRTMIN); + sig_action.sa_handler = signal_catcher; + sig_action.sa_mask = sig_mask; + sig_action.sa_flags = 0; + if (sigaction(SIGRTMIN, &sig_action, NULL) == -1) + errno_abort("Set signal action"); + timer_val.it_interval.tv_sec = 2; + timer_val.it_interval.tv_nsec = 0; + timer_val.it_value.tv_sec = 2; + timer_val.it_value.tv_nsec = 0; + if (timer_settime(timer_id, 0, &timer_val, NULL) == -1) + errno_abort("Set timer"); - /* - * Wait for all threads to complete. - */ - for (thread_count = 0; thread_count < 5; thread_count++) { - status = pthread_join (sem_waiters[thread_count], NULL); - if (status != 0) - err_abort (status, "Join thread"); - } - return 0; + /* + * Wait for all threads to complete. + */ + for (thread_count = 0; thread_count < 5; thread_count++) { + status = pthread_join(sem_waiters[thread_count], NULL); + if (status != 0) + err_abort(status, "Join thread"); + } + return 0; #endif } diff --git a/src/ch06/semaphore_wait.c b/src/ch06/semaphore_wait.c index e023530..f379e7e 100644 --- a/src/ch06/semaphore_wait.c +++ b/src/ch06/semaphore_wait.c @@ -3,11 +3,11 @@ * * Demonstrate use of semaphores for synchronization. */ -#include -#include #include #include #include +#include +#include #include "errors.h" sem_t semaphore; @@ -15,68 +15,69 @@ sem_t semaphore; /* * Thread start routine to wait on a semaphore. */ -void *sem_waiter (void *arg) +void* +sem_waiter(void* arg) { - long num = (long)arg; + long num = (long) arg; - printf ("Thread %d waiting\n", num); - if (sem_wait (&semaphore) == -1) - errno_abort ("Wait on semaphore"); - printf ("Thread %d resuming\n", num); - return NULL; + printf("Thread %d waiting\n", num); + if (sem_wait(&semaphore) == -1) + errno_abort("Wait on semaphore"); + printf("Thread %d resuming\n", num); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int thread_count; - pthread_t sem_waiters[5]; - int status; + int thread_count; + pthread_t sem_waiters[5]; + int status; #if !defined(_POSIX_SEMAPHORES) - printf ("This system does not support POSIX semaphores\n"); - return -1; + printf("This system does not support POSIX semaphores\n"); + return -1; #else - if (sem_init (&semaphore, 0, 0) == -1) - errno_abort ("Init semaphore"); + if (sem_init(&semaphore, 0, 0) == -1) + errno_abort("Init semaphore"); - /* - * Create 5 threads to wait concurrently on the semaphore. - */ - for (thread_count = 0; thread_count < 5; thread_count++) { - status = pthread_create ( - &sem_waiters[thread_count], NULL, - sem_waiter, (void*)thread_count); - if (status != 0) - err_abort (status, "Create thread"); - } + /* + * Create 5 threads to wait concurrently on the semaphore. + */ + for (thread_count = 0; thread_count < 5; thread_count++) { + status = pthread_create( + &sem_waiters[thread_count], NULL, sem_waiter, (void*) thread_count); + if (status != 0) + err_abort(status, "Create thread"); + } - sleep (2); + sleep(2); - /* - * "Broadcast" the semaphore by repeatedly posting until the - * count of waiters goes to 0. - */ - while (1) { - int sem_value; + /* + * "Broadcast" the semaphore by repeatedly posting until the + * count of waiters goes to 0. + */ + while (1) { + int sem_value; - if (sem_getvalue (&semaphore, &sem_value) == -1) - errno_abort ("Get semaphore value"); - if (sem_value >= 0) - break; - printf ("Posting from main: %d\n", sem_value); - if (sem_post (&semaphore) == -1) - errno_abort ("Post semaphore"); - } + if (sem_getvalue(&semaphore, &sem_value) == -1) + errno_abort("Get semaphore value"); + if (sem_value >= 0) + break; + printf("Posting from main: %d\n", sem_value); + if (sem_post(&semaphore) == -1) + errno_abort("Post semaphore"); + } - /* - * Wait for all threads to complete. - */ - for (thread_count = 0; thread_count < 5; thread_count++) { - status = pthread_join (sem_waiters[thread_count], NULL); - if (status != 0) - err_abort (status, "Join thread"); - } - return 0; + /* + * Wait for all threads to complete. + */ + for (thread_count = 0; thread_count < 5; thread_count++) { + status = pthread_join(sem_waiters[thread_count], NULL); + if (status != 0) + err_abort(status, "Join thread"); + } + return 0; #endif } diff --git a/src/ch06/sigev_thread.c b/src/ch06/sigev_thread.c index 89806a3..77ce2f5 100644 --- a/src/ch06/sigev_thread.c +++ b/src/ch06/sigev_thread.c @@ -17,8 +17,8 @@ timer_t timer_id; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -int counter = 0; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +int counter = 0; /* * Thread start routine to notify the application when the @@ -29,78 +29,76 @@ int counter = 0; * be awakened, and will terminate the program. */ void -timer_thread (void *arg) +timer_thread(void* arg) { - int status; + int status; - status = pthread_mutex_lock (&mutex); + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + if (++counter >= 5) { + status = pthread_cond_signal(&cond); if (status != 0) - err_abort (status, "Lock mutex"); - if (++counter >= 5) { - status = pthread_cond_signal (&cond); - if (status != 0) - err_abort (status, "Signal condition"); - } - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); + err_abort(status, "Signal condition"); + } + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); - printf ("Timer %d\n", counter); + printf("Timer %d\n", counter); } main() { - int status; - struct itimerspec ts; - struct sigevent se; + int status; + struct itimerspec ts; + struct sigevent se; #ifdef sun - fprintf ( - stderr, - "This program cannot compile on Solaris 2.5.\n" - "To build and run on Solaris 2.6, remove the\n" - "\"#ifdef sun\" block in main().\n"); + fprintf(stderr, + "This program cannot compile on Solaris 2.5.\n" + "To build and run on Solaris 2.6, remove the\n" + "\"#ifdef sun\" block in main().\n"); #else - /* - * Set the sigevent structure to cause the signal to be - * delivered by creating a new thread. - */ - se.sigev_notify = SIGEV_THREAD; - se.sigev_value.sival_ptr = &timer_id; - se.sigev_notify_function = timer_thread; - se.sigev_notify_attributes = NULL; + /* + * Set the sigevent structure to cause the signal to be + * delivered by creating a new thread. + */ + se.sigev_notify = SIGEV_THREAD; + se.sigev_value.sival_ptr = &timer_id; + se.sigev_notify_function = timer_thread; + se.sigev_notify_attributes = NULL; - /* - * Specify a repeating timer that fires each 5 seconds. - */ - ts.it_value.tv_sec = 5; - ts.it_value.tv_nsec = 0; - ts.it_interval.tv_sec = 5; - ts.it_interval.tv_nsec = 0; + /* + * Specify a repeating timer that fires each 5 seconds. + */ + ts.it_value.tv_sec = 5; + ts.it_value.tv_nsec = 0; + ts.it_interval.tv_sec = 5; + ts.it_interval.tv_nsec = 0; - DPRINTF (("Creating timer\n")); - status = timer_create(CLOCK_REALTIME, &se, &timer_id); - if (status == -1) - errno_abort ("Create timer"); + DPRINTF(("Creating timer\n")); + status = timer_create(CLOCK_REALTIME, &se, &timer_id); + if (status == -1) + errno_abort("Create timer"); - DPRINTF (( - "Setting timer %d for 5-second expiration...\n", timer_id)); - status = timer_settime(timer_id, 0, &ts, 0); - if (status == -1) - errno_abort ("Set timer"); + DPRINTF(("Setting timer %d for 5-second expiration...\n", timer_id)); + status = timer_settime(timer_id, 0, &ts, 0); + if (status == -1) + errno_abort("Set timer"); - status = pthread_mutex_lock (&mutex); + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + while (counter < 5) { + status = pthread_cond_wait(&cond, &mutex); if (status != 0) - err_abort (status, "Lock mutex"); - while (counter < 5) { - status = pthread_cond_wait (&cond, &mutex); - if (status != 0) - err_abort (status, "Wait on condition"); - } - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); + err_abort(status, "Wait on condition"); + } + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); #endif /* Sun */ - return 0; + return 0; } diff --git a/src/ch06/sigwait.c b/src/ch06/sigwait.c index 8d1c203..3507cd2 100644 --- a/src/ch06/sigwait.c +++ b/src/ch06/sigwait.c @@ -4,15 +4,15 @@ * Demonstrate use of sigwait() to synchronously handle * asynchrnous signals within a threaded program. */ -#include -#include #include #include +#include +#include #include "errors.h" pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -int interrupted = 0; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +int interrupted = 0; sigset_t signal_set; /* @@ -20,79 +20,80 @@ sigset_t signal_set; * the "interrupted" flag (the main thread's wait predicate) and * signal a condition variable. The main thread will exit. */ -void *signal_waiter (void *arg) +void* +signal_waiter(void* arg) { - int sig_number; - int signal_count = 0; - int status; + int sig_number; + int signal_count = 0; + int status; - while (1) { - sigwait (&signal_set, &sig_number); - if (sig_number == SIGINT) { - printf ("Got SIGINT (%d of 5)\n", signal_count+1); - if (++signal_count >= 5) { - status = pthread_mutex_lock (&mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - interrupted = 1; - status = pthread_cond_signal (&cond); - if (status != 0) - err_abort (status, "Signal condition"); - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - break; - } - } - } - return NULL; -} - -int main (int argc, char *argv[]) -{ - pthread_t signal_thread_id; - int status; - - /* - * Start by masking the "interesting" signal, SIGINT in the - * initial thread. Because all threads inherit the signal mask - * from their creator, all threads in the process will have - * SIGINT masked unless one explicitly unmasks it. The - * semantics of sigwait require that all threads (including - * the thread calling sigwait) have the signal masked, for - * reliable operation. Otherwise, a signal that arrives - * while the sigwaiter is not blocked in sigwait might be - * delivered to another thread. - */ - sigemptyset (&signal_set); - sigaddset (&signal_set, SIGINT); - status = pthread_sigmask (SIG_BLOCK, &signal_set, NULL); - if (status != 0) - err_abort (status, "Set signal mask"); - - /* - * Create the sigwait thread. - */ - status = pthread_create (&signal_thread_id, NULL, - signal_waiter, NULL); - if (status != 0) - err_abort (status, "Create sigwaiter"); - - /* - * Wait for the sigwait thread to receive SIGINT and signal - * the condition variable. - */ - status = pthread_mutex_lock (&mutex); - if (status != 0) - err_abort (status, "Lock mutex"); - while (!interrupted) { - status = pthread_cond_wait (&cond, &mutex); + while (1) { + sigwait(&signal_set, &sig_number); + if (sig_number == SIGINT) { + printf("Got SIGINT (%d of 5)\n", signal_count + 1); + if (++signal_count >= 5) { + status = pthread_mutex_lock(&mutex); if (status != 0) - err_abort (status, "Wait for interrupt"); + err_abort(status, "Lock mutex"); + interrupted = 1; + status = pthread_cond_signal(&cond); + if (status != 0) + err_abort(status, "Signal condition"); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + break; + } } - status = pthread_mutex_unlock (&mutex); - if (status != 0) - err_abort (status, "Unlock mutex"); - printf ("Main terminating with SIGINT\n"); - return 0; + } + return NULL; +} + +int +main(int argc, char* argv[]) +{ + pthread_t signal_thread_id; + int status; + + /* + * Start by masking the "interesting" signal, SIGINT in the + * initial thread. Because all threads inherit the signal mask + * from their creator, all threads in the process will have + * SIGINT masked unless one explicitly unmasks it. The + * semantics of sigwait require that all threads (including + * the thread calling sigwait) have the signal masked, for + * reliable operation. Otherwise, a signal that arrives + * while the sigwaiter is not blocked in sigwait might be + * delivered to another thread. + */ + sigemptyset(&signal_set); + sigaddset(&signal_set, SIGINT); + status = pthread_sigmask(SIG_BLOCK, &signal_set, NULL); + if (status != 0) + err_abort(status, "Set signal mask"); + + /* + * Create the sigwait thread. + */ + status = pthread_create(&signal_thread_id, NULL, signal_waiter, NULL); + if (status != 0) + err_abort(status, "Create sigwaiter"); + + /* + * Wait for the sigwait thread to receive SIGINT and signal + * the condition variable. + */ + status = pthread_mutex_lock(&mutex); + if (status != 0) + err_abort(status, "Lock mutex"); + while (!interrupted) { + status = pthread_cond_wait(&cond, &mutex); + if (status != 0) + err_abort(status, "Wait for interrupt"); + } + status = pthread_mutex_unlock(&mutex); + if (status != 0) + err_abort(status, "Unlock mutex"); + printf("Main terminating with SIGINT\n"); + return 0; } diff --git a/src/ch06/susp.c b/src/ch06/susp.c index 243dd56..4247171 100644 --- a/src/ch06/susp.c +++ b/src/ch06/susp.c @@ -26,15 +26,15 @@ #include #include "errors.h" -#define THREAD_COUNT 20 -#define ITERATIONS 40000 +#define THREAD_COUNT 20 +#define ITERATIONS 40000 unsigned long thread_count = THREAD_COUNT; -unsigned long iterations = ITERATIONS; -pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; -volatile int sentinel = 0; -pthread_once_t once = PTHREAD_ONCE_INIT; +unsigned long iterations = ITERATIONS; +pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +volatile int sentinel = 0; +pthread_once_t once = PTHREAD_ONCE_INIT; pthread_t *array = NULL, null_pthread = {0}; int bottom = 0; int inited = 0; @@ -44,23 +44,23 @@ int inited = 0; * receiving SIGUSR2 (resume). */ void -suspend_signal_handler (int sig) +suspend_signal_handler(int sig) { - sigset_t signal_set; + sigset_t signal_set; - /* - * Block all signals except SIGUSR2 while suspended. - */ - sigfillset (&signal_set); - sigdelset (&signal_set, SIGUSR2); - sentinel = 1; - sigsuspend (&signal_set); + /* + * Block all signals except SIGUSR2 while suspended. + */ + sigfillset(&signal_set); + sigdelset(&signal_set, SIGUSR2); + sentinel = 1; + sigsuspend(&signal_set); - /* - * Once I'm here, I've been resumed, and the resume signal - * handler has been run to completion. - */ - return; + /* + * Once I'm here, I've been resumed, and the resume signal + * handler has been run to completion. + */ + return; } /* @@ -69,9 +69,9 @@ suspend_signal_handler (int sig) * to cause sigsuspend() to return. */ void -resume_signal_handler (int sig) +resume_signal_handler(int sig) { - return; + return; } /* @@ -79,39 +79,39 @@ resume_signal_handler (int sig) * (called by pthread_once). */ void -suspend_init_routine (void) +suspend_init_routine(void) { - int status; - struct sigaction sigusr1, sigusr2; + int status; + struct sigaction sigusr1, sigusr2; - /* - * Allocate the suspended threads array. This array is used - * to guarentee idempotency - */ - bottom = 10; - array = (pthread_t*) calloc (bottom, sizeof (pthread_t)); + /* + * Allocate the suspended threads array. This array is used + * to guarentee idempotency + */ + bottom = 10; + array = (pthread_t*) calloc(bottom, sizeof(pthread_t)); - /* - * Install the signal handlers for suspend/resume. - */ - sigusr1.sa_flags = 0; - sigusr1.sa_handler = suspend_signal_handler; + /* + * Install the signal handlers for suspend/resume. + */ + sigusr1.sa_flags = 0; + sigusr1.sa_handler = suspend_signal_handler; - sigemptyset (&sigusr1.sa_mask); - sigusr2.sa_flags = 0; - sigusr2.sa_handler = resume_signal_handler; - sigusr2.sa_mask = sigusr1.sa_mask; + sigemptyset(&sigusr1.sa_mask); + sigusr2.sa_flags = 0; + sigusr2.sa_handler = resume_signal_handler; + sigusr2.sa_mask = sigusr1.sa_mask; - status = sigaction (SIGUSR1, &sigusr1, NULL); - if (status == -1) - errno_abort ("Installing suspend handler"); - - status = sigaction (SIGUSR2, &sigusr2, NULL); - if (status == -1) - errno_abort ("Installing resume handler"); - - inited = 1; - return; + status = sigaction(SIGUSR1, &sigusr1, NULL); + if (status == -1) + errno_abort("Installing suspend handler"); + + status = sigaction(SIGUSR2, &sigusr2, NULL); + if (status == -1) + errno_abort("Installing resume handler"); + + inited = 1; + return; } /* @@ -122,79 +122,76 @@ suspend_init_routine (void) * additional effect on the thread -- a single thd_continue * call will cause it to resume execution. */ -int -thd_suspend (pthread_t target_thread) +int +thd_suspend(pthread_t target_thread) { - int status; - int i = 0; + int status; + int i = 0; - /* - * The first call to thd_suspend will initialize the - * package. - */ - status = pthread_once (&once, suspend_init_routine); - if (status != 0) - return status; - - /* - * Serialize access to suspend, makes life easier - */ - status = pthread_mutex_lock (&mut); - if (status != 0) - return status; - - /* - * Threads that are suspended are added to the target_array; - * a request to suspend a thread already listed in the array - * is ignored. Sending a second SIGUSR1 would cause the - * thread to re-suspend itself as soon as it is resumed. - */ - while (i < bottom) - if (array[i++] == target_thread) { - status = pthread_mutex_unlock (&mut); - return status; - } - - /* - * Ok, we really need to suspend this thread. So, lets find - * the location in the array that we'll use. If we run off - * the end, realloc the array for more space. - */ - i = 0; - while (array[i] != 0) - i++; - - if (i == bottom) { - array = (pthread_t*) realloc ( - array, (++bottom * sizeof (pthread_t))); - if (array == NULL) { - pthread_mutex_unlock (&mut); - return errno; - } - - array[bottom] = null_pthread; /* Clear new entry */ - } - - /* - * Clear the sentinel and signal the thread to suspend. - */ - sentinel = 0; - status = pthread_kill (target_thread, SIGUSR1); - if (status != 0) { - pthread_mutex_unlock (&mut); - return status; - } - - /* - * Wait for the sentinel to change. - */ - while (sentinel == 0) - sched_yield (); - - array[i] = target_thread; - - status = pthread_mutex_unlock (&mut); + /* + * The first call to thd_suspend will initialize the + * package. + */ + status = pthread_once(&once, suspend_init_routine); + if (status != 0) return status; + + /* + * Serialize access to suspend, makes life easier + */ + status = pthread_mutex_lock(&mut); + if (status != 0) + return status; + + /* + * Threads that are suspended are added to the target_array; + * a request to suspend a thread already listed in the array + * is ignored. Sending a second SIGUSR1 would cause the + * thread to re-suspend itself as soon as it is resumed. + */ + while (i < bottom) + if (array[i++] == target_thread) { + status = pthread_mutex_unlock(&mut); + return status; + } + + /* + * Ok, we really need to suspend this thread. So, lets find + * the location in the array that we'll use. If we run off + * the end, realloc the array for more space. + */ + i = 0; + while (array[i] != 0) i++; + + if (i == bottom) { + array = (pthread_t*) realloc(array, (++bottom * sizeof(pthread_t))); + if (array == NULL) { + pthread_mutex_unlock(&mut); + return errno; + } + + array[bottom] = null_pthread; /* Clear new entry */ + } + + /* + * Clear the sentinel and signal the thread to suspend. + */ + sentinel = 0; + status = pthread_kill(target_thread, SIGUSR1); + if (status != 0) { + pthread_mutex_unlock(&mut); + return status; + } + + /* + * Wait for the sentinel to change. + */ + while (sentinel == 0) sched_yield(); + + array[i] = target_thread; + + status = pthread_mutex_unlock(&mut); + return status; } /* @@ -202,141 +199,136 @@ thd_suspend (pthread_t target_thread) * it out of the sigsuspend() in which it's waiting. If the * target thread isn't suspended, return with success. */ -int -thd_continue (pthread_t target_thread) +int +thd_continue(pthread_t target_thread) { - int status; - int i = 0; + int status; + int i = 0; - /* - * Serialize access to suspend, makes life easier - */ - status = pthread_mutex_lock (&mut); - if (status != 0) - return status; - - /* - * If we haven't been initialized, then the thread must be "resumed" - * it couldn't have been suspended! - */ - if (!inited) { - status = pthread_mutex_unlock (&mut); - return status; - } - - /* - * Make sure the thread is in the suspend array. If not, it - * hasn't been suspended (or it has already been resumed) and - * we can just carry on. - */ - while (array[i] != target_thread && i < bottom) - i++; - - if (i >= bottom) { - pthread_mutex_unlock (&mut); - return 0; - } - - /* - * Signal the thread to continue, and remove the thread from - * the suspended array. - */ - status = pthread_kill (target_thread, SIGUSR2); - if (status != 0) { - pthread_mutex_unlock (&mut); - return status; - } - - array[i] = 0; /* Clear array element */ - status = pthread_mutex_unlock (&mut); + /* + * Serialize access to suspend, makes life easier + */ + status = pthread_mutex_lock(&mut); + if (status != 0) return status; + + /* + * If we haven't been initialized, then the thread must be "resumed" + * it couldn't have been suspended! + */ + if (!inited) { + status = pthread_mutex_unlock(&mut); + return status; + } + + /* + * Make sure the thread is in the suspend array. If not, it + * hasn't been suspended (or it has already been resumed) and + * we can just carry on. + */ + while (array[i] != target_thread && i < bottom) i++; + + if (i >= bottom) { + pthread_mutex_unlock(&mut); + return 0; + } + + /* + * Signal the thread to continue, and remove the thread from + * the suspended array. + */ + status = pthread_kill(target_thread, SIGUSR2); + if (status != 0) { + pthread_mutex_unlock(&mut); + return status; + } + + array[i] = 0; /* Clear array element */ + status = pthread_mutex_unlock(&mut); + return status; } -static void * -thread_routine (void *arg) +static void* +thread_routine(void* arg) { - int number = (int)arg; - int status; - int i; - char buffer[128]; + int number = (int) arg; + int status; + int i; + char buffer[128]; - for (i = 1; i <= iterations; i++) { - /* - * Every time each thread does 5000 interations, print - * a progress report. - */ - if (i % 2000 == 0) { - sprintf ( - buffer, "Thread %02d: %d\n", - number, i); - write (1, buffer, strlen (buffer)); - } - - sched_yield (); + for (i = 1; i <= iterations; i++) { + /* + * Every time each thread does 5000 interations, print + * a progress report. + */ + if (i % 2000 == 0) { + sprintf(buffer, "Thread %02d: %d\n", number, i); + write(1, buffer, strlen(buffer)); } - return (void *)0; + sched_yield(); + } + + return (void*) 0; } int -main (int argc, char *argv[]) +main(int argc, char* argv[]) { - pthread_t threads[THREAD_COUNT]; - pthread_attr_t detach; - int status; - void *result; - int i; + pthread_t threads[THREAD_COUNT]; + pthread_attr_t detach; + int status; + void* result; + int i; - status = pthread_attr_init (&detach); + status = pthread_attr_init(&detach); + if (status != 0) + err_abort(status, "Init attributes object"); + status = pthread_attr_setdetachstate(&detach, PTHREAD_CREATE_DETACHED); + if (status != 0) + err_abort(status, "Set create-detached"); + + for (i = 0; i < THREAD_COUNT; i++) { + status = pthread_create(&threads[i], &detach, thread_routine, (void*) i); if (status != 0) - err_abort (status, "Init attributes object"); - status = pthread_attr_setdetachstate ( - &detach, PTHREAD_CREATE_DETACHED); + err_abort(status, "Create thread"); + } + + sleep(2); + + for (i = 0; i < THREAD_COUNT / 2; i++) { + printf("Suspending thread %d.\n", i); + status = thd_suspend(threads[i]); if (status != 0) - err_abort (status, "Set create-detached"); + err_abort(status, "Suspend thread"); + } - for (i = 0; i< THREAD_COUNT; i++) { - status = pthread_create ( - &threads[i], &detach, thread_routine, (void *)i); - if (status != 0) - err_abort (status, "Create thread"); - } + printf("Sleeping ...\n"); + sleep(2); - sleep (2); + for (i = 0; i < THREAD_COUNT / 2; i++) { + printf("Continuing thread %d.\n", i); + status = thd_continue(threads[i]); + if (status != 0) + err_abort(status, "Suspend thread"); + } - for (i = 0; i < THREAD_COUNT/2; i++) { - printf ("Suspending thread %d.\n", i); - status = thd_suspend (threads[i]); - if (status != 0) - err_abort (status, "Suspend thread"); - } + for (i = THREAD_COUNT / 2; i < THREAD_COUNT; i++) { + printf("Suspending thread %d.\n", i); + status = thd_suspend(threads[i]); + if (status != 0) + err_abort(status, "Suspend thread"); + } - printf ("Sleeping ...\n"); - sleep (2); + printf("Sleeping ...\n"); + sleep(2); - for (i = 0; i < THREAD_COUNT/2; i++) { - printf ("Continuing thread %d.\n", i); - status = thd_continue (threads[i]); - if (status != 0) - err_abort (status, "Suspend thread"); - } + for (i = THREAD_COUNT / 2; i < THREAD_COUNT; i++) { + printf("Continuing thread %d.\n", i); + status = thd_continue(threads[i]); + if (status != 0) + err_abort(status, "Continue thread"); + } - for (i = THREAD_COUNT/2; i < THREAD_COUNT; i++) { - printf ("Suspending thread %d.\n", i); - status = thd_suspend (threads[i]); - if (status != 0) - err_abort (status, "Suspend thread"); - } - - printf ("Sleeping ...\n"); - sleep (2); - - for (i = THREAD_COUNT/2; i < THREAD_COUNT; i++) { - printf ("Continuing thread %d.\n", i); - status = thd_continue (threads[i]); - if (status != 0) - err_abort (status, "Continue thread"); - } - - pthread_exit (NULL); /* Let threads finish */ + pthread_exit(NULL); /* Let threads finish */ } diff --git a/src/ch07/barrier.c b/src/ch07/barrier.c index 06cba29..866925b 100644 --- a/src/ch07/barrier.c +++ b/src/ch07/barrier.c @@ -20,66 +20,68 @@ * to do something in a serial region before entering another * parallel section of code. */ +#include "barrier.h" #include #include "errors.h" -#include "barrier.h" /* * Initialize a barrier for use. */ -int barrier_init (barrier_t *barrier, int count) +int +barrier_init(barrier_t* barrier, int count) { - int status; + int status; - barrier->threshold = barrier->counter = count; - barrier->cycle = 0; - status = pthread_mutex_init (&barrier->mutex, NULL); - if (status != 0) - return status; - status = pthread_cond_init (&barrier->cv, NULL); - if (status != 0) { - pthread_mutex_destroy (&barrier->mutex); - return status; - } - barrier->valid = BARRIER_VALID; - return 0; + barrier->threshold = barrier->counter = count; + barrier->cycle = 0; + status = pthread_mutex_init(&barrier->mutex, NULL); + if (status != 0) + return status; + status = pthread_cond_init(&barrier->cv, NULL); + if (status != 0) { + pthread_mutex_destroy(&barrier->mutex); + return status; + } + barrier->valid = BARRIER_VALID; + return 0; } /* * Destroy a barrier when done using it. */ -int barrier_destroy (barrier_t *barrier) +int +barrier_destroy(barrier_t* barrier) { - int status, status2; + int status, status2; - if (barrier->valid != BARRIER_VALID) - return EINVAL; + if (barrier->valid != BARRIER_VALID) + return EINVAL; - status = pthread_mutex_lock (&barrier->mutex); - if (status != 0) - return status; + status = pthread_mutex_lock(&barrier->mutex); + if (status != 0) + return status; - /* - * Check whether any threads are known to be waiting; report - * "BUSY" if so. - */ - if (barrier->counter != barrier->threshold) { - pthread_mutex_unlock (&barrier->mutex); - return EBUSY; - } + /* + * Check whether any threads are known to be waiting; report + * "BUSY" if so. + */ + if (barrier->counter != barrier->threshold) { + pthread_mutex_unlock(&barrier->mutex); + return EBUSY; + } - barrier->valid = 0; - status = pthread_mutex_unlock (&barrier->mutex); - if (status != 0) - return status; + barrier->valid = 0; + status = pthread_mutex_unlock(&barrier->mutex); + if (status != 0) + return status; - /* - * If unable to destroy either 1003.1c synchronization - * object, return the error status. - */ - status = pthread_mutex_destroy (&barrier->mutex); - status2 = pthread_cond_destroy (&barrier->cv); - return (status == 0 ? status : status2); + /* + * If unable to destroy either 1003.1c synchronization + * object, return the error status. + */ + status = pthread_mutex_destroy(&barrier->mutex); + status2 = pthread_cond_destroy(&barrier->cv); + return (status == 0 ? status : status2); } /* @@ -87,58 +89,60 @@ int barrier_destroy (barrier_t *barrier) * the count (of remaining members) reaches 0, broadcast to wake * all threads waiting. */ -int barrier_wait (barrier_t *barrier) +int +barrier_wait(barrier_t* barrier) { - int status, cancel, tmp, cycle; + int status, cancel, tmp, cycle; - if (barrier->valid != BARRIER_VALID) - return EINVAL; + if (barrier->valid != BARRIER_VALID) + return EINVAL; - status = pthread_mutex_lock (&barrier->mutex); - if (status != 0) - return status; + status = pthread_mutex_lock(&barrier->mutex); + if (status != 0) + return status; - cycle = barrier->cycle; /* Remember which cycle we're on */ + cycle = barrier->cycle; /* Remember which cycle we're on */ - if (--barrier->counter == 0) { - barrier->cycle = !barrier->cycle; - barrier->counter = barrier->threshold; - status = pthread_cond_broadcast (&barrier->cv); - /* - * The last thread into the barrier will return status - * -1 rather than 0, so that it can be used to perform - * some special serial code following the barrier. - */ - if (status == 0) - status = -1; - } else { - /* - * Wait with cancellation disabled, because barrier_wait - * should not be a cancellation point. - */ - pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &cancel); - - /* - * Wait until the barrier's cycle changes, which means - * that it has been broadcast, and we don't want to wait - * anymore. - */ - while (cycle == barrier->cycle) { - status = pthread_cond_wait ( - &barrier->cv, &barrier->mutex); - if (status != 0) break; - } - - pthread_setcancelstate (cancel, &tmp); - } + if (--barrier->counter == 0) { + barrier->cycle = !barrier->cycle; + barrier->counter = barrier->threshold; + status = pthread_cond_broadcast(&barrier->cv); /* - * Ignore an error in unlocking. It shouldn't happen, and - * reporting it here would be misleading -- the barrier wait - * completed, after all, whereas returning, for example, - * EINVAL would imply the wait had failed. The next attempt - * to use the barrier *will* return an error, or hang, due - * to whatever happened to the mutex. + * The last thread into the barrier will return status + * -1 rather than 0, so that it can be used to perform + * some special serial code following the barrier. */ - pthread_mutex_unlock (&barrier->mutex); - return status; /* error, -1 for waker, or 0 */ + if (status == 0) + status = -1; + } + else { + /* + * Wait with cancellation disabled, because barrier_wait + * should not be a cancellation point. + */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel); + + /* + * Wait until the barrier's cycle changes, which means + * that it has been broadcast, and we don't want to wait + * anymore. + */ + while (cycle == barrier->cycle) { + status = pthread_cond_wait(&barrier->cv, &barrier->mutex); + if (status != 0) + break; + } + + pthread_setcancelstate(cancel, &tmp); + } + /* + * Ignore an error in unlocking. It shouldn't happen, and + * reporting it here would be misleading -- the barrier wait + * completed, after all, whereas returning, for example, + * EINVAL would imply the wait had failed. The next attempt + * to use the barrier *will* return an error, or hang, due + * to whatever happened to the mutex. + */ + pthread_mutex_unlock(&barrier->mutex); + return status; /* error, -1 for waker, or 0 */ } diff --git a/src/ch07/barrier.h b/src/ch07/barrier.h index 4e3fa21..f72e2a8 100644 --- a/src/ch07/barrier.h +++ b/src/ch07/barrier.h @@ -17,26 +17,28 @@ * Structure describing a barrier. */ typedef struct barrier_tag { - pthread_mutex_t mutex; /* Control access to barrier */ - pthread_cond_t cv; /* wait for barrier */ - int valid; /* set when valid */ - int threshold; /* number of threads required */ - int counter; /* current number of threads */ - int cycle; /* alternate wait cycles (0 or 1) */ + pthread_mutex_t mutex; /* Control access to barrier */ + pthread_cond_t cv; /* wait for barrier */ + int valid; /* set when valid */ + int threshold; /* number of threads required */ + int counter; /* current number of threads */ + int cycle; /* alternate wait cycles (0 or 1) */ } barrier_t; -#define BARRIER_VALID 0xdbcafe +#define BARRIER_VALID 0xdbcafe /* * Support static initialization of barriers */ -#define BARRIER_INITIALIZER(cnt) \ - {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \ - BARRIER_VALID, cnt, cnt, 0} +#define BARRIER_INITIALIZER(cnt) \ + { \ + PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, BARRIER_VALID, cnt, \ + cnt, 0 \ + } /* * Define barrier functions */ -extern int barrier_init (barrier_t *barrier, int count); -extern int barrier_destroy (barrier_t *barrier); -extern int barrier_wait (barrier_t *barrier); +extern int barrier_init(barrier_t* barrier, int count); +extern int barrier_destroy(barrier_t* barrier); +extern int barrier_wait(barrier_t* barrier); diff --git a/src/ch07/barrier_main.c b/src/ch07/barrier_main.c index eb86abd..ca065ce 100644 --- a/src/ch07/barrier_main.c +++ b/src/ch07/barrier_main.c @@ -17,11 +17,11 @@ * Keep track of each thread */ typedef struct thread_tag { - pthread_t thread_id; - int number; - int increment; - int array[ARRAY]; - } thread_t; + pthread_t thread_id; + int number; + int increment; + int array[ARRAY]; +} thread_t; barrier_t barrier; thread_t thread[THREADS]; @@ -29,87 +29,91 @@ thread_t thread[THREADS]; /* * Start routine for threads. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - thread_t *self = (thread_t*)arg; /* Thread's thread_t */ - int in_loop, out_loop, count, status; - + thread_t* self = (thread_t*) arg; /* Thread's thread_t */ + int in_loop, out_loop, count, status; + + /* + * Loop through OUTLOOPS barrier cycles. + */ + for (out_loop = 0; out_loop < OUTLOOPS; out_loop++) { + status = barrier_wait(&barrier); + if (status > 0) + err_abort(status, "Wait on barrier"); + /* - * Loop through OUTLOOPS barrier cycles. + * This inner loop just adds a value to each element in + * the working array. */ - for (out_loop = 0; out_loop < OUTLOOPS; out_loop++) { - status = barrier_wait (&barrier); - if (status > 0) - err_abort (status, "Wait on barrier"); + for (in_loop = 0; in_loop < INLOOPS; in_loop++) + for (count = 0; count < ARRAY; count++) + self->array[count] += self->increment; - /* - * This inner loop just adds a value to each element in - * the working array. - */ - for (in_loop = 0; in_loop < INLOOPS; in_loop++) - for (count = 0; count < ARRAY; count++) - self->array[count] += self->increment; + status = barrier_wait(&barrier); + if (status > 0) + err_abort(status, "Wait on barrier"); - status = barrier_wait (&barrier); - if (status > 0) - err_abort (status, "Wait on barrier"); + /* + * The barrier causes one thread to return with the + * special return status -1. The thread receiving this + * value increments each element in the shared array. + */ + if (status == -1) { + int thread_num; - /* - * The barrier causes one thread to return with the - * special return status -1. The thread receiving this - * value increments each element in the shared array. - */ - if (status == -1) { - int thread_num; - - for (thread_num = 0; thread_num < THREADS; thread_num++) - thread[thread_num].increment += 1; - } + for (thread_num = 0; thread_num < THREADS; thread_num++) + thread[thread_num].increment += 1; } - return NULL; + } + return NULL; } -int main (int arg, char *argv[]) +int +main(int arg, char* argv[]) { - int thread_count, array_count; - int status; + int thread_count, array_count; + int status; - barrier_init (&barrier, THREADS); + barrier_init(&barrier, THREADS); - /* - * Create a set of threads that will use the barrier. - */ - for (thread_count = 0; thread_count < THREADS; thread_count++) { - thread[thread_count].increment = thread_count; - thread[thread_count].number = thread_count; + /* + * Create a set of threads that will use the barrier. + */ + for (thread_count = 0; thread_count < THREADS; thread_count++) { + thread[thread_count].increment = thread_count; + thread[thread_count].number = thread_count; - for (array_count = 0; array_count < ARRAY; array_count++) - thread[thread_count].array[array_count] = array_count + 1; + for (array_count = 0; array_count < ARRAY; array_count++) + thread[thread_count].array[array_count] = array_count + 1; - status = pthread_create (&thread[thread_count].thread_id, - NULL, thread_routine, (void*)&thread[thread_count]); - if (status != 0) - err_abort (status, "Create thread"); - } + status = pthread_create(&thread[thread_count].thread_id, + NULL, + thread_routine, + (void*) &thread[thread_count]); + if (status != 0) + err_abort(status, "Create thread"); + } - /* - * Now join with each of the threads. - */ - for (thread_count = 0; thread_count < THREADS; thread_count++) { - status = pthread_join (thread[thread_count].thread_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); + /* + * Now join with each of the threads. + */ + for (thread_count = 0; thread_count < THREADS; thread_count++) { + status = pthread_join(thread[thread_count].thread_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); - printf ("%02d: (%d) ", thread_count, thread[thread_count].increment); + printf("%02d: (%d) ", thread_count, thread[thread_count].increment); - for (array_count = 0; array_count < ARRAY; array_count++) - printf ("%010u ", thread[thread_count].array[array_count]); - printf ("\n"); - } + for (array_count = 0; array_count < ARRAY; array_count++) + printf("%010u ", thread[thread_count].array[array_count]); + printf("\n"); + } - /* - * To be thorough, destroy the barrier. - */ - barrier_destroy (&barrier); - return 0; + /* + * To be thorough, destroy the barrier. + */ + barrier_destroy(&barrier); + return 0; } diff --git a/src/ch07/rwlock.c b/src/ch07/rwlock.c index bbcc2a8..89afdd9 100644 --- a/src/ch07/rwlock.c +++ b/src/ch07/rwlock.c @@ -21,79 +21,81 @@ * lock. rwl_writetrylock() attempts to lock a read-write lock * for write access, and returns EBUSY instead of blocking. */ +#include "rwlock.h" #include #include "errors.h" -#include "rwlock.h" /* * Initialize a read-write lock */ -int rwl_init (rwlock_t *rwl) +int +rwl_init(rwlock_t* rwl) { - int status; + int status; - rwl->r_active = 0; - rwl->r_wait = rwl->w_wait = 0; - rwl->w_active = 0; - status = pthread_mutex_init (&rwl->mutex, NULL); - if (status != 0) - return status; - status = pthread_cond_init (&rwl->read, NULL); - if (status != 0) { - /* if unable to create read CV, destroy mutex */ - pthread_mutex_destroy (&rwl->mutex); - return status; - } - status = pthread_cond_init (&rwl->write, NULL); - if (status != 0) { - /* if unable to create write CV, destroy read CV and mutex */ - pthread_cond_destroy (&rwl->read); - pthread_mutex_destroy (&rwl->mutex); - return status; - } - rwl->valid = RWLOCK_VALID; - return 0; + rwl->r_active = 0; + rwl->r_wait = rwl->w_wait = 0; + rwl->w_active = 0; + status = pthread_mutex_init(&rwl->mutex, NULL); + if (status != 0) + return status; + status = pthread_cond_init(&rwl->read, NULL); + if (status != 0) { + /* if unable to create read CV, destroy mutex */ + pthread_mutex_destroy(&rwl->mutex); + return status; + } + status = pthread_cond_init(&rwl->write, NULL); + if (status != 0) { + /* if unable to create write CV, destroy read CV and mutex */ + pthread_cond_destroy(&rwl->read); + pthread_mutex_destroy(&rwl->mutex); + return status; + } + rwl->valid = RWLOCK_VALID; + return 0; } /* * Destroy a read-write lock */ -int rwl_destroy (rwlock_t *rwl) +int +rwl_destroy(rwlock_t* rwl) { - int status, status1, status2; + int status, status1, status2; - if (rwl->valid != RWLOCK_VALID) - return EINVAL; - status = pthread_mutex_lock (&rwl->mutex); - if (status != 0) - return status; + if (rwl->valid != RWLOCK_VALID) + return EINVAL; + status = pthread_mutex_lock(&rwl->mutex); + if (status != 0) + return status; - /* - * Check whether any threads own the lock; report "BUSY" if - * so. - */ - if (rwl->r_active > 0 || rwl->w_active) { - pthread_mutex_unlock (&rwl->mutex); - return EBUSY; - } + /* + * Check whether any threads own the lock; report "BUSY" if + * so. + */ + if (rwl->r_active > 0 || rwl->w_active) { + pthread_mutex_unlock(&rwl->mutex); + return EBUSY; + } - /* - * Check whether any threads are known to be waiting; report - * EBUSY if so. - */ - if (rwl->r_wait != 0 || rwl->w_wait != 0) { - pthread_mutex_unlock (&rwl->mutex); - return EBUSY; - } + /* + * Check whether any threads are known to be waiting; report + * EBUSY if so. + */ + if (rwl->r_wait != 0 || rwl->w_wait != 0) { + pthread_mutex_unlock(&rwl->mutex); + return EBUSY; + } - rwl->valid = 0; - status = pthread_mutex_unlock (&rwl->mutex); - if (status != 0) - return status; - status = pthread_mutex_destroy (&rwl->mutex); - status1 = pthread_cond_destroy (&rwl->read); - status2 = pthread_cond_destroy (&rwl->write); - return (status == 0 ? status : (status1 == 0 ? status1 : status2)); + rwl->valid = 0; + status = pthread_mutex_unlock(&rwl->mutex); + if (status != 0) + return status; + status = pthread_mutex_destroy(&rwl->mutex); + status1 = pthread_cond_destroy(&rwl->read); + status2 = pthread_cond_destroy(&rwl->write); + return (status == 0 ? status : (status1 == 0 ? status1 : status2)); } /* @@ -103,81 +105,85 @@ int rwl_destroy (rwlock_t *rwl) * Simply record that the thread is no longer waiting, * and unlock the mutex. */ -static void rwl_readcleanup (void *arg) +static void +rwl_readcleanup(void* arg) { - rwlock_t *rwl = (rwlock_t *)arg; + rwlock_t* rwl = (rwlock_t*) arg; - rwl->r_wait--; - pthread_mutex_unlock (&rwl->mutex); + rwl->r_wait--; + pthread_mutex_unlock(&rwl->mutex); } /* * Lock a read-write lock for read access. */ -int rwl_readlock (rwlock_t *rwl) +int +rwl_readlock(rwlock_t* rwl) { - int status; + int status; - if (rwl->valid != RWLOCK_VALID) - return EINVAL; - status = pthread_mutex_lock (&rwl->mutex); - if (status != 0) - return status; - if (rwl->w_active) { - rwl->r_wait++; - pthread_cleanup_push (rwl_readcleanup, (void*)rwl); - while (rwl->w_active) { - status = pthread_cond_wait (&rwl->read, &rwl->mutex); - if (status != 0) - break; - } - pthread_cleanup_pop (0); - rwl->r_wait--; - } - if (status == 0) - rwl->r_active++; - pthread_mutex_unlock (&rwl->mutex); + if (rwl->valid != RWLOCK_VALID) + return EINVAL; + status = pthread_mutex_lock(&rwl->mutex); + if (status != 0) return status; + if (rwl->w_active) { + rwl->r_wait++; + pthread_cleanup_push(rwl_readcleanup, (void*) rwl); + while (rwl->w_active) { + status = pthread_cond_wait(&rwl->read, &rwl->mutex); + if (status != 0) + break; + } + pthread_cleanup_pop(0); + rwl->r_wait--; + } + if (status == 0) + rwl->r_active++; + pthread_mutex_unlock(&rwl->mutex); + return status; } /* * Attempt to lock a read-write lock for read access (don't * block if unavailable). */ -int rwl_readtrylock (rwlock_t *rwl) +int +rwl_readtrylock(rwlock_t* rwl) { - int status, status2; + int status, status2; - if (rwl->valid != RWLOCK_VALID) - return EINVAL; - status = pthread_mutex_lock (&rwl->mutex); - if (status != 0) - return status; - if (rwl->w_active) - status = EBUSY; - else - rwl->r_active++; - status2 = pthread_mutex_unlock (&rwl->mutex); - return (status2 != 0 ? status2 : status); + if (rwl->valid != RWLOCK_VALID) + return EINVAL; + status = pthread_mutex_lock(&rwl->mutex); + if (status != 0) + return status; + if (rwl->w_active) + status = EBUSY; + else + rwl->r_active++; + status2 = pthread_mutex_unlock(&rwl->mutex); + return (status2 != 0 ? status2 : status); } /* * Unlock a read-write lock from read access. */ -int rwl_readunlock (rwlock_t *rwl) +int +rwl_readunlock(rwlock_t* rwl) { - int status, status2; + int status, status2; - if (rwl->valid != RWLOCK_VALID) - return EINVAL; - status = pthread_mutex_lock (&rwl->mutex); - if (status != 0) - return status; - rwl->r_active--; - if (rwl->r_active == 0 && rwl->w_wait > 0) - status = pthread_cond_signal (&rwl->write); - status2 = pthread_mutex_unlock (&rwl->mutex); - return (status2 == 0 ? status : status2); + if (rwl->valid != RWLOCK_VALID) + return EINVAL; + status = pthread_mutex_lock(&rwl->mutex); + if (status != 0) + return status; + rwl->r_active--; + if (rwl->r_active == 0 && rwl->w_wait > 0) + status = pthread_cond_signal(&rwl->write); + status2 = pthread_mutex_unlock(&rwl->mutex); + return (status2 == 0 ? status : status2); } /* @@ -187,90 +193,95 @@ int rwl_readunlock (rwlock_t *rwl) * Simply record that the thread is no longer waiting, * and unlock the mutex. */ -static void rwl_writecleanup (void *arg) +static void +rwl_writecleanup(void* arg) { - rwlock_t *rwl = (rwlock_t *)arg; + rwlock_t* rwl = (rwlock_t*) arg; - rwl->w_wait--; - pthread_mutex_unlock (&rwl->mutex); + rwl->w_wait--; + pthread_mutex_unlock(&rwl->mutex); } /* * Lock a read-write lock for write access. */ -int rwl_writelock (rwlock_t *rwl) +int +rwl_writelock(rwlock_t* rwl) { - int status; + int status; - if (rwl->valid != RWLOCK_VALID) - return EINVAL; - status = pthread_mutex_lock (&rwl->mutex); - if (status != 0) - return status; - if (rwl->w_active || rwl->r_active > 0) { - rwl->w_wait++; - pthread_cleanup_push (rwl_writecleanup, (void*)rwl); - while (rwl->w_active || rwl->r_active > 0) { - status = pthread_cond_wait (&rwl->write, &rwl->mutex); - if (status != 0) - break; - } - pthread_cleanup_pop (0); - rwl->w_wait--; - } - if (status == 0) - rwl->w_active = 1; - pthread_mutex_unlock (&rwl->mutex); + if (rwl->valid != RWLOCK_VALID) + return EINVAL; + status = pthread_mutex_lock(&rwl->mutex); + if (status != 0) return status; + if (rwl->w_active || rwl->r_active > 0) { + rwl->w_wait++; + pthread_cleanup_push(rwl_writecleanup, (void*) rwl); + while (rwl->w_active || rwl->r_active > 0) { + status = pthread_cond_wait(&rwl->write, &rwl->mutex); + if (status != 0) + break; + } + pthread_cleanup_pop(0); + rwl->w_wait--; + } + if (status == 0) + rwl->w_active = 1; + pthread_mutex_unlock(&rwl->mutex); + return status; } /* * Attempt to lock a read-write lock for write access. Don't * block if unavailable. */ -int rwl_writetrylock (rwlock_t *rwl) +int +rwl_writetrylock(rwlock_t* rwl) { - int status, status2; + int status, status2; - if (rwl->valid != RWLOCK_VALID) - return EINVAL; - status = pthread_mutex_lock (&rwl->mutex); - if (status != 0) - return status; - if (rwl->w_active || rwl->r_active > 0) - status = EBUSY; - else - rwl->w_active = 1; - status2 = pthread_mutex_unlock (&rwl->mutex); - return (status != 0 ? status : status2); + if (rwl->valid != RWLOCK_VALID) + return EINVAL; + status = pthread_mutex_lock(&rwl->mutex); + if (status != 0) + return status; + if (rwl->w_active || rwl->r_active > 0) + status = EBUSY; + else + rwl->w_active = 1; + status2 = pthread_mutex_unlock(&rwl->mutex); + return (status != 0 ? status : status2); } /* * Unlock a read-write lock from write access. */ -int rwl_writeunlock (rwlock_t *rwl) +int +rwl_writeunlock(rwlock_t* rwl) { - int status; + int status; - if (rwl->valid != RWLOCK_VALID) - return EINVAL; - status = pthread_mutex_lock (&rwl->mutex); - if (status != 0) - return status; - rwl->w_active = 0; - if (rwl->r_wait > 0) { - status = pthread_cond_broadcast (&rwl->read); - if (status != 0) { - pthread_mutex_unlock (&rwl->mutex); - return status; - } - } else if (rwl->w_wait > 0) { - status = pthread_cond_signal (&rwl->write); - if (status != 0) { - pthread_mutex_unlock (&rwl->mutex); - return status; - } - } - status = pthread_mutex_unlock (&rwl->mutex); + if (rwl->valid != RWLOCK_VALID) + return EINVAL; + status = pthread_mutex_lock(&rwl->mutex); + if (status != 0) return status; + rwl->w_active = 0; + if (rwl->r_wait > 0) { + status = pthread_cond_broadcast(&rwl->read); + if (status != 0) { + pthread_mutex_unlock(&rwl->mutex); + return status; + } + } + else if (rwl->w_wait > 0) { + status = pthread_cond_signal(&rwl->write); + if (status != 0) { + pthread_mutex_unlock(&rwl->mutex); + return status; + } + } + status = pthread_mutex_unlock(&rwl->mutex); + return status; } diff --git a/src/ch07/rwlock.h b/src/ch07/rwlock.h index 5ab1801..7ef32f6 100644 --- a/src/ch07/rwlock.h +++ b/src/ch07/rwlock.h @@ -17,33 +17,35 @@ * Structure describing a read-write lock. */ typedef struct rwlock_tag { - pthread_mutex_t mutex; - pthread_cond_t read; /* wait for read */ - pthread_cond_t write; /* wait for write */ - int valid; /* set when valid */ - int r_active; /* readers active */ - int w_active; /* writer active */ - int r_wait; /* readers waiting */ - int w_wait; /* writers waiting */ + pthread_mutex_t mutex; + pthread_cond_t read; /* wait for read */ + pthread_cond_t write; /* wait for write */ + int valid; /* set when valid */ + int r_active; /* readers active */ + int w_active; /* writer active */ + int r_wait; /* readers waiting */ + int w_wait; /* writers waiting */ } rwlock_t; -#define RWLOCK_VALID 0xfacade +#define RWLOCK_VALID 0xfacade /* * Support static initialization of barriers */ -#define RWL_INITIALIZER \ - {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \ - PTHREAD_COND_INITIALIZER, RWLOCK_VALID, 0, 0, 0, 0} +#define RWL_INITIALIZER \ + { \ + PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \ + PTHREAD_COND_INITIALIZER, RWLOCK_VALID, 0, 0, 0, 0 \ + } /* * Define read-write lock functions */ -extern int rwl_init (rwlock_t *rwlock); -extern int rwl_destroy (rwlock_t *rwlock); -extern int rwl_readlock (rwlock_t *rwlock); -extern int rwl_readtrylock (rwlock_t *rwlock); -extern int rwl_readunlock (rwlock_t *rwlock); -extern int rwl_writelock (rwlock_t *rwlock); -extern int rwl_writetrylock (rwlock_t *rwlock); -extern int rwl_writeunlock (rwlock_t *rwlock); +extern int rwl_init(rwlock_t* rwlock); +extern int rwl_destroy(rwlock_t* rwlock); +extern int rwl_readlock(rwlock_t* rwlock); +extern int rwl_readtrylock(rwlock_t* rwlock); +extern int rwl_readunlock(rwlock_t* rwlock); +extern int rwl_writelock(rwlock_t* rwlock); +extern int rwl_writetrylock(rwlock_t* rwlock); +extern int rwl_writeunlock(rwlock_t* rwlock); diff --git a/src/ch07/rwlock_main.c b/src/ch07/rwlock_main.c index 3ed66b9..ec32466 100644 --- a/src/ch07/rwlock_main.c +++ b/src/ch07/rwlock_main.c @@ -8,31 +8,31 @@ * to allow interleaved thread execution, since threads are not * timesliced. */ -#include "rwlock.h" #include "errors.h" +#include "rwlock.h" -#define THREADS 5 -#define DATASIZE 15 -#define ITERATIONS 10000 +#define THREADS 5 +#define DATASIZE 15 +#define ITERATIONS 10000 /* * Keep statistics for each thread. */ typedef struct thread_tag { - int thread_num; - pthread_t thread_id; - int updates; - int reads; - int interval; + int thread_num; + pthread_t thread_id; + int updates; + int reads; + int interval; } thread_t; /* * Read-write lock and shared data */ typedef struct data_tag { - rwlock_t lock; - int data; - int updates; + rwlock_t lock; + int data; + int updates; } data_t; thread_t threads[THREADS]; @@ -41,127 +41,135 @@ data_t data[DATASIZE]; /* * Thread start routine that uses read-write locks */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - thread_t *self = (thread_t*)arg; - int repeats = 0; - int iteration; - int element = 0; - int status; + thread_t* self = (thread_t*) arg; + int repeats = 0; + int iteration; + int element = 0; + int status; - for (iteration = 0; iteration < ITERATIONS; iteration++) { - /* - * Each "self->interval" iterations, perform an - * update operation (write lock instead of read - * lock). - */ - if ((iteration % self->interval) == 0) { - status = rwl_writelock (&data[element].lock); - if (status != 0) - err_abort (status, "Write lock"); - data[element].data = self->thread_num; - data[element].updates++; - self->updates++; - status = rwl_writeunlock (&data[element].lock); - if (status != 0) - err_abort (status, "Write unlock"); - } else { - /* - * Look at the current data element to see whether - * the current thread last updated it. Count the - * times, to report later. - */ - status = rwl_readlock (&data[element].lock); - if (status != 0) - err_abort (status, "Read lock"); - self->reads++; - if (data[element].data == self->thread_num) - repeats++; - status = rwl_readunlock (&data[element].lock); - if (status != 0) - err_abort (status, "Read unlock"); - } - element++; - if (element >= DATASIZE) - element = 0; + for (iteration = 0; iteration < ITERATIONS; iteration++) { + /* + * Each "self->interval" iterations, perform an + * update operation (write lock instead of read + * lock). + */ + if ((iteration % self->interval) == 0) { + status = rwl_writelock(&data[element].lock); + if (status != 0) + err_abort(status, "Write lock"); + data[element].data = self->thread_num; + data[element].updates++; + self->updates++; + status = rwl_writeunlock(&data[element].lock); + if (status != 0) + err_abort(status, "Write unlock"); } + else { + /* + * Look at the current data element to see whether + * the current thread last updated it. Count the + * times, to report later. + */ + status = rwl_readlock(&data[element].lock); + if (status != 0) + err_abort(status, "Read lock"); + self->reads++; + if (data[element].data == self->thread_num) + repeats++; + status = rwl_readunlock(&data[element].lock); + if (status != 0) + err_abort(status, "Read unlock"); + } + element++; + if (element >= DATASIZE) + element = 0; + } - if (repeats > 0) - printf ( - "Thread %d found unchanged elements %d times\n", - self->thread_num, repeats); - return NULL; + if (repeats > 0) + printf("Thread %d found unchanged elements %d times\n", + self->thread_num, + repeats); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int count; - int data_count; - int status; - unsigned int seed = 1; - int thread_updates = 0; - int data_updates = 0; + int count; + int data_count; + int status; + unsigned int seed = 1; + int thread_updates = 0; + int data_updates = 0; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our threads can run concurrently, we need to - * increase the concurrency level to THREADS. - */ - DPRINTF (("Setting concurrency level to %d\n", THREADS)); - thr_setconcurrency (THREADS); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level to THREADS. + */ + DPRINTF(("Setting concurrency level to %d\n", THREADS)); + thr_setconcurrency(THREADS); #endif - /* - * Initialize the shared data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) { - data[data_count].data = 0; - data[data_count].updates = 0; - status = rwl_init (&data[data_count].lock); - if (status != 0) - err_abort (status, "Init rw lock"); - } + /* + * Initialize the shared data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data[data_count].data = 0; + data[data_count].updates = 0; + status = rwl_init(&data[data_count].lock); + if (status != 0) + err_abort(status, "Init rw lock"); + } - /* - * Create THREADS threads to access shared data. - */ - for (count = 0; count < THREADS; count++) { - threads[count].thread_num = count; - threads[count].updates = 0; - threads[count].reads = 0; - threads[count].interval = rand_r (&seed) % 71; - status = pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)&threads[count]); - if (status != 0) - err_abort (status, "Create thread"); - } + /* + * Create THREADS threads to access shared data. + */ + for (count = 0; count < THREADS; count++) { + threads[count].thread_num = count; + threads[count].updates = 0; + threads[count].reads = 0; + threads[count].interval = rand_r(&seed) % 71; + status = pthread_create(&threads[count].thread_id, + NULL, + thread_routine, + (void*) &threads[count]); + if (status != 0) + err_abort(status, "Create thread"); + } - /* - * Wait for all threads to complete, and collect - * statistics. - */ - for (count = 0; count < THREADS; count++) { - status = pthread_join (threads[count].thread_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - thread_updates += threads[count].updates; - printf ("%02d: interval %d, updates %d, reads %d\n", - count, threads[count].interval, - threads[count].updates, threads[count].reads); - } + /* + * Wait for all threads to complete, and collect + * statistics. + */ + for (count = 0; count < THREADS; count++) { + status = pthread_join(threads[count].thread_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + thread_updates += threads[count].updates; + printf("%02d: interval %d, updates %d, reads %d\n", + count, + threads[count].interval, + threads[count].updates, + threads[count].reads); + } - /* - * Collect statistics for the data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) { - data_updates += data[data_count].updates; - printf ("data %02d: value %d, %d updates\n", - data_count, data[data_count].data, data[data_count].updates); - rwl_destroy (&data[data_count].lock); - } + /* + * Collect statistics for the data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data_updates += data[data_count].updates; + printf("data %02d: value %d, %d updates\n", + data_count, + data[data_count].data, + data[data_count].updates); + rwl_destroy(&data[data_count].lock); + } - printf ("%d thread updates, %d data updates\n", - thread_updates, data_updates); - return 0; + printf("%d thread updates, %d data updates\n", thread_updates, data_updates); + return 0; } diff --git a/src/ch07/rwlock_try_main.c b/src/ch07/rwlock_try_main.c index c6d67ac..4fa19dd 100644 --- a/src/ch07/rwlock_try_main.c +++ b/src/ch07/rwlock_try_main.c @@ -8,32 +8,32 @@ * timesliced. */ #include -#include "rwlock.h" #include "errors.h" +#include "rwlock.h" -#define THREADS 5 -#define ITERATIONS 1000 -#define DATASIZE 15 +#define THREADS 5 +#define ITERATIONS 1000 +#define DATASIZE 15 /* * Keep statistics for each thread. */ typedef struct thread_tag { - int thread_num; - pthread_t thread_id; - int r_collisions; - int w_collisions; - int updates; - int interval; + int thread_num; + pthread_t thread_id; + int r_collisions; + int w_collisions; + int updates; + int interval; } thread_t; /* * Read-write lock and shared data */ typedef struct data_tag { - rwlock_t lock; - int data; - int updates; + rwlock_t lock; + int data; + int updates; } data_t; thread_t threads[THREADS]; @@ -42,115 +42,129 @@ data_t data[DATASIZE]; /* * Thread start routine that uses read-write locks */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - thread_t *self = (thread_t*)arg; - int iteration; - int element; - int status; + thread_t* self = (thread_t*) arg; + int iteration; + int element; + int status; - element = 0; /* Current data element */ + element = 0; /* Current data element */ - for (iteration = 0; iteration < ITERATIONS; iteration++) { - if ((iteration % self->interval) == 0) { - status = rwl_writetrylock (&data[element].lock); - if (status == EBUSY) - self->w_collisions++; - else if (status == 0) { - data[element].data++; - data[element].updates++; - self->updates++; - rwl_writeunlock (&data[element].lock); - } else - err_abort (status, "Try write lock"); - } else { - status = rwl_readtrylock (&data[element].lock); - if (status == EBUSY) - self->r_collisions++; - else if (status != 0) { - err_abort (status, "Try read lock"); - } else { - if (data[element].data != data[element].updates) - printf ("%d: data[%d] %d != %d\n", - self->thread_num, element, - data[element].data, data[element].updates); - rwl_readunlock (&data[element].lock); - } - } - - element++; - if (element >= DATASIZE) - element = 0; + for (iteration = 0; iteration < ITERATIONS; iteration++) { + if ((iteration % self->interval) == 0) { + status = rwl_writetrylock(&data[element].lock); + if (status == EBUSY) + self->w_collisions++; + else if (status == 0) { + data[element].data++; + data[element].updates++; + self->updates++; + rwl_writeunlock(&data[element].lock); + } + else + err_abort(status, "Try write lock"); } - return NULL; + else { + status = rwl_readtrylock(&data[element].lock); + if (status == EBUSY) + self->r_collisions++; + else if (status != 0) { + err_abort(status, "Try read lock"); + } + else { + if (data[element].data != data[element].updates) + printf("%d: data[%d] %d != %d\n", + self->thread_num, + element, + data[element].data, + data[element].updates); + rwl_readunlock(&data[element].lock); + } + } + + element++; + if (element >= DATASIZE) + element = 0; + } + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - int count, data_count; - unsigned int seed = 1; - int thread_updates = 0, data_updates = 0; - int status; + int count, data_count; + unsigned int seed = 1; + int thread_updates = 0, data_updates = 0; + int status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our threads can run concurrently, we need to - * increase the concurrency level to THREADS. - */ - DPRINTF (("Setting concurrency level to %d\n", THREADS)); - thr_setconcurrency (THREADS); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level to THREADS. + */ + DPRINTF(("Setting concurrency level to %d\n", THREADS)); + thr_setconcurrency(THREADS); #endif - /* - * Initialize the shared data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) { - data[data_count].data = 0; - data[data_count].updates = 0; - rwl_init (&data[data_count].lock); - } + /* + * Initialize the shared data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data[data_count].data = 0; + data[data_count].updates = 0; + rwl_init(&data[data_count].lock); + } - /* - * Create THREADS threads to access shared data. - */ - for (count = 0; count < THREADS; count++) { - threads[count].thread_num = count; - threads[count].r_collisions = 0; - threads[count].w_collisions = 0; - threads[count].updates = 0; - threads[count].interval = rand_r (&seed) % ITERATIONS; - status = pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)&threads[count]); - if (status != 0) - err_abort (status, "Create thread"); - } + /* + * Create THREADS threads to access shared data. + */ + for (count = 0; count < THREADS; count++) { + threads[count].thread_num = count; + threads[count].r_collisions = 0; + threads[count].w_collisions = 0; + threads[count].updates = 0; + threads[count].interval = rand_r(&seed) % ITERATIONS; + status = pthread_create(&threads[count].thread_id, + NULL, + thread_routine, + (void*) &threads[count]); + if (status != 0) + err_abort(status, "Create thread"); + } - /* - * Wait for all threads to complete, and collect - * statistics. - */ - for (count = 0; count < THREADS; count++) { - status = pthread_join (threads[count].thread_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - thread_updates += threads[count].updates; - printf ("%02d: interval %d, updates %d, " - "r_collisions %d, w_collisions %d\n", - count, threads[count].interval, - threads[count].updates, - threads[count].r_collisions, threads[count].w_collisions); - } + /* + * Wait for all threads to complete, and collect + * statistics. + */ + for (count = 0; count < THREADS; count++) { + status = pthread_join(threads[count].thread_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + thread_updates += threads[count].updates; + printf( + "%02d: interval %d, updates %d, " + "r_collisions %d, w_collisions %d\n", + count, + threads[count].interval, + threads[count].updates, + threads[count].r_collisions, + threads[count].w_collisions); + } - /* - * Collect statistics for the data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) { - data_updates += data[data_count].updates; - printf ("data %02d: value %d, %d updates\n", - data_count, data[data_count].data, data[data_count].updates); - rwl_destroy (&data[data_count].lock); - } + /* + * Collect statistics for the data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data_updates += data[data_count].updates; + printf("data %02d: value %d, %d updates\n", + data_count, + data[data_count].data, + data[data_count].updates); + rwl_destroy(&data[data_count].lock); + } - return 0; + return 0; } diff --git a/src/ch07/workq.c b/src/ch07/workq.c index 4efa2e3..687cc1d 100644 --- a/src/ch07/workq.c +++ b/src/ch07/workq.c @@ -20,288 +20,289 @@ * processing threads will begin to shut down. (They will be * restarted when work appears.) */ +#include "workq.h" #include #include #include #include "errors.h" -#include "workq.h" /* * Thread start routine to serve the work queue. */ -static void *workq_server (void *arg) +static void* +workq_server(void* arg) { - struct timespec timeout; - workq_t *wq = (workq_t *)arg; - workq_ele_t *we; - int status, timedout; + struct timespec timeout; + workq_t* wq = (workq_t*) arg; + workq_ele_t* we; + int status, timedout; - /* - * We don't need to validate the workq_t here... we don't - * create server threads until requests are queued (the - * queue has been initialized by then!) and we wait for all - * server threads to terminate before destroying a work - * queue. - */ - DPRINTF (("A worker is starting\n")); - status = pthread_mutex_lock (&wq->mutex); - if (status != 0) + /* + * We don't need to validate the workq_t here... we don't + * create server threads until requests are queued (the + * queue has been initialized by then!) and we wait for all + * server threads to terminate before destroying a work + * queue. + */ + DPRINTF(("A worker is starting\n")); + status = pthread_mutex_lock(&wq->mutex); + if (status != 0) + return NULL; + + while (1) { + timedout = 0; + DPRINTF(("Worker waiting for work\n")); + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += 2; + + while (wq->first == NULL && !wq->quit) { + /* + * Server threads time out after spending 2 seconds + * waiting for new work, and exit. + */ + status = pthread_cond_timedwait(&wq->cv, &wq->mutex, &timeout); + if (status == ETIMEDOUT) { + DPRINTF(("Worker wait timed out\n")); + timedout = 1; + break; + } + else if (status != 0) { + /* + * This shouldn't happen, so the work queue + * package should fail. Because the work queue + * API is asynchronous, that would add + * complication. Because the chances of failure + * are slim, I choose to avoid that + * complication. The server thread will return, + * and allow another server thread to pick up + * the work later. Note that, if this was the + * only server thread, the queue won't be + * serviced until a new work item is + * queued. That could be fixed by creating a new + * server here. + */ + DPRINTF(("Worker wait failed, %d (%s)\n", status, strerror(status))); + wq->counter--; + pthread_mutex_unlock(&wq->mutex); return NULL; + } + } + DPRINTF(("Work queue: %#lx, quit: %d\n", wq->first, wq->quit)); + we = wq->first; - while (1) { - timedout = 0; - DPRINTF (("Worker waiting for work\n")); - clock_gettime (CLOCK_REALTIME, &timeout); - timeout.tv_sec += 2; - - while (wq->first == NULL && !wq->quit) { - /* - * Server threads time out after spending 2 seconds - * waiting for new work, and exit. - */ - status = pthread_cond_timedwait ( - &wq->cv, &wq->mutex, &timeout); - if (status == ETIMEDOUT) { - DPRINTF (("Worker wait timed out\n")); - timedout = 1; - break; - } else if (status != 0) { - /* - * This shouldn't happen, so the work queue - * package should fail. Because the work queue - * API is asynchronous, that would add - * complication. Because the chances of failure - * are slim, I choose to avoid that - * complication. The server thread will return, - * and allow another server thread to pick up - * the work later. Note that, if this was the - * only server thread, the queue won't be - * serviced until a new work item is - * queued. That could be fixed by creating a new - * server here. - */ - DPRINTF (( - "Worker wait failed, %d (%s)\n", - status, strerror (status))); - wq->counter--; - pthread_mutex_unlock (&wq->mutex); - return NULL; - } - } - DPRINTF (("Work queue: %#lx, quit: %d\n", wq->first, wq->quit)); - we = wq->first; - - if (we != NULL) { - wq->first = we->next; - if (wq->last == we) - wq->last = NULL; - status = pthread_mutex_unlock (&wq->mutex); - if (status != 0) - return NULL; - DPRINTF (("Worker calling engine\n")); - wq->engine (we->data); - free (we); - status = pthread_mutex_lock (&wq->mutex); - if (status != 0) - return NULL; - } - - /* - * If there are no more work requests, and the servers - * have been asked to quit, then shut down. - */ - if (wq->first == NULL && wq->quit) { - DPRINTF (("Worker shutting down\n")); - wq->counter--; - - /* - * NOTE: Just to prove that every rule has an - * exception, I'm using the "cv" condition for two - * separate predicates here. That's OK, since the - * case used here applies only once during the life - * of a work queue -- during rundown. The overhead - * is minimal and it's not worth creating a separate - * condition variable that would be waited and - * signaled exactly once! - */ - if (wq->counter == 0) - pthread_cond_broadcast (&wq->cv); - pthread_mutex_unlock (&wq->mutex); - return NULL; - } - - /* - * If there's no more work, and we wait for as long as - * we're allowed, then terminate this server thread. - */ - if (wq->first == NULL && timedout) { - DPRINTF (("engine terminating due to timeout.\n")); - wq->counter--; - break; - } + if (we != NULL) { + wq->first = we->next; + if (wq->last == we) + wq->last = NULL; + status = pthread_mutex_unlock(&wq->mutex); + if (status != 0) + return NULL; + DPRINTF(("Worker calling engine\n")); + wq->engine(we->data); + free(we); + status = pthread_mutex_lock(&wq->mutex); + if (status != 0) + return NULL; } - pthread_mutex_unlock (&wq->mutex); - DPRINTF (("Worker exiting\n")); - return NULL; + /* + * If there are no more work requests, and the servers + * have been asked to quit, then shut down. + */ + if (wq->first == NULL && wq->quit) { + DPRINTF(("Worker shutting down\n")); + wq->counter--; + + /* + * NOTE: Just to prove that every rule has an + * exception, I'm using the "cv" condition for two + * separate predicates here. That's OK, since the + * case used here applies only once during the life + * of a work queue -- during rundown. The overhead + * is minimal and it's not worth creating a separate + * condition variable that would be waited and + * signaled exactly once! + */ + if (wq->counter == 0) + pthread_cond_broadcast(&wq->cv); + pthread_mutex_unlock(&wq->mutex); + return NULL; + } + + /* + * If there's no more work, and we wait for as long as + * we're allowed, then terminate this server thread. + */ + if (wq->first == NULL && timedout) { + DPRINTF(("engine terminating due to timeout.\n")); + wq->counter--; + break; + } + } + + pthread_mutex_unlock(&wq->mutex); + DPRINTF(("Worker exiting\n")); + return NULL; } /* * Initialize a work queue. */ -int workq_init (workq_t *wq, int threads, void (*engine)(void *arg)) +int +workq_init(workq_t* wq, int threads, void (*engine)(void* arg)) { - int status; + int status; - status = pthread_attr_init (&wq->attr); - if (status != 0) - return status; - status = pthread_attr_setdetachstate ( - &wq->attr, PTHREAD_CREATE_DETACHED); - if (status != 0) { - pthread_attr_destroy (&wq->attr); - return status; - } - status = pthread_mutex_init (&wq->mutex, NULL); - if (status != 0) { - pthread_attr_destroy (&wq->attr); - return status; - } - status = pthread_cond_init (&wq->cv, NULL); - if (status != 0) { - pthread_mutex_destroy (&wq->mutex); - pthread_attr_destroy (&wq->attr); - return status; - } - wq->quit = 0; /* not time to quit */ - wq->first = wq->last = NULL; /* no queue entries */ - wq->parallelism = threads; /* max servers */ - wq->counter = 0; /* no server threads yet */ - wq->idle = 0; /* no idle servers */ - wq->engine = engine; - wq->valid = WORKQ_VALID; - return 0; + status = pthread_attr_init(&wq->attr); + if (status != 0) + return status; + status = pthread_attr_setdetachstate(&wq->attr, PTHREAD_CREATE_DETACHED); + if (status != 0) { + pthread_attr_destroy(&wq->attr); + return status; + } + status = pthread_mutex_init(&wq->mutex, NULL); + if (status != 0) { + pthread_attr_destroy(&wq->attr); + return status; + } + status = pthread_cond_init(&wq->cv, NULL); + if (status != 0) { + pthread_mutex_destroy(&wq->mutex); + pthread_attr_destroy(&wq->attr); + return status; + } + wq->quit = 0; /* not time to quit */ + wq->first = wq->last = NULL; /* no queue entries */ + wq->parallelism = threads; /* max servers */ + wq->counter = 0; /* no server threads yet */ + wq->idle = 0; /* no idle servers */ + wq->engine = engine; + wq->valid = WORKQ_VALID; + return 0; } /* * Destroy a work queue. */ -int workq_destroy (workq_t *wq) +int +workq_destroy(workq_t* wq) { - int status, status1, status2; + int status, status1, status2; - if (wq->valid != WORKQ_VALID) - return EINVAL; - status = pthread_mutex_lock (&wq->mutex); - if (status != 0) + if (wq->valid != WORKQ_VALID) + return EINVAL; + status = pthread_mutex_lock(&wq->mutex); + if (status != 0) + return status; + wq->valid = 0; /* prevent any other operations */ + + /* + * Check whether any threads are active, and run them down: + * + * 1. set the quit flag + * 2. broadcast to wake any servers that may be asleep + * 4. wait for all threads to quit (counter goes to 0) + * Because we don't use join, we don't need to worry + * about tracking thread IDs. + */ + if (wq->counter > 0) { + wq->quit = 1; + /* if any threads are idling, wake them. */ + if (wq->idle > 0) { + status = pthread_cond_broadcast(&wq->cv); + if (status != 0) { + pthread_mutex_unlock(&wq->mutex); return status; - wq->valid = 0; /* prevent any other operations */ + } + } /* - * Check whether any threads are active, and run them down: - * - * 1. set the quit flag - * 2. broadcast to wake any servers that may be asleep - * 4. wait for all threads to quit (counter goes to 0) - * Because we don't use join, we don't need to worry - * about tracking thread IDs. + * Just to prove that every rule has an exception, I'm + * using the "cv" condition for two separate predicates + * here. That's OK, since the case used here applies + * only once during the life of a work queue -- during + * rundown. The overhead is minimal and it's not worth + * creating a separate condition variable that would be + * waited and signalled exactly once! */ - if (wq->counter > 0) { - wq->quit = 1; - /* if any threads are idling, wake them. */ - if (wq->idle > 0) { - status = pthread_cond_broadcast (&wq->cv); - if (status != 0) { - pthread_mutex_unlock (&wq->mutex); - return status; - } - } - - /* - * Just to prove that every rule has an exception, I'm - * using the "cv" condition for two separate predicates - * here. That's OK, since the case used here applies - * only once during the life of a work queue -- during - * rundown. The overhead is minimal and it's not worth - * creating a separate condition variable that would be - * waited and signalled exactly once! - */ - while (wq->counter > 0) { - status = pthread_cond_wait (&wq->cv, &wq->mutex); - if (status != 0) { - pthread_mutex_unlock (&wq->mutex); - return status; - } - } - } - status = pthread_mutex_unlock (&wq->mutex); - if (status != 0) + while (wq->counter > 0) { + status = pthread_cond_wait(&wq->cv, &wq->mutex); + if (status != 0) { + pthread_mutex_unlock(&wq->mutex); return status; - status = pthread_mutex_destroy (&wq->mutex); - status1 = pthread_cond_destroy (&wq->cv); - status2 = pthread_attr_destroy (&wq->attr); - return (status ? status : (status1 ? status1 : status2)); + } + } + } + status = pthread_mutex_unlock(&wq->mutex); + if (status != 0) + return status; + status = pthread_mutex_destroy(&wq->mutex); + status1 = pthread_cond_destroy(&wq->cv); + status2 = pthread_attr_destroy(&wq->attr); + return (status ? status : (status1 ? status1 : status2)); } /* * Add an item to a work queue. */ -int workq_add (workq_t *wq, void *element) +int +workq_add(workq_t* wq, void* element) { - workq_ele_t *item; - pthread_t id; - int status; + workq_ele_t* item; + pthread_t id; + int status; - if (wq->valid != WORKQ_VALID) - return EINVAL; + if (wq->valid != WORKQ_VALID) + return EINVAL; - /* - * Create and initialize a request structure. - */ - item = (workq_ele_t *)malloc (sizeof (workq_ele_t)); - if (item == NULL) - return ENOMEM; - item->data = element; - item->next = NULL; - status = pthread_mutex_lock (&wq->mutex); + /* + * Create and initialize a request structure. + */ + item = (workq_ele_t*) malloc(sizeof(workq_ele_t)); + if (item == NULL) + return ENOMEM; + item->data = element; + item->next = NULL; + status = pthread_mutex_lock(&wq->mutex); + if (status != 0) { + free(item); + return status; + } + + /* + * Add the request to the end of the queue, updating the + * first and last pointers. + */ + if (wq->first == NULL) + wq->first = item; + else + wq->last->next = item; + wq->last = item; + + /* + * if any threads are idling, wake one. + */ + if (wq->idle > 0) { + status = pthread_cond_signal(&wq->cv); if (status != 0) { - free (item); - return status; + pthread_mutex_unlock(&wq->mutex); + return status; } - + } + else if (wq->counter < wq->parallelism) { /* - * Add the request to the end of the queue, updating the - * first and last pointers. + * If there were no idling threads, and we're allowed to + * create a new thread, do so. */ - if (wq->first == NULL) - wq->first = item; - else - wq->last->next = item; - wq->last = item; - - /* - * if any threads are idling, wake one. - */ - if (wq->idle > 0) { - status = pthread_cond_signal (&wq->cv); - if (status != 0) { - pthread_mutex_unlock (&wq->mutex); - return status; - } - } else if (wq->counter < wq->parallelism) { - /* - * If there were no idling threads, and we're allowed to - * create a new thread, do so. - */ - DPRINTF (("Creating new worker\n")); - status = pthread_create ( - &id, &wq->attr, workq_server, (void*)wq); - if (status != 0) { - pthread_mutex_unlock (&wq->mutex); - return status; - } - wq->counter++; + DPRINTF(("Creating new worker\n")); + status = pthread_create(&id, &wq->attr, workq_server, (void*) wq); + if (status != 0) { + pthread_mutex_unlock(&wq->mutex); + return status; } - pthread_mutex_unlock (&wq->mutex); - return 0; + wq->counter++; + } + pthread_mutex_unlock(&wq->mutex); + return 0; } diff --git a/src/ch07/workq.h b/src/ch07/workq.h index 39a99d9..93cd745 100644 --- a/src/ch07/workq.h +++ b/src/ch07/workq.h @@ -26,34 +26,33 @@ * Structure to keep track of work queue requests. */ typedef struct workq_ele_tag { - struct workq_ele_tag *next; - void *data; + struct workq_ele_tag* next; + void* data; } workq_ele_t; /* * Structure describing a work queue. */ typedef struct workq_tag { - pthread_mutex_t mutex; - pthread_cond_t cv; /* wait for work */ - pthread_attr_t attr; /* create detached threads */ - workq_ele_t *first, *last; /* work queue */ - int valid; /* set when valid */ - int quit; /* set when workq should quit */ - int parallelism; /* number of threads required */ - int counter; /* current number of threads */ - int idle; /* number of idle threads */ - void (*engine)(void *arg); /* user engine */ + pthread_mutex_t mutex; + pthread_cond_t cv; /* wait for work */ + pthread_attr_t attr; /* create detached threads */ + workq_ele_t *first, *last; /* work queue */ + int valid; /* set when valid */ + int quit; /* set when workq should quit */ + int parallelism; /* number of threads required */ + int counter; /* current number of threads */ + int idle; /* number of idle threads */ + void (*engine)(void* arg); /* user engine */ } workq_t; -#define WORKQ_VALID 0xdec1992 +#define WORKQ_VALID 0xdec1992 /* * Define work queue functions */ -extern int workq_init ( - workq_t *wq, - int threads, /* maximum threads */ - void (*engine)(void *)); /* engine routine */ -extern int workq_destroy (workq_t *wq); -extern int workq_add (workq_t *wq, void *data); +extern int workq_init(workq_t* wq, + int threads, /* maximum threads */ + void (*engine)(void*)); /* engine routine */ +extern int workq_destroy(workq_t* wq); +extern int workq_add(workq_t* wq, void* data); diff --git a/src/ch07/workq_main.c b/src/ch07/workq_main.c index 90352d1..8a8295f 100644 --- a/src/ch07/workq_main.c +++ b/src/ch07/workq_main.c @@ -4,141 +4,139 @@ * Demonstrate a use of work queues. */ #include -#include #include +#include #include -#include "workq.h" #include "errors.h" +#include "workq.h" -#define ITERATIONS 25 +#define ITERATIONS 25 typedef struct power_tag { - int value; - int power; + int value; + int power; } power_t; typedef struct engine_tag { - struct engine_tag *link; - pthread_t thread_id; - int calls; + struct engine_tag* link; + pthread_t thread_id; + int calls; } engine_t; -pthread_key_t engine_key; /* Keep track of active engines */ +pthread_key_t engine_key; /* Keep track of active engines */ pthread_mutex_t engine_list_mutex = PTHREAD_MUTEX_INITIALIZER; -engine_t *engine_list_head = NULL; +engine_t* engine_list_head = NULL; workq_t workq; /* * Thread-specific data destructor routine for engine_key */ -void destructor (void *value_ptr) +void +destructor(void* value_ptr) { - engine_t *engine = (engine_t*)value_ptr; + engine_t* engine = (engine_t*) value_ptr; - pthread_mutex_lock (&engine_list_mutex); - engine->link = engine_list_head; - engine_list_head = engine; - pthread_mutex_unlock (&engine_list_mutex); + pthread_mutex_lock(&engine_list_mutex); + engine->link = engine_list_head; + engine_list_head = engine; + pthread_mutex_unlock(&engine_list_mutex); } /* * This is the routine called by the work queue servers to * perform operations in parallel. */ -void engine_routine (void *arg) +void +engine_routine(void* arg) { - engine_t *engine; - power_t *power = (power_t*)arg; - int result, count; - int status; + engine_t* engine; + power_t* power = (power_t*) arg; + int result, count; + int status; - engine = pthread_getspecific (engine_key); - if (engine == NULL) { - engine = (engine_t*)malloc (sizeof (engine_t)); - status = pthread_setspecific ( - engine_key, (void*)engine); - if (status != 0) - err_abort (status, "Set tsd"); - engine->thread_id = pthread_self (); - engine->calls = 1; - } else - engine->calls++; - result = 1; - printf ( - "Engine: computing %d^%d\n", - power->value, power->power); - for (count = 1; count <= power->power; count++) - result *= power->value; - free (arg); + engine = pthread_getspecific(engine_key); + if (engine == NULL) { + engine = (engine_t*) malloc(sizeof(engine_t)); + status = pthread_setspecific(engine_key, (void*) engine); + if (status != 0) + err_abort(status, "Set tsd"); + engine->thread_id = pthread_self(); + engine->calls = 1; + } + else + engine->calls++; + result = 1; + printf("Engine: computing %d^%d\n", power->value, power->power); + for (count = 1; count <= power->power; count++) result *= power->value; + free(arg); } /* * Thread start routine that issues work queue requests. */ -void *thread_routine (void *arg) +void* +thread_routine(void* arg) { - power_t *element; - int count; - unsigned int seed = (unsigned int)time (NULL); - int status; + power_t* element; + int count; + unsigned int seed = (unsigned int) time(NULL); + int status; - /* - * Loop, making requests. - */ - for (count = 0; count < ITERATIONS; count++) { - element = (power_t*)malloc (sizeof (power_t)); - if (element == NULL) - errno_abort ("Allocate element"); - element->value = rand_r (&seed) % 20; - element->power = rand_r (&seed) % 7; - DPRINTF (( - "Request: %d^%d\n", - element->value, element->power)); - status = workq_add (&workq, (void*)element); - if (status != 0) - err_abort (status, "Add to work queue"); - sleep (rand_r (&seed) % 5); - } - return NULL; + /* + * Loop, making requests. + */ + for (count = 0; count < ITERATIONS; count++) { + element = (power_t*) malloc(sizeof(power_t)); + if (element == NULL) + errno_abort("Allocate element"); + element->value = rand_r(&seed) % 20; + element->power = rand_r(&seed) % 7; + DPRINTF(("Request: %d^%d\n", element->value, element->power)); + status = workq_add(&workq, (void*) element); + if (status != 0) + err_abort(status, "Add to work queue"); + sleep(rand_r(&seed) % 5); + } + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t thread_id; - engine_t *engine; - int count = 0, calls = 0; - int status; + pthread_t thread_id; + engine_t* engine; + int count = 0, calls = 0; + int status; - status = pthread_key_create (&engine_key, destructor); - if (status != 0) - err_abort (status, "Create key"); - status = workq_init (&workq, 4, engine_routine); - if (status != 0) - err_abort (status, "Init work queue"); - status = pthread_create (&thread_id, NULL, thread_routine, NULL); - if (status != 0) - err_abort (status, "Create thread"); - (void)thread_routine (NULL); - status = pthread_join (thread_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - status = workq_destroy (&workq); - if (status != 0) - err_abort (status, "Destroy work queue"); + status = pthread_key_create(&engine_key, destructor); + if (status != 0) + err_abort(status, "Create key"); + status = workq_init(&workq, 4, engine_routine); + if (status != 0) + err_abort(status, "Init work queue"); + status = pthread_create(&thread_id, NULL, thread_routine, NULL); + if (status != 0) + err_abort(status, "Create thread"); + (void) thread_routine(NULL); + status = pthread_join(thread_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + status = workq_destroy(&workq); + if (status != 0) + err_abort(status, "Destroy work queue"); - /* - * By now, all of the engine_t structures have been placed - * on the list (by the engine thread destructors), so we - * can count and summarize them. - */ - engine = engine_list_head; - while (engine != NULL) { - count++; - calls += engine->calls; - printf ("engine %d: %d calls\n", count, engine->calls); - engine = engine->link; - } - printf ("%d engine threads processed %d calls\n", - count, calls); - return 0; + /* + * By now, all of the engine_t structures have been placed + * on the list (by the engine thread destructors), so we + * can count and summarize them. + */ + engine = engine_list_head; + while (engine != NULL) { + count++; + calls += engine->calls; + printf("engine %d: %d calls\n", count, engine->calls); + engine = engine->link; + } + printf("%d engine threads processed %d calls\n", count, calls); + return 0; } diff --git a/src/ch08/inertia.c b/src/ch08/inertia.c index 936cbcf..c1eda77 100644 --- a/src/ch08/inertia.c +++ b/src/ch08/inertia.c @@ -11,46 +11,49 @@ #include #include "errors.h" -void *printer_thread (void *arg) +void* +printer_thread(void* arg) { - char *string = *(char**)arg; + char* string = *(char**) arg; - printf ("%s\n", string); - return NULL; + printf("%s\n", string); + return NULL; } -int main (int argc, char *argv[]) +int +main(int argc, char* argv[]) { - pthread_t printer_id; - char *string_ptr; - int i, status; + pthread_t printer_id; + char* string_ptr; + int i, status; #ifdef sun - /* - * On Solaris 2.5, threads are not timesliced. To ensure - * that our two threads can run concurrently, we need to - * increase the concurrency level to 2. - */ - DPRINTF (("Setting concurrency level to 2\n")); - thr_setconcurrency (2); + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our two threads can run concurrently, we need to + * increase the concurrency level to 2. + */ + DPRINTF(("Setting concurrency level to 2\n")); + thr_setconcurrency(2); #endif - string_ptr = "Before value"; - status = pthread_create ( - &printer_id, NULL, printer_thread, (void*)&string_ptr); - if (status != 0) - err_abort (status, "Create thread"); + string_ptr = "Before value"; + status = + pthread_create(&printer_id, NULL, printer_thread, (void*) &string_ptr); + if (status != 0) + err_abort(status, "Create thread"); - /* - * Give the thread a chance to get started if it's going to run - * in parallel, but not enough that the current thread is likely - * to be timesliced. (This is a tricky balance, and the loop may - * need to be adjusted on your system before you can see the bug.) - */ - for (i = 0; i < 10000000; i++); + /* + * Give the thread a chance to get started if it's going to run + * in parallel, but not enough that the current thread is likely + * to be timesliced. (This is a tricky balance, and the loop may + * need to be adjusted on your system before you can see the bug.) + */ + for (i = 0; i < 10000000; i++) + ; - string_ptr = "After value"; - status = pthread_join (printer_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - return 0; + string_ptr = "After value"; + status = pthread_join(printer_id, NULL); + if (status != 0) + err_abort(status, "Join thread"); + return 0; }