OSI_Operations are provided to the PFS to wait for internal events
and to post the waiting thread when the event occurs.
Three important reasons for using the OSI wait and post services
rather than native MVS™ WAIT and
POST are:
- The OSI services allow signals to interrupt a wait.
- Users are not left hanging if z/OS UNIX or the PFS
is stopped.
- The PFS is protected from any system integrity exposures that
might result from the cross-memory post operation.
There are two kinds of wait, distinguished by whether signals are
enabled during the wait:
When a signal-enabled wait is entered, all serialization that was
obtained by the LFS is dropped before the wait and reobtained after
it. This means that other operations may intrude on an otherwise exclusive
operation. The PFS must take this into account if it uses signal-enabled
waits. This does not mean that two exclusive operations will actually be
running in the PFS for the same vnode-inode at the same time, but
that a second operation may run while the first is blocked. When
the first is resumed there may have been state changes made by the
second. For writes on stream sockets, the default socket option of
exclusive write will prevent the dropping of LFS serialization during
single-enabled waits.
The WAITX option also allows LFS serialization to be dropped around
the wait, independent of whether signals are enabled. See the LFS-PFS control block serialization for details on LFS serialization.
As a consequence of dropping LFS serialization, it is possible
for a file system to be unmounted, with the IMMEDIATE or FORCE operands,
while a task is waiting. If this happens, the wait service returns
with an OSI_UNMOUNTED return code when it is posted, and the PFS must
cancel the rest of the operation and return to the LFS with some care. Because
it is expected that vfs_umount will have cleaned up all file-system-related
resources, the current operation may have to avoid references to internal
file system structures that are freed by vfs_umount.
Waits that are signal-enabled or that request the LFS to drop its
serialization cannot be used on some vnode and VFS operations. The
implementation notes for those operations state this.
The OSI sleep and wakeup functions are similar to wait and post,
with these advantages:
- Osi_sleep
- Does not require a separate setup call
- Associates a Resource_id and Pfs_id with the sleeping thread
- Osi_wakeup
- Wakes up all threads that match Resource_id and Pfs_id
Implementation details: The PFS implementation for waiting
and posting involves the steps described in this section. There are
two threads involved: the waiting thread and the posting thread.
- The waiting thread is running on behalf of some VFS or vnode operation
when it must wait for an event to occur. It calls osi_wait to set
up for the wait, performs internal coordination to schedule the eventual
wakeup, and calls osi_wait again to actually suspend the thread.
- The posting thread may be an independent PFS task, or it may be
running on behalf of some other user's VFS or vnode operation. It
determines that a thread is waiting for the resource it is dealing
with, and calls osi_post to wake that thread up.
- When the waiting thread wakes up, it checks the return code from
osi_wait and reacts accordingly.
This table lists the PFS implementation
for the waiting thread.Waiting thread |
Posting thread |
---|
- Determine that a wait is necessary.
osi_wait(OSI_SETUPSIG, OSI, RC)
- Create an internal wait structure that is used by the posting
thread to recognize that the waiting thread is waiting.
- Save the osi_token in this structure.
- Chain the wait structure where the posting thread will find it.
osi_wait(OSI_SUSPEND, OSI, RC)
|
(None) |
(None) |
|
- Select on return code:
- When (OSI_POSTED): proceed with what you were going to do.
- When (OSI_SIGNALRCV): a signal has arrived (when using SETUPSIG
rather than SETUP). Back out of this operation and return EINTR.
- Otherwise: an abnormal end or unexpected error occurred. Back
out of this operation and return EMVSERR.
- End
|
(None) |
Note: - This example assumes that the PFS has its own serialization around
the chaining and unchaining of the wait structure.
- A variation of the steps in this table would be to unchain and
free the wait structure on the waiting thread. In this case, the
posting thread marks the structure as "posted" so that another
event occurrence cannot result in the same structure's being used
again. Recovery is more complicated with this approach, though.
- One also has to consider abnormal ends while waiting—for instance,
the user might be canceled. In that case, control does not return
to the code after the osi_wait. If the PFS supports vn_recovery, or
has an ESTAE or FRR active, it gets control there and the situation
can be handled as when a signal is received.
- For abnormal ends and any return code other than OSI_POSTED, additional
serialization between the waiting thread and the posting thread is
necessary. In these cases the waiting thread is ending before, or
even while, the posting thread is trying to wake it up.
This is
why it is important to save a copy of the osi_token from the waiting
thread's OSI, rather than just the address of the waiting thread's OSI.
The waiting thread's OSI storage could be gone by the time the posting
thread tries to refer to it.
- Another consideration is user address space end-of-memory, which
abnormally terminates the waiting thread without activating any ESTAE
or FRR. In this case, the LFS uses the OSI recovery token to invoke
vfs_recovery, which gives the PFS a chance to clean up.