Added file queue handling
This commit is contained in:
@ -1,3 +1,8 @@
|
||||
[threadpool]
|
||||
|
||||
quantity = 10
|
||||
quantity = 10
|
||||
|
||||
[files]
|
||||
|
||||
MaxFiles = 20
|
||||
MaxSize = 10000000
|
||||
726
lib/threadpool/fileQueue.c
Normal file
726
lib/threadpool/fileQueue.c
Normal file
@ -0,0 +1,726 @@
|
||||
#include <fileQueue.h>
|
||||
#include <util.h>
|
||||
|
||||
#define NAMELEN 256
|
||||
|
||||
// creazione di un fileT
|
||||
fileT* createFileT(char *f, int O_LOCK, int client, int open){
|
||||
if(!f){
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fileT *file = malloc(sizeof(fileT));
|
||||
|
||||
if (f == NULL) {
|
||||
perror("Malloc createFileT");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->O_LOCK = (O_LOCK == 0)? 0 : 1;
|
||||
f->owner = client;
|
||||
f->open = (open == 0)? 0 : 1;
|
||||
f->size = 0;
|
||||
|
||||
if ((f->filepath = malloc(sizeof(char)*NAMELEN)) == NULL) {
|
||||
perror("Malloc filepath");
|
||||
destroyFile(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(f->filepath, f, NAMELEN);
|
||||
|
||||
if ((f->data = malloc(1)) == NULL) { // così semplicemente facciamo realloc
|
||||
perror("Malloc content");
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
// append su fileT
|
||||
int writeFileT(fileT *f, void *data, size_t size) {
|
||||
if(!f || !data || size < 0){
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((f->data = realloc(f->data, f->size + size)) == NULL) {
|
||||
perror("Realloc content");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy((char*) f->data + f->size, data, size);
|
||||
f->size = f->size + size;
|
||||
}
|
||||
|
||||
// destroy fileT
|
||||
void destroyFile(fileT *f) {
|
||||
if(!f)
|
||||
return;
|
||||
if(f->filepath)
|
||||
free(f->filepath);
|
||||
if(f->data)
|
||||
free(f->data);
|
||||
free(f);
|
||||
}
|
||||
|
||||
// --------------
|
||||
|
||||
// creazione queue
|
||||
queueT* createQueue(size_t maxLen, size_t maxSize) {
|
||||
if(maxLen<0 || maxSize<0){
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queueT *q = malloc(sizeof(queueT));
|
||||
if(q==NULL){
|
||||
perror("Malloc createQueue");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// creazione lock
|
||||
if (pthread_mutex_init(&q->m, NULL) != 0) {
|
||||
perror("pthread_mutex_init createQueue");
|
||||
destroyQueue(q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
q->maxLen = maxLen;
|
||||
q->len = 0;
|
||||
q->maxSize = maxSize;
|
||||
q->size = 0;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
// insert
|
||||
int enqueue(queueT *q, fileT* data) {
|
||||
if(!q || !data){
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == q->maxLen) { // too many files
|
||||
errno = ENFILE;
|
||||
goto _end_enqueue;
|
||||
}
|
||||
|
||||
if (q->size + data->size > q->maxSize) {
|
||||
errno = EFBIG;
|
||||
goto _end_enqueue;
|
||||
}
|
||||
|
||||
// inserisco l'elemento
|
||||
nodeT *newNode = malloc(sizeof(nodeT));
|
||||
if (newNode == NULL) {
|
||||
perror("malloc newNode");
|
||||
goto _end_enqueue;
|
||||
}
|
||||
|
||||
newNode->data = data;
|
||||
newNode->next = NULL;
|
||||
nodeT *tmp = queue->head;
|
||||
|
||||
if (q->head == NULL)
|
||||
q->head = newNode;
|
||||
else {
|
||||
while (tmp->next)
|
||||
tmp = temp->next;
|
||||
|
||||
temp->next = newNode;
|
||||
}
|
||||
|
||||
q->tail = newNode;
|
||||
|
||||
++q->len;
|
||||
q->size += data->size;
|
||||
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_enqueue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// remove
|
||||
fileT* dequeue(queueT *q) {
|
||||
if(!q) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, NULL); // begin me
|
||||
|
||||
if (q->head == NULL || q->len == 0) { // coda vuota
|
||||
errno = ENOENT;
|
||||
goto _end_dequeue;
|
||||
}
|
||||
|
||||
fileT *data = (q->head)->data;
|
||||
|
||||
nodeT *tmp = NULL;
|
||||
tmp = q->head;
|
||||
q->head = (q->head)->next;
|
||||
|
||||
if (q->head == NULL) { // coda diventa vuota
|
||||
q->tail = NULL;
|
||||
}
|
||||
|
||||
--q->len;
|
||||
q->size -= data->size;
|
||||
free(tmp); // free del nodo
|
||||
|
||||
UNLOCK_RETURN(&q->m, NULL); // end me
|
||||
return data;
|
||||
|
||||
_end_dequeue:
|
||||
UNLOCK_RETURN(&q->m, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void voidDequeue(queueT *q) {
|
||||
if(!q) {
|
||||
errno = EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK(&q->m); // begin me
|
||||
|
||||
if (q->head == NULL || q->len == 0) { // coda vuota
|
||||
errno = ENOENT;
|
||||
goto _end_void_dequeue;
|
||||
}
|
||||
|
||||
nodeT *tmp = NULL;
|
||||
tmp = q->head;
|
||||
|
||||
q->head = (q->head)->next;
|
||||
|
||||
if (q->head == NULL) { // coda diventa vuota
|
||||
q->tail = NULL;
|
||||
}
|
||||
|
||||
--q->len;
|
||||
q->size -= data->size;
|
||||
|
||||
destroyFile(tmp->data); // free fileT
|
||||
free(tmp); // free nodo
|
||||
|
||||
UNLOCK(&q->m); // end me
|
||||
return;
|
||||
|
||||
_end_void_dequeue:
|
||||
UNLOCK_RETURN(&q->m, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// print queue
|
||||
int printQueue(FILE *stream, queueT *q) {
|
||||
if(!q || !stream) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return 0;
|
||||
|
||||
nodeT *tmp = q->head;
|
||||
|
||||
fprintf(stream, "Lista file:");
|
||||
fprintf(stream, "[Nome File] -> Dimensione in MB");
|
||||
while (temp!=NULL) {
|
||||
float res = ((float)(tmp->data)->size)/1000000; // in MB
|
||||
fprintf(stream, "[%s]\t-> %f MB\n", (tmp->data)->filepath, res);
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_print_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// acquisizione lock
|
||||
int lockFileInQueue(queueT *q, char *filepath, int owner) {
|
||||
if(!q || !filepath) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == 0) {
|
||||
errno = ENOENT;
|
||||
goto _end_lock_file_queue;
|
||||
}
|
||||
|
||||
// scorro la queue per trovare l'elemento
|
||||
nodeT *tmp = q->head;
|
||||
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if(!tmp) { // non trovato
|
||||
errno = ENOENT;
|
||||
goto _end_lock_file_queue;
|
||||
}
|
||||
|
||||
if ((tmp->data)->O_LOCK && (tmp->data)->owner != owner) { // lock non del owner
|
||||
errno = EPERM;
|
||||
goto _end_lock_file_queue;
|
||||
}
|
||||
|
||||
// acquisisco lock sul file
|
||||
(temp->data)->O_LOCK = 1;
|
||||
(temp->data)->owner = owner;
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_lock_file_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int unlockFileInQueue(queueT *q, char *filepath, int owner) {
|
||||
if(!q || !filepath) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == 0) {
|
||||
errno = ENOENT;
|
||||
goto _end_unlock_file_queue;
|
||||
}
|
||||
|
||||
// scorro la queue per trovare l'elemento
|
||||
nodeT *tmp = q->head;
|
||||
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if(!tmp) { // non trovato
|
||||
errno = ENOENT;
|
||||
goto _end_lock_file_queue;
|
||||
}
|
||||
|
||||
if((tmp->data)->O_LOCK == 0) { // nessuno ha il lock
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner
|
||||
errno = EPERM;
|
||||
goto _end_unlock_file_queue;
|
||||
}
|
||||
|
||||
(tmp->data)->O_LOCK = 0;
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_unlock_file_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// open file
|
||||
int openFileInQueue(queueT *q, char *filepath, int O_LOCK, int owner) {
|
||||
if(!q || !filepath) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == 0) {
|
||||
errno = ENOENT;
|
||||
goto _end_open_file_queue;
|
||||
}
|
||||
|
||||
// scorro la queue per trovare l'elemento
|
||||
nodeT *tmp = q->head;
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if(!tmp) { // non trovato
|
||||
errno = ENOENT;
|
||||
goto _end_open_file_queue;
|
||||
}
|
||||
|
||||
if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner
|
||||
errno = EPERM;
|
||||
goto _end_open_file_queue;
|
||||
}
|
||||
|
||||
(tmp->data)->open = 1;
|
||||
(tmp->data)->O_LOCK = (O_LOCK==0)?0:1;
|
||||
|
||||
if(O_LOCK!=0) {
|
||||
(tmp->data)->owner = client;
|
||||
}
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_open_file_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// close and relese lock
|
||||
int closeFileInQueue(queueT *q, char *filepath, int owner) {
|
||||
if(!q || !filepath) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == 0) {
|
||||
errno = ENOENT;
|
||||
goto _end_close_file_queue;
|
||||
}
|
||||
|
||||
// scorro la queue per trovare l'elemento
|
||||
nodeT *tmp = q->head;
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if(!tmp) { // non trovato
|
||||
errno = ENOENT;
|
||||
goto _end_close_file_queue;
|
||||
}
|
||||
|
||||
if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner
|
||||
errno = EPERM;
|
||||
goto _end_close_file_queue;
|
||||
}
|
||||
|
||||
(tmp->data)->open = 0;
|
||||
(tmp->data)->O_LOCK = 0;
|
||||
(tmp->data)->owner = owner;
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_open_file_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int writeFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner) {
|
||||
if(!q || !filepath || !data) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(size == 0)
|
||||
return 0;
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == 0) { // coda vuota
|
||||
errno = ENOENT;
|
||||
goto _end_write_file_queue;
|
||||
}
|
||||
|
||||
if (q->size + size > q->maxSize) { // non c'e' abbastanza spazio
|
||||
errno = EFBIG;
|
||||
goto _end_write_file_queue;
|
||||
}
|
||||
|
||||
// scorro la queue per trovare l'elemento
|
||||
nodeT *tmp = q->head;
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if(!tmp) { // non trovato
|
||||
errno = ENOENT;
|
||||
goto _end_write_file_queue;
|
||||
}
|
||||
|
||||
if ((tmp->data)->open == 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) {
|
||||
// if file non è aperto o la lock non è del owner
|
||||
errno = EPERM;
|
||||
goto _end_write_file_queue;
|
||||
}
|
||||
|
||||
// scrivo
|
||||
if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->size + size)) == NULL) {
|
||||
perror("Realloc content");
|
||||
goto _end_write_file_queue;
|
||||
}
|
||||
memcpy((tmp->data)->data, data, size);
|
||||
|
||||
q->size = (q->size) - ((tmp->data)->size) + size;
|
||||
(tmp->data)->size = size;
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_write_file_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int appendFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner) {
|
||||
if (!q || !filepath || !data) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == 0) { // coda vuota
|
||||
errno = ENOENT;
|
||||
goto _end_append_file_queue;
|
||||
}
|
||||
|
||||
if (q->size + size > q->maxSize) { // non c'e' abbastanza spazio
|
||||
errno = EFBIG;
|
||||
goto _end_append_file_queue;
|
||||
}
|
||||
|
||||
// scorro la queue per trovare l'elemento
|
||||
nodeT *tmp = q->head;
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if(!tmp) { // non trovato
|
||||
errno = ENOENT;
|
||||
goto _end_append_file_queue;
|
||||
}
|
||||
|
||||
if ((tmp->data)->open == 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) {
|
||||
// if file non è aperto o la lock non è del owner
|
||||
errno = EPERM;
|
||||
goto _end_append_file_queue;
|
||||
}
|
||||
|
||||
// scrivo
|
||||
if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->size + size)) == NULL) {
|
||||
perror("Realloc content");
|
||||
goto _end_append_file_queue;
|
||||
}
|
||||
|
||||
memcpy(((tmp->data)->data) + (tmp->data)->size, data, size);
|
||||
// memmove sarebbe un'alternativa
|
||||
(tmp->data)->size += size;
|
||||
q->size += size;
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_append_file_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int removeFileFromQueue(queueT *q, char *filepath, int owner) {
|
||||
if(!q || !filepath) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
if (q->len == 0) { // coda vuota
|
||||
errno = ENOENT;
|
||||
goto _end_remove_file_queue;
|
||||
}
|
||||
|
||||
// scorro la queue per trovare l'elemento
|
||||
nodeT *tmp = q->head;
|
||||
nodeT *pre = q->head;
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
if(prc!=tmp)
|
||||
prc = prc->next;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (!tmp) { // non trovato
|
||||
errno = ENOENT;
|
||||
goto _end_remove_file_queue;
|
||||
}
|
||||
|
||||
if ((tmp->data)->open != 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) {
|
||||
// if file è aperto o la lock non è del owner
|
||||
errno = EPERM;
|
||||
goto _end_append_file_queue;
|
||||
}
|
||||
|
||||
if (tmp == prc) { // file è il primo
|
||||
q->head = tmp->next;
|
||||
|
||||
if (tmp->next == NULL) {
|
||||
q->tail = tmp;
|
||||
}
|
||||
} else { // file non è il primo
|
||||
prc->next = tmp->next;
|
||||
|
||||
if (prc->next == NULL) {
|
||||
q->tail = prc;
|
||||
}
|
||||
}
|
||||
|
||||
--q->len;
|
||||
q->size -= (tmp->data)->size;
|
||||
destroyFile(tmp->data); // free file
|
||||
free(tmp); // free node
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return 0;
|
||||
|
||||
_end_remove_file_queue:
|
||||
UNLOCK_RETURN(&q->m, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// ----------------
|
||||
|
||||
// cerco e ritorno una copia
|
||||
fileT* find(queueT *q, char *filepath) {
|
||||
if(!q || !filepath) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOCK_RETURN(&q->m, NULL); // begin me
|
||||
|
||||
if (q->len == 0)
|
||||
goto _end_find_in_queue;
|
||||
|
||||
fileT *res = NULL;
|
||||
nodeT *tmp = q->head;
|
||||
|
||||
while (tmp) {
|
||||
if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if(!tmp)
|
||||
goto _end_find_in_queue;
|
||||
|
||||
// creo una nuova istanza
|
||||
res = createFileT((tmp->data)->filepath, (tmp->data)->O_LOCK, (tmp->data)->owner, (tmp->data)->open);
|
||||
|
||||
if (!res) {
|
||||
perror("createFileT res");
|
||||
goto _end_find_in_queue;
|
||||
}
|
||||
|
||||
if (writeFileT(res, (tmp->data)->data, (tmp->data)->size) == -1) {
|
||||
perror("writeFileT res");
|
||||
goto _end_find_in_queue;
|
||||
}
|
||||
|
||||
UNLOCK_RETURN(&q->m, NULL); // end me
|
||||
return res;
|
||||
|
||||
_end_find_in_queue:
|
||||
UNLOCK_RETURN(&q->m, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// numero di elementi della queue
|
||||
size_t getLen(queueT *q) {
|
||||
if(!q) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
size_t len = -1;
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
len = queue->len;
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return len;
|
||||
}
|
||||
|
||||
// dimensione in byte
|
||||
size_t getSize(queueT *q) {
|
||||
if(!q) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
size_t size = -1;
|
||||
|
||||
LOCK_RETURN(&q->m, -1); // begin me
|
||||
|
||||
size = q->size;
|
||||
|
||||
UNLOCK_RETURN(&q->m, -1); // end me
|
||||
return size;
|
||||
}
|
||||
|
||||
void destroyQueue(queueT *q) {
|
||||
if(!q)
|
||||
return;
|
||||
|
||||
// no need for lock over queue
|
||||
while (q->len > 0) {
|
||||
errno = 0;
|
||||
voiDequeue(q);
|
||||
if (errno) {
|
||||
perror("voiDequeue");
|
||||
}
|
||||
}
|
||||
|
||||
if (&queue->m) {
|
||||
pthread_mutex_destroy(&q->m);
|
||||
}
|
||||
|
||||
free(queue);
|
||||
}
|
||||
224
lib/threadpool/fileQueue.h
Normal file
224
lib/threadpool/fileQueue.h
Normal file
@ -0,0 +1,224 @@
|
||||
#pragma once
|
||||
#ifndef _FILE_QUEUE
|
||||
#define _FILE_QUEUE
|
||||
|
||||
|
||||
// struttura dati per gestire i file in memoria principale
|
||||
typedef struct {
|
||||
char *filepath; // path assoluto del file
|
||||
int O_LOCK; // 1 se il file e' in modalita' locked
|
||||
int owner; // client che possiede la lock sul file
|
||||
int open; // 1 se il file e' aperto
|
||||
void *data; // contenuto del file
|
||||
size_t size; // dimensione del file in bytes
|
||||
} fileT;
|
||||
|
||||
// nodo di una linked list
|
||||
typedef struct node {
|
||||
fileT *data;
|
||||
struct node *next;
|
||||
} nodeT;
|
||||
|
||||
// coda FIFO
|
||||
typedef struct {
|
||||
nodeT *head; // puntatore al primo elemento
|
||||
nodeT *tail; // puntatore all'ultimo elemento
|
||||
size_t maxLen; // numero massimo di elementi
|
||||
size_t len; // numero attuale di elementi
|
||||
size_t maxSize; // dimensione massima
|
||||
size_t size; // dimensione attuale
|
||||
pthread_mutex_t m; // lock sulla coda
|
||||
} queueT;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creazione di un fileT.
|
||||
* \param f: string che identifica il fileT tramite il suo path assoluto
|
||||
* \param O_LOCK: 1 locked, 0 unlocked
|
||||
* \param client: client associato
|
||||
* \param open: apertura del file dopo la creazione
|
||||
*
|
||||
* \retval puntatore al fileT, NULL se errore (errno)
|
||||
*/
|
||||
fileT* createFileT(char *f, int O_LOCK, int client, int open);
|
||||
|
||||
/**
|
||||
* Append su un fileT.
|
||||
* \param f: fileT sul quale scrivere
|
||||
* \param data: puntatore al buffer da scrivere
|
||||
* \param size: dimensione in bytes del buffer
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int writeFileT(fileT *f, void *data, size_t size);
|
||||
|
||||
/**
|
||||
* Rimozione di un fileT.
|
||||
* \param f
|
||||
*/
|
||||
void destroyFile(fileT *f);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Alloca ed inizializza una coda di fileT. Deve essere chiamata da un solo
|
||||
* thread.
|
||||
* \param maxLen: lunghezza massima della coda
|
||||
* \param maxSize: dimensione massima della coda in bytes
|
||||
*
|
||||
* \retval puntatore alla coda allocata, NULL se errore
|
||||
*/
|
||||
queueT* createQueue(size_t maxLen, size_t maxSize);
|
||||
|
||||
/**
|
||||
* Inserisce un fileT nella coda.
|
||||
* \param q: puntatore alla coda
|
||||
* \param data: puntatore al fileT da inserire
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int enqueue(queueT *q, fileT* data);
|
||||
|
||||
/**
|
||||
* Estrae un fileT dalla coda.
|
||||
* \param q: puntatore alla coda
|
||||
*
|
||||
* \retval puntatore al file estratto, NULL se errore
|
||||
*/
|
||||
fileT* dequeue(queueT *q);
|
||||
|
||||
/**
|
||||
* Estrae un fileT dalla coda come la dequeue, ma invece di restituire il
|
||||
* file estratto lo distrugge immediatamente, liberandone la memoria.
|
||||
*
|
||||
* \param q: puntatore alla coda
|
||||
*/
|
||||
void voidDequeue(queueT *q);
|
||||
|
||||
/**
|
||||
* Stampa l'intero contenuto della coda.
|
||||
* \param stream: file su cui stampare
|
||||
* \param q: puntatore alla coda da stampare
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int printQueue(FILE *stream, queueT *q);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Cerca di ottenere il lock su un fileT, fallisce se un altro client ha gia'
|
||||
* richiesto la lock
|
||||
* \param q: puntatore alla coda che contiene il fileT
|
||||
* \param filepath: path assoluto (identificatore) del fileT
|
||||
* \param owner: client che ha richiesto l'operazione
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int lockFileInQueue(queueT *q, char *filepath, int owner);
|
||||
|
||||
/**
|
||||
* Rilascia il lock di un file, fallisce se non si e' il possessore del lock
|
||||
* \param q: puntatore alla coda che contiene il fileT
|
||||
* \param filepath -> path assoluto (identificatore) del fileT
|
||||
* \param owner -> client che ha richiesto l'operazione
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int unlockFileInQueue(queueT *q, char *filepath, int owner);
|
||||
|
||||
/**
|
||||
* Apre un fileT contenuto nella coda. Fallisce se il lock appartiene a un
|
||||
* client diverso.
|
||||
* \param q: puntatore alla coda che contiene il fileT da aprire
|
||||
* \param filepath: path assoluto (identificatore) del fileT da aprire
|
||||
* \param O_LOCK: 1 locked, 0 unlocked
|
||||
* \param owner: client che ha richiesto l'apertura
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int openFileInQueue(queueT *q, char *filepath, int O_LOCK, int owner);
|
||||
|
||||
/**
|
||||
* Chiude un file contenuto nella coda. Ha successo se fileT non e' stato aperto.
|
||||
* Fallisce se il file e' stato messo in modalita' locked da un client diverso.
|
||||
* \param q: puntatore alla coda che contiene il fileT da chiudere
|
||||
* \param filepath: path assoluto (identificatore) del fileT da chiudere
|
||||
* \param owner: client che ha richiesto la chiusura
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int closeFileInQueue(queueT *q, char *filepath, int owner);
|
||||
|
||||
/**
|
||||
* Scrive del contenuto su un fileT all'interno della coda. Fallisce se il file
|
||||
* non e' stato aperto o se il lock appartiene a un client diverso.
|
||||
* \param q: puntatore alla coda che contiene il fileT su cui scrivere
|
||||
* \param filepath: path assoluto (identificatore) del fileT
|
||||
* \param data: buffer che contiene i dati
|
||||
* \param size: dimensione in bytes del buffer
|
||||
* \param owner: client che ha richiesto l'operazione di scrittura
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int writeFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner);
|
||||
|
||||
/**
|
||||
* Scrive del contenuto in append su un fileT all'interno della coda. Fallisce
|
||||
* se il file non e' stato aperto o se il lock appartiene a un client diverso.
|
||||
* \param q: puntatore alla coda che contiene il fileT su cui effettuare l'append
|
||||
* \param filepath: path assoluto (identificatore) del fileT
|
||||
* \param data: buffer che contiene i dati
|
||||
* \param size: dimensione in bytes del buffer
|
||||
* \param owner: client che ha richiesto l'operazione di append
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (setta errno)
|
||||
*/
|
||||
int appendFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner);
|
||||
|
||||
/**
|
||||
* Rimuove un fileT dalla coda. Fallisce se non si è in possesso della lock o se
|
||||
* la lock e' posseduta da un client diverso.
|
||||
* \param q: puntatore alla coda che contiene il fileT da rimuovere
|
||||
* \param filepath: path assoluto (identificatore) del fileT da rimuovere
|
||||
* \param owner: client che ha richiesto la rimozione
|
||||
*
|
||||
* \retval 0 se successo, -1 se errore (errno)
|
||||
*/
|
||||
int removeFileFromQueue(queueT *q, char *filepath, int owner);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Cerca un fileT nella coda.
|
||||
* \param q: puntatore alla coda sulla quale cercare il fileT
|
||||
* \param filepath: path assoluto del fileT da cercare
|
||||
*
|
||||
* \retval puntatore a una copia del fileT se trovato, NULL se non trovato o errore (errno)
|
||||
*/
|
||||
fileT* find(queueT *q, char *filepath);
|
||||
|
||||
/**
|
||||
* Numero di elementi presenti nella coda.
|
||||
* \param q: puntatore alla coda
|
||||
*
|
||||
* \retval numero di elementi presenti, -1 se errore (errno)
|
||||
*/
|
||||
size_t getLen(queueT *q);
|
||||
|
||||
/**
|
||||
* Restituisce la dimensione attuale della coda in bytes.
|
||||
* \param q: puntatore alla coda
|
||||
*
|
||||
* \retval dimensione della coda in bytes, -1 se errore (errno)
|
||||
*/
|
||||
size_t getSize(queueT *q);
|
||||
|
||||
/**
|
||||
* Cancella una coda allocata con createQueue e ne libera la memoria.
|
||||
* \param q: puntatore alla coda da distruggere
|
||||
*/
|
||||
void destroyQueue(queueT *q);
|
||||
|
||||
#endif // _FILE_QUEUE
|
||||
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef _SERVER_STATUS
|
||||
#define _SERVER_STATUS
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t *mtx;
|
||||
pthread_cond_t *cond;
|
||||
|
||||
long max_space_occupied;
|
||||
long cur_space_occupied;
|
||||
long max_files;
|
||||
long cur_files;
|
||||
char exiting;
|
||||
} serverStatus;
|
||||
|
||||
#endif /* _SERVER_STATUS */
|
||||
18
lib/utils/serverUtil.h
Normal file
18
lib/utils/serverUtil.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#ifndef _SERVER_UTIL
|
||||
#define _SERVER_UTIL
|
||||
|
||||
#include <ini.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define CONFGETINT(var, config, t, q, p, base) \
|
||||
var = (int) strtol(ini_get(config, t, q), p, base); \
|
||||
if(var<=0) { \
|
||||
fprintf(stderr, "ERROR reading config for variable %c\n", t); \
|
||||
ini_free(config); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
|
||||
#endif /* _SERVER_STATUS */
|
||||
@ -83,25 +83,6 @@ static inline void print_error(const char * str, ...) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Controlla se la stringa passata come primo argomento e' un numero.
|
||||
* \return 0 ok 1 non e' un numbero 2 overflow/underflow
|
||||
*/
|
||||
static inline int isNumber(const char* s, long* n) {
|
||||
if (s==NULL) return 1;
|
||||
if (strlen(s)==0) return 1;
|
||||
char* e = NULL;
|
||||
errno=0;
|
||||
long val = strtol(s, &e, 10);
|
||||
if (errno == ERANGE) return 2; // overflow/underflow
|
||||
if (e != NULL && *e == (char)0) {
|
||||
*n = val;
|
||||
return 0; // successo
|
||||
}
|
||||
return 1; // non e' un numero
|
||||
}
|
||||
|
||||
#define LOCK(l) if (pthread_mutex_lock(l)!=0) { \
|
||||
fprintf(stderr, "ERRORE FATALE lock\n"); \
|
||||
pthread_exit((void*)EXIT_FAILURE); \
|
||||
|
||||
34
src/server.c
34
src/server.c
@ -13,7 +13,8 @@
|
||||
#include <util.h>
|
||||
#include <serverWorker.h>
|
||||
#include <ini.h>
|
||||
#include <serverStatus.h>
|
||||
#include <serverUtil.h>
|
||||
#include <fileQueue.h>
|
||||
|
||||
|
||||
/**
|
||||
@ -80,7 +81,9 @@ int main(int argc, char *argv[]) {
|
||||
// TODO read config file
|
||||
checkargs(argc, argv);
|
||||
ini_t *config = ini_load(argv[1]);
|
||||
int threadsInPool = (int) strtol(ini_get(config, "threadpool", "quantity"), NULL, 10);
|
||||
int threadsInPool; CONFGETINT(threadsInPool, config, "threadpool", "quantity", NULL, 10);
|
||||
int maxFiles; CONFGETINT(maxFiles, config, "files", "MaxFiles", NULL, 10);
|
||||
int maxSize; CONFGETINT(maxSize, config, "files", "MaxSize", NULL, 10);
|
||||
ini_free(config);
|
||||
|
||||
sigset_t mask;
|
||||
@ -90,7 +93,6 @@ int main(int argc, char *argv[]) {
|
||||
sigaddset(&mask, SIGTERM);
|
||||
|
||||
if (pthread_sigmask(SIG_BLOCK, &mask, NULL) != 0) {
|
||||
// TODO logging utility
|
||||
fprintf(stderr, "ERROR setting mask\n");
|
||||
goto _cleanup;
|
||||
}
|
||||
@ -100,55 +102,57 @@ int main(int argc, char *argv[]) {
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.sa_handler = SIG_IGN;
|
||||
if ( (sigaction(SIGPIPE,&s,NULL)) == -1 ) {
|
||||
// TODO logging utility
|
||||
perror("sigaction");
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* La pipe viene utilizzata come canale di comunicazione tra il signal handler thread ed il
|
||||
* thread lisener per notificare la terminazione.
|
||||
* Una alternativa è quella di utilizzare la chiamata di sistema
|
||||
* 'signalfd' ma non e' POSIX.
|
||||
*/
|
||||
printf("File Server ready.");
|
||||
fflush(stdout);
|
||||
|
||||
int signal_pipe[2];
|
||||
if (pipe(signal_pipe) == -1) {
|
||||
// TODO logging utility
|
||||
perror("pipe");
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
// todo logging + statistiche
|
||||
|
||||
|
||||
|
||||
pthread_t sighandler_thread;
|
||||
sigHandler_t handlerArgs = { &mask, signal_pipe[1] };
|
||||
if (pthread_create(&sighandler_thread, NULL, sigHandler, &handlerArgs) != 0) {
|
||||
// TODO logging utility
|
||||
fprintf(stderr, "ERROR creating signal handler thread\n");
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
int listenfd;
|
||||
if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
// TODO logging utility
|
||||
perror("socket");
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
// thread per i segnali
|
||||
struct sockaddr_un serv_addr;
|
||||
memset(&serv_addr, '0', sizeof(serv_addr));
|
||||
serv_addr.sun_family = AF_UNIX;
|
||||
strncpy(serv_addr.sun_path, SOCKNAME, strlen(SOCKNAME)+1);
|
||||
|
||||
if (bind(listenfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) {
|
||||
// TODO logging utility
|
||||
perror("bind");
|
||||
goto _cleanup;
|
||||
}
|
||||
if (listen(listenfd, MAXBACKLOG) == -1) {
|
||||
// TODO logging utility
|
||||
perror("listen");
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
// creo la queue
|
||||
queueT *queue = createQueue(maxFiles, maxSize);
|
||||
|
||||
|
||||
|
||||
|
||||
threadpool_t *pool = NULL;
|
||||
|
||||
pool = createThreadPool(threadsInPool, threadsInPool);
|
||||
|
||||
Reference in New Issue
Block a user