TOC PREV NEXT INDEX

POSIX 1.b Migration Guide


Asynchronous I/O

Changes in asynchronous I/O features center primarily around reordered data structure entries and function parameters. In addition, POSIX.1b introduces a new idea of asynchronous I/O priority. The priority of an asynchronous I/O operation can be lowered, but not raised, with respect to the process scheduling priority.

Refer to "Changes from Draft 9 to POSIX.1b" for a comparison of data structures and flags specific to asynchronous I/O.

Data Structure Changes

The aiocb data structure changed has significantly. Because of these changes, the liocb data structure has been eliminated. The following is a comparison of the aiocb data structures for Draft 9 and POSIX.1b.

aiocb Structure  
Draft 9
POSIX.1b
aio_offset
aio_offset
aio_event
aio_sigevent
aio_prio
aio_reqprio
aio_whence
No Equivalent (always SEEK_SET)
aio_flag
No Equivalent
aio_errno
No Equivalent
aio_nobytes
No Equivalent
No Equivalent
aio_nbytes
No Equivalent
aio_fildes
No Equivalent
aio_buf
No Equivalent
aio_lio_opcode

POSIX.1b structure includes the file descriptor, buffer, and listio opcode fields. The new aio_nbytes field has the same semantics as defined by the read() and write() synopses.

As a result, the synopses for the asynchronous I/O functions have changed
as follows:

There is no relation between the new aio_nbytes field and the old aio_nobytes field. The aio_return() function may be used on the same aiocb structure more than once, as a proprietary extension from LynuxWorks. This can be disabled by a new proprietary library call aio_setparam(). Refer to the aio_setparam() man page for more information.

The aio_prio field from Draft 9 was unused and has been replaced with the aio_reqprio field. With this field, POSIX.1b asynchronous I/O can be queued in a priority order.

The priority of an asynchronous process is the process priority minus the aio_reqprio value. Priority of asynchronous I/O can be lowered, but not raised, with respect to the process priority. However, as a proprietary feature from LynuxWorks, the priority of an asynchronous I/O operation can be raised with respect to the process priority. This is achieved by the aio_setparam() library call, which is specific to LynxOS. Refer to the aio_setparam() man page for more information.

Asynchronous Read and Write

The following example shows a code comparison for an asynchronous write operation. Also, it shows the use of two new functions for POSIX.1b; namely, aio_return() and aio_error().

In POSIX.1b code the sa_flags flag is set to SA_SIGINFO, and the sigev_notify field is set to SIGEV_SIGNAL to ensure the use of a
real-time signal.

Draft 9 Code

#include <errno.h>
#include <sys/aio.h>

#define SIZE 256

void event_handler(void *evt_value,
evt_class_t evt_class, evtset_t evt_mask);

main()
{
int fd;
char buf[SIZE];
struct aiocb cb;
struct sigaction sa;
:
fd = open(.......);
:
sa.sa_handler = event_handler;
sa.sa_flags = SA_D9EV;
sigemptyset(&sa.sa_mask);

sigaction(EVTCLASS_MIN, &sa, NULL);

cb.aio_event.evt_handler = event_handler;
cb.aio_event.evt_value = NULL;
cb.aio_event.evt_class = EVTCLASS_MIN;
evtemptyset(&cb.aio_event.evt_classmask);
cb.aio_flag = AIO_EVENT;
cb.aio_offset = 0;
cb.aio_whence = 0;
cb.aio_prio = 0;

awrite(fd, buf, SIZE, &cb);

while (cb.aio_errno == EINPROG) {
:
:
}

printf("Errno = %d, No. of bytes = %d\n",
cb.aio_errno, cb.aio_nobytes);
:
}

void event_handler(evt_value, evt_class, evt_mask)
void *evt_value;
evt_class_t evt_class;
evtset_t evt_mask;
{
:
:
}

Equivalent POSIX.1b Code

#include <aio.h>
#include <errno.h>

#define SIZE 256

void signal_handler(int signo, siginfo_t *info, void *context);

