Google
 

Trailing-Edge - PDP-10 Archives - tops20-v7-ft-dist1-clock - 7-sources/rmsque.b36
There are 6 other files named rmsque.b36 in the archive. Click here to see a list.
%TITLE 'Q U E U E   -- ENQ/DEQ interface'
!<BLF/REQUIRE 'RMSBLF.REQ'>
MODULE queue (IDENT = '2.0'
		) =
BEGIN

GLOBAL BIND
    quev = 2^24 + 0^18 + 443;			! Edit date: 13-Dec-83

!+
!
!
!    FUNCTION:	THIS MODULE CONTAINS ALL ROUTINES WHICH INTERFACE
!    TO THE TOPS-10 or TOPS-20 ENQ/DEQ FACILITY.
!    AUTHOR:	S. BLOUNT
!
!
!	COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1977, 1986.
!	ALL RIGHTS RESERVED.
!
!	THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED  AND
!	COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
!	THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS  SOFTWARE  OR
!	ANY  OTHER  COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
!	AVAILABLE TO ANY OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE
!	SOFTWARE IS HEREBY TRANSFERRED.
!
!	THE INFORMATION IN THIS SOFTWARE IS  SUBJECT  TO  CHANGE  WITHOUT
!	NOTICE  AND  SHOULD  NOT  BE CONSTRUED AS A COMMITMENT BY DIGITAL
!	EQUIPMENT CORPORATION.
!
!	DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF
!	ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
!
!
!
!
!    **********	TABLE OF CONTENTS	**************
!
!
!
!
!    ROUTINE			FUNCTION
!    =======			========
!
!    FILEQ			LOCK A FILE DURING AN $OPEN MACRO
!
!    LOCKIT			LOCK A RECORD FOR ANY ACCESS
!
!
!
!
!
!    REVISION HISTORY:
!
!    EDIT	INITIALS	DATE		PURPOSE
!    ====	========	====		=======
!
!    1	JK		16-JUL-76	SETBUSYFLAG IF UNABLE TO LOCK
!    2	JK		16-JUL-76	CAPABILITIES ARE NOT SHARABLE
!    3	JK		16-JUL-76	SEPARATE STATUS FOR UNEXPECTED
!					    ENQUE/DEQUE ERRORS
!    4	JK		19-JUL-76	ADD 'ACCESS' ARGUMENT TO 'LOCKIT'
!    5	JK		26-JUL-76	'LOCKIT' NOW SUPPORTS CAPABILITIES
!    6	JK		26-JUL-76	ALLOW ZERO FOR ID IN 'LOCKIT'.
!    7	JK		27-JUL-76	'LOCKIT' SHOULDN'T SET 'USRSTS'.
!    8	SB		3-JAN-77	RETURN ERFLK IN FILEQ
!    9	SB		24-JAN-77	MAKE FB$UPD,FB$DEL IMPLY
!					    FB$GET IN FILEQ
!    10	SB		31-JAN-77	USE QBLKFLAGS IN LOCKIT
!    11	SB		3-MAY-77	ADD NESTING BIT TO ENQ TO ALLOW OPENING
!					    OF SAME FILE TWICE.
!
!    *************************************************
!    *						*
!    *		NEW REVISION HISTORY		*
!    *						*
!    *************************************************
!
!    PRODUCT	MODULE	 SPR
!    EDIT	 EDIT	 QAR		DESCRIPTION
!    ======	======	=====		===========
!
!	**  Begin RMS v2 Development **
!
!	400	400	xxxxx	    Clean up BLISS code (RL,22-Apr-83)
!
!	443	 - 	xxxxx	    (RL,13-Dec-83) Provide separate lock
!				    requests for UPD and DEL rather than
!				    lumping UPD in as GET+PUT.
!
!    ***** END OF REVISION HISTORY *****
!
!
!
!
!
!-

%IF %SWITCHES(TOPS10)
%THEN
LIBRARY 'BLI:UUOSYM';
UNDECLARE
    ER$FUL;
%FI

