Copyright © IFAC Real Time Programming, Schloss Dagstuhl. Gennany, 1999
DEVELOPING PROVABLY CORRECT SYSTEMS WITH OBSERV Shmuel Tyszberowicz· Amiram Yehudai·
• Computer Science Department, Tel-Aviv University, Israel
Abstract: The OBSERV methodology for software development is based on rapid construction of an executable specification, or prototype, of a system. The specification may be examined and modified repeatedly to achieve the desired functionality. The objectives of OBSERV also include facilitating a smooth transition to a target system, and providing means for reusing specification, design, and coding of systems and subsystems. This article describes OBSERV, and demonstrates how the methods used in our approach can be used to develop provably correct real-time reactive systems. Correctness is checked by means of simulation and formally proved with a model checker. Copyright © 1999lFAC
Keywords: OBSERV, real-time reactive systems, simulation, model-checking.
1. INTRODUCTION
2.0BSERV
2.1 General Description The OBSERV language combines several paradigms to express the behavior of a system. The class-based approach 1 provides the basic mechanism for building a system from a collection of objects, with well-defined interfaces between them. Finite state machines are used to model the behavior of individual objects. At a lower level, activities that occur within objects (either upon entry to a state or in transition between states) are described with the logic programming paradigm (Prolog), thus allowing a non-procedural description when possible.
The OBSERV methodology for software development is based on rapid construction of an executable specification, or prototype, of a system. The specification may be examined and modified repeatedly to achieve the desired functionality. The objectives of OBSERV also include facilitating a smooth transition to a target system, and providing means for reusing specification, design, and coding of systems and subsystems. This article describes OBSERV, and demonstrates how the methods used in our approach can be used to develop provably correct real-time reactive systems. Correctness is checked by means of simulation and formally proved with a model checker.
In OBSERV, the designer defines a system by identifying objects and the relations between them. Whenever one designs an object, one actually defines a type, that can be instantiated as many times as needed. The con currency of a
In the following section we describe OBSERV and its environment. In Section 3 we demonstrate how OBSERV can be used to develop provably correct systems, by means of both a simulator (Section 3.1) and a model checker (Section 3.2). Finally, further work is discussed in (Section 4).
1 According to Wegner's classification (Wegner, 1987), OBSERV is considered a class-based language, i.e., each of the objects in OBSERV belong to a class, but there is . no inheritance.
183
system is expressed by constructing it from independent objects; they communicate by sending messages. Objects are isolated from each other by decoupling the knowledge about the receiver of the message from the sender. Each object declares its own outgoing interface in addition to the more conventional incoming interface. The outgoing interface is the list of messages the object may send out, with names local to the sending object. The mapping between these and the object(s) to which they are sent is placed elsewhere.
kind, viewed from the outside as a single object with a well-defined interface. The definition of a compound object includes mapping each service supplied by the object (each entry in its incoming interface) to services (entries in the incoming interfaces) of some of its components. We also need to map each entry in the outgoing interface of each component object to entries in the incoming interface of some other component(s), and/or entries in the compound object's outgoing interface. Control in such an object is distributed among its components, by simply specifying to which components each incoming event is directed. The structuring facility supplied by the compound objects, as well as the ability to endow regular objects with their own state variables, encourages the construction of hierarchical systems.
We distinguish between three kinds of objects: primitive, regular, and compound objects. A primitive object encapsulates a simple value and provides operations that set, retrieve, and modify that value. Primitive objects are pure servers (they have no outgoing messages as they do not require any service from the outside) . Primitive types are user-defined, like the other types in OBSERV, and not fixed built-ins. For convenience, however, types like integer, boolean and string are pre-defined.
2.2 Real- Time Aspects The timer(T) transition enables the specification of the occurrence of timeouts and the initiation of periodic activities. According to (Dasarathy, 1985), there are two categories of timing constraints for a real-time system:
The behavior of regular objects is described by means of state machines, which consist of states, transitions, and activities. State variables, that are objects of any kind, are used to store state information. Transitions from state to state may be conditional, and they occur either due to an external event or as a result of a spontaneous event. The former happens when a request is sent by another object. The latter is activated either by the end of a state activity (end transition) , or if within a certain amount of time following the completion of the state activity, no transition out of the state has occurred (timer(T) transition).
(1) limits on the response time of a system, and (2) demands on the rates at which users apply stimuli to the system. Both the response time and the stimuli rates may be further classified by the following restrictions: • no more than T time units may elapse between the occurrence of two events, stimuli and/or responses, and • no less than T time units may elapse between the occurrence of two events, • an event must occur for T units of time.
Two kinds of activities are concerned with regular objects: (i) state activity, performed when entering a state, and (ii) event activity, performed when the event is served. Activities cause messages to be sent (outside the object or to state variables), and may change the values of state variables. Activities, as well as conditions, are expressed using Prolog commands for computations, with special forms for message sending.
The timer(T) event enables the designer to specify all these classifications. It is possible to set an unbound parameter 3 T thus enabling the user to dynamically specify values for the time a transition should take place. At most one timer transition may emanate from each state. This is sufficient to enable the description of any event that depends on a clock, whether timeouts or periodic events, possibly at the cost of some additional states. For instance, suppose we are in state Si and we need to exit that state after T units of time, for a known T, have elapsed. The identity of the target state depends on satisfying various conditions, i.e., the timer(T) transitions are conditional. This seems to require more than one timer(T) transition emanating from the same state. In order to bypass this obstacle, a new state, say Sj, may be added ; it will be entered, unconditionally, after T time
To reduce complexity, we allow only a limited kind of concurrency: a regular object is allowed to respond to one external event at a time , 2 with the only exception that it can respond to simple, side-effect free inquiries (immediate events) concurrently to one non-immediate event. More significant concurrency is achieved by combining several objects to a compound object, which is the main structuring mechanism in OBSERV. A compound object is a collection of objects of any 2 These events are called non-immediate event. ; if an object has to respond to more than one of these events , the others are queued .
3
184
An argument is unbound if it is not assigned a value .
units in Si, using the timer(T) transition. There will be only conditional end transitions coming out of state Si . The conditions associated with these transitions, as well as the target states, are those that were planned for exiting from state Si, using the conditional timer(T) transitions.
are performed instantaneously. Therefore, if O 2 is a primitive object then the time the regular object 0 1 needs to wait for a result depends solely on the transmit time of both the message and the result. We also assume that it takes no time for a regular object to send a message to a state variable (it is considered a local activity). It also takes no time for a result to be returned by a state variable. Hence, if O 2 is a primitive state variable of Ob then 0 1 has no waiting period, i.e., the result is immediately returned.
A simple modification enabled us to implement a second version of the simulator which supports a less restrictive semantics. This version enables more than one timer(T) transition to emanate from the same state. This requires that, in all the transitions, T has the same value. The end transition may be interpreted as a timer(O) transition.
A regular object O 2 may receive several messages during the same period of time. Immediate messages will be served immediately and concurrently with other activities. Other messages will be queued and handled in the order they were received. This is a simple model. We have also considered and experimented with a scheme that discards messages that have not begun to be served within a certain period of time.
In order to ease the specification, we have added the timer (Lower, Upper) construct to the syntax of OBSERV. This is straightforward interpreted: the timer transition is activated within the closed interval [Lower, Upper]. During the simulation process, a random value within these boundaries is chosen.
If the designer wishes to limit waiting time, he may design the interaction between 0 1 and O 2 so that returning the value is decoupled from sending E; a second message can be designed to return the value. This message may be from O 2 to 0 1 so that O 2 sends the result when it is ready or from 0 1 to O 2 so that 0 1 may periodically ask whether the result is ready. The designer may also use parameters of messages to pass information that directs O 2 how and when to act. In particular, a parameter may be used to pass a time value, so that O 2 can perform some special activities as specified by the designer if a longer time than expected has elapsed since handling of the message began. Note that this is different from the mechanism mentioned in the previous paragraph. While the former mechanism deals with managing the queue, which is ordinarily beyond the direct control of the object, the latter treats design issues.
2.3 Me!!age! and Time OBSERV views objects as independent entities acting in parallel; their interaction is achieved by sending messages. In this section we consider message passing between objects and the concept of time as seen in OBSERV. When an object 0 1 sends a message E to another object O 2 , several things may occur. If E is not expected to return a value, 0 1 may proceed without waiting for E to be acted upon. If E does return a value, then 0 1 must wait until it receives the value. This waiting period is the result of the time it takes for the message to reach O 2 , the time until O 2 can start serving the message, the time O 2 needs to serve it, possibly including further messages sent to other objects, and the time needed for the result to travel back to 0 1 • The three kinds of objects in OBSERV vary in their behavior and have different time notions as well. Compound objects can be seen as a structuring mechanism: they do not initiate message sending, and any message received by them is ultimately mapped to either a regular or a primitive object. Thus, when describing the time concept it suffices to consider regular and primitive objects. These two kinds of objects vary in the amount of time they need to handle incoming messages. We assume that local activities, which are essentially computations, take no time to be completed. If the designer wishes to model a situation in which an object takes a measurable time to perform some computation, this can be achieved by using a state with a timer transition. Activities within a primitive object are considered to be atomic. These activities include only computations which
2.4 The Environment
The OBSERV environment is a collection of tools that enable the construction, browsing, checking, and simulation of OBSERV designs. The tools are all built on top of ProLab (Backer et al., 1988), a Prolog programming environment developed at GMD (the German National Research Center for Information Technology). All the tools share a common user-interface, with windowing and scrolling conventions supplied by ProLab. We have followed the ModelView-Controller (MVC) paradigm as suggested in Small talk (Krasner and Pope, 1988), a paradigm which is also advocated and supported by ProLab. The MVC paradigm supports highly interactive software.
185
The tools that can be invoked are a static checker, a browser, and a simulator. Each tool in OBSERV has two main parts, both implemented in Prolog: the application level and the interaction level.
3.2 Formal Verification of Properties
The OBSERV description of a system is mapped to the representation language of OBSERV. This language consists of Prolog facts which are used to define objects and their relationships. The common basis for the OBSERV tools is a representation language, which is essentially a collection of special predefined Prolog predicates. Refer to (Tyszberowicz and Yehudai, 1990) for a full description of the representation language.
A formal proof that an implementation meets its specification is very important especially in embedded real-time systems. When the program is described as a finite-state machine, which is the case in OBSERV, model checking can be used. One of the problems with model checkers is the need to write programs as state machines. This is not the usual way programs are written. OBSERV's specifications are written as finite state machines, and this simplifies mechanical translation into an input to SMV, a model checker developed at CMU (McMillan, 1992). As already mentioned, the OBSERV description of a system is mapped to the representation language of OBSERV, which consists of Prolog facts. Each type in this database of facts serves as a module, and is separately translated.
2.5 The Simulator The simulator is used to execute the prototype as defined using the OBSERV language. We simulate a single object of a user-chosen type, called the system under simulation. The system being simulated includes the entire hierarchy whose root is the chosen type.
Primitive objects can be seen as state machines with only one state, which is their value. We abstract data, replacing them by messages. Thus, for example, the predefined type boolean has an incoming event set(N), where N is true or false. We replace it by the input signal set.-N. The model checker will arbitrarily choose the value-true or false-of the input signal. In order to ensure that the model checker will infinitely many times use the value true, we add set..N to the fairness statement of SMV.
The simulator may detect deadlocks, which occur when there are objects waiting for the result of messages they have sent and no object has any action to perform. The interested reader can find a detailed description of OBSERV in (Tyszberowicz and Yehudai, 1992).
The translation of regular objects is almost straightforward. For each incoming event and for each state, we define a boolean variable with the name of the event or state. When the variable associated with the incoming event is true it means that the event occurred at that point in time. When the variable associated with the state is true, it means that we are in that specific state. Only one variable representing a state will be true at any step. We can also prove this property using the model checker.
3. BUILDING PROVABLY CORRECT SYSTEMS 3.1 Using the Simulator to Check Properties
OBSERV's simulator can be used to check the behavior of a system under development. First, we can examine the behavior of each type separately. Once all the primitive and regular objects seem to be correctly implemented, we can check compund objects, which are actually subsystems at various levels of granularity.
For a compound object we recursively translate each of its component objects. Then, in order to avoid name clash (the developer can use the same names inside different objects) we use a renaming mechanism.
By using the simulator we can check the functional correctness of the system. We can also find desired properties that the developed system does not fulfill. This, however, is no proof that indeed all the properties and constrains are met. For this, a formal method is needed.
The mapping mechanism causes some minor activities, such as removing declarations and the fairness statements of variables that are no longer input events, defining the values of internal events, etc.
Using the trace option of the simulator-tracing the messages sent among objects-we actually create a file that contains a kind of use-cases (Jacobson et al. , 1992). Those cases help both in the simulation and during the formal verification.
The detailed translation process is described in (Tyszberowicz, 1998). This article describes how OBSERV was used to implement a provably correct Production Cell system.
186
The desired properties of an OBSERV implementation are verified in a stepwise manner. First, each regular and primitive object is separately verified , focusing on modular properties. 'Then, we verify properties of each compound object, the last one being the system itself.
systems that we are currently working on. The language MASS models a system as an act-a collection of tasks, with reactions that prescribe which events should trigger the activation of each task, and what are the real time constraints on the termination of these response tasks. A related real-time logic PLOT for plant modeling and requirements specification was also developed. A deductive proof system is used to verify a MASS design against the PLOT requirements. We plan to use existing model checkers to help the verification process.
In the Production Cell example we proved safety ("something bad never happens") and liveness ( "something good eventually happens" ) properties . Thus, for example, one of the safety demands was that the belt emits a signal (ready_to_consume) which means it is allowed to put a blank on it, only when the belt has no blanks on it (at the state unloaded). The CTL formula to verify this property of the belt (i.e., this is checked when the belt is designed) is
5. REFERENCES Backer, A., R. Budde, K. Kulenkamp, A. Meckenstock, K.-H. Sylla and H. Ziillighoven (1988). Prolab, a Prolog programming environment user's manual. Technical report. GMD. St. Augustin, Germany. Dasarathy, B. (1985). Timing constraints of real-time systems: Constructs for expressing them, methods of validating them. IEEE Transactions on Software Engineering 11(1), 80-86. Gafni, V. (1997) . MASS/PLOT, A Specification Framework for Real-Time Systems. PhD the-
AG(ready _to_consume -+ unloadedJeft) .
AG(f) means that the formula f holds on every path from the initial state; i.e., f holds globally. In this example we state that the belt emits ready_to_consume only when it is in the unloaded_left state. An example of a liveness property that was proved is that once the belt is in its unloaded state, it will eventually arrive its at-edge position (loaded with the blank).
SiS.
AG(unloaded -+ AF aLedge) .
Tel-Aviv University. ftp://ftp.math.tau .ac.il /pub/amiram/gafni..phd.ps.Z. Jacobson, I., M. Christerson, P. Jonsson and G. Overgaard (1992) . Object-Oriented Software Engineering - A Use Case Driven Approach. Addison-Wesley / ACM Press. Krasner, G.E. and S.T. Pope (1988). A cookbook for using the model-view-controller user interface paradigm in smalltalk-80. Journal of Object-Oriented Programming 1(3), 26-48. McMillan, K. L. (1992). Symbolic Model Checking: An Approach to the State Explosion Problem. PhD thesis. Carnegie Mellon University. Tyszberowicz, S. (1998) . How to implement a safe real-time system: The OBSERV implementation of the production cell case study. RealTime Systems Journal 15(1), 61-90 . Tyszberowicz, S. and A. Yehudai (1990) . OBSERV-The representation language. Technical Report 169/90. Eskenasy Institute of Computer Science, TelAviv University. Israel. Tysz berowicz, S. and A. Yehudai (1992). OBSERV-A prototyping language and environment. TOSEM 1(3), 269-309. Wegner, P. (1987). Dimensions of object-based languages design. Proceedings of OOPSLA '87, SIGPLAN Notices 22(12), 168-182.
Both properties have been demonstrated when the belt object was simulated. In order to prove the correctness, we needed the model checker.
4. FURTHER WORK OBSERV has been used to construct executable specification of systems under development _ The properties of the methodology enabled us to specify reactive real-time systems. After running si mulations, which demonstrated the behavior of the system, we used a model checker to verify that the system indeed always fulfill some desired properties. The model checker has mainly been used to verify safety and unbounded responsiveness properties. Those properties are important for any system. For real-time systems, however, many of the responses are constrained in time. Failure to fulfill those time constraints means failure of the system. SMV supplies algorithms that compute the minimum and the maximum number of occurrences of a condition on any path between two given events. We are trying now to see how to use them to verify some quantitative temporal properties (like responsiveness within a given number of time units, etc) . MASS (Gafni, 1997) is an activation oriented approach for hierarchical representation of real-time
187