run clang-format

This commit is contained in:
Bassem Girgis
2018-10-17 23:47:57 -05:00
parent 558e8e22da
commit c8a8949366
56 changed files with 4153 additions and 3900 deletions

104
.clang-format Normal file
View File

@@ -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

View File

@@ -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)

View File

@@ -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);
}
}
}

View File

@@ -8,49 +8,53 @@
#include <wait.h>
#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);
}
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -4,26 +4,27 @@
* Demonstrate detection of errors from a typical POSIX 1003.1c-1995
* function, pthread_join.
*/
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
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;
}

View File

@@ -7,22 +7,24 @@
#include <pthread.h>
#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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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");
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -39,7 +39,9 @@ std::list<alarm_t> 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");
}
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -9,22 +9,22 @@
* by calling thr_setconcurrency(), because threads are not
* timesliced.
*/
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/types.h>
#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;
}

View File

@@ -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);
}
}
}

View File

@@ -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");

View File

@@ -7,43 +7,42 @@
* to allow interleaved thread execution, since threads are not
* timesliced.
*/
#include <pthread.h>
#include <math.h>
#include <pthread.h>
#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;
}

View File

@@ -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;
}

View File

@@ -11,30 +11,30 @@
#include <pthread.h>
#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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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");
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -9,54 +9,56 @@
* _POSIX_THREAD_PRIORITY_SCHEDULING, it does not support the
* SCHED_RR policy for threads.
*/
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#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;
}

View File

@@ -6,9 +6,9 @@
* Special note: This demonstration will fail on Solaris 2.5
* because it does not implement SCHED_RR.
*/
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -4,127 +4,132 @@
* Demonstrate the use of "fork handlers" to protect data
* invariants across a fork.
*/
#include <sys/types.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -8,109 +8,111 @@
* and _POSIX_SEMAPHORES features of POSIX 1003.1b-1993. It will
* not run (and may not compile) without them.
*/
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#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
}

View File

@@ -3,11 +3,11 @@
*
* Demonstrate use of semaphores for synchronization.
*/
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#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
}

View File

@@ -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;
}

View File

@@ -4,15 +4,15 @@
* Demonstrate use of sigwait() to synchronously handle
* asynchrnous signals within a threaded program.
*/
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#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;
}

View File

@@ -26,15 +26,15 @@
#include <signal.h>
#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 */
}

View File

@@ -20,66 +20,68 @@
* to do something in a serial region before entering another
* parallel section of code.
*/
#include "barrier.h"
#include <pthread.h>
#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 */
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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 <pthread.h>
#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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -8,32 +8,32 @@
* timesliced.
*/
#include <pthread.h>
#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;
}

View File

@@ -20,288 +20,289 @@
* processing threads will begin to shut down. (They will be
* restarted when work appears.)
*/
#include "workq.h"
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#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;
}

View File

@@ -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);

View File

@@ -4,141 +4,139 @@
* Demonstrate a use of work queues.
*/
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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;
}

View File

@@ -11,46 +11,49 @@
#include <pthread.h>
#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;
}