REQUIRE 'RMSREQ';

REQUIRE 'RMSOSD';

!DO THE APPROPRIATE TYPE OF ENQ FOR THE OBJECT COMPUTER
!
%IF %SWITCHES(TOPS20)
%THEN

MACRO
    do_enq =
		do_jsys(enq)
%;

MACRO
    then_enq =
		JSYS(-1,enq,ac1,ac2)
	THEN	RETURN true
%;

!
!   DO THE APPROPRIATE TYPE OF DEQ FOR THE OBJECT COMPUTER
!

MACRO
    do_deq =
		do_jsys(deq)
%;

MACRO
    then_deq =
		JSYS(-1,deq,ac1,ac2)
	THEN	RETURN true
%;
%FI
%SBTTL 'FILEQ - File queuer'

GLOBAL ROUTINE fileq (lock_opr, fcode) : NOVALUE =
! FILEQ
! =====
!
! THIS ROUTINE IS USED TO PERFORM ALL FILE
!	SYNCHRONIZATION OPERATIONS WHEN A FILE
!	IS OPENED. IT CHECKS THE USER'S FILE ACCESS
!	FIELD ( FAC ) AND COMPARES IT TO THE SHARABILITY
!	ACCESS FIELD ( SHR ). IT THEN ISSUES
!	VARIOUS ENQ CALLS TO THE MONITOR
!	IN ORDER TO GUARANTEE COMPATIBLE FILE USE.
!
!
!			Note
!
!	Under TOPS-10 we do not have the "nesting" of locks
!	capability that is available under TOPS-20.  As a result,
!	accessing the same file with two FAB's in RMS-10 will
!	have a restriction.  Since we will get a duplicate request
!	error from TOPS-10 when we ENQ the locks for the second
!	FAB, we must ignore the error.  The fact that we are accessing
!	these two files from the saem job will assure compatible
!	access.  The only problem that can be forseen is that if
!	the first FAB is closed, and another job tries to open the
!	same file for incompatible access to that of the second FAB
!	a conflict occurs.  There seems to be no easy way around this.
!	It should not be a major problem since the record level locking
!	will still work.
!
! INPUT:
!	A CODE TO INDICATE THE JSYS TO BE PERFORMED
!		ENQ
!		DEQ
!	FUNCTION CODE OF JSYS
!
! OUTPUT:
!	TRUE: FILE LOCKED
!	FALSE: NOT LOCKED ( FILE WAS NOT AVAILABLE )
    BEGIN
%IF %SWITCHES(TOPS20)
%THEN
    regs;
%ELSE
    REGISTER
	t1;
%FI

    LOCAL
	qblock : VECTOR [qblklength],
	temp,
	mask,
	count,
	facvalue,				! VALUE OF USER'S FAC FIELD
	shrvalue,				! VALUE OF USER'S SHR FIELD
	blkptr;

    MAP
	qblock : BLOCK [1];

    MAP
	blkptr : REF BLOCK;

    TRACE ('FILEQ');
!+
!    GET THE USER'S FAC AND SHR FIELD AND SET FB$GET IF
!    HE SPECIFIED FB$UPD OR FB$DEL IN EITHER FIELD.
!-
    facvalue = .fab [fabfac, 0];
    shrvalue = .fab [fabshr, 0];

    IF chkflag (facvalue, axupd + axdel) NEQ 0	!
    THEN
	setflag (facvalue, axget);		! Set FB$GET bit

    IF chkflag (shrvalue, axupd + axdel) NEQ 0	!
    THEN
	setflag (shrvalue, axget);		! Set FB$GET bit

!+
!    MASK will contain the current access value.
!    COUNT will keep track of the # of locks used.
!-
    clear(qblock, qblklength);                  ! Clear the arg block     !a572

    blkptr = qblock + qblkhdrsz;		! Q-block pointer (past header)
    mask = 1;					! Init mask
    count = 0;					!   and counter
