.TITLE LOCK .IDENT /17JA87/ ; ; File:[22,310]LOCK.MAC ; Author: Philip Hannay. 17-Jan-87. Derived from Pasutl LOCKER ; History: Philip Hannay. 17-Jan-87. Created. ; ; Phil Hannay 5-Jun-84 Modified UNLOCK procedure to wait 5 ticks after ; unlocking the file (setting the flag) before exiting. The reason for ; this is to give another program waiting for this file a chance to get ; in and lock the file. Otherwise, this caller can relock the file ; right away again if it desires and effectivly monopolize the file ; until it blocks for some other reason. Note that we use a WTSE for ; the mark time so that we will not checkpoint unless absolutely ; required. ; ; Last Edit: 19-JAN-1987 15:05:23 .rem | Function LOCK ( EFN:Event_Flag; TMO: integer): boolean; External; {*USER* LOCK a resource(s) associated with the global event flag EFN. If the resource is not available, continue trying for TMO seconds. The function LOCK returns a boolean value where TRUE is "resource locked for caller's use", and FALSE is "resource locked by another program and could not be locked for caller use within the TMO seconds" The LOCK function is used for interprogram coordination, permitting multiple programs to run and yet insure that only one among them can use a certain resource at a time. This function is useful for locking shared files, regions and ports in a system. The basic mechanism for signaling among programs is global flags. Both global and group global flags can be used. For all global flags that will be used, the lowest numbered flag in each DEC defined 16 flag group is reserved for use by this funtion for timeout handling. This means that if we used flags 43 and 44 for locking, then flag 33 is also used. If we use the group global group 65 thru 80, we can use any of the flag from 66 thru 80 for locking, but we cannot use flag 65, since this routine will use it. The function value returned is a boolean TRUE or FALSE. There is no other status. Any errors return the value of FALSE, giving little info on the type of error. For example, if you specify a flag out of range or one of the reserve "timeout flags", it will be an error, and a FALSE will be returned emulating a timeout. It is up to the caller to do validity checks if need be or to trace input values. Be sure group global flags are created before attempting to use them. If the group globals do not exist, a directive error will occur in the function, and the value of FALSE will be returned emulating a timeout. Note: This module uses a different locking scheme than normally used. A set flag denotes an unlocked file, region or port, while a clear flag denotes a locked file, region or port. This procedure enables us to use waits triggered by flag sets to make for instant response to a changed lock state while remaining inactive during the wait interval. This allows for the most efficient interactive file, region and port sharing possible by multiple programs. } {*WIZARD* The LOCK function sets up a WTLO wait for the specified resource associated flag EFN and the "timeout flag". The "timeout flag" is the lowest flag in the 16 flag group. It has been arbitrarily chosen as the lowest flag of a flag group. We want to wait for the "resource flag" to be set. At the same time, we don't want to wait forever, so we have to have a way to get going, so we use another flag and do a Wait Logical Or. We are constrained to use another flag within the flag group, so that is why we use the lowest one. When the wait is satisfied, but are still unable to clear the "resource flag", we cannot tell if we had a timeout or should wait longer. This is becuase the "timeout flag" is used by other programs also, and their timeouts might be happening and setting the "timeout flag". In other words, if the wait is satisfied, and yet we cannot get the "resource flag", then we know it was the "timeout flag" that satisfied the wait. However, the program does not know if it set the "timeout flag" or if another program set it. That is, we know it was a timeout, we just don't know who's timeout it was. To settle this timeout determination problem, we use an AST triggered by a marktime. Now we can use the AST to not only set the "timeout flag" to wake us up, but also to put a 1 in a register that we cleared before entering the wait. The 1 in the register will signal us that it was our AST and thus our timeout that set the "timeout flag". There is no provision to automatically reset a locked resource if the caller fails to unlock it (program error or abnormal end). If it is required, the caller should look at an outside method (watchdog program) that will unlock the resources automatically in the event of an error. Under normal circumstances, if programs are solid, and error messages are printed when timeouts occur, the user or tech can use the EFN program to evalute the state of a resouce flag and force the unlock (set flag). } | ; ; Assemble with PASMAC.MAC as prefix file. ; ; .ENABL LSB .MCALL CLEF$S .MCALL MRKT$S .MCALL ASTX$S .MCALL SETF$S .MCALL WTLO$S .MCALL CMKT$S FUNC LOCK, STAT, BOOLEAN PARAM EFN, CHAR PARAM TMO, INTEGER SAVE BEGIN MOVB EFN(SP),R0 ;MOVE EFN NUMBER TO R0 CMP R0,#33. ;CHECK TO SEE IF RESOURCE LOCK FLAG IS ;WITHIN THE CORRECT RANGE 33 THRU 96 BLT 19$ ;TIMEOUT IF FLAG IS LESS THAN 34 CMP R0,#96. ;CHECK THE UPPER LIMIT BGT 19$ ;EMULATE TIMEOUT IF FLAG GT 96 CMP R0,#57. ;CHECK TO SEE IF RESOURCE LOCK FLAG IS ;WITHIN RESERVE SYS RANGE 57 THRU 64 BLT 1$ ;BRANCH IF FLAG IS LESS THAN 57 CMP R0,#64. ;CHECK THE UPPER LIMIT BLE 19$ ;EMULATE TIMEOUT IF FLAG IN SYS RANGE 1$: CMP R0,#33. ;33 IS NOT A VALID FLAG FOR USE BEQ 19$ ;EMULATE TIMEOUT IF FLAG IS 33 CMP R0,#49. ;49 IS NOT A VALID FLAG FOR USE BEQ 19$ ;EMULATE TIMEOUT IF FLAG IS 49 CMP R0,#65. ;65 IS NOT A VALID FLAG FOR USE BEQ 19$ ;EMULATE TIMEOUT IF FLAG IS 65 CMP R0,#81. ;81 IS NOT A VALID FLAG FOR USE BEQ 19$ ;EMULATE TIMEOUT IF FLAG IS 81 ;VALID LOCK FLAG CLEF$S R0 ;TRY TO CLEAR (LOCK) RESOURCE FLAG CMP $DSW,#IS.SET ;CHECK RETURN STATUS OF CLEAR COMMAND BEQ 20$ ;BRANCH IF "WAS SET" - RESOURCE IS OURS ;NO BRANCH - "WAS CLR", RESOURCE HELD ;BY ANOTHER PROGRAM, SO WE SET UP A WAIT ;FIGURE OUT THE GROUP WE ARE IN MOV #81.,R1 ;ASSUME WE ARE IN GROUP 5, TMO FLAG 81 CMP R0,R1 ;SEE IF WE ARE IN GROUP 5 BGT 7$ ;BRANCH IF WE ARE IN GROUP 5 MOV #65.,R1 ;ASSUME WE ARE IN GROUP 4, TMO FLAG 65 CMP R0,R1 ;SEE IF WE ARE IN GROUP 4 BGT 7$ ;BRANCH IF WE ARE IN GROUP 4 MOV #49.,R1 ;ASSUME WE ARE IN GROUP 3, TMO FLAG 49 CMP R0,R1 ;SEE IF WE ARE IN GROUP 3 BGT 7$ ;BRANCH IF WE ARE IN GROUP 3 MOV #33.,R1 ;MUST BE GROUP 2, TMO FLAG 33 ;TMO FLAG IS IN R1, NOW CREATE MASK 7$: MOV R0,R3 ;R3 WILL BE A COUNTER MADE EQUAL TO SUB R1,R3 ;DIFFERENCE BETWEEN RESOURCE FLAG ;TIMEOUT FLAG CLR R2 ;WE WILL GENERATE AN "OR" MASK ;IN R2 FOR USE IN A WTLO DIRECTIVE SEC ;SET THE C BIT 5$: ROL R2 ;C BIT TO LOW BIT, HIGH BIT TO C BIT SOB R3,5$ ;LOOP UNTIL R3 BECOMES ZERO SEC ;SET THE C BIT AGAIN ROL R2 ;MOVE C BIT TO LOW BIT ;WE NOW HAVE A MASK IN R2 FOR OUR WAIT ;TO USE - THE TWO BITS CORRESSPONDING ;TO THE RESOURCE FLAG AND TMO FLAG ARE ;SET, AND ALL OTHERS ARE CLEAR CLEF$S R1 ;CLEAR THE TIMEOUT FLAG MOV TMO(SP),R4 ;TIME DELAY MAGNITUDE IN R4 (SECONDS) CLR R3 ;R3 IS THE TIMEOUT BOOLEAN SET BY AST ;IF SET AFTER WAIT, A TIMEOUT OCCURRED MRKT$S ,R4,#2,#PPLOCK ;WE SET UP A TIMEOUT AST TO PPLOCK CMP $DSW,#IS.SUC ;CHECK THE DIRECTIVE STATUS BNE 19$ ;EMULATE TIMEOUT IF UNABLE TO SETUP AST ; ; DUE TO SOME ODDITY IN THE WTLO DIRECTIVE, WE CANNOT DYNAMICALLY ; GENERATE THE GROUP NUMBER. (CANNOT USE MOV FORM). SINCE WE WANT ; TO BE ABLE TO PUT THIS IN A RO RESLIB, WE WILL GENERATE ALL 4 ; POSSIBLE DIRECTIVES. ; 6$: CMP R1,#49. ;SEE WHICH GROUP WE ARE IN BLT 2$ ;BRANCH IF IN GROUP 2 BEQ 3$ ;BRANCH IF IN GROUP 3 CMP R1,#81. ;GROUP 4 AND 5 ARE LEFT BLT 4$ ;BRANCH IF IN GROUP 4 ;GROUP 5 WTLO$S 5,R2 ;WAIT UNTIL LOCK FLAG OR TMO FLAG SET BCS 19$ ;EMULATE TIMEOUT ON DIRECTIVE ERROR BR 9$ ;GO AROUND GROUP 2 WTLO 4$: WTLO$S 4,R2 ;WAIT UNTIL LOCK FLAG OR TMO FLAG SET BCS 19$ ;EMULATE TIMEOUT ON DIRECTIVE ERROR BR 9$ ;GO AROUND GROUP 2 WTLO 3$: WTLO$S 3,R2 ;WAIT UNTIL LOCK FLAG OR TMO FLAG SET BCS 19$ ;EMULATE TIMEOUT ON DIRECTIVE ERROR BR 9$ ;GO AROUND GROUP 2 WTLO 2$: WTLO$S 2,R2 ;WAIT UNTIL LOCK FLAG OR TMO FLAG SET BCS 19$ ;EMULATE TIMEOUT ON DIRECTIVE ERROR 9$: CLEF$S R0 ;CHECK TO SEE IF RESOURCE AVAILABLE CMP $DSW,#IS.SET ;IT IS IF "WAS SET" IS RETURNED BEQ 20$ ;BRANCH IF RESOURCE IS NOW OURS ;NO RESOURCE, MAYBE OUR TIMEOUT WENT OFF TST R3 ;SEE IF THE TIMEOUT WOKE US UP BEQ 6$ ;BRANCH IF IT WAS NOT THE TIMEOUT YET 19$: CLRB STAT(SP) ;SET STATUS FALSE TO SHOW TIMEOUT OR ERR BR 21$ ;BRANCH AROUND SUCCESS PORTION 20$: MOVB #1,STAT(SP) ;SET STATUS TRUE TO SHOW RESOURCE OURS 21$: CMKT$S ;CANCEL ANY OUTSTANDING MARK TIMES ; ; ; HERE IS THE PPLOCK AST - SETS THE TIMEOUT BOOLEAN AND THE MASTER FLAG ; TO WAKE UP WAITING ROUTINE ; .PSECT PPLOCK,I ; PPLOCK: INC R3 ;SET THE TIMEOUT BOOLEAN (R3) MRKT$S ,#2,#2,#PPLOCK ;WE SET UP A SAFETY AST TO PPLOCK ;THIS IS BECAUSE IT IS POSSIBLE THAT ;SOMEONE ELSE COULD CLEAR THE MASTER ;JUST AFTER WE SET IT AND BEFORE WE ;POPPED OUT OF THE AST. THIS WILL ;INSURE THAT WE WON'T GET STUCK SETF$S R1 ;SET THE MASTER FLAG TO WAKE UP JOB TST (SP)+ ;POP THE EFN AST EXCESS OFF STACK ASTX$S ;EXIT THIS AST, RETURN TO MAIN MOV #5,R0 ;AST EXIT FAILURE, MARK R0 WITH AN ID EMT 1 ;BLOW UP THE PROGRAM ; ; END OF AST ; ; .PSECT ;BACK TO THE BLANK PSECT ; ENDPR .END