需要libaio libaio-devel的包,到http://rpm.pbone.net/index.php3去下
这是模仿libaio-oracle写的,哪位好人去做个测试,把结果发上来,最好能和glibc的在相同环境下对比对比
代码如有不对的地方,请指出
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <libaio.h>
#define IOCB_CMD_READ 0
#define IOCB_CMD_WRITE 1
#define IOCB_CMD_NOP 2
#define IOCB_CMD_CANCEL 3
#define IOCB_CMD_FSYNC 4
#define IOCB_CMD_FDSYNC 5
#define IOCB_CMD_RUNNING 6
#define IOCB_CMD_DONE 7
#define MAX_EVENTS 512
#define MAX_AIO_REAP MAX_EVENTS
#define aio_data data
#define DATA_FROM_REQ(r) ((void *)(r))
#define REQ_FROM_DATA(d) ((AIORequest *)(d))
#define MAX_IO_QUEUE 1024
#define aiocb aiocb64
#define aio_read aio_read64
#define aio_write aio_write64
#define aio_error aio_error64
#define aio_return aio_return64
#define aio_suspend aio_suspend64
struct aiocb64 {
int aio_fildes; /* File desriptor. */
short aio_lio_opcode; /* Operation to be performed. */
short aio_reqprio; /* Request priority offset. */
void *aio_buf; /* Location of buffer. */
size_t aio_nbytes; /* Length of transfer. */
int aio_offset; /* File offset. */
/* these are internal to the kernel/libc. */
long __aio_key; // kernel sets this to -1 if completed
// otherwise >= 0 (the request#)
void * __aio_data; // pointer to be returned in event's data
int __error_code;
};
enum
{
LIO_READ,
#define LIO_READ LIO_READ
LIO_WRITE,
#define LIO_WRITE LIO_WRITE
LIO_NOP,
#define LIO_NOP LIO_NOP
LIO_POLL,
#define LIO_POLL LIO_POLL
};
enum
{
AIO_CANCELED,
#define AIO_CANCELED AIO_CANCELED
AIO_NOTCANCELED,
#define AIO_NOTCANCELED AIO_NOTCANCELED
AIO_ALLDONE
#define AIO_ALLDONE AIO_ALLDONE
};
enum
{
LIO_WAIT,
#define LIO_WAIT LIO_WAIT
LIO_NOWAIT
#define LIO_NOWAIT LIO_NOWAIT
};
typedef struct _AIORequest AIORequest;
enum
{
AIOR_UNUSED = 0, /* Unused control block */
AIOR_IN_PROGRESS = 0xbeef, /* In progress I/O */
AIOR_COMPLETE = 0xdead, /* Completed I/O */
};
struct _AIORequest
{
struct iocb iocb; /* Control block sent to kernel */
struct aiocb64 *aiocb; /* User's control block */
};
static io_context_t AIO_context;
static int _aio_rw(int op, struct aiocb64 * aiocbp);
int aio_init()
{
if (io_queue_init(MAX_IO_QUEUE, &(AIO_context)))
return -1;
return(0);
}
int aio_read64(struct aiocb64 *aiocbp)
{
int rc;
if (aiocbp == NULL)
{
errno = EINVAL;
return(-1);
}
rc = _aio_rw(LIO_READ, aiocbp);
return(rc > -1 ? 0 : -1);
}
int aio_write64(struct aiocb64 *aiocbp)
{
int rc;
struct aiocb64 *aiocbs[] = {NULL};
if (aiocbp == NULL)
{
errno = EINVAL;
return(-1);
}
aiocbs[0] = aiocbp;
rc = _aio_rw(LIO_WRITE, aiocbp);
return(rc > -1 ? 0 : -1);
}
static long aior_get_events(struct timespec *timeout)
{
struct io_event events[MAX_EVENTS];
int i;
long ret;
AIORequest *req;
/* Thanks for no compat defines in libaio.h */
#ifdef OLD_LIBAIO
ret = io_getevents(AIO_context, MAX_EVENTS, events, timeout);
#else
ret = io_getevents(AIO_context, 1, MAX_EVENTS, events, timeout);
#endif /* OLD_LIBAIO */
if (ret < 0)
return(ret);
else if (ret == 0)
return(0);
for (i = 0; i < ret; i++)
{
req = REQ_FROM_DATA(events[i].data);
req->aiocb->__error_code = events[i].res;
if (req->aiocb->__aio_key != AIOR_IN_PROGRESS)
{
//printf("aior_get_events: aiocb at %p has __aio_key %ld!/n",req->aiocb, req->aiocb->__aio_key);
continue;
}
req->aiocb->__aio_key = AIOR_COMPLETE;
//printf("aior_get_events: Collected aiocb at %p/n",req->aiocb);
}
return(ret);
}
int aio_error64(struct aiocb64 *aiocbp)
{
int ret;
struct timespec to = {0, 0};
if (aiocbp == NULL)
{
errno = EINVAL;
return(-1);
}
if (aiocbp->__aio_key == AIOR_COMPLETE)
{
AIORequest *req = REQ_FROM_DATA(aiocbp->__aio_data);
if (NULL != req)
{
aiocbp->__aio_data = NULL;
free(req);
}
if (aiocbp->__error_code < 0)
return(-(aiocbp->__error_code));
else
return(0);
}
/* Do we have an invalid __aio_key? */
if (aiocbp->__aio_key != AIOR_IN_PROGRESS)
{
errno = EINVAL;
return(-1);
}
ret = aior_get_events(&to);
if (ret < 0)
{
errno = -ret;
return(-1);
}
/*
* AIOR_COMPLETE_FREE really shouldn't happen here, but it
* doesn't hurt.
*/
if (aiocbp->__aio_key == AIOR_COMPLETE )
{
//printf("aio_error: aiocb at %p complete/n", aiocbp);
AIORequest *req = REQ_FROM_DATA(aiocbp->__aio_data);
if (NULL != req)
{
aiocbp->__aio_data = NULL;
free(req);
}
if (aiocbp->__error_code < 0)
return(-(aiocbp->__error_code));
else
return(0);
}
return(EINPROGRESS);
}
int aio_return64(struct aiocb64 *aiocbp)
{
return aio_error64(aiocbp);
}
int aio_suspend64(/*const*/ struct aiocb64 * const list[], int nent,
const struct timespec *timeout)
{
struct timespec mod_timeout;
AIORequest * req;
int ret = 0;
int done = 0, i;
/* Get round constness */
if (timeout)
memcpy(&mod_timeout, timeout, sizeof(mod_timeout));
while (done == 0)
{
for (i = 0; i < nent; i++)
{
if ((list[i] != NULL) && ((list[i]->__aio_key == AIOR_COMPLETE) ))
{
ret = 0;
done = 1;
req = REQ_FROM_DATA(list[i]->__aio_data);
if (NULL != req)
{
list[i]->__aio_data = NULL;
free(req);
}
break;
}
}
if (done == 0)
{
/*
* Note that this relative timeout is currently not
* adjusted. This means that each time around the loop
* a full timeout is incurred. Hopefully the kernel will
* soon adjust the timeout when it returns. Otherwise,
* aio_suspend() and aio_reap() will have to do
* gettimeofday() tricks to make it work right.
*/
ret = aior_get_events(timeout ? &mod_timeout : NULL);
if ((ret == -ETIMEDOUT) || (ret == 0))
{
errno = EAGAIN;
ret = -1;
done = 1;
}
}
}
return(ret);
}
static int _aio_rw(int op, struct aiocb64 * paiocb)
{
AIORequest *req;
struct iocb **iocbpp;
int i, ret;
int retrycount = 0;
if (paiocb == NULL)
return -EINVAL;
req = (AIORequest *)malloc(sizeof(AIORequest) + sizeof(struct iocb *));
if (req == NULL)
return -EAGAIN;
else
memset(req, 0, (sizeof(AIORequest) + sizeof(struct iocb *)));
iocbpp = (struct iocb **)(req + 1);
req->aiocb = paiocb;
paiocb->__aio_data = req;
paiocb->__aio_key = AIOR_IN_PROGRESS;
iocbpp[0] = &(req->iocb);
switch (op)
{
case LIO_READ:
io_prep_pread(&(req->iocb), paiocb->aio_fildes, paiocb->aio_buf, paiocb->aio_nbytes, paiocb->aio_offset);
break;
case LIO_WRITE:
io_prep_pwrite(&(req->iocb), paiocb->aio_fildes, paiocb->aio_buf, paiocb->aio_nbytes, paiocb->aio_offset);
break;
default:
return -EINVAL;
}
req->iocb.aio_data = DATA_FROM_REQ(req);
ret = io_submit(AIO_context, 1, iocbpp);
if (-EAGAIN == ret)
{
ret = io_submit(AIO_context, 1, iocbpp);
}
if (ret < 0)
{
errno = -ret;
ret = -1;
}
return ret;
}
const int DATA_LEN = 8192;
const int DATA_SIZE = 50000;
char bufferAO[8192] __attribute__((aligned(4096)));
void testLIBAIO()
{
struct timeval start;
struct timeval end;
int ret;
int i = 0;
int dwFlags = O_RDWR | O_LARGEFILE | O_DIRECT | O_SYNC | O_CREAT | O_EXCL; //| O_NOATIME
dwFlags = O_RDWR | O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL;
int fd = open("libaio_write.dat", dwFlags);
if (fd<0)
{
perror("open error:");
return;
}
if (ftruncate64(fd, DATA_LEN * DATA_SIZE))
{
perror("ftruncate64 error:");
return;
}
aio_init();
gettimeofday(&start, NULL);
for (; i<= DATA_SIZE; i++)
{
struct aiocb stAio;
memset(bufferAO, i%128, DATA_LEN);
memset(&stAio, 0, sizeof(stAio));
stAio.aio_buf = bufferAO;
stAio.aio_nbytes = DATA_LEN;
stAio.aio_offset = i * DATA_LEN;
stAio.aio_fildes = fd;
ret = aio_write(&stAio);
if(ret < 0)
{
perror("libaio_write error:");
return;
}
struct aiocb *cblist[1] = {&stAio};
ret = aio_error(&stAio);
if (ret == 0) {
// already completed
}
else if (ret == EINPROGRESS) {
if (aio_suspend((/*const*/ struct aiocb *const*)cblist, 1, NULL))
{
perror("libaio_suspend error:");
return;
}
}
else {
perror("libaio_error error:");
return;
}
/*
if (aio_return(&stAio) != DATA_LEN)
{
perror("libaio_return error:");
return;
}
*/
}
gettimeofday(&end, NULL);
close(fd);
printf("/nLIBAIO O_DIRECT second : %d microSec : %d/n", end.tv_sec-start.tv_sec, end.tv_usec-start.tv_usec);
}
int main()
{
testLIBAIO();
return 1;
}