diff --git a/Makefile b/Makefile index 9697cba..5fb4ec5 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CFLAGS = -Iinc -pthread -lrt VPATH = src OBJECTS := %.o list.o producer.o transformer.o consumer.o -EXECUTE := main.out test.out +EXECUTE := main.out #test.out .PHONY: all clean diff --git a/inc/consumer.hpp b/inc/consumer.hpp index 99e2815..d5e7d7f 100644 --- a/inc/consumer.hpp +++ b/inc/consumer.hpp @@ -1,2 +1,8 @@ -void consumer (); \ No newline at end of file +/* + consumer: + Unlinks blocks from list2, + Consumes them, + Links them to freelist +*/ +void *consumer (void *); \ No newline at end of file diff --git a/inc/globals.hpp b/inc/globals.hpp index 3c04cd4..d4a6ad4 100644 --- a/inc/globals.hpp +++ b/inc/globals.hpp @@ -4,4 +4,9 @@ extern block memory[N]; // create the three lists extern list lists[3]; -extern list *freelist, *list1, *list2; \ No newline at end of file +extern list *freelist, *list1, *list2; + +// count semaphores +extern sem_t semfl, seml1, seml2; +// binary semaphores +extern sem_t mutfl, mutl1, mutl2; \ No newline at end of file diff --git a/inc/list.hpp b/inc/list.hpp index 9cbcd78..a5eb338 100644 --- a/inc/list.hpp +++ b/inc/list.hpp @@ -20,5 +20,4 @@ void list_link (list *l, block *b); // list_init: links an array of blocks onto the end of a list void list_init (list *l, block *m, int size); // list_print: prints a list -void list_print (list *l); -void list_concise(list *l); \ No newline at end of file +void list_print(list *l, bool verbose = false); \ No newline at end of file diff --git a/inc/producer.hpp b/inc/producer.hpp index 6198cf5..1d563be 100644 --- a/inc/producer.hpp +++ b/inc/producer.hpp @@ -1,2 +1,8 @@ -void producer (); \ No newline at end of file +/* + producer: + Unlinks blocks from freelist, + Produces them, + Links them to list1 +*/ +void *producer (void *); \ No newline at end of file diff --git a/inc/transformer.hpp b/inc/transformer.hpp index 15a543e..d11e4aa 100644 --- a/inc/transformer.hpp +++ b/inc/transformer.hpp @@ -1,2 +1,10 @@ -void transformer (); \ No newline at end of file +/* + transformer: + Unlinks block x from list1 + Unlinks block y from freelist + Uses block x to generate block y's data + Links block x to freelist + Links block y to list2 +*/ +void *transformer (void *); \ No newline at end of file diff --git a/src/consumer.cpp b/src/consumer.cpp index 30254d4..cd2ed4e 100644 --- a/src/consumer.cpp +++ b/src/consumer.cpp @@ -1,9 +1,29 @@ +#include +#include #include "list.hpp" -#include "globals.hpp" +#include "globals.hpp" // freelist list1 list2 #include "consumer.hpp" -void consumer () { - block* c = list_unlink(list2); - //TODO: consume information in block c - list_link(freelist, c); -} \ No newline at end of file +int consume(block* c); + +void *consumer (void *) { + while (true) { + sem_wait(&seml2); // decrease seml2 + sem_wait(&mutl2); + block* c = list_unlink(list2); + sem_post(&mutl2); + //* consume information in block c + consume(c); + sem_wait(&mutfl); + list_link(freelist, c); + sem_post(&mutfl); + sem_post(&semfl); // increase freelist + } + return nullptr; +} + +int consume(block *c) { + c->data = -c->data; + usleep(75); + return 0; +} diff --git a/src/list.cpp b/src/list.cpp index a1a2b49..48d74fd 100644 --- a/src/list.cpp +++ b/src/list.cpp @@ -60,7 +60,8 @@ void list_init (list *l, block *m, int size) { } // YAML-like, because I like YAML -void list_print(list *l) { + +void print_verbose(list *l) { if (!l) return; std::printf("l_%p:\n - start: '%p',\n - end: '%p',\n - length: '%d',\n - blocks:",l,l->start,l->end,l->length); block* b = l->start; @@ -73,17 +74,21 @@ void list_print(list *l) { std::printf(" []\n"); } } - -void list_concise (list *l) { +// l_[addr]{size}: {element:value, ...} +void print_concise(list *l) { if (!l) return; - std::printf("%lx: {", (__uint64_t)l&0xffff); + std::printf("l_%lx{%d}: {", (long int)l&0xffff, l->length); block *b = l->start; if (b) { do { - std::printf("%lx:%d, ", (__uint64_t)b&0xfff, b->data); + std::printf("%lx:%d, ", (long int)b&0xfff, b->data); } while (b = b->next); std::printf("\b\b} \n"); } else { std::printf("}\n"); } +} + +void list_print(list *l, bool verbose) { + (verbose?print_verbose:print_concise)(l); } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 8fa432b..4102cc1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,13 @@ -#include -#include +#include +#include +#include +#include +#include #include "list.hpp" #include "globals.hpp" #include "producer.hpp" +#include "consumer.hpp" +#include "transformer.hpp" // Create all of memory block memory[N] = {0}; @@ -10,9 +15,45 @@ block memory[N] = {0}; list lists[3] = {0}; list *freelist = &lists[0], *list1 = &lists[1], *list2 = &lists[2]; +// count semaphores +sem_t semfl, seml1, seml2; +// binary semaphores +sem_t mutfl, mutl1, mutl2; + int main (int argc, char* argv[]) { // initialize the freelist list_init(freelist, memory, N); - //TODO: Use pthreads to split execution + //TODO: Implement a semaphore solution to the problem + sem_init(&semfl, 0, freelist->length); + sem_init(&seml1, 0, 0); + sem_init(&seml2, 0, 0); + sem_init(&mutfl, 0, 1); + sem_init(&mutl1, 0, 1); + sem_init(&mutl2, 0, 1); + + //TODO: Use pthreads to split execution + // Make some pthreads + pthread_t thread1, thread2, thread3; + + // Create thread1 as producer + pthread_create(&thread1, NULL, producer, NULL); + + // Create thread2 as transformer + pthread_create(&thread2, NULL, transformer, NULL); + + // Create thread3 as consumer + pthread_create(&thread3, NULL, consumer, NULL); + + while (true) { + list_print(freelist); + list_print(list1); + list_print(list2); + sleep(1); + } + // Wait for them to finish + pthread_join(thread1, NULL); + pthread_join(thread2, NULL); + pthread_join(thread3, NULL); + } diff --git a/src/producer.cpp b/src/producer.cpp index 5e83cfe..985622f 100644 --- a/src/producer.cpp +++ b/src/producer.cpp @@ -1,9 +1,32 @@ +#include +#include #include "list.hpp" -#include "globals.hpp" +#include "globals.hpp" // freelist list1 list2 #include "producer.hpp" -void producer () { - block* b = list_unlink(freelist); - //TODO: Produce information in block b - list_link(list1, b); -} \ No newline at end of file +#define wait(x) sem_wait(&x) +#define sgnl(x) sem_post(&x) + +void produce(block* b); + +void *producer (void *) { + while (true) { + wait(semfl); // wait for freelist not empty + wait(mutfl); // lock freelist + block *b = list_unlink(freelist); + sgnl(mutfl); // unlock freelist + //* Produce information in block b + produce(b); + wait(mutl1); // lock l1 + list_link(list1, b); + sgnl(mutl1); // unlock l1 + sgnl(seml1); + } + return nullptr; +} + +void produce(block *b) { + b->data++; + usleep(65); + return; +} diff --git a/src/test.cpp b/src/test.cpp index 93696cc..8af736d 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -1,5 +1,6 @@ -#include -#include +#include +#include +#include #include "list.hpp" #include "globals.hpp" #include "producer.hpp" @@ -14,42 +15,47 @@ list *freelist = &lists[0], *list1 = &lists[1], *list2 = &lists[2]; +// count semaphores +sem_t semfl, seml1, seml2; +// binary semaphores +sem_t mutfl, mutl1, mutl2; + void producer_test(); void transfer_test(); void consumer_test(); int main(int argc, char *argv[]) { list_init(freelist, memory, N); - list_concise(freelist); - producer_test(); - transfer_test(); - consumer_test(); + list_print(freelist); + //producer_test(); + //transfer_test(); + //consumer_test(); } void producer_test() { printf("Starting producer_test:\n");\ - producer(); - list_concise(freelist); - list_concise(list1); - list_concise(list2); + producer(NULL); + list_print(freelist); + list_print(list1); + list_print(list2); printf("Ending producer_test\n"); } void transfer_test() { printf("Starting transfer_test:\n"); - transformer(); - list_concise(freelist); - list_concise(list1); - list_concise(list2); + transformer(NULL); + list_print(freelist); + list_print(list1); + list_print(list2); printf("Ending transfer_test\n"); } void consumer_test() { printf("Starting consumer_test:\n"); - consumer(); - list_concise(freelist); - list_concise(list1); - list_concise(list2); + consumer(NULL); + list_print(freelist); + list_print(list1); + list_print(list2); printf("Ending consumer_test\n"); } diff --git a/src/transformer.cpp b/src/transformer.cpp index 012239b..64768aa 100644 --- a/src/transformer.cpp +++ b/src/transformer.cpp @@ -1,11 +1,44 @@ +#include +#include #include "list.hpp" -#include "globals.hpp" +#include "globals.hpp" // freelist list1 list2 #include "transformer.hpp" -void transformer () { - block* x = list_unlink(list1); - block* y = list_unlink(freelist); - //TODO: use block x to produce info in y - list_link(freelist, x); - list_link(list2, y); -} \ No newline at end of file +void transform(block* x, block* y); + +void *transformer (void *) { + block *x, *y; + while (true) { + sem_wait(&seml1); // decrease seml1 + sem_wait(&mutl1); + x = list_unlink(list1); + sem_post(&mutl1); + + sem_wait(&semfl); // decrease semfl + sem_wait(&mutfl); + y = list_unlink(freelist); + sem_post(&mutfl); + + //* use block x to produce info in y + transform(x, y); + + sem_wait(&mutfl); + list_link(freelist, x); + sem_post(&mutfl); + sem_post(&semfl); + + sem_wait(&mutl2); + list_link(list2, y); + sem_post(&mutl2); + sem_post(&seml2); + } + return nullptr; +} + +void transform(block *x, block *y) { + x->data ^= y->data; + y->data ^= x->data; + x->data ^= y->data; + usleep(55); + return; +}