For anyone interested.
THIS IS AN EXAMPLE OF A THE COMPLETE PROCESS USED TO ADD A NEW
DISPATCHABLE UNIT (DU) ENTRY TO A QUEUE OF ACTIVE DUS. FOR SIMPLICITY,
A DU IS EQUIVALENT TO A TASK.
THIS QUEUE CAN BE SIMULTANEOUSLY SEARCHED, NEW DUS ADDED AND
TERMINATING DUS DELETED. ADDS AND DELETES ARE DONE VERY INFREQUENTLY
(COMPARED TO SEARCHES) AND ONLY BY THE DU ITSELF. DU ENTRIES FOR OTHER
DUS ARE NEVER ADDED OR DELETED FROM THE QUEUE BY ANOTHER DU.
THE ADD AND DELETE RULE IS VERY IMPORTANT BECAUSE ONLY THE DU CAN OWN
ITS ENTRY THUS INSURING THAT THE OWNER (CODE THAT REFERENCES THE ENTRY)
IS THE ONLY CODE THAT CAN ADD OR DELETE THAT ENTRY. REGARDLESS OF WHAT
TYPE OF QUEUE YOU ARE SERIALIZING WITH PLO, COMMON SENSE MUST APPLY. IF
DELETES WERE ALLOWED WITH AN ENTRY THAT COULD STILL BE REFERENCED,
THERE WILL BE UNDESIRABLE RESULTS. IN THOSE CASES. SUCH AS WORK QUEUE,
THE ENTRY SHOULD BE DELETED FROM THE ACTIVE CHAIN OR A MECHANISM BE
PROVIDED TO DEFINE OWNERSHIP THUS PREVENTING DELETES FROM "OWNED"
ENTRIES.
THE QUEUE POINTERS ARE KEPT IN COMMON STORAGE BUT NOT IN CSA. THIS CODE
USES EITHER SHARED OR COMMON MEMORY OBJECTS. WHEN THIS CODE EXECUTES,
IT IS GUARANTEED THAT THE MEMORY OBJECT IS AVAILABLE. THE FOLLOWING
STRUCTURE IS ALWAYS USED FOR ALL QUEUES LIKE THIS ONE:
QUEUE ...
QUEUE__START DS D START OF CELLS USED FOR QUEUE
* WHEN THE QUEUE IS INITIALIZED, THE FREE CHAIN IS 0 TO AVOID
* ADDING FREE ELEMNTS TO THE WORKING SET OF THIS CODE. INSTAED, THE
* HWM=START AND AVAILQ IS 0. CODE SHOW HOW THIS IS MANAGED
*
QUEUE_HWM DS D CURRENT HIGH WATER MARK OF CELLS
QUEUE_END DS D END OF CELLS USED FOR THIS QUEUE
*
QUEUE_HEAD DS D CURRENT ACTIVRE HEAD
QUEUE_TAIL DS D CURRENT ACTIVE TAIL
QUEUE_COUNTERS DS 0D LOCK WORD AND COUNTERS
QUEUE_CHANGES DS A HIGH WORD IS CHANGES
QUEUE_ENTRIES DS A LOW WORD IS ENTRIES IN CHAIN
*
QUEUE_AVAILQ DS D FREE CHAIN IS SINGLY LINKED
QUEUE_AVCOUNTERS DS 0D LOCK WORD AND COUNTERS FOR FREE
QUEUE_AVCHANGES DS A HIGH WORD IS CHANGES
QUEUE_AVENTRIES DS A LOW WORD IS ENTRIES IN CHAIN
...
THE COUNTER IS A DOUBLEWORD CONSISTING OF 2 FULLWORD POINTERS. THE
COUNTER IS ALWAYS USED AS THE PLO LOCK WORD AND IS ALWAYS LOADED WITH A
LG (LOAD GRANDE). THE CHANGE COUNT IS ALWAYS THE HIGH WORD AND
INCREMENT WITH INCCHANGES CONSTANT IN THE PROGRAM CONSTANTS. THE ENTRY
COUNT IS ALWAYS THE LOW WORD AND INCREMENTED WITH AHI WHICH ONLY
AFFECTS THE LOW WORD. I DON'T USE ANY OF THE SPECIAL HIGH WORD INST OR
IMMEDIATE INSTR BECAUSE THEY ARE A FACILITY SO I KEEP THE CODE AT A
FAIRLY OLD FACILITY LEVEL
* CONSTANT IN PROGRAM
DS 0D
INCCHANGES DC F'1',F'0'
THIS IS A SAMPLE ELEMENT LAYOUT. ESSENTIALLY, I ALWAYS KEEP THE PREV
AND NEXT POINTERS AS THE FIRST DOUBLE WORDS IN AN ELEMENT. THE
REMAINING AREAS OF THE ELEMENT HAVE NO BEARING ON THIS PROCESS.
ELEMENT ...
ELEMENT_PTRS DS 0XL16
ELEMENT_PREV DS D
ELEMENT_NEXT DS D
ELEMENT_DATA DS ...
...
ELEMENT_SIZE EQU *-ELEMENT_PREV
ALL THE CODE IS REENTRANT AND THE FOLOWING WORK AREAS ARE REFERENCED:
* IN WORKING STORAGE
PLOWORK DS XL144 NEED FOR COMPARE AND SWAP AND STORES
SEARCH_PTR DS D INITIALIZED TO 0 FOR START OF SEARCH
* SET TO 0 FOR ADD OR ENTRY TO BE DELETED
SEARCH_COUNTER DS D SET BY CALLER TO CURRENT COUNTER VALUE
SO HERE IS THE SAMPLE EXTRACTED FROM A WORKING ALGORITHM. I CAN'T PUT
THE ORIGINAL CODE IN THIS EXAMPLE FOR MANY REASONS. BUT I CAREFULLY
EXTRACTED FROM A WORKING ALGORIGHM AND MADE IT INTO THIS EXAMPLE.
THIS EXAMPLE SHOWS COMPARE AND LOAD, COMPARE DOUBLE AND SWAP AND
SWAP AND DOUBLE STORE. IF YOU'RE NOT FAMILIAR WITH PLO TYPE
SERIALIZATIONS, IT MAY TAKE A WHILE TO DIGEST ALL OF THIS.
I DON'T USE THE PLO MNEMONICS. I'VE BEEN CODING IT A VERY LONG TIME AND
I JUST CODE IT.
* START OF A SERVICE CALL FROM A DU, SEE IF ITS ALREADY BEEN ADDED
* KEY IS ASCB ADDRESS AND DU (TCB). THE ADD ONLY RUNS IN THE DU BEING
* ADDED
********************************************************************
* PRIME THE SEARCH ARGUMENTS. SEARCH_VALUE HAS THE QUEUE_COUNTERS AT
* START OF THE SEARCH AND THEY ARE NOT CHANGED UNLESS THE PROCESS HAS
* TO BE REDRIVEN
SEARCH_REDRIVE DS 0H
XC SEARCH_PTR,SEARCH_PTR PRIME TO START AT HEAD
MVC SEARCH_COUNTER,QUEUE_COUNTERS GET STARTING COUNTER
*********************************************************************
* SEARCH QUEUE FOR REQUIRED ELEMENT
SEARCH_LOOP DS 0H
LA R1,QUEUE_COUNTERS LOCK WORD
LG R14,SEARCH_COUNTER LOAD CURRENT COUNTER
***********************************************************************
* LOAD CURRENT PTR TO DETERMINE WHERE WE ARE IN THE QUEUE CHAIN
LG R2,SEARCH_PTR LOAD LAST POINTER
LTGR R2,R2 FIRST TIME?
JH SEARCH_NEXT NO - GET NEXT
***********************************************************************
* DO PLO LCOMPARE AND LOAD FOR HEAD
LA R2,QUEUE_HEAD POINT TO HEAD OF CHAIN
LA R0,2 COMPARE AND LOAD FUNCTION 64 BIT
PLO R14,0(R1),R3,0(R2) IF COUNTER SAME, R3--> QUEUE HEAD
JZ SEARCH_CHECK GOT HEAD POINTER
J SEARCH_REDRIVE COUNTER CHANGED - REDRIVE
***********************************************************************
* DO PLO COMPARE AND LOAD FOR NEXT
SEARCH_NEXT DS 0H
LA R0,2 COMPARE AND LOAD FUNCTION 64 BIT
PLO R14,0(R1),R3,ELEMENT_NEXT-ELEMENT(R2)
* IF COUNTER SAME, R3--> NEXT
JNZ SEARCH_REDRIVE COUNTER CHANGED - REDRIVE
***********************************************************************
* SEE IF WE'VE REACHED THE END OF CHAIN
SEARCH_CHECK DS 0H
LTGR R3,R3 GOT IT?
JZ ADDFROMFREE NO - HAVE TO ADD IT
***********************************************************************
* SEE IF THIS THE DESIRED ELEMENT
PERFORM_SEARCHCOMP DS 0H
STG R3,SEARCH_PTR SAVE FOR NEXT PASS
... COMPARE ELEMENT AND GO TO FOUND IF EQUAL
J SEARCH_LOOP PROCESS NEXT ELEMENT
***********************************************************************
* IF NOT FOUND, ADD A NEW ELEMENT. WE DON'T CHANGE THE COUNTER IN CASE
* ANOTHER DU HAS ADDED AN ELEMENT FORCING A REDRIVE
*
* FIRST GET AN AVALIABLE SLOT. TO MINIMIZE WORKING SET, WE USE A FREE
* CHAIN AND A HWM OF SLOTS. THIS WAY WE DON'T HAVE TO CHAIN ALL THE
* SLOTS ONTO A FREE CHAIN DRIVING UP WORKING SET. DELETE WILL ADD
* TO FREE CHAIN AS SLOTS ARE DELETED
*
ADDFROMFREE DS 0H
LG R14,QUEUE_AVCOUNTERS GET COUNTER FOR AVAILABLE QUEUE
LGR R15,R14 COPY COUNTER TO AJUST
LA R1,QUEUE_AVCOUNTERS COUNTER IS LOCK WORD
LG R2,QUEUE_AVAILQ GET CURRENT FREE ELEMENT HEAD
LTGR R2,R2 GOT ONE?
JNH ADDFROMHWM NO - ADJUST HIGH WATER MARK
ALG R15,INCCHANGES INCR CHANGES BY 1 HIGH WORD
AHI R15,-1 DECR ELEMENTS IN FREE BY 1
LG R3,ELEMENT_NEXT-ELEMENT(,R2) GET NEXT IN FREE
LA R0,10 PLO DOUBLE COMPARE AND SWAP
PLO R14,0(R1),R2,QUEUE_AVAILQ GET FREE ELEMENT ELEMENT
JNZ ADDFROMFREE
J ADDNEW
********************************************************************
* INCREMENT HWM FOR NEW ELEMENT
ADDFROMHWM DS 0H
LG R2,QUEUE_HWM GET CURRENT HIGH WATER MARK
LA R3,ELEMENT_SIZE(,R3) INCR HWM
CLG R3,QUEUE_END REACHED ED OF SLOTS?
JH WEREOUTOFSPACE WE'RE OUT OF SPACE
ALG R15,INCCHANGES INCREMENT CHANGE COUNT
* ENTRY COUNT DOESN'T CHANGE
LA R0,10 PLO DOUBLE COMPARE AND SWAP
PLO R14,0(R1),R2,QUEUE_HWM GET FROM HWM
JNZ ADDFROMFREE
***********************************************************************
* NOW UPDATE THE ELEMENT AND ADD TO QUEUE
* R2 - HAS SOT TO BUILD ELEMENT
PERFORM_ADDNEW DS 0H
LGR R3,R2 COPY SLOT ADDRESS
STG R3,SEARCH_PTR
USING ELEMENT,R3
XC ELEMENT_PTRS,ELEMENT_PTRS
... BUILD ELEMENT
**********************************************************************
* ALWAYS ADD TO START OF QUEUE
XC PLOWORK+56(56),PLOWORK+56
LG R14,SEARCH_COUNTER ORIGINAL COUNTER AT START
LGR R15,R14 COPY COUNTER
ALG R15,INCCHANGES INCREMENT CHANGE COUNT
AHI R15,1 INCREMENT NUMBER OF ELEMENTS
*
STG R3,PLOWORK+56 NEW HEAD VAUE - OPER 3
LA R0,QUEUE_HEAD ADDRESS OF HEAD
STG R0,PLOWORK+72 OPERAND 4 FOR DOUBLE STORE
*
STG R3,PLOWORK+88 NEW HEAD'S PREV - OPER 5
LG R1,QUEUE_HEAD CURRENT HEAD
STG R1,ELEMENT_NEXT SET NEXT IN NEW ELEMENT
LA R1,ELEMENT_PREV-ELEMENT(,R1)
STG R1,PLOWORK+104 OPERAND 6 FOR DOUBLE STORE
LA R1,QUEUE_COUNTERS SAME LOCK AS SEARCH
LA R0,18 COMPARE AND SWAP AND DOUBLE STORE 64 BIT
PLO R14,0(R1),R14,PLOWORK
JZ FOUND
**********************************************************************
* SOMEONE ELSE HAS UPDATED THE CHAIN. WE NEED TO RETURN THE BUILT
* ELEMENT TO THE FREE CHAIN AND REDRIVE. REDRIVES ARE VERY INFREQUENT
ADDTOFREE DS 0H
XC ELEMENT_PTRS,ELEMENT_PTRS
LG R14,QUEUE_AVCOUNTERS GET COUNTER FOR AVAILABLE QUEUE
LGR R15,R14 COPY COUNTER TO AJUST
LA R1,QUEUE_AVCOUNTERS COUNTER IS LOCK WORD
LG R2,QUEUE_AVAILQ GET CURRENT FREE ELEMENT HEAD
STG R2,ELEMENT_NEXT SET CURR HEAD AS NEXT
ALG R15,INCCHANGES INCR CHANGES BY 1 HIGH WORD
AHI R15,1 INCR ELEMENTS IN FREE BY 1
LA R0,10 PLO DOUBLE COMPARE AND SWAP
PLO R14,0(R1),R2,QUEUE_AVAILQ ADD TO FREE ELEMENTS
JNZ ADDTOFREE
J SEARCH_REDRIVE
**********************************************************************
* COME HERE IF ELEMENT FOUND - PROCESS IS DONE
FOUND DS 0H
* R3 HAS FOUND ELEMENT
...
***********************************************************************
* ERROR ROUTINE FOR OUT OF SPACE
WEREOUTOFSPACE DS 0H
...
HOPEFULLY, I DIDN'T TRANSLATE SOMETHING INCORRECTLY OR MISTYPED IT BUT
THIS IS A WORKING ALGORITHM THAT GETS CALLED THE FIRST TIME ANY DU
REQUESTS ANY SERVICE FROM THIS SERVER. IT'S USED BY TERMINATION
TO INSURE ALL RESOURCES ARE RETURNED WHEN A DU ENDS.
-----Original Message-----
From: IBM Mainframe Discussion List [mailto:[email protected]] On
Behalf Of [email protected]
Sent: Saturday, November 09, 2013 1:48 PM
To: [email protected]
Subject: Serialization without Enque
I have been reading and following this thread sine PLO is not an instruction
I use every day.
It would be nice if someone would actually post some working code using a
PLO instruction, to illustrate how one would add an element to a queue and
remove an element from a queue.
Paul D'Angelo
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions, send email
to [email protected] with the message: INFO IBM-MAIN
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: INFO IBM-MAIN