10 Cancelling actions

It is possible to cancel an action which is in a wait state. Here is a simple example.

  interface timer
     action WAIT
        obey
        endobey
        cancel
        endcancel
     endaction
  endinterface
  
        SUBROUTINE TIMER ( STATUS )
        IMPLICIT NONE
        INCLUDE ’SAE_PAR’
        INCLUDE ’ACT_ERR’
        INCLUDE ’ADAMDEFNS’
        INTEGER STATUS
        INTEGER SEQ
        INTEGER CONTEXT
  
        IF ( STATUS .NE. SAI__OK ) RETURN
        CALL TASK_GET_CONTEXT ( CONTEXT, STATUS )
        IF ( CONTEXT .EQ. OBEY ) THEN
           CALL TASK_GET_SEQ ( SEQ, STATUS )
           IF ( SEQ .EQ. 0 ) THEN
              CALL TASK_PUT_DELAY ( 10000, STATUS )
              CALL TASK_PUT_REQUEST ( ACT__WAIT, STATUS )
           ELSE
              CALL MSG_OUT ( ’ ’, ’finished’, STATUS )
           ENDIF
        ELSE IF ( CONTEXT .EQ. CANCEL ) THEN
           CALL MSG_OUT ( ’ ’, ’I was cancelled’, STATUS )
           CALL TASK_PUT_REQUEST ( ACT__CANCEL, STATUS )
        ENDIF
        END

Note the CANCEL declaration in the interface file. This example is exercised by

  ICL> send timer obey wait
  ICL> send timer cancel wait

It is possible to write the application such that CANCEL modifies the behaviour of the rescheduling action rather than terminating it.

  interface timer
     parameter CANTIME
        type ’_INTEGER’
     endparameter
     action WAIT
        obey
        endobey
        cancel needs CANTIME
        endcancel
     endaction
  endinterface
  
        SUBROUTINE TIMER ( STATUS )
        IMPLICIT NONE
        INCLUDE ’SAE_PAR’
        INCLUDE ’ACT_ERR’
        INCLUDE ’ADAMDEFNS’
        INTEGER STATUS
        INTEGER SEQ
        INTEGER CONTEXT
        INTEGER STATE
        SAVE STATE, TIME
  
        IF ( STATUS .NE. SAI__OK ) RETURN
        CALL TASK_GET_CONTEXT ( CONTEXT, STATUS )
        IF ( CONTEXT .EQ. OBEY ) THEN
           CALL TASK_GET_SEQ ( SEQ, STATUS )
           IF ( SEQ .EQ. 0 ) THEN
              STATE = 0
              CALL TASK_PUT_DELAY ( 500, STATUS )
              CALL TASK_PUT_REQUEST ( ACT__WAIT, STATUS )
           ELSE
              IF ( STATE .EQ. 0 ) THEN
  *            Normal reschedule
                 CALL TASK_PUT_DELAY ( 500, STATUS )
                 CALL MSG_OUT ( ’ ’, ’default timer’, STATUS )
                 CALL TASK_PUT_REQUEST ( ACT__WAIT, STATUS )
              ELSE
  *            Rescheduling after CANCEL
                 CALL TASK_PUT_DELAY ( TIME, STATUS )
                 CALL MSG_OUT ( ’ ’, ’altered timer’, STATUS )
                 CALL TASK_PUT_REQUEST ( ACT__WAIT, STATUS )
              ENDIF
           ENDIF
        ELSE IF ( CONTEXT .EQ. CANCEL ) THEN
           STATE = 1
           CALL PAR_GET0I ( ’CANTIME’, TIME, STATUS )
           CALL TASK_PUT_DELAY ( TIME, STATUS )
           CALL MSG_OUT ( ’ ’, ’timer changed’, STATUS )
           CALL TASK_PUT_REQUEST ( ACT__WAIT, STATUS )
        ENDIF
        END

Then:

  ICL> send timer obey wait
  ICL> send timer cancel wait 10000

will cause the task to start rescheduling at 0.5sec intervals, but then switch to rescheduling at 10sec intervals. In this particular example the action never terminates.

An example of sending a CANCEL to a task which is controlling a subsidiary task is given in Appendix B.