diff --git a/Makefile b/Makefile index 9b83028..1e4d0d2 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,21 @@ CC = gcc CFLAGS = -Wall -Wpedantic LD = gcc -LDFLAGS = +LDFLAGS = -lpthread -lrt BIN_NAME = cfloor all: $(BIN_NAME) -test: obj/test.o obj/networking.o - $(LD) -o $@ $^ +test: obj/test.o obj/networking.o obj/linked.o + $(LD) $(LDFLAGS) -o $@ $^ +obj/test.o: src/networking.h obj/networking.o: src/networking.h src/headers.h +obj/linked.o: src/linked.h obj/%.o: src/%.c obj - $(CC) -c -o $@ $< + $(CC) $(CFLAGS) -c -o $@ $< obj: @mkdir -p obj diff --git a/src/linked.c b/src/linked.c index e69de29..1fbcca6 100644 --- a/src/linked.c +++ b/src/linked.c @@ -0,0 +1,205 @@ +#include +#include +#include + +#include "linked.h" + +linkedList_t linked_create() { + linkedList_t list = { + .first = NULL + }; + sem_init(&(list.modify_sem), 0, 1); + return list; +} + +size_t linked_push(linkedList_t* list, void* data) { + link_t* new = malloc(sizeof (link_t)); + if (new == NULL) + return -1; + + new->data = data; + sem_init(&(new->modify_sem), 0, 1); + new->inUse = 0; + new->list = list; + new->next = NULL; + new->unlinked = false; + + size_t index = 0; + + link_t* current = NULL; + + sem_wait(&(list->modify_sem)); + current = list->first; + if (current == NULL) { + new->prev = NULL; + list->first = new; + sem_post(&(list->modify_sem)); + return index; + } + sem_post(&(list->modify_sem)); + + index++; + sem_wait(&(current->modify_sem)); + while(current->next != NULL) { + sem_wait(&(current->next->modify_sem)); + sem_post(&(current->modify_sem)); + current = current->next; + index++; + } + + new->prev = current; + current->next = new; + + sem_post(&(current->modify_sem)); + + return index; +} + +link_t* linked_first(linkedList_t* list) { + if (list->first == NULL) { + return NULL; + } + link_t* link = list->first; + + link->inUse++; + + return link; +} + +void linked_free(link_t* link) { + free(link); +} + +void linked_unlock(link_t* link) { + link->inUse--; + + if (link->unlinked && link->inUse == 0) { + linked_free(link); + } +} + +link_t* linked_next(link_t* link) { + linked_unlock(link); + + if (link->next == NULL) { + return NULL; + } + link = link->next; + + link->inUse++; + + return link; +} + +link_t* linked_get(linkedList_t* list, size_t index) { + link_t* link = linked_first(list); + + while(link != NULL) { + if (index-- == 0) { + return link; + } + + link = linked_next(link); + } + + return NULL; +} + +size_t linked_length(linkedList_t* list) { + link_t* link = linked_first(list); + + size_t length = 0; + + while(link != NULL) { + length++; + link = linked_next(link); + } + + return length; +} + +int linked_unlink(link_t* link) { + // need to get prev sem before link sem to avoid dead lock + sem_t* prevModify = NULL; + link_t** prevNext = NULL; + + while(true) { + /* + * Try to lock prev. If locked prev was modified try again. + * Abort if link is unlinked. + */ + + link_t* prev = link->prev; + if (prev == NULL) { + sem_wait(&(link->list->modify_sem)); + if (link->list->first != link) { + sem_post(&(link->list->modify_sem)); + if (link->unlinked) { + return -1; + } + continue; + } + prevModify = &(link->list->modify_sem); + prevNext = &(link->list->first); + break; + } else { + sem_wait(&(prev->modify_sem)); + if (prev->next != link) { + sem_post(&(prev->modify_sem)); + if (link->unlinked) { + return - 1; + } + continue; + } + prevModify = &(prev->modify_sem); + prevNext = &(prev->next); + break; + } + } + + sem_wait(&(link->modify_sem)); + + if (link->unlinked) { + sem_post(&(link->modify_sem)); + sem_post(prevModify); + return - 1; + } + + if (link->next) { + sem_wait(&(link->next->modify_sem)); + // we don't need to check for changes because link is already locked + + // while we are here we can modify next + link->next->prev = link->prev; + + // we don't need this one anymore + sem_post(&(link->next->modify_sem)); + } + + link->unlinked = true; + + *prevNext = link->next; + + // everything is done + + sem_post(&(link->modify_sem)); + + sem_post(prevModify); + + if (link->inUse == 0) { + linked_free(link); + } + + return 0; +} + +void linked_destroy(linkedList_t* list) { + link_t* link = linked_first(list); + + while(link != NULL) { + link_t* next = link->next; + linked_unlink(link); + link = next; + } +} + diff --git a/src/linked.h b/src/linked.h index e69de29..0130281 100644 --- a/src/linked.h +++ b/src/linked.h @@ -0,0 +1,33 @@ +#ifndef LINKED_H +#define LINKED_H + +#include +#include +#include + +typedef struct linkedList { + sem_t modify_sem; + struct link* first; +} linkedList_t; + +typedef struct link { + void* data; + sem_t modify_sem; + volatile sig_atomic_t inUse; + bool unlinked; + struct link* next; + struct link* prev; + struct linkedList* list; +} link_t; + +linkedList_t linked_create(); +size_t linked_push(linkedList_t* list, void* data); +link_t* linked_first(linkedList_t* list); +link_t* linked_next(link_t* link); +size_t linked_length(linkedList_t* list); +void linked_unlock(link_t* link); +link_t* linked_get(linkedList_t* list, size_t index); +int linked_unlink(link_t* link); +void linked_destroy(linkedList_t* list); + +#endif diff --git a/src/main.c b/src/main.c index 86cb63f..2d5df3a 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ -int main(int argc, char* argv) { +int main(int argc, char** argv) { } diff --git a/src/test.c b/src/test.c index f6a919d..d63c1fc 100644 --- a/src/test.c +++ b/src/test.c @@ -6,7 +6,7 @@ handler_t handlerGetter(struct metaData metaData, const char* host) { return NULL; } -int main(int argc, char* argv) { +int main(int argc, char** argv) { initNetworking((struct networkingConfig) { .connectionTimeout = 30000, .defaultResponse = {