?? NEWTITLE := 'NAM/VE: Connection Manager' ??
MODULE nlm$cl_connection_manager_r1;
?? RIGHT := 110 ??

{
{   PURPOSE:
{     The prime purpose of this module is to isolate the knowledge of the structures required
{     to access a specific connection.  Secondarily, the module contains service procedures to
{     support the connection establishment and disestablishment phases.
{
{     NOTE: the module which constitutes the timer task, the
{           and the channel connection manager are knowledgeable of the access structure.
{           Therefore, modifications to the access structure must be reflected there also.
{
{           Procedures, other than 'release exclusive access', are to be called only by the
{           connection manager which resides in OSF$JOB_TEMPLATE_23D, the timer task, and the
{           Channel connection manager.
{
{   DESIGN:
{     This module is designed to reside in the OSF$SYSTEM_CORE_113 library.
{
{     The access scheme is basically two leveled -- nonexclusive access to a connection root is
{     acquired before exclusive access is attempted to a specific connection.  The two level
{     access along with the specific algorithms is unknown to the users of the get/release access
{     procedures contained in this module.
{
{     The module contains procedures used by the network input task, timer monitor task, and user
{     tasks to acquire exclusive access to a specific connection.  A single procedure exists to
{     release exclusive access in any case.
{
{     The service procedure for connection establishment, assign connection, enhances the isolation
{     of the two level access structure and at the same time restrict the knowledge of the
{     mechanics of the internal connection structure.
{
{     The service procedure for connection disestablishment, release connection, basically restrict
{     the knowledge of the mechanics of the internal connection structure and are not involved in
{     the access structure.
{
?? NEWTITLE := 'Global Declarations Referenced by this Module' ??
?? PUSH (LISTEXT := ON) ??
*copyc nlc$nam_configuration_constants
*copyc nlt$cc_connection
*copyc nlt$cl_connections
*copyc oss$mainframe_paged_literal
*copyc oss$mainframe_pageable
*copyc oss$network_paged
*copyc ost$name
*copyc ost$status
?? POP ??
*copyc dsp$get_nve_image_description
*copyc nlp$cl_get_layer_connection
*copyc osp$system_error
*copyc osp$begin_subsystem_activity
*copyc osp$clear_locked_variable
*copyc osp$end_subsystem_activity
*copyc osp$increment_locked_variable
*copyc pmp$get_executing_task_gtid
*copyc pmp$ready_task
*copyc syp$cycle
*copyc jmv$system_core_id
*copyc nav$network_paged_heap
*copyc nlv$cl_connections
*copyc nlv$cl_active_connections
*copyc nlv$maximum_system_connections
*copyc nlv$timer_monitor_task
*copyc osv$mainframe_wired_heap
*copyc osv$page_size
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST
    successful = 0,
    failed = 1,
    locked = 2;

  VAR
    v$cl_terminated_connections: [oss$mainframe_pageable] integer := 0,

    v$unlocked_connection_access: [READ, oss$mainframe_paged_literal] nlt$cl_connection_access :=
          [FALSE, 0, [0, 0]],

    v$null_cl_connection: [READ, oss$mainframe_paged_literal] nlt$cl_connection :=
          [NIL, [FALSE, 0, [0, 0]], FALSE, * , [FALSE, * ], [FALSE, * ], * , $nlt$cl_layers [], NIL,
          $nlt$device_ids [], FALSE, 1];

?? OLDTITLE ??
?? TITLE := '[XDCL, #GATE] nlp$cc_find_duplicate_connect', EJECT ??
*copy nlh$cc_find_duplicate_connect

{ NOTE: This routine resides in this module so it can access the connection structures directly and can gain
{       access to the roots without many ring crossing calls to the access routines.

  PROCEDURE [XDCL, #GATE] nlp$cc_find_duplicate_connect
    (    device_id: nlt$device_identifier;
         peer_reference_number: nlt$cl_reference_number;
     VAR duplicate: boolean);

    VAR
      cl_connection: ^nlt$cl_connection,
      connection: ^nlt$cc_connection,
      layer_active: boolean,
      root: nlt$cl_reference_number;

    duplicate := FALSE;
    IF (nlv$cl_connections.list <> NIL) THEN

    /search_roots/
      FOR root := LOWERBOUND (nlv$cl_connections.list^) TO UPPERBOUND (nlv$cl_connections.list^) DO
        IF nlv$cl_connections.list^ [root].first <> NIL THEN
          get_nonexclusive_to_root (root);
          cl_connection := nlv$cl_connections.list^ [root].first;

        /search_stem/
          WHILE (cl_connection <> NIL) DO
            nlp$cl_get_layer_connection (nlc$channel_connection_layer, cl_connection, layer_active,
                  connection);
            IF layer_active AND (peer_reference_number = connection^.peer_reference_number) AND
                  (device_id = connection^.device_specific_attributes.device_id) AND
                  (connection^.device_specific_attributes.state <> nlc$cc_closed) THEN
              release_nonexclusive_to_root (root);
              duplicate := TRUE;
              EXIT /search_roots/; {----->
            IFEND;
            cl_connection := cl_connection^.nextt;
          WHILEND /search_stem/;
          release_nonexclusive_to_root (root);
        IFEND;
      FOREND /search_roots/;
    IFEND;

  PROCEND nlp$cc_find_duplicate_connect;
?? TITLE := '[XDCL, #GATE] nlp$cc_get_exclus_to_unaccepted {connection}', EJECT ??
*copy nlh$cc_get_exclus_to_unaccepted

{ NOTE: This routine resides in this module so it can access the connection structures directly and can gain
{       access to the roots without many ring crossing calls to the access routines.

  PROCEDURE [XDCL, #GATE] nlp$cc_get_exclus_to_unaccepted
    (    peer_reference_number: nlt$cl_reference_number;
         device_id: nlt$device_identifier;
         system_input_task: boolean;
     VAR connection_exists: boolean;
     VAR access_gained: boolean;
     VAR connection: ^nlt$cc_connection;
     VAR cl_connection: ^nlt$cl_connection);

    VAR
      layer_active: boolean,
      root: nlt$cl_reference_number;

    access_gained := FALSE;
    connection_exists := FALSE;
    IF (nlv$cl_connections.list <> NIL) THEN

    /search_roots/
      FOR root := LOWERBOUND (nlv$cl_connections.list^) TO UPPERBOUND (nlv$cl_connections.list^) DO
        IF nlv$cl_connections.list^ [root].first <> NIL THEN
          get_nonexclusive_to_root (root);
          cl_connection := nlv$cl_connections.list^ [root].first;

        /search_stem/
          WHILE (cl_connection <> NIL) DO
            nlp$cl_get_layer_connection (nlc$channel_connection_layer, cl_connection, layer_active,
                  connection);
            IF layer_active AND (peer_reference_number = connection^.peer_reference_number) AND
                  (device_id = connection^.device_specific_attributes.device_id) AND
                  (connection^.device_specific_attributes.state <> nlc$cc_closed) THEN
              nlp$cl_get_exclusive_access (cl_connection^.identifier, system_input_task, connection_exists,
                    access_gained, cl_connection);
              release_nonexclusive_to_root (root);
              EXIT /search_roots/; {----->
            IFEND;
            cl_connection := cl_connection^.nextt;
          WHILEND /search_stem/;
          release_nonexclusive_to_root (root);
        IFEND;
      FOREND /search_roots/;
    IFEND;

  PROCEND nlp$cc_get_exclus_to_unaccepted;

?? TITLE := '  [XDCL, #GATE] nlp$cl_get_exclusive_access', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_get_exclusive_access
    (    connection_id: nlt$cl_connection_id;
         system_input_task: boolean;
     VAR connection_exists: boolean;
     VAR access_gained: boolean;
     VAR cl_connection: ^nlt$cl_connection);

*copy nlh$cl_get_exclusive_access

    VAR
      actual_value: nlt$cl_connection_access,
      connection: ^nlt$cl_connection,
      cs_status: successful .. locked,
      global_task_id: ost$global_task_id,
      initial_value: nlt$cl_connection_access,
      new_value: nlt$cl_connection_access,
      root: nlt$cl_reference_number;

    connection_exists := FALSE;
    access_gained := FALSE;
    IF (nlv$cl_connections.list <> NIL) THEN
      root := (connection_id.reference_number MOD (UPPERBOUND (nlv$cl_connections.list^) + 1));
      get_nonexclusive_to_root (root);
      connection := nlv$cl_connections.list^ [root].first;

    /search_stem/
      WHILE (connection <> NIL) DO
        IF ((connection^.identifier = connection_id) AND (connection^.layer_connections <> NIL)) THEN
          connection_exists := TRUE;
          pmp$get_executing_task_gtid (global_task_id);
          osp$begin_subsystem_activity;
          REPEAT
            new_value.notify_system_task := FALSE;
            new_value.fill := 0;
            new_value.task_id := global_task_id;
            REPEAT
              #COMPARE_SWAP (connection^.access_control, v$unlocked_connection_access, new_value,
                    actual_value, cs_status);
            UNTIL cs_status <> locked;
            IF cs_status = successful THEN
              access_gained := TRUE;
            ELSEIF actual_value.task_id <> new_value.task_id THEN { cs_status = failed }
              IF system_input_task THEN

{ The connection is currently locked by some other task. Update the notify_system_task
{ field in the access_control word so that the system input task work list process will
{ be invoked when access to the connection is released.

                initial_value := actual_value;
                new_value := actual_value;
                new_value.notify_system_task := TRUE;
                REPEAT
                  #COMPARE_SWAP (connection^.access_control, initial_value, new_value, actual_value,
                        cs_status);
                UNTIL cs_status <> locked;
              IFEND;
            ELSE
              osp$system_error ('NAM/VE - lock already set by current task', NIL);
            IFEND;
          UNTIL (cs_status = successful) OR NOT system_input_task;
          cl_connection := connection;
          IF NOT access_gained THEN
            osp$end_subsystem_activity;
          IFEND;
          EXIT /search_stem/; {----->
        ELSE
          connection := connection^.nextt;
        IFEND;
      WHILEND /search_stem/;
      release_nonexclusive_to_root (root);
    ELSE
      cl_connection := NIL;
    IFEND;
  PROCEND nlp$cl_get_exclusive_access;
?? OLDTITLE ??
?? TITLE := '  [XDCL, #GATE] nlp$cl_get_exclusive_via_cid', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_get_exclusive_via_cid
    (    connection_id: nlt$cl_connection_id;
     VAR connection_exists: boolean;
     VAR cl_connection: ^nlt$cl_connection);

*copy nlh$cl_get_exclusive_via_cid

    VAR
      actual_value: nlt$cl_connection_access,
      connection: ^nlt$cl_connection,
      cs_status: successful .. locked,
      new_value: nlt$cl_connection_access,
      root: nlt$cl_reference_number;

    connection_exists := FALSE;
    cl_connection := NIL;

    IF (nlv$cl_connections.list <> NIL) THEN
      root := (connection_id.reference_number MOD (UPPERBOUND (nlv$cl_connections.list^) + 1));
      get_nonexclusive_to_root (root);
      connection := nlv$cl_connections.list^ [root].first;

    /search_stem/
      WHILE (connection <> NIL) DO
        IF ((connection^.identifier = connection_id) AND (connection^.layer_connections <> NIL)) THEN
          connection_exists := TRUE;
          pmp$get_executing_task_gtid (new_value.task_id);
          new_value.notify_system_task := FALSE;
          new_value.fill := 0;
          osp$begin_subsystem_activity;
          REPEAT
            #COMPARE_SWAP (connection^.access_control, v$unlocked_connection_access, new_value, actual_value,
                  cs_status);
            IF cs_status = failed THEN
              IF actual_value.task_id <> new_value.task_id THEN
                osp$end_subsystem_activity;
                syp$cycle;
                osp$begin_subsystem_activity;
              ELSE
                osp$system_error ('NAM/VE - lock already set by current task', NIL);
              IFEND;
            IFEND;
          UNTIL cs_status = successful;
          cl_connection := connection;
          EXIT /search_stem/; {----->
        ELSE
          connection := connection^.nextt;
        IFEND;
      WHILEND /search_stem/;
      release_nonexclusive_to_root (root);
    IFEND;
  PROCEND nlp$cl_get_exclusive_via_cid;
?? TITLE := '  [XDCL, #GATE] nlp$cl_release_exclusive_access', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_release_exclusive_access
    (VAR cl_connection {INPUT, OUTPUT} : ^nlt$cl_connection);

*copy nlh$cl_release_exclusive_access

    VAR
      actual_value: nlt$cl_connection_access,
      connection: ^nlt$cl_connection,
      cs_status: successful .. locked,
      initial_value: nlt$cl_connection_access;


    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    pmp$get_executing_task_gtid (initial_value.task_id);
    initial_value.fill := 0;
    initial_value.notify_system_task := FALSE;
    REPEAT
      #COMPARE_SWAP (connection^.access_control, initial_value, v$unlocked_connection_access, actual_value,
            cs_status);
      IF cs_status = failed THEN
        IF actual_value.task_id = initial_value.task_id THEN
          initial_value := actual_value;
        ELSE
          osp$system_error ('NAM/VE - lock not locked by current task', NIL);
        IFEND;
      IFEND;
    UNTIL cs_status = successful;

    osp$end_subsystem_activity;
    IF actual_value.notify_system_task THEN
      notify_system_task;
    IFEND;
    cl_connection := NIL;
  PROCEND nlp$cl_release_exclusive_access;
?? TITLE := '  [XDCL, #GATE] nlp$cl_clear_exclusive_access', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_clear_exclusive_access
    (VAR cl_connection {INPUT, OUTPUT} : ^nlt$cl_connection);

*copy nlh$cl_clear_exclusive_access

    VAR
      actual_value: nlt$cl_connection_access,
      connection: ^nlt$cl_connection,
      cs_status: successful .. locked,
      initial_value: nlt$cl_connection_access;

    IF (cl_connection <> NIL) THEN
      connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
      pmp$get_executing_task_gtid (initial_value.task_id);
      initial_value.fill := 0;
      initial_value.notify_system_task := FALSE;
      REPEAT
        #COMPARE_SWAP (connection^.access_control, initial_value, v$unlocked_connection_access, actual_value,
              cs_status);
        IF cs_status = failed THEN
          IF actual_value.task_id = initial_value.task_id THEN
            initial_value := actual_value;
          ELSE { Connection not locked by current task }
            cl_connection := NIL;
            RETURN; {----->
          IFEND;
        IFEND;
      UNTIL cs_status = successful;

      osp$end_subsystem_activity;
      IF actual_value.notify_system_task THEN
        notify_system_task;
      IFEND;
      cl_connection := NIL;
    IFEND;
  PROCEND nlp$cl_clear_exclusive_access;
?? TITLE := '  [INLINE] notify_system_task', EJECT ??

  PROCEDURE [INLINE] notify_system_task;

*copyc pmp$set_system_flag
*copyc nav$system_input_taskid

    VAR
      status: ost$status;

    REPEAT
      syp$cycle; {Pause, in case event is not yet on work list}
      pmp$set_system_flag (nlc$cc_work_list_flag, nav$system_input_taskid, status);
      IF NOT status.normal THEN
        IF (status.condition <> pme$unknown_recipient_task) THEN
          osp$system_error ('CANNOT SET SYSTEM FLAG', ^status);
        IFEND;
      IFEND;
    UNTIL status.normal;
  PROCEND notify_system_task;
?? TITLE := '[XDCL, #GATE] nlp$cl_add_device_to_connection', EJECT ??
*copy nlh$cl_add_device_to_connection

  PROCEDURE [XDCL, #GATE] nlp$cl_add_device_to_connection
    (    device_id: nlt$device_identifier;
         cl_connection {INPUT, OUTPUT} : ^nlt$cl_connection);

    VAR
      connection: ^nlt$cl_connection;

    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    connection^.device_ids := connection^.device_ids + $nlt$device_ids [device_id];

  PROCEND nlp$cl_add_device_to_connection;
?? TITLE := '  [XDCL, #GATE] nlp$cl_activate_layer', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_activate_layer
    (    layer: nlt$cl_layer_name;
         cl_connection: ^nlt$cl_connection);

*copy nlh$cl_activate_layer

    VAR
      connection: ^nlt$cl_connection;

    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    connection^.layers_active := connection^.layers_active + $nlt$cl_layers [layer];
  PROCEND nlp$cl_activate_layer;
?? TITLE := '  [XDCL, #GATE] nlp$cl_deactivate_layer', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_deactivate_layer
    (    layer: nlt$cl_layer_name;
         cl_connection: ^nlt$cl_connection);

*copy nlh$cl_deactivate_layer

    VAR
      available_connections: integer,
      connection: ^nlt$cl_connection,
      ignore_status: ost$status,
      terminated_connections: integer;

    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    connection^.layers_active := connection^.layers_active - $nlt$cl_layers [layer];
    IF connection^.layers_active = $nlt$cl_layers [] THEN
      available_connections := nlv$maximum_system_connections - nlv$cl_active_connections;
      IF available_connections <= (nlv$maximum_system_connections DIV 4) THEN
        IF available_connections <= (nlv$maximum_system_connections DIV 16) THEN
          pmp$ready_task (nlv$timer_monitor_task, ignore_status);
        ELSE
          osp$increment_locked_variable (v$cl_terminated_connections, 0, terminated_connections);
          IF terminated_connections >= (nlv$maximum_system_connections DIV 8) THEN
            pmp$ready_task (nlv$timer_monitor_task, ignore_status);
          IFEND;
        IFEND;
      IFEND;
    IFEND;
  PROCEND nlp$cl_deactivate_layer;
?? TITLE := '  [XDCL, #GATE] nlp$cl_zero_terminated_connects', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_zero_terminated_connects;

*copy nlh$cl_zero_terminated_connects

    osp$clear_locked_variable (v$cl_terminated_connections, 0);

  PROCEND nlp$cl_zero_terminated_connects;
?? TITLE := '  [XDCL, #GATE] nlp$cl_activate_sender', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_activate_sender
    (    cl_connection: ^nlt$cl_connection);

*copy nlh$cl_activate_sender

    VAR
      executing_task_id: ost$global_task_id,
      connection: ^nlt$cl_connection;

    pmp$get_executing_task_gtid (executing_task_id);
    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    connection^.message_sender.task := executing_task_id;
    connection^.message_sender.active := TRUE;
  PROCEND nlp$cl_activate_sender;
?? TITLE := '  [XDCL, #GATE] nlp$cl_deactivate_sender', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_deactivate_sender
    (    cl_connection: ^nlt$cl_connection);

*copy nlh$cl_deactivate_sender

    VAR
      connection: ^nlt$cl_connection;

    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    connection^.message_sender.active := FALSE;
  PROCEND nlp$cl_deactivate_sender;
?? TITLE := '  [XDCL, #GATE] nlp$cl_activate_receiver', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_activate_receiver
    (    cl_connection: ^nlt$cl_connection);

*copy nlh$cl_activate_receiver

    VAR
      executing_task_id: ost$global_task_id,
      connection: ^nlt$cl_connection;

    pmp$get_executing_task_gtid (executing_task_id);
    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    connection^.message_receiver.task := executing_task_id;
    connection^.message_receiver.active := TRUE;
  PROCEND nlp$cl_activate_receiver;
?? TITLE := '  [XDCL, #GATE] nlp$cl_deactivate_receiver', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_deactivate_receiver
    (    cl_connection: ^nlt$cl_connection);

*copy nlh$cl_deactivate_receiver

    VAR
      connection: ^nlt$cl_connection;

    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    connection^.message_receiver.active := FALSE;
  PROCEND nlp$cl_deactivate_receiver;
?? TITLE := '  [XDCL, #GATE] nlp$cl_assign_connection', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_assign_connection
    (    application_layer: nlt$cl_application_layer;
         layer_connections: ^nlt$cl_layer_connections;
     VAR cl_connection: ^nlt$cl_connection);

*copy nlh$cl_assign_connection

    VAR
      actual_value: nlt$cl_connection_access,
      connection: ^nlt$cl_connection,
      connection_id_assigned: boolean,
      cs_status: successful .. locked,
      new_value: nlt$cl_connection_access;

?? NEWTITLE := '    initialize_connection_list', EJECT ??

    PROCEDURE initialize_connection_list;

      VAR
        v$null_connection_root: [READ, oss$mainframe_paged_literal] nlt$cl_connection_root :=
              [[FALSE, 0, FALSE, 0], NIL],
        v$locked_connection: [READ, oss$mainframe_paged_literal] string (8) := nlc$cl_connections_locked,
        v$unlocked_connection: [READ, oss$mainframe_paged_literal] string (8) := nlc$cl_connections_unlocked;

      VAR
        actual_lock: string (8),
        connections: ^array [0 .. * ] of nlt$cl_connection_root,
        number_of_entries: integer,
        result: successful .. locked,
        root: nlt$cl_reference_number;

      osp$begin_subsystem_activity;
      REPEAT
        #COMPARE_SWAP (nlv$cl_connections_control.lock, v$unlocked_connection, v$locked_connection,
              actual_lock, result);
        IF (result = failed) THEN
          osp$end_subsystem_activity;
          syp$cycle;
          osp$begin_subsystem_activity;
        IFEND;
      UNTIL (result = successful);

      IF (nlv$cl_connections.list = NIL) THEN
        number_of_entries := nlc$base_connection_array_size;
        WHILE (number_of_entries * 4) < nlv$maximum_system_connections DO
          number_of_entries := number_of_entries * 2;
        WHILEND;
        ALLOCATE connections: [0 .. (number_of_entries - 1)] IN osv$mainframe_wired_heap^;
        IF (nlv$cl_connections.cid_seed = 0) THEN
          nlv$cl_connections.cid_seed := (#FREE_RUNNING_CLOCK (0) MOD
                (UPPERVALUE (nlt$cl_reference_number) + 1));
        IFEND;
        FOR root := 0 TO (number_of_entries - 1) DO
          connections^ [root] := v$null_connection_root;
        FOREND;
        nlv$cl_connections.list := connections;
      IFEND;

      REPEAT
        #COMPARE_SWAP (nlv$cl_connections_control.lock, v$locked_connection, v$unlocked_connection,
              actual_lock, result);
      UNTIL (result = successful);
      osp$end_subsystem_activity;

    PROCEND initialize_connection_list;
?? OLDTITLE ??
?? NEWTITLE := '    assign_connection_id', EJECT ??

    PROCEDURE assign_connection_id
      (    connection: ^nlt$cl_connection;
       VAR connection_id_assigned: boolean;
       VAR connection_id: nlt$cl_connection_id);

      VAR
        root: nlt$cl_reference_number,
        number_of_roots: nlt$cl_connections_per_system,
        result: successful .. locked,
        initial_active,
        new_active,
        actual_active: integer,
        first_connection,
        stem: ^nlt$cl_connection,
        stem_length: nlt$cl_reference_number,
        ignore_status: ost$status;

?? NEWTITLE := '      decrement_active_connections', EJECT ??

      PROCEDURE [INLINE] decrement_active_connections
        (VAR actual_active {INPUT, OUTPUT} : integer);

        VAR
          result: successful .. locked,
          new_active: integer;

        new_active := actual_active - 1;
        REPEAT
          #COMPARE_SWAP (nlv$cl_connections.active, actual_active, new_active, actual_active, result);
          IF (result = failed) THEN
            new_active := actual_active - 1;
          IFEND;
        UNTIL (result = successful);
        nlv$cl_active_connections := new_active;
        actual_active := new_active;

      PROCEND decrement_active_connections;
?? TITLE := '      [INLINE] get_connection_id', EJECT ??

      PROCEDURE [INLINE] get_connection_id
        (VAR connection_id: nlt$cl_connection_id);

        VAR
          result: successful .. locked,
          initial_seed,
          new_seed: integer;

        initial_seed := 0;
        new_seed := 1;
        REPEAT
          #COMPARE_SWAP (nlv$cl_connections.cid_seed, initial_seed, new_seed, initial_seed, result);
          CASE result OF
          = successful =
            connection_id.sequence := (new_seed DIV (UPPERVALUE (nlt$cl_reference_number) + 1));
            connection_id.reference_number := (new_seed MOD (UPPERVALUE (nlt$cl_reference_number) + 1));
          = failed =
            IF (((initial_seed + 1) MOD (UPPERVALUE (nlt$cl_reference_number) + 1)) <> 0) THEN
              new_seed := initial_seed + 1;
            ELSE
              new_seed := initial_seed + 2;
            IFEND;
          = locked =
            ;
          CASEND;
        UNTIL (result = successful);

      PROCEND get_connection_id;
?? OLDTITLE ??
?? EJECT ??
      number_of_roots := UPPERBOUND (nlv$cl_connections.list^) + 1;
      connection^.nextt := NIL;
      connection_id_assigned := FALSE;

      REPEAT
        #COMPARE_SWAP (nlv$cl_connections.active, 0, 0, actual_active, result);
        IF (result = successful) THEN
          actual_active := 0;
        IFEND;
      UNTIL (result <> locked);

    /assign_id/
      WHILE (NOT connection_id_assigned AND (actual_active < nlv$maximum_system_connections)) DO
        initial_active := actual_active;
        get_connection_id (connection_id);
        root := (connection_id.reference_number MOD number_of_roots);
        new_active := initial_active + 1;

      /assign_connection/
        WHILE NOT connection_id_assigned DO
          #COMPARE_SWAP (nlv$cl_connections.active, initial_active, new_active, actual_active, result);
          CASE result OF
          = successful =
            nlv$cl_active_connections := new_active;
            get_exclusive_to_root (root);
            first_connection := nlv$cl_connections.list^ [root].first;

            IF (first_connection = NIL) THEN
              { Place connection at root. }
              nlv$cl_connections.list^ [root].first := connection;
              release_exclusive_to_root (root);
              connection_id_assigned := TRUE;
            ELSE
              stem := first_connection;
              stem_length := 1;

            /add_connection_to_stem/
              WHILE NOT connection_id_assigned DO
                IF (stem^.identifier.reference_number <> connection_id.reference_number) THEN
                  IF (stem^.nextt = NIL) THEN
                    IF (stem_length < ((actual_active DIV number_of_roots) + 1)) THEN
                      stem^.nextt := connection;
                      release_exclusive_to_root (root);
                      connection_id_assigned := TRUE;
                      IF (initial_active = 0) THEN
                        pmp$ready_task (nlv$timer_monitor_task, ignore_status);
                      IFEND;
                    ELSE
                      release_exclusive_to_root (root);
                      decrement_active_connections (actual_active);
                      CYCLE /assign_id/; {----->
                    IFEND;
                  ELSE
                    stem_length := stem_length + 1;
                    stem := stem^.nextt;
                  IFEND;
                ELSE
                  release_exclusive_to_root (root);
                  decrement_active_connections (actual_active);
                  CYCLE /assign_id/; {----->
                IFEND;
              WHILEND /add_connection_to_stem/;
            IFEND;

          = failed =
            initial_active := actual_active;
            new_active := initial_active + 1;
          = locked =
            ;
          CASEND;
        WHILEND /assign_connection/;
      WHILEND /assign_id/;

    PROCEND assign_connection_id;
?? OLDTITLE ??
?? EJECT ??

    IF nlv$maximum_system_connections > 0 THEN
      IF (nlv$cl_connections.list = NIL) THEN
        initialize_connection_list;
      IFEND;

      ALLOCATE connection IN osv$mainframe_wired_heap^;
      connection^ := v$null_cl_connection;
      pmp$get_executing_task_gtid (new_value.task_id);
      new_value.fill := 0;
      new_value.notify_system_task := FALSE;
      connection^.access_control := new_value;
      osp$begin_subsystem_activity;
      assign_connection_id (connection, connection_id_assigned, connection^.identifier);
      IF connection_id_assigned THEN
        connection^.application_layer := application_layer;
        IF (application_layer = nlc$tcp_interface) OR (application_layer = nlc$udp_interface) THEN
          connection^.queue_on_connection := TRUE;
          connection^.connection_queue.fill := 0;
          connection^.connection_queue.in_queue := FALSE;
          connection^.connection_queue.next_connection := NIL;
          connection^.input_queue.next_received_message := NIL;
          connection^.input_queue.fill := 0;
          connection^.active_receiver := NIL;
        IFEND;
        connection^.layer_connections := layer_connections;
        cl_connection := connection;
      ELSE
        FREE connection IN osv$mainframe_wired_heap^;
        osp$end_subsystem_activity;
        cl_connection := NIL;
      IFEND;
    ELSE
      cl_connection := NIL;
    IFEND;

  PROCEND nlp$cl_assign_connection;
?? TITLE := '  [INLINE] get_exclusive_to_root', EJECT ??

  PROCEDURE [INLINE] get_exclusive_to_root
    (    root: nlt$cl_reference_number);

    VAR
      result: successful .. locked,
      initial_root: nlt$cl_connection_root_access,
      new_root: nlt$cl_connection_root_access,
      actual_root: nlt$cl_connection_root_access;

    initial_root.value := 0;
    new_root := initial_root;
    new_root.exclusive := TRUE;

    osp$begin_subsystem_activity;
    REPEAT
      #COMPARE_SWAP (nlv$cl_connections.list^ [root].access_control, initial_root, new_root, actual_root,
            result);
      IF (result = failed) THEN
        osp$end_subsystem_activity;
        syp$cycle;
        osp$begin_subsystem_activity;
      IFEND;
    UNTIL (result = successful);
  PROCEND get_exclusive_to_root;
?? TITLE := '  [INLINE] get_nonexclusive_to_root', EJECT ??

  PROCEDURE [INLINE] get_nonexclusive_to_root
    (    root: nlt$cl_reference_number);

    VAR
      result: successful .. locked,
      new_root: nlt$cl_connection_root_access,
      actual_root: nlt$cl_connection_root_access;

    actual_root.value := 0;
    new_root := actual_root;
    new_root.nonexclusive_accessors := 1;

    REPEAT
      #COMPARE_SWAP (nlv$cl_connections.list^ [root].access_control, actual_root, new_root, actual_root,
            result);
      IF (result = failed) THEN
        IF actual_root.exclusive THEN
          syp$cycle;
          actual_root.exclusive := FALSE;
        IFEND;
        new_root.nonexclusive_accessors := actual_root.nonexclusive_accessors + 1;
      IFEND;
    UNTIL (result = successful);
  PROCEND get_nonexclusive_to_root;
?? TITLE := '  [XDCL, #GATE] nlp$cl_get_nonexclusive_to_root', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_get_nonexclusive_to_root
    (    root: nlt$cl_reference_number);

*copy nlh$cl_get_nonexclusive_to_root

    get_nonexclusive_to_root (root);
  PROCEND nlp$cl_get_nonexclusive_to_root;
?? TITLE := '  [INLINE] release_exclusive_to_root', EJECT ??

  PROCEDURE [INLINE] release_exclusive_to_root
    (    root: nlt$cl_reference_number);

    VAR
      result: successful .. locked,
      initial_root: nlt$cl_connection_root_access,
      new_root: nlt$cl_connection_root_access,
      actual_root: nlt$cl_connection_root_access;

    new_root.value := 0;
    initial_root := new_root;
    initial_root.exclusive := TRUE;

    REPEAT
      #COMPARE_SWAP (nlv$cl_connections.list^ [root].access_control, initial_root, new_root, actual_root,
            result);
    UNTIL (result = successful);
    osp$end_subsystem_activity;

  PROCEND release_exclusive_to_root;
?? TITLE := '  [INLINE] release_nonexclusive_to_root', EJECT ??

  PROCEDURE [INLINE] release_nonexclusive_to_root
    (    root: nlt$cl_reference_number);

    VAR
      result: successful .. locked,
      new_root: nlt$cl_connection_root_access,
      actual_root: nlt$cl_connection_root_access;

    new_root.value := 0;
    actual_root := new_root;
    actual_root.nonexclusive_accessors := 1;

  /release_root/
    REPEAT
      #COMPARE_SWAP (nlv$cl_connections.list^ [root].access_control, actual_root, new_root, actual_root,
            result);
      IF (result = failed) THEN
        new_root.nonexclusive_accessors := actual_root.nonexclusive_accessors - 1;
      IFEND;
    UNTIL (result = successful);

  PROCEND release_nonexclusive_to_root;
?? TITLE := '  [XDCL, #GATE] nlp$cl_release_nonexclu_to_root', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_release_nonexclu_to_root
    (    root: nlt$cl_reference_number);

*copy nlh$cl_release_nonexclu_to_root

    release_nonexclusive_to_root (root);
  PROCEND nlp$cl_release_nonexclu_to_root;
?? TITLE := '  [XDCL, #GATE] nlp$cl_get_connection_access', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_get_connection_access
    (    cl_connection: ^nlt$cl_connection;
     VAR access_gained: boolean);

*copy nlh$cl_get_connection_access

    VAR
      actual_value: nlt$cl_connection_access,
      connection: ^nlt$cl_connection,
      cs_status: successful .. locked,
      new_value: nlt$cl_connection_access;

    connection := #ADDRESS (1, #SEGMENT (cl_connection), #OFFSET (cl_connection));
    pmp$get_executing_task_gtid (new_value.task_id);
    new_value.fill := 0;
    new_value.notify_system_task := FALSE;
    osp$begin_subsystem_activity;
    REPEAT
      #COMPARE_SWAP (connection^.access_control, v$unlocked_connection_access, new_value, actual_value,
            cs_status);
    UNTIL cs_status <> locked;
    access_gained := (cs_status = successful);
    IF NOT access_gained THEN
      IF (actual_value.task_id <> new_value.task_id) THEN
        osp$end_subsystem_activity;
      ELSE
        osp$system_error ('NAM/VE - lock already set by current task', NIL);
      IFEND;
    IFEND;
  PROCEND nlp$cl_get_connection_access;
?? TITLE := '  [XDCL, #GATE] nlp$cl_release_connection', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_release_connection
    (    connection_id: nlt$cl_connection_id);

*copy nlh$cl_release_connection

    VAR
      actual_cl_access: nlt$cl_connection_access,
      root: nlt$cl_reference_number,
      connection: ^^nlt$cl_connection,
      connection_to_free: ^nlt$cl_connection,
      connection_exists: boolean,
      initial_cl_access: nlt$cl_connection_access,
      new_cl_access: nlt$cl_connection_access,
      result: successful .. locked,
      initial_active,
      new_active,
      actual_active: integer;

    root := (connection_id.reference_number MOD (UPPERBOUND (nlv$cl_connections.list^) + 1));
    get_exclusive_to_root (root);
    connection := ^nlv$cl_connections.list^ [root].first;
    connection_exists := FALSE;

    WHILE (NOT connection_exists AND (connection^ <> NIL)) DO
      IF (connection^^.identifier = connection_id) THEN
        connection_exists := TRUE;
        pmp$get_executing_task_gtid (new_cl_access.task_id);
        new_cl_access.fill := 0;
        new_cl_access.notify_system_task := FALSE;
        REPEAT
          #COMPARE_SWAP (connection^^.access_control, v$unlocked_connection_access, new_cl_access,
                actual_cl_access, result);
        UNTIL result <> locked;
        IF result = successful THEN
          IF connection^^.layers_active = $nlt$cl_layers [] THEN
            connection_to_free := connection^;
            connection^ := connection^^.nextt;
            FREE connection_to_free^.layer_connections IN nav$network_paged_heap^;
            FREE connection_to_free IN osv$mainframe_wired_heap^;
            release_exclusive_to_root (root);

            initial_active := 1;
            new_active := 0;

          /decrement_active_connections/
            REPEAT
              #COMPARE_SWAP (nlv$cl_connections.active, initial_active, new_active, initial_active, result);
              IF (result = failed) THEN
                new_active := initial_active - 1;
              IFEND;
            UNTIL (result = successful);
            nlv$cl_active_connections := new_active;
          ELSE { layers active

{ Unlock the connection.

            initial_cl_access := new_cl_access;
            REPEAT
              #COMPARE_SWAP (connection^^.access_control, initial_cl_access, v$unlocked_connection_access,
                    actual_cl_access, result);
              IF result = failed THEN
                IF actual_cl_access.task_id = initial_cl_access.task_id THEN
                  initial_cl_access := actual_cl_access;
                ELSE
                  osp$system_error ('NAM/VE - lock not locked by current task', NIL);
                IFEND;
              IFEND;
            UNTIL result = successful;

            IF actual_cl_access.notify_system_task THEN
              notify_system_task;
            IFEND;
            release_exclusive_to_root (root);
          IFEND;
        ELSEIF actual_cl_access.task_id <> new_cl_access.task_id THEN
          release_exclusive_to_root (root);
        ELSE
          osp$system_error ('NAM/VE - lock already set by current task', NIL);
        IFEND;
      ELSE
        connection := ^connection^^.nextt;
      IFEND;
    WHILEND;
  PROCEND nlp$cl_release_connection;
?? TITLE := '  [XDCL, #GATE] nlp$cl_recover_cid_seed', EJECT ??

  PROCEDURE [XDCL, #GATE] nlp$cl_recover_cid_seed;

*copy nlh$cl_recover_cid_seed

    VAR
      image_descriptor: dst$nve_image_descriptor,
      rmfwsn: ost$segment, {recoverd mainframe wired segment number}
      system_core_id: ^ost$name,
      cid_seed: ^integer;

    VAR
      syv$recovery_override: [XREF] 0 .. 0ff(16);

    dsp$get_nve_image_description (image_descriptor);
    IF (image_descriptor.rcv_mainframe_wired_segment <> NIL) THEN
      rmfwsn := #SEGMENT (image_descriptor.rcv_mainframe_wired_segment);
      IF (image_descriptor.rcv_page_size = osv$page_size) THEN

        { Image file required from this point on !!!!!

        system_core_id := #ADDRESS (1, rmfwsn, #OFFSET (^jmv$system_core_id));
        IF (system_core_id^ = jmv$system_core_id) OR (syv$recovery_override <> 0) THEN
          cid_seed := #ADDRESS (1, rmfwsn, #OFFSET (^nlv$cl_connections.cid_seed));
          nlv$cl_connections.cid_seed := (cid_seed^ MOD (UPPERVALUE (nlt$cl_reference_number) + 1));
        IFEND;
      IFEND;
    IFEND;
  PROCEND nlp$cl_recover_cid_seed;
MODEND nlm$cl_connection_manager_r1;
