diff --git a/projet k3/implem.c b/projet k3/implem.c new file mode 100644 index 0000000000000000000000000000000000000000..f95970b9686b4ca978ccb79d4addf8a571f1f361 --- /dev/null +++ b/projet k3/implem.c @@ -0,0 +1,307 @@ +#define NT 4 +#include <math.h> +#include <time.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> +#include <pthread.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <semaphore.h> + +typedef struct{ + int file_descriptor; + pthread_mutex_t mutex; +} threadf_t; + +typedef struct{ + pthread_mutex_t mutex; + sem_t empty, full; + long w, x, y, *z; + threadf_t *out; +} buffer_t; + +typedef struct{ + size_t len; + char *str; +} word_t; + +typedef struct _link{ + void *data; + struct _link *nx; +} link_t; + +threadf_t *threadf_init(const char *fn){ + threadf_t *new = malloc(sizeof(threadf_t)); + if(new == NULL) exit(EXIT_FAILURE); + + new->file_descriptor = open(fn, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); + if(new->file_descriptor == -1) exit(EXIT_FAILURE); + pthread_mutex_init(&new->mutex, NULL); + return new; +} + +void threadf_destroy(threadf_t *threadf){ + pthread_mutex_destroy(&threadf->mutex); + if(close(threadf->file_descriptor) == -1) + strerror(errno); + free(threadf); +} + +buffer_t *buffer_init(const char *fn){ + buffer_t *new = malloc(sizeof(buffer_t)); + if(new == NULL) exit(EXIT_FAILURE); + + new->w = 2 * NT; new->x = 0; new->y = 0; + new->z = malloc(sizeof(long) * new->w); + if(new->z == NULL) exit(EXIT_FAILURE); + new->out = threadf_init(fn); + + pthread_mutex_init(&new->mutex, NULL); + sem_init(&new->empty, 0, new->w); + sem_init(&new->full, 0, 0); + return new; +} + +void buffer_put(buffer_t *bf, long v){ + sem_wait(&bf->empty); // WAITING FOR AT LEAST ONE FREE CASE IN THE BUFFER + pthread_mutex_lock(&bf->mutex); + bf->z[bf->x % bf->w] = v; + bf->x = (bf->x + 1) % bf->w; + pthread_mutex_unlock(&bf->mutex); + sem_post(&bf->full); // SIGNALING THAT THERE'S ONE MORE ELEMENT IN THE BUFFER +} + +long buffer_get(buffer_t *bf){ + long output; + sem_wait(&bf->full); // WAITING FOR AT LEAST ONE ELEMENT IN THE BUFFER TO CONSUME + pthread_mutex_lock(&bf->mutex); + output = bf->z[bf->y % bf->w]; + bf->y = (bf->y + 1) % bf->w; + pthread_mutex_unlock(&bf->mutex); + sem_post(&bf->empty); + return output; +} + +void buffer_destroy(buffer_t *bf){ + free(bf->z); + sem_destroy(&bf->full); + sem_destroy(&bf->empty); + threadf_destroy(bf->out); + pthread_mutex_destroy(&bf->mutex); + free(bf); +} + +word_t *word_init(char *str, size_t len){ + word_t *new = malloc(sizeof(word_t)); + if(new == NULL) exit(EXIT_FAILURE); + new->str = str; new->len = len; + return new; +} + +word_t *long_to_str(long value){ + size_t len = 1; + long tmp = value; + while(tmp /= 10) len++; + int len_copy = len; + char *str = malloc(sizeof(char) * len); + if(str == NULL) exit(EXIT_FAILURE); + while(len_copy--){ str[len_copy] = (char) ((value % 10) + '0'); value /= 10; } + return word_init(str, len); +} + +void *word_destroy(word_t *word){ + free(word->str); + free(word); +} + +link_t *link_init(void *data){ + link_t *new = malloc(sizeof(link_t)); + if(new == NULL) exit(EXIT_FAILURE); + new->data = data; + new->nx = new; + return new; +} + +void link_enqueue(link_t **link, void *data){ + if((*link)->data){ + link_t *new = link_init(data); + new->nx = (*link)->nx; + (*link)->nx = new; + *link = new; + } + else{ + (*link)->data = data; + } +} + +void *link_dequeue(link_t **link){ + void *output; + if(*link == (*link)->nx){ + output = (*link)->data; + (*link)->data = NULL; + } + else{ + link_t *tmp = (*link)->nx; + (*link)->nx = tmp->nx; + output = tmp->data; + free(tmp); + } + return output; +} + +void fermat_slave(link_t **link, long x){ + if(x == 1) return; + + long a = ceil(sqrt(x)); + long sq = a * a; + + if(sq == x){ + fermat_slave(link, a); + } + else{ + long b, c; + do { + b = (a * a) - x; + c = floor(sqrt(b)); + } while ((c * c) != b && ++a); + + if(a - c == 1){ + long *a_plus_c = malloc(sizeof(long)); + if(a_plus_c == NULL) exit(EXIT_FAILURE); + *a_plus_c = a + c; + + int is_in = 0; + if((*link)->data){ + link_t *tmp = (*link); + is_in = (*a_plus_c == *(long *) tmp->data); + tmp = tmp->nx; + while (!is_in && tmp != *link){ + is_in = (*a_plus_c == *(long *) tmp->data); + tmp = tmp->nx; + } + } + + if(!is_in) + link_enqueue(link, a_plus_c); + } + else{ + fermat_slave(link, a - c); + fermat_slave(link, a + c); + } + } +} + +void fermat(link_t **link, long x){ + long tmp = x; + if(x != 2){ + if(x % 2 == 0){ + long *two = malloc(sizeof(long)); + if(two == NULL) exit(EXIT_FAILURE); + *two = 2; link_enqueue(link, two); + x /= 2; + while(x % 2 == 0){ + x /= 2; + } + } + fermat_slave(link, x); + + if(*(long *) (*link)->data == tmp){ + link_dequeue(link); + } + } +} + +void *consumer(void *arg){ + char *space = malloc(sizeof(char)), *new_line = malloc(sizeof(char)); + if(space == NULL) exit(EXIT_FAILURE); if(new_line == NULL) exit(EXIT_FAILURE); + *space = ' '; *new_line = '\n'; + buffer_t *bf = (buffer_t *) arg; + while(1){ + long value = buffer_get(bf); + if(value < 0){ break; } // IF BUFFER SIGNALS END THEN QUIT + + link_t *line = link_init(NULL); + fermat(&line, value); + + // modif here + pthread_mutex_lock(&bf->out->mutex); + word_t *first = long_to_str(value); + write(bf->out->file_descriptor, first->str, first->len); + + while(line->data){ + word_t *out = long_to_str(*(long *) link_dequeue(&line)); + write(bf->out->file_descriptor, space, 1); + write(bf->out->file_descriptor, out->str, out->len); + word_destroy(out); + } + write(bf->out->file_descriptor, new_line, 1); + pthread_mutex_unlock(&bf->out->mutex); + } + free(space); free(new_line); + return NULL; +} + +// gcc implem.c -o files/implem -lpthread -lm +// ./files/implem test_input.txt files/implem.txt +// valgrind --leak-check=yes ./files/implem files/example_input.txt files/ouput.txt + +int main(int argc, char const *argv[]){ + pthread_t threads[NT]; + buffer_t *bf = buffer_init(argv[2]); + + int input_fd = open(argv[1], O_RDONLY); + if(input_fd == -1) strerror(errno); + + struct stat fs; + if(fstat(input_fd, &fs) == -1){ strerror(errno); close(input_fd); } + + char *proj = mmap(NULL, fs.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0); + if(proj == MAP_FAILED){ strerror(errno); close(input_fd); } + + // BOOTING CONSUMERS + for(uint8_t t = 0; t < NT; t++){ + if(pthread_create(&threads[t], NULL, consumer, bf)){ + printf("Error while creating a thread \n"); exit(EXIT_FAILURE); + } + } + + long current = 0; + size_t len = fs.st_size / sizeof(char); + for(size_t i = 0; i < len; i++){ + if(proj[i] != '\r'){ + long tmp = proj[i] - '0'; + if(0 <= tmp && tmp <= 9){ + current = (current * 10) + tmp; + } + else{ + printf("Wrong file format \n"); exit(EXIT_FAILURE); + } + } + else{ + buffer_put(bf, current); + current = 0; + i++; + } + } + + // ENDING CONSUMERS ACTIVITY + for(uint8_t t = 0; t < NT; t++){ buffer_put(bf, -1); } + for(uint8_t t = 0; t < NT; t++){ + if(pthread_join(threads[t], NULL)){ + printf("Error on joining !"); exit(EXIT_FAILURE); + } + } + + // TERMINATE TODO: HANDLE MEMORY PROPERLY + buffer_destroy(bf); + if(munmap(proj, fs.st_size) == -1) + strerror(errno); close(input_fd); + if(close(input_fd) == -1) + strerror(errno); + return 0; +}