{
    "content": [
        {
            "type": "text",
            "text": "# aio(7) (man)\n\n**Summary:** aio - POSIX asynchronous I/O overview\n\n## Examples\n\n- `The program below opens each of the files named in its command-line arguments  and  queues  a`\n- `request on the resulting file descriptor using aioread(3).  The program then loops, periodi‐`\n- `cally monitoring each of the I/O operations that is still  in  progress  using  aioerror(3).`\n- `Each  of  the  I/O requests is set up to provide notification by delivery of a signal.  After`\n- `all I/O requests have completed, the program retrieves their status using aioreturn(3).`\n- `The SIGQUIT signal (generated by typing control-\\) causes the program to request cancellation`\n- `of each of the outstanding requests using aiocancel(3).`\n- `Here is an example of what we might see when running this program.  In this example, the pro‐`\n- `gram queues two requests to standard input, and these are satisfied by  two  lines  of  input`\n- `containing \"abc\" and \"x\".`\n- `$ ./a.out /dev/stdin /dev/stdin`\n- `opened /dev/stdin on descriptor 3`\n- `opened /dev/stdin on descriptor 4`\n- `aioerror():`\n- `for request 0 (descriptor 3): In progress`\n- `for request 1 (descriptor 4): In progress`\n- `abc`\n- `I/O completion signal received`\n- `aioerror():`\n- `for request 0 (descriptor 3): I/O succeeded`\n- `for request 1 (descriptor 4): In progress`\n- `aioerror():`\n- `for request 1 (descriptor 4): In progress`\n- `I/O completion signal received`\n- `aioerror():`\n- `for request 1 (descriptor 4): I/O succeeded`\n- `All I/O requests completed`\n- `aioreturn():`\n- `for request 0 (descriptor 3): 4`\n- `for request 1 (descriptor 4): 2`\n- `#include <fcntl.h>`\n- `#include <stdlib.h>`\n- `#include <unistd.h>`\n- `#include <stdio.h>`\n- `#include <errno.h>`\n- `#include <aio.h>`\n- `#include <signal.h>`\n- `#define BUFSIZE 20     /* Size of buffers for read operations */`\n- `#define errExit(msg) do { perror(msg); exit(EXITFAILURE); } while (0)`\n- `struct ioRequest {      /* Application-defined structure for tracking`\n- `I/O requests */`\n- `int           reqNum;`\n- `int           status;`\n- `struct aiocb *aiocbp;`\n- `};`\n- `static volatile sigatomict gotSIGQUIT = 0;`\n- `/* On delivery of SIGQUIT, we attempt to`\n- `cancel all outstanding I/O requests */`\n- `static void             /* Handler for SIGQUIT */`\n- `quitHandler(int sig)`\n- `gotSIGQUIT = 1;`\n- `#define IOSIGNAL SIGUSR1   /* Signal used to notify I/O completion */`\n- `static void                 /* Handler for I/O completion signal */`\n- `aioSigHandler(int sig, siginfot *si, void *ucontext)`\n- `if (si->sicode == SIASYNCIO) {`\n- `write(STDOUTFILENO, \"I/O completion signal received\\n\", 31);`\n- `/* The corresponding ioRequest structure would be available as`\n- `struct ioRequest *ioReq = si->sivalue.sivalptr;`\n- `and the file descriptor would then be available via`\n- `ioReq->aiocbp->aiofildes */`\n- `int`\n- `main(int argc, char *argv[])`\n- `struct sigaction sa;`\n- `int s;`\n- `int numReqs;        /* Total number of queued I/O requests */`\n- `int openReqs;       /* Number of I/O requests still in progress */`\n- `if (argc < 2) {`\n- `fprintf(stderr, \"Usage: %s <pathname> <pathname>...\\n\",`\n- `argv[0]);`\n- `exit(EXITFAILURE);`\n- `numReqs = argc - 1;`\n- `/* Allocate our arrays */`\n- `struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList));`\n- `if (ioList == NULL)`\n- `errExit(\"calloc\");`\n- `struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList));`\n- `if (aiocbList == NULL)`\n- `errExit(\"calloc\");`\n- `/* Establish handlers for SIGQUIT and the I/O completion signal */`\n- `sa.saflags = SARESTART;`\n- `sigemptyset(&sa.samask);`\n- `sa.sahandler = quitHandler;`\n- `if (sigaction(SIGQUIT, &sa, NULL) == -1)`\n- `errExit(\"sigaction\");`\n- `sa.saflags = SARESTART | SASIGINFO;`\n- `sa.sasigaction = aioSigHandler;`\n- `if (sigaction(IOSIGNAL, &sa, NULL) == -1)`\n- `errExit(\"sigaction\");`\n- `/* Open each file specified on the command line, and queue`\n- `a read request on the resulting file descriptor */`\n- `for (int j = 0; j < numReqs; j++) {`\n- `ioList[j].reqNum = j;`\n- `ioList[j].status = EINPROGRESS;`\n- `ioList[j].aiocbp = &aiocbList[j];`\n- `ioList[j].aiocbp->aiofildes = open(argv[j + 1], ORDONLY);`\n- `if (ioList[j].aiocbp->aiofildes == -1)`\n- `errExit(\"open\");`\n- `printf(\"opened %s on descriptor %d\\n\", argv[j + 1],`\n- `ioList[j].aiocbp->aiofildes);`\n- `ioList[j].aiocbp->aiobuf = malloc(BUFSIZE);`\n- `if (ioList[j].aiocbp->aiobuf == NULL)`\n- `errExit(\"malloc\");`\n- `ioList[j].aiocbp->aionbytes = BUFSIZE;`\n- `ioList[j].aiocbp->aioreqprio = 0;`\n- `ioList[j].aiocbp->aiooffset = 0;`\n- `ioList[j].aiocbp->aiosigevent.sigevnotify = SIGEVSIGNAL;`\n- `ioList[j].aiocbp->aiosigevent.sigevsigno = IOSIGNAL;`\n- `ioList[j].aiocbp->aiosigevent.sigevvalue.sivalptr =`\n- `&ioList[j];`\n- `s = aioread(ioList[j].aiocbp);`\n- `if (s == -1)`\n- `errExit(\"aioread\");`\n- `openReqs = numReqs;`\n- `/* Loop, monitoring status of I/O requests */`\n- `while (openReqs > 0) {`\n- `sleep(3);       /* Delay between each monitoring step */`\n- `if (gotSIGQUIT) {`\n- `/* On receipt of SIGQUIT, attempt to cancel each of the`\n- `outstanding I/O requests, and display status returned`\n- `from the cancellation requests */`\n- `printf(\"got SIGQUIT; canceling I/O requests: \\n\");`\n- `for (int j = 0; j < numReqs; j++) {`\n- `if (ioList[j].status == EINPROGRESS) {`\n- `printf(\"    Request %d on descriptor %d:\", j,`\n- `ioList[j].aiocbp->aiofildes);`\n- `s = aiocancel(ioList[j].aiocbp->aiofildes,`\n- `ioList[j].aiocbp);`\n- `if (s == AIOCANCELED)`\n- `printf(\"I/O canceled\\n\");`\n- `else if (s == AIONOTCANCELED)`\n- `printf(\"I/O not canceled\\n\");`\n- `else if (s == AIOALLDONE)`\n- `printf(\"I/O all done\\n\");`\n- `else`\n- `perror(\"aiocancel\");`\n- `gotSIGQUIT = 0;`\n- `/* Check the status of each I/O request that is still`\n- `in progress */`\n- `printf(\"aioerror():\\n\");`\n- `for (int j = 0; j < numReqs; j++) {`\n- `if (ioList[j].status == EINPROGRESS) {`\n- `printf(\"    for request %d (descriptor %d): \",`\n- `j, ioList[j].aiocbp->aiofildes);`\n- `ioList[j].status = aioerror(ioList[j].aiocbp);`\n- `switch (ioList[j].status) {`\n- `case 0:`\n- `printf(\"I/O succeeded\\n\");`\n- `break;`\n- `case EINPROGRESS:`\n- `printf(\"In progress\\n\");`\n- `break;`\n- `case ECANCELED:`\n- `printf(\"Canceled\\n\");`\n- `break;`\n- `default:`\n- `perror(\"aioerror\");`\n- `break;`\n- `if (ioList[j].status != EINPROGRESS)`\n- `openReqs--;`\n- `printf(\"All I/O requests completed\\n\");`\n- `/* Check status return of all I/O requests */`\n- `printf(\"aioreturn():\\n\");`\n- `for (int j = 0; j < numReqs; j++) {`\n- `ssizet s;`\n- `s = aioreturn(ioList[j].aiocbp);`\n- `printf(\"    for request %d (descriptor %d): %zd\\n\",`\n- `j, ioList[j].aiocbp->aiofildes, s);`\n- `exit(EXITSUCCESS);`\n\n## See Also\n\n- iocancel(2)\n- iodestroy(2)\n- iogetevents(2)\n- iosetup(2)\n- iosubmit(2)\n- aiocancel(3)\n- aioerror(3)\n- aioinit(3)\n- aioread(3)\n- aioreturn(3)\n- aiowrite(3)\n- liolistio(3)\n\n## Section Outline\n\n- **NAME** (2 lines)\n- **DESCRIPTION** (92 lines)\n- **ERRORS** (3 lines)\n- **VERSIONS** (2 lines)\n- **CONFORMING TO** (2 lines)\n- **NOTES** (15 lines)\n- **EXAMPLES** (35 lines) — 1 subsections\n  - Program source (197 lines)\n- **SEE ALSO** (7 lines)\n- **COLOPHON** (7 lines)\n\n## Full Content\n\n### NAME\n\naio - POSIX asynchronous I/O overview\n\n### DESCRIPTION\n\nThe  POSIX  asynchronous  I/O (AIO) interface allows applications to initiate one or more I/O\noperations that are performed asynchronously (i.e., in the background).  The application  can\nelect  to be notified of completion of the I/O operation in a variety of ways: by delivery of\na signal, by instantiation of a thread, or no notification at all.\n\nThe POSIX AIO interface consists of the following functions:\n\naioread(3)\nEnqueue a read request.  This is the asynchronous analog of read(2).\n\naiowrite(3)\nEnqueue a write request.  This is the asynchronous analog of write(2).\n\naiofsync(3)\nEnqueue a sync request for the I/O operations on a file descriptor.  This is the asyn‐\nchronous analog of fsync(2) and fdatasync(2).\n\naioerror(3)\nObtain the error status of an enqueued I/O request.\n\naioreturn(3)\nObtain the return status of a completed I/O request.\n\naiosuspend(3)\nSuspend the caller until one or more of a specified set of I/O requests completes.\n\naiocancel(3)\nAttempt to cancel outstanding I/O requests on a specified file descriptor.\n\nliolistio(3)\nEnqueue multiple I/O requests using a single function call.\n\nThe aiocb (\"asynchronous I/O control block\") structure defines parameters that control an I/O\noperation.  An argument of this type is employed with all  of  the  functions  listed  above.\nThis structure has the following form:\n\n#include <aiocb.h>\n\nstruct aiocb {\n/* The order of these fields is implementation-dependent */\n\nint             aiofildes;     /* File descriptor */\nofft           aiooffset;     /* File offset */\nvolatile void  *aiobuf;        /* Location of buffer */\nsizet          aionbytes;     /* Length of transfer */\nint             aioreqprio;    /* Request priority */\nstruct sigevent aiosigevent;   /* Notification method */\nint             aiolioopcode; /* Operation to be performed;\nliolistio() only */\n\n/* Various implementation-internal fields not shown */\n};\n\n/* Operation codes for 'aiolioopcode': */\n\nenum { LIOREAD, LIOWRITE, LIONOP };\n\nThe fields of this structure are as follows:\n\naiofildes\nThe file descriptor on which the I/O operation is to be performed.\n\naiooffset\nThis is the file offset at which the I/O operation is to be performed.\n\naiobuf\nThis is the buffer used to transfer data for a read or write operation.\n\naionbytes\nThis is the size of the buffer pointed to by aiobuf.\n\naioreqprio\nThis  field  specifies  a value that is subtracted from the calling thread's real-time\npriority in order to determine the priority for execution of  this  I/O  request  (see\npthreadsetschedparam(3)).   The  specified  value must be between 0 and the value re‐\nturned by sysconf(SCAIOPRIODELTAMAX).  This field is ignored  for  file  synchro‐\nnization operations.\n\naiosigevent\nThis  field  is  a  structure that specifies how the caller is to be notified when the\nasynchronous I/O operation completes.  Possible values  for  aiosigevent.sigevnotify\nare SIGEVNONE, SIGEVSIGNAL, and SIGEVTHREAD.  See sigevent(7) for further details.\n\naiolioopcode\nThe type of operation to be performed; used only for liolistio(3).\n\nIn  addition to the standard functions listed above, the GNU C library provides the following\nextension to the POSIX AIO API:\n\naioinit(3)\nSet parameters for tuning the behavior of the glibc POSIX AIO implementation.\n\n### ERRORS\n\nEINVAL The aioreqprio field of the aiocb structure was less than 0, or was greater than  the\nlimit returned by the call sysconf(SCAIOPRIODELTAMAX).\n\n### VERSIONS\n\nThe POSIX AIO interfaces are provided by glibc since version 2.1.\n\n### CONFORMING TO\n\nPOSIX.1-2001, POSIX.1-2008.\n\n### NOTES\n\nIt  is a good idea to zero out the control block buffer before use (see memset(3)).  The con‐\ntrol block buffer and the buffer pointed to by aiobuf must not be changed while the I/O  op‐\neration is in progress.  These buffers must remain valid until the I/O operation completes.\n\nSimultaneous asynchronous read or write operations using the same aiocb structure yield unde‐\nfined results.\n\nThe current Linux POSIX AIO implementation is provided in user space by glibc.   This  has  a\nnumber  of  limitations, most notably that maintaining multiple threads to perform I/O opera‐\ntions is expensive and scales poorly.  Work has been in progress for some time  on  a  kernel\nstate-machine-based  implementation  of  asynchronous  I/O  (see  iosubmit(2),  iosetup(2),\niocancel(2), iodestroy(2), iogetevents(2)), but this implementation hasn't yet matured  to\nthe point where the POSIX AIO implementation can be completely reimplemented using the kernel\nsystem calls.\n\n### EXAMPLES\n\nThe program below opens each of the files named in its command-line arguments  and  queues  a\nrequest on the resulting file descriptor using aioread(3).  The program then loops, periodi‐\ncally monitoring each of the I/O operations that is still  in  progress  using  aioerror(3).\nEach  of  the  I/O requests is set up to provide notification by delivery of a signal.  After\nall I/O requests have completed, the program retrieves their status using aioreturn(3).\n\nThe SIGQUIT signal (generated by typing control-\\) causes the program to request cancellation\nof each of the outstanding requests using aiocancel(3).\n\nHere is an example of what we might see when running this program.  In this example, the pro‐\ngram queues two requests to standard input, and these are satisfied by  two  lines  of  input\ncontaining \"abc\" and \"x\".\n\n$ ./a.out /dev/stdin /dev/stdin\nopened /dev/stdin on descriptor 3\nopened /dev/stdin on descriptor 4\naioerror():\nfor request 0 (descriptor 3): In progress\nfor request 1 (descriptor 4): In progress\nabc\nI/O completion signal received\naioerror():\nfor request 0 (descriptor 3): I/O succeeded\nfor request 1 (descriptor 4): In progress\naioerror():\nfor request 1 (descriptor 4): In progress\nx\nI/O completion signal received\naioerror():\nfor request 1 (descriptor 4): I/O succeeded\nAll I/O requests completed\naioreturn():\nfor request 0 (descriptor 3): 4\nfor request 1 (descriptor 4): 2\n\n#### Program source\n\n#include <fcntl.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <stdio.h>\n#include <errno.h>\n#include <aio.h>\n#include <signal.h>\n\n#define BUFSIZE 20     /* Size of buffers for read operations */\n\n#define errExit(msg) do { perror(msg); exit(EXITFAILURE); } while (0)\n\nstruct ioRequest {      /* Application-defined structure for tracking\nI/O requests */\nint           reqNum;\nint           status;\nstruct aiocb *aiocbp;\n};\n\nstatic volatile sigatomict gotSIGQUIT = 0;\n/* On delivery of SIGQUIT, we attempt to\ncancel all outstanding I/O requests */\n\nstatic void             /* Handler for SIGQUIT */\nquitHandler(int sig)\n{\ngotSIGQUIT = 1;\n}\n\n#define IOSIGNAL SIGUSR1   /* Signal used to notify I/O completion */\n\nstatic void                 /* Handler for I/O completion signal */\naioSigHandler(int sig, siginfot *si, void *ucontext)\n{\nif (si->sicode == SIASYNCIO) {\nwrite(STDOUTFILENO, \"I/O completion signal received\\n\", 31);\n\n/* The corresponding ioRequest structure would be available as\nstruct ioRequest *ioReq = si->sivalue.sivalptr;\nand the file descriptor would then be available via\nioReq->aiocbp->aiofildes */\n}\n}\n\nint\nmain(int argc, char *argv[])\n{\nstruct sigaction sa;\nint s;\nint numReqs;        /* Total number of queued I/O requests */\nint openReqs;       /* Number of I/O requests still in progress */\n\nif (argc < 2) {\nfprintf(stderr, \"Usage: %s <pathname> <pathname>...\\n\",\nargv[0]);\nexit(EXITFAILURE);\n}\n\nnumReqs = argc - 1;\n\n/* Allocate our arrays */\n\nstruct ioRequest *ioList = calloc(numReqs, sizeof(*ioList));\nif (ioList == NULL)\nerrExit(\"calloc\");\n\nstruct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList));\nif (aiocbList == NULL)\nerrExit(\"calloc\");\n\n/* Establish handlers for SIGQUIT and the I/O completion signal */\n\nsa.saflags = SARESTART;\nsigemptyset(&sa.samask);\n\nsa.sahandler = quitHandler;\nif (sigaction(SIGQUIT, &sa, NULL) == -1)\nerrExit(\"sigaction\");\n\nsa.saflags = SARESTART | SASIGINFO;\nsa.sasigaction = aioSigHandler;\nif (sigaction(IOSIGNAL, &sa, NULL) == -1)\nerrExit(\"sigaction\");\n\n/* Open each file specified on the command line, and queue\na read request on the resulting file descriptor */\n\nfor (int j = 0; j < numReqs; j++) {\nioList[j].reqNum = j;\nioList[j].status = EINPROGRESS;\nioList[j].aiocbp = &aiocbList[j];\n\nioList[j].aiocbp->aiofildes = open(argv[j + 1], ORDONLY);\nif (ioList[j].aiocbp->aiofildes == -1)\nerrExit(\"open\");\nprintf(\"opened %s on descriptor %d\\n\", argv[j + 1],\nioList[j].aiocbp->aiofildes);\n\nioList[j].aiocbp->aiobuf = malloc(BUFSIZE);\nif (ioList[j].aiocbp->aiobuf == NULL)\nerrExit(\"malloc\");\n\nioList[j].aiocbp->aionbytes = BUFSIZE;\nioList[j].aiocbp->aioreqprio = 0;\nioList[j].aiocbp->aiooffset = 0;\nioList[j].aiocbp->aiosigevent.sigevnotify = SIGEVSIGNAL;\nioList[j].aiocbp->aiosigevent.sigevsigno = IOSIGNAL;\nioList[j].aiocbp->aiosigevent.sigevvalue.sivalptr =\n&ioList[j];\n\ns = aioread(ioList[j].aiocbp);\nif (s == -1)\nerrExit(\"aioread\");\n}\n\nopenReqs = numReqs;\n\n/* Loop, monitoring status of I/O requests */\n\nwhile (openReqs > 0) {\nsleep(3);       /* Delay between each monitoring step */\n\nif (gotSIGQUIT) {\n\n/* On receipt of SIGQUIT, attempt to cancel each of the\noutstanding I/O requests, and display status returned\nfrom the cancellation requests */\n\nprintf(\"got SIGQUIT; canceling I/O requests: \\n\");\n\nfor (int j = 0; j < numReqs; j++) {\nif (ioList[j].status == EINPROGRESS) {\nprintf(\"    Request %d on descriptor %d:\", j,\nioList[j].aiocbp->aiofildes);\ns = aiocancel(ioList[j].aiocbp->aiofildes,\nioList[j].aiocbp);\nif (s == AIOCANCELED)\nprintf(\"I/O canceled\\n\");\nelse if (s == AIONOTCANCELED)\nprintf(\"I/O not canceled\\n\");\nelse if (s == AIOALLDONE)\nprintf(\"I/O all done\\n\");\nelse\nperror(\"aiocancel\");\n}\n}\n\ngotSIGQUIT = 0;\n}\n\n/* Check the status of each I/O request that is still\nin progress */\n\nprintf(\"aioerror():\\n\");\nfor (int j = 0; j < numReqs; j++) {\nif (ioList[j].status == EINPROGRESS) {\nprintf(\"    for request %d (descriptor %d): \",\nj, ioList[j].aiocbp->aiofildes);\nioList[j].status = aioerror(ioList[j].aiocbp);\n\nswitch (ioList[j].status) {\ncase 0:\nprintf(\"I/O succeeded\\n\");\nbreak;\ncase EINPROGRESS:\nprintf(\"In progress\\n\");\nbreak;\ncase ECANCELED:\nprintf(\"Canceled\\n\");\nbreak;\ndefault:\nperror(\"aioerror\");\nbreak;\n}\n\nif (ioList[j].status != EINPROGRESS)\nopenReqs--;\n}\n}\n}\n\nprintf(\"All I/O requests completed\\n\");\n\n/* Check status return of all I/O requests */\n\nprintf(\"aioreturn():\\n\");\nfor (int j = 0; j < numReqs; j++) {\nssizet s;\n\ns = aioreturn(ioList[j].aiocbp);\nprintf(\"    for request %d (descriptor %d): %zd\\n\",\nj, ioList[j].aiocbp->aiofildes, s);\n}\n\nexit(EXITSUCCESS);\n}\n\n### SEE ALSO\n\niocancel(2), iodestroy(2), iogetevents(2), iosetup(2), iosubmit(2), aiocancel(3),\naioerror(3), aioinit(3), aioread(3), aioreturn(3), aiowrite(3), liolistio(3)\n\n\"Asynchronous I/O Support in Linux 2.5\", Bhattacharya, Pratt, Pulavarty, and Morgan,\nProceedings of the Linux Symposium, 2003,\n⟨https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf⟩\n\n### COLOPHON\n\nThis page is part of release 5.10 of the Linux man-pages project.  A description of the\nproject, information about reporting bugs, and the latest version of this page, can be found\nat https://www.kernel.org/doc/man-pages/.\n\n\n\nLinux                                        2020-08-13                                       AIO(7)\n\n"
        }
    ],
    "structuredContent": {
        "command": "aio",
        "section": "7",
        "mode": "man",
        "summary": "aio - POSIX asynchronous I/O overview",
        "synopsis": null,
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [
            "The program below opens each of the files named in its command-line arguments  and  queues  a",
            "request on the resulting file descriptor using aioread(3).  The program then loops, periodi‐",
            "cally monitoring each of the I/O operations that is still  in  progress  using  aioerror(3).",
            "Each  of  the  I/O requests is set up to provide notification by delivery of a signal.  After",
            "all I/O requests have completed, the program retrieves their status using aioreturn(3).",
            "The SIGQUIT signal (generated by typing control-\\) causes the program to request cancellation",
            "of each of the outstanding requests using aiocancel(3).",
            "Here is an example of what we might see when running this program.  In this example, the pro‐",
            "gram queues two requests to standard input, and these are satisfied by  two  lines  of  input",
            "containing \"abc\" and \"x\".",
            "$ ./a.out /dev/stdin /dev/stdin",
            "opened /dev/stdin on descriptor 3",
            "opened /dev/stdin on descriptor 4",
            "aioerror():",
            "for request 0 (descriptor 3): In progress",
            "for request 1 (descriptor 4): In progress",
            "abc",
            "I/O completion signal received",
            "aioerror():",
            "for request 0 (descriptor 3): I/O succeeded",
            "for request 1 (descriptor 4): In progress",
            "aioerror():",
            "for request 1 (descriptor 4): In progress",
            "I/O completion signal received",
            "aioerror():",
            "for request 1 (descriptor 4): I/O succeeded",
            "All I/O requests completed",
            "aioreturn():",
            "for request 0 (descriptor 3): 4",
            "for request 1 (descriptor 4): 2",
            "#include <fcntl.h>",
            "#include <stdlib.h>",
            "#include <unistd.h>",
            "#include <stdio.h>",
            "#include <errno.h>",
            "#include <aio.h>",
            "#include <signal.h>",
            "#define BUFSIZE 20     /* Size of buffers for read operations */",
            "#define errExit(msg) do { perror(msg); exit(EXITFAILURE); } while (0)",
            "struct ioRequest {      /* Application-defined structure for tracking",
            "I/O requests */",
            "int           reqNum;",
            "int           status;",
            "struct aiocb *aiocbp;",
            "};",
            "static volatile sigatomict gotSIGQUIT = 0;",
            "/* On delivery of SIGQUIT, we attempt to",
            "cancel all outstanding I/O requests */",
            "static void             /* Handler for SIGQUIT */",
            "quitHandler(int sig)",
            "gotSIGQUIT = 1;",
            "#define IOSIGNAL SIGUSR1   /* Signal used to notify I/O completion */",
            "static void                 /* Handler for I/O completion signal */",
            "aioSigHandler(int sig, siginfot *si, void *ucontext)",
            "if (si->sicode == SIASYNCIO) {",
            "write(STDOUTFILENO, \"I/O completion signal received\\n\", 31);",
            "/* The corresponding ioRequest structure would be available as",
            "struct ioRequest *ioReq = si->sivalue.sivalptr;",
            "and the file descriptor would then be available via",
            "ioReq->aiocbp->aiofildes */",
            "int",
            "main(int argc, char *argv[])",
            "struct sigaction sa;",
            "int s;",
            "int numReqs;        /* Total number of queued I/O requests */",
            "int openReqs;       /* Number of I/O requests still in progress */",
            "if (argc < 2) {",
            "fprintf(stderr, \"Usage: %s <pathname> <pathname>...\\n\",",
            "argv[0]);",
            "exit(EXITFAILURE);",
            "numReqs = argc - 1;",
            "/* Allocate our arrays */",
            "struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList));",
            "if (ioList == NULL)",
            "errExit(\"calloc\");",
            "struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList));",
            "if (aiocbList == NULL)",
            "errExit(\"calloc\");",
            "/* Establish handlers for SIGQUIT and the I/O completion signal */",
            "sa.saflags = SARESTART;",
            "sigemptyset(&sa.samask);",
            "sa.sahandler = quitHandler;",
            "if (sigaction(SIGQUIT, &sa, NULL) == -1)",
            "errExit(\"sigaction\");",
            "sa.saflags = SARESTART | SASIGINFO;",
            "sa.sasigaction = aioSigHandler;",
            "if (sigaction(IOSIGNAL, &sa, NULL) == -1)",
            "errExit(\"sigaction\");",
            "/* Open each file specified on the command line, and queue",
            "a read request on the resulting file descriptor */",
            "for (int j = 0; j < numReqs; j++) {",
            "ioList[j].reqNum = j;",
            "ioList[j].status = EINPROGRESS;",
            "ioList[j].aiocbp = &aiocbList[j];",
            "ioList[j].aiocbp->aiofildes = open(argv[j + 1], ORDONLY);",
            "if (ioList[j].aiocbp->aiofildes == -1)",
            "errExit(\"open\");",
            "printf(\"opened %s on descriptor %d\\n\", argv[j + 1],",
            "ioList[j].aiocbp->aiofildes);",
            "ioList[j].aiocbp->aiobuf = malloc(BUFSIZE);",
            "if (ioList[j].aiocbp->aiobuf == NULL)",
            "errExit(\"malloc\");",
            "ioList[j].aiocbp->aionbytes = BUFSIZE;",
            "ioList[j].aiocbp->aioreqprio = 0;",
            "ioList[j].aiocbp->aiooffset = 0;",
            "ioList[j].aiocbp->aiosigevent.sigevnotify = SIGEVSIGNAL;",
            "ioList[j].aiocbp->aiosigevent.sigevsigno = IOSIGNAL;",
            "ioList[j].aiocbp->aiosigevent.sigevvalue.sivalptr =",
            "&ioList[j];",
            "s = aioread(ioList[j].aiocbp);",
            "if (s == -1)",
            "errExit(\"aioread\");",
            "openReqs = numReqs;",
            "/* Loop, monitoring status of I/O requests */",
            "while (openReqs > 0) {",
            "sleep(3);       /* Delay between each monitoring step */",
            "if (gotSIGQUIT) {",
            "/* On receipt of SIGQUIT, attempt to cancel each of the",
            "outstanding I/O requests, and display status returned",
            "from the cancellation requests */",
            "printf(\"got SIGQUIT; canceling I/O requests: \\n\");",
            "for (int j = 0; j < numReqs; j++) {",
            "if (ioList[j].status == EINPROGRESS) {",
            "printf(\"    Request %d on descriptor %d:\", j,",
            "ioList[j].aiocbp->aiofildes);",
            "s = aiocancel(ioList[j].aiocbp->aiofildes,",
            "ioList[j].aiocbp);",
            "if (s == AIOCANCELED)",
            "printf(\"I/O canceled\\n\");",
            "else if (s == AIONOTCANCELED)",
            "printf(\"I/O not canceled\\n\");",
            "else if (s == AIOALLDONE)",
            "printf(\"I/O all done\\n\");",
            "else",
            "perror(\"aiocancel\");",
            "gotSIGQUIT = 0;",
            "/* Check the status of each I/O request that is still",
            "in progress */",
            "printf(\"aioerror():\\n\");",
            "for (int j = 0; j < numReqs; j++) {",
            "if (ioList[j].status == EINPROGRESS) {",
            "printf(\"    for request %d (descriptor %d): \",",
            "j, ioList[j].aiocbp->aiofildes);",
            "ioList[j].status = aioerror(ioList[j].aiocbp);",
            "switch (ioList[j].status) {",
            "case 0:",
            "printf(\"I/O succeeded\\n\");",
            "break;",
            "case EINPROGRESS:",
            "printf(\"In progress\\n\");",
            "break;",
            "case ECANCELED:",
            "printf(\"Canceled\\n\");",
            "break;",
            "default:",
            "perror(\"aioerror\");",
            "break;",
            "if (ioList[j].status != EINPROGRESS)",
            "openReqs--;",
            "printf(\"All I/O requests completed\\n\");",
            "/* Check status return of all I/O requests */",
            "printf(\"aioreturn():\\n\");",
            "for (int j = 0; j < numReqs; j++) {",
            "ssizet s;",
            "s = aioreturn(ioList[j].aiocbp);",
            "printf(\"    for request %d (descriptor %d): %zd\\n\",",
            "j, ioList[j].aiocbp->aiofildes, s);",
            "exit(EXITSUCCESS);"
        ],
        "see_also": [
            {
                "name": "iocancel",
                "section": "2",
                "url": "https://www.chedong.com/phpMan.php/man/iocancel/2/json"
            },
            {
                "name": "iodestroy",
                "section": "2",
                "url": "https://www.chedong.com/phpMan.php/man/iodestroy/2/json"
            },
            {
                "name": "iogetevents",
                "section": "2",
                "url": "https://www.chedong.com/phpMan.php/man/iogetevents/2/json"
            },
            {
                "name": "iosetup",
                "section": "2",
                "url": "https://www.chedong.com/phpMan.php/man/iosetup/2/json"
            },
            {
                "name": "iosubmit",
                "section": "2",
                "url": "https://www.chedong.com/phpMan.php/man/iosubmit/2/json"
            },
            {
                "name": "aiocancel",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/aiocancel/3/json"
            },
            {
                "name": "aioerror",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/aioerror/3/json"
            },
            {
                "name": "aioinit",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/aioinit/3/json"
            },
            {
                "name": "aioread",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/aioread/3/json"
            },
            {
                "name": "aioreturn",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/aioreturn/3/json"
            },
            {
                "name": "aiowrite",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/aiowrite/3/json"
            },
            {
                "name": "liolistio",
                "section": "3",
                "url": "https://www.chedong.com/phpMan.php/man/liolistio/3/json"
            }
        ],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 92,
                "subsections": []
            },
            {
                "name": "ERRORS",
                "lines": 3,
                "subsections": []
            },
            {
                "name": "VERSIONS",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "CONFORMING TO",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "NOTES",
                "lines": 15,
                "subsections": []
            },
            {
                "name": "EXAMPLES",
                "lines": 35,
                "subsections": [
                    {
                        "name": "Program source",
                        "lines": 197
                    }
                ]
            },
            {
                "name": "SEE ALSO",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "COLOPHON",
                "lines": 7,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "aio - POSIX asynchronous I/O overview\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "The  POSIX  asynchronous  I/O (AIO) interface allows applications to initiate one or more I/O\noperations that are performed asynchronously (i.e., in the background).  The application  can\nelect  to be notified of completion of the I/O operation in a variety of ways: by delivery of\na signal, by instantiation of a thread, or no notification at all.\n\nThe POSIX AIO interface consists of the following functions:\n\naioread(3)\nEnqueue a read request.  This is the asynchronous analog of read(2).\n\naiowrite(3)\nEnqueue a write request.  This is the asynchronous analog of write(2).\n\naiofsync(3)\nEnqueue a sync request for the I/O operations on a file descriptor.  This is the asyn‐\nchronous analog of fsync(2) and fdatasync(2).\n\naioerror(3)\nObtain the error status of an enqueued I/O request.\n\naioreturn(3)\nObtain the return status of a completed I/O request.\n\naiosuspend(3)\nSuspend the caller until one or more of a specified set of I/O requests completes.\n\naiocancel(3)\nAttempt to cancel outstanding I/O requests on a specified file descriptor.\n\nliolistio(3)\nEnqueue multiple I/O requests using a single function call.\n\nThe aiocb (\"asynchronous I/O control block\") structure defines parameters that control an I/O\noperation.  An argument of this type is employed with all  of  the  functions  listed  above.\nThis structure has the following form:\n\n#include <aiocb.h>\n\nstruct aiocb {\n/* The order of these fields is implementation-dependent */\n\nint             aiofildes;     /* File descriptor */\nofft           aiooffset;     /* File offset */\nvolatile void  *aiobuf;        /* Location of buffer */\nsizet          aionbytes;     /* Length of transfer */\nint             aioreqprio;    /* Request priority */\nstruct sigevent aiosigevent;   /* Notification method */\nint             aiolioopcode; /* Operation to be performed;\nliolistio() only */\n\n/* Various implementation-internal fields not shown */\n};\n\n/* Operation codes for 'aiolioopcode': */\n\nenum { LIOREAD, LIOWRITE, LIONOP };\n\nThe fields of this structure are as follows:\n\naiofildes\nThe file descriptor on which the I/O operation is to be performed.\n\naiooffset\nThis is the file offset at which the I/O operation is to be performed.\n\naiobuf\nThis is the buffer used to transfer data for a read or write operation.\n\naionbytes\nThis is the size of the buffer pointed to by aiobuf.\n\naioreqprio\nThis  field  specifies  a value that is subtracted from the calling thread's real-time\npriority in order to determine the priority for execution of  this  I/O  request  (see\npthreadsetschedparam(3)).   The  specified  value must be between 0 and the value re‐\nturned by sysconf(SCAIOPRIODELTAMAX).  This field is ignored  for  file  synchro‐\nnization operations.\n\naiosigevent\nThis  field  is  a  structure that specifies how the caller is to be notified when the\nasynchronous I/O operation completes.  Possible values  for  aiosigevent.sigevnotify\nare SIGEVNONE, SIGEVSIGNAL, and SIGEVTHREAD.  See sigevent(7) for further details.\n\naiolioopcode\nThe type of operation to be performed; used only for liolistio(3).\n\nIn  addition to the standard functions listed above, the GNU C library provides the following\nextension to the POSIX AIO API:\n\naioinit(3)\nSet parameters for tuning the behavior of the glibc POSIX AIO implementation.\n",
                "subsections": []
            },
            "ERRORS": {
                "content": "EINVAL The aioreqprio field of the aiocb structure was less than 0, or was greater than  the\nlimit returned by the call sysconf(SCAIOPRIODELTAMAX).\n",
                "subsections": []
            },
            "VERSIONS": {
                "content": "The POSIX AIO interfaces are provided by glibc since version 2.1.\n",
                "subsections": []
            },
            "CONFORMING TO": {
                "content": "POSIX.1-2001, POSIX.1-2008.\n",
                "subsections": []
            },
            "NOTES": {
                "content": "It  is a good idea to zero out the control block buffer before use (see memset(3)).  The con‐\ntrol block buffer and the buffer pointed to by aiobuf must not be changed while the I/O  op‐\neration is in progress.  These buffers must remain valid until the I/O operation completes.\n\nSimultaneous asynchronous read or write operations using the same aiocb structure yield unde‐\nfined results.\n\nThe current Linux POSIX AIO implementation is provided in user space by glibc.   This  has  a\nnumber  of  limitations, most notably that maintaining multiple threads to perform I/O opera‐\ntions is expensive and scales poorly.  Work has been in progress for some time  on  a  kernel\nstate-machine-based  implementation  of  asynchronous  I/O  (see  iosubmit(2),  iosetup(2),\niocancel(2), iodestroy(2), iogetevents(2)), but this implementation hasn't yet matured  to\nthe point where the POSIX AIO implementation can be completely reimplemented using the kernel\nsystem calls.\n",
                "subsections": []
            },
            "EXAMPLES": {
                "content": "The program below opens each of the files named in its command-line arguments  and  queues  a\nrequest on the resulting file descriptor using aioread(3).  The program then loops, periodi‐\ncally monitoring each of the I/O operations that is still  in  progress  using  aioerror(3).\nEach  of  the  I/O requests is set up to provide notification by delivery of a signal.  After\nall I/O requests have completed, the program retrieves their status using aioreturn(3).\n\nThe SIGQUIT signal (generated by typing control-\\) causes the program to request cancellation\nof each of the outstanding requests using aiocancel(3).\n\nHere is an example of what we might see when running this program.  In this example, the pro‐\ngram queues two requests to standard input, and these are satisfied by  two  lines  of  input\ncontaining \"abc\" and \"x\".\n\n$ ./a.out /dev/stdin /dev/stdin\nopened /dev/stdin on descriptor 3\nopened /dev/stdin on descriptor 4\naioerror():\nfor request 0 (descriptor 3): In progress\nfor request 1 (descriptor 4): In progress\nabc\nI/O completion signal received\naioerror():\nfor request 0 (descriptor 3): I/O succeeded\nfor request 1 (descriptor 4): In progress\naioerror():\nfor request 1 (descriptor 4): In progress\nx\nI/O completion signal received\naioerror():\nfor request 1 (descriptor 4): I/O succeeded\nAll I/O requests completed\naioreturn():\nfor request 0 (descriptor 3): 4\nfor request 1 (descriptor 4): 2\n",
                "subsections": [
                    {
                        "name": "Program source",
                        "content": "#include <fcntl.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <stdio.h>\n#include <errno.h>\n#include <aio.h>\n#include <signal.h>\n\n#define BUFSIZE 20     /* Size of buffers for read operations */\n\n#define errExit(msg) do { perror(msg); exit(EXITFAILURE); } while (0)\n\nstruct ioRequest {      /* Application-defined structure for tracking\nI/O requests */\nint           reqNum;\nint           status;\nstruct aiocb *aiocbp;\n};\n\nstatic volatile sigatomict gotSIGQUIT = 0;\n/* On delivery of SIGQUIT, we attempt to\ncancel all outstanding I/O requests */\n\nstatic void             /* Handler for SIGQUIT */\nquitHandler(int sig)\n{\ngotSIGQUIT = 1;\n}\n\n#define IOSIGNAL SIGUSR1   /* Signal used to notify I/O completion */\n\nstatic void                 /* Handler for I/O completion signal */\naioSigHandler(int sig, siginfot *si, void *ucontext)\n{\nif (si->sicode == SIASYNCIO) {\nwrite(STDOUTFILENO, \"I/O completion signal received\\n\", 31);\n\n/* The corresponding ioRequest structure would be available as\nstruct ioRequest *ioReq = si->sivalue.sivalptr;\nand the file descriptor would then be available via\nioReq->aiocbp->aiofildes */\n}\n}\n\nint\nmain(int argc, char *argv[])\n{\nstruct sigaction sa;\nint s;\nint numReqs;        /* Total number of queued I/O requests */\nint openReqs;       /* Number of I/O requests still in progress */\n\nif (argc < 2) {\nfprintf(stderr, \"Usage: %s <pathname> <pathname>...\\n\",\nargv[0]);\nexit(EXITFAILURE);\n}\n\nnumReqs = argc - 1;\n\n/* Allocate our arrays */\n\nstruct ioRequest *ioList = calloc(numReqs, sizeof(*ioList));\nif (ioList == NULL)\nerrExit(\"calloc\");\n\nstruct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList));\nif (aiocbList == NULL)\nerrExit(\"calloc\");\n\n/* Establish handlers for SIGQUIT and the I/O completion signal */\n\nsa.saflags = SARESTART;\nsigemptyset(&sa.samask);\n\nsa.sahandler = quitHandler;\nif (sigaction(SIGQUIT, &sa, NULL) == -1)\nerrExit(\"sigaction\");\n\nsa.saflags = SARESTART | SASIGINFO;\nsa.sasigaction = aioSigHandler;\nif (sigaction(IOSIGNAL, &sa, NULL) == -1)\nerrExit(\"sigaction\");\n\n/* Open each file specified on the command line, and queue\na read request on the resulting file descriptor */\n\nfor (int j = 0; j < numReqs; j++) {\nioList[j].reqNum = j;\nioList[j].status = EINPROGRESS;\nioList[j].aiocbp = &aiocbList[j];\n\nioList[j].aiocbp->aiofildes = open(argv[j + 1], ORDONLY);\nif (ioList[j].aiocbp->aiofildes == -1)\nerrExit(\"open\");\nprintf(\"opened %s on descriptor %d\\n\", argv[j + 1],\nioList[j].aiocbp->aiofildes);\n\nioList[j].aiocbp->aiobuf = malloc(BUFSIZE);\nif (ioList[j].aiocbp->aiobuf == NULL)\nerrExit(\"malloc\");\n\nioList[j].aiocbp->aionbytes = BUFSIZE;\nioList[j].aiocbp->aioreqprio = 0;\nioList[j].aiocbp->aiooffset = 0;\nioList[j].aiocbp->aiosigevent.sigevnotify = SIGEVSIGNAL;\nioList[j].aiocbp->aiosigevent.sigevsigno = IOSIGNAL;\nioList[j].aiocbp->aiosigevent.sigevvalue.sivalptr =\n&ioList[j];\n\ns = aioread(ioList[j].aiocbp);\nif (s == -1)\nerrExit(\"aioread\");\n}\n\nopenReqs = numReqs;\n\n/* Loop, monitoring status of I/O requests */\n\nwhile (openReqs > 0) {\nsleep(3);       /* Delay between each monitoring step */\n\nif (gotSIGQUIT) {\n\n/* On receipt of SIGQUIT, attempt to cancel each of the\noutstanding I/O requests, and display status returned\nfrom the cancellation requests */\n\nprintf(\"got SIGQUIT; canceling I/O requests: \\n\");\n\nfor (int j = 0; j < numReqs; j++) {\nif (ioList[j].status == EINPROGRESS) {\nprintf(\"    Request %d on descriptor %d:\", j,\nioList[j].aiocbp->aiofildes);\ns = aiocancel(ioList[j].aiocbp->aiofildes,\nioList[j].aiocbp);\nif (s == AIOCANCELED)\nprintf(\"I/O canceled\\n\");\nelse if (s == AIONOTCANCELED)\nprintf(\"I/O not canceled\\n\");\nelse if (s == AIOALLDONE)\nprintf(\"I/O all done\\n\");\nelse\nperror(\"aiocancel\");\n}\n}\n\ngotSIGQUIT = 0;\n}\n\n/* Check the status of each I/O request that is still\nin progress */\n\nprintf(\"aioerror():\\n\");\nfor (int j = 0; j < numReqs; j++) {\nif (ioList[j].status == EINPROGRESS) {\nprintf(\"    for request %d (descriptor %d): \",\nj, ioList[j].aiocbp->aiofildes);\nioList[j].status = aioerror(ioList[j].aiocbp);\n\nswitch (ioList[j].status) {\ncase 0:\nprintf(\"I/O succeeded\\n\");\nbreak;\ncase EINPROGRESS:\nprintf(\"In progress\\n\");\nbreak;\ncase ECANCELED:\nprintf(\"Canceled\\n\");\nbreak;\ndefault:\nperror(\"aioerror\");\nbreak;\n}\n\nif (ioList[j].status != EINPROGRESS)\nopenReqs--;\n}\n}\n}\n\nprintf(\"All I/O requests completed\\n\");\n\n/* Check status return of all I/O requests */\n\nprintf(\"aioreturn():\\n\");\nfor (int j = 0; j < numReqs; j++) {\nssizet s;\n\ns = aioreturn(ioList[j].aiocbp);\nprintf(\"    for request %d (descriptor %d): %zd\\n\",\nj, ioList[j].aiocbp->aiofildes, s);\n}\n\nexit(EXITSUCCESS);\n}\n"
                    }
                ]
            },
            "SEE ALSO": {
                "content": "iocancel(2), iodestroy(2), iogetevents(2), iosetup(2), iosubmit(2), aiocancel(3),\naioerror(3), aioinit(3), aioread(3), aioreturn(3), aiowrite(3), liolistio(3)\n\n\"Asynchronous I/O Support in Linux 2.5\", Bhattacharya, Pratt, Pulavarty, and Morgan,\nProceedings of the Linux Symposium, 2003,\n⟨https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf⟩\n",
                "subsections": []
            },
            "COLOPHON": {
                "content": "This page is part of release 5.10 of the Linux man-pages project.  A description of the\nproject, information about reporting bugs, and the latest version of this page, can be found\nat https://www.kernel.org/doc/man-pages/.\n\n\n\nLinux                                        2020-08-13                                       AIO(7)",
                "subsections": []
            }
        }
    }
}