main()
{
int fd;
char buf[SIZE];
struct aiocb cb;
struct sigaction sa;
int err, ret;
:
fd = open(.......);
:
sa.sa_sigaction = signal_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);

sigaction(SIGRTMIN, &sa, NULL);

cb.aio_sigevent.sigev_signo = SIGRTMIN;
cb.aio_sigevent.sigev_value.sival_ptr = NULL;
cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb.aio_offset = 0;
cb.aio_reqprio = 0;
cb.aio_fildes = fd;
cb.aio_buf = buf;
cb.aio_nbytes = SIZE;

aio_write(&cb);

while (aio_error(&cb) == EINPROGRESS) {
:
:
}

err=aio_err (&cb);
ret=aio_return (&cb);
:
}
void signal_handler(signo, info, context)
int signo;
siginfo_t *info;
void *context;
{
:
:
}

List Directed I/O

The following example illustrates how a Draft 9 program doing list-directed I/O can be migrated to POSIX.1b. In Draft 9, LIO_NOWAIT ignores the final event argument while LIO_ASYNC ensures a final event delivery. In POSIX.1b, LIO_NOWAIT ensures a final signal delivery on completion of the last listio job. If, however, the final signal argument is NULL, no signal is sent.

Draft 9 Code

#include <sys/aio.h>

#define SIZE 1024

void evt_handler1(void *evt_value,
evt_class_t evt_class, evtset_t evt_mask);
void evt_handler2(void *evt_value,
evt_class_t evt_class, evtset_t evt_mask);
void evt_final_handler(void *evt_value,
evt_class_t evt_class,evtset_t evt_mask);

main()
{
int fd1, fd2;
char buf1[SIZE], buf2[SIZE];
struct liocb list1, list2, *lcb[2];
struct sigaction sa;
struct event final_evt;
:
fd1 = open(......);
fd2 = open(......);
:
sa.sa_handler = evt_handler1;
sa.sa_flags = SA_D9EV;
sigemptyset(&sa.sa_mask);

sigaction(EVTCLASS_MIN, &sa, NULL);

sa.sa_handler = evt_handler2;
sa.sa_flags = SA_D9EV;
sigemptyset(&sa.sa_mask);

sigaction(EVTCLASS_MIN+1, &sa, NULL);
:
list1.lio_opcode = LIO_WRITE;
list1.lio_fildes = fd1;
list1.lio_buf = buf1;
list1.lio_nbytes = SIZE;
list1.lio_aiocb.aio_event.evt_data = NULL;
list1.lio_aiocb.aio_event.evt_class = EVTCLASS_MIN;
list1.lio_aiocb.aio_event.evt_handler =
evt_handler1;
evtemptyset(&list1.lio_aiocb.aio_event.
evt_classmask);
list1.lio_aiocb.aio_flag = AIO_EVENT;
list1.lio_aiocb.aio_offset = 0;
list1.lio_aiocb.aio_whence = 0;
list1.lio_aiocb.aio_prio = 0;

list2.lio_opcode = LIO_READ;
list2.lio_fildes = fd2;
list2.lio_buf = buf2;
list2.lio_nbytes = SIZE;
list2.lio_aiocb.aio_event.evt_data = NULL;
list2.lio_aiocb.aio_event.evt_class =
EVTCLASS_MIN+1;
list2.lio_aiocb.aio_event.evt_handler =
evt_handler2;
evtemptyset(&list2.lio_aiocb.aio_event.
evt_classmask);
list2.lio_aiocb.aio_flag = AIO_EVENT;
list2.lio_aiocb.aio_offset = 0;
list2.lio_aiocb.aio_whence = 0;
list2.lio_aiocb.aio_prio = 0;

lcb[0] = &list1;
lcb[1] = &list2;

sa.sa_handler = evt_final_handler;
sa.sa_flags = SA_D9EV;
sigemptyset(&sa.sa_mask);

sigaction(EVTCLASS_MIN+2, &sa, NULL);

final_evt.evt_value = NULL;
final_evt.evt_class = EVTCLASS_MIN+2;
final_evt.evt_handler = evt_final_handler;
evtemptyset(&final_evt.evt_classmask);
:
listio(LIO_ASYNC, lcb, 2, &final_evt);
:
}

