aio(7) - wariua/manpages-ko GitHub Wiki
aio - POSIX λΉλκΈ° I/O μκ°
POSIX λΉλκΈ° I/O(AIO) μΈν°νμ΄μ€λ₯Ό μμ©μμ μ΄μ©νμ¬ λΉλκΈ°μ μΌλ‘ (μ¦ λ°°κ²½μμ) μνλλ I/O λμμ ν κ° μ΄μ κ°μν μ μλ€. I/O λμ μλ£μ λν μλ¦Όμ μμ©μμ μνλ λ€μν λ°©μμΌλ‘ λ°μ μ μλ€. μκ·Έλ μ λ¬, μ€λ λ μ€ν, λλ μλ¦Όμ λ°μ§ μμ μλ μλ€.
POSIX AIO μΈν°νμ΄μ€λ λ€μ ν¨μλ€λ‘ μ΄λ€μ Έ μλ€.
- aio_read(3)
- μ½κΈ° μμ²μ νμ λ£λλ€.
read(2)
μ λΉλκΈ° ννμ΄λ€. - aio_write(3)
- μ°κΈ° μμ²μ νμ λ£λλ€.
write(2)
μ λΉλκΈ° ννμ΄λ€. - aio_fsync(3)
- νμΌ λμ€ν¬λ¦½ν° μμ I/O λμλ€μ λν λκΈ°ν μμ²μ νμ λ£λλ€. fsync(2) λ° fdatasync(2)μ λΉλκΈ° ννμ΄λ€.
- aio_error(3)
- νμ λ£μ I/O μμ²μ μ€λ₯ μνλ₯Ό μ»λλ€.
- aio_return(3)
- μλ£λ I/O μμ²μ λ°ν μνλ₯Ό μ»λλ€.
- aio_suspend(3)
- μ§μ ν I/O μμ²μ΄ νλ μ΄μ μλ£λ λκΉμ§ νΈμΆμλ₯Ό λ©μΆλ€.
- aio_cancel(3)
- μ§μ ν νμΌ λμ€ν¬λ¦½ν° μμ λ―Έμ²λ¦¬ I/O μμ²λ€μ μ·¨μ μλνλ€.
- lio_listio(3)
- ν λ²μ ν¨μ νΈμΆλ‘ μ¬λ¬ I/O μμ²μ νμ λ£λλ€.
aiocb
(λΉλκΈ° I/O μ μ΄ λΈλ‘) κ΅¬μ‘°μ²΄κ° I/O λμμ μ μ΄νλ λ§€κ°λ³μλ€μ μ μνλ€. μμ λμ΄ν ν¨μ λͺ¨λμμ μ΄ νμ
μ μΈμλ₯Ό μ΄λ€. μ΄ κ΅¬μ‘°μ²΄λ λ€μ ννμ΄λ€.
#include <aiocb.h>
struct aiocb {
/* μ΄ νλλ€μ μμλ ꡬνμ λ°λΌ λ€λ¦ */
int aio_fildes; /* νμΌ λμ€ν¬λ¦½ν° */
off_t aio_offset; /* νμΌ μ€νμ
*/
volatile void *aio_buf; /* λ²νΌ μμΉ */
size_t aio_nbytes; /* μ μ‘ κΈΈμ΄ */
int aio_reqprio; /* μμ² μ°μ μμ */
struct sigevent aio_sigevent; /* μλ¦Ό λ°©λ² */
int aio_lio_opcode; /* μνν λμ.
lio_listio()μμλ§ */
/* μ¬λ¬ ꡬν λ΄λΆμ© νλ μλ΅ */
};
/* 'aio_lio_opcode'μ λμ μ½λ */
enum { LIO_READ, LIO_WRITE, LIO_NOP };
μ΄ κ΅¬μ‘°μ²΄μ νλλ€μ λ€μκ³Ό κ°λ€.
aio_fildes
- I/O λμμ μνν νμΌ λμ€ν¬λ¦½ν°.
aio_offset
- I/O λμμ μνν νμΌ μ€νμ .
aio_buf
- μ½κΈ° λλ μ°κΈ° λμμμ λ°μ΄ν° μ΄λμ μ¬μ©νλ λ²νΌ.
aio_nbytes
-
aio_buf
κ° κ°λ¦¬ν€λ λ²νΌμ ν¬κΈ°. aio_reqprio
- μ΄ νλμ μ§μ ν κ°μ νΈμΆ μ€λ λμ μ€μκ° μ°μ μμμμ λΉΌμ μ΄ I/O μμ²μ μ€ν μ°μ μμλ₯Ό κ²°μ νλ€. (pthread_setschedparam(3) μ°Έκ³ .) μ§μ νλ κ°μ΄ 0κ³Ό
sysconf(_SC_AIO_PRIO_DELTA_MAX)
λ°ν κ° μ¬μ΄μ μμ΄μΌ νλ€. νμΌ λκΈ°ν λμμμλ μ΄ νλλ₯Ό 무μνλ€. aio_sigevent
- λΉλκΈ° I/O λμμ΄ μλ£λμ λ νΈμΆμκ° μλ¦Όμ λ°λ λ°©λ²μ μ§μ νλ ꡬ쑰체μ΄λ€.
aio_sigevent.sigev_notify
μ κ°λ₯ν κ°μSIGEV_NONE
,SIGEV_SIGNAL
,SIGEV_THREAD
μ΄λ€. μμΈν λ΄μ©μ sigevent(7) μ°Έκ³ . aio_lio_opcode
- μνν λμ μ’ λ₯. lio_listio(3)μμλ§ μ¬μ©.
μμ λμ΄ν νμ€ ν¨μλ€μ λν΄μ GNU C λΌμ΄λΈλ¬λ¦¬μμλ POSIX AIO APIμ λν λ€μ νμ₯μ μ 곡νλ€.
- aio_init(3)
- glibc POSIX AIO ꡬνμ λμμ μ‘°μ νλ λ§€κ°λ³μλ€μ μ€μ νλ€.
EINVAL
-
aiocb
ꡬ쑰체μaio_reqprio
νλκ° 0λ³΄λ€ μκ±°λsysconf(_SC_AIO_PRIO_DELTA_MAX)
νΈμΆμ΄ λ°νν νκ³μΉλ³΄λ€ ν¬λ€.
glibc λ²μ 2.1λΆν° POSIX AIO μΈν°νμ΄μ€λ₯Ό μ 곡νλ€.
POSIX.1-2001, POSIX.1-2008.
μ μ΄ λΈλ‘ λ²νΌλ₯Ό μ¬μ©νκΈ° μ μ 0μΌλ‘ μ±μ°λ κ² μ’λ€. (memset(3)
μ°Έκ³ .) I/O λμμ΄ μ§ν μ€μΈ λμ μ μ΄ λΈλ‘ λ²νΌμ aio_buf
κ° κ°λ¦¬ν€λ λ²νΌκ° λ³κ²½λμ΄μ μ λλ€. I/O λμμ΄ μλ£λ λκΉμ§ κ·Έ λ²νΌλ€μ΄ μ ν¨ν μνλ‘ μ μ§λΌμΌ νλ€.
κ°μ aiocb
ꡬ쑰체λ₯Ό μ¬μ©ν΄ λμμ λΉλκΈ° μ½κΈ° λμκ³Ό μ°κΈ° λμμ ν λ λμ€λ κ²°κ³Όλ κ·μ λΌ μμ§ μλ€.
νμ¬ λ¦¬λ μ€μ POSIX AIO ꡬνμ μ¬μ©μ 곡κ°μμ glibcκ° μ 곡νλ€. κ·Έλμ μ¬λ¬ μ μ½μ΄ μλλ°, κ°μ₯ λμ λλ 건 I/O λμμ μννκΈ° μν΄ μ¬λ¬ μ€λ λλ₯Ό μ μ§νλ κ² λΉμ©μ΄ ν¬κ³ νμ₯μ±μ΄ λ¨μ΄μ§λ€λ μ μ΄λ€. μΌλ§ μ λΆν° 컀λμμ μν λ¨Έμ κΈ°λ°μΌλ‘ λΉλκΈ° I/Oλ₯Ό ꡬννλ μμ μ΄ μ§ν μ€μ΄κΈ΄ νλ° (io_submit(2), io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2) μ°Έκ³ ) κ·Έ 컀λ μμ€ν νΈμΆλ€μ μ΄μ©ν΄ POSIX AIO ꡬνμ μμ ν μ¬κ΅¬νν μ μλ μμ€κΉμ§λ μμ§ μ€μ§ λͺ»νλ€.
μλ νλ‘κ·Έλ¨μμλ λͺ λ Ήν μΈμμ μ§λͺ ν νμΌλ€ κ°κ°μ μ΄μ΄μ μ»μ νμΌ λμ€ν¬λ¦½ν°μ aio_read(3)λ‘ μμ²μ λ£λλ€. κ·Έλ¬κ³ μ 루νλ₯Ό λλ©΄μ μμ§ μ§ν μ€μΈ I/O λμ κ°κ°μ aio_error(3)λ₯Ό μ΄μ©ν΄ μ£ΌκΈ°μ μΌλ‘ νμΈνλ€. I/O μμ² κ°κ°μ μκ·Έλ μ λ¬λ‘ μλ¦Όμ μ£Όλλ‘ μ€μ νλ€. λͺ¨λ I/O μμ²μ΄ μλ£λ νμ aio_return(3)μΌλ‘ μνλ₯Ό κ°μ Έμ¨λ€.
SIGQUIT
μκ·Έλ(Control-\ μ
λ ₯μΌλ‘ μμ±)μ μ£Όλ©΄ νλ‘κ·Έλ¨μμ aio_cancel(3)λ‘ λ―Έμ²λ¦¬ μμ² κ°κ°μ μ·¨μλ₯Ό μμ²νλ€.
λ€μμ μ΄ νλ‘κ·Έλ¨μ μ€νν κ²°κ³Ό μμμ΄λ€. μ΄ μμμλ νμ€ μ λ ₯μ λν μμ²μ λ κ° νκ³ , "abc"μ "x"λ₯Ό λ΄μ λ μ λ ₯ νμΌλ‘ κ·Έ μμ²μ μΆ©μ‘±μν¨λ€.
$ ./a.out /dev/stdin /dev/stdin
opened /dev/stdin on descriptor 3
opened /dev/stdin on descriptor 4
aio_error():
for request 0 (descriptor 3): In progress
for request 1 (descriptor 4): In progress
abc
I/O completion signal received
aio_error():
for request 0 (descriptor 3): I/O succeeded
for request 1 (descriptor 4): In progress
aio_error():
for request 1 (descriptor 4): In progress
x
I/O completion signal received
aio_error():
for request 1 (descriptor 4): I/O succeeded
All I/O requests completed
aio_return():
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 BUF_SIZE 20 /* μ½κΈ° λμμ μν λ²νΌ ν¬κΈ° */
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define errMsg(msg) do { perror(msg); } while (0)
struct ioRequest { /* I/O μμ² μΆμ μ μν΄ μμ© μ체μμ
μ μνλ ꡬ쑰체 */
int reqNum;
int status;
struct aiocb *aiocbp;
};
static volatile sig_atomic_t gotSIGQUIT = 0;
/* SIGQUITμ΄ μ λ¬λλ©΄ λ―Έμ²λ¦¬ I/O μμ²μ
λͺ¨λ μ·¨μνλ €κ³ μλ */
static void /* SIGQUIT νΈλ€λ¬ */
quitHandler(int sig)
{
gotSIGQUIT = 1;
}
#define IO_SIGNAL SIGUSR1 /* I/O μλ£λ₯Ό μ리λ λ° μΈ μκ·Έλ */
static void /* I/O μλ£ μκ·Έλ νΈλ€λ¬ */
aioSigHandler(int sig, siginfo_t *si, void *ucontext)
{
if (si->si_code == SI_ASYNCIO) {
write(STDOUT_FILENO, "I/O completion signal received\n", 31);
/* λμνλ ioRequest ꡬ쑰체λ₯Ό λ€μκ³Ό κ°μ΄ μ»μ μ μμ:
struct ioRequest *ioReq = si->si_value.sival_ptr;
κ·Έλ¦¬κ³ νμΌ λμ€ν¬λ¦½ν°λ₯Ό λ€μμ ν΅ν΄ μ»μ μ μμ:
ioReq->aiocbp->aio_fildes */
}
}
int
main(int argc, char *argv[])
{
struct ioRequest *ioList;
struct aiocb *aiocbList;
struct sigaction sa;
int s, j;
int numReqs; /* νμ λ£μ I/O μμ² μ΄ κ°μ */
int openReqs; /* μμ§ μ§ν μ€μΈ I/O μμ² κ°μ */
if (argc < 2) {
fprintf(stderr, "Usage: %s <pathname> <pathname>...\n",
argv[0]);
exit(EXIT_FAILURE);
}
numReqs = argc - 1;
/* λ°°μ΄ ν λΉ */
ioList = calloc(numReqs, sizeof(struct ioRequest));
if (ioList == NULL)
errExit("calloc");
aiocbList = calloc(numReqs, sizeof(struct aiocb));
if (aiocbList == NULL)
errExit("calloc");
/* SIGQUIT λ° I/O μλ£ μκ·Έλμ μν νΈλ€λ¬ μ€μ */
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sa.sa_handler = quitHandler;
if (sigaction(SIGQUIT, &sa, NULL) == -1)
errExit("sigaction");
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sa.sa_sigaction = aioSigHandler;
if (sigaction(IO_SIGNAL, &sa, NULL) == -1)
errExit("sigaction");
/* λͺ
λ Ήνμ μ§μ ν νμΌ κ°κ°μ μ΄κ³ , κ·Έλ κ² μ»μ νμΌ
λμ€ν¬λ¦½ν°μμ μ½κΈ° μμ²μ νμ λ£κΈ° */
for (j = 0; j < numReqs; j++) {
ioList[j].reqNum = j;
ioList[j].status = EINPROGRESS;
ioList[j].aiocbp = &aiocbList[j];
ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY);
if (ioList[j].aiocbp->aio_fildes == -1)
errExit("open");
printf("opened %s on descriptor %d\n", argv[j + 1],
ioList[j].aiocbp->aio_fildes);
ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE);
if (ioList[j].aiocbp->aio_buf == NULL)
errExit("malloc");
ioList[j].aiocbp->aio_nbytes = BUF_SIZE;
ioList[j].aiocbp->aio_reqprio = 0;
ioList[j].aiocbp->aio_offset = 0;
ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL;
ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr =
&ioList[j];
s = aio_read(ioList[j].aiocbp);
if (s == -1)
errExit("aio_read");
}
openReqs = numReqs;
/* 루ν λλ©΄μ I/O μμ² μν νμΈ */
while (openReqs > 0) {
sleep(3); /* νμΈ κ°κ²© */
if (gotSIGQUIT) {
/* SIGQUIT μμ μ λ―Έμ²λ¦¬ I/O μμ² κ°κ°μ μ·¨μ μλνκ³ ,
μ·¨μ μμ²μμ λ°ν λ°μ μνλ₯Ό νμ */
printf("got SIGQUIT; canceling I/O requests: \n");
for (j = 0; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" Request %d on descriptor %d:", j,
ioList[j].aiocbp->aio_fildes);
s = aio_cancel(ioList[j].aiocbp->aio_fildes,
ioList[j].aiocbp);
if (s == AIO_CANCELED)
printf("I/O canceled\n");
else if (s == AIO_NOTCANCELED)
printf("I/O not canceled\n");
else if (s == AIO_ALLDONE)
printf("I/O all done\n");
else
errMsg("aio_cancel");
}
}
gotSIGQUIT = 0;
}
/* μμ§ μ§ν μ€μΈ I/O μμ² κ°κ°μ μν νμΈ */
printf("aio_error():\n");
for (j = 0; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" for request %d (descriptor %d): ",
j, ioList[j].aiocbp->aio_fildes);
ioList[j].status = aio_error(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:
errMsg("aio_error");
break;
}
if (ioList[j].status != EINPROGRESS)
openReqs--;
}
}
}
printf("All I/O requests completed\n");
/* λͺ¨λ I/O μμ²μ μν λ°ν κ° νμΈ */
printf("aio_return():\n");
for (j = 0; j < numReqs; j++) {
ssize_t s;
s = aio_return(ioList[j].aiocbp);
printf(" for request %d (descriptor %d): %zd\n",
j, ioList[j].aiocbp->aio_fildes, s);
}
exit(EXIT_SUCCESS);
}
io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2), io_submit(2), aio_cancel(3), aio_error(3), aio_init(3), aio_read(3), aio_return(3), aio_write(3), lio_listio(3)
"Asynchronous I/O Support in Linux 2.5", Bhattacharya, Pratt, Pulavarty, and Morgan, Proceedings of the Linux SYmposium, 2003, https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf
2019-03-06