Issue 19679: Initial execution of an activity is not run-to-completion (fuml-rtf) Source: Model Driven Solutions (Mr. Ed Seidewitz, ed-s(at)modeldriven.com) Nature: Uncategorized Issue Severity: Summary: When an activity accepts an event, its execution proceeds as a “run-to-completion step”, and any new event occurrences (signal instances) are saved in the event pool and not dispatched until after the completion of the step. However, when an activity first starts executing (asynchronously), it is NOT in a run-to-completion step before it waits for the first time at an accept event action. This means that, during this time, any event occurrences that arrive could potentially be dispatched immediately and lost. Further, even if the first action to be executed in an activity is an accept event action, the specification would allow an execution trace in which all event occurrences happened before the action fired for the first time, meaning that, currently, it can never be ensured that an activity will be able to accept any event occurrences at all. Recommended solution: Rather than having the ClassifierBehaviorExecutionActivity start asynchronously from the EventDispatchLoop of the object activation for the context object, the EventDispatchLoop should make a synchronous call to execute the initial classifier behavior execution, and then only start looping once the initial execution completes. Note that the equivalent behavior should also be specified for bUML, so that the ArrivalSignal instances sent to an object activation are properly queued while the EventDispatchLoop is waiting for the initial classifier behavior execution to complete. Resolution: Invoke classifier behaviors from the event dispatch loop The UML 2.5 specification calls the initial event that starts the execution of a behavior the "event of its invocation". Essentially, what is required to resolve this issue is for such an invocation event occurrence to be handled as a run-to-completion step in the behavior execution, just as signal event occurrences are currently handled. A particularly direct way to do this would be to explicitly model invocation event occurrences, place them in the event pool for the context object of the behavior being (asynchronously) invoked and then having them dispatched and accepted using the current event loop and run-to-completion mechanisms. Doing this would also manage the case of a context object with multiple classifier behavior executions that don't all start at the same time. This can happen if the object has multiple types with classifier behaviors. If the object is the target value for a start object behavior action whose object input pin is explicitly typed by one of the relevant classes, than only the classifier behavior associated with that class is started, even if the object has other types with classifier behaviors (in contrast, if the object pin is untyped, then classifier behaviors are started for all the object's types that have them; see the definition of the ObjectActivation::startBehavior operation in 8.4.3.2.5 of the fUML 1.1 specification). This means that, when a classifier behavior execution is started, this may happen after other classifier behavior executions have already started and are already handling incoming (signal) event occurrences. Thus, the new invocation could happen when there are already event occurrences in the event pool waiting to happen and even possibly when there is already an ongoing run-to-completion step happening for a previously dispatched event occurrence. By explicitly modeling the invocation event occurrence for the new classifier behavior, the invocation can be managed in the same way as other event occurrences, by being placed in the event pool and eventually dispatched and handled in a run-to-completion step for the initial execution of the classifier behavior. Finally, this approach provides an opportunity to generalize the model of the event pool to contain event occurrences other than signal instances. This will likely be eventually necessary anyway, in order to allow future specifications to incorporate the handling of other kinds of events into the fUML Common Behaviors framework (such as call events for state machines). So, the proposal to resolve this issue is as follows: 1. Create a new abstract EventOccurrence class, with a concrete SignalEventOccurrence subclass that has a reference to a SignalInstance. 2. Generalize the eventPool to contain EventOccurrences instead of just SignalInstances. 3. Create a new InvocationEventOccurrence subclass of EventOccurrence with a reference to an Execution being invoked. 4. Change the ObjectActivation::startObjectBehavior operation to create an InvocationEventOccurrence and place it into the eventPool, rather than directly initiating the asynchronous execution of a behavior. 5. Change the ClassifierBehaviorExecution class to ClassifierBehaviorInvocationEventAccepter, an EventAccepter that registers itself to match the InvocationEventOccurrence for a specific behavior Execution and, when it accepts a matching InvocationEventOccurrence, runs that Execution as a run-to-completion step. Revised Text: In 8.4.3.1 Overview, in the third to the last paragraph of the section title "Active Objects", add the following sentence at the end: These semantics are captured in the object activation for an active object, which is created when the active behavior of the object is started. Replace the last two paragraphs under "Active Objects" with the following paragraph: Note that a behavior may itself be instantiated as an active object and the active behavior of a behavior instance is just the behavior itself, acting as its own context object. For simplicity, in the description of the semantics of active objects and event handling below, the running behavior of an active object is always referred to as its "classifier behavior execution". However, in the case of an active object that is a behavior instance (which is already an execution), the "classifier behavior execution" will actually be the active object itself, not an instance of some other "classifier behavior". Replace the "Event Dispatching" section with Event Dispatching An active object may asynchronously react to the occurrence of various events. When an object is notified of the occurrence of an event, it is said to have received the event occurrence. Asynchronicity means that the receipt of the event occurrence is decoupled from the dispatching of that occurrence, which is when a determination is made as to how the object will react to the event occurrence (if at all). In order to achieve this decoupling, ObjectActivation is itself an active class (in the execution model). The classifier behavior for ObjectActivation (see Figure 8.17) is a simple dispatch loop. When an event occurrence is received by an active object, its is placed into the event pool of the object activation for that object, after which the object activation sends an ArrivalSignal to itself. The dispatch loop waits for an ArrivalSignal and, when this happens, calls the dispatchNextEvent operation. This operation dispatches a single event occurrence from the event pool. Once this is complete ("run to completion semantics" for dispatched event occurrences), the dispatch loop returns to waiting for another event occurrence to arrive. It is important to carefully note the two semantics levels in the above description. At the level of a user model, the execution model is modeling the receipt of an event occurrence and the dispatching of that event occurrence, to be handled as defined in the user model. However, the semantic model itself also uses the active class ObjectActivation and the signal ArrivalSignal, whose receipt by an object activation is an event occurrence handled by the classifier behavior of the object activation (i.e., the event dispatch loop). The semantics for active class and signals, as used in the execution model, are given by the base semantics for those model constructs (see Clause 10; also see Clause 6 for a general discussion of fUML execution semantics versus base semantics). Note, while an event occurrence is being dispatched, it is possible that the active object will receive additional event occurrences. In this case, these event occurrences will be concurrently placed into the event pool for the active object and an ArrivalSignal will be generated for each arriving event occurrence. When the dispatch loop is ready to accept another event occurrence, it will accept exactly one pending ArrivalSignal, causing another event occurrence to be dispatched. The dispatch loop will continue to dispatch event occurrences, one at a time, until there are no more pending ArrivalSignals (or until the active object is destroyed). Which event occurrence is actually dispatched out of the event pool is not determined by the ArrivalSignal but, rather, by the dispatchNextEvent operation. However, the exact behavior to be specified for this operation is a semantic variation point in fUML. (See 2.4 for a full discussion of semantic variation within fUML.) Following the general approach of using the Strategy Pattern to model semantic variation points (see 8.2.1), the variability of event dispatching is captured by using strategy classes for the ObjectActivation::getNextEvent operation. GetNextEventStrategy provides the abstract base class for this type of strategy. The default dispatching behavior is given by the concrete FIFOGetNextEventStrategy, which dispatches event occurrences on a first-in first-out (FIFO queue) basis. Any variant behavior must be fully specified by overriding the behavioral specification of the dispatchNextEvent operation. A conforming execution tool may define an alternative rule for how this dispatching is to take place by defining a new GetNextEventStrategy subclass specifying whatever rule is desired. An instance of this alternate strategy must then be registered with the execution factory at a given locus, rather than the default strategy. Once an event occurrence is selected for dispatch, it is matched against the list of waiting event accepters for the active object. If a match is found, the event occurrence is passed to the event accepter using its accept operation. If no matching event acceptor is found, the event occurrence is not returned to the event pool and is lost. (Note that deferred events are not included in the fUML subset.) The event accepters for an active object are points within the executing classifier behaviors of the object that are waiting for certain events. An executing classifier behavior may register an event accepter for itself using the Object::registerForEvent operation. The event accepter is then added to the list of waiting event accepters for the object and any matching event occurence is passed back to the executing classifier behavior via the accept operation of the event accepter. Add the following new section: Event Occurrences The event-dispatching framework described above is intended to be general enough to handle the occurrence of various different kinds of events defined in UML. However, currently there are two kinds of events whose occurrences are handled in the fUML execution model: classifier behavior (asynchronous) invocation events and signal reception events. It is expected that other specifications building on fUML may specify the semantics of other kinds of events within the general fUML event-handling framework. A classifier behavior for an active object may be started using a start object behavior action (see 8.6.4.2.8). When a behavior of an active object is so started, if no object activation yet exists for the active object, one is created. An active object with multiple types may have multiple classifier behaviors, which may be started separately, so it is possible that an object activation may already exist when a classifier behavior is started, if it is not the first one. In either case, the actual starting of the behavior is then delegated to the object activation. To start a classifier behavior, an Execution instance is created for it (see 8.4.2.2.1), but this execution does not run immediately. Instead, an invocation event occurrence for the execution is added to the event pool and a classifier behavior invocation event accepter is registered to handle this event occurrence. As previously described in general for event occurrences, this decouples the receipt of the event occurrence requesting the start of a classifier behavior from the dispatching of the event occurrence, at which point the classifier behavior invocation event accepter actually starts the classifier behavior execution. In this way, the classifier behavior executes asynchronously from its invocation and within an initial run-to-completion step, so that any event occurrences received by the active object during this initial execution are saved until the object is ready to handle them. An object activation also keeps a list of the classifier behavior invocation event accepters created to start classifier behavior executions. This maintains a link between the object activation and any ongoing executions so that, if the associated active object is destroyed, any running classifier behavior executions may be terminated. Once a classifier behavior is running, it may register event accepters to handle the occurrences of other kinds of events received by its context object. In particular, the firing of an accept event action results in the registration of an event accepter for the events declared in the triggers of that action (see 8.6.4.2.1 and 8.6.4.2.2). Currently, an accept event action in fUML is limited to handling signal events. When a signal instance is received by an active object, a signal event occurrence for the signal instance is placed in the event pool. When this signal event occurrence is dispatched, if there is a matching accept event action event accepter for it, then the corresponding signal instance will be accepted by the accept event action, resulting in the resumption of execution of the activity containing the action. Replace Figures 8.16 and 8.17 with the diagrams in the attachments (to be provided). Change the title of 8.4.3.2.1 to ClassifierBehaviorInvocationEventAccepter. Replace the sentence A classifier behavior execution executes the classifier behavior from a specific active class. with A classifier behavior invocation event accepter accepts an invocation event occurrence for the invocation of the execution of a classifier behavior from a specific active class. [Editor's Note: Under "Generalizations", "None" also needs to be changed to "EventAccepter", per the generalization relationship from ClassifierBehaviorInvocationEventAccepter to EventAccepter on the new diagram for Figure 8.17. ] Remove Figure 8.18 (and remove ClassifierBehaviorExecutionActivity from the execution model). Change the name of the execute operation to invokeBehavior (with the same arguments). In the initial comments for that operation, change the final line // Then start the active behavior of this ClassifierBehaviorExecution object, which will execute the execution object on a separate thread of control. to // Then register this event accepter with the object activation. Add the following operations in alphabetical order with the other operations and renumber the operations appropriately. accept ( in eventOccurrence : EventOccurrence ) // Accept an invocation event occurrence. Execute the execution of this // classifier behavior invocation event accepter. if (eventOccurrence instanceof InvocationEventOccurrence) { this.execution.execute(); } match ( in eventOccurrence : EventOccurrence ) : Boolean // Return true if the given event occurrence is an invocation event // occurrence for the execution of this classifier behavior invocation // event accepter. boolean matches = false; if (eventOccurrence instanceof InvocationEventOccurrence) { matches = ((InvocationEventOccurrence)eventOccurrence).execution == this.execution; } return matches; In 8.4.3.2.2 EventAccepter, change the names of the arguments of both operations from signalInstance to eventOccurrence and change their types from SignalInstance to EventOccurrence. In 8.4.3.2.3 FIFOGetNextEventStrategy, in the getNextEvent operation, change the return type and the type of the signalInstance variable from SignalInstance to EventOccurrence. Change the name of the signalInstance variable to eventOccurrence. In 8.4.3.2.4 GetNextEventStrategy, in the getNextEvent operation, change the return type from SignalInstance to EventOccurrence. In 8.4.3.2.5 ObjectActivation, under Associations, replace *classifierBehaviorExecutions : ClassifierBehaviorExecution [0..*] The executing classifier behaviors for this object activation. *eventPool : SignalInstance [0..*] The pool of signals sent to the object of this object activation, pending dispatching as events. (All the data values in the pool must be signal instances ? that is, they must have a single type that is a signal.) with *classifierBehaviorInvocations : ClassifierBehaviorInvocationEventAccepter [0..*] The invocations of the executing classifier behaviors for this object activation. *eventPool : EventOccurrence [0..*] The pool of event occurrences received by the object of this object activation, pending dispatching. Change the description of waitingEventAccepters from The set of event accepters waiting for signals to be received by the object of this object activation. to The set of event accepters waiting for event occurrences to be dispatched from the event pool. In the dispatchNextEvent operation, change the initial comment to: // Get the next event occurrence out of the event pool. // If there are one or more waiting event accepters with triggers that // match the event occurrence, then dispatch it to exactly one of those // waiting accepters. In the body of the operation, change the name of the signalInstance variable to eventOccurrence and change its type from SignalInstance to EventOccurrence. Change the type of the getNextEvent operation from SignalInstance to EventOccurrence. Replace the body of the send operation with: // Add a signal event occurrence for the given signal instance to the event pool // and signal that a new event occurrence has arrived. SignalEventOccurrence eventOccurrence = new SignalEventOccurrence(); eventOccurrence.signalInstance = (SignalInstance) signalInstance.copy(); this.eventPool.addValue(eventOccurrence); _send(new ArrivalSignal()); In the startBehavior operation, in the initial comment, change "classifier behavior execution" to "classifier behavior invocation" (four times). At the end of the second sentence, after "for it", insert "and add an invocation event occurrence to the event pool." Before the statement boolean notYetStarted = true; add the statement _beginIsolation(); In the while loop, change this.classifierBehaviorExecutions to this.classifierBehaviorInvocations (twice). In the if statement beginning if (notYetStarted), replace all the statements within the if statement with ClassifierBehaviorInvocationEventAccepter newInvocation = new ClassifierBehaviorInvocationEventAccepter(); newInvocation.objectActivation = this; this.classifierBehaviorInvocations.addValue(newInvocation); newInvocation.invokeBehavior(classifier, inputs); InvocationEventOccurrence eventOccurrence = new InvocationEventOccurrence(); eventOccurrence.execution = newInvocation.execution; this.eventPool.addValue(eventOccurrence); _send(new ArrivalSignal()); After the if statement, add the statement _endIsolation(); In the operation stop, change the name of the variable classifierBehaviorExecutions to classifierBehaviorInvocations and change its type from ClassifierBehaviorExecutionList to ClassifierBehaviorInvocationEventAccepterList. Change the name of the variable classifierBehaviorExecution to classifierBehaviorInvocation and change its type from ClassifierBehaviorExecution to ClassifierBehaviorInvocationEventAccepter. Add the following subclause after 8.4.3.2.2 EventAccepter: 8.4.3.2.3 EventOccurrence An event occurrence represents a single occurrence of a specific kind of event. Generalizations None Attributes None Associations None Operations None Renumber 8.4.3.2.3 FIFOGetNextEventStrategy to 8.4.3.2.4, renumber 8.4.3.2.4 GetNextEventStrategy to 8.4.3.2.5 and add the following subclause: 8.4.3.2.6 InvocationEventOccurrence An invocation event occurrence represents a signal occurrence of the event of the asynchronous invocation of a specific behavior execution. Generalizations *"EventOccurrence" on page 173 Attributes None Associations *execution : Execution The execution being asynchronously invoked. Operations None Renumber 8.4.3.2.5 ObjectActivation to 8.4.3.2.7 and add the following subclause: 8.4.3.2.8 SignalEventOccurrence A signal event occurrence represents the occurrence of a signal event due to the receipt of a specific signal instance. Generalizations *"EventOccurrence" on page 173 Attributes None Associations *signalInstance : SignalInstance The signal instance whose receipt caused this signal event occurrence. Operations None Renumber 8.4.3.2.6 SignalInstance to 8.4.3.2.8. In 8.6.4.1 Overview, under the "Accept Event Action" section, in the third paragraph, in the first sentence, replace "singal instance" with "signal event occurrence" and, after "context object" insert "with a signal instance". In Figure 8.36 (as currently numbered), in class AcceptEventActionEventAccepter, change the arguments of each of the operations from signalInstance : SignalInstance to eventOccurrence : EventOccurrence. In 8.6.4.2.2 AcceptEventActionEventAccepter, replace the two operations with [1] accept ( in eventOccurrence : EventOccurrence ) // Accept a signal event occurrence. Forward the signal instance to the action activation. if (eventOccurrence instanceof SignalEventOccurrence) { this.actionActivation.accept(((SignalEventOccurrence)eventOccurrence).signalInstance); } [2] match ( in eventOccurrence : EventOccurrence ) : Boolean // Return true if the given event occurrence is a signal event occurrence and the // signal instance matches a trigger of the accept action of the action activation. boolean matches = false; if (eventOccurrence instanceof SignalEventOccurrence) { matches = this.actionActivation. match(((SignalEventOccurrence)eventOccurrence).signalInstance); } return matches; Actions taken: December 12, 2014: received issue October 8, 2015: Resolved December 22, 2015: closed issue Discussion: End of Annotations:===== m: Ed Seidewitz To: "issue@omg.org" Subject: Initial execution of an activity is not run-to-completion Thread-Topic: Initial execution of an activity is not run-to-completion Thread-Index: AQHQFgsjnn4OAku6sEedx5MnhnbkcA== Date: Fri, 12 Dec 2014 12:57:09 +0000 Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: X-Mailprotector-Decision: deliver X-Mailprotector-Connection: TLSv1|cas203.mailprotector.com|54.208.113.85|CAS203.mailprotector.local|0.0|0.0|0|||0|0|0|0 X-Mailprotector-Results: subject_50_chars clean X-Mailprotector-Score: 0 X-Mailprotector-IP-Analysis: 0, 54.208.113.85, Ugly c=0 p=0 Source New X-Mailprotector-Scan-Diagnostics: 0-0-0-2150-c X-Mailprotector-ID: d73f4ae8-c9fc-4f5b-abd6-e0321def215a X-Virus-Scanned: amavisd-new at omg.org X-MIME-Autoconverted: from base64 to 8bit by amethyst.omg.org id sBCCvc8D006831 Content-Transfer-Encoding: 8bit Specification: Semantics of a Foundational Subset for Executable Models v1.1 Subclause: 8.4.3 Communications When an activity accepts an event, its execution proceeds as a “run-to-completion step”, and any new event occurrences (signal instances) are saved in the event pool and not dispatched until after the completion of the step. However, when an activity first starts executing (asynchronously), it is NOT in a run-to-completion step before it waits for the first time at an accept event action. This means that, during this time, any event occurrences that arrive could potentially be dispatched immediately and lost. Further, even if the first action to be executed in an activity is an accept event action, the specification would allow an execution trace in which all event occurrences happened before the action fired for the first time, meaning that, currently, it can never be ensured that an activity will be able to accept any event occurrences at all. Recommended solution: Rather than having the ClassifierBehaviorExecutionActivity start asynchronously Sent from my iPad