!+
!   Loop once for each possible access.
!   AXTRN can be excluded because TRUNCATE
!   requires SHR=NIL.
!-

    WHILE .mask LEQ axdel DO 			! 			!A443
	BEGIN					! TO SET UP A Q-BLOCK ENTRY
!d572	blkptr [0, lh] = 0;			! CLEAR FLAGS, LEVEL NUMBER
	blkptr [qblkjfn] = .userjfn;		! SET JFN
	blkptr [qblkcode] = rmsqcode + .mask;	! USER CODE
	blkptr [qblkltype] = ltypefile;		! SET LOCK TYPE
!d572	blkptr [qblkword3] = 0;			! CLEAR SHARER'S GROUP

	!+
	!    WE MUST NOW DETERMINE HOW WE ARE GOING TO
	!    LOCK EACH RESOURCE. IF THE FAC AND SHR
	!    BITS ARE EQUAL, THEN WE WILL LOCK THE
	!    RESOURCE "SHARED". THIS EITHER MEANS THAT
	!    WE WILL DO THE OPERATION AND WE WILL ALLOW
	!    OTHERS TO ALSO DO IT, OR WE WONT DO IT AND
	!    WE DONT WANT OTHERS TO DO IT EITHER. IN THE
	!    LATTER CASE, WE MUST USE A SHARER'S GROUP
	!    TO MAKE SURE THAT NOBODY DOES THE OPERATION,
	!    BUT OTHER PEOPLE WHO ALSO DONT WANT IT TO BE
	!    DONE CAN LOCK THE RESOURCE IN THE SAME MANNER
	!-

	IF (.facvalue AND .mask) EQL (.shrvalue AND .mask)
	THEN
	    BEGIN
	    blkptr [qblkflags] = enqshr + enqnst;	! SHARABLE AND NESTING
	    !
	    !   If both are off, use group #1
	    !

	    IF (.facvalue AND .mask) EQL 0
	    THEN
		blkptr [qblkgroup] = 1		! SET GROUP = 1
	    END;

	!+
	!    WE MUST NOW MAKE SURE THAT LEVEL NUMBERS ARE BYPASSED
	!-

	blkptr [qblkflags] = .blkptr [qblkflags] OR enqbln;

	!+
	!    NOW, THIS ENTRY IN THE QBLOCK IN SET UP
	!    BUT, IF WE ARE NOT GOING TO PERFORM THE OPERATION,
	!    BUT OTHERS MAY DO SO, THEN WE DON'T NEED
	!    TO EVEN QUEUE FOR IT. IN THAT CASE, WE WILL IGNORE
	!    THIS ENTRY
	!-

	IF ((.facvalue AND .mask) NEQ 0) OR 	! If we will do operation
	    ((.shrvalue AND .mask) EQL 0)	! or others can't do it.
	THEN
	    BEGIN
	    blkptr = .blkptr + qblkntrysz;	! Bump pointer past this entry
	    count = .count + 1;			! Bump the count of entries
	    END;

	mask = .mask^1;				! SHIFT MASK
	END;

    !+
    !    WE MUST NOW FILL IN THE Q-BLOCK HEADER
    !-

    qblock [qhdrcount] = .count;		! # OF LOCKS
    qblock [qhdrlength] = (.count*qblkntrysz) + 2;	! LENGTH
!   qblock [qhdrpsi] = 0;			! CLEAR PSI CHANNEL #   !d572
    qblock [qhdrid] = .userjfn;			! ID = JFN

    !+
    !   Debugging -- dump the q-block
    !-

%IF dbug
%THEN
    begindebug (dbblocks)bugout('DUMP OF FILE-Q:');
    temp = .qblock [qhdrlength];
    dump (.temp, .qblock)enddebug;
