?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Network Access: Ring 3 Service Routines For Socket Layer' ??
MODULE nlm$sk_service_routines_r3;

{ PURPOSE:
{   This module contains procedures that execute in ring 3 and are needed to service
{   the NAM/VE Socket Layer.
{ DESIGN:
{   These procedures are called by the socket layer external interface code.
{   The XDCL'd procedures have been grouped in alphabetical order
{   followed by the internal procedures. The internal procedures are also in alphabetical
{   order.
{   This module contains code that resides on OSF$JOB_TEMPLATE_23D.
{
{ NOTES:
{   The following abbreviations have been used in this module:
{          TCP - Transmission Control Protocol
{          UDP - User Datagram Protocol

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc jmt$system_supplied_name
*copyc jmt$user_supplied_name
*copyc nae$sk_socket_layer
*copyc nat$connection_id
*copyc nat$wait_time
*copyc nlt$sk_offered_socket
*copyc nlt$sk_offered_sockets_list
*copyc nlt$tcp_socket_layer
*copyc nlt$tcp_socket_type
*copyc nlt$udp_global_socket
*copyc nlt$udp_global_socket_id
*copyc ost$caller_identifier
*copyc ost$global_task_id
*copyc ost$signature_lock_status
*copyc ost$status
?? POP ??
*copyc avp$get_capability
*copyc jmp$job_exists
*copyc nap$condition_handler_trace
*copyc nap$namve_system_error
*copyc nlp$cl_get_exclusive_via_cid
*copyc nlp$cl_get_layer_connection
*copyc nlp$cl_release_exclusive_access
*copyc nlp$udp_free_exclusive_access
*copyc nlp$udp_get_exclusive_via_gsid
*copyc osp$clear_job_signature_lock
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_job_signature_lock
*copyc osp$set_status_abnormal
*copyc osp$test_signature_lock
*copyc pmp$get_executing_task_gtid
*copyc pmp$get_job_names
*copyc pmp$ready_task
*copyc pmp$wait
*copyc syp$cycle
*copyc nav$network_paged_heap
*copyc nlv$sk_offered_sockets_list

?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$sk_accept_socket_offer', EJECT ??
*copy nlh$sk_accept_socket_offer

  PROCEDURE [XDCL] nlp$sk_accept_socket_offer
    (    source_job: jmt$system_supplied_name;
         socket_id: nat$sk_socket_identifier;
         time_stamp: ost$free_running_clock;
         wait_time: nat$wait_time;
     VAR socket_type: nat$sk_socket_type;
     VAR global_socket_id: nlt$udp_global_socket_id;
     VAR connection_id: nat$connection_id;
     VAR tcp_socket_type: nlt$tcp_socket_type;
     VAR bound_address: nat$sk_ip_address;
     VAR port: nat$sk_port_number;
     VAR traffic_pattern: nat$sk_traffic_pattern;
     VAR application: nat$application_name;
     VAR ring: ost$ring;
     VAR capability: ost$name;
     VAR status: ost$status);

?? NEWTITLE := 'terminate_accept_socket_offer', EJECT ??

    PROCEDURE terminate_accept_socket_offer
      (    condition: pmt$condition;
           condition_descriptor: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

    VAR
      lock_status: ost$signature_lock_status;

      nap$condition_handler_trace (condition, save_area);
      osp$test_signature_lock (nlv$sk_offered_sockets_list.lock, lock_status);
      IF lock_status <> osc$sls_locked_by_another_task THEN
        IF lock_status = osc$sls_not_locked THEN
          osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);
        IFEND;
        remove_wait_for_socket_offer (current_task_id, source_job);
        osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
      IFEND;
      handler_status.normal := TRUE;

    PROCEND terminate_accept_socket_offer;
?? OLDTITLE, EJECT ??

    VAR
      caller_id: ost$caller_identifier,
      capability_required: boolean,
      cl_connection: ^nlt$cl_connection,
      connection_exists: boolean,
      current_job_name: jmt$system_supplied_name,
      current_task_id: ost$global_task_id,
      current_time: ost$free_running_clock,
      end_time: integer,
      global_socket: ^nlt$udp_global_socket,
      layer_active: boolean,
      offered_socket: ^nlt$sk_offered_socket,
      previous_wait_for_socket_offer: ^^nlt$sk_wait_for_socket_offer,
      remaining_time: integer,
      task_queued: boolean,
      tcp_connection: ^nlt$tcp_socket_layer,
      user_supplied_name: jmt$user_supplied_name,
      wait_for_socket_offer: ^nlt$sk_wait_for_socket_offer;

    pmp$get_job_names (user_supplied_name, current_job_name, {ignore} status);
    pmp$get_executing_task_gtid (current_task_id);
    status.normal := TRUE;
    #CALLER_ID (caller_id);
    task_queued := FALSE;
    end_time := #FREE_RUNNING_CLOCK (0) + wait_time*1000;
    remaining_time := wait_time;
    osp$establish_block_exit_hndlr (^terminate_accept_socket_offer);

  /accept_socket_offer/
    REPEAT
      osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);

{ Search for socket offer from the given source job to the current job.

      offered_socket := nlv$sk_offered_sockets_list.offered_socket;
      WHILE (offered_socket <> NIL) AND ((offered_socket^.source_job <> source_job) OR
            (offered_socket^.destination_job <> current_job_name) OR
            (offered_socket^.status <> nlc$sk_offer_pending)) DO
        offered_socket := offered_socket^.next_entry;
      WHILEND;

      IF offered_socket <> NIL THEN

{ Validate caller's ring.

        IF caller_id.ring <= offered_socket^.ring THEN
          IF offered_socket^.capability <> osc$null_name THEN
            offered_socket^.status := nlc$sk_offer_being_validated;
            capability := offered_socket^.capability;
            osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
            avp$get_capability (capability, avc$user, capability_required, status);
            IF NOT capability_required THEN
              osp$set_status_abnormal ('AV', ave$missing_required_capability, capability, status);
            IFEND;
            IF NOT status.normal THEN
              IF task_queued THEN
                osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);
                remove_wait_for_socket_offer (current_task_id, source_job);
                osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
              IFEND;
              EXIT /accept_socket_offer/;
            ELSE  { valid user
              osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);

{ Search the offered socket from the given source job and with status of
{ nlc$sk_offer_being_validated. This is necessary because the socket
{ offer could have been canceled in the meantime.

              offered_socket := nlv$sk_offered_sockets_list.offered_socket;
              WHILE (offered_socket <> NIL) AND ((offered_socket^.source_job <> source_job) OR
                    (offered_socket^.destination_job <> current_job_name) OR
                    (offered_socket^.status <> nlc$sk_offer_being_validated)) DO
                offered_socket := offered_socket^.next_entry;
              WHILEND;
            IFEND;
          IFEND;
        ELSE { invalid user
          IF task_queued THEN
            remove_wait_for_socket_offer (current_task_id, source_job);
          IFEND;
          osp$set_status_abnormal (nac$status_id, nae$sk_invalid_user, 'NAP$SK_ACCEPT_SOCKET_OFFER',
                status);
          osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
          EXIT /accept_socket_offer/;
        IFEND;
      IFEND;
        IF offered_socket <> NIL THEN
           offered_socket^.status := nlc$sk_offer_accepted;
           socket_type := offered_socket^.socket_type;
           bound_address := offered_socket^.bound_address;
           traffic_pattern := offered_socket^.traffic_pattern;
           port := offered_socket^.port;
           application := offered_socket^.application;
           ring := offered_socket^.ring;
           capability := offered_socket^.capability;
           IF socket_type = nac$sk_udp_socket THEN
             global_socket_id := offered_socket^.global_socket_id;
             nlp$udp_get_exclusive_via_gsid (global_socket_id, global_socket);
             IF global_socket <> NIL THEN

{ Just reuse the existing global socket.
{ Store the new job socket id and the time stamp in the global socket structure.
{ Note that if the global socket has been terminated, it will be switched to the
{ accepting job.

                IF global_socket^.status = nlc$udp_global_socket_offered THEN
                  global_socket^.status := nlc$udp_global_socket_open;
                IFEND;
                global_socket^.local_socket_id := socket_id;
                global_socket^.time_stamp := time_stamp;
                nlp$udp_free_exclusive_access (global_socket);
              IFEND;
            ELSE
             connection_id := offered_socket^.connection_id;
             tcp_socket_type := offered_socket^.tcp_socket_type;
             nlp$cl_get_exclusive_via_cid (offered_socket^.connection_id, connection_exists,
                    cl_connection);
             IF cl_connection <> NIL THEN
               nlp$cl_get_layer_connection (nlc$tcp_interface, cl_connection, layer_active,
                      tcp_connection);
               IF layer_active THEN
                 IF tcp_connection^.state = nlc$tcp_conn_offered THEN
                   tcp_connection^.state := nlc$tcp_conn_open;
                   tcp_connection^.socket_id := socket_id;
                 ELSEIF (tcp_connection^.state = nlc$tcp_conn_closed) OR
                   (tcp_connection^.state = nlc$tcp_conn_closing) OR
                   (tcp_connection^.state = nlc$tcp_conn_terminated) THEN

{ Do not update the state of the connection.

                      tcp_connection^.socket_id := socket_id;
                  IFEND;
                ELSE { Layer inactive
{ The connection is assumed to have been terminated via application mangement.
{ Note a terminated connection is being switched.
                  IFEND;
                  nlp$cl_release_exclusive_access (cl_connection);
                ELSE { cl_connection = NIL
{ The connection is assumed to have been terminated via application mangement.
{ Note a terminated connection is being switched.
                IFEND;
              IFEND;

            IF offered_socket^.waiting_task.index <> 0 THEN
              pmp$ready_task (offered_socket^.waiting_task, {ignore} status);
              status.normal := TRUE;
            IFEND;

{ The task offering the socket will dequeue the task from the wait for socket offer queue.

            osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
            EXIT /accept_socket_offer/;
      ELSE { No socket offer
        IF remaining_time > 0 THEN

{ Queue the task in the wait for socket offer queue (if not already queued).

          IF NOT task_queued THEN
            REPEAT
              ALLOCATE wait_for_socket_offer IN nav$network_paged_heap^;
              IF wait_for_socket_offer = NIL THEN
                syp$cycle;
              IFEND;
            UNTIL wait_for_socket_offer <> NIL;
            wait_for_socket_offer^.next_entry := NIL;
            wait_for_socket_offer^.waiting_task_id := current_task_id;
            wait_for_socket_offer^.waiting_job := current_job_name;
            wait_for_socket_offer^.source_job := source_job;
            previous_wait_for_socket_offer := ^nlv$sk_offered_sockets_list.wait_for_socket_offer;
            WHILE (previous_wait_for_socket_offer^ <> NIL) DO
              previous_wait_for_socket_offer := ^previous_wait_for_socket_offer^^.next_entry;
            WHILEND;
            previous_wait_for_socket_offer^ := wait_for_socket_offer;
            task_queued := TRUE;
          IFEND;
          osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
          pmp$wait (remaining_time, remaining_time);
          current_time := #FREE_RUNNING_CLOCK (0);
          IF current_time < end_time THEN
            remaining_time := (end_time - current_time) DIV 1000;
          ELSE
            remaining_time := 0;
          IFEND;
        ELSE { Remaining_time = 0

{ Dequeue the task from the wait for socket offer queue (if queued).

          IF task_queued THEN
            task_queued := FALSE;
            remove_wait_for_socket_offer (current_task_id, source_job);
          IFEND;
          osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
          osp$set_status_abnormal (nac$status_id, nae$sk_no_socket_offered, source_job, status);
        IFEND;
      IFEND;
    UNTIL (NOT status.normal);

    osp$disestablish_cond_handler;

  PROCEND nlp$sk_accept_socket_offer;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$sk_await_socket_offer', EJECT ??
*copy nlh$sk_await_socket_offer

  PROCEDURE [XDCL] nlp$sk_await_socket_offer
    (    source_job: jmt$system_supplied_name;
         wait: boolean;
     VAR activity_complete: boolean);

    VAR
      current_job_name: jmt$system_supplied_name,
      current_task_id: ost$global_task_id,
      ignore_status: ost$status,
      offered_socket: ^nlt$sk_offered_socket,
      previous_offered_socket: ^^nlt$sk_offered_socket,
      previous_wait_for_socket_offer: ^^nlt$sk_wait_for_socket_offer,
      user_supplied_name: jmt$user_supplied_name,
      wait_for_socket_offer: ^nlt$sk_wait_for_socket_offer;

    activity_complete := FALSE;
    pmp$get_executing_task_gtid (current_task_id);
    pmp$get_job_names (user_supplied_name, current_job_name, ignore_status);
    osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);

{ Check if a socket offer has been made by the source job.

    offered_socket := nlv$sk_offered_sockets_list.offered_socket;
    WHILE (offered_socket <> NIL) AND ((offered_socket^.source_job <> source_job) OR
          (offered_socket^.destination_job <> current_job_name)) DO
      offered_socket := offered_socket^.next_entry;
    WHILEND;
    IF offered_socket <> NIL THEN
      activity_complete := TRUE;
    ELSEIF wait THEN

{ Queue the task in the wait for socket offer list (if not already queued).

      previous_wait_for_socket_offer := ^nlv$sk_offered_sockets_list.wait_for_socket_offer;
      WHILE (previous_wait_for_socket_offer^ <> NIL) AND (previous_wait_for_socket_offer^^.
            waiting_task_id <> current_task_id) DO
        previous_wait_for_socket_offer := ^previous_wait_for_socket_offer^^.next_entry;
      WHILEND;
      IF previous_wait_for_socket_offer^ = NIL THEN
        REPEAT
          ALLOCATE wait_for_socket_offer IN nav$network_paged_heap^;
          IF wait_for_socket_offer = NIL THEN
            syp$cycle;
          IFEND;
        UNTIL wait_for_socket_offer <> NIL;
        wait_for_socket_offer^.next_entry := NIL;
        wait_for_socket_offer^.waiting_task_id := current_task_id;
        wait_for_socket_offer^.waiting_job := current_job_name;
        wait_for_socket_offer^.source_job := source_job;
        previous_wait_for_socket_offer^ := wait_for_socket_offer;
      IFEND;
    IFEND;

    osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);

  PROCEND nlp$sk_await_socket_offer;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$sk_offer_socket', EJECT ??
*copy nlh$sk_offer_socket

  PROCEDURE [XDCL] nlp$sk_offer_socket
    (    socket_id: nat$sk_socket_identifier;
         destination_job: jmt$system_supplied_name;
         socket_type: nat$sk_socket_type;
         global_socket_id: nlt$udp_global_socket_id;
         connection_id: nat$connection_id;
         tcp_socket_type: nlt$tcp_socket_type;
         port: nat$sk_port_number;
         bound_address: nat$sk_ip_address;
         traffic_pattern: nat$sk_traffic_pattern;
         application: nat$application_name;
         ring: ost$ring;
         capability: ost$name;
         wait_time: nat$wait_time;
     VAR offer_accepted: boolean);

?? NEWTITLE := 'terminate_offer_socket', EJECT ??

    PROCEDURE terminate_offer_socket
      (    condition: pmt$condition;
           condition_descriptor: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

    VAR
      lock_status: ost$signature_lock_status;

      nap$condition_handler_trace (condition, save_area);
      osp$test_signature_lock (nlv$sk_offered_sockets_list.lock, lock_status);
      IF lock_status <> osc$sls_locked_by_another_task THEN
        IF lock_status = osc$sls_not_locked THEN
          osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);
        IFEND;

{ Remove the offered socket.

        offered_socket := nlv$sk_offered_sockets_list.offered_socket;
        previous_offered_socket := ^nlv$sk_offered_sockets_list.offered_socket;
        WHILE (offered_socket <> NIL) AND ((offered_socket^.socket_id <> socket_id) OR
              (offered_socket^.source_job <> current_job_name)) DO
          previous_offered_socket := ^offered_socket^.next_entry;
          offered_socket := offered_socket^.next_entry;
        WHILEND;

        IF offered_socket <> NIL THEN
          offer_accepted := offered_socket^.status = nlc$sk_offer_accepted;

{ Remove the offered socket entry from the list.

          previous_offered_socket^ := offered_socket^.next_entry;
          FREE offered_socket IN nav$network_paged_heap^;
        IFEND;
        osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
      IFEND;
      handler_status.normal := TRUE;

    PROCEND terminate_offer_socket;
?? OLDTITLE, EJECT ??

    CONST
      poll_time = 5000;

    VAR
      current_job_name: jmt$system_supplied_name,
      current_task_id: ost$global_task_id,
      current_time: ost$free_running_clock,
      destination_job_exists: boolean,
      end_time: integer,
      ignore_status: ost$status,
      offered_socket: ^nlt$sk_offered_socket,
      previous_offered_socket: ^^nlt$sk_offered_socket,
      previous_wait_for_socket_offer: ^^nlt$sk_wait_for_socket_offer,
      remaining_time: integer,
      user_supplied_name: jmt$user_supplied_name,
      wait_for_socket_offer: ^nlt$sk_wait_for_socket_offer;

    offer_accepted := FALSE;

{ If the destination job does not exist, there is no point in proceeding.

    jmp$job_exists (destination_job, $jmt$job_state_set [jmc$queued_job, jmc$initiated_job],
          destination_job_exists, ignore_status);
    IF NOT destination_job_exists THEN
      RETURN;
    IFEND;

    pmp$get_job_names (user_supplied_name, current_job_name, ignore_status);
    pmp$get_executing_task_gtid (current_task_id);
    REPEAT
      ALLOCATE offered_socket IN nav$network_paged_heap^;
      IF offered_socket = NIL THEN
        syp$cycle;
      IFEND;
    UNTIL offered_socket <> NIL;
    offered_socket^.next_entry := NIL;
    offered_socket^.socket_id := socket_id;
    offered_socket^.status := nlc$sk_offer_pending;
    offered_socket^.source_job := current_job_name;
    offered_socket^.application := application;
    offered_socket^.ring := ring;
    offered_socket^.capability := capability;
    offered_socket^.system_privilege := FALSE;
    offered_socket^.port := port;
    offered_socket^.bound_address := bound_address;
    offered_socket^.traffic_pattern := traffic_pattern;
    offered_socket^.socket_type := socket_type;
    IF socket_type = nac$sk_udp_socket THEN
      offered_socket^.global_socket_id := global_socket_id;
    ELSE
      offered_socket^.connection_id := connection_id;
      offered_socket^.tcp_socket_type := tcp_socket_type;
    IFEND;

    offered_socket^.destination_job := destination_job;
    IF wait_time > 0 THEN
      offered_socket^.waiting_task := current_task_id;
    ELSE
      offered_socket^.waiting_task.index := 0;
    IFEND;

    osp$establish_block_exit_hndlr (^terminate_offer_socket);
    osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);

{ Add the offered socket entry at the end of the list.

    previous_offered_socket := ^nlv$sk_offered_sockets_list.offered_socket;
    WHILE previous_offered_socket^ <> NIL DO
      previous_offered_socket := ^previous_offered_socket^^.next_entry;
    WHILEND;
    previous_offered_socket^ := offered_socket;

{ Search the wait for socket offer list for a task waiting for a socket offer
{ from the current job.

    previous_wait_for_socket_offer := ^nlv$sk_offered_sockets_list.wait_for_socket_offer;
    wait_for_socket_offer := nlv$sk_offered_sockets_list.wait_for_socket_offer;
    WHILE (wait_for_socket_offer <> NIL) AND ((wait_for_socket_offer^.source_job <>
      current_job_name) OR (wait_for_socket_offer^.waiting_job <> destination_job)) DO
      previous_wait_for_socket_offer := ^wait_for_socket_offer^.next_entry;
      wait_for_socket_offer := wait_for_socket_offer^.next_entry;
    WHILEND;

    IF wait_for_socket_offer <> NIL THEN
      pmp$ready_task (wait_for_socket_offer^.waiting_task_id, ignore_status);

{ Delink the wait for socket offer entry.

      previous_wait_for_socket_offer^ := wait_for_socket_offer^.next_entry;
      FREE wait_for_socket_offer IN nav$network_paged_heap^;
    IFEND;

    osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);

{ Wait for the socket offer to be accepted.

    end_time := #FREE_RUNNING_CLOCK (0) + wait_time*1000;
    remaining_time := wait_time;
    IF remaining_time > poll_time THEN
      remaining_time := poll_time;
    IFEND;
    REPEAT
      IF remaining_time > 0 THEN
        pmp$wait (remaining_time, remaining_time);
        current_time := #FREE_RUNNING_CLOCK (0);
        IF current_time < end_time THEN
          remaining_time := (end_time - current_time) DIV 1000;
          IF remaining_time > poll_time THEN
            remaining_time := poll_time;
          IFEND;
        ELSE
          remaining_time := 0;
        IFEND;
      IFEND;

{ Check if the socket offer has been accepted.

      osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);

{ Find the offered socket matching the given socket id and the destination job name.

      offered_socket := nlv$sk_offered_sockets_list.offered_socket;
      previous_offered_socket := ^nlv$sk_offered_sockets_list.offered_socket;
      WHILE (offered_socket <> NIL) AND ((offered_socket^.socket_id <> socket_id) OR
            (offered_socket^.source_job <> current_job_name)) DO
        previous_offered_socket := ^offered_socket^.next_entry;
        offered_socket := offered_socket^.next_entry;
      WHILEND;

      IF offered_socket <> NIL THEN
        jmp$job_exists (destination_job, $jmt$job_state_set [jmc$queued_job, jmc$initiated_job],
              destination_job_exists, ignore_status);
        IF (offered_socket^.status = nlc$sk_offer_accepted) OR (remaining_time = 0) OR
              (NOT destination_job_exists) THEN
          offer_accepted := offered_socket^.status = nlc$sk_offer_accepted;

{ Remove the offered socket entry from the list.

          previous_offered_socket^ := offered_socket^.next_entry;
          FREE offered_socket IN nav$network_paged_heap^;
        IFEND;
      ELSE
        nap$namve_system_error ( {Recoverable_error=} TRUE, 'Lost offered socket entry for the current job.',
              NIL);
        remaining_time := 0; { Terminate request }
      IFEND;
      osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);
    UNTIL (offer_accepted) OR (remaining_time <= 0) OR (NOT destination_job_exists);

    osp$disestablish_cond_handler;

  PROCEND nlp$sk_offer_socket;
?? OLDTITLE ??
?? NEWTITLE := 'nlp$sk_remove_wait_socket_offer', EJECT ??
*copy nlh$sk_remove_wait_socket_offer

  PROCEDURE [XDCL] nlp$sk_remove_wait_socket_offer
    (    source_job: jmt$system_supplied_name);

    VAR
      current_task_id: ost$global_task_id;

    pmp$get_executing_task_gtid (current_task_id);
    osp$set_job_signature_lock (nlv$sk_offered_sockets_list.lock);
    remove_wait_for_socket_offer (current_task_id, source_job);
    osp$clear_job_signature_lock (nlv$sk_offered_sockets_list.lock);

  PROCEND nlp$sk_remove_wait_socket_offer;
?? OLDTITLE ??
?? NEWTITLE := '[INLINE] remove_wait_for_socket_offer', EJECT ??
{ PURPOSE:
{   The purpose of this procedure is to remove the given task from
{   the queue of tasks waiting for socket offer from specified jobs.

  PROCEDURE [INLINE] remove_wait_for_socket_offer (
    current_task_id: ost$global_task_id;
    source_job: jmt$system_supplied_name);

    VAR
      previous_wait_for_socket_offer: ^^nlt$sk_wait_for_socket_offer,
      wait_for_socket_offer: ^nlt$sk_wait_for_socket_offer;

    previous_wait_for_socket_offer := ^nlv$sk_offered_sockets_list.wait_for_socket_offer;
    wait_for_socket_offer := nlv$sk_offered_sockets_list.wait_for_socket_offer;
    WHILE (wait_for_socket_offer <> NIL) AND ((wait_for_socket_offer^.waiting_task_id <>
          current_task_id) OR (wait_for_socket_offer^.source_job <> source_job)) DO
      previous_wait_for_socket_offer := ^wait_for_socket_offer^.next_entry;
      wait_for_socket_offer := wait_for_socket_offer^.next_entry;
    WHILEND;
    IF wait_for_socket_offer <> NIL THEN
      previous_wait_for_socket_offer^ := wait_for_socket_offer^.next_entry;
      FREE wait_for_socket_offer IN nav$network_paged_heap^;
    IFEND;

  PROCEND remove_wait_for_socket_offer;
?? OLDTITLE ??
MODEND nlm$sk_service_routines_r3;
