The asyncio callable service performs I/O operations against a socket asynchronously. It also provides synchronous operations for compatibility with the regular functions.
Operation | Environment |
---|---|
Authorization: | Supervisor state or problem state, any PSW key |
Dispatchable unit mode: | Task or SRB |
Cross memory mode: | PASN = HASN |
AMODE (BPX1AIO): | 31-bit |
AMODE (BPX4AIO): | 64-bit |
ASC mode: | Primary mode |
Interrupt status: | Enabled for interrupts |
Locks: | Unlocked |
Control parameters: | All parameters must be addressable by the caller and in the primary address space. |
|
AMODE 64 callers use BPX4AIO with the same parameters. All addresses in the Aiocb structure are doublewords.
The name of a fullword that contains the length of the Aiocb control block that is being passed in the next parameter. To determine the value of Aiocb_length, use the BPXYAIO macro (see BPXYAIO — Map asyncio parameter list).
The name of an Aiocb structure to be used to control this I/O operation. See usage note 3 for information about on setting the Aiocb fields.
The BPXYAIO macro (see BPXYAIO — Map asyncio parameter list) maps the Aiocb.
When the I/O completes, the return value, return code, and reason code of the requested function are returned in the Aiocb, and the application is notified. See usage note 2 for more information about asynchronous input/output.
When the I/O function itself is rejected immediately, the return code and reason code are specific to that function. They are documented with the description of the regular version of the function.
Return_code | Explanation |
---|---|
EAGAIN | One of the following occurred:
|
EALREADY | The Aiocb has already been canceled. |
EBADF | The AioFd field does not contain a valid descriptor or the descriptor of a socket. The following reason codes can accompany the return code: JRFileDesNotInUse, JRFileNotOpen. |
EFAULT | A supplied data area cannot be referenced. |
EINVAL | A parameter is not valid. For example, AioBuffSize is negative, or AioCmd or AioNotifyType are unsupported values. The following reason codes can accompany the return code: JrAsyncBadAiocbLen, JrAsyncBadOffset, JrAsyncBadNotifyType, JrAsyncBadMsgHdrLen, JrAsyncBadSockAddr, JrAsyncBadCmd. |
EIO | There was a network or transport failure. |
EMVSINITIAL | Support for unauthorized user exits failed to initialize. |
ENOSYS | The socket transport or physical file system does not support asynchronous I/O. Possible value: JrAsyncOpNotSupp. |
EOPNOTSUP | If the return code is JrMsgFlagInvalidFlag, the TCPIP stack does not support the specified AioPosixFlags value. If the return code is JrAsyncAnr, a previous accept() operation was processed on this server socket, and because of this the use of asynchronous accept_and_receive is not supported. |
EPERM | The caller is not authorized. Consult Reason_code to determine the exact reason the error occurred. If the return code is JrAsyncAuthErr, one of the following flags was set by an unauthorized caller: AioCallB4, AioUseUserKey, or AioCommBuff. |
Refer also to the regular versions of the various functions for errors that might be detected before the system schedules the request,or if the request was processed asynchronously (AioSync was specified).
The name of a fullword in which the asyncio service stores the reason code. The asyncio service returns Reason_code only if Return_value is -1. Reason_code further qualifies the Return_code value.
The following reason codes may be reported: JrAsyncAuthErr, JrAsyncBadAiocbLen, JrAsyncBadCmd, JrAsyncBadMsgHdrLen, JrAsyncBadNotifyType, JrAsyncBadOffset, JrAsyncBadSigNo, JrAsyncBadSockAddr, JrAsyncExitModeTCB, JrAsyncOpNotSupp, JrAsyncSigKey0Err, JrReadUserStorageFailed, JrWriteUserStorageFailed, JrSyscallAbend, JrMsgInvalidFlag, JrAsyncANR.
The Aiocb and any areas pointed to from the Aiocb, such as a receive buffer, must remain valid until the I/O has completed.
Only one type of notification is issued.
If no notification is requested, the application can check the AioRc field periodically until it changes from EINPROGRESS.
The asyncio service supports AF_INET and AF_INET6 sockets; it cannot be used with AF_UNIX sockets.
For details on their semantics and returned information, refer to the descriptions of the regular versions of these functions.
In 64-bit mode, AioBuffPtr is a doubleword pointer field, and is at a different offset within the Aiocb.
The sockaddr structure itself is supplied to the sendto and connect functions and returned by the recvfrom, accept_and_recv, and accept functions.
In 64-bit mode, AioSockAddrPtr is a doubleword pointer field, and is at a different offset within the Aiocb.
This field is supplied to all functions that use AioSockAddrPtr. It is updated with the returned sockaddr length by the recvfrom, accept, and accept_and_recv functions. The following functions allow a value of 0 to be specified, indicating that no sockaddr structure is to be returned: Aio#Accept, Aio#ANR and Aio#Connect.
Default: Aio#Posix.
For non-authorized callers the exit is always run on the caller's TCB. If the caller's TCB ends before the I/O completes, the system does not run the exit.
In 64-bit mode, SigEvent is a larger structure with several doubleword pointer fields; consequently, AioSigEvent is larger and at a different offset within the Aiocb.
Note: The SO_RCVTIMEO socket option can be used to achieve a timeout function for asynchronous receive type operations. For more information see the setsockopt() function in z/OS XL C/C++ Runtime Library Reference.
If the request completes successfully and immediately, the Return_Value from asyncio is 1. The system returns the results of the function itself in the Aiocb. In this case there is no I/O completion notification.
On an asynchronous read (or on accept_and_recv) , if data has already arrived, this option avoids the extra overhead of scheduling the SRB and performing the notification. You must code the program to handle the received data in two places: after the call to asyncio and after the notification.
For the best performance, you should always set AioOk2CompImd and be able to handle I/O completion at the point of the call.
Default: Off, or it is not all right to complete immediately. The system issues the I/O completion notification.
If the request is successful, the Return_value from asyncio is 1. The system returns the results of the function itself in the Aiocb. There is no I/O completion notification.
This option provides equivalence with the regular versions of the functions. It is useful for synchronous operations that must be cancelable, for operations whose waits should be limited by AioTimeOut, and for calling the select() function with the much more efficient poll() interface.
Default: Off, or asynchronous.
Default: Off, or do not cancel the I/O for any type of I/O complete notification other than TCB Exit. For TCB Exits, the exit cannot be run after the TCB terminates, so the I/O will be canceled.
Default: Off, or wait.
Default: Off, or issue the notifications.
Default: Off, or do not call the exit for preprocessing.
Default: Off, or use the caller's key for all storage references.
Default: Off, or the buffers reside in the caller's address space.
Default: Off, or use task-level security.
These fields are meaningful only after a successfully scheduled asynchronous request has completed, or when the asyncio service has a Return_value of 1.
The AioRc field is set to EINPROGRESS when a request is successfully scheduled. This value is changed to reflect the final results of the operation when the I/O completes.
The AioRc field is set to ETIMEDOUT for any function that times out because the AioTimeOut field is used.
The AioRc field is set to ECANCELLED for a request that is subsequently canceled. See usage note 13 for more information about canceling operations.
Callers of BPX1AIO (BPX4AIO) are considered authorized if the program is running in supervisor state or a system key, or if the program is APF-authorized.
There are restrictions on the use of exits. See this topic for more information.
The program should be designed to respond to the message queue in a timely manner so that waiting is avoided. These messages are sent from a system SRB, and waiting will tie up this critical resource and impact overall performance. Using small messages and a large queue can also help avoid waiting. If IPC_NOWAIT is specified and the queue fills up, or there is any other error in trying to send the message, the message will be lost. The system SRB will issue an EC6 abend with reason code FsAioMsgQError. The dump or logrec record produced will contain the return and reason codes from the internal call to BPX1QSN msgsnd() and potentially other diagnostic information about the problem.
The length of the message text is limited to 240 bytes.
The exit is called in the AMODE of the caller, AMODE 31 for BPX1AIO and AMODE 64 for BPX4AIO.
The exit is passed the original Aiocb to correlate this completion with the original request. The Aiocb contains an application area (AioExitData) that can be used to communicate with the exit. Note that since the application allocates the Aiocb in the first place, the areas before and after the control block are also available for related use. The Aiocb can be embedded in a larger application control block that can easily be reached from the Aiocb.
The exit is usually called to process received data, or free the storage that has been tied up with this request. At this point, the Aiocb contains the final return value, return code, and reason code of the function.
When a request has been canceled, the AioRv field is -1, and the AioRc field is set to ECANCELED. See usage note 13 for more information about canceling operations.
Because the exit program is running on an SRB, the rules for SRB-mode callers must be followed if the exit makes any calls to z/OS UNIX functions. In particular, register 2 must be set before a call, to identify the process to which the exit belongs. See Callable services available to SRB mode routines for details. Note, though, that the discussion on recovery for user SRBs is not relevant, because the exit is running on a z/OS UNIX SRB.
The AioExitModeTCB flag can be used to run the exit on the original TCB rather than on the system SRB. In this case the restrictions that are listed for Unauthorized Exits apply. The exit is entered in the key of the first caller of BPX1AIO (BPX4AIO) in this process. This key cannot be changed.
The exit is free to do whatever is supported within the environment from which it is called. It may issue another call to asyncio.
Note that you cannot use deferred allocation with AioOk2CompImd.
When the preprocessing exit is called, the AioRv value usually contains the amount of data that is available, up to the requested amount. You can allocate smaller buffers when they will be sufficient. You should be prepared for cases in which AioRv is zero, when you should allocate buffers for the original requested amount. The actual amount of data that is received is returned in AioRv on the I/O completion call to the exit.
The preprocessing call is only made when the operation has, up to this point, been successful. The preprocessing call is in addition to, not a replacement of, the call that is made after the I/O completes. The exit can use the AioExitData area to record its entry, and thus distinguish between the first and second calls during a successful operation. If AioRv is -1, this is the only call that is made to the exit.
The preprocessing exit can change the following Aiocb fields to affect subsequent processing: AioBuffPtr, AioBuffAlet, AioExitPtr, and AioECBPtr. You may not change the function.
SRB-mode routines should not call asyncio after it has entered process termination. See Callable services available to SRB mode routines.
Operation | Environment |
---|---|
Authorization: | Same as the caller of asyncio |
Dispatchable unit mode: | SRB or TCB |
Cross memory mode: | PASN = HASN |
AMODE: | Same as the caller of asyncio |
ASC mode: | Primary mode |
Interrupt status: | Enabled for interrupts |
Locks: | Unlocked |
Control parameters: | All parameters are addressable in the primary address space in key 0 storage. |
For authorized exits on the SRB, the work area is in key 0. For unauthorized exits, or authorized exits running on the TCB, it is in the key of the caller of asyncio.
No return of status information is defined for the exit program.
Your program does not have to worry about timing or serialization with regard to the Aiocb that is being canceled. If that request has already finished, this attempt to cancel it will be ignored.
Cancel releases any blocked requests from their waits, and drives through the I/O completion notifications as it does for a failed request. The original AioRc is set to ECANCELED. Any requests that are not currently blocked are allowed to complete normally. If they attempt to enter a blocked wait they are failed with ECANCELED. Exits that are about to be called are still called normally, and those that are running are not interrupted. Aio#Cancel only "cancels" blocked requests, causing them to fail with ECANCELED.
Synchronous requests (those with AioSync) are also broken out of their blocking waits. They are returned with an AioRc of ECANCELED.
Usually the Aio#Cancel function waits until all I/O completion notifications have finished before asyncio returns to the caller. When asyncio returns, all exits have run, ECBs have been posted, and signals have been sent. The system is finished with the original request Aiocbs and buffers, and they can be freed by the application, subject to its own design. Note that for ECB and signal notifications, there is no coordination with the waiter or signal receiver, so there may still be application code running that is dealing with the request that has just been canceled. Because of timing, you can never tell which requests will finish normally and which requests will be canceled. You know, however, that the system is finished with the request and that any I/O complete notifications that are to be issued have been issued when asyncio returns to your program.
Canceling all requests on a given descriptor does not stop new requests from being made, or otherwise affect the descriptor. The program can start afresh or close the descriptor, depending on why it issued the cancel.
The asynchronous features of asyncio do not apply to Aio#Cancel; that is, you cannot specify a signal, an exit program, or an ECB. AioTimeOut does not apply to Aio#Cancel.
Cancel succeeds regardless of whether any outstanding requests have been found to cancel.
An individual request can be canceled only once. Subsequent attempts to explicitly cancel the same request fail with EALREADY.
Aio#Cancel cannot be used to cancel any operations other than those that are started with asyncio. You cannot cancel a read(), for example.
A cancel operation itself is not cancelable.
Closing a descriptor deletes all requests that are still cancelable on that descriptor. I/O completion notifications are not issued for these requests. If you need exits to be run or ECBs to be posted, you must issue cancel for the descriptor before you issue close for the descriptor.
In most cases, close() will flush out and wait for requests that are still in progress to be deleted. However, it cannot wait for requests that are already in the I/O complete exit programs; or that are just about to call these exits, post the I/O complete ECB, or send the I/O complete signal. Consequently, application code related to asyncio requests on the just-closed descriptor may still be in progress when the close() function returns.
Descriptors that are part of an Aio#SelPoll request are removed from that operation. The request remains outstanding, and may complete as a result of activity on one of the other descriptors or when it times out. If all the descriptors for a particular SelPoll happen to be closed, no special action is taken; the request either times out or hangs forever.
Not all asynchronous operations support being called to start another I/O before the prior I/O has completed on that same socket. First of all, and most important, each call must have its own Aiocb and buffer or data areas; otherwise a serious and immediate error occurs for all of the operations, and the results are very unpredictable if two operations are using the same areas. In general, starting two or more asynchronous operations on a single socket is analogous to having two or more threads calling the regular synchronous versions of these operations at the same time, and the results are pretty much the same.
Aio#Accept and Aio#ANR may be called more than once. Each inbound connection request will complete a distinct call.
Aio#Connect: Stream (TCP) sockets may not be connected more than once. It does not make sense to connect UDP sockets several times simultaneously, because each connection replaces the previous one, and results will be unpredictable. The results of issuing requests that depend on the connection, such as Aio#Write, before the connection has completed are unpredictable.
Aio#Read, Aio#ReadV, Aio#Recv, Aio#RecvMsg, Aio#RecvFrom: For stream (TCP) sockets, the receive-type operations should not be called more than once before each call completes, as the results are unpredictable. The main reason for this is that the arrival of any data from the network can start the completion of one of these requests while the actual data movement occurs later, and so the data on the stream can be received by different threads out of order.
Aio#Write, Aio#WriteV, Aio#Send, Aio#SendTo, Aio#SendMsg: For stream (TCP) sockets, the send-type operations should not be called more than once before each call completes. Data may be transmitted on the network out of order, and, in general, results are unpredictable. For datagram (UDP) sockets, the send-type operations may be called more than once, because each distinct call defines a single datagram, and there is no implied order of arrival in UDP for these datagrams. Beware of sending too much data, though. If there is network congestion, or the receiver is slow, you can tie up a large amount of system storage with uncontrolled asynchronous sends, and eventually the BPX1AIO calls will start to fail with ENOBUFS.
Aio#SelPoll may be called more than once, but be aware that any one event will complete all the calls at the same time.
Aio#Cancel is not an asynchronous operation.
A socket must not be set to nonblocking state if you want I/O completion to wait for data.
If the socket is in nonblocking state and there is no data available, either the asyncio request has its I/O completion driven very quickly with an AioRc of EWOULDBLOCK, or the asyncio call fails with a Return_code of EWOULDBLOCK.
Note that Aio#ANR does not support nonblocking I/O.
Signals do not interrupt asynchronous operations unless they lead to the termination of the caller's process.
The entire PollFD array must consistently use only one type of bit. You cannot use select and poll bits for the same file descriptor, nor can you use select bits for one descriptor and poll bits for another. For the sake of performance, the input array is not checked to enforce this rule, and results are unpredictable if the rule is broken. The first occurrence of select bits that are turned on causes the operation to be a select() rather than a poll().
The AioTimeOut field can be used to specify a timeout value for the operation.
Aio#SelPoll can only be used with socket descriptors.
Aio#SelPoll operations cannot be canceled by descriptor; the specific aiocb must be canceled.
For example, doing Aio#Read for each of five sockets is much faster and more efficient than doing one Aio#SelPoll for that same set of sockets. This is because when an Aio#Read completes for one socket you have the data; the other sockets are unaffected and remain ready for inbound data. On the next Aio#Read only that one socket has to be readied again. When Aio#SelPoll completes for any socket, all the others are taken out of their prepared state. You still have to issue another call to actually get the data. On the next Aio#SelPoll all the sockets must be "put back" into their prepared state again.
Asynchronous I/O is similar to the select() and poll() functions in that you can wait for data from many different descriptors at the same time. Asynchronous I/O, though, is much faster and much more efficient for large numbers of descriptors. With the asyncio service you also have control over when you wait for the next event.
ALETS are generally usable only for synchronous requests (AioSync), with the exception of recvmsg/sendmsg. A preprocessing exit (AioCallB4) could update the SRB it is running on with an ALET for a data space, but this would add too many instructions to the operation to be practical for the general read or write. You could, however, consider using a Common Area Data Space (CADS).
The asyncio service supports AF_INET and AF_INET6 sockets; it cannot be used with AF_UNIX sockets.
For an example that uses this callable service, see BPX1AIO (asyncio) example.