%FI

    !+
    !    NOW, DO THE ENQ/DEQ
    !-

    SELECT .lock_opr OF
	SET

	[enqcall] :

	    %IF %SWITCHES(TOPS20)
            %THEN
                IF NOT enq (.fcode, qblock) THEN monerr ();
            %ELSE
                BEGIN
                t1 = .fcode ^ 18 + qblock;

                IF NOT ENQ$_UUO(t1)
                THEN
                    IF .t1 NEQ ENQDR_ THEN monerr ();
                END;
            %FI
	[deqcall] :

	    %IF %SWITCHES(TOPS20)
            %THEN
                 IF NOT deq (.fcode, qblock) THEN monerr ();
            %ELSE
                BEGIN
                t1 = .fcode ^ 18 + qblock;

                IF NOT DEQ$_UUO(t1) THEN monerr ();
                END;
            %FI
	[OTHERWISE] :
	    rmsbug (msgjsys)			! BAD JSYS CODE
	TES;

    RETURN;
    END;					! End routine FILEQ
%SBTTL 'LOCKIT - record/capability locking'

GLOBAL ROUTINE lockit (lock_opr, fcode, id, access, locktype) =
! LOCKIT
! ======
!
!	     THIS ROUTINE PERFORMS THE LOCKING/UNLOCKING OF RECORDS AND
!	CAPABILITIES.
!
! INPUT:
!	LOCK_OPR		JSYS CODE FOR ENQ OR DEQ
!		ENQ		ENQ THIS RESOURCE
!		DEQ		DEQ THIS RESOURCE
!	FCODE			FUNCTION CODE FOR JSYS
!	ID			RESOURCE ID TO ENQ OR DEQ
!	ACCESS			LOCK ACCESS
!		ENQXCL		EXCLUSIVE ACCESS (FOR ENQ ONLY)
!		ENQSHR		SHARED ACCESS (FOR ENQ ONLY)
!		ENQLTL		LONG-TERM LOCK
!		(ENQBLN IS ALWAYS SET BY THIS ROUTINE)
!	LOCKTYPE		LOCK-TYPE CODE
!
! OUTPUT:
!	TRUE:	JSYS TOOK SKIP RETURN
!	FALSE:	ERROR (JSYS TOOK NON-SKIP RETURN)
!
! NOTES:
!
!	1.	IF THIS ROUTINE RETURNS "FALSE", THEN USRSTV
!		WILL CONTAIN THE MONITOR ERROR CODE RETURNED.
!
    BEGIN

    LOCAL
	qblock : VECTOR [qblkntrysz + 2],
	idtext,					! Debugging text pointer
	blockptr : REF BLOCK;

    MAP
	qblock : BLOCK [1];

    TRACE ('LOCKIT');

    !+
    !    CHECK PARAMETERS
    !-

    checkinput (id, GEQ, 0);			! ID MUST BE NON-NEGATIVE

    !+
    !    SET UP THE ENQ BLOCK FORMAT
    !-

    clear(qblock, qblkntrysz + 2);              ! Clear the enq block     !a572

    qblock [qhdrcount] = 1;			! SET UP HEADER
    qblock [qhdrlength] = qblkntrysz + qblkhdrsz;
!   qblock [qhdrpsi] = 0;			! CLEAR PSI CHANNEL NR    !d572
    qblock [qhdrid] = .rst;			! USE STREAM ID AS REQUEST ID
    blockptr = qblock + 2;			! SET UP POINTER
    blockptr [qblkflags] = enqbln + .access;	! SET "BYPASS LEVEL NUMBERS"
    blockptr [qblkjfn] = .fst [fstjfn];		!
    blockptr [qblkcode] = rmsqcode + .id;	! SET UP CODE
    blockptr [qblkltype] = .locktype;		! AND LOCK-TYPE
!   blockptr [qblkword3] = 0;			! CLEAR POOL COUNT        !d572

%IF dbug
%THEN
    begindebug (dbblocks)bugout(%STRING ('	Dump of QBLOCK:', 	!
	%CHAR (13, 10), ' '));
    dump (qblkntrysz + qblkhdrsz, .qblock)enddebug;
%FI

    !+
    !    DO ALL THIS CODE FOR DEBUGGING ONLY
    !-

