On 05/29/2014 04:12 PM, John Lumby wrote:
Thanks for looking at it!

Date: Thu, 29 May 2014 00:19:33 +0300
From: hlinnakan...@vmware.com
To: johnlu...@hotmail.com; pgsql-hackers@postgresql.org
CC: klaussfre...@gmail.com
Subject: Re: [HACKERS] Extended Prefetching using Asynchronous IO - proposal 
and patch

On 05/28/2014 11:52 PM, John Lumby wrote:


The patch seems to assume that you can put the aiocb struct in shared
memory, initiate an asynchronous I/O request from one process, and wait
for its completion from another process. I'm pretty surprised if that
works on any platform.

It works on linux.    Actually this ability allows the asyncio implementation to
reduce complexity in one respect (yes I know it looks complex enough) :
it makes waiting for completion of an in-progress IO simpler than for
the existing synchronous IO case,.   since librt takes care of the waiting.
specifically,   no need for extra wait-for-io control blocks
such as in bufmgr's  WaitIO()

[checks]. No, it doesn't work. See attached test program.

It kinda seems to work sometimes, because of the way it's implemented in glibc. The aiocb struct has a field for the result value and errno, and when the I/O is finished, the worker thread fills them in. aio_error() and aio_return() just return the values of those fields, so calling aio_error() or aio_return() do in fact happen to work from a different process. aio_suspend(), however, is implemented by sleeping on a process-local mutex, which does not work from a different process.

Even if it worked on Linux today, it would be a bad idea to rely on it from a portability point of view. No, the only sane way to make this work is that the process that initiates an I/O request is responsible for completing it. If another process needs to wait for an async I/O to complete, we must use some other means to do the waiting. Like the io_in_progress_lock that we already have, for the same purpose.

- Heikki

/*
 * 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
}
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to