?? RIGHT := 110 ??
?? NEWTITLE := '  NOS/VE: Program Management - Task End Handler Interfaces', EJECT ??
MODULE pmm$end_handler_processing;
?? RIGHT := 110 ??

{  PURPOSE:
{    This module contains program services for establishing and
{  disestablishing handlers that execute at task termination for
{  the purpose of task cleanup.
{
{  DESIGN:
{    Task end handlers are queued in task private lists for each ring
{  and are called during task termination cleanup.
{
?? EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cyd$cybil_structure_definitions
*copyc osd$virtual_address
*copyc ost$caller_identifier
*copyc ost$status
*copyc oss$task_private
*copyc osv$task_private_heap
*copyc pme$condition_exceptions

?? POP ??
*copyc pmp$task_state
*copyc pmt$end_handler_desc
*copyc osp$set_status_abnormal

  VAR
    pmv$end_handler_list: [XDCL, STATIC, oss$task_private] ^pmt$end_handler_ring_list := NIL;

?? TITLE := '  [XDCL, #GATE] pmp$establish_end_handler', EJECT ??

  PROCEDURE [XDCL, #GATE] pmp$establish_end_handler
    (    end_handler: pmt$end_handler;
     VAR status: ost$status);

    VAR
      caller: ost$caller_identifier;

    #CALLER_ID (caller);
    pmp$establish_end_hndlr_in_ring (end_handler, caller.ring, status);

  PROCEND pmp$establish_end_handler;

?? TITLE := '  [XDCL, #GATE] pmp$establish_end_hndlr_in_ring', EJECT ??

  PROCEDURE [XDCL, #GATE] pmp$establish_end_hndlr_in_ring
    (    end_handler: pmt$end_handler;
         ring: ost$ring;
     VAR status: ost$status);

    VAR
      converter: record
        case 0 .. 1 of
        = 0 =
          end_handler: pmt$end_handler,
        = 1 =
          pointer_to_procedure: cyt$pointer_to_procedure,
        casend,
      recend;

    VAR
      caller: ost$caller_identifier,
      ring_index: ost$ring,
      handler_list: ^pmt$end_handler_ring_list,
      desc_ptr: ^pmt$end_handler_desc,
      cur_ptr: ^pmt$end_handler_desc;

    #CALLER_ID (caller);
    status.normal := TRUE;

    IF pmp$task_state () <> pmc$task_active THEN
      osp$set_status_abnormal (pmc$program_management_id, pme$handler_queue_error, '', status);
      RETURN; {----->
    IFEND;

    IF (caller.ring > ring) THEN
      osp$set_status_abnormal (pmc$program_management_id, pme$handler_more_privileged, '', status);
      RETURN; {----->
    IFEND;

    IF pmv$end_handler_list = NIL THEN
      ALLOCATE handler_list IN osv$task_private_heap^;
      FOR ring_index := LOWERBOUND (pmt$end_handler_ring_list) TO UPPERBOUND (pmt$end_handler_ring_list) DO
        handler_list^ [ring_index] := NIL;
      FOREND;
      pmv$end_handler_list := handler_list;
    IFEND;

    converter.end_handler := end_handler;
    IF converter.pointer_to_procedure.static_link <> NIL THEN
      osp$set_status_abnormal (pmc$program_management_id, pme$handler_nested_proc, '', status);
      RETURN; {----->
    IFEND;

    ALLOCATE desc_ptr IN osv$task_private_heap^;

    desc_ptr^.end_handler := end_handler;
    desc_ptr^.disestablished := FALSE;
    desc_ptr^.called := FALSE;
    desc_ptr^.link := NIL;

    IF pmv$end_handler_list^ [ring] = NIL THEN
      pmv$end_handler_list^ [ring] := desc_ptr;
    ELSE
      cur_ptr := pmv$end_handler_list^ [ring];
      WHILE cur_ptr^.link <> NIL DO
        cur_ptr := cur_ptr^.link;
      WHILEND;
      cur_ptr^.link := desc_ptr;
    IFEND;

  PROCEND pmp$establish_end_hndlr_in_ring;

?? TITLE := '  [XDCL, #GATE] pmp$disestablish_end_handler', EJECT ??

  PROCEDURE [XDCL, #GATE] pmp$disestablish_end_handler
    (    end_handler: pmt$end_handler;
     VAR status: ost$status);

    VAR
      caller: ost$caller_identifier;

    #CALLER_ID (caller);
    pmp$disestab_end_hndlr_in_ring (end_handler, caller.ring, status);

  PROCEND pmp$disestablish_end_handler;
?? TITLE := '  [XDCL, #GATE] pmp$disestab_end_hndlr_in_ring', EJECT ??

  PROCEDURE [XDCL, #GATE] pmp$disestab_end_hndlr_in_ring
    (    end_handler: pmt$end_handler;
         ring: ost$ring;
     VAR status: ost$status);

    VAR
      cur_ptr: ^pmt$end_handler_desc,
      dis_ptr: ^pmt$end_handler_desc,
      caller: ost$caller_identifier;

    #CALLER_ID (caller);

    status.normal := TRUE;

    IF (caller.ring > ring) THEN
      osp$set_status_abnormal (pmc$program_management_id, pme$handler_more_privileged, '', status);
      RETURN; {----->
    IFEND;

    IF pmv$end_handler_list = NIL THEN
      osp$set_status_abnormal (pmc$program_management_id, pme$no_established_handler, '', status);
      RETURN; {----->
    IFEND;


    cur_ptr := pmv$end_handler_list^ [ring];
    dis_ptr := NIL;

    WHILE cur_ptr <> NIL DO
      IF (cur_ptr^.end_handler = end_handler) AND (NOT cur_ptr^.disestablished) AND (NOT cur_ptr^.called) THEN
        dis_ptr := cur_ptr;
      IFEND;
      cur_ptr := cur_ptr^.link;
    WHILEND;

    IF dis_ptr = NIL THEN
      osp$set_status_abnormal (pmc$program_management_id, pme$no_established_handler, '', status);
    ELSE
      dis_ptr^.disestablished := TRUE;
    IFEND;

  PROCEND pmp$disestab_end_hndlr_in_ring;

MODEND pmm$end_handler_processing;