%IF dbug
%THEN
    begindebug (dblock)idtext = (

	CASE .locktype FROM 0 TO 3 OF
	    SET

	    [0] :
		UPLIT (%ASCIZ' RECORD ');	! Record

	    [1] :
		UPLIT (%ASCIZ' FILE ');		! File

	    [2] :
		UPLIT (%ASCIZ' CAP ');		! Capability

	    [3] :
		UPLIT (%ASCIZ' BUCKET ');	! Bucket
	    TES);

    txtout (rm$asz, .idtext);

    IF .lock_opr EQL deqcall THEN bugout ('UN');

    printvalue ('LOCKING: ', id);
    enddebug;
%FI

    !+
    !    GENERATE THE ENQ/DEQ FUNCTION CODE AND ADDRESS OF THE BLOCK
    !-

    IF .lock_opr EQL enqcall
    THEN

    !+
    !    ENQ
    !-

    %IF %SWITCHES(TOPS20)
    %THEN
	BEGIN					! Processing of ENQ call

	LOCAL
	    enq_error;

!+
!    PERFORM THE ENQ JSYS. IF IT SUCCEEDS, WE
!    CAN EXIT IMMEDIATELY. IF IT FAILS, WE MUST
!    DETERMINE IF THE ERROR WAS EXPECTED (I.E.,
!    THE LOCK IS ALREADY BUSY, OR WE HAVE ALREADY
!    REQUESTED THE LOCK FOR MULTIPLE STREAMS)
!-

	IF enq (.fcode, qblock; enq_error)	! Do the JSYS
	THEN
	    RETURN true
	ELSE
	    BEGIN
	    usrstv = .enq_error;		! Save system error

	    IF (.usrstv EQL enqx6) OR 		! Requested locks not locked
		(.usrstv EQL enqx5)		! Lock already requested
	    THEN
		usrsts = er$rlk			! Record locked
	    ELSE
		usrsts = er$edq;		! Unexpected error

	    					! SET STATUS TO "ENQ/DEQ ERROR"
	    RETURN false
	    END

	END
    %ELSE  !TOPS10                                                       !a572v
	BEGIN					! Processing of ENQ call

	REGISTER
	    t1;

!+
!    PERFORM THE ENQ UUO. IF IT SUCCEEDS, WE
!    CAN EXIT IMMEDIATELY. IF IT FAILS, WE MUST
!    DETERMINE IF THE ERROR WAS EXPECTED (I.E.,
!    THE LOCK IS ALREADY BUSY, OR WE HAVE ALREADY
!    REQUESTED THE LOCK FOR MULTIPLE STREAMS)
!-

	t1 = .fcode ^ 18 + qblock;

	IF ENQ$_UUO(t1)				! Do the JSYS
	THEN
	    RETURN true
	ELSE
	    BEGIN
	    usrstv = .t1;			! Save system error

	    IF (.usrstv EQL ENQRU_) OR 		! Some resource not available
		(.usrstv EQL ENQDR_)		! Duplicate request
	    THEN
		usrsts = er$rlk			! Record locked
	    ELSE
		usrsts = er$edq;		! Unexpected error

	    					! SET STATUS TO "ENQ/DEQ ERROR"
	    RETURN false
	    END

	END
    %FI
    ELSE

    !+
    !    DEQ
    !-
    %IF %SWITCHES(TOPS20)
    %THEN
	BEGIN

	LOCAL
	    deq_error;

	IF deq (.fcode, qblock; deq_error)
	THEN
	    RETURN true
	ELSE
	    BEGIN
	    usrstv = .deq_error;		! Save monitor error
	    usrsts = er$edq;			! Should not happen
	    RETURN false
	    END

	END;
    %ELSE !TOPS10                                                   !a572vv

	BEGIN

	REGISTER
	    t1;

	t1 = .fcode ^ 18 + qblock;

	IF DEQ$_UUO(t1)
	THEN
	    RETURN true
	ELSE
	    BEGIN
	    usrstv = .t1;			! Save monitor error
	    usrsts = er$edq;			! Should not happen
	    RETURN false
	    END

	END;
    %FI                                                             !a572^^
    END;					! End LOCKIT

END

ELUDOM