summaryrefslogtreecommitdiff
path: root/pgm5
diff options
context:
space:
mode:
author53hornet <53hornet@gmail.com>2019-02-02 22:59:54 -0500
committer53hornet <53hornet@gmail.com>2019-02-02 22:59:54 -0500
commit379c2c17e68d5d471a6a9673b7e9cd1fb9d99bbb (patch)
treeeed499da8211a5eece757639331a2d82bce4fa4c /pgm5
downloadcsci415-master.tar.xz
csci415-master.zip
Diffstat (limited to 'pgm5')
-rw-r--r--pgm5/counter.c690
-rw-r--r--pgm5/makefile11
-rw-r--r--pgm5/p5test/file017
-rw-r--r--pgm5/p5test/file12
-rw-r--r--pgm5/p5test/file23
-rw-r--r--pgm5/p5test/file39
-rw-r--r--pgm5/p5test/file45
-rw-r--r--pgm5/p5test/file511
-rw-r--r--pgm5/p5test/file61
-rw-r--r--pgm5/prodcons.d/Makefile10
-rw-r--r--pgm5/prodcons.d/README2
-rw-r--r--pgm5/prodcons.d/prodcons.c124
-rw-r--r--pgm5/run.sh13
13 files changed, 898 insertions, 0 deletions
diff --git a/pgm5/counter.c b/pgm5/counter.c
new file mode 100644
index 0000000..26735b4
--- /dev/null
+++ b/pgm5/counter.c
@@ -0,0 +1,690 @@
+/*
+ * counter.c
+ * Adam Carpenter - 2017 - acarpent - acarpenter@email.wm.edu
+ * Utilizes code from P. Kearns
+ * Utilizes code from linuxthreads demonstration "prodcons.c"
+ */
+
+
+// **** Library inclusions ****
+#include<errno.h>
+#include<pthread.h>
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include<time.h>
+#include<unistd.h>
+
+
+// **** Definitions for counter ****
+#define FALSE 0
+#define LEN_LINE 2048
+#define LEN_FILENAME 4096
+#define MAX_THREADS 26
+#define TRUE 1
+#define USAGE "counter: usage: counter -b num_lines -t max_counters -d file_delay -D thread_delay [file]...\n"
+
+
+// **** Structure declarations ****
+struct prodConBuff {
+ /*
+ * struct prodConBuff
+ */
+ pthread_mutex_t bufferLock;// Mutex ensures exclusive access to buffer.
+ int readPos; // Position for reading.
+ int writePos; // Position for writing.
+ pthread_cond_t notEmpty; // Signaled when buffer isn't empty.
+ pthread_cond_t notFull; // Signaled when buffer isn't full.
+ // char *lines[];
+ char **lines; // Array of strings serves as data container.
+};
+
+struct NODE {
+ /*
+ * struct NODE
+ */
+ char *word; // char *word or word[LEN_LINE]
+ long count;
+ struct NODE *next;
+};
+
+struct linkedList {
+ /*
+ * struct linkedList
+ */
+ pthread_mutex_t listLock; // Mutex ensures exclusive access to linked list.
+ struct NODE *head; // Pointer to first node in list.
+};
+
+
+// **** Global variables ****
+static char nextThread;
+static int fileDelay;
+static int maxCounters;
+static int moreStuff;
+static int numLines;
+static int threadDelay;
+static pthread_t threadPool[MAX_THREADS]; // Bad Threadpool.
+struct prodConBuff buffer;
+struct linkedList evenList;
+struct linkedList oddList;
+
+
+// **** Structure initializations ****
+static void initBuffer(struct prodConBuff *buffer) {
+ /*
+ * initBuffer() initializes the buffer structure to an empty array ready for
+ * producer-consumer actions.
+ * The buffer of lines is initialized to NULL. As the program runs, if
+ * slots are empty they will be malloc'd to fit given lines being inserted
+ * into the buffer, and freed as they are taken out.
+ */
+ int i;
+
+ pthread_mutex_init(&buffer->bufferLock, NULL);
+ pthread_cond_init(&buffer->notEmpty, NULL);
+ pthread_cond_init(&buffer->notFull, NULL);
+ buffer->readPos = 0;
+ buffer->writePos = 0;
+ buffer->lines = (char **) calloc(numLines, LEN_LINE);
+
+ for (i = 0; i < numLines; i++) {
+ buffer->lines[i] = (char *) calloc(LEN_LINE, sizeof(char));
+ }
+
+ if (numLines == 1) {
+ buffer->lines[0][0] = '\0';
+ }
+}
+
+static void initLinkedList(struct linkedList *list) {
+ /*
+ * initLinkedList() initializes the linked list structure (its lock and its
+ * head node.)
+ */
+ pthread_mutex_init(&list->listLock, NULL);
+ list->head = NULL;
+}
+
+
+// **** Modifier and thread functions ****
+static void sleeper(const struct timespec *req, struct timespec *rem) {
+ // Researched methods of maintaining nanosleep times online and
+ // found an interesting method using recursion that was similar to this.
+
+ struct timespec newRem;
+
+ if (nanosleep(req, rem) < 0) {
+ sleeper(rem, &newRem);
+ }
+
+}
+
+static void quitThread() {
+ /*
+ * quitThread()
+ */
+ #ifdef atcdebug
+ fprintf(stderr, "counter: thread quit because no more stuff.\n");
+ #endif
+
+ nextThread--;
+ pthread_exit(NULL);
+}
+
+static int putInBuffer(struct prodConBuff *buffer, char *line) {
+ /*
+ * putInBuffer()
+ */
+ int newThread;
+
+ newThread = FALSE;
+ pthread_mutex_lock(&buffer->bufferLock);
+
+ // If buffer is full, spawn a new counter thread.
+ if ((buffer->writePos + 1) % numLines == buffer->readPos) {
+ newThread = TRUE;
+ }
+
+ // Wait until buffer isn't full anymore.
+ while ((buffer->writePos + 1) % numLines == buffer->readPos) {
+ pthread_cond_wait(&buffer->notFull, &buffer->bufferLock);
+
+ #ifdef atcdebug
+ fprintf(stderr, "reader: waiting for space...\n");
+ #endif
+ }
+
+ #ifdef atcdebug
+ fprintf(stderr, "reader: gonna insert in slot: %d\n", buffer->writePos);
+ #endif
+
+ // Copy the text into the next slot in the buffer.
+ strncpy(buffer->lines[buffer->writePos], line, LEN_LINE);
+ buffer->writePos++;
+
+ if (buffer->writePos >= numLines) {
+ buffer->writePos = 0;
+ }
+
+ #ifdef atcdebug
+ fprintf(stderr, "reader: buffer is now: { ");
+ int i;
+ for (i = 0; i < numLines; i++) {
+ if (i == buffer->writePos) {
+ fprintf(stderr, "*");
+
+ }
+
+ fprintf(stderr, "%s ", buffer->lines[i]);
+
+ }
+ fprintf(stderr, "}\n\n");
+ #endif
+
+ // Signal buffer isn't empty anymore and unlock mutex.
+ pthread_cond_signal(&buffer->notEmpty);
+ pthread_mutex_unlock(&buffer->bufferLock);
+ return newThread;
+}
+
+static int putInSingleBuffer(struct prodConBuff *buffer, char *line) {
+ /*
+ * putInSingleBuffer(0)
+ */
+ int newThread;
+
+ pthread_mutex_lock(&buffer->bufferLock);
+ newThread = FALSE;
+
+ // If slot is taken, spawn a new counter thread
+ if (buffer->lines[0][0] != '\0') {
+ newThread = TRUE;
+ }
+
+ // Wait until slot isn't full anymore.
+ while (buffer->lines[0][0] != '\0') {
+ pthread_cond_wait(&buffer->notFull, &buffer->bufferLock);
+ }
+
+ // Insert line into buffer.
+ strncpy(buffer->lines[buffer->writePos], line, LEN_LINE);
+
+ // Signal buffer slot isn't empty anymore and unlock mutex.
+ pthread_cond_signal(&buffer->notEmpty);
+ pthread_mutex_unlock(&buffer->bufferLock);
+ return newThread;
+}
+
+static void getFromBuffer(struct prodConBuff *buffer, char *line) {
+ /*
+ * getFromBuffer()
+ */
+
+ pthread_mutex_lock(&buffer->bufferLock);
+
+ // If buffer is 'empty' and nothing more will be written, quit.
+ if (!moreStuff && buffer->readPos == buffer->writePos) {
+ quitThread();
+ }
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+ // Wait until buffer isn't empty anymore.
+ while (buffer->readPos == buffer->writePos) {
+ #ifdef atcdebug
+ fprintf(stderr, "counter: waiting for stuff...\n");
+ #endif
+
+ pthread_cond_wait(&buffer->notEmpty, &buffer->bufferLock);
+ }
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ #ifdef atcdebug
+ fprintf(stderr, "counter: getting from slot: %d\n", buffer->readPos);
+ #endif
+
+ // Get line from buffer and advance read position.
+ strncpy(line, buffer->lines[buffer->readPos], LEN_LINE);
+ buffer->readPos++;
+ if (buffer->readPos >= numLines) buffer->readPos = 0;
+
+ #ifdef atcdebug
+ fprintf(stderr, "counter: buffer is now: { ");
+ int i;
+ for (i = 0; i < numLines; i++) {
+ if (i == buffer->readPos) {
+ fprintf(stderr, "*");
+
+ }
+
+ fprintf(stderr, "%s ", buffer->lines[i]);
+
+ }
+ fprintf(stderr, "}\n\n");
+ #endif
+
+ // Signal buffer isn't full anymore and unlock mutex.
+ pthread_cond_signal(&buffer->notFull);
+ pthread_mutex_unlock(&buffer->bufferLock);
+}
+
+static void getFromSingleBuffer(struct prodConBuff *buffer, char *line) {
+ /*
+ * getFromSingleBuffer();
+ */
+
+ pthread_mutex_lock(&buffer->bufferLock);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+ // Wait until buffer isn't empty anymore.
+ while (buffer->lines[0][0] == '\0') {
+
+ // If buffer slot is empty and nothing more will be written to it, quit.
+ if ((buffer->lines[0][0] == 0) && !moreStuff) {
+ quitThread();
+ }
+
+ pthread_cond_wait(&buffer->notEmpty, &buffer->bufferLock);
+ }
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ // Get line from buffer slot.
+ strncpy(line, buffer->lines[0], LEN_LINE);
+ buffer->lines[0][0] = '\0';
+
+ // Signal buffer slot isn't full anmore and unlock mutex.
+ pthread_cond_signal(&buffer->notFull);
+ pthread_mutex_unlock(&buffer->bufferLock);
+}
+
+static void putInList(struct linkedList *list, char *word) {
+ /*
+ * putInList()
+ */
+ struct NODE *current;
+ struct NODE *new;
+
+ pthread_mutex_lock(&list->listLock);
+
+ #ifdef atcdebug
+ fprintf(stderr, "counter: gonna insert into list\n");
+ #endif
+
+ if (list->head == NULL) {
+ new = (struct NODE *) malloc(sizeof(struct NODE));
+ new->word = (char *) malloc(strlen(word));
+ strcpy(new->word, word);
+ new->count = 1;
+ list->head = new;
+ }
+ else {
+
+ for (current = list->head; current != NULL; current = current->next) {
+
+ if (strcmp(current->word, word) == 0) {
+ // Word already in list; update count.
+ current->count++;
+ break;
+ }
+ else if (current->next != NULL
+ && strcmp(word, current->next->word) < 0) {
+ // Insert in front of next-greatest lexiographical word.
+ new = (struct NODE *) malloc(sizeof(struct NODE));
+ new->word = (char *) malloc(strlen(word));
+ strcpy(new->word, word);
+ new->count = 1;
+ new->next = current->next;
+ current->next = new;
+ break;
+ }
+ else if (current->next == NULL) {
+ // Reached the end; Insert at back of list.
+ new = (struct NODE *) malloc(sizeof(struct NODE));
+ new->word = (char *) malloc(strlen(word));
+ strcpy(new->word, word);
+ new->count = 1;
+ new->next = NULL;
+ current->next = new;
+ break;
+ }
+
+ }
+
+ }
+
+ #ifdef atcdebug
+ fprintf(stderr, "counter: list is now: {");
+ current = list->head;
+ while (current != NULL) {
+ fprintf(stderr, "%s->", current->word);
+ current = current->next;
+ }
+ fprintf(stderr, "}\n\n");
+ #endif
+
+ pthread_mutex_unlock(&list->listLock);
+}
+
+static void printList(struct linkedList *list) {
+ /*
+ * printList()
+ */
+ struct NODE *current;
+
+ // For debugging purposes and future implementations, lock the list.
+ pthread_mutex_lock(&list->listLock);
+
+ // Print the word of every node in the list.
+ for (current = list->head; current != NULL; current = current->next) {
+ printf("Count: %ld Word: %s\n", current->count, current->word);
+ }
+
+ pthread_mutex_unlock(&list->listLock);
+}
+
+static void freeList(struct linkedList *list) {
+ /*
+ * freeList()
+ */
+ struct NODE *current;
+ struct NODE *temp;
+
+ // For debugging purposes and future implementations, lock the list.
+ pthread_mutex_lock(&list->listLock);
+
+ // Free every node in the list.
+ while (current != NULL) {
+ temp = current;
+ current = current->next;
+ free(temp);
+ }
+
+ pthread_mutex_unlock(&list->listLock);
+}
+
+static void * counterThread(void * arg) {
+ /*
+ * counterThread()
+ */
+ char name;
+ char line[LEN_LINE];
+ char *token;
+ struct timespec requestedTime;
+ struct timespec remainingTime;
+
+ name = (char) arg;
+ requestedTime.tv_sec = threadDelay / 1000;
+ requestedTime.tv_nsec = threadDelay % 1000 * 1000000;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ #ifdef atcdebug
+ fprintf(stderr, "counter: name == %c, numLines == %d, threadDelay == %d\n", name, numLines, threadDelay);
+ #endif
+
+ while (TRUE) {
+
+ // Sleep for allotted time.
+ sleeper(&requestedTime, &remainingTime);
+
+ if (numLines == 1) {
+ getFromSingleBuffer(&buffer, line);
+ }
+ else {
+ getFromBuffer(&buffer, line);
+ }
+
+ // Get the first word in the line.
+ token = strtok(line, " ");
+
+ // With each word, see if there are an even or odd number of characters
+ // and insert the word into the designated list. Then print the name
+ // of the thread on stdout.
+ while (token != NULL) {
+
+ if (strlen(token) % 2 == 0) {
+ putInList(&evenList, token);
+
+ #ifndef atcdebug
+ printf("%c ", name);
+ #endif
+
+ }
+ else {
+ putInList(&oddList, token);
+
+ #ifndef atcdebug
+ printf("%c ", name);
+ #endif
+
+ }
+
+ token = strtok(NULL, " ");
+ }
+
+ }
+
+ return NULL;
+}
+
+static void createThread() {
+ /*
+ * createThread()
+ */
+
+ // Would a new thread put us over the maximum allowed?
+ // If not, create another counter thread as requested.
+
+ if (((nextThread - 'a') < maxCounters)) {
+ #ifdef atcdebug
+ fprintf(stderr, "reader: creating thread, name == %c\n", nextThread);
+ #endif
+
+ pthread_create(&threadPool[nextThread - 'a'], NULL, counterThread, (void *) nextThread);
+ nextThread++;
+ }
+
+}
+
+
+// **** Main ****
+int main(int argc, char *argv[]) {
+ /*
+ * main() acts as the reader thread, and therefore the producer.
+ */
+ char line[LEN_LINE];
+ int i;
+ FILE *textFile;
+ struct timespec requestedTime;
+ struct timespec remainingTime;
+
+ // Get command line args.
+ if (argc < 10) {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ numLines = maxCounters = fileDelay = threadDelay = -1;
+ i = 1;
+ errno = 0;
+
+ while (argv[i] && i < 9) {
+
+ // Get numLines.
+ if (strcmp(argv[i], "-b") == 0) {
+ i++;
+
+ if (argv[i]) {
+ numLines = strtol(argv[i], NULL, 10);
+
+ if (errno != 0 || numLines <= 0) {
+ fprintf(stderr, "counter: num_lines must be a positive, non-zero integer.\n");
+ exit(1);
+ }
+
+ }
+ else {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ }
+ // Get maxCounters.
+ else if (strcmp(argv[i], "-t") == 0) {
+ i++;
+
+ if (argv[i]) {
+ maxCounters = strtol(argv[i], NULL, 10);
+
+ if (errno != 0 || maxCounters <= 0 || maxCounters > 26) {
+ fprintf(stderr, "counter: max_counters must be a positive, non-zero integer no greater than 26.\n");
+ exit(1);
+ }
+
+ }
+ else {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ }
+ // Get fileDelay.
+ else if (strcmp(argv[i], "-d") == 0) {
+ i++;
+
+ if (argv[i]) {
+ fileDelay = strtol(argv[i], NULL, 10);
+
+ if (errno != 0 || fileDelay < 0) {
+ fprintf(stderr, "counter: file_delay must be a positive integer.\n");
+ exit(1);
+ }
+
+ }
+ else {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ }
+ // Get threadDelay.
+ else if (strcmp(argv[i], "-D") == 0) {
+ i++;
+
+ if (argv[i]) {
+ threadDelay = strtol(argv[i], NULL, 10);
+
+ if (errno != 0 || threadDelay < 0) {
+ fprintf(stderr, "counter: thread_delay must be a positive integer.\n");
+ exit(1);
+ }
+
+ }
+ else {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ }
+ else {
+
+ if (numLines < 0 || maxCounters < 0
+ || fileDelay < 0 || threadDelay < 0) {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ }
+
+ i++;
+ }
+
+ #ifdef atcdebug
+ fprintf(stderr, "reader: numLines = %d, maxCounters = %d, fileDelay = %d, "
+ "threadDelay = %d\n", numLines, maxCounters, fileDelay, threadDelay);
+ #endif
+
+ // Set up thread environment.
+ initBuffer(&buffer);
+ initLinkedList(&evenList);
+ initLinkedList(&oddList);
+ nextThread = 'a';
+ moreStuff = TRUE;
+
+ // Start up first counter (consumer) thread.
+ createThread();
+
+ // **** Reader (producer) thread ****
+ textFile = NULL;
+ requestedTime.tv_sec = threadDelay / 1000;
+ requestedTime.tv_nsec = threadDelay % 1000 * 1000000;
+
+ while (argv[i]) {
+
+ // Open each file given in argv[].
+ if (!(textFile = fopen(argv[i], "r"))) {
+ fprintf(stderr, "counter: could not open %s\n", argv[i]);
+ }
+ else {
+
+ // Read each line in the file and insert it into the buffer.
+ while (fgets(line, LEN_LINE, textFile)) {
+ // Strip newline.
+ line[strcspn(line, "\n")] = '\0';
+
+ if (numLines == 1) {
+
+ // Attempt to create a new thread if function says
+ // buffer was full.
+ if (putInSingleBuffer(&buffer, line) == TRUE) {
+ createThread();
+ }
+
+ }
+ else {
+
+ // Attempt to create a new thread if put function says
+ // buffer was full.
+ if (putInBuffer(&buffer, line) == TRUE) {
+ createThread();
+ }
+
+ }
+
+ // Sleep for allotted time.
+ while (nanosleep(&requestedTime, &remainingTime) == -1) {
+ requestedTime = remainingTime;
+ }
+
+ }
+
+ fclose(textFile);
+ }
+
+ i++;
+ }
+
+ // Let counter threads know that there won't be any more input and wait
+ // for threads to finish before printing and terminating.
+ moreStuff = FALSE;
+
+ sleep(2);
+
+ for (i = 0; i < MAX_THREADS; i++) {
+
+ if (threadPool[i]) {
+ pthread_cancel(threadPool[i]);
+ }
+
+ }
+
+ printf("\n==== Words with an even number of letters ====\n");
+ printList(&evenList);
+ printf("\n==== Words with an odd number of letters ====\n");
+ printList(&oddList);
+ freeList(&evenList);
+ freeList(&oddList);
+ exit(0);
+}
diff --git a/pgm5/makefile b/pgm5/makefile
new file mode 100644
index 0000000..4de261f
--- /dev/null
+++ b/pgm5/makefile
@@ -0,0 +1,11 @@
+all: counter
+
+counter: counter.c
+ gcc -D_REENTRANT -o counter counter.c -lpthread
+
+debug: counter.c
+ gcc -Wall -g -D_REENTRANT -Datcdebug -o counter counter.c -lpthread
+
+clean:
+ rm -f counter
+ gcc -D_REENTRANT -o counter counter.c -lpthread
diff --git a/pgm5/p5test/file0 b/pgm5/p5test/file0
new file mode 100644
index 0000000..16d6515
--- /dev/null
+++ b/pgm5/p5test/file0
@@ -0,0 +1,17 @@
+a
+aa
+aaa
+aaaa
+aaaaa
+aaaaaa
+aaaaaaa
+aaaaaaaa
+aaaaaaaaa
+aaaaaaaaaa
+aaaaaaaaaaa
+aaaaaaaaaaaa
+aaaaaaaaaaaaa
+aaaaaaaaaaaaaa
+aaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaa
diff --git a/pgm5/p5test/file1 b/pgm5/p5test/file1
new file mode 100644
index 0000000..f9a742d
--- /dev/null
+++ b/pgm5/p5test/file1
@@ -0,0 +1,2 @@
+a a a a a a
+a a a a
diff --git a/pgm5/p5test/file2 b/pgm5/p5test/file2
new file mode 100644
index 0000000..0fd6f48
--- /dev/null
+++ b/pgm5/p5test/file2
@@ -0,0 +1,3 @@
+aa aa aa aa aa
+aa aa aa
+aa aa
diff --git a/pgm5/p5test/file3 b/pgm5/p5test/file3
new file mode 100644
index 0000000..5234a25
--- /dev/null
+++ b/pgm5/p5test/file3
@@ -0,0 +1,9 @@
+aaa aaa aaa aaa aaa
+aaa
+aaa
+
+aaa
+aaa
+aaa
+
+
diff --git a/pgm5/p5test/file4 b/pgm5/p5test/file4
new file mode 100644
index 0000000..29c981d
--- /dev/null
+++ b/pgm5/p5test/file4
@@ -0,0 +1,5 @@
+aaaa aaaa
+aaaa aaaa
+aaaa aaaa
+aaaa aaaa
+aaaa aaaa
diff --git a/pgm5/p5test/file5 b/pgm5/p5test/file5
new file mode 100644
index 0000000..6976d6b
--- /dev/null
+++ b/pgm5/p5test/file5
@@ -0,0 +1,11 @@
+aaaaa
+aaaaa
+aaaaa
+aaaaa
+aaaaa
+aaaaa
+aaaaa
+aaaaa
+aaaaa
+aaaaa
+
diff --git a/pgm5/p5test/file6 b/pgm5/p5test/file6
new file mode 100644
index 0000000..abc805a
--- /dev/null
+++ b/pgm5/p5test/file6
@@ -0,0 +1 @@
+aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa
diff --git a/pgm5/prodcons.d/Makefile b/pgm5/prodcons.d/Makefile
new file mode 100644
index 0000000..174975d
--- /dev/null
+++ b/pgm5/prodcons.d/Makefile
@@ -0,0 +1,10 @@
+CC=gcc
+CFLAGS=-g -Wall -D_REENTRANT
+LIBS=-lpthread
+
+prodcons: prodcons.c
+ $(CC) $(CFLAGS) -o prodcons prodcons.c $(LIBS)
+
+clean:
+ rm -f prodcons core.*
+
diff --git a/pgm5/prodcons.d/README b/pgm5/prodcons.d/README
new file mode 100644
index 0000000..3c85ac4
--- /dev/null
+++ b/pgm5/prodcons.d/README
@@ -0,0 +1,2 @@
+Producer/Consumer with a bounded buffer. From the
+linuxthreads demos.
diff --git a/pgm5/prodcons.d/prodcons.c b/pgm5/prodcons.d/prodcons.c
new file mode 100644
index 0000000..665c744
--- /dev/null
+++ b/pgm5/prodcons.d/prodcons.c
@@ -0,0 +1,124 @@
+/* The classic producer-consumer example.
+ Illustrates mutexes and conditions.
+ All integers between 0 and 9999 should be printed exactly twice,
+ once to the right of the arrow and once to the left. */
+
+#include <stdio.h>
+#include <pthread.h>
+
+#define BUFFER_SIZE 16
+
+/* Circular buffer of integers. */
+
+struct prodcons
+{
+ int buffer[BUFFER_SIZE]; /* the actual data */
+ pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */
+ int readpos, writepos; /* positions for reading and writing */
+ pthread_cond_t notempty; /* signaled when buffer is not empty */
+ pthread_cond_t notfull; /* signaled when buffer is not full */
+};
+
+/* Initialize a buffer */
+static void
+init (struct prodcons *b)
+{
+ pthread_mutex_init (&b->lock, NULL);
+ pthread_cond_init (&b->notempty, NULL);
+ pthread_cond_init (&b->notfull, NULL);
+ b->readpos = 0;
+ b->writepos = 0;
+}
+
+/* Store an integer in the buffer */
+static void
+put (struct prodcons *b, int data)
+{
+ pthread_mutex_lock (&b->lock);
+ /* Wait until buffer is not full */
+ while ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
+ {
+ pthread_cond_wait (&b->notfull, &b->lock);
+ /* pthread_cond_wait reacquired b->lock before returning */
+ }
+ /* Write the data and advance write pointer */
+ b->buffer[b->writepos] = data;
+ b->writepos++;
+ if (b->writepos >= BUFFER_SIZE)
+ b->writepos = 0;
+ /* Signal that the buffer is now not empty */
+ pthread_cond_signal (&b->notempty);
+ pthread_mutex_unlock (&b->lock);
+}
+
+/* Read and remove an integer from the buffer */
+static int
+get (struct prodcons *b)
+{
+ int data;
+ pthread_mutex_lock (&b->lock);
+ /* Wait until buffer is not empty */
+ while (b->writepos == b->readpos)
+ {
+ pthread_cond_wait (&b->notempty, &b->lock);
+ }
+ /* Read the data and advance read pointer */
+ data = b->buffer[b->readpos];
+ b->readpos++;
+ if (b->readpos >= BUFFER_SIZE)
+ b->readpos = 0;
+ /* Signal that the buffer is now not full */
+ pthread_cond_signal (&b->notfull);
+ pthread_mutex_unlock (&b->lock);
+ return data;
+}
+
+/* A test program: one thread inserts integers from 1 to 10000,
+ the other reads them and prints them. */
+
+#define OVER (-1)
+
+struct prodcons buffer;
+
+static void *
+producer (void *data)
+{
+ int n;
+ for (n = 0; n < 10000; n++)
+ {
+ printf ("%d --->\n", n);
+ put (&buffer, n);
+ }
+ put (&buffer, OVER);
+ return NULL;
+}
+
+static void *
+consumer (void *data)
+{
+ int d;
+ while (1)
+ {
+ d = get (&buffer);
+ if (d == OVER)
+ break;
+ printf ("---> %d\n", d);
+ }
+ return NULL;
+}
+
+int
+main (void)
+{
+ pthread_t th_a, th_b;
+ void *retval;
+
+ init (&buffer);
+ /* Create the threads */
+ pthread_create (&th_a, NULL, producer, 0);
+ pthread_create (&th_b, NULL, consumer, 0);
+ /* Wait until producer and consumer finish. */
+ pthread_join (th_a, &retval);
+ pthread_join (th_b, &retval);
+ return 0;
+}
diff --git a/pgm5/run.sh b/pgm5/run.sh
new file mode 100644
index 0000000..7d75216
--- /dev/null
+++ b/pgm5/run.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+make
+cp -f counter p5test/counter
+cd p5test
+
+./counter -b 4 -t 1 -d 0 -D 0 file0
+./counter -b 2 -t 2 -d 1000 -D 1000 file0
+./counter -b 10 -t 1 -d 0 -D 0 /usr/share/fortune/linuxcookie
+./counter -b 2 -t 26 -d 0 -D 0 /usr/share/fortune/linuxcookie
+./counter -b 2 -t 10 -d 0 -D 0 /usr/share/fortune/linuxcookie
+./counter -b 2 -t 10 -d 0 -D 0 file{1,2,3,4,5,6}
+./counter -b 1 -t 1 -d 0 -D 0 /usr/share/fortune/linuxcookie