#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/errno.h>
#include <stdlib.h>
#include <fcntl.h>

#define ITS 1000
extern int errno;

int main(int argc, char *argv[]) {
    pid_t pid=0;
    FILE *fd=NULL, *d[2] = {NULL, NULL};
    unsigned int sum=0, i=0, j=0, k[4] = {0,0,0,0}, val=0,
	sums[8] = {0,10,0,0,0,0,0,0};
    int err=0;
    
    d[0] = fopen("/dev/dm14-0", "rb+");
    d[1] = fopen("/dev/dm14-1", "rb+");
    for (i=0;i<2;i++) {
        if (!d[i]) {
    	    perror("D");
    	    return 0;
	}
	if ((val = fcntl(fileno(d[i]), F_SETFL, O_NONBLOCK)) < 0) {
	    perror("F");
	    return 0;
	}
    }

    while(k[0]<ITS || k[1]<ITS || k[2]<ITS || k[3]<ITS) {
	printf("Looping: %u %u %u %u", k[0], k[1], k[2], k[3]);
	
	for(j=0;j<2;j++) {
	    if (k[j+2] < ITS) {
		errno = 0;
		sums[j]++;
	        sums[j+2] += sums[j];
		fwrite(&sums[j], sizeof(int), 1, d[j]);
		err = ferror(d[j]);
		if ((err != 0) && (errno != EWOULDBLOCK) && (errno != 0)) {
		    printf("E: %i %i\n", err, errno);
	    	    perror("w");
		    return 0;
		} else if (errno != EWOULDBLOCK) { // write successful
    		    k[j+2]++;
		} else { // would have blocked, so reset
		    sums[j+2] -= sums[j];
		    sums[j]--;
		}
		printf(" %i %i", err, errno);
	    }

	    if (k[j] < ITS) {
		errno = 0;
		fread(&sums[j+6], sizeof(int), 1, d[j]);
		err = ferror(d[j]);
		if ((err != 0) && (errno != EWOULDBLOCK) && (errno != 0)) {
		    printf("E: %i %i\n", err, errno);
	    	    perror("R");
		    return 0;
		} else if (errno != EWOULDBLOCK) { // success
		    sums[j+4] += sums[j+6];
		    k[j]++;
	        }
		printf(" %i %i", err, errno);
	    }
	}
	printf("\r");
    }
    
    printf("\r\n");
    printf("0: got %u, expected %u\n", sums[5], sums[2]);
    printf("1: got %u, expected %u\n", sums[4], sums[3]);

    pid = fork();

    if (pid == 0) {
        fd = fopen("/dev/dm14-0", "rb+");
	if (!fd) {
	    perror("D0");
	    return 0;
	}

        for (i=0; i<ITS; i++) {
            val++;
            sum += val;
            fwrite(&val, sizeof(int), 1, fd);
	    if (ferror(fd)) {
		perror("W0");
		return 0;
	    }
        }
        printf("0: expected %u\n", sum);

        sum = 0;

        for (i=0; i<ITS; i++) {
            fread(&val, sizeof(int), 1, fd);
	    if (ferror(fd)) {
		perror("R0");
		return 0;
	    }
            sum += val;
        }
        printf("1: got %u\n", sum);
    } else {
        fd = fopen("/dev/dm14-1", "rb+");
	if (!fd) {
	    perror("D1");
	    return 0;
	}

        for (i=0; i<ITS; i++) {
            fread(&val, sizeof(int), 1, fd);
	    if (ferror(fd)) {
		perror("W1");
		return 0;
	    }
            sum += val;
        }
        printf("0: got %u\n", sum);

        sum = 0;

        for (i=0; i<ITS; i++) {
            val++;
            sum += val;
            fwrite(&val, sizeof(int), 1, fd);
	    if (ferror(fd)) {
		perror("R1");
		return 0;
	    }
        }
        printf("1: expected %d\n", sum);
    }
    
    fclose(fd);

    return 0;
}
