?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE: Program Control - Preemptive Communications' ??
?? NEWTITLE := '  tmm$manage_signals_and_flags - Global System Declarations' ??
{   PURPOSE:
{    The purpose of this module is to package the contained procedures
{    so that they have the privilege necessary to read the XCB and to
{    read/write job pageable.

{   DESIGN:
{    The procedures contained in this module have an execution bracket
{    of 2, 2 and a call bracket of 3.

?? EJECT ??
MODULE tmm$manage_signals_and_flags;
?? SET (LIST := OFF) ??
*copyc OST$EXECUTION_CONTROL_BLOCK
*copyc OST$CALLER_IDENTIFIER
*copyc OSE$HEAP_FULL_EXCEPTIONS
*copyc PMC$PROGRAM_MANAGEMENT_ID
*copyc OSV$JOB_PAGEABLE_HEAP
?? SET (LIST := ON) ??
?? TITLE := '  tmm$manage_signals_and_flags - Global External Procedures' ??
?? EJECT ??

*copyc I#DISABLE_TRAPS
*copyc I#RESTORE_TRAPS
*copyc PMP$FIND_EXECUTING_TASK_XCB
*copyc PMP$FIND_EXECUTING_TASK_TCB
*copyc PMP$GET_EXECUTING_TASK_GTID
*copyc PMP$CYCLE
?? TITLE := '  tmm$manage_signals_and_flags - Internal Declarations' ??
?? EJECT ??
*copyc TMT$TASK_LOCAL_LINKED_SIGNAL
*copyc TMV$SIGNAL_HANDLER_DESCRIPTIONS
*copyc TMV$FLAG_HANDLER_DESCRIPTIONS
*copyc TMC$EXECUTION_RING_CONSTANTS
?? TITLE := '  tmm$manage_signals_and_flags - External Procedures' ??
?? EJECT ??
*copyc TMH$GET_SIGNAL
*copyc TMP$GET_SIGNAL
*copyc TMP$FIND_MAINFRAME_SIGNAL
*copyc TMP$DISPOSE_PREEMPTIVE_COMMO
*copyc TMH$CLEAR_SYSTEM_FLAG
*copyc TMP$CLEAR_SYSTEM_FLAG

*copyc TMH$ENABLE_PREEMPTIVE
*copyc TMP$ENABLE_PREEMPTIVE
?? TITLE := '  [XDCL, #GATE] tmp$find_signal' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] tmp$find_signal (VAR signal_found: boolean;
    VAR signal: tmt$signal;
    VAR signal_handler: tmt$signal_handler);
*copyc TMH$FIND_SIGNAL

    VAR
      caller: ost$caller_identifier,
      traps: 0 .. 3,
      buffer_index: 1 .. (tmc$maximum_signals + 1),
      signal_status: tmt$signal_status,
      xcb: ^ost$execution_control_block,
      tcb: ^pmt$task_control_block;

    #caller_id (caller);
    pmp$find_executing_task_xcb (xcb);
    tcb := xcb^.task_control_block;

    signal_found := FALSE;
    buffer_index := LOWERVALUE (tmt$signal_buffers);
    i#disable_traps (traps);
    WHILE NOT signal_found AND (buffer_index <= UPPERVALUE (tmt$signal_buffers)) DO
      IF xcb^.signals.present [buffer_index] AND (tcb^.signal_execution_ring [buffer_index] = caller.ring)
        THEN
        tmp$get_signal (buffer_index, signal, signal_status);
        CASE signal_status OF
        = tmc$normal_signal_status =
          tcb^.signal_execution_ring [buffer_index] := tmc$unallocated;
          signal_found := TRUE;
          signal_handler := tmv$signal_handler_descriptions [signal.signal.identifier].signal_handler;
        = tmc$no_signal_present =
          ;
        = tmc$invalid_buffer_index =
          ;
        ELSE
        CASEND;
      ELSE
        buffer_index := buffer_index + 1;
      IFEND;
    WHILEND;

    IF NOT signal_found THEN
      find_task_local_signal (caller.ring, signal_found, signal);
      IF signal_found THEN
        signal_handler := tmv$signal_handler_descriptions [signal.signal.identifier].signal_handler;
      IFEND;
    IFEND;
    i#restore_traps (traps);
  PROCEND;
?? TITLE := '  find_task_local_signal' ??
?? EJECT ??

  PROCEDURE find_task_local_signal (execution_ring: tmt$handler_execution_ring;
    VAR signal_found: boolean;
    VAR signal: tmt$signal);

{
{   The purpose of this request is to obtain a signal from the task
{ local signal list which corresponds to to execution ring.
{
{       FIND_TASK_LOCAL_SIGNAL (EXECUTION_RING, SIGNAL_FOUND, SIGNAL)
{
{ EXECUTION_RING: (input) This parameter specifies the ring of the
{       signal.
{
{ SIGNAL_FOUND: (output) This parameter specifies whether a signal
{       was found for the specified execution ring.
{
{ SIGNAL: (output) This parameter specifies the returned signal.
{
{

    VAR
      tcb: ^pmt$task_control_block,
      free_signal: ^tmt$task_local_linked_signal,
      delink: ^^tmt$task_local_linked_signal;

    pmp$find_executing_task_tcb (tcb);
    delink := ^tcb^.task_local_signal_list.delink;
    signal_found := FALSE;
    WHILE NOT signal_found AND (delink^ <> NIL) DO
      IF (delink^^.signal_execution_ring = execution_ring) THEN
        signal := delink^^.linked;
        free_signal := delink^;
        delink^ := delink^^.next_linked_signal;
        FREE free_signal IN osv$job_pageable_heap^;
        signal_found := TRUE;
        IF (delink^ = NIL) THEN
          tcb^.task_local_signal_list.link := delink;
        IFEND;
      ELSE
        delink := ^delink^^.next_linked_signal;
      IFEND;
    WHILEND;
  PROCEND;
?? TITLE := '  post_task_local_signal' ??
?? EJECT ??

  PROCEDURE post_task_local_signal (signal: tmt$signal);

{   The purpose of this request is to add signal to the task local signal list.

    VAR
      tcb: ^pmt$task_control_block,
      ignore_status: ost$status;

    pmp$find_executing_task_tcb (tcb);
    ALLOCATE tcb^.task_local_signal_list.link^ IN osv$job_pageable_heap^;
    tcb^.task_local_signal_list.link^^.signal_execution_ring := tmc$unallocated;
    tcb^.task_local_signal_list.link^^.linked := signal;
    tcb^.task_local_signal_list.link^^.next_linked_signal := NIL;
    tcb^.task_local_signal_list.link := ^tcb^.task_local_signal_list.link^^.next_linked_signal;
  PROCEND;
?? TITLE := '  [XDCL] tmp$dispose_mainframe_signals' ??
?? EJECT ??

  PROCEDURE [XDCL] tmp$dispose_mainframe_signals (flag_id: ost$system_flag);
*copyc TMH$DISPOSE_MAINFRAME_SIGNALS

    VAR
      gtid: ost$global_task_id,
      signal_found: boolean,
      signal: tmt$signal,
      signal_to_dispose: boolean,
      traps: 0 .. 3;

    i#disable_traps (traps);
    signal_to_dispose := FALSE;
    signal_found := TRUE;
    pmp$get_executing_task_gtid (gtid);
    WHILE signal_found DO
      tmp$find_mainframe_signal (gtid, signal_found, signal);
      IF signal_found THEN
        post_task_local_signal (signal);
        signal_to_dispose := TRUE;
      IFEND;
    WHILEND;
    i#restore_traps (traps);
    IF signal_to_dispose THEN
      tmp$dispose_preemptive_commo (tmc$free_flag);
    IFEND;
  PROCEND;
?? TITLE := '  [XDCL, #GATE] tmp$find_flag_to_process' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] tmp$find_flag_to_process (VAR flag_found: boolean;
    VAR flag_id: ost$system_flag;
    VAR flag_handler: tmt$system_flag_handler);

*copyc TMH$FIND_FLAG_TO_PROCESS

    VAR
      caller: ost$caller_identifier,
      xcb: ^ost$execution_control_block,
      tcb: ^pmt$task_control_block,
      system_flag_found: boolean,
      system_flag: ost$system_flag,
      flag_status: tmt$flag_status,
      trap_enables: 0 .. 3;

    #caller_id (caller);
    flag_id := LOWERVALUE (ost$system_flag);
    flag_found := FALSE;
    pmp$find_executing_task_xcb (xcb);
    tcb := xcb^.task_control_block;
    i#disable_traps (trap_enables);
    system_flag := LOWERVALUE (ost$system_flag);
    system_flag_found := FALSE;
  /search_for_flags/
    WHILE NOT system_flag_found AND (xcb^.system_flags <> $tmt$system_flags []) DO

      IF (system_flag IN xcb^.system_flags) AND (tcb^.flag_execution_ring [system_flag] = caller.ring) THEN
        tmp$clear_system_flag (system_flag, flag_status);
        CASE flag_status OF
        = tmc$normal_flag_status =
          flag_id := system_flag;
          flag_handler := tmv$flag_handler_descriptions [system_flag].flag_handler;
          system_flag_found := TRUE;
        = tmc$flag_not_set =
          ;
        = tmc$invalid_flag_id =
          ;
        ELSE
        CASEND;
      ELSE
        IF (system_flag < (UPPERVALUE (ost$system_flag))) THEN
          system_flag := SUCC (system_flag);
        ELSE
          EXIT /search_for_flags/;
        IFEND;
      IFEND;
    WHILEND /search_for_flags/;
    flag_found := system_flag_found;

    i#restore_traps (trap_enables);
  PROCEND;
?? TITLE := '  [XDCL, #GATE] tmp$enable_preemptive_commo' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] tmp$enable_preemptive_commo;

*copyc TMH$ENABLE_PREEMPTIVE_COMMO

    VAR
      f: ost$system_flag,
      s: tmt$signal_buffers,
      tcb: ^pmt$task_control_block;

    pmp$find_executing_task_tcb (tcb);
    FOR f := LOWERVALUE (ost$system_flag) TO UPPERVALUE (ost$system_flag) DO
      tcb^.flag_execution_ring [f] := tmc$unallocated;
    FOREND;
    FOR s := LOWERVALUE (tmt$signal_buffers) TO UPPERVALUE (tmt$signal_buffers) DO
      tcb^.signal_execution_ring [s] := tmc$unallocated;
    FOREND;
    tcb^.task_local_signal_list.delink := NIL;
    tcb^.task_local_signal_list.link := ^tcb^.task_local_signal_list.delink;
    tmp$enable_preemptive;
  PROCEND;
MODEND tmm$manage_signals_and_flags;