void evt_handler1(evt_value, evt_class, evt_mask)
void *evt_value;
evt_class_t evt_class;
evtset_t evt_mask;
{
:
:
}

void evt_handler2(evt_value, evt_class, evt_mask)
void *evt_value;
evt_class_t evt_class;
evtset_t evt_mask;
{
:
:
}

void evt_final_handler(evt_value, evt_class, evt_mask)
void *evt_value;
evt_class_t evt_class;
evtset_t evt_mask;
{
:
:
}

Equivalent POSIX.1b Code

#include <aio.h>

#define SIZE 1024

void signal_handler1(int signo, siginfo_t *info,
void *context);
void signal_handler2(int signo, siginfo_t *info,
void *context);
void signal_final_handler(int signo, siginfo_t *info,
void *context);

main()
{
int fd1, fd2;
char buf1[SIZE], buf2[SIZE];
struct aiocb cb1, cb2, *cbs[2];
struct sigaction sa;
struct sigevent final_se;
:
fd1 = open(......);
fd2 = open(......);
:
sa.sa_sigaction = signal_handler1;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);

sigaction(SIGRTMIN, &sa, NULL);

sa.sa_sigaction = signal_handler2;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);

sigaction(SIGRTMIN+1, &sa, NULL);
:
cb1.aio_sigevent.sigev_signo = SIGRTMIN;
cb1.aio_sigevent.sigev_value.sival_ptr = NULL;
cb1.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb1.aio_offset = 0;
cb1.aio_reqprio = 0;
cb1.aio_fildes = fd1;
cb1.aio_buf = buf1;
cb1.aio_nbytes = SIZE;
cb1.aio_lio_opcode = LIO_WRITE;

cb2.aio_sigevent.sigev_signo = SIGRTMIN+1;
cb2.aio_sigevent.sigev_value.sival_ptr = NULL;
cb2.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb2.aio_offset = 0;
cb2.aio_reqprio = 0;
cb2.aio_fildes = fd2;
cb2.aio_buf = buf2;
cb2.aio_nbytes = SIZE;
cb2.aio_lio_opcode = LIO_READ;

cbs[0] = &cb1;
cbs[1] = &cb2;

sa.sa_sigaction = signal_final_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);

sigaction(SIGRTMIN+2, &sa, NULL);

final_se.sigev_signo = SIGRTMIN+2;
final_se.sigev_value.sival_ptr = NULL;
final_se.sigev_value.sigev_notify = SIGEV_SIGNAL;
:
lio_listio(LIO_NOWAIT, cbs, 2, &final_se);
:
}

void signal_handler1(signo, info, context)
int signo;
siginfo_t *info;
void *context;
{
:
:
}

void signal_handler2(signo, info, context);
int signo;
siginfo_t *info;
void *context;
{
:
:
}

void signal_final_handler(signo, info, context)
int signo;
siginfo_t *info;
void *context;
{
:
:
}

Changes from Draft 9 to POSIX.1b

All Draft 9 functionality has an equivalent in POSIX.1b, but there are differences in the data structure entries and the way parameters are passed to functions.

Asynchronous I/O Interface  
Draft 9
POSIX.1b
<sys/aio.h>
<aio.h>
struct liocb
Provided by structure aiocb
AIO_EVENT
No Equivalent
LIO_ASYNC
No Equivalent
AIO_PRIO_DFL
No Equivalent
AIO_PRIO_MAX
No Equivalent
AIO_PRIO_MIN
No Equivalent
AIO_LISTIO_MAX
No Equivalent
No Equivalent
AIO_PRIO_DELTA_MAX
aread()
aio_read()
awrite()
aio_write()
listio()
lio_listio()
acancel()
aio_cancel()
iosuspend()
aio_suspend()
afsync()
aio_fsync()
No Equivalent
aio_error()
Retrieves the error status from an aiocb structure
No Equivalent
aio_return()
Retrieves the return status from an aiocb structure

