So-called "guarded commands" are introduced as a building block for alternative and repetitive constructs that allow non-deterministic program components for which at least the activity evoked, but possibly even the final state, is not necessarily uniquely determined by the initial state. For the formal derivation of programs expressed in terms of these constructs, a calculus will be shown. CR-category: 4. Guarded commands, non-determinacy and a calculus for the derivation of programs. In section 2, two statements, an alternative construct and a repetitive construct will be introduced, together with an intuitive mechanistic definition of their semantics.
|Published (Last):||8 December 2005|
|PDF File Size:||12.40 Mb|
|ePub File Size:||5.71 Mb|
|Price:||Free* [*Free Regsitration Required]|
Each named step is passed two blocks: an ensure block that defines a test for a necessary and sufficient condition of the step, and a using block that will cause that condition to obtain.
If the using block is ommitted, the step acts as a simple assertion. If step is called in void context i. If do is given arguments, they will be passed to the ensure block and if necessary the using block. Defines a new guarded command step. If called in void context, the step is executed immediately. If called in scalar or array context i. NAME is a string that will be printed on failure also see verbose below.
Typically at least a ensure and using block will be included. Note that because step is a subroutine and not a control structure though it acts like one in void context , it typically must be followed by a semicolon.
If true, will print output not only on failure of a step, but also at the beginning of a step i. Also prints a message "Step step name succeeded" if the ensure condition now obtains after running using. Whether or not verbose is set, an exception will be thrown if the condition fails to obtain after running using, with the message "Step step name failed at line Clears rollbacks. Should return true if the condition of the test has been met, false otherwise. If the using block is omitted, the step will work as a simple assertion: if the ensure block returns a false value, an exception will be thrown.
The condition is checked at the beginning of the enclosing step prior to ensure , and again after running the using block if the using block is run, of course. If it returns a false value, an exception is thrown with the message "Sanity check for step name failed".
Note given this behavior that a sanity check should specify an invariant condition, i. If this step, or any following step, fails either through ensure verification or sanity check failure , the rollback will be run.
Warning: if an exception die or croak is thrown in your rollback, the script will stop and other rollbacks will not be called. If arguments are supplied, they will be passed to every block within the step. Note that the arguments are read-only within the block i. Some attempt is made to deal with return values, so you can get something approximating a reasonable result from do when the using block has executed. But the author has not found a real-world need for return values, so their behavior is not very well-defined.
Feel free to contact him if you believe you have a solution. After all ensures have been run, run using with those arguments whose ensure failed. Return values are not supported. At present, multiple arguments for each call are not supported, either though you can certainly simulate that using a list-of-lists, if you write your blocks to take an arrayref. Will throw an exception if the file cannot be opened for reading. Will throw an exception if the file cannot be opened for writing.
Will throw an exception if the file cannot be opened for appending. Much has been written on good programming methodology, but in general such methodologies have general-purpose programs in mind. When applied to scripts, which are generally very high-level and procedural in nature, the methodologies can rapidly result in unreadable spaghetti, with more code devoted to methodology than to method.
Most scripters react in one of two ways: they either let the spaghetti ensue, or they throw up their hands and write fragile code. An example Suppose you want to write a script to mount a scratch directory from an NFS server. If anything at all went wrong, the user would be left to pick up the pieces afterwards. Good scripters will check for errors. There are now nine places where the script may abnormally terminate, leaving the task incomplete and the user still to pick up the pieces.
If the script aborts early, the user may choose to try to fix the problem encountered and then manually revert to the initial state so that the script can be re-executed. Worse yet, the first response of many users to an unexpected error message is simply to try the command again.
If the script aborts late in the process, the user may try to fix the encountered problem and then finish the task manually. This too, is fraught with peril--and the entire point of automating the task was to reduce the chance of operator error!
One last observation about this new script--the functional code of the script has now been largely obscured by the error-checking code. In a larger, more complicated script, the code could rapidly degenerate into an unreadable mass. This hardly seems like good reason for the script to entirely fail. The problem is that naive error-checking as above is syntactic in basis--a result of conditions intrinsic to the implementation of the script--rather than being semantic--i.
Guarded commands to the rescue These observations have resulted in the development of this module. Using guarded commands, the script can be written more resiliently, more clearly, and in many cases, more easily.
The first step in writing a script using guarded commands is to decompose the actions desired into a set of procedures, or steps. In this script, like many in system automation programming, the steps are strictly linear, with each dependent on one or more steps prior. Some scripts will have more complicated dependencies, loops, conditionals and the like. For each step, one needs to define two things: A necessary and sufficient condition to judge whether the step has been completed.
Code that will cause that condition to come into being. The code above would have created exactly one space between the two fields, but the regex allows for any amount of whitespace. If conditions change--for example, a new machine is preconfigured with a suitable fstab entry--the script will continue to function. Having written the condition for the step--expressed in an ensure block--the scripter then turns to how to bring the condition about.
There is no need. If the print fails, there will be no fstab entry corresponding to the regex above, and the script will fail for want of having obtained the condition. It may seem wrong at first--even blasphemous! This is the first Lesson: Lesson 1. Trust your conditions, and the rest will follow. Because its checks are semantic in nature, the script will react properly to minor changes in the environment that would derail a conventionally written script.
If it fails due to some unforeseen problem, it can be rerun once the problem has been fixed. It will automatically pick up exactly where it left off. Not only can this script be used to cause the intended state to come into being in this case, mounting the scratch filesystem , it can be used to verify that the state exists. If it exits without failure, then the desired state is verified. It would be perfectly reasonable, for instance, to include the above script in a crontab entry run periodically.
If something went awry--e. Only important tests--the semantic ones--need to be written. There is no need to check every possible error condition of every line of code. The error-checking code and the running code are held together in a single step command, but are separated into ensure and using blocks. This results in a more readable script without error-checking spaghetti.
Lesson 2. With guarded commands, you can afford to be audacious. If every line of code in a script that has a side effect is put into using blocks, the script becomes much less dangerous.
There is a smaller chance that the script will "run away" and do something unexpected and horrible. Each step is checked after a using block is run, and so long as your semantic tests are correct, the script will halt if things start to go awry. Lesson 3. Take note of idempotence, and turn it to your advantage. Many UNIX tools have the property of idempotence: ln -f, cp, and rsync are three examples.
Idempotence is a large part of the power of Commands::Guarded. If you put every expression with side-effects or, more precisely, side effects that will persist beyond the life of the script, e. In turn, a script that completes successfully is also idempotent: you can run it again and it should change nothing.
Knowing about idempotence can help you in writing your ensure and using blocks. The following import tags can be used: :step or :default Imports the default subs of step, ensure, using, sanity, and rollback. This is also what you get if you just say use Commands::Guarded; but you will need to use one of these tags if you import another tag or named sub.
Describes guarded commands in a fundamentally different form than implemented in this module. Please note that because this was an Invited Talk, information is not included in the proceedings of that conference. TODO A method to selectively clear rollbacks. This is complicated because the same rollback codeblock might be registered several times with different arguments using do ARGS. Rational behavior when ensure is omitted.
Today it just throws an error. A reasonable way to extend and subclass. Thanks and love to J. As sane as I ever am, anyway.
Guarded commands, nondeterminacy and formal derivation of programs
SPIN verifies correct operation of concurrent software applications. From Wikipedia, the free encyclopedia. Retrieved August 16, Skip and Abort are very simple as guardex as important statements in the guarded command language. Its simplicity makes proving the correctness of programs easier, using Hoare logic. Skip is the empty instruction: If none of the guards are true, the result is undefined.
Guarded commands, non-determinacy and a calculus for the derivation of programs
Each named step is passed two blocks: an ensure block that defines a test for a necessary and sufficient condition of the step, and a using block that will cause that condition to obtain. If the using block is ommitted, the step acts as a simple assertion. If step is called in void context i. If do is given arguments, they will be passed to the ensure block and if necessary the using block.