you will parallelize the CRC verification of several files, the data paths of
which will be passed as command line arguments. The path to the CRC will be, as in the previous practice,
obtained by appending ”.crc” to the data file path. The code is given almost complete, but it has data races.
You must add the relevant synchronization tools in the fileManager.c and main.c to avoid them.
The parallelization is done using threads, each of them will continuously choose a file from which no
other thread is currently reading, read a 256-byte block of the data file and its CRC, and verify it. In case
there is an inconsistency, the thread should log it in the standard output in the standard - specifying the file
in which the inconsistency was found. Notice that different blocks of the same file can be read by different
threads - but not simultaneously. You’ll need to complete their functions (markFileAsFinished and
getAndReserveFile). Also, the threads will have to exit only when there are no more files to process

main.c:
#include "crc.h"
#include "fileManager.h"
#include "myutils.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for sleep function : waits for seconds

FileManager fm;

void* worker_function(void * arg){
  while (1){
    dataEntry d;
    char * buff[256];
    short int crc;
    int res = getAndReserveFile(&fm, &d); // Reserves a file. The release is missing. Where should you put it?
    read(d.fdcrc, &crc, sizeof(short int));
    int nBytesReadData = read(d.fddata, buff, 256);

    if (crc != crcSlow(buff, nBytesReadData)) {
      printf("CRC error in file %d\n", d.filename);
    }
  }
}

int main(int argc, char ** argv) {
  initialiseFdProvider(&fm, argc, argv);
  pthread_t threadID[N];
  for (int i = 0; i < N; ++i) {
    pthread_t thread;
    pthread_create(&threadID[i], NULL, worker_function, NULL);
  }

  for (int i = 0; i < N; ++i) {
    pthread_join(threadID[i], NULL);
  }
  destroyFdProvider(&fm);
}

fileManager.c:
#include "fileManager.h"

void initialiseFdProvider(FileManager * fm, int argc, char **argv) {
  // Complete the initialisation
  /* Your rest of the initailisation comes here*/
  fm->nFilesTotal = argc -1;
  fm->nFilesRemaining = fm->nFilesTotal;
  // Initialise enough memory to store the arrays
  fm->fdData = malloc(sizeof(int) * fm->nFilesTotal);
  fm->fdCRC= malloc(sizeof(int) * fm->nFilesTotal);
  fm->fileFinished = malloc(sizeof(int) * fm->nFilesTotal);
  fm->fileAvailable = malloc(sizeof(int) * fm->nFilesTotal);

  int i;
  for (i = 1; i < fm->nFilesTotal +1; ++i) {
    char path[100];
    strcpy(path, argv[i]);
    strcat(path, ".crc");
    fm->fdData[i] = open(argv[i], O_RDONLY);
    fm->fdCRC[i] = open(path, O_RDONLY);

    fm->fileFinished[i] = 0;
    fm->fileAvailable[i] = 1;
  }
}
void destroyFdProvider(FileManager * fm) {
  int i;
  for (i = 0; i < fm->nFilesTotal; i++) {
    close(fm->fdData[i]);
    close(fm->fdCRC[i]);
  }
  free(fm->fdData);
  free(fm->fdCRC);
  free(fm->fileFinished);
}
int getAndReserveFile(FileManager *fm, dataEntry * d) {
  // This function needs to be implemented by the students
  int i;
  for (i = 0; i < fm->nFilesTotal; ++i) {
    if (fm->fileAvailable[i] && !fm->fileFinished[i]) {
      d->fdcrc = fm->fdCRC[i];
      d->fddata = fm->fdData[i];
      d->index = i;

      // CODE HERE You should mark that the file is not available 
     
      // END CODE 
      return 0;
    }
  }       
  return 1;
}
void unreserveFile(FileManager *fm,dataEntry * d) {
  fm->fileAvailable[d->index] = 1; 
}

void markFileAsFinished(FileManager * fm, dataEntry * d) {
  fm->fileFinished[d->index] = 1;
  fm->nFilesRemaining--; //mark that a file has finished
  if (fm->nFilesRemaining == 0) {
    printf("All files have been processed\n");
    //TO COMPLETE: unblock all waiting threads, if needed
  }
}

myutils.h:
#ifndef MYUTILS
#define MYUTILS

#include <sys/time.h>
#include <sys/types.h> 
#include <netdb.h> 
#include <unistd.h>   // unix-like system calls read and write
#include <fcntl.h>   // unix-like file handling : open
#include <stdlib.h>   // standard C lib input output basic functions compatible with Windows
#include <stdio.h>   // standard C lib input output basic functions compatible with Windows
#include <stdbool.h>
#include <string.h>   // also from standard C lib : basic string functions like strlen
#include <pthread.h>


void startTimer(int i);  // start timer i
long endTimer(int i);   // returns millis since timer i started

int get_file_size(char* fname);

int read_split( int fin, char* buff, int maxlen, char* ch_end );

// Semaphores implementation Using pthreads monitors
typedef struct semaphore_struct {
	int i;
	pthread_mutex_t lock;
	pthread_cond_t cond;
} my_semaphore;

void my_sem_init(my_semaphore* sem, int i);
void my_sem_wait(my_semaphore* sem);
void my_sem_signal(my_semaphore* sem);
#endif
crc.h:
/**********************************************************************
 *
 * Filename:  crc.h
 * 
 * Description: A header file describing the various CRC standards.
 *
 * Notes:    
 *
 * 
 * Copyright (c) 2000 by Michael Barr. This software is placed into
 * the public domain and may be used for any purpose. However, this
 * notice must not be changed or removed and no warranty is either
 * expressed or implied by its publication or distribution.
 **********************************************************************/

#ifndef _crc_h
#define _crc_h


#define FALSE	0
#define TRUE	!FALSE

/*
 * Select the CRC standard from the list that follows.
 */
#define CRC_CCITT


#if defined(CRC_CCITT)

typedef unsigned short crc;

#define CRC_NAME			"CRC-CCITT"
#define POLYNOMIAL			0x1021
#define INITIAL_REMAINDER	0xFFFF
#define FINAL_XOR_VALUE		0x0000
#define REFLECT_DATA		FALSE
#define REFLECT_REMAINDER	FALSE
#define CHECK_VALUE			0x29B1

#elif defined(CRC16)

typedef unsigned short crc;

#define CRC_NAME			"CRC-16"
#define POLYNOMIAL			0x8005
#define INITIAL_REMAINDER	0x0000
#define FINAL_XOR_VALUE		0x0000
#define REFLECT_DATA		TRUE
#define REFLECT_REMAINDER	TRUE
#define CHECK_VALUE			0xBB3D

#elif defined(CRC32)

typedef unsigned long crc;

#define CRC_NAME			"CRC-32"
#define POLYNOMIAL			0x04C11DB7
#define INITIAL_REMAINDER	0xFFFFFFFF
#define FINAL_XOR_VALUE		0xFFFFFFFF
#define REFLECT_DATA		TRUE
#define REFLECT_REMAINDER	TRUE
#define CHECK_VALUE			0xCBF43926

#else

#error "One of CRC_CCITT, CRC16, or CRC32 must be #define'd."

#endif


void crcInit(void);
crc  crcSlow(unsigned char const message[], int nBytes);
crc  crcFast(unsigned char const message[], int nBytes);


#endif /* _crc_h */