Skip to content

Commit

Permalink
No commit message
Browse files Browse the repository at this point in the history
  • Loading branch information
kocheva2 committed Sep 29, 2016
1 parent 4005f0a commit 5f76122
Show file tree
Hide file tree
Showing 13 changed files with 598 additions and 0 deletions.
96 changes: 96 additions & 0 deletions luscious_locks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# use gcc with -fsanitize=thread bc clang on student vms (3.4) has buggy thread
# sanitizer
# this means we also need -ltsan in the link step. libtsan must be installed
# (sudo yum install libtsan on student vms)

OBJS_DIR = .objs

# define all the student executables
EXE_RENDE=rendezvous
EXE_SEM=semamore_tests
EXE_QUEUE=queue_tests
EXE_BAR=barrier_tests
EXES_STUDENT=$(EXE_BAR) $(EXE_SEM) $(EXE_RENDE) $(EXE_QUEUE)

# list object file dependencies for each
OBJS_RENDE=$(EXE_RENDE).o semamore.o
OBJS_SEM=$(EXE_SEM).o semamore.o
OBJS_QUEUE=$(EXE_QUEUE).o queue.o
OBJS_BAR=$(EXE_BAR).o barrier.o

# set up compiler
CC = clang
WARNINGS = -Wall -Wextra -Werror -Wno-error=unused-parameter
INCLUDES=-I./includes/
CFLAGS_DEBUG = $(INCLUDES) -O0 $(WARNINGS) -g -std=c99 -c -MMD -MP -D_GNU_SOURCE -DDEBUG
CFLAGS_RELEASE = $(INCLUDES) -O2 $(WARNINGS) -g -std=c99 -c -MMD -MP -D_GNU_SOURCE

# set up linker
LD = clang
LDFLAGS = -lrt -pthread -fPIC

# the string in grep must appear in the hostname, otherwise the Makefile will
# not allow the assignment to compile
IS_VM=$(shell hostname | grep "fa16")

ifeq ($(IS_VM),)
$(error This assignment must be compiled on the CS241 VMs)
endif

.PHONY: all
all: release

# build types
# run clean before building debug so that all of the release executables
# disappear
.PHONY: debug
.PHONY: release
.PHONY: tsan

release: $(EXES_STUDENT)
debug: clean $(EXE_QUEUE:%=%-debug) $(EXE_BAR:%=%-debug) $(EXE_SEM:%=%-debug)

# include dependencies
-include $(OBJS_DIR)/*.d

$(OBJS_DIR):
@mkdir -p $(OBJS_DIR)

# patterns to create objects
# keep the debug and release postfix for object files so that we can always
# separate them correctly
$(OBJS_DIR)/%-debug.o: %.c | $(OBJS_DIR)
$(CC) $(CFLAGS_DEBUG) $< -o $@

$(OBJS_DIR)/%-release.o: %.c | $(OBJS_DIR)
$(CC) $(CFLAGS_RELEASE) $< -o $@

# exes
# you will need a triple of exe and exe-debug and exe-tsan for each exe (other
# than provided exes)
$(EXE_BAR): $(OBJS_BAR:%.o=$(OBJS_DIR)/%-release.o)
$(LD) $^ $(LDFLAGS) -o $@

$(EXE_BAR)-debug: $(OBJS_BAR:%.o=$(OBJS_DIR)/%-debug.o)
$(LD) $^ $(LDFLAGS) -o $@

$(EXE_RENDE): $(OBJS_RENDE:%.o=$(OBJS_DIR)/%-release.o)
$(LD) $^ $(LDFLAGS) -o $@

$(EXE_QUEUE): $(OBJS_QUEUE:%.o=$(OBJS_DIR)/%-release.o)
$(LD) $^ $(LDFLAGS) -o $@

$(EXE_QUEUE)-debug: $(OBJS_QUEUE:%.o=$(OBJS_DIR)/%-debug.o)
$(LD) $^ $(LDFLAGS) -o $@

$(EXE_SEM): $(OBJS_SEM:%.o=$(OBJS_DIR)/%-release.o)
$(LD) $^ $(LDFLAGS) -o $@

$(EXE_SEM)-debug: $(OBJS_SEM:%.o=$(OBJS_DIR)/%-debug.o)
$(LD) $^ $(LDFLAGS) -o $@



.PHONY: clean
clean:
-rm -rf .objs $(EXES_STUDENT) $(EXES_STUDENT:%=%-debug)
18 changes: 18 additions & 0 deletions luscious_locks/barrier.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Luscious Locks Lab
* CS 241 - Fall 2016
*/
#include "barrier.h"

// The returns are just for errors if you want to check for them.
int barrier_destroy(barrier_t *barrier) {
int error = 0;
return error;
}

int barrier_init(barrier_t *barrier, unsigned int num_threads) {
int error = 0;
return error;
}

int barrier_wait(barrier_t *barrier) { return 0; }
28 changes: 28 additions & 0 deletions luscious_locks/barrier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Luscious Locks Lab
* CS 241 - Fall 2016
*/
#include <pthread.h>

typedef struct barrier_t {
pthread_mutex_t mtx;
pthread_cond_t cv;

// Total number of threads
unsigned int n_threads;

// Increasing or decreasing count
unsigned int count;

// Keeps track of what usage number of the barrier we are at
unsigned int times_used;
} barrier_t;

