/* cpfile.c -- Copy a file overlapping read and write */ #include #include #include #include #include #include #include #include #define BUFFERSIZE 8192 typedef struct bufferstruct { char b[BUFFERSIZE]; int count; /* Number of characters in b */ int last; /* !=0 iff it is last data buffer */ pthread_mutex_t mutex; pthread_cond_t condition; } buffer; /* Operations on buffer */ void initbuffer (buffer * p); int fillbuffer (buffer * p); /* Returns 0 iff no more data */ int unfillbuffer (buffer * p); /* Returns 0 iff last data */ void filler(void); /* The procedure executed by the reading thread*/ buffer buf[2]; /* The two buffers used for concurrent reading, writing*/ int infile, outfile; /* File descriptors for input and output files */ int main (int argc, char *argv[]){ pthread_t t; int ubuffer; /* It is 0 or 1, indicating buffer to be emptied*/ int rc; /* Return Code */ if (argc < 3) { printf("Usage: cpfile fromfile tofile\n"); exit(0);} if ((infile = open(argv[1], O_RDONLY)) < 0) { printf("Cannot open %s\n", argv[1]); exit(0);} if ((outfile = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IRGRP|S_IROTH)) < 0) { printf("Cannot open %s\n", argv[2]); exit(0);} initbuffer(&buf[0]); initbuffer(&buf[1]); if ((rc = pthread_create(&t, NULL, (void *)filler, NULL))!= 0) { fprintf(stderr, "Cannot create thread %s\n", strerror(rc)); exit(1);} ubuffer = 0; while (unfillbuffer(&(buf[ubuffer]))) ubuffer = 1-ubuffer; close(outfile); pthread_exit(0); return 0; /*Not executed - just to shut up a compiler warning */ } /* The thread that reads from source file */ void filler(void){ int fbuffer = 0; /* It is 0 or 1, undicating buffer to be filled*/ while (fillbuffer(&(buf[fbuffer]))) fbuffer = 1-fbuffer; close(infile); pthread_exit (0); } void initbuffer (buffer * p) { int rc; if((rc = pthread_mutex_init(&(p->mutex), NULL)) != 0) { fprintf(stderr, "pthread_mutex_init %s\n", strerror(rc)); exit(0);} if((rc = pthread_cond_init(&((p->condition)), NULL)) != 0) { fprintf(stderr, "Cannot create thread %s\n", strerror(rc)); exit(0);} p->count = 0; p->last = 0; } /* It reads from the infile into buffer. Returns 0 when no more data */ int fillbuffer (buffer * p) { int temp; pthread_mutex_lock(&(p->mutex)); while ((p->count) > 0) pthread_cond_wait(&((p->condition)), &(p->mutex)); (p->count) = read(infile, p->b, BUFFERSIZE); if (p->count < 0) { fprintf(stderr, "%s\n", strerror(p->count)); exit(0); } p->last = (p->count == 0); temp = p->count; pthread_cond_signal(&((p->condition))); pthread_mutex_unlock(&(p->mutex)); return temp; } /* It writes into the outfile from buffer. Returns 0 iff last data */ int unfillbuffer (buffer * p) { int nn = 0; char *q; pthread_mutex_lock(&(p->mutex)); while ((p->count) == 0) { pthread_cond_wait(&((p->condition)), &(p->mutex));} q = p->b; while (p->count > 0) { nn = write(outfile, q, p->count); if (nn < 0) { fprintf(stderr, "%s\n", strerror(nn)); exit(0); } p->count -= nn; q += nn; } nn = p->last; pthread_cond_signal(&((p->condition))); pthread_mutex_unlock(&(p->mutex)); return nn; }