/* Copyright 2004 Sun Microsystems, Inc. ALL RIGHTS RESERVED Use of this software is authorized pursuant to the terms of the license found at http://developers.sun.com/berkeley_license.html Listing 1. Example of using a port to reap the status of AIO to /tmp/foo Compile with Sun Studio 9: cc -o port_aio -mt -lrt -laio listing1_aio.c Compile with gcc 3.4.1: gcc -o port_aio -lrt -laio listing1_aio.c Usage: ./port_aio Usage example: /usr/sbin/mkfile 10M /tmp/foo; ./port_aio 10 */ #include #include #include #include #include #include #include #include #include #define aio_status(p) p->aio_resultp.aio_errno extern long random(void); const unsigned BUFSIZE = 2048; const unsigned NUM_BUFS = 10000; const unsigned NUM_DISK_PAGES = 40000; char *raw_disk = "/tmp/foo"; char *buf = NULL; int port_aio(int ios){ int fd; aiocb_t *aiocb; port_event_t *portevb; port_event_t *portevp; struct sigevent *sigevp; int port; uint_t nget; int error; port_notify_t portnotify; struct timespec timeout; /* Create a port */ port = port_create(); if(port == -1){ perror("Cannot create port "); return (-1); } /* Open the raw disk */ if((fd = open(raw_disk, O_RDWR)) == -1){ perror("Cannot open raw disk [open(2)] "); return (-1); } aiocb = calloc(ios, sizeof (aiocb_t)); if(aiocb == NULL){ perror("Failed to allocate an aiocb structure [calloc(2)] "); return (-1); } portevb = calloc(ios, sizeof (port_event_t)); if(portevb == NULL){ perror("Failed to allocate a port_event structure [calloc(2)] "); return (-1); } /* Initialize all the aiocbs */ int index; for(index = 0;index < ios; index++){ aiocb[index].aio_reqprio = 0; aiocb[index].aio_lio_opcode = LIO_WRITE; aiocb[index].aio_fildes = fd; aiocb[index].aio_nbytes = BUFSIZE; aiocb[index].aio_buf = buf + (random() % NUM_BUFS) * BUFSIZE; aiocb[index].aio_offset = BUFSIZE + (random() % NUM_DISK_PAGES) * BUFSIZE; portnotify.portnfy_port = port; portnotify.portnfy_user = (void *)aiocb[index].aio_offset; sigevp = &aiocb[index].aio_sigevent; sigevp->sigev_notify = SIGEV_PORT; sigevp->sigev_value.sival_ptr = &portnotify; if(aio_write(&aiocb[index]) == -1){ perror("Failure to write asynchronously [aio_write(3RT)] "); close(port); return (-1); } } timeout.tv_sec = 5; timeout.tv_nsec = 0; nget = ios; /* Now wait for I/O to complete */ error = port_getn(port, portevb, ios, &nget, &timeout); if(error == -1){ perror("Failed to reap aio events [port_getn(3C)] "); return (-1); } printf("port_getn() returned %d I/Os\n", nget); /* Now use aio_error to reap all the status */ for(index = 0;index < nget; index++){ int retval; aiocb_t *aiocbp; portevp = &portevb[index]; aiocbp = (aiocb_t *)portevp->portev_object; if(portevp->portev_user != (void *)aiocbp->aio_offset){ printf("Wrong event index detected !\n"); return (-1); } if(aiocbp == NULL){ printf("Wrong aiocb pointer detected !\n"); return (-1); } if(retval = aio_status(aiocbp)){ perror("aio_error failure "); printf("aio_error returned: %d\n", retval); return (-1); } /* Check return value */ if((retval = aio_return(aiocbp)) != BUFSIZE){ printf("aio_return = %d\n", retval); return (-1); } } close(fd); close(port); return (0); } int main(int argc, char *argv[]){ int retval; int shmid; int ios = 0; if(argv[1] != NULL) ios = atoi(argv[1]); if(argc != 2 || ios < 1){ printf("usage: %s \n", argv[0]); return (-1); } /* Create the buffers */ shmid = shmget(IPC_PRIVATE, BUFSIZE * NUM_BUFS, 00400 | 00200); if(shmid == -1){ perror("Unable to get shared memory [shmget(2)] "); exit(-1); } buf = shmat(shmid, 0, 00400 | 00200 | SHM_SHARE_MMU); if((int)buf == -1){ perror("Unable to attach shared memory [shmat(2)] "); exit(-1); } if(port_aio(ios) == -1){ printf("Failed to complete the asynchronous write without error!\n"); exit (-1); } if(shmdt(buf) < 0){ perror("Unable to detach shared memory [shmdt(2)] "); exit (-1); } if(shmctl(shmid, IPC_RMID, 0) < 0){ perror("Unable to remove shared memory [shmctl(2)] "); exit (-1); } return retval; }