diff --git a/mutex_barriers/ex3/.gitignore b/mutex_barriers/ex3/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7ed204fb7126f174687df888937e9c7f61c1b9f7 --- /dev/null +++ b/mutex_barriers/ex3/.gitignore @@ -0,0 +1,2 @@ +*.o +Ex3_etu diff --git a/mutex_barriers/ex3/Ex3_etu.c b/mutex_barriers/ex3/Ex3_etu.c new file mode 100644 index 0000000000000000000000000000000000000000..9c12921819f02b3b0111891e6d6bd1de1d9b8f20 --- /dev/null +++ b/mutex_barriers/ex3/Ex3_etu.c @@ -0,0 +1,169 @@ +#include "thread_wrapper.h" +// #include <assert.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define DEBUG true + +#define STACK_SIZE 100000 +#define THREAD_COUNT 100 +#define NB_OF_PUSH_POP 1000 + +// Barrier used to make sure all threads are created and ready before starting +// to run the stack test +pthread_barrier_t *b; + +typedef struct { + int *ptr; + int size; + int capacity; + pthread_mutex_t lock; +} stack_t; + +typedef struct { + int id; + stack_t *stack; +} thr_params; + +bool stack_create(stack_t *s, int max_size) { + if (max_size < 1) { + fprintf(stderr, "Stack size has to be equal to or greater than 1"); + return false; + } + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + + pthread_mutex_init(&s->lock, &attr); + + // pthread_mutexattr_destroy(&attr); + + s->ptr = malloc(max_size * sizeof(int)); + s->capacity = max_size; + s->size = 0; + + return true; +} + +bool stack_is_empty(stack_t *s) { return s->size == 0; } + +void stack_push(stack_t *s, int val) { + if (s->size < s->capacity) { + pthread_mutex_lock(&s->lock); + s->ptr[(s->capacity - 1) - s->size] = val; + s->size++; + pthread_mutex_unlock(&s->lock); + // fprintf(stderr, "%d has been inserted\n", val); + } else { + fprintf(stderr, "Stack is full\n"); + } +} + +// Returns -1 in case of an error +int stack_pop(stack_t *s) { + if (stack_is_empty(s)) { + fprintf(stderr, "Stack is empty\n"); + return -1; + } + + pthread_mutex_lock(&s->lock); + int ret = s->ptr[s->capacity - s->size]; + s->size--; + pthread_mutex_unlock(&s->lock); + + return ret; +} + +void stack_destroy(stack_t *s) { + if (s->ptr != NULL) { + pthread_mutex_destroy(&s->lock); + free(s->ptr); + } +} + +void *test_stack(void *data) { + bar_wait(b); + + thr_params *p = (thr_params *)data; + + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + unsigned int seed = (unsigned int)ts.tv_nsec; + + for (int i = 0; i < NB_OF_PUSH_POP; i++) { + // push + int val = rand_r(&seed) % 1000; + stack_push(p->stack, val); + + // pop + if (!stack_is_empty(p->stack)) { + stack_pop(p->stack); + } + } + return NULL; +} + +// Testing if stack is correctly implemented in a single-threaded setting +// int main(void) { +// stack_t s; +// +// if (!stack_create(&s, 10)) { +// exit(EXIT_FAILURE); +// } +// +// for (int i = 0; i < 10; i++) { +// stack_push(&s, i); +// } +// +// for (int i = 0; i < 20; i++) { +// fprintf(stdout, "stack_pop returned: %d\n", stack_pop(&s)); +// } +// +// stack_destroy(&s); +// +// return EXIT_SUCCESS; +// } + +int main() { + b = bar_create(THREAD_COUNT); + + stack_t s; + if (!stack_create(&s, STACK_SIZE)) { + fprintf(stderr, "Failed creating stack!\n"); + return EXIT_FAILURE; + } +#ifdef DEBUG + printf("Created stack of %d\n", STACK_SIZE); +#endif + +#ifdef DEBUG + printf("Launching %d threads\n", THREAD_COUNT); +#endif + pthread_t t[THREAD_COUNT]; + thr_params p[THREAD_COUNT]; + for (int i = 0; i < THREAD_COUNT; i++) { + p[i].id = i; + p[i].stack = &s; + thread_create(&t[i], test_stack, &p[i]); + } + + for (int i = 0; i < THREAD_COUNT; i++) + thread_join(t[i], NULL); + +#ifdef DEBUG + printf("Stack empty ? %s\n", stack_is_empty(&s) ? "yes" : "NO!"); +#endif + + stack_destroy(&s); +#ifdef DEBUG + printf("Stack destroyed\n"); +#endif + + bar_destroy(b); + + return EXIT_SUCCESS; +} diff --git a/mutex_barriers/ex3/Makefile b/mutex_barriers/ex3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ffb039b962083cfe1e4f3345ccdde9e374b08482 --- /dev/null +++ b/mutex_barriers/ex3/Makefile @@ -0,0 +1,21 @@ +CC=gcc -Wall -Wextra -std=gnu99 -g +LIBS=-lpthread -lm -lrt +SRCS=$(wildcard *.c) +OBJS=$(SRCS:.c=.o) +BINS=$(SRCS:%.c=%) + +all: Ex3_etu + + +Ex3_etu: Ex3_etu.o thread_wrapper.o + $(CC) $^ -o $@ $(LIBS) + +Ex3_etu.o: Ex3_etu.c thread_wrapper.h + $(CC) $< -c + + +thread_wrapper.o: thread_wrapper.c thread_wrapper.h + $(CC) $< -c + +clean: + rm -f $(BINS) $(OBJS) diff --git a/mutex_barriers/ex3/thread_wrapper.c b/mutex_barriers/ex3/thread_wrapper.c new file mode 100644 index 0000000000000000000000000000000000000000..6ac8f650c3ad7c3e029bf494e5fcde3451dbdf81 --- /dev/null +++ b/mutex_barriers/ex3/thread_wrapper.c @@ -0,0 +1,63 @@ +#include <error.h> +#include <errno.h> +#include <stdlib.h> +#include "thread_wrapper.h" + +#define ERR_CODE 1 + +pthread_mutex_t *mutex_create() { + pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t)); + if (!mutex) error(ERR_CODE, ENOMEM, "malloc failed!"); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + int status = pthread_mutex_init(mutex, &attr); + if (status) error(ERR_CODE, status, "pthread_mutex_init failed!"); + pthread_mutexattr_destroy(&attr); + return mutex; +} + +void mutex_lock(pthread_mutex_t *mutex) { + int status = pthread_mutex_lock(mutex); + if (status) error(ERR_CODE, status, "pthread_mutex_lock failed!"); +} + +void mutex_unlock(pthread_mutex_t *mutex) { + int status = pthread_mutex_unlock(mutex); + if (status) error(ERR_CODE, status, "pthread_mutex_unlock failed!"); +} + +void mutex_destroy(pthread_mutex_t *mutex) { + int status = pthread_mutex_destroy(mutex); + if (status) error(ERR_CODE, status, "pthread_mutex_destroy failed!"); + free(mutex); +} + +pthread_barrier_t *bar_create(int count) { + pthread_barrier_t *b = malloc(sizeof(pthread_barrier_t)); + int status = pthread_barrier_init(b, NULL, count); + if (status) error(ERR_CODE, status, "pthread_barrier_init failed!"); + return b; +} + +void bar_destroy(pthread_barrier_t *b) { + int status = pthread_barrier_destroy(b); + if (status) error(ERR_CODE, status, "pthread_barrier_destroy failed!"); + free(b); +} + +void bar_wait(pthread_barrier_t *b) { + int status = pthread_barrier_wait(b); + if (status != PTHREAD_BARRIER_SERIAL_THREAD && status != 0) error(ERR_CODE, status, "pthread_barrier_wait failed!"); +} + +void thread_create(pthread_t *thread, void *(*start_routine)(void *), void *arg) { + int status = pthread_create(thread, NULL, start_routine, arg); + if (status) error(ERR_CODE, status, "pthread_create failed!"); +} + +void thread_join(pthread_t thread, void **retval) { + int status = pthread_join(thread, retval); + if (status) error(ERR_CODE, status, "pthread_join failed!"); +} + diff --git a/mutex_barriers/ex3/thread_wrapper.h b/mutex_barriers/ex3/thread_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..40646c80ab9d048c5ff31f38b6244ca7f5c6b03a --- /dev/null +++ b/mutex_barriers/ex3/thread_wrapper.h @@ -0,0 +1,16 @@ +#ifndef _THREAD_WRAPPER_H_ +#define _THREAD_WRAPPER_H_ + +#include <pthread.h> + +extern pthread_mutex_t *mutex_create(); +extern void mutex_lock(pthread_mutex_t *mutex); +extern void mutex_unlock(pthread_mutex_t *mutex); +extern void mutex_destroy(pthread_mutex_t *mutex); +extern pthread_barrier_t *bar_create(int count); +extern void bar_destroy(pthread_barrier_t *b); +extern void bar_wait(pthread_barrier_t *b); +extern void thread_create(pthread_t *thread, void *(*start_routine)(void *), void *arg); +extern void thread_join(pthread_t thread, void **retval); + +#endif