[Info-vax] Returning data from Cobol AST routine.
Stephen Hoffman
seaohveh at hoffmanlabs.invalid
Tue Sep 21 17:33:56 EDT 2021
On 2021-09-21 21:06:42 +0000, Jan-Erik Sderholm said:
> Den 2021-09-21 kl. 18:45, skrev Stephen Hoffman:
>> On 2021-09-20 22:55:02 +0000, Jan-Erik Sderholm said:
>>
>>> The idea is to have an AST routine that will read from a mailbox when
>>> something is written to it. My idea was that the read of the mailbox
>>> would be using an AST to avoid polling the mailbox.
>>
>> In no particular order...
>>
>> Start with chapters 6 and 8 in the first VSI Programming Concepts
>> Manual. Memory sync and AST operations details.
>>
>> All data shared between mainline and AST must be atomic-accessed, or
>> must be protected by atomic operations, or some other locking.
>
> I thought of not re-queing the QIO until the current data had been
> processed. That way there will not be any new AST until the whole
> appliation is ready for that, right?
I prefer to have the AST requeue the $io_perform or $qio. Let the
mainline dequeue and process the arriving messages.
>
>> The AST can arrive between pretty much any two hardware instructions
>> within any code sequence, or is best assumed to arrive at the least
>> opportune moment. Including within an unaligned variable read, or
>> within a multi-part update operation such as an un-interlocked queue
>> update.
>>
>
> My thought was to only queue an QIO when I know the application is ready.
You're seemingly trying to create a sync design with async tools.
Enqueue the pending work onto the queue and $wake the mainline and let
it churn out dequeues and processing. The AST does is enqueue the
finished $io_perform or $qio onto the AST-to-mainline queue, tickle the
$wake for the mainline, deallocates a buffer from the free queue, and
re-queues the buffer and the $io_perform or $qio AST. This as this
style of async coding on OpenVMS best gets out of AST mode and back to
the mainline expeditiously.
if you want to do that style of sorta-kinda async coding that you seem
to be envisioning, queue the $io_perform or $qio and keep going on
whatever in the mainline, and then $synch on the event flag (EFN$C_ENF)
when the mainline has gotten as far as it can go without the completion.
>> Interlocked bitflags or interlocked queues are commonly used to avoid
>> these races. There are other ways too, though these interlocked
>> operations tend to be fast and fairly lightweight. These were VAX
>> hardware instructions, and are now available as C built-ins and as
>> LIBRTL calls. Calls to $SETAST can be used to brute-force block AST
>> activity.
>>
>> For cases processing async I/O such as this, an app design maintaining
>> a set of two or sometimes three queues is fairly common. The mainline
>> hibernates, if it doesn't have something to do. One queue pre-populated
>> at startup and used as a free list of data structures available for
>> use, one queue of data structures from mainline to AST, and one for
>> structures AST to mainline. The interlocked queues avoid issues with
>> variable tearing, and with race conditions. The structures can also
>> contain the IOSB, the data buffer, the interlocked queue headers, and
>> whatever other data is required.
>>
>> Make the number of buffers pre-allocated programmable, and add some
>> instrumentation for when the free list is exhausted. It's absolutely
>> possible to dynamically add some structures when the freel queue s
>> empty, at the cost of some added complexity.
>>
>> Use two unidirectional mailboxes whenever mailbox message traffic is
>> bidirectional. One reader, one or more writers, for each of the two
>> mailboxes. Don't try to multiplex a mailbox. That way leads to gnarly.
>>
>> Always have a scheduled timer AST or (locally preferable) have a
>> scheduled wakeup call operating in the background, triggering a routine
>> that processes the queues every ten or thirty or minute, on the off
>> chance an AST or event flag gets lost somewhere. This happens more
>> often than any of us would prefer, and the scheduled wakeup. This so
>> that the AST issues a $wake, and the mainline loops and does its
>> processing and eventually issues a $hiber when the work-pending queue
>> is empty. Once started, the mainline initializes the queues and queues
>> the ASTs, then hibernates. The ASTs arrive as the I/O completions
>> arrive, and each can trigger a wakeup call and can shuffle buffers
>> among the interlocked queues and can also re-queue the I/O operation
>> for the next I/O operation. And the scheduled wakeup call masks any
>> lost wakeup calls, at minimal cost. (Wakes are coalesced into one, and
>> I've worked with a few app designs where a wake was occasionally lost.)
>>
>> For a few of these app cases I've used global sections for app control,
>> sometimes lock manager doorbell locks, sometimes controlled activity
>> through signals, sometimes a management mailbox pair, and it's often
>> possible to pass management commands into the app through the mailbox.
>>
>
> Most of the above I do not understand. But keep it in mind if there is
> some scenario where it seems to fit in.
Like how OO changes perceptions/abstractions around how data and code
is packaged and accessed within an app, using ASTs is a different way
of thinking about program control.
See chapters 6 and 8 in the Programming Concepts manual for memory
considerations. I'd expect to get bit otherwise, and—having followed
the path you're on—what's biting will be hard to find.
While I'm thinking about it, add some embedded logging into the app,
particularly around the comms. Make sure it can be enabled dynamically,
if it's not defaulted to enabled.
>> Protect the mailboxes against unauthorized access correctly, and there
>> can be protocol design cases where looking at the PID of the message
>> sender can be necessary.
>
> All access to the mailbox (both "ends") are from our own code.
Yeah. I've heard that before. You still want to protect the mailboxes
against unauthorized access, etc. Even if it's just some sap having
gotten loose in production with a debug tool, or a wrong-tool-version.
>>
>> You will want to consider including some sort of a protocol version
>> within the mailbox message traffic too, as that can makes message
>> protocol upgrades a whole lot easier.
>
> Good idea.
>
>>
>> These app designs pretty quickly become state machines, too. It can be
>> easier to start out with interlocked queues and state machine than to
>> try to retrofit this. This having retrofit more than a few state
>> machines into apps that got way too gnarly.
>>
>> If there's any chance the other end of the connection is untrusted,
>> parsing gets vastly more difficult.
>
> All access to the mailbox (both "ends") are from our own code.
I once assumed that was the case, too.
>> COBOL will be more involved, as it doesn't do pointers at all well, and
>> the designs I tend to use are rather more dynamic.
>
> Good for you. Our application build environment is Cobol based.
You had stated that you had C, and that you wanted an async design. C
handles tasks such as async network communications and dynamic memory
allocation rather better than does COBOL. COBOL just doesn't do dynamic
memory allocation all that well, prior to 2002.
--
Pure Personal Opinion | HoffmanLabs LLC
More information about the Info-vax
mailing list