[comp.lang.ada] More on terminate-but-stay-resident interrupt handlers

NCOHEN@IBM.COM (Norman COHEN) (11/24/87)

I have three points to make regarding the discussion of terminate-but-
stay-resident interrupt handlers:

1. As noted by cca!mirror!ishmael!ada-uts!stt@husc6.harvard.edu,
   "Despite the wording in the LRM, one of the language maintenance
   committee decisions somewhere along the way required that the tasks
   dependent on library packages be allowed to complete before the
   program as a whole was ended."

   The decision in question is AI-399.  John Goodenough brought it to my
   attention after reading my suggestion for terminate-but-stay-resident
   interrupt handlers, noting that the AI "has been approved in essence
   at the WG9 and Ada Board level."  AI-399 is a binding interpretation,
   i.e., a new rule.  It changes LRM section 9.4 as follows: The
   "environment task" that invokes a main program (see 10.1(8)) is now
   considered the master of a library package.  Among the
   consequences of this change are the following:

   a. Assuming that the environment task does nothing BUT call the
      main program (which is not stipulated by AI-399 but may be
      stipulated eventually by AI-222), the environment task becomes
      complete upon return from the main program.  At this point, if all
      tasks declared in library packages are terminated or waiting at
      selective waits with terminate alternatives, these tasks and the
      environment task may terminate.  (Thus, despite the words "hence
      not a library package" in 9.4(8), and despite my words to the
      contrary last week, a terminate alternative may be selected by a
      task declared in a library package.)

   b. As long as a task declared in a library package (e.g. an
      interrupt handler) has not terminated, the environment task cannot
      terminate, even if the main program has terminated.  (The
      environment task remains complete, waiting for its dependent task
      to terminate.)

   Despite point (b), an implementation choosing to do so can allow
   terminate-but-stay-resident interrupt handlers to be written in the
   way I described last week: The handlers can be written as tasks
   declared in library packages and specified by means of
   implementation-defined pragmas to be terminate-but-stay-resident
   tasks.  The word "terminated" has two different meanings in this
   context: One is the Ada meaning, subject to the rules in 9.4 about
   when tasks terminate.  The other is the operating-system meaning
   captured in the phrase "terminate but stay resident." The two
   meanings need not coincide.  In appropriate circumstances, such as
   when the dependent tasks of the completed environment task are
   interrupt handlers and require no explicit scheduling, an
   implementation can treat an environment task that is completed but
   not yet terminated (in the Ada sense) as an application that has
   terminated (in the operating-system sense) but remained resident.
   For example, an interactive user of the operating system would see a
   new prompt and would be able to spawn a new environment task
   executing a new main program even though the previous environment
   task was technically still executing.

   Truth-in-tasking (a companion to truth-in-packaging) requires me to
   relate the following recommendation contained in AI-399:

       It is recommended that implementations targetted to
       conventional time-sharing operating systems define the
       environment task as being created and activated when Ada
       program execution is initiated by operating system command,
       and that termination of the environment task occur before
       control is returned to the command interpreter.  It is up to
       the implementation to define the environment task in an
       appropriate manner for the target environment.

   Please note, however, the words "It is recommended" (not required by
   the binding interpretation) and the admission in the next sentence
   that the implementer is the ultimate judge of what is appropriate in
   a given environment.  The Unix shell, for example, spawns a subshell
   to execute a command line ending with an &, and does not wait for the
   "environment task" executing the command to complete before prompting
   for a new command line.  Surely the recommendation in AI-399 would
   not apply in such a context.

2. Dave Emery objects, "...it seems to me that this is potentially
   erroneous, in that the language does not define...what would happen
   in this instance (i.e. isn't this implementation dependent)."  Yes,
   it is unabashedly implementation-dependent.  The notion of terminate-
   but-stay-resident programs is implementation-dependent, so any Ada
   scheme to implement them must be implementation-dependent.  No, it is
   not erroneous.  The term "erroneous" is narrowly defined by the LRM
   to refer to twelve specific ways that a program can violate the rules
   of Ada without (necessarily) being caught either by the compiler or
   by run-time checks.  Nonportable programming is to be avoided if it
   can be (it can't be in the case of terminate-but-stay-resident
   interrupt handlers); but unlike erroneous execution, nonportable
   programming does not necessarily violate any rules of the Ada
   language.

   This erroneous use of the term "erroneous" is quite prevalent.  I
   have an article on this matter in the pipeline to Ada Letters.

3. Concerning the interaction between terminate alternatives and
   interrupt entries, which was the real subject of Dave's original
   query:

   The rules in 9.4 defining masters and dependents and stipulating when
   a terminate alternative could be selected were intended to ensure
   that a task T could select a terminate alternative only when all tasks
   able to name T in an entry call were themselves terminated or waiting
   at selective waits with terminate alternatives.  (Alas, a loophole
   was later discovered, but this was the intent.) It was believed that,
   as a consequence of the definition of a master and its relation to
   the scope rules, a task could be named only from within its master or
   some task dependent on its master.

   This reasoning does not apply to tasks with interrupt entries,
   because a "hardware task" that calls an interrupt entry (see
   13.5.1(2)) is not subject to Ada scope rules; it can call an
   interrupt entry without being able to name the called task.  That is
   why 13.5.1(3) states that, when an accept statement for an interrupt
   entry and a terminate alternative occur in the same selective wait,
   "an implementation may impose further requirements for the selection
   of the terminate alternative in addition to those given in section
   9.4."

   (The loophole involves a function returning a task object declared
   within the function.  The function is the task's master.  If the task
   has a terminate alternative, the alternative becomes selectable as
   soon as the function executes its return statement, and the function
   then returns.  If a call on the function occurs as the prefix in an
   entry call, then an entry of the task returned by the function is
   called after that task has selected a terminate alternative.  The
   entry call raises Tasking_Error.)