?? RIGHT := 110 ??
MODULE osm$lock_manager {deck := osmlok} ;
?? RIGHT := 110 ??

{  PURPOSE:
{     This module contains procedures to manage system table locks.

?? NEWTITLE := 'Global Declarations referenced by this module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc ost$status
*copyc oss$mainframe_pageable
*copyc ost$execution_control_block
*copyc ost$signature_lock
*copyc ost$wait
*copyc ost$heap
*copyc osc$processor_defined_registers
?? POP ??
*copyc osp$system_error
*copyc mmp$mfh_for_segment_manager
*copyc pmp$cycle
*copyc pmp$delay
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$set_signature_lock', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$set_signature_lock
    (VAR lock: ost$signature_lock;
         wait: ost$wait;
     VAR status: ost$status);

*copyc osh$set_signature_lock

    VAR
      ring: integer,
      local_reject_count: integer,
      task_id: ost$global_task_id,
      xcb_p: ^ost$execution_control_block,
      new_value,
      actual_value: integer,
      ptr: ^cell,
      cs_status: 0 .. 2;

    status.normal := TRUE;

    xcb_p := #ADDRESS (1, osc$segnum_job_fixed_heap, #READ_REGISTER (osc$pr_base_constant));
    task_id := xcb_p^.global_task_id;
    new_value := task_id.index * 256 * #SIZE (task_id.seqno) + task_id.seqno;
    local_reject_count := 0;

    ptr := ^lock;
    ring := #RING (ptr);

  /lock_loop/
    WHILE TRUE DO

{      Check for lock on a system table.
      IF ring = 1 THEN
        xcb_p^.system_table_lock_count := xcb_p^.system_table_lock_count + 256;
      IFEND;

      local_reject_count := local_reject_count + 1;
      REPEAT
        #COMPARE_SWAP (lock.lock_id, 0, new_value, actual_value, cs_status);
      UNTIL cs_status <> osc$cs_variable_locked;
      IF cs_status = osc$cs_successful THEN
        RETURN; {----->
      IFEND;

      IF ring = 1 THEN
        xcb_p^.system_table_lock_count := xcb_p^.system_table_lock_count - 256;
      IFEND;

      IF new_value = actual_value THEN
        osp$system_error ('Lock already set by current task', NIL);
      IFEND;

      IF wait = osc$wait THEN
        pmp$cycle (status);
        CYCLE /lock_loop/; {----->
      IFEND;


{  Unable to set the lock.

      IF (ring = 1) AND (xcb_p^.system_give_up_cpu) THEN
        pmp$cycle (status);
      IFEND;

{! The following may miss a count if a trap occurs during this line - so what.

      status.normal := FALSE;
      RETURN; {----->
    WHILEND /lock_loop/;

  PROCEND osp$set_signature_lock;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$clear_signature_lock', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$clear_signature_lock
    (VAR lock: ost$signature_lock;
     VAR status: ost$status);

*copyc osh$clear_signature_lock

    VAR
      ring: integer,
      task_id: ost$global_task_id,
      xcb_p: ^ost$execution_control_block,
      actual_value,
      initial_value: integer,
      ptr: ^cell,
      cs_status: 0 .. 2;

    status.normal := TRUE;
    xcb_p := #ADDRESS (1, osc$segnum_job_fixed_heap, #READ_REGISTER (osc$pr_base_constant));
    task_id := xcb_p^.global_task_id;
    initial_value := task_id.index * 256 * #SIZE (task_id.seqno) + task_id.seqno;
    REPEAT
      #COMPARE_SWAP (lock.lock_id, initial_value, 0, actual_value, cs_status);
    UNTIL cs_status <> osc$cs_variable_locked;
    IF cs_status <> osc$cs_successful THEN
      status.normal := FALSE;
      osp$system_error ('LOCKMGR - not locked', NIL);
    IFEND;

    ptr := ^lock;
    ring := #RING (ptr);
    IF ring = 1 THEN

{ Debug code.

      IF xcb_p^.system_table_lock_count < 256 THEN
        osp$system_error ('LOCKMGR - system_table_lock_count error', NIL);
      IFEND;

{ End debug code.

      xcb_p^.system_table_lock_count := xcb_p^.system_table_lock_count - 256;

{ Check for escaped allocation. If allocation occured while tables were locked, process
{ the allocation.

      IF xcb_p^.stlc_allocation AND (xcb_p^.system_table_lock_count < 256) THEN
        xcb_p^.stlc_allocation := FALSE;
        mmp$mfh_for_segment_manager;
      IFEND;

      IF (xcb_p^.system_table_lock_count <= 0) AND (xcb_p^.system_give_up_cpu) THEN
        pmp$cycle (status);
      IFEND;
    IFEND;

  PROCEND osp$clear_signature_lock;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$initialize_signature_lock', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$initialize_signature_lock
    (VAR lock: ost$signature_lock;
     VAR status: ost$status);

*copyc osh$initialize_signature_lock

    status.normal := TRUE;
    lock.lock_id := 0;


  PROCEND osp$initialize_signature_lock;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$test_signature_lock', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$test_signature_lock
    (VAR lock: ost$signature_lock;
     VAR lock_status: ost$signature_lock_status);

*copyc osh$test_signature_lock

    VAR
      cs_status: 0 .. 2,
      task_id: ost$global_task_id,
      xcb_p: ^ost$execution_control_block,
      actual_value,
      current_task_value: integer;

    REPEAT
      #COMPARE_SWAP (lock.lock_id, 0, 0, actual_value, cs_status);
    UNTIL cs_status <> osc$cs_variable_locked;
    IF cs_status = osc$cs_successful THEN
      lock_status := osc$sls_not_locked;
    ELSE
      xcb_p := #ADDRESS (1, osc$segnum_job_fixed_heap, #READ_REGISTER (osc$pr_base_constant));
      task_id := xcb_p^.global_task_id;
      current_task_value := task_id.index * 256 * #SIZE (task_id.seqno) + task_id.seqno;
      IF actual_value = current_task_value THEN
        lock_status := osc$sls_locked_by_current_task;
      ELSE
        lock_status := osc$sls_locked_by_another_task;
      IFEND;
    IFEND;

  PROCEND osp$test_signature_lock;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$mfh_for_segment_manager', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$mfh_for_segment_manager;

    mmp$mfh_for_segment_manager;

  PROCEND osp$mfh_for_segment_manager;
?? OLDTITLE ??
MODEND osm$lock_manager;
