/*
 * Test program to test if POSIX aio functions work across processes
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <aio.h>


char *shmem;

void
processA(void)
{
	int fd;
	struct aiocb *aiocbp = (struct aiocb *) shmem;
	char *buf = shmem + sizeof(struct aiocb);

	fd = open("aio-shmem-test-file", O_CREAT | O_WRONLY | O_SYNC, S_IRWXU);
	if (fd == -1)
	{
		fprintf(stderr, "open() failed\n");
		exit(1);
	}
	printf("processA starting AIO\n");

	strcpy(buf, "foobar");

	memset(aiocbp, 0, sizeof(struct aiocb));
	aiocbp->aio_fildes = fd;
	aiocbp->aio_offset = 0;
	aiocbp->aio_buf = buf;
	aiocbp->aio_nbytes = strlen(buf);
	aiocbp->aio_reqprio = 0;
	aiocbp->aio_sigevent.sigev_notify = SIGEV_NONE;

	if (aio_write(aiocbp) != 0)
	{
		fprintf(stderr, "aio_write() failed\n");
		exit(1);
	}
}

void
processB(void)
{
	struct aiocb *aiocbp = (struct aiocb *) shmem;
	const struct aiocb * const pl[1] = { aiocbp };
	int rv;


	printf("waiting for the write to finish in process B\n");

	if (aio_suspend(pl, 1, NULL) != 0)
	{
		fprintf(stderr, "aio_suspend() failed\n");
		exit(1);
	}
	printf("aio_suspend() returned 0\n");

	rv = aio_error(aiocbp);
	if (rv != 0)
	{
		fprintf(stderr, "aio_error returned %d: %s\n", rv, strerror(rv));
		exit(1);
	}
	rv = aio_return(aiocbp);
	printf("aio_return returned %d\n", rv);
}



int main(int argc, char **argv)
{
	int pidB;

	shmem = mmap(NULL, sizeof(struct aiocb) + 1000,
				 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
				 -1, 0);
	if (shmem == MAP_FAILED)
	{
		fprintf(stderr, "mmap() failed\n");
		exit(1);
	}

#ifdef SINGLE_PROCESS
	/* this works */
	processA();
	processB();
#else
	/*
	 * Start the I/O request in parent process, then fork and try to wait
	 * for it to finish from the child process. (doesn't work, it will hang
	 * forever)
	 */
	processA();

	pidB = fork();
	if (pidB == -1)
	{
		fprintf(stderr, "fork() failed\n");
		exit(1);
	}
	if (pidB != 0)
	{
		/* parent */
		wait (pidB);
	}
	else
	{
		/* child */
		processB();
	}
#endif
}