Data Structures

The data structure aiocb changed a lot from Draft 9 to POSIX.1b. Also, the liocb data structure has been eliminated because of the changes to aiocb.

The following is a comparison of the aiocb data structures for Draft 9
and POSIX.1b.

aiocb Structure  
Draft 9
POSIX.1b
aio_offset
aio_offset
aio_event
aio_sigevent
aio_prio
aio_reqprio
aio_whence
No Equivalent
aio_flag
No Equivalent
aio_errno
No Equivalent
aio_nobytes
No Equivalent
No Equivalent
aio_nbytes
No Equivalent
aio_fildes
No Equivalent
aio_buf
No Equivalent
aio_lio_opcode

POSIX.1b structure includes the file descriptor, buffer, and listio opcode fields. The new aio_nbytes field has the same semantics as defined by the read() and write() synopses. Therefore, the synopses for the aio functions have changed as follows:

The aio_whence field has been eliminated. The aio_offset argument is treated as an offset from the beginning of the file. The effect is as if aio_whence is always SEEK_SET.

The aio_errno field has been eliminated. Instead, a new function, aio_error() with the aiocb argument does the same job.

The aio_flag field has been eliminated. It is superseded by the
aio_sigevent field.

The aio_nobytes field has been eliminated. The new aio_return() function retrieves the return status from an aiocb structure. aio_return() can be called only once per structure; this structure may not be passed to aio_error() or aio_return() again.

There is no relation between the new aio_nbytes field and the old aio_nobytes field. The aio_return() function may be used on the same aiocb structure more than once, as a proprietary extension from LynuxWorks. This can be disabled by a new proprietary library call aio_setparam(). Refer to the aio_setparam() man page for more information.

Priority of asynchronous I/O can be lowered, but not raised, with respect to the process priority. However, a proprietary feature of LynxOS allows the priority of an asynchronous I/O operation to be raised with respect to the process priority. This is done by the aio_setparam() library call. Refer to the aio_setparam() man page for more information.

Timed Suspension

The Draft 9 iosuspend() function suspends the process until the completion
of I/O. The aio_suspend() function from POSIX.1b adds an option for timed suspension. It takes an extra timespec argument for timeout. If this argument is NULL, the behavior is the same as suspension until the completion of I/O.

Cancellation Notification

With the acancel() function from Draft 9, no event notification is given when an asynchronous I/O function is successfully cancelled. However, with the aio_cancel() function from POSIX.1b, normal signal delivery occurs for all asynchronous I/O functions that are cancelled.

listio Signal Delivery

POSIX.1b provides only two mode values as opposed to the three values from Draft 9. The LIO_ASYNC value has been removed. The LIO_NOWAIT argument ensures a final signal delivery, and is equivalent to LIO_ASYNC from Draft 9. If the final signal parameter passed to lio_listio() is NULL, a final signal is not sent. This is equivalent to the LIO_NOWAIT behavior from Draft 9.

aio_fsync()

The POSIX.1b aio_fsync() function (equivalent to the Draft 9 afsync() function) provides fsync() behavior with the O_SYNC flag, and fdatasync() behavior with the O_DSYNC flag. The difference is that for synchronized I/O file integrity completion, the O_FSYNC flag is used in Draft 9, while the O_SYNC flag is used in POSIX.1b. Refer to the synchronous I/O section for the semantics of these functions.

Interoperability

Asynchronous I/O is fully inter-operable. A process using Draft 9 asynchronous I/O is compatible with a process performing POSIX.1b asynchronous I/O to the same file.

Note: Due to a rare condition in the Draft 9 specification, multiple processes accessing a file during asynchronous I/O can produce unexpected results. Avoid using Draft 9 asynchronous I/O if the file will be accessed by multiple processes.



LynuxWorks, Inc.
855 Branham Lane East
San Jose, CA 95138
http://www.lynuxworks.com
1.800.255.5969
TOC PREV NEXT INDEX