/**
* These functions behave near exactly like pthread_barrier's
* You should read the man pages for these to get a sense of how to
* implement them.
*/
int barrier_init(barrier_t *barrier, unsigned int num_threads);
int barrier_destroy(barrier_t *barrier);
int barrier_wait(barrier_t *barrier);
24 changes: 24 additions & 0 deletions luscious_locks/barrier_test_correct_output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Throwaway Test:
5
5
5
5
5
Reusable Test:
10
10
10
10
10
15
15
15
15
15
20
20
20
20
20
Test 1 passed
Test 2 passed
103 changes: 103 additions & 0 deletions luscious_locks/barrier_tests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* Luscious Locks Lab
* CS 241 - Fall 2016
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "barrier.h"

#define NUM_THREADS 5

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_t pthreads[NUM_THREADS];
barrier_t barrier;

long int count = 0;
int pass1, pass2;

void *thread_func_throwaway(void *var) {
sleep((long int)var);
pthread_mutex_lock(&mtx);
count++;
pthread_mutex_unlock(&mtx);
barrier_wait(&barrier);

return (void *)count;
}

void *thread_func_reusable(void *var) {
usleep((long int)var);
int i;
for (i = 0; i < 3; i++) {
pthread_mutex_lock(&mtx);
count++;
pthread_mutex_unlock(&mtx);
usleep((long int)var);
barrier_wait(&barrier);
pthread_mutex_lock(&mtx);
printf("%ld\n", count);
if (count % 5)
pass2 = 0;
pthread_mutex_unlock(&mtx);
barrier_wait(&barrier);
}

return (void *)count;
}

int main() {
long int i, ret;
pass1 = 1;
pass2 = 1;

pthread_mutex_init(&mtx, NULL);
barrier_init(&barrier, NUM_THREADS);

for (i = 0; i < NUM_THREADS; i++) {
pthread_create(&pthreads[i], NULL, &thread_func_throwaway, (void *)i);
}
printf("Throwaway Test:\n");
for (i = 0; i < NUM_THREADS; i++) {
pthread_join(pthreads[i], (void **)(&ret));
printf("%ld\n", ret);
if (ret != 5)
pass1 = 0;
}

printf("Reusable Test:\n");

int error;
for (i = 0; i < NUM_THREADS; i++) {
error =
pthread_create(&pthreads[i], NULL, &thread_func_reusable, (void *)i);
if (error) {
fprintf(stderr, "pthread_create failed with error %d\n", error);
exit(1);
}
}

for (i = 0; i < NUM_THREADS; i++) {
error = pthread_join(pthreads[i], (void **)(&ret));
if (error) {
fprintf(stderr, "pthread_join failed with error %d\n", error);
exit(1);
}
}

if (!pass1)
printf("Test 1 failed\n");
else
printf("Test 1 passed\n");
if (!pass2)
printf("Test 2 failed\n");
else
printf("Test 2 passed\n");

pthread_mutex_destroy(&mtx);
barrier_destroy(&barrier);

return 0;
}
59 changes: 59 additions & 0 deletions luscious_locks/queue.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Luscious Locks Lab
* CS 241 - Fall 2016
*/
#include "queue.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

/**
* Struct representing a node in a queue_t
*/
typedef struct queue_node_t {

struct queue_node_t *next;
void *data;
} queue_node_t;

/**
* Struct representing a queue
*/
struct queue_t {

queue_node_t *head, *tail;
int size;
int maxSize;
pthread_cond_t cv;
pthread_mutex_t m;
};

/**
* Given data, place it on the queue. Can be called by multiple threads.
* Blocks if the queue is full.
*/
void queue_push(queue_t *queue, void *data) { /* Your code here */ }

/**
* Retrieve the data from the front of the queue. Can be called by multiple
* threads.
* Blocks if the queue is empty.
*/
void *queue_pull(queue_t *queue) {
/* Your code here */
return NULL;
}

/**
* Allocates heap memory for a queue_t and initializes it.
* Returns a pointer to this allocated space.
*/
queue_t *queue_create(int maxSize) {
/* Your code here */
return NULL;
}

/**
* Destroys the queue, freeing any remaining nodes in it.
*/
void queue_destroy(queue_t *queue) { /* Your code here */ }
33 changes: 33 additions & 0 deletions luscious_locks/queue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Luscious Locks Lab
* CS 241 - Fall 2016
*/

/**
* Struct representing a queue
*/
typedef struct queue_t queue_t;

/**
* Given data, place it on the queue. Can be called by multiple threads.
* Blocks if the queue is full.
*/
void queue_push(queue_t *queue, void *data);

/**
* Retrieve the data from the front of the queue. Can be called by multiple
* threads.
* Blocks if the queue is empty.
*/
void *queue_pull(queue_t *queue);

/**
* Allocates heap memory for a queue_t and initializes it.
* Returns a pointer to this allocated space.
*/
queue_t *queue_create(int maxSize);

/**
* Destroys the queue, freeing any remaining nodes in it.
*/
void queue_destroy(queue_t *queue);
17 changes: 17 additions & 0 deletions luscious_locks/queue_tests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Luscious Locks Lab
* CS 241 - Fall 2016
*/
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "queue.h"

int main(int argc, char **argv) {

printf("Please write tests cases\n");
return 0;
}
Loading

0 comments on commit 5f76122

Please sign in to comment.