Building Parallel Embedded And Realtime Applications With Ada John W Mccormick
Building Parallel Embedded And Realtime Applications With Ada John W Mccormick
Building Parallel Embedded And Realtime Applications With Ada John W Mccormick
Building Parallel Embedded And Realtime Applications With Ada John W Mccormick
1. Building Parallel Embedded And Realtime
Applications With Ada John W Mccormick download
https://ebookbell.com/product/building-parallel-embedded-and-
realtime-applications-with-ada-john-w-mccormick-2149188
Explore and download more ebooks at ebookbell.com
2. Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Building Parallel Programs Smps Clusters And Java 1st Edition Alan
Kaminsky
https://ebookbell.com/product/building-parallel-programs-smps-
clusters-and-java-1st-edition-alan-kaminsky-2427182
Modern Fortran Building Efficient Parallel Applications 1st Edition
Milan Curcic
https://ebookbell.com/product/modern-fortran-building-efficient-
parallel-applications-1st-edition-milan-curcic-12023762
Pro Tbb C Parallel Programming With Threading Building Blocks 1st
Edition Michael Voss
https://ebookbell.com/product/pro-tbb-c-parallel-programming-with-
threading-building-blocks-1st-edition-michael-voss-50195056
Joyfully Together The Art Of Building A Harmonious Community Thich
Nhat Hanh
https://ebookbell.com/product/joyfully-together-the-art-of-building-a-
harmonious-community-thich-nhat-hanh-5756860
3. Building Spas With Django And Html Over The Wire Learn To Build
Realtime Single Page Applications With Python 1st Edition Andros
Fenollosa
https://ebookbell.com/product/building-spas-with-django-and-html-over-
the-wire-learn-to-build-realtime-single-page-applications-with-
python-1st-edition-andros-fenollosa-44868684
Building The Snowflake Data Cloud Monetizing And Democratizing Your
Data Andrew Carruthers
https://ebookbell.com/product/building-the-snowflake-data-cloud-
monetizing-and-democratizing-your-data-andrew-carruthers-44888670
Building Web Applications With Vuejs Mvvm Patterns For Conventional
And Singlepage Websites Ralph Steyer
https://ebookbell.com/product/building-web-applications-with-vuejs-
mvvm-patterns-for-conventional-and-singlepage-websites-ralph-
steyer-44898498
Building Bridges Between Soft And Statistical Methodologies For Data
Science Luis A Garcaescudero
https://ebookbell.com/product/building-bridges-between-soft-and-
statistical-methodologies-for-data-science-luis-a-
garcaescudero-44905084
Building Microservices Designing Finegrained Systems 2nd Edition 2nd
Release 2nd 20220708 Second Release Sam Newman
https://ebookbell.com/product/building-microservices-designing-
finegrained-systems-2nd-edition-2nd-release-2nd-20220708-second-
release-sam-newman-45010590
7. BUILDING PARALLEL, EMBEDDED, AND REAL-TIME
APPLICATIONS WITH ADA
The arrival and popularity of multi-core processors have sparked a renewed interest
in the development of parallel programs. Similarly, the availability of low-cost
microprocessors and sensors has generated a great interest in embedded real-time
programs. This book provides students and programmers whose backgrounds are in
traditional sequential programming with the opportunity to expand their capabilities
into parallel, embedded, real-time, and distributed computing. It also addresses the
theoretical foundation of real-time scheduling analysis, focusing on theory that is
useful for actual applications.
Written by award-winning educators at a level suitable for undergraduates and
beginning graduate students, this book is the first truly entry-level textbook in the
subject. Complete examples allow readers to understand the context in which a new
concept is used, and enable them to build and run the examples, make changes, and
observe the results.
john w. mccormick is Professor of Computer Science at the University of
Northern Iowa.
frank singhoff is Professor of Computer Science at Université de
Bretagne Occidentale (University of Brest).
jérôme hugues is Associate Professor in the Department of Mathematics,
Computer Science, and Control at the Institute for Space and Aeronautics Engi-
neering (ISAE), Toulouse.
9. BUILDING PARALLEL, EMBEDDED,
AND REAL-TIME APPLICATIONS
WITH ADA
JOHN W. MCCORMICK
University of Northern Iowa
FRANK SINGHOFF
Université de Bretagne Occidentale
J É RÔME HUGUES
Institute for Space and Aeronautics
Engineering (ISAE), Toulouse
10. cambridge university press
Cambridge, New York, Melbourne, Madrid, Cape Town,
Singapore, São Paulo, Delhi, Tokyo, Mexico City
Cambridge University Press
The Edinburgh Building, Cambridge CB2 8RU, UK
Published in the United States of America by Cambridge University Press, New York
www.cambridge.org
Information on this title: www.cambridge.org/9780521197168
C
J. W. McCormick, F. Singhoff, and J. Hugues 2011
This publication is in copyright. Subject to statutory exception
and to the provisions of relevant collective licensing agreements,
no reproduction of any part may take place without the written
permission of Cambridge University Press.
First published 2011
Printed in the United Kingdom at the University Press, Cambridge
A catalog record for this publication is available from the British Library
Library of Congress Cataloging in Publication data
McCormick, John W., 1948–
Building parallel, embedded, and real-time applications with Ada / John W. McCormick,
Frank Singhoff, Jerome Hugues.
p. cm.
Includes bibliographical references and index.
ISBN 978-0-521-19716-8 (hardback)
1. Ada (Computer program language) 2. Parallel programming (Computer science)
3. Embedded computer systems – Programming. 4. Real-time data processing.
5. Multiprocessors – Programming.
I. Singhoff, Frank. II. Hugues, Jerome. III. Title.
QA76.73.A35M375 2011
004.35 – dc22 2010053214
ISBN 978-0-521-19716-8 Hardback
Cambridge University Press has no responsibility for the persistence or
accuracy of URLs for external or third-party internet websites referred to
in this publication, and does not guarantee that any content on such
websites is, or will remain, accurate or appropriate.
The photograph on the cover shows astronaut Stephen K. Robinson standing on the end of the International Space
Station’s robotic manipulator system, Canadarm 2. This arm, built by MacDonald, Dettwiler, and Associates Ltd
for the Canadian Space Agency, is 17.6 m long when fully extended. It has seven motorized joints, each a complex
embedded real-time system. Given its crucial role on the space station, the reliability of Canadarm 2 must be
impeccable. The software for these joints and for the workstation that the astronauts use to control them is written
in Ada. This book provides an introduction to the concepts of concurrent programming, embedded systems, and
real-time constraints necessary for understanding and developing the software for such systems.
11. Contents
List of illustrations page viii
List of tables x
Foreword xi
Preface xiii
1 Introduction and overview 1
1.1 Parallel programming 2
1.2 Distributed programming 11
1.3 Real-time systems 12
Summary 19
Exercises 20
2 Sequential programming with Ada 23
2.1 Control structures 26
2.2 Subprograms 30
2.3 The Ada type model 35
2.4 Blocks and exceptions 62
2.5 Programming in the large 65
2.6 Object-oriented programming 76
2.7 Low-level programming 82
Summary 102
Exercises 103
3 Task basics 107
3.1 Defining tasks 107
3.2 The task life cycle 109
3.3 Task hierarchies 113
3.4 Exceptions 117
3.5 The implementation of Ada tasking 119
3.6 Other task features 119
12. vi Contents
Summary 121
Exercises 122
4 Communication and synchronization based on shared
objects 126
4.1 Mutual exclusion 126
4.2 The protected object 130
4.3 Synchronization 134
4.4 The protected entry 135
4.5 Restrictions 140
4.6 Entry queues 141
4.7 Some useful concurrent patterns 143
4.8 Requeue and private operations 149
4.9 Pragmas Atomic and Volatile 153
4.10 Interrupts 155
Summary 161
Exercises 162
5 Communication and synchronization based on direct
interaction 166
5.1 The rendezvous 166
5.2 The selective accept statement 171
5.3 Entry call options 180
5.4 State machines 181
Summary 191
Exercises 192
6 Distributed systems with Ada 195
6.1 What are distributed systems? 195
6.2 Middleware, architectures, and concepts 200
6.3 DSA, the Distributed Systems Annex 202
6.4 PolyORB: compilation chain and run-time for the DSA 212
6.5 Advanced DSA concepts 215
6.6 CORBA, the Common Object Request Broker
Architecture 221
6.7 Advanced CORBA concepts 236
6.8 CORBA versus the DSA 247
Summary 248
Exercises 250
7 Real-time systems and scheduling concepts 251
7.1 Task characteristics 253
7.2 Real-time schedulers 257
13. Contents vii
7.3 Dependent tasks 278
Summary 285
Exercises 286
8 Real-time programming with Ada 294
8.1 Expressing time 295
8.2 Implementing periodic tasks 298
8.3 Ada implementation of the car application 303
8.4 Handling shared resources 305
8.5 The Ada scheduling model 308
8.6 Ravenscar 312
8.7 POSIX 1003.1b and its Ada binding 314
8.8 POSIX implementation of the car application 324
8.9 Ada tasks versus POSIX processes 328
Summary 329
Exercises 330
9 Tools for building and verifying real-time
applications 333
9.1 Ada run-times to implement real-time applications 334
9.2 Some variants of the GNAT run-time 339
9.3 Validating scheduling of a system 347
Summary 355
Exercises 356
References 359
Index 365
14. Illustrations
1.1 An example of an embedded system 16
2.1 The Ada type hierarchy 37
2.2 Distribution of model numbers 41
2.3 Access variables 58
2.4 A linked list implementation of a stack of characters 60
2.5 Class diagram for commercial ovens 78
2.6 Association between register bits and enunciation lights 84
2.7 Memory mapped input/output 87
2.8 Port mapped input/output 89
2.9 Example digital to analog converter 90
3.1 The basic states of a task 110
3.2 The substates of executable 112
3.3 Parent tasks are suspended during the activation of a child
task 115
4.1 The read/write lock 133
4.2 The read lock 134
4.3 Entry queues for the protected bounded buffer 142
4.4 Tasks in the entry queues have precedence over those delayed
behind the lock 143
5.1 Statement sequencing in rendezvous 167
5.2 State machine diagram notation 182
5.3 State diagram for car headlights 183
5.4 State diagram for a large induction motor 188
6.1 Overview of a middleware 197
6.2 Distribution models 198
6.3 Interaction using a middleware 200
6.4 Ada user code and the Ada run-time 212
6.5 Sequence of actions for synchronous calls 216
6.6 Sequence of actions for asynchronous calls 216
6.7 Overview of CORBA 222
15. List of illustrations ix
6.8 Components of an IOR 242
6.9 Hierarchy of POAs 245
7.1 Parameters of a periodic task 257
7.2 Example of scheduling with preemptive fixed priority scheduler
and Rate Monotonic priority assignments 262
7.3 Example of scheduling with non-preemptive fixed priority sched-
uler and Rate Monotonic priority assignments 263
7.4 Task i worst case response time 266
7.5 Template for analysis with exhaustive simulations 271
7.6 Analysis with exhaustive simulations 271
7.7 Scheduling with a preemptive EDF scheduler 274
7.8 Scheduling with a non-preemptive EDF scheduler 275
7.9 A priority inversion 279
7.10 A scheduling sequence with PIP 281
7.11 A scheduling sequence with ICPP 282
7.12 Task release time jitter 284
7.13 Holistic analysis 285
8.1 A comparison of the drift in release times for using relative and
absolute delays 301
8.2 Ada’s scheduling model 309
8.3 Example of an application using several different dispatching
policies 312
8.4 POSIX 1003.1b scheduling model 317
8.5 Drawing to fill 331
9.1 Layered design of an Ada program 340
9.2 Characterizing the parameters of a task with Cheddar 351
9.3 Output of the Cheddar tool: feasibility tests 352
9.4 Output of the Cheddar tool: simulation 353
16. Tables
2.1 Magnitude of range gate error when modeling time as a floating
point real number 41
2.2 The layout of the control status register 91
5.1 A state transition table for the state machine of Figure 5.3 186
6.1 IDL-to-Ada mapping rules 227
7.1 Dynamic priorities handled by Earliest Deadline First 273
7.2 A simple comparison of fixed priority scheduling and EDF 277
8.1 Some chapters of the POSIX 1003 standard 315
17. Foreword
The task of programming is a difficult one. Over the decades there have
been many promises to eliminate this difficulty. It is interesting to recall
that Fortran was first promoted on the basis that it would do away with
programming, and allow scientists to enter their mathematical equations
directly into the computer. Yet, the difficulty of programming has not gone
away, and indeed, the task is more difficult now, especially because of the
widespread introduction of parallelism into all realms of programming.
In universities today, many professors find that students shy away from
difficult problems and challenges. As a result computer science programs
have been made easier and “more fun,” and many recent textbooks reflect
this worrisome trend. What we need is not students who find easy stuff fun,
we need students who find difficult challenges fun!
In this climate a textbook that tackles the most difficult area of program-
ming, the creation of complex embedded systems in which parallelism and
real-time concerns play a major role, is very welcome. We entrust our lives to
such complex systems all the time these days, in cars, planes, trains, medical
equipment, and many other circumstances.
This book addresses the task of teaching the complex elements required
to create such systems. The choice of Ada, though unfamiliar for say the
creation of simple web programs, is a natural one for two reasons. First, it
is the only language in common use where tasking and parallelism play an
important “first-class” citizen role (C/C++ rely entirely on external libraries
for such support, and the support for such concepts in Java is very weak).
Second, Ada is indeed a language of choice for building complex systems
of this kind. For example, much of the avionics in the new Boeing 787
“Dreamliner” is written in Ada, as is the new air traffic control system
in England. The choice of Ada as a vehicle is thus a good one, and actually
18. xii Foreword
makes it easier for students to grasp the critical new concepts, even though
they may have been exposed to other languages previously.
This book is an important addition to the arsenal of teaching materials
for a well-educated computer science graduate. It is also eminently readable,
and, perhaps I can even say it is fun to read. Despite the potentially dry na-
ture of this subject matter, it is presented in an entertaining and accessible
manner that reflects the remarkable teaching skills of its authors.
Robert Dewar
AdaCore
19. Preface
The arrival and popularity of multi-core processors have sparked a renewed
interest in the development of parallel programs. Similarly, the availability
of low cost microprocessors and sensors has generated a great interest in em-
bedded real-time programs. This book provides students and programmers
with traditional backgrounds in sequential programming the opportunity
to expand their capabilities into these important emerging paradigms. It
also addresses the theoretical foundations of real-time scheduling analysis,
focusing on theory that is useful for real applications.
Two excellent books by Burns and Wellings (2007; 2009) provide a com-
plete, in depth presentation of Ada’s concurrent and real-time features. They
make use of Ada’s powerful object-oriented programming features to create
high-level concurrent patterns. These books are “required reading” for soft-
ware engineers working with Ada on real-time projects. However, we found
that their coverage of all of Ada’s concurrent and real-time features and the
additional level of abstraction provided by their clever use of the object-
oriented paradigm made it difficult for our undergraduate students to grasp
the fundamental concepts of parallel, embedded, and real-time program-
ming. We believe that the subset of Ada presented in this book provides
the simplest model for understanding the fundamental concepts. With this
basic knowledge, our readers can more easily learn the more detailed aspects
of the Ada language and the more widely applicable patterns presented by
Burns and Wellings. Readers can also apply the lessons learned here with
Ada to the creation of systems written in more complex languages such as
C, C++, and real-time Java.
The first chapter gives an overview of and motivation for studying par-
allel, embedded, and real-time programming. The fundamental terminology
of parallel, concurrent, distributed, real-time, and embedded systems is pre-
sented in the context of two cooks sharing resources to prepare food.
20. xiv Preface
The first six sections of Chapter 2 provide a brief introduction to se-
quential programming with Ada. Only those Ada constructs relevant to the
remainder of the book are presented. In conjunction with the on-line learn-
ing references provided, our students whose backgrounds did not include
Ada were able to come quickly up to speed with their peers who had some
previous Ada experience. Students with some Ada background found this
chapter an excellent review of the language. The final section of this chap-
ter provides detailed coverage of Ada’s low-level programming constructs.
These features allow the program to interact with hardware — almost al-
ways necessary in an embedded system. These features are illustrated with
a complete example of a device driver for a sophisticated analog to digital
converter.
Chapter 3 introduces the notion of the task, Ada’s fundamental construct
for parallel execution. We show how tasks are created, activated, run, and
completed. We use state diagrams to illustrate the life cycle of a task. We
present the parent-child and master-dependent task hierarchies. We conclude
this chapter with a brief discussion of some less frequently used tasking
features: abortion, identification, and programmer-defined attributes.
Chapter 4 introduces the most widely used construct for communication
and synchronization between tasks — the protected object. The need for mu-
tual exclusion, introduced with cooking examples in Chapter 1, is revisited
in the context of an Ada program with multiple tasks incrementing a shared
variable. After demonstrating this classic problem, we introduce encapsu-
lation of shared data within a protected object. We illustrate the locking
mechanisms provided by protected functions and procedures with several
figures. The need for synchronization, again introduced with cooking exam-
ples in Chapter 1, is revisited and the solution based on the protected entry
is discussed and illustrated. We provide additional practice with protected
objects by developing a number of useful concurrent patterns — semaphores,
barriers, and broadcasts. The use of requeue is motivated with a problem of
allocating a limited number of pencils. The chapter concludes with a discus-
sion of interrupts. We return to the analog to digital converter introduced
in Chapter 2 and replace the polling logic with an interrupt handler.
Chapter 5 looks at the use of direct task interaction through the ren-
dezvous. We begin by illustrating the behavior of simple entry calls and
accepts. Then we discuss the variations of the selective accept statement
that provides the server with more control over its interactions with clients.
We introduce the use of both relative and absolute delays. Next we discuss
the entry call options which give a client more control over its interaction
21. Preface xv
with a server. We conclude this chapter with a discussion on the implemen-
tation of state machines for both passive and active objects.
Distribution is an important issue in software engineering and is the topic
of Chapter 6. While it is easy to motivate the advantages of distribution,
the details take more effort. We introduce middleware and discuss the major
problems with distributed applications. We provide an introduction to two
approaches for distributing an Ada program. The Distributed Systems An-
nex (DSA) provides a solution for a pure Ada application. We develop the
software for a very simple distributed student information system through
three examples of increasing complexity. For those who want more details,
we provide information on more advanced DSA concepts. While CORBA
requires a larger amount of code to implement a distributed system than
the DSA, it is more commonly used in industry. Not only is there more sup-
port for CORBA than the DSA, it provides an easy integration of different
programming languages in a single application. We use the same example of
a distributed student information system to develop a CORBA-based solu-
tion. Again, we provide additional details for those wanting a more advanced
understanding of CORBA. We introduce and use the PolyORB tool for our
DSA and CORBA examples.
Chapter 7 is an introduction to the theoretical foundations of real-time
scheduling analysis, focusing on theory that is useful for real applications.
This presentation is independent of any programming language. We begin
with an introduction of the characteristics of a task relevant to scheduling
analysis. We define the characteristics of schedulers and discuss fixed priority
scheduling and earliest deadline first scheduling. Ensuring that all tasks
meet their deadlines is paramount to any hard real-time system. We show
you how to calculate and use processor utilization factors and worst case
response times to verify schedulability. We begin by analyzing examples
with independent tasks. Then we add the complexities of resource sharing
with different priority inheritance protocols.
In Chapter 8 we explain how to write real-time applications in Ada that
are compliant with the scheduling theory discussed in the previous chapter.
In particular, we show how to implement periodic tasks, activate priority
inheritance protocols, and select an appropriate scheduler. The first six sec-
tions discuss how we can use Ada’s Real-Time Systems Annex to implement
compliant applications. The remainder of the chapter is devoted to imple-
menting such applications with POSIX. We conclude with a comparison of
the two approaches.
Our Ada applications do not run alone. They execute within a run-time
configuration consisting of the processor and the environment in which the
22. xvi Preface
application operates. Our final chapter introduces the reader to run-time
environments. We discuss three variants of the GNAT run-time: ORK+,
MaRTE, and RTEMS. We examine the effect of the run-time on the analysis
of schedulability and the determination of task characteristics such as worst
case execution time. The schedulability tools MAST and Cheddar are also
introduced.
Resources
A website with the complete source code for all examples and some of the
exercises in the book may be found at www.cambridge.org/9780521197168.
Solutions to all of the exercises are available to qualified instructors. Please
visit www.cambridge.org/9780521197168.
Acknowledgments
We would like to thank the many individuals who have helped us with this
project. The comments, corrections, and suggestions made by our technical
reviewers, Alexander Mentis and Pat Rogers, have enormously improved and
enriched this book. We are grateful to them both. In addition to providing
many useful comments and corrections, Dan Eilers compiled many of our
examples with the ICC Ada compiler to ensure we did not use any GNAT-
specific constructs.
It is sometimes difficult for those of us with years of experience to write
for those who are just beginning. The students in the Real-Time Systems
class at the University of Northern Iowa did not hesitate to point out those
portions of the manuscript, including the exercises, they felt needed further
explanation.
Anyone who has written a textbook can appreciate the amount of time
and effort involved and anyone related to a textbook author can tell you
at whose expense that time is spent. John thanks his wife Naomi for her
support and understanding.
Frank would like to thank all his Master’s students who have for the past
10 years tested his courses and exercises on real-time systems. In 2002, we
began work on Cheddar, a simple tool whose goal is to provide students
with a better understanding of real-time scheduling. We were helped by
different partners and contributors: special thanks to Pierre Dissaux, Alain
Plantec, Jérôme Legrand, Laurent Pautet, Fabrice Kordon, Peter Feiler,
Jérôme Hugues, Yvon Kermarrec and all the others that are listed on the
Cheddar website. Finally, many thanks Magali for your patience during all
my busy days off!
23. Preface xvii
Jérôme would like to thank all his friends and colleagues for the memorable
years he spent working on PolyORB at Telecom ParisTech: Laurent Pautet,
Fabrice Kordon, and all our Master’s students that helped us at that time;
Bob Duff and Thomas Quinot from AdaCore; and Vadim Godunko for all his
personal contributions to the project. Participating in such a large project,
and seeing it now as a project used in the industry, is a great pleasure.
Finally, I’d like to thank Alice for letting me write this book near the fireplace
over the long winter nights!
John W. McCormick
University of Northern Iowa
mccormick@cs.uni.edu
Frank Singhoff
Université de Bretagne Occidentale
singhoff@univ-brest.fr
Jérôme Hugues
Institute for Space and Aeronautics
Engineering (ISAE), Toulouse
jerome.hugues@isae.fr
25. 1
Introduction and overview
The arrival and popularity of multi-core processors have sparked a renewed
interest in the development of parallel programs. Similarly, the availability
of low-cost microprocessors and sensors has generated a great interest in
embedded real-time programs. Ada is arguably the most appropriate lan-
guage for development of parallel and real-time applications. Since it was
first standardized in 1983, Ada’s three major goals have remained:
• Program reliability and maintenance
• Programming as a human activity
• Efficiency
Meeting these goals has made Ada remarkably successful in the domain
of mission-critical software. It is the language of choice for developing soft-
ware for systems in which failure might result in the loss of life or prop-
erty. The software in air traffic control systems, avionics, medical devices,
railways, rockets, satellites, and secure data communications is frequently
written in Ada. Ada has been supporting multiprocessor, multi-core, and
multithreaded architectures as long as it has existed. We have nearly 30
years of experience in using Ada to deal with the problem of writing pro-
grams that run effectively on machines using more than one processor. While
some have predicted it will be another decade before there is a programming
model for multi-core systems, programmers have successfully used the Ada
model for years. In February 2007, Karl Nyberg won the Sun Microsystems
Open Performance Contest by building an elegant parallel Ada application
(Nyberg, 2007). The parallel Ada code he wrote a decade earlier provided
the foundation of this success.
It is estimated that over 99% of all the microprocessors manufactured
these days end up as part of a device whose primary function is not com-
puting (Turley, 1999). Today’s airplanes, automobiles, cameras, cell phones,
26. 2 Introduction and overview
GPS receivers, microwave ovens, mp3 players, tractors, and washing ma-
chines all depend on the software running on the microprocessors embedded
within them. Most consumers are unaware that the software in their new
washing machine is far more complex than the software that controlled the
Apollo moon landings. Embedded systems interact with the world through
sensors and actuators. Ada is one of the few programming languages to
provide high-level operations to control and manipulate the registers and
interrupts of these input and output devices.
Most programs written for embedded systems are real-time programs. A
real-time program is one whose correctness depends on both the validity
of its calculations and the time at which those calculations are completed
(Burns and Wellings, 2009; Laplante, 2004). Users expect that their wireless
phone will convert and transmit their voice quickly and regularly enough
that nothing in their conversation is lost. Audio engineers quantify “quickly”
into the maximum amount of time that the analog to digital conversion,
compression, and transmission will take. They specify a set of deadlines.
A deadline is a point in time by which an activity must be completed.
Software engineers have the responsibility of ensuring that the computations
done by the software are completed by these deadlines. This responsibility
is complicated by the parallel nature of most real-time embedded software.
One embedded processor may be responsible for a number of related control
operations. Our wireless phone should not lose any of the video it captures
simultaneously with our talking. The software engineer must ensure that
all of the tasks competing for processor cycles finish their computations on
time.
1.1 Parallel programming
A parallel program is one that carries out a number of operations simulta-
neously. There are two primary reasons for writing parallel programs. First,
they usually execute faster than their sequential counterparts. The prospect
of greater performance has made parallel programming popular in scientific
and engineering domains such as DNA analysis, geophysical simulations,
weather modeling, and design automation. There are theoretical limits on
how much speedup can be obtained by the use of multiple processors. In
1967, Gene Amdahl published a classic paper (Amdahl, 1967) that showed
that if P is the fraction of a sequential program that can be run in parallel
27. 1.1 Parallel programming 3
on N processors, the maximum speedup is given by the formula
1
(1 − P) + P
N
Thus, for example, if 80% of our program can be run in parallel, the maxi-
mum speedup obtained with four processors is
1
(1 − 0.8) + 0.8
4
= 2.5
The second reason for writing parallel programs is that they are frequently
better models of the processes they represent. More accurate models are
more likely to behave in the manner we expect. As the real world is inherently
parallel, embedded software that interacts with its environment is usually
easier to design as a collection of parallel solutions than as a single sequential
set of steps. Parallel solutions are also more adaptable to new situations than
sequential solutions. We’ll show you some examples later in this chapter
where the parallel algorithm is far more flexible than the sequential version.
Before beginning our discussion of parallel programming, let’s take a brief
look at the hardware on which such programs execute.
1.1.1 Flynn’s taxonomy
Michael Flynn (1974) described a simple taxonomy of four computer archi-
tectures based on data streams and instruction streams. He classifies the
classic Von Neumann model as a Single stream of Instructions executing on
Single stream of Data (SISD). An SISD computer exhibits no parallelism.
This is the model to which novice programmers are introduced as they learn
to develop algorithms.
The simplest way to add parallelism to the SISD model is to add multi-
ple data streams. The Single stream of Instructions executing on Multiple
streams of Data (SIMD) architecture is often called array or vector pro-
cessing. Originally developed to speed up vector arithmetic so common in
scientific calculations, an SIMD computer applies a single instruction to mul-
tiple data elements. Let’s look at an example. Suppose we have the following
declarations of three arrays of 100 real values.
subtype Index Range i s I n t e g e r range 1 . . 1 0 0 ;
type Vector i s array ( Index Range ) of Float ;
A, B, C : Vector ; –– Three array v a r i a b l e s
28. 4 Introduction and overview
We would like to add the corresponding values in arrays B and C and store
the result in array A. The SISD solution to this problem uses a loop to apply
the add instruction to each of the 100 pairs of real numbers.
for Index in Index Range loop
A ( Index ) := B ( Index ) + C ( Index ) ;
end loop ;
Each iteration of this loop adds two real numbers and stores the result in
array A. With an SIMD architecture, there are multiple processing units for
carrying out all the additions in parallel. This approach allows us to replace
the loop with the simple arithmetic expression
A := B + C;
that adds all 100 pairs of real numbers simultaneously.
The Multiple stream of Instructions executing on a Single stream of Data
(MISD) architecture is rare. It has found limited uses in pattern match-
ing, cryptology, and fault-tolerant computing. Perhaps the most well-known
MISD system is the space shuttle’s digital fly-by-wire flight control sys-
tem (Knoll, 1993). In a fly-by-wire system, the pilot’s controls have no direct
hydraulic or mechanical connections to the flight controls. The pilot’s input
is interpreted by software which makes the appropriate changes to the flight
control surfaces and thrusters. The space shuttle uses five independent pro-
cessors to analyze the same data coming from the sensors and pilot. These
processors are connected to a voting system whose purpose is to detect and
remove a failed processor before sending the output of the calculations to
the flight controls.
The most common type of parallel architecture today is the MIMD (Mul-
tiple stream of Instructions executing on Multiple streams of Data) archi-
tecture. Nearly all modern supercomputers, networked parallel computers,
clusters, grids, SMP (symmetric multiprocessor) computers and multi-core
computers are MIMD architectures. These systems make use of a number
of independent processors to execute different instructions on different sets
of data. There is a great variety in the ways these processors access mem-
ory and communicate among themselves. MIMD architectures are divided
into two primary groups: those that use shared memory and those that use
private memory.
The simplest approach to shared memory is to connect each processor
to a common bus which connects them to the memory. The shared bus
and memory may be used for processors to communicate and to synchro-
nize their activities. Multi-core processors reduce the physical space used by
placing multiple processors (cores) on a single chip. Each core usually has its
29. 1.1 Parallel programming 5
own small memory cache and shares a larger on-chip cache with its counter-
parts. In more complicated schemes, multiple processors may be connected
to shared memory in hierarchical or network configurations.
When each processor in an MIMD system has its own private memory,
communication among them is done by passing messages on some form of
communication network. There are a wide variety of interconnection net-
works. In static networks, processors are hardwired together. The connec-
tions in a static network can be made in a number of configurations including
linear, ring, star, tree, hypercube, and so on. Dynamic networks use some
form of programmable switches between the processors. Switching networks
may range from simple crossbar connections between processors in a single
box to the internet-connecting processors on different continents.
1.1.2 Concurrent programming
With the many different organizations of parallel hardware available, it
might seem that a programmer would need a detailed understanding of
the particular hardware they are using in order to write a parallel program.
As usual in our discipline, we are saved by the notion of abstraction. The
notion of the concurrent program as a means for writing parallel programs
without regard for the underlying hardware was first introduced by Edsger
Dijkstra (1968). Moti Ben-Ari (1982) elegantly summed up Dijkstra’s idea
in three sentences.
Concurrent programming is the name given to programming notation and tech-
niques for expressing potential parallelism and solving the resulting synchronization
and communication problems. Implementation of parallelism is a topic in computer
systems (hardware and software) that is essentially independent of concurrent pro-
gramming. Concurrent programming is important because it provides an abstract
setting in which to study parallelism without getting bogged down in the imple-
mentation details.
When a sequential program is executed, there is a single thread of control.
The instructions are executed one at a time in the order specified by the
program. A concurrent program is a collection of sequential processes.1 Each
of these processes has its own thread of control that executes its instructions
one at a time, its own set of registers, and its own stack for local variables,
parameters, etc. Given adequate hardware, each process may execute on its
own processor using shared or private memory. A concurrent program may
1 The term process has specific and sometimes different meanings in the context of particular
operating systems. The term process in the context of concurrent programming is a general
term for a sequence of instructions that executes concurrently with other sequences of
instructions.
30. 6 Introduction and overview
also execute on a single processor system by interleaving the instructions
of each process. Between these extremes is the more common situation of
having N processes executing on M processors where N M. In this case,
the execution of instructions from N processes is interleaved among the M
processors.
If the processes in a concurrent program are independent, we can write
each process in the same manner in which we write a sequential program.
There are no special concerns or requirements that the programmer must
address. However, it is rare that the processes in a concurrent program are
truly independent. They almost always need to share some resources or
communicate with each other to solve the problem for which the concurrent
program was written. Sharing and communication require programming lan-
guage constructs beyond those needed in sequential programs. In this chap-
ter we introduce the problems that we must resolve in concurrent programs
with interacting processes. Later, we present the Ada language features and
techniques for solving them.
Synchronization is a problem faced in any activity involving concurrent
processing. For example, suppose that Horace and Mildred are cooperating
in the cooking for a dinner party. They expect that the work will go faster
with two people (processors) carrying out the instructions in the recipes. For
the preparation of scalloped potatoes, Horace has taken on the responsibility
of peeling the potatoes while Mildred will cut them into thin slices. As it is
easier to peel a whole potato rather than remove peels from individual slices
of potato, the two have agreed to synchronize their operations. Mildred will
not slice a potato until Horace has peeled it. They worked out the following
algorithms:
Horace’s scalloped potato instructions
while there are still potatoes remaining do
Peel one potato
Wait until Mildred is ready for the potato
Give Mildred the peeled potato
end while
Mildred’s scalloped potato instructions
loop
Wait until Horace has a peeled potato
Take the peeled potato from Horace
Slice the potato
Place the potato slices in the baking dish
Dot the potato slices with butter
Sprinkle with flour
Exit loop when Horace has peeled the last potato
end loop
31. 1.1 Parallel programming 7
Communication among processes is another activity present in nearly all
concurrent activities. Communication is the exchange of data or control
signals between processes. In our cooking example, Horace communicates
directly with Mildred by handing her a peeled potato (data). Further com-
munication is required to let Mildred know that he has peeled the last potato
(a control signal).
What happens when Mildred’s potato slicing is interrupted by a phone
call? When Horace finishes peeling a potato, he must wait for Mildred to
complete her phone call and resume her slicing activities. Horace’s frustra-
tion of having to hold his peeled potato while Mildred talks to her mother
can be relieved with a more indirect communication scheme. Instead of hand-
ing a peeled potato directly to Mildred, he can place it in a bowl. Mildred
will take potatoes out of the bowl rather than directly from Horace. He can
now continue peeling potatoes while Mildred handles the phone call. Should
Horace need to answer a knock at the front door, Mildred may be able to
continue working on the potatoes that he piled up in the bowl while she
was on the phone. The bowl does not eliminate all waiting. Mildred cannot
slice if there is not at least one potato in the bowl for her to take. She must
wait for Horace to place a peeled potato into the bowl. Horace cannot con-
tinue peeling when the bowl is completely full. He must wait for Mildred to
remove a potato from the bowl to make room for his newly peeled potato.
Our concurrent scalloped potato algorithm is an example of the producer-
consumer pattern. This pattern is useful when we need to coordinate the
asynchronous production and consumption of information or objects. In
Chapter 4 we’ll show you how Ada’s protected object can provide the func-
tionality of the potato bowl and in Chapter 5 you will see how Ada’s ren-
dezvous allows processes to communicate directly with each other.
Mutual exclusion is another important consideration in concurrent pro-
gramming. Different processes typically share resources. It is usually not
acceptable for two processes to use the same resource simultaneously. Mu-
tual exclusion is a mechanism that prevents two processes from simultane-
ously using the same resource. Let’s return to our cooking example. Suppose
that Mildred is currently preparing the cake they plan for dessert while Ho-
race is preparing the marinade for the meat. Both require use of the 5 ml
(1 teaspoon) measuring spoon. Mildred cannot be measuring salt with the
spoon at the same time Horace is filling it with soy sauce. They must take
their turns using the shared spoon. Here are the portions of their cooking
algorithms they worked out to accomplish their sharing:
Horace’s marinade instructions
Wait until the 5 ml measuring spoon is on the spoon rack
32. 8 Introduction and overview
Remove the 5 ml measuring spoon from the rack
Measure 10 ml of soy sauce
Wash and dry the 5 ml measuring spoon
Return the 5 ml measuring spoon to the spoon rack
Mildred’s cake instructions
Wait until the 5 ml measuring spoon is on the spoon rack
Remove the 5 ml measuring spoon from the rack
Measure 5 ml of salt
Wash and dry the 5 ml measuring spoon
Return the 5 ml measuring spoon to the spoon rack
This example illustrates a set of steps for using a shared resource. First,
some pre-protocol is observed to ensure that a process has exclusive use of
the resource. In our cooking example, Horace and Mildred use the fact that
the rack on which they hang their measuring spoons cannot be accessed by
two people at the same time in their small kitchen. Second, the resource is
used for a finite amount of time by a single thread of control (a person in
our cooking example). This stage of mutual exclusion is called the critical
section. A critical section is a sequence of instructions that must not be
accessed concurrently by more than one thread of execution. In our example,
the critical section is the use of the 5 ml measuring spoon. After the critical
section, the fourth and final step, the post-protocol, is carried out. The
post-protocol signals an end of the exclusive use of the shared resource.
In our example, the post-protocol consists of cleaning the measuring spoon
and returning it to the spoon rack.
Mutual exclusion is a static safety property (Ben-Ari, 1982). The require-
ment that each critical section excludes other processes from using the re-
source (Mildred and Horace cannot both be filling the 5 ml spoon) does
not change during the execution of the instructions. It is possible to have
safety features that adversely affect the dynamic behavior of a system. For
example, we could make a hand-held electric power saw completely safe by
cutting off the power cord. However, such a drastic safety measure precludes
us from using the saw for its primary purpose. The safety provided by mutual
exclusion can also disrupt our system so that its goals remain unfulfilled.
Returning to our cooking example, Mildred and Horace have devised the
following algorithms for sharing two different measuring spoons.
Horace’s deadly embrace
Wait until the 5 ml measuring spoon is on the spoon rack
Remove the 5 ml measuring spoon from the rack
Wait until the 15 ml measuring spoon is on the spoon rack
Remove the 15 ml measuring spoon from the rack
Measure 20 ml of soy sauce
33. 1.1 Parallel programming 9
Wash and dry the 15 ml measuring spoon
Return the 15 ml measuring spoon to the spoon rack
Wash and dry the 5 ml measuring spoon
Return the 5 ml measuring spoon to the spoon rack
Mildred’s deadly embrace
Wait until the 15 ml measuring spoon is on the spoon rack
Remove the 15 ml measuring spoon from the rack
Wait until the 5 ml measuring spoon is on the spoon rack
Remove the 5 ml measuring spoon from the rack
Measure 20 ml of salt
Wash and dry the 5 ml measuring spoon
Return the 5 ml measuring spoon to the spoon rack
Wash and dry the 15 ml measuring spoon
Return the 15 ml measuring spoon to the spoon rack
These steps certainly prevent Horace and Mildred from using the same
measuring spoon simultaneously. The cooking for most dinner parties goes
without problem. However, one day, when the guests arrive they find no
meal and Horace and Mildred waiting in the kitchen. This is an example
of deadlock. Deadlock means that no process is making progress toward
the completion of its goal. Can you see what happened in the kitchen that
fateful day?
Use of scenarios is a common way to uncover the potential for deadlock
in a concurrent program. A scenario is one possible sequence of events in
the execution of a concurrent set of instructions. Here is one scenario that
results in the deadlock observed in the kitchen.
1. Mildred finds that the 15 ml measuring spoon is available
2. Mildred removes the 15 ml measuring spoon from the rack
3. Horace finds that the 5 ml measuring spoon is available
4. Horace removes the 5 ml measuring spoon from the rack
5. Horace finds that the 15 ml measuring spoon is not available and waits
6. Mildred finds that the 5 ml measuring spoon is not available and waits
Our two cooks become deadlocked when each of them holds the measuring
spoon that the other needs to continue. This problem may arise any time that
a process requires multiple resources simultaneously. How is it possible that
previous dinner parties have come off without problem? Here is a scenario in
which everything goes smoothly with the sharing of the measuring spoons.
1. Mildred finds that the 15 ml measuring spoon is available
2. Mildred removes the 15 ml measuring spoon from the rack
3. Mildred finds that the 5 ml measuring spoon is available
4. Mildred removes the 5 ml measuring spoon from the rack
34. 10 Introduction and overview
5. Horace finds that the 5 ml measuring spoon is not available and waits
6. Mildred measures 20 ml of salt
7. Mildred washes and dries the 5 ml measuring spoon
8. Mildred returns the 5 ml measuring spoon to the spoon rack
9. Horace finds that the 5 ml measuring spoon is available
10. Horace removes the 5 ml measuring spoon from the rack
11. Horace finds that the 15 ml measuring spoon is not available and waits
12. Mildred washes and dries the 15 ml measuring spoon
13. Mildred returns the 15 ml measuring spoon to the spoon rack
14. Horace finds that the 15 ml measuring spoon is available
15. Horace removes the 15 ml measuring spoon from the rack
16. and so on . . . Each cook has used both spoons successfully
The simplest solution to the form of deadlocking seen in the first scenario is
to forbid the simultaneous use of multiple resources. In our kitchen we could
restructure the two algorithms so that each cook takes one measuring spoon,
uses it, and returns it before taking the second spoon. There is no reason
that each cook needs both measuring spoons at a given time. However, there
are times when processes do need multiple resources simultaneously. For
example, a cook may need both a measuring spoon and a bowl to complete
a particular mixing chore. A common solution for avoiding deadlock in this
situation is to require that all processes obtain the resources in the same
order. If our two cooks are required to obtain the 5 ml spoon before obtaining
the 15 ml spoon, they will avoid deadlock. The first cook to take the 5 ml
spoon will be able to obtain the 15 ml spoon as well. The second cook will
wait for the 5 ml spoon to be returned to the rack and will not, in the
meantime, try to obtain the 15 ml spoon.
Now that you understand scenarios, you may notice another potential
problem in our mutual exclusion examples. Suppose one cook observes that
the 5 ml measuring spoon is on the rack. But before they remove it, the
other cook also observes that the spoon is on the rack and removes it. The
first cook is now baffled by the disappearance of the spoon they recently
observed. Our pre-protocol consisted of two separate steps: observing and
removing. For this example and for all other mutual exclusion protocols
to succeed, the pre-protocol must be completed as an atomic action. An
atomic action is an action that cannot be interrupted. The observation
of the spoon must be immediately followed by its removal. Fortunately for
our cooks, the kitchen is so small that when one cook is checking the spoon
rack, there is no room for the other cook to approach it. Our observe and
remove is done as an atomic action.
35. 1.2 Distributed programming 11
Liveness is an important dynamic property of concurrent programs. Live-
ness means that every process in a concurrent program makes progress to-
ward its goals. Deadlock is the most serious violation of liveness. Starvation
is a more localized violation of liveness. Starvation is the indefinite post-
ponement of some of the processes in a concurrent program while others do
make progress toward their goals. Let’s look at an example of starvation in
our kitchen example. Suppose Horace and Mildred need to repeatedly use
the 5 ml measuring spoon. It is possible, though unlikely, that every time
Horace checks for the 5 ml measuring on the rack he finds it is not there.
Mildred has managed to beat him to the spoon each time. Every time she
replaces the spoon, she returns to take it again before Horace gets the op-
portunity to check for it. Horace’s starvation violates our human concept of
fairness. In a real kitchen, Horace and Mildred would certainly take turns
using the spoon so that each of them makes progress towards their goals.
Fairness in a concurrent program means that each process has an equal
opportunity to move forward toward its goal. As we will see later, we often
assign different priorities to different tasks making a conscious decision to
be unfair.
You now have a basic understanding of some of the problems associated
with concurrent programming. In Chapter 3 you’ll learn how to create pro-
cesses (called tasks) in an Ada program. Chapters 4 and 5 describe solutions
to Ada task synchronization and communication necessary to construct a
concurrent program in Ada.
1.2 Distributed programming
A distributed program is one whose concurrent processes are assigned to
different computers connected by a network. There is a distributed version
of the dinner party called a potluck. In this version of dinner, each person or
couple is expected to cook one dish at their home and bring it to a central
location for the dinner. Some communication is necessary between homes
to coordinate the dishes — most people would not want a dinner of eight
desserts and no other courses. Each participant uses the resources in their
own home to prepare their dish.
Distributed programming usually requires abstractions beyond those
needed for non-distributed concurrent programming. These abstractions pro-
vide the tools necessary for dealing with heterogeneous environments, net-
work connections of varying response times, and potential network failures.
A main goal of distributed programming is to provide a more powerful ap-
plication than is possible on a single machine. Scalability, the property of a
36. 12 Introduction and overview
design to be easily enlarged, is a highly desirable property for distributed ap-
plications. Two well-known distributed processing systems are SETI@home,
which uses over 300,000 active computers to analyze radio telescope data
to find evidence of intelligent signals from space, and Folding@home, which
uses over 200,000 computers to simulate protein folding to better understand
biological systems. The processors in both of these distributed systems are
connected by the internet. It is also common to use a private network for
communication among processors making up a distributed system. The Na-
tional Ignition Facility at the University of California Lawrence Livermore
National Laboratory uses a private network to connect the 300 front-end
processors that control the 192-beam, 1.8-Megajoule, 500-Terawatt laser
used for inertial confinement fusion and high-energy-density experimental
studies (Carey et al., 2003). The control software at the facility is a mixed
language environment of Ada (for functional controls) and Java (for user
interface and database back end). CORBA (discussed in Chapter 6) is used
to communicate between languages and processors.
The great potentials of distributed applications come with additional risks.
Distributed programs are best suited for applications that do not require
large amounts of communication between processes. The delay (latency)
between the time a message is sent to a process and the time a response is
received is much greater going through a network than over a local bus. If
the distributed program is not well designed, failure of a small number of
computers in the network can completely disrupt the application. Diagnosing
problems in distributed applications is usually more difficult than in non-
distributed applications as the analysis may require connections to a widely
dispersed set of computers.
Chapter 6 describes two approaches to building a distributed Ada pro-
gram. The first approach uses features from the Distributed Systems Annex
(DSA) in the Ada library. The second describes the use of the CORBA
middleware for communication between the distributed processes.
1.3 Real-time systems
There are many definitions of a real-time system but, as you would expect, all
include the concept of time. A particular activity must be completed within
a specified time limit, its deadline. A non-real-time program is considered
correct when the output is that described in the program’s specification.
You have probably spent a good deal of time verifying programs you have
written by testing them with various input values. You may have even used
proof checkers such as the one available with SPARK Ada (Barnes, 2003) to
37. 1.3 Real-time systems 13
verify a program mathematically. A real-time program’s correctness depends
on both the correctness of the outputs and their timeliness (Stankovic, 1988).
A real-time program that calculates the correct answer after the deadline
has passed is not correct.
You may have noticed that our earlier discussions were on concurrent
programming while this section discusses real-time systems. The only time-
related property of a concurrent program is liveness. Liveness is concerned
with every process making progress toward its goal. It makes no assumptions
concerning the absolute or relative speeds at which the processes execute
their instructions. A concurrent program is independent of the hardware on
which it is executing. In order to determine whether or not our software
can meet its real-time deadlines, we must have a good understanding of
the hardware on which it executes. We must consider the entire system
(hardware and software) in our analysis of real-time applications.
1.3.1 Classification of real-time systems
Don’t all programs have deadlines? A monthly billing program needs to
complete the printing of invoices before they can be mailed at the end of the
month. The automated teller machine should dispense cash to a customer
immediately after their request. In both of these cases, missing the deadline
is not a failure of the software, but a degradation of the service it provides.
We will still get the invoices to our customers and the bank customer may
be a little annoyed for having to wait longer than they would like. We call
a system whose performance is only degraded by a missed deadline a soft
real-time system. A soft real-time system need only produce the correct
answers; missing deadlines is only an inconvenience. Of course, such incon-
veniences in a commercial application may result in sluggish sales. A hard
real-time system is one in which a single missed deadline leads to com-
plete failure of the system. The fly-by-wire system described earlier is an
example of a hard real-time system. The aircraft will likely crash if the sys-
tem does not complete current calculations required for moving the control
surfaces by a deadline. The deadline in this case is imposed by the aircraft’s
aerodynamics. Control systems for automobile engines, chemical plants, oil
refineries, and nuclear power plants are all hard real-time systems. Some
people (Burns and Wellings, 2009; Laplante, 2004) include a third category
of real time systems. A firm real-time system is one in which a few missed
deadlines are acceptable, but missing more than a few may lead to system
failure. A video analysis application may miss deadlines on a few frames and
38. 14 Introduction and overview
still be acceptable. How many missed deadlines are acceptable depends on
the quality of service (QoS) expected by the users of the system.
It is really the system requirements that characterize a particular system
as soft, firm, or hard real-time. The specification for a payroll processing
program does not generally contain a requirement such as “an employee’s
taxes must be calculated within 53 milliseconds of obtaining their gross
pay and number of deductions.” A specification for an automated teller
machine may state that the system should respond to customer requests
in a timely manner without specifying an exact number of seconds. The
specification for a video analysis program may specify some acceptable level
of quality but say nothing about a deadline for completing the processing of
one video frame. On the other hand, the specification for software running
an engine control unit inside a race car will specify strict deadlines for the
computations that determine the quantity of fuel injected into each cylinder.
If the computations are not completed within that deadline, the engine could
experience a catastrophic failure.
The desired behaviors of real-time systems are sometimes different than
those for a concurrent program. For example, starvation, which is generally
seen as something to avoid in a concurrent program, may be expected in a
real-time system.
A common myth equates real-time systems and fast systems. The deter-
ministic nature of real-time systems is the defining characteristic, not the
speed at which they execute. It is true that many deadlines specified for
real-time systems are short. And a specification with many short deadlines
certainly challenges the designer and implementer to create efficient, fast
code. So it is not difficult to see why people equate real-time and fast. But,
keep in mind that it is possible to have a slow real-time system.
1.3.2 Embedded systems
You may have noticed that all of the examples of hard real-time systems
given in the last section are embedded systems. The engine control com-
puter in our race car is a component of that car that is no less important
to winning a race than its tires. Similarly, the fly-by-wire aircraft, chemical
plant, oil refinery, and nuclear power plant all use computers to produce
results that are more than computations. An embedded system interacts
with its environment through sensors (input devices) and actuators (out-
put devices). Each embedded system must respond to sensor events and
meet deadlines imposed by its environment. The engine control unit’s dead-
lines are imposed by the movements of the mechanical parts making up that
39. 1.3 Real-time systems 15
engine. Because deadlines are imposed by environmental constraints, it might
be argued that all hard real-time systems are embedded systems.
You might think that in order to meet short deadlines, an embedded
system would benefit from the use of multiple processors. However, many
embedded systems are mass market products. The economy of scale is an
incentive to manufacture many units of a particular model car or cellular
phone. In such a manufacturing environment, a great deal of money can be
saved by shaving a few cents off the cost of each individual unit. So most
such embedded systems are implemented with a single processor that has the
minimum performance required for the application. Running a concurrent
program on a single processor requires the interleaving of instructions from
each process. Switching the processor from executing the instructions of one
process to those of another process is known as a context switch. A context
switch requires the processor to save its current state (typically the values of
all the registers) and restore the state of the process being resumed. The time
required for the context switches may be a significant fraction of the total
execution time. So you might assume that sequential programming would
be far more common than concurrent programming in embedded systems.
But just the opposite is usually true. Because the real world is a parallel
system, it is easier to design an embedded system using concurrent rather
than sequential programming techniques. The cost of context switching is
small in relation to the reduction in development and maintenance efforts.
Let’s look at an example. Our cooks, Horace and Mildred, have started a
small commercial venture to manufacture their popular tomato apple chut-
ney. They have purchased a large pressure cooker with an embedded micro-
processor. The cooker has a sensor called a thermocouple that is used to
measure the internal temperature. The electronics associated with the ther-
mocouple produce a voltage that is proportional to the temperature at the
tip of the probe. The output of the thermocouple is connected to an analog
to digital converter (ADC) that converts the analog voltage to a 12-bit un-
signed integer which can be read by the processor. A second sensor produces
a voltage that is proportional to the pressure within the cooker. It is con-
nected to a second ADC. The cooker is heated by a gas flame whose intensity
is set by a valve connected to a rotary actuator. A voltage sent to the actu-
ator determines the setting of the gas valve. Our processor is connected to
the actuator through a digital to analog converter (DAC) which converts a
12-bit unsigned integer to a voltage. The cooker has a vent to relieve excess
pressure. The amount of venting is controlled by a second valve/actuator
that is connected to a second DAC. Figure 1.1 is a representation of the
pressure cooker system.
40. 16 Introduction and overview
Gas Valve
A
D
C
DAC
DAC
Processor
Pressure Relief Valve
Thermocouple
Pressure Transducer
Pressure Cooker
A
D
C
123° C
89 kPa
Displays
Figure 1.1 An example of an embedded system
Mildred develops the following algorithm to maintain optimal cooking
conditions for their chutney:
Initial sequential control algorithm for cooking tomato apple
chutney
loop
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Input the temperature value from the ADC connected to the thermocouple
Calculate a new gas valve setting
Output the new gas valve setting to the DAC connected to the gas valve
Display the temperature
Wait until 5 seconds have elapsed from the start of the loop iteration
end loop
This simple algorithm adjusts the relief valve and gas valve every five
seconds. The input, calculations, and output must be completed within this
five-second window. Failure to meet this deadline may result in a catas-
trophic event. Now after running a few tests, our cooks discover that the
pressure fluctuates beyond acceptable limits. They consult with a friend
who is a control engineer. He suggests that they decrease the period for
pressure regulation from five seconds to two seconds and decrease the pe-
riod for temperature regulation from five seconds to four seconds. Here is
Mildred’s second algorithm.
41. 1.3 Real-time systems 17
Final sequential control algorithm for cooking tomato
apple chutney
loop
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Input the temperature value from the ADC connected to the thermocouple
Calculate a new gas valve setting
Output the new gas valve setting to the DAC connected to the gas valve
Display the temperature
Wait until 2 seconds have elapsed from the start of the last pressure input
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Wait until 2 seconds have elapsed from the start of the last pressure input
end loop
The loop in this algorithm has a period of four seconds. The temperature is
adjusted once during that time and the pressure is adjusted twice. This sec-
ond algorithm provides adequate control of the cooking conditions for their
tomato apple chutney recipe. However, they find that with these periods,
the pressure control is unstable when they use it to cook an experimental
batch of mango chutney. After analyzing the fluctuations, their control en-
gineer friend suggests that mango chutney requires a pressure adjustment
every 1.5 seconds and a temperature adjustment every 2.5 seconds. It takes
a lot of trial and error for Mildred to develop her sequential algorithm for
mango chutney.
Sequential control algorithm for cooking mango chutney
loop
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Input the temperature value from the ADC connected to the thermocouple
Calculate a new gas valve setting
Output the new gas valve setting to the DAC connected to the gas valve
Display the temperature
Wait until 1.5 seconds have elapsed from the last pressure input
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
42. 18 Introduction and overview
Wait until 1.0 seconds have elapsed from the last pressure input
Input the temperature value from the ADC connected to the thermocouple
Calculate a new gas valve setting
Output the new gas valve setting to the DAC connected to the gas valve
Display the temperature
Wait until 0.5 seconds have elapsed from the last temperature input
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Wait until 1.5 seconds have elapsed from the last pressure input
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Wait until 0.5 seconds have elapsed from the last pressure input
Input the temperature value from the ADC connected to the thermocouple
Calculate a new gas valve setting
Output the new gas valve setting to the DAC connected to the gas valve
Display the temperature
Wait until 1.0 seconds have elapsed from the last temperature input
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Wait until 1.5 seconds have elapsed from the last pressure input
end loop
The loop in this algorithm has a period of 7.5 seconds. The temperature
is adjusted three times during this period and the pressure is adjusted five
times. This algorithm seems quite complicated for such a seemingly simple
task. It is fortunate that the two sensor periods had the common factor of 0.5
seconds or the algorithm could have been even longer. This simple embedded
system controls just two process variables. Imagine the complexity of the
sequential software if we were to expand our system to include the control
of pH and sugar content of the chutneys.
Now let’s look at a concurrent version of the pressure cooker control algo-
rithm. We create one process for each of our control variables. The processor
will execute these two processes concurrently.
43. 1.3 Real-time systems 19
Control pressure for mango chutney
loop
Input the pressure value from the ADC connected to the pressure transducer
Calculate a new relief valve setting
Output the new relief valve setting to the DAC connected to the relief valve
Display the pressure
Wait until 1.5 seconds have elapsed from the last pressure input
end loop
Control temperature for mango chutney
loop
Input the temperature value from the ADC connected to the thermocouple
Calculate a new gas valve setting
Output the new gas valve setting to the DAC connected to the gas valve
Display the temperature
Wait until 2.5 seconds have elapsed from the last temperature input
end loop
The concurrent algorithm for cooking the mango chutney is significantly
shorter and easier to understand than the sequential one. Another advan-
tage of this approach is that we can use the same program for all of our
pressure cooker recipes. With the sequential approach, we had to write dif-
ferent algorithms for our two chutneys, each with its own set of customized
delays. In our concurrent version, we simply replace the delay time in the
last statement of each process with a variable whose value could be entered
from a keypad. Because the interleaving of the instructions in the two pro-
cesses is non-deterministic, the concurrent approach requires significantly
more effort to show that each of the deadlines can be met. Chapters 7 and 8
describe how to demonstrate that our concurrent Ada programs will meet all
their deadlines. But before that, you will learn the sequential and concurrent
features of Ada necessary for writing real-time applications.
Summary
• Ada is arguably the most appropriate language for development of parallel
and real-time applications.
• Over 99% of processors manufactured are used in embedded systems.
• A parallel program is one that carries out a number of operations simul-
taneously.
• Flynn’s taxonomy categorizes parallel architectures into four simple groups:
SISD, SIMD, MISD, and MIMD.
• Concurrent programming provides notations and techniques for writing
parallel programs without the need to understand the details of the
underlying architecture.
44. 20 Introduction and overview
• Synchronization is the coordination of processes to reach a common goal.
• Communication is the exchange of data or control signals between pro-
cesses.
• A scenario is one possible sequence of events in the execution of a concur-
rent set of instructions.
• Mutual exclusion is a mechanism that prevents two processes from simul-
taneously using the same resource.
• An atomic action is an action that cannot be interrupted.
• Liveness is a property of concurrent programs that indicates that every
process is making progress toward its goal.
• Deadlock is the state in which no process is making progress toward the
completion of its goal.
• Starvation is the indefinite postponement of some of the processes in a
concurrent program.
• A distributed program is one whose concurrent processes are assigned to
different computers connected by a network.
• A deadline is a point in time by which an activity must be completed.
• A soft real-time system need only produce the correct answers; missing a
deadline is only an inconvenience.
• A hard real-time system fails when a single deadline is missed.
• A firm real-time system may miss a few deadlines, but missing more than
a few may lead to system failure.
• An embedded system interacts with its environment through sensors (in-
put) and actuators (output).
• Most embedded systems are hard real-time systems — they must respond
to sensor events and meet deadlines imposed by their environment.
• Concurrency provides a simpler programming model for embedded sys-
tems than sequential programming.
Exercises
1.1 Suppose that 75% of a particular sequential program can be run in
parallel. Use Amdahl’s equation to determine the amount of speedup
obtained by running this program on 8 processors. On 16 processors.
1.2 Cluster computing and grid computing are two forms of MIMD com-
puting. Search the internet to find out more about these two hardware
configurations. What is the primary difference between these systems?
For what sorts of applications is each most suited?
1.3 Name two reasons for using parallel programming rather than sequen-
tial programming.
45. Exercises 21
1.4 What is the relationship between parallel and concurrent program-
ming?
1.5 Rewrite the algorithms that Horace and Mildred followed for peeling
and slicing potatoes to incorporate a bowl to hold the potatoes that
Horace has peeled. Be sure to handle the cases of the empty bowl and
the completely full bowl.
1.6 Define the term scenario.
1.7 Write a scenario for the algorithms you wrote for Exercise 1.5. Assume
that the bowl holds a maximum of three potatoes. Just after slicing the
first potato, Mildred is called away to answer the phone. She spends
more time on the phone than it takes to peel four potatoes. There are
a total of five potatoes to prepare.
1.8 Modify the scenario you wrote for Exercise 1.7. This time, while Mildred
is on the phone, Horace is called away to answer the front door. Mildred
returns to resume slicing before Horace returns to the kitchen.
1.9 Define the terms pre-protocol, post-protocol, critical section, and atomic
action.
1.10 Define the terms deadlock, liveness, starvation, and fairness.
1.11 Search the internet for a definition of the term livelock.
1.12 We gave one scenario for the deadly embrace algorithms that did not
result in a deadlock. Write a different scenario that also does not result
in a deadlock. Remember that checking for a spoon and removing it
from the rack are done as an atomic action.
1.13 We gave one scenario for the deadly embrace algorithms that resulted
in a deadlock. Write a different scenario that also results in a deadlock.
Remember that checking for a spoon and removing it from the rack are
done as an atomic action.
1.14 Rewrite the algorithms that Horace and Mildred followed for obtaining
and using two measuring spoons. Eliminate the possibility of deadlock
by removing the need for one cook to have the two spoons simultane-
ously. Remember that checking for a spoon and removing it from the
rack are done as an atomic action.
1.15 Rewrite the algorithms that Horace and Mildred followed for obtaining
and using two measuring spoons. Eliminate the possibility of deadlock
by ensuring that each cook obtains the two spoons in the same order.
Remember that checking for a spoon and removing it from the rack are
done as an atomic action.
1.16 Distributed systems can be implemented with CORBA. Most of
CORBA architectures are client-server oriented. Search the internet
for a description of client-server architectures.
46. 22 Introduction and overview
1.17 Differentiate between soft real-time systems and hard real-time sys-
tems.
1.18 List some examples of software that have no deadlines.
1.19 Can you think of an embedded system that is not a hard real-time
system? Conversely, can you think of a hard real-time system that is
not an embedded system?
1.20 Define the term context switch.
1.21 Search the internet for examples of processors which are typically used
in embedded systems. Look for low-cost and high-quality processors.
1.22 Name some items in your home that might be embedded systems.
1.23 Write a sequential algorithm for the pressure cooker example that ad-
justs the pressure relief valve every 1.2 seconds and the gas control
valve every 1.8 seconds.
1.24 To ensure that all deadlines of our pressure cooker example are met,
we must determine the worst case execution time (WCET) of each
statement of the sequential algorithm. Search the Internet for a defi-
nition of worst case execution time and some methods for determining
worst case execution times. We’ll make use of WCET in Chapters 7, 8,
and 9.
47. 2
Sequential programming with Ada
In this chapter we will introduce you to the basic sequential features of
the Ada programming language. You may find it useful to skim this chap-
ter on first reading and then return to it when you encounter an unfa-
miliar language feature in later chapters. One chapter is not adequate to
discuss all aspects of sequential programming with Ada. We discuss those
that are most relevant to concurrent, embedded, and real-time programming
and the examples used in this book. Barnes (2006) presents a comprehen-
sive description of the Ada programming language. Ben-Ari (2009) does an
excellent job describing the aspects of Ada relevant to software engineer-
ing. Dale et al. (2000) provide an introduction to Ada for novice program-
mers. You can find Ada implementations of the common data structures in
Dale and McCormick (2007). There are also many Ada language resources
available online that you may find useful while reading this chapter including
English (2001), Riehle (2003), and Wikibooks (2010a). We will often refer
you to the ARM, the Ada Reference Manual (Taft et al., 2006), which is
available in both print and electronic forms.1
DeRemer and Kron (1975) distinguished the activities of writing large
programs from those of writing small programs. They considered large pro-
grams to be systems built from many small programs (modules), usually
written by different people. It is common today to separate the features
of a programming language along the same lines. In the first part of this
chapter we present the aspects of Ada required to write the most basic
programs. Then we’ll discuss some of Ada’s features that support the de-
velopment of large programs. Finally, we’ll look at those features that allow
our Ada program to interact directly with hardware. Let’s start with a simple
example that illustrates the basic structure of an Ada program. The
1 http://www.ada-auth.org/arm.html provides the ARM in multiple formats.
48. 24 Sequential programming with Ada
following program prompts the user to enter two integers and displays their
average.
with Ada . Text IO ;
with Ada . I n t e g e r T e x t I O ;
with Ada . Float Text IO ;
procedure Average i s
–– Display the average of two numbers entered by the user
A : I n t e g e r ;
B : I n t e g e r ;
M : Float ;
begin
Ada . Text IO . Put Line ( Item = ” Enter two i n t e g e r s . ” ) ;
Ada . I n t e g e r T e x t I O . Get ( Item = A) ;
Ada . I n t e g e r T e x t I O . Get ( Item = B) ;
M := Float (A + B) / 2 . 0 ;
Ada . Text IO . New Line ;
Ada . Text IO . Put ( Item = ”The average of your i n t e g e r s i s ” ) ;
Ada . Float Text IO . Put ( Item = M,
Fore = 1 ,
Aft = 2 ,
Exp = 0 ) ;
Ada . Text IO . New Line ;
end Average ;
The bold words in all our examples are reserved words. You can find a
list of all 72 reserved words in section 2.9 of the ARM. The first three lines
of the program are context clauses. The with clauses specify what library
units our program requires. In this example, we use input and output op-
erations from three different library units: one for the input and output of
strings and characters (Ada.Text IO), one for the input and output of inte-
gers (Ada.Integer Text IO), and one for the input and output of floating
point real numbers (Ada.Float Text IO). Following the context clauses is
the specification of our program. In this example the specification consists of
the name Average and no parameters. The name is repeated in the last line
that marks the end of this program unit. The line that begins with the two
adjacent hyphens is a comment. Comments start with two adjacent hyphens
and extend to the end of the line.
Following the program unit’s specification is the declarative part. In
our example, we declare three variables. Variables A and B are declared
to be of type Integer, a language-defined whole number type with an
implementation-defined range. Variable M is declared to be of type Float, a
language-defined floating point number type with an implementation-defined
precision and range. The initial value of all three variables is not defined.
49. Sequential programming with Ada 25
All but one of the executable statements in our example are calls to pro-
cedures (subprograms) in various library packages. In the first statement, we
call the procedure Put Line in the library package Ada.Text IO. Ada allows
us to overload subprogram names. The use of the library package name as a
prefix makes it perfectly clear which put procedure we are calling. Some Ada
programmers prefer to eliminate these package name prefixes by including
an additional context clause called the use clause. We’ll show you examples
of the use clause and positional parameter association at the end of this
section.
Except for procedure New Line, all of the procedures called in the exam-
ple require parameters. Ada provides both named and positional parameter
association. You are probably very familiar with positional parameter asso-
ciation in which the formal and actual parameters are associated by their
position in the parameter list. With named parameter association, the order
of parameters in our call is irrelevant. Our example uses named association
to match up the formal and actual parameters. To use named association,
we give the name of the formal parameter followed by the arrow symbol,
=, followed by the actual parameter. In our call to procedure Put Line, the
formal parameter is Item and the actual parameter is the string literal of our
prompt. When there is but a single parameter, named parameter association
provides little useful information. But when there are multiple parameters,
as in the call to Ada.Float Text IO.Put, named parameter association pro-
vides information that makes both reading and writing the call easier. The
formal parameters Fore, Aft, and Exp in this call supply information on
how to format the real number. Details on the formatting of real numbers
are given in section A.10.9 of the ARM.
The only statement in our example that is not a procedure call is the
assignment statement that calculates the average of the two integers entered
by the user. The arithmetic expression in this assignment statement includes
three operations. First, the two integers are added. Then the integer sum is
explicitly converted to a floating point number. Finally, the floating point
sum is divided by two. The explicit conversion (casting) to type Float is
necessary because Ada makes no implicit type conversions. The syntax of
an explicit type conversion is similar to that of a function call using the type
as the name of the function.
Here is a shorter version of our example that illustrates the use of use
clauses and positional parameter association. Throughout the remainder of
this book we will make use of prefixing and named parameter association
when it makes the code clearer.
50. 26 Sequential programming with Ada
with Ada . Text IO ; use Ada . Text IO ;
with Ada . I n t e g e r T e x t I O ; use Ada . I n t e g e r T e x t I O ;
with Ada . Float Text IO ; use Ada . Float Text IO ;
procedure Average i s
–– Display the average of two numbers entered by the user
A : I n t e g e r ;
B : I n t e g e r ;
M : Float ;
begin
Put Line ( ” Enter two i n t e g e r s . ” ) ;
Get (A) ;
Get (B) ;
M := Float (A + B) / 2 . 0 ;
New Line ;
Put ( ”The average of your i n t e g e r s i s ” ) ;
Put (M, 1 , 2 , 0 ) ;
New Line ;
end Average ;
2.1 Control structures
Ada provides two statements for making decisions: the if statement and the
case statement. Section 5.3 of the ARM gives the details of the if state-
ment and section 5.4 gives the details of the case statement. Ada provides a
loop statement with several different iteration schemes. These schemes are
described in detail in section 5.5 of the ARM. In this section we’ll provide
examples of each control structure.
2.1.1 If statements
Here are some examples of various forms of the if statement.
i f A 0 then
Put Line ( ”A i s negative ” ) ;
end i f ;
i f A B then
Put Line ( ”A i s g r e a t e r than B” ) ;
else
Put Line ( ”A i s not g r e a t e r than B” ) ;
end i f ;
i f A = B then
Put Line ( ”A and B are equal ” ) ;
e l s i f A B then
Put Line ( ”A i s g r e a t e r than B” ) ;
else
51. 2.1 Control structures 27
Put Line ( ”A i s l e s s than B” ) ;
end i f ;
i f A B and A C then
Put Line ( ”A i s g r e a t e r than both B and C” ) ;
e l s i f B A and B C then
Put Line ( ”B i s g r e a t e r than both A and C” ) ;
e l s i f C A and C B then
Put Line ( ”C i s g r e a t e r than both A and B” ) ;
end i f ;
While these examples show only one statement for each choice, you may
use a sequence of statements. Ada provides the following equality, relational,
and logical operators commonly used in the Boolean expressions of if state-
ments.
Equality operators
= equal
/= not equal
Relational operators
less than
= less than or equal to
greater than
= greater than or equal to
Logical operators
not logical negation
and logical conjunction
or logical disjunction
xor exclusive or
and then short circuit and
or else short circuit or
Boolean expressions which include both and and or operators must include
parentheses to indicate the desired order of evaluation. Section 4.5 of the
ARM gives a complete listing and description of all of Ada’s operators and
the six precedence levels.
2.1.2 Case statement
The case statement selects one of many alternatives based on the value of
an expression with a discrete result. Here is an example of a case statement.
52. 28 Sequential programming with Ada
case Ch i s
when ’ a ’ . . ’ z ’ =
Put Line ( ”Ch i s a lowercase l e t t e r ” ) ;
when ’A ’ . . ’Z ’ =
Put Line ( ”Ch i s an uppercase l e t t e r ” ) ;
when ’ 0 ’ . . ’ 9 ’ =
Put Line ( ”Ch i s a d i g i t ” ) ;
when ’ . ’ | ’ ! ’ | ’ ? ’ =
Put Line ( ”Ch i s a sentence t e r m i n a t i o n c h a r a c t e r ” ) ;
when others =
Put Line ( ”Ch i s some other c h a r a c t e r ” ) ;
end case ;
The case selector may be any expression that has a discrete result. In
our example the expression is the character variable Ch. Variable Ch is of
the language-defined type Character, a character type whose 256 values
correspond to the 8-bit Latin-1 values. Ada also provides 16-bit and 32-bit
character types which are described in section 3.5.2 of the ARM.
Our example contains five case alternatives. The determination of which
alternative is executed is based on the value of the case selector. While
our example shows a single executable statement for each alternative, you
may use a sequence of statements. Each alternative is associated with a
set of discrete choices. In our example, these choices are given by ranges
(indicated by starting and ending values separated by two dots), specific
choices (separated by vertical bars), and the final choice, others, which
handles any selector values not given in previous choice sets. The others
alternative must be given last. Ada requires that there be an alternative
for every value in the domain of the discrete case selector. The others
alternative is frequently used to meet this requirement.
2.1.3 Loop statements
Ada’s loop statement executes a sequence of statements repeatedly, zero
or more times. The simplest form of the loop statement is the infinite loop.
While it may at first seem odd to have a loop syntax for an infinite loop, such
loops are common in embedded software where the system runs from the
time the device is powered up to when it is switched off. Here is an example
based on our pressure cooker temperature control algorithm from Chapter 1.
loop
ADC. Read ( Temperature ) ; –– Read the temperature from the ADC
C a l c u l a t e V a l v e
( Current Temp = Temperature , –– C a l c u l a t e the new
New Setting = V a l v e S e t t i n g ) ; –– gas v a l v e s e t t i n g
53. 2.1 Control structures 29
DAC. Write ( V a l v e S e t t i n g ) ; –– Change the v a l v e s e t t i n g
delay 1 . 5 ; –– Wait 1.5 seconds
end loop ;
We use an exit statement within a loop to terminate the execution of that
loop when some condition is met. The exit statement may go anywhere in
the sequence of statements making up the loop body. Here is a loop that
reads and sums integer values until it encounters a negative sentinel value.
The negative value is not added to the sum.
Sum := 0;
loop
Get ( Value ) ;
exit when Value 0;
Sum := Sum + Value ;
end loop ;
There are two iteration schemes that may be used with the loop statement.
The while iteration scheme is used to create a pretest loop. The loop body is
executed while the condition is true. The loop terminates when the condition
is false. The following loop uses a while iteration scheme to calculate the
square root of X using Newton’s method.
Approx := X / 2 . 0 ;
while abs (X – Approx ∗∗ 2) Tolerance loop
Approx := 0.5 ∗ ( Approx + X / Approx ) ;
end loop ;
Put ( ”The square root of ” ) ;
Put ( Item = X, Fore = 1 , Aft = 5 , Exp = 0 ) ;
Put ( ” i s approximately ” ) ;
Put ( Item = Approx , Fore = 1 , Aft = 5 , Exp = 0 ) ;
New Line ;
This program fragment uses two operators not found in some program-
ming languages. abs returns the absolute value of its operand and ** is used
to raise a number to an integer power.
The for iteration scheme is used to create deterministic counting loops.
Here is a simple example of this scheme.
for Count in 5 . . 8 loop
Put ( Count ) ;
New Line ;
end loop ;
As you can probably guess, this loop displays the four integers 5, 6, 7, and
8. Let’s look at the details underlying the for iteration scheme. The variable
Count in this example is called the loop parameter. The loop parameter is
not defined in a declarative part like normal variables. Count is defined only
54. 30 Sequential programming with Ada
for the body of this loop. The range 5..8 defines a discrete subtype with four
values. The body of the loop is executed once for each value in this discrete
subtype. The values are assigned to the loop parameter in increasing order.
Within the body of the loop, the loop parameter is treated as a constant;
we cannot modify it. To make our loops more general, we can replace the
literals 5 or 8 in our example with any expression that evaluates to a discrete
type. We’ll revisit this topic when we discuss types and subtypes later in
this chapter.
If we add the reserved word reverse to the for loop, the values are as-
signed to the loop parameter in decreasing order. The following for loop
displays the four numbers in reverse order.
for Count in reverse 5 . . 8 loop
Put ( Count ) ;
New Line ;
end loop ;
Reversing the order of the values in our example range creates a subtype
with a null range — a subtype with no values. A for loop with a null range
iterates zero times. Such a situation often arises when the range is defined
by variables. Each of the following for loops displays nothing.
A := 9;
B := 2;
for Count in A . . B loop –– With a n u l l range , t h i s
Put ( Count ) ; –– loop i t e r a t e s zero times
New Line ;
end loop ;
for Count in reverse A . . B loop –– With a n u l l range , t h i s
Put ( Count ) ; –– loop i t e r a t e s zero times
New Line ;
end loop ;
2.2 Subprograms
A subprogram is a program unit whose execution is invoked by a subprogram
call. Ada provides two forms of subprograms: the procedure and the function.
We use a procedure call statement to invoke a procedure. You saw examples
of procedure call statements in the program Average at the beginning of this
chapter. We invoke a function by using its name in an expression. A function
returns a value that is used in the expression that invoked it. The definition of
a subprogram can be given in two parts: a declaration defining its signature
and a body containing its executable statements. Alternatively, we can skip
56. arvonsa ja perityn nimensä nojassa piti oikeutenansa vaatia
tyttäreltänsä. Onneton isä voi sentähden sydämmessänsä etsiä
lohdutusta varmassa tiedossa, että aina oli rehellisesti täyttänyt
velvollisuutensa. Rikos, josta hän nyt oli syytetty, ei voinutkaan olla
rikos syvemmässä merkityksessä: hän oli tehnyt mitä ihmisyyden laki
vaati, ja ainoasti jalon päätöksen tieto tässä kohden, antoi hänelle
voimaa kestämään sitä kärsimystä, joka nyt oli häntä kohtaava.
Vanha tornin vartija palasi toimestansa ja sanoi hänessä
harvastaan huomatulla innolla: Me olemme tehneet hyvän työn,
parooni! Tuolla ulapalla on purjehtija. — Minä näin selvästi valon
lyhdystä, jonka se on nostanut mastoon. Tänä hetkenä se siunaa
meidän valoamme.
Parooni katsoi ulos akkunasta. Ulkona, tyrskyvien aaltojen
hämärässä näkyi lyhdyn valaisema pilkku. Oli mahdotonta tornista
katsoen päättää, kuinka kaukana se oli. Ainoastaan sen liikkeistä
voitiin huomata, että se läheni koillisesta.
Vielä siis lohdutus! huudahti parooni. Vapauteni viimeisenä
hetkenä, te'en kuitenkin vielä hyvän työn.
Onko viimeinen hetkeni käsillä, herra parooni? sanoi tornin
vartija juhlallisella vakavuudella. Voinko katsoa olevani kuolemani
hetkellä?
Ei sinun tarvitse pelätä, ukko Stolpe! vastasi parooni. Sinua ei
mikään onnettomuus kohtaa. Sinä olet tehnyt tehtäväsi ja totellut
minun käskyjäni.
Minä olen totellut itseäni ja omaatuntoani, puhkesi vartija
sanomaan. Minä olenkin valmis vastaamaan te'oistani. Mutta minä
57. tahdon tietää onko kuolinhetkeni lähellä, sillä ainoasti silloin pääsen
valastani.
Mitä tarkoitat, vanhus? kysyi parooni. Mutta — minä en tahdo
vietellä sinua valan rikkomiseen. Sentähden sanon sinulle: ole
rauhassa. Sinuun ei mikään kova onni kohtaa.
Silloin astui vanhus keskelle salia. Mutta minä tahdon kuolla,
huudahti hän. Minä kaipaan kuolemaa! Muuten en saa sanoa mitä
minun täytyy sanoa.
Säilytä sinä valasi, Stolpe! sanoi parooni. Onhan mahdollista,
että minä kuitenkin tiedän, mitä sinä et saa ilmaista.
Mitä parooni tietää en minä voi arvata, lausui ukko. Mutta minä
tiedän, että valani, jonka vannoin entiselle herralleni hänen
kuolinhetkellänsä, olen pitänyt ja pidän vastedeskin. Jo siitä asti, kun
herrani ruumiin kera aallot minun ajoivat rantaan tuolla niemellä,
olette te, parooni, ollut hyväntekijäni ja auttajani. Jo silloin heti näin,
ett'en salaisuuteni ilmoittamalla voinut saada mitään hyvää aikaan;
sentähden olen sitä uskollisemmasti pitänyt valani ja salannut sen.
Onneton salaisuus on kyllä tuttu perheessäni! tokasi parooni.
Sisareni häpeän tietävät lapsenikin.
Häpeän? toisti Stolpe, tuimasti närkästyen, Ei sanaakaan,
parooni, joka sokaisisi vanhan herrani muistoa! Hän nyrkitti kätensä
ja puri yhteen hampaansa.
Kuule, Stolpe! keskeytti häntä parooni. Täällä on pimeä. Sytytä
lamput! En tahdo kätkeytä pimeyteen, kun he tulevat, jotka etsivät
minua.
58. Vartija hillitsi tunteensa ja teki mitä hänen oli käsketty. Sali
valostui ja molemmat vanhukset odottivat äänettöminä kohtaloinsa
päätöstä.
Kun, tällä ajalla, sotamiehet yhden upseerin komentamina ja kreivi
Telepnoff'in seuraamina saapuivat Marienhag'iin, olivat jo paroonitar
ja Natalia matkapuvuissa puutarhan kautta lähteneet vaunuille
meren rannalla. Kun palvelijat ilmoittivat, ett'ei parooni ollut sisällä,
sanoi Telepnoff heti: Hän on valotornissa. Se on vähän matkan
päässä tästä, ja sieltä me hänen löydämme.
Vähäinen joukko, kaksitoista sotamiestä, jatkoivat matkaansa
osoitetulle paikalle. Kreivi ei aavistanutkaan, että matkueen, jonka
etupäässä hän kulki, voivat paroonitar ja Natalia helposti nähdä
ollessansa muutamien pensaitten ja kivien takana rannassa,
levottomalla tuskalla odottaen mitä valotornissa piti tehtämän.
Sinne astui sisälle kreivi aseilla varustettuine seuralaisineen.
Telepnoff koki kuolettaa sitä hävyn tunnetta, joka liikkui hänessä;
kun hän astui paroonin eteen ja sanoi: Suonette anteeksi, herra
parooni, että kutsumattanne näin myöhäiseen tulen luoksenne.
Mutta meriasiain-ministeri on nähnyt hyväksi käskeä minun
tutkimaan Dagerort'in valotornin asioiden laitaa ja on sitä paitsi
täst'edes uskonut minulle sen hoidon. Olen sentähden ottanut
mukaani tarpeeksi väkeä, voidakseni sitä puolustaa, jos vihollisia
sattuisi tulemaan.
Parooni astui arvollisesti häntä vastaan. Näytti siltä, kuin vasten-
mielisyyden ja nurjuuden tunne, joka häneen nousi, kun hänelle
ilmoitettiin, että valotornin hoito oli toiselle uskottu, olisi hänessä
myös herättänyt rauhoittavan ja toiveisenkin tunteen. Siinäkö koko
asianne minulle, kreivi? kysyi hän.
59. Minulla ei omasta puolestani ainakaan ole muuta, vastasi kreivi.
Mutta tuli on sytytetty annettujen käskyjen uhaksi! Missä on
vartija?
Tässä! vastasi Stolpe ynseästi, astuessaan esiin ja oiasten
voimakasta vaikka harmaapäistä vartaloansa.
Eikö parooni ole sinulle ilmoittanut keisarittaren käskyä, että
valotornista pitää tuli sammutettaman? kysäsi kreivi taasen.
On! oli Stolpen vastaus. Mutta Jumala, joka hallitsee myrskyn ja
aallot, on suurempi, kuin keisaritar. Ja kirjoitettu on: joka teidät
eksyttää, hän saa tuomionsa, kuka hän onkin. Minä en tahdo ketään
eksyttää, sentähden olen sytyttänyt tulen.
Minä hankin toisen vartijan, sanoi kreivi. Sinun
tottelemattomuudestasi pidetään tutkimus ja päätös.
Kreivi! keskeytti parooni; vanhus tuossa tahtoo omistaa
rikoksen, jota hän ei ole tehnyt. Minä olen uskaltanut käskeä tulen
sytyttämisen. Minä luulin ihmisellisyyden ja kansan oikeuden sitä
vaativan.
Venäläinen upseeri astui nyt esiin. Minä olen saanut käskyn
kutsua ja seurata herra paroonia Pietariin. Meidän täytyy heti lähteä
matkalle, enkä minä voi teille antaa muuta kuin muutaman minuutin
valmistusai'aksi. Minä pyydän sentähden, että käskette perheenne
tekemään mikä tärkeintä on.
Velvollisuuteni on totella hallitukseni käskyjä, vastasi parooni.
Minä olen valmis, milloin vain tahdotte, herraseni. Mutta sallikaa
kysyäni: onko teillä käskyjä perheeni suhteen?
60. Ei, herra parooni, oli vastaus.
Se on siis vapaa! virkkoi parooni. Minä jätän sen vaan hyvästi.
Pietariin siis minun viette, hyvä herra?
Niin, aluksi Pietariin.
Ja sitten?
En tiedä, oli lyhyt vastaus. Kreivi Telepnoff kääntyi samassa
Stolpen puoleen ja sanoi: Anna heti ylimmäisen salin avaimet! Tuli
pitää nyt oitis sammutettamaan!
Oh, vastasi vanhus ynseästi, tottahan se edes saa palaa,
kunnes se itse sammuu.
Etkö tottele! ärjäsi kreivi vihan vimmassa. Tänne avaimet!
Tuolla ne ovat! vastasi ukko ja, pilkallisesti nauraa hohottaen,
nosti hän voimallisen käsivartensa ja heitti yht'äkkiä koko kalisevan
avainkimpun mereen muutamasta akkunasta, niin että särkyneet
ruudut säristen lensivät pirstaleina pitkin.
Herra luutnantti! riehui kreivi, vangitkaa tuo konna! Käskekää
väkenne auttamaan minua ovia murtamaan! Tuli pitää
sammutettaman. Valevalkea pitää sytytettämän tuolla lahden
perässä, sillä ruotsalainen laivasto on lähtenyt purjeille. Se on jo
läheisyydessä. Tuossa! Murtakaa tuo ovi!
Sotamiehet, tottuneet tottelemaan, kiiruhtivat heti näytetylle ovelle
ja koettivat sapeliensa ja painettiensa avulla särkeä sitä. Mutta ovi oli
luja ja raudoitettu.
62. XII.
Raskaana lepäsi pimeä talviyö Suomenlahden ja Itämeren aalloilla,
kun Ruotsin laivasto, kolmetoista linjalaivaa, yksitoista rekattia ja
muutamia pienempiä haaksia, ohjasi kulkuansa Itämereen päin.
Laivasto kulki niin pitkällä etelässä kuin suinkin uskalsi, sillä sen piti
menemän niin läheltä Dagerort'in ohitse kuin mahdollista. Ensin
etsittiin valotornia turhaan ja jo annettiin merkki, että kaikki laivat
kääntyisivät enemmän etelään päin, kun yht'äkkiä tuo punertava
valo liekähti ja osoitti, että jo oli menty lähemmälle kuin oli
uskallettavaa. Pian annettiin merkki ohjata enemmän pohjoiseen
päin, ettei törmättäisi Hiidenmaan niemiin ja luotoihin.
Mutta Ulla Fersen, joka, äärimmäisenä laivaston eteläisellä siivellä,
kulki hyvänmoisen matkan laivaston edellä, oli jo mennyt liian likelle,
kun leimuava tuli sille yht'äkkiä näytti vaaran. Mutta sen
pelkäämätön päällikkö huomasi heti asemansa ja ryhtyi
tarpeenmukaisiin toimiin.
Me olemme kulku-väylässä, joka menee ihan Dagerort'in ohitse,
sanoi hän. Kun meillä on valotorni oppaanamme, me kyllä
löydämme oikean tolan. Mutta laivaston on pysyminen enemmän
pohjoisessa, ett'ei joutuisi karille. Nostakaat varoitusmerkki ja
63. niinpian kuin siihen on vastattu, ottakaat alas kaikki lyhdyt. Meitä ei
pidä huomattaman maalta.
Kaikella tarkkuudella ja huolella, jota taitavat merimiehet voivat
hyväksensä käyttää, ohjattiin nyt Ulla Fersen sitä suuntaa, jota sen
piti seurata karien ja luotojen lomitse. Vaikka yö oli pimeä ja myrsky
pauhasi raskaasti pyörivillä, jäisillä aalloilla, keijui keveä rekatti
kiitävän pilven tapaisena tyrskyvää kuohua pitkin.
Dagerort'in luona teki rekatti käännöksen itään päin, niin että se
joutui niemekkeen taakse tuulen suojaan, ja heitti sitten purjeensa
takaperin. Vene laskettiin vesille ja rohkea päällikkö, muutamien
merisoturien seuraamana ja ravakkaiden merimiesten soutamana,
kiiti rantaan. Hän huomasi että välisalin akkunoista loisti valkea ja
päätti siitä, että paroonin perhe oli Marienhag'ista tullut vanhasta
rakennuksesta nauttimaan raivoavan myrskyn juhlallista näytelmää.
Äänettä saapui vene rantaan. Hiljaa astelivat rohkeat seikkailijat
rannalle, jossa hetkittäin heikko tähtivalo, joka pilkistihe vähän
välistä hajonneiden pilvien lomista, ennemmin antoi aavistuksen
vastassa olevista esineistä, kuin valaisi niitä. Muutama himmeä säde
valotornin akkunoista oli paras ohje.
Äkkiä tapasivat sotamiehet vaunut valjastettuine hevoisineen.
Silmänräpäyksessä oli hämmästynyt ajaja temmattu istuimeltansa
alas, hevoisia pidettäissä suitsista kiinni.
Hiljaa! käski Sjöstjerna, kiiruhtaessaan vaunuille. Onko ketään
vaunuissa?
Jumalani! Ruotsin kieltä, huudahti paroonitar. Kuka kysyy?
64. Se on Sjöstjerna! Minä tunnen hänen puheensa! keskeytti
Natalia.
Kuinka te tänne tulette, kapteeni?
Vaiti, vaiti! sanoi hän. Minä tulen jäähyväisille. Vielä kerran
tahdoin eläissäni laskea jalkani Dagerort'in maalle: sentähden olen
tuokioksi tullut tänne.
Ah! te tulette meitä auttamaan ja pelastamaan! huudahti
paroonitar.
Hän kertoi hänelle äkkiä mitä oli tapahtunut.
Sjöstjerna mietti hetkisen. Sitten sanoi hän päättävästi: Matka
Ruotsiin on kuitenkin lyhyempi kuin matka Siperiaan, Ulla Fersen on
täällä ja ottaa taasen ilolla vieraansa vastaan!
Jalo pelastajamme! rukoili paroonitar, mutta ennen kaikkia;
pelastakaa puolisoni! Pelastakaa hän! Me seuraamme häntä minne
ikänäkin häntä vietänee.
Oletteko tekin päättänyt seurata isäänne, neiti Natalia? kysyi
hän.
Olen! vastasi hän ilon tunteella, joka läpäisi koko Sjöstjernan
sydämmen ja herätti sen sisimmissä sopissa erinomaisen ihanan
vastasoinnun. Semmoinen myöntymys, sen tunsi hän, olisi jonakin
pyhänä hetkenä elämänsä suloisin autuus.
Mutta hetken vaara herätti hänen taasen sotaiseen toimeensa.
Varovasti hän otti tiedon venäläisten soturien luvusta. Kun hän myös
sai tietää, ett'ei muuta sotavoimaa ollut läheisyydessä, teki hän heti
suunnitelmansa. Hän käski naisien olemaan rauhallisina, eikä
65. antautua levottomuuteen, jos taistelukin nousisi. Sitten hän kiirehti
miehinensä valotornille.
Siellä antoi juuri rautaovi perää venäläisten soturien ponnistuksille.
Upseeri, joka seisoi ovella, kuuli askeleita takanansa ja kääntyi sinne
päin. Mutta äkkiä hän tunsi itseänsä otetuksi kauluksesta kiinni ja
takaperin temmatuksi portaita myöden alas, ennenkuin oli ehtinyt
tehdä vähintäkään vastarintaa.
Vaiti! ärjäsi ääni hänen korvaansa miekan terän salamoidessa
silmäinsä edessä ja väkevien käsien häneltä aseitansa riistäessä. Hän
antaui heti vangiksi ruotsalaisille merisotureille.
Kreivi Telepnoff oli huomannut hänen äkkinäisen katoamisensa ja
juoksi säikähtyen ylös, kun painetin kärkiä näkyi oven rei'ässä. Mutta
samassa töyttäsivät ruotsalaiset sisälle ja karkasivat heti
hämmästyneiden venäläisten päälle, jotka muutamassa silmän
räpäyksessä oli saatu vangiksi. Voitto oli minuutissa verta
vuodattamatta saatu.
Kun Sjöstjerna astui saliin, päästi vartija ilohuudon. Hän on täällä
taas!' puhkesi hän sanomaan, Se on hän; se on herrani poika!
Kummallista, sanoi Sjöstjerna katsoen ympärillensä. Toiset
täällä näyttävät tuntevan salaisuuksiani enemmän kuin minä itse.
Mikä on tarkoituksesi, vanhus? Toisen kerran jo näyt tuntevan
minun. Mitä tarkoitat? Missä olet minun ennen nähnyt? ja miksi
nimität minua herrasi poi'aksi?
Vanhus oikaisi, liikutuksesta väristen, kätensä häneen päin. Minä
tunnen jokaisen kasvojenne muodon. Te olette hänen näköisensä.
Niin, te olette Adolf Sjöstjernan poika.
66. Sinä olet maininnut isäni nimen, sanoi Sjöstjerna ja astui
lähemmäksi häntä. Sano pian, oletko tuntenut hänen? Oletko
tuntenut äitini?
O, Jumalani! huudahti vanhus, kyyneleiden kastellessa hänen
harmaita silmäripsiänsä. Niin, te olette herrani poika. Ja hänen
rouvaansa, enkö olisi nähnyt sitä lempeätä enkeliä, äitiänne, nuori
herrani! Niin, nyt loppukoon elämäni. Nyt tahdon kuolla saadakseni
ilmaista, mitä minun pitäisi kuolinhetkeeni salata.
Vanha parooni, joka kivettyneen näköisenä oli katsellut tätä
kohtausta, nousi nyt ja läheni heitä.
Silloin oikaisi Sjöstjerna vartalonsa ja sanoi suurella äänellä: Minä
huomaan että kohtaloni tänä hetkenä selviää. Tämä on pyhä hetki.
Minä tahdon häiritsemättä kuunnella mitä sinulla on sanottavana,
vanhus. Sotamiehet, viekäät vangit alas ja vartijoitkaat heitä
ulkopuolella.
Ovatko nämät herrat myös vankiamme? kysäsi korpraali
osoittaen
Telepnoff'ia ja vanhaa paroonia.
He minä vartijoitsen itse, vastasi Sjöstjerna ja sotamiehet
lähtivät alas.
No, mitä sinulla on sanomista? sanoi Sjöstjerna kääntyen tornin
vartijaan päin.
Vanhus oli ennättänyt rauhoittua ensimmäisestä innostansa.
Myrskyiset tunteet, jotka äsken panivat hänen muuten vakavia
kasvojansa liikkeesen, oli hän taasen sulkenut rintaansa. Silmässänsä
67. vain sähkyi tuli, jota hän ei voinut hillitä. Suuren päätöksen teko
osoittihe ukon jokaisessa katseessa ja liikkeessä. Herra, sanoi hän
Sjöstjernalle, te tiedätte siis olevanne Adolf Sjöstjernan poika? Mikä
teidän ristimänimenne on?
Otto, vastasi hän.
Niin oikein, sanoi vanhus. Se on nimenne — Tiedättekö kuinka
isänne kuoli?
En, vastasi Otto utelevin silmäyksin.
Niin kuulkaa siis, alkoi vanhus. Me jouduimme haaksirikkoon
muutamalla karilla Worms'in ja Hiidenmaan välillä.
Haa! huudahti Sjöstjerna, sama kari puuttuikin kartasta.
Niin, sanoi vanhus, kaksi vuorokautta ajeli tuuli meitä sinne
tänne muutamalla laivan palasella. Herrani vuoti verta. Hän ei
puhunut selvään, mutta minä tiedän että hän ajatteli oikein. Hän
vaati minulta valan ja minä annoin sen, ja olen pitänyt sen. Minä
vannoin ett'en ennen kuolinhetkeäni ilmoittaisi mitä tiesin. Mutta nyt,
herra, nyt tahdon puhua, sillä nyt se on välttämätöntä. Minä olen
tänään kuullut sanan, joka pakoittaa minun puhumaan, vaikka
tiedän, että minun pitää kuoleman jos puhun; sitä vaatii valani. Minä
olen kuullut sanan; se oli: häpeä —
Häpeä, toisti vanhus vitkaan, tuimasti katsoessaan parooniin.
I'ästynyt parooni Akatius tunsi punastuvansa ja Sjöstjernan kasvot
säihkyivät tulesta.
Häpeä, virkkoi Stolpe vielä kerran. Häpeä ei ole milloinkaan
saastuttanut Adolf Sjöstjernan nimeä, sillä häpeää ei takertunut
68. hänen tekoihinsakaan. Häpeä ei sokaise hänen vaimoansa eikä
lastansakaan. Te sanoitte tänään sanan, herra parooni, hänen
häpeästänsä ja rikoksestansa. Teitä on petetty. Jos joku on teille
semmoisia luuletellut, niin —.
Jumala sen tietää, huudahti parooni ukkoa keskeyttäen, ett'ei
kukaan niin paljon kuin minä, surrut sisareni häpeätä. Mutta jos hän
on tämän nuoren herran äiti, niin näytä hänen avioisuutensa toteen!
Hän oli ruhtinas Palitkin'in morsian.
Min'en tunne ketään ruhtinasta, vastasi Stolpe pikaistuneena.
Jos hän oli luvattu toiselle, oli se tapahtunut hänen tietämättänsä
tahi ainakin hänen suostumattansa; sillä minä olin itse mukana
pienessä kappelissa Kasan'in kirkon vieressä, kun herrani, evesti
Sjöstjerna ja kaunis neiti Ulrika Fersen vihittiin. Kaksi upseeria ja
kaksi korkeasukuista naista oli myös läsnä. Heidän nimensä ovat
kirjoitetut herrani jälkeensä jättämiin paperiin.
Sinä et voi valehdella, Stolpe' sanoi parooni, sinä et tahdokaan
valehdella hyväntekijällesi!
Niin, parooni, jatkoi vanha tornin vartija, minä olen teitä
vihannut, mutta minä olen teitä rakastanutkin. Nyt se tietäkää. Kun
yht'äkkiä veitte pois herrani rouvan, aavistamattansa tavatessanne
hänet hovissa, ja sallimatta hänen edes ottaa jäähyväisiä
puolisoltansa ja lapseltansa, syttyi minussa viha teihin. Mutta kun
pelastitte minun tuulen ajamalta haaksirikolta veneesenne ja sallitte
minun ottaa mukaani herrani ruumiin, jonka te hautasitte, minun
ollessani sairaana ja tainnotonna; kun te parannuttuani uskoitte
minulle vartijan toimen tässä tornissa: silloin opin minä teitä
kunnioittamaan, rakastamaan. Tosin olen kuullut, että herrani
onneton puoliso on asunut tässä tornissa ja että hän on heittäynyt
69. jostakin akkunasta mereen ja hukkunut; mutta minä en ole sitä
nähnyt. Se oli siis tapahtunut sairauteni ja tainnottomuuteni aikana.
Mutta sen tiedän, että hänen ja herrani hauta minulle näytettiin; ja
ett'ei hyödyttänyt, eikä ollut velvollisuuteni mukaistakaan rikkoa
tainnottomalle herralleni antamaa valaani, sen tunsin.
Niin, lausui parooni, tainnoton hän varmaankin oli, kun vaati
sinulta semmoisen valan. Ilman sitä valaa olisi todellakin moni
synkkä ja surullinen hetki elämässäni ollut melkoista loitommalla.
Jos niin on, parooni, että teillä on ollut surua, on se ollut liiankin
helppo rangaistus kovuudestanne sisartanne kohtaan.
Sjöstjerna, vaikka mahtavat tunteet aaltoilivat hänen
sydämmessänsä, kuunteli äänetönnä vanhuksen puhetta. Vihdoin
hän ojensi ukolle kätensä. Mutta kuka olet sinä, vanhus, sanoi hän,
joka annoit minulle sen valon, jota etsin. Sinä olet minun pelastanut
elämäni raskaimmasta murheesta.
Ukon silmät säihkyivät. Olenko todella, nuori herrani? huudahti
hän. Olenko herrani pojalle saanut iloa aikaan? Sitten en ole
turhaan elänyt näitä kahtakymmentä vuotta tällä autiolla niemellä ja
nyt kuolen ilolla. Tässä, herraseni, sanoi hän, tässä ovat isänne
paperit. Hän otti taskustansa nahkaisen lompakon ja antoi sen
Sjöstjernalle.
Vapisevin käsin otti hän lahjan ja avasi sen. Sen sisässä oli
pienempi lompakko, johon oli kirjaelemalla ommeltu nimi ja vaakuna.
Herrat tunsivat ne kummankin perheen omiksi. Vil'aistuansa
papereihin huomasivat he niissä olevan tarpeeksi laillisia todistuksia,
että neiti Ulrika Fersen oli vuoden ollut evesti Adolf Sjöstjernan
70. puolisona, kun heidän poikansa Otto syntyi Pietarissa ja kastettiin
kaupungin ruotsalaisessa seurakunnassa.
Vanha parooni avasi äkkiä helmansa; virtana vuotivat hänen
kyyneleensä, kun hän Ottoa syleillen, lausui: Oi, onnettoman,
rakkaan sisareni poika. Tule syliini, anna minun likistää sinua
sydäntäni vastaan; isän sydämmelle, joka nyt saa rakastaa sinua
niin, kuin se ennen on toivonut!
Syvästi liikutettuna vastasi nuorukainen hänen syleilyänsä, ja
kääntyi sitten Stolpen puoleen: Mutta kuka olet sinä, isäni vanha
ystävä ja palvelija'?
Minä olen ruotsalainen, vastasi vanhus. Minä seurasin useat
vuodet evesti Sjöstjernaa hänen matkoillansa enkä hänen kuoltuansa
voinut muuttaa pois hänen hautansa läheisyydestä. — Mutta jääkää
hyvästi, nuori herra! Vanha sydämmeni tykkyi ilosta, kummallakin
kerralla nähdessäni teidän kauniin rekattinne. Eihän se nytkään ole
kaukana, koska te olette täällä. Jos tuli on tornistamme valaissut
teitä tänä myrskyisenä yönä, niin kuolen nyt toista vertaa
mieluummin.
On todellakin, valo täältä on ohjannut minua ja koko ruotsalaista
laivastoa, virkkoi Sjöstjerna. Jos se ei olisi valaissut meitä, niin
luultavastikin olisimme joutuneet karille, sillä me olisimme sitä
etsineet etelämmästä.
Silloin oikaisi vanhus vartalonsa ja kummallinen hymy levisi hänen
kivikoville kasvoillensa. Hän löi nuorta meriupseeria voimakkaasti
olalle ja sanoi: Herra, nythän olen kuitenkin vanhoilla päivilläni
tehnyt isänmaalleni hyvän työn, ja olkoon se elämäni viimeinen.
71. No niin, sanoi Sjöstjerna, seuraa nyt minua rekatilleni! Minä
olen kuullut koko jutun kreivin vilpillisistä hankkeista. — Terävä ja
halveksiva katse lensi ällistyneen ja äänettömän läsnäolijan, kreivi
Telepnoff'in puoleen, joka seisoi erikseen muutaman akkunan
vieressä — ja samaten kuin vangitsin sotamiehet, samaten
vangitsen parooninkin ja kenen tahdon hänen väestänsä. Sinunkin,
Stolpe-ukko.
Ei, herra, sanoi vartija, minä olen sanonut teille, että Stolpe
ukko on elänyt kylliksi. Nyt on vala rikottu, siksi täytyy hänen
kuoleman, sillä muistakaa, herra, se piti rikottaman vasta hänen
kuolinhetkenänsä! Sitä paitsi minun pitää jäämän tänne vielä tänä
yönä hoitamaan tulta.
Sjöstjernaa huoletti. Siinä olet oikeassa, vanhus, sanoi hän;
tornisi valo on tänä yönä laivastollemme välttämätön.
Niin, senpä tähden jäänkin, sanoi Stolpe. Mutta minä tarvitsen
auttajankin, jatkoi hän. Siksi pyydän saada tämän venäläisen
herran. — Hän osoitti kreiviin. — Käsitänpä hyvin kyllä, ett'ei
semmoista herraa päästetä irki ennen aikaansa asiaa ilmoittamaan ja
hätärytyä Hiidenmaalla nostamaan. Mutt'ei teidän tarvitse ottaa
häntä mukaanne. Sallikaa Stolpen häntä vartijoita! Voitte olla varma
siitä, ett'en häntä päästä.
Sjöstjerna mietti. Kreivi astui esiin, pelon tuskasta vavisten. Mikä
on tarkoituksenne, kapteeni Sjöstjerna? kysyi hän. Tahdotteko
viedä minun vankina mukananne? Eli panetteko tämän ukon minua
täällä vartijoitsemaan? Sallikaa minun mieluummin valita
jälkimmäinen. Siinä tapauksessahan pääsen vapaaksi huomenna
varhain. Silloin minä sinun kelpo lailla palkitsen, ukkoseni.
72. Nyt hymyili vanha Stolpe toisen kerran. Mutta tämä hänen
hymynsä oli hirmuinen. Siinä kuvastihe semmoinen iva, joka peloitti
kreiviä niin että hän rupesi pyytämäänsä katumaan. Mutta Sjöstjerna
suostui siihen.
No niin, sanoi hän, saakoon vanhus tahtonsa perille. En
todellakaan käsitä mitä pahaa hänelle voisi tapahtua. Hänhän vain
on totellut herransa käskyjä.
Mutta minä pyydän sinua, Stolpe. sanoi parooni, kohtele kreiviä
säädyllisesti!
Minä tarvitsen hänen apuansa, sanoi Stolpe, tuomaan
muutaman kärryllisen kivihiiliä, sillä minä olen seisonut tässä liian
kauvan ja laiminlyönyt tulen hoidon. Mutta en minä kreiviä kauvan
vaivaa. Olkaa hyvä, nouskaa portaita myöden ylös tuolle ovelle,
jonka sotamiehet äsken mursivat rikki. Jääkää hyvästi jalo
hyväntekijäni, herra parooni! Jääkäät Jumalan haltuun! Mutta yhtä
pyytää tänä hetkenä isänne uskollinen palvelija: Otto herra, sallikaa
syleilläni teitä!
Sjöstjerna heittäyi vanhan merimiehen syliin, ja molemmat
puristivat sitten toisiensa käsiä.
Kiirehtikää nyt, korkea-arvoinen, hieno herra! sanoi vartija
säihkyvin silmin. Kiirehtikäämme ylös!
Kreivi ei uskaltanut tehdä vastarintaa, vaan piti välttämättömänä
totella. Hän kernaammin antaui yhdeksi yötä vanhuksen
kiusattavaksi ja vartijoittavaksi, kuin tänä myrskyisenä vuoden
aikana kulkea vankina meriä pitkin.
73. Auki murretussa tornin ovessa katsoi kreiviä seuraava vanhus vielä
taaksensa, nyökäytti päätänsä Sjöstjernalle ja sanoi: Tänä yönä
tuleni loistaa, olkaa siitä varma, nuori herrani!
Vai'eten syleilivät parooni ja Otto taasen toisiansa, ennenkuin
astuivat portaita myöden alas. Tornin veräjän ulkopuolella seisoivat
sotamiehet vankinensa järjestetyissä riveissä ja koko matkue lähti
nyt rantaan.
Vanha parooni tapasi ilolla puolisonsa ja tyttärensä vaunuissa
istumassa ja auttoi heitä astumaan alas. Muutamilla sanoilla ilmoitti
hän heille iloisen sanoman, ette he nyt pelastettaisiin ja että heidän
pelastajansa oli sisarensa ja evesti Sjöstjernan oikea ja laillinen
poika.
Rannalla auttoi Sjöstjerna itse naisia veneesen, muutaman
palvelijan kantaessa niitä tavaroita ja varoja, jotka olivat Siperiaan
matkustusta varten laitetut valmiiksi.
Kun Sjöstjerna itse viimeisenä hyppäsi veneesen ja istuikse neiti
Natalian ja hänen isänsä välille, tarttui hän toisella kädellänsä
peräsimeen, toisen käden salaa puristaessa Natalian kättä.
Molemmat ymmärsivät toisensa; sillä äänetön merkki oli kylläksi, sen
jälkeen mitä nyt oli tiedoksi tullut.
Niinpian kuin vene oli ehtinyt rekatille, levitettiin taasen sen
purjeet ja nyt se poistui Hiidenmaan rannoilta, joita se jo kolmannen
kerran oli mennyt niin lähelle.
Kun koko Ruotsin laivasto hajoitetussa järjestyksessänsä teki
käännöksen Dagerort'in niemien ohitse, kiiti taasen Ulla Fersen
tilallensa, äärimmäiseksi vasemmalla siivellä. Muutamaa luutnanttia
74. pisti päähän, juuri kun rekatti rupesi etäämmälle poistumaan, ohjata
tähystin valotorniin päin ja ilmoitti sitten, että juuri tulen loisteessa
voitiin eroittaa taistelu. Näkyi kuinka mies syöksi toisen tuleen.
Jos luutnantti, joka tämän näki, olisi voinut yhtä selvään nähdä
mitä tapahtui aamulla, auringon noustessa, jo näkymättömiin
jääneellä valotornilla, olisi hän nähnyt toisen miehen vapaaehtoisesti
syöksyvän tornista aaltoihin, jotka kuohuivat sen juurella.
* * * * *
Parooni Reinhold'in kautta sai keisaritar tiedon Dagerort'in
valotornin seikkojen oikeasta laidasta ja antoi vakuuttaa hänen
isällensä armonsa, niin että hän hyvässä turvassa voi palata
Marienhag'iin. Kaksi ensimmäistä vuotta kotiintulonsa jälkeen tuntui
kuitenkin sekä paroonista että paroonittaresta autioilta, kun he vasta
rauhan jälkeen saivat ilon kodissansa taasen nähdä tyttärensä ja
hänen onnellisen puolisonsa. Hän oli urotöidensä palkinnoksi saanut
paremman arvoisen laivan päällikkyyden ja toinen päällikkö siis
molempien vuosien merisotina johti Ulla Ferseniä, kun sen uhkea
lippu ja keveät purjeet liikkuivat samoilla kulentavesillä.
75. *** END OF THE PROJECT GUTENBERG EBOOK ULLA FERSEN:
HISTORIALLINEN NOVELLI ***
Updated editions will replace the previous one—the old editions will
be renamed.
Creating the works from print editions not protected by U.S.
copyright law means that no one owns a United States copyright in
these works, so the Foundation (and you!) can copy and distribute it
in the United States without permission and without paying
copyright royalties. Special rules, set forth in the General Terms of
Use part of this license, apply to copying and distributing Project
Gutenberg™ electronic works to protect the PROJECT GUTENBERG™
concept and trademark. Project Gutenberg is a registered trademark,
and may not be used if you charge for an eBook, except by following
the terms of the trademark license, including paying royalties for use
of the Project Gutenberg trademark. If you do not charge anything
for copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such as
creation of derivative works, reports, performances and research.
Project Gutenberg eBooks may be modified and printed and given
away—you may do practically ANYTHING in the United States with
eBooks not protected by U.S. copyright law. Redistribution is subject
to the trademark license, especially commercial redistribution.
START: FULL LICENSE
77. PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
To protect the Project Gutenberg™ mission of promoting the free
distribution of electronic works, by using or distributing this work (or
any other work associated in any way with the phrase “Project
Gutenberg”), you agree to comply with all the terms of the Full
Project Gutenberg™ License available with this file or online at
www.gutenberg.org/license.
Section 1. General Terms of Use and
Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand, agree
to and accept all the terms of this license and intellectual property
(trademark/copyright) agreement. If you do not agree to abide by all
the terms of this agreement, you must cease using and return or
destroy all copies of Project Gutenberg™ electronic works in your
possession. If you paid a fee for obtaining a copy of or access to a
Project Gutenberg™ electronic work and you do not agree to be
bound by the terms of this agreement, you may obtain a refund
from the person or entity to whom you paid the fee as set forth in
paragraph 1.E.8.
1.B. “Project Gutenberg” is a registered trademark. It may only be
used on or associated in any way with an electronic work by people
who agree to be bound by the terms of this agreement. There are a
few things that you can do with most Project Gutenberg™ electronic
works even without complying with the full terms of this agreement.
See paragraph 1.C below. There are a lot of things you can do with
Project Gutenberg™ electronic works if you follow the terms of this
agreement and help preserve free future access to Project
Gutenberg™ electronic works. See paragraph 1.E below.
78. 1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright law
in the United States and you are located in the United States, we do
not claim a right to prevent you from copying, distributing,
performing, displaying or creating derivative works based on the
work as long as all references to Project Gutenberg are removed. Of
course, we hope that you will support the Project Gutenberg™
mission of promoting free access to electronic works by freely
sharing Project Gutenberg™ works in compliance with the terms of
this agreement for keeping the Project Gutenberg™ name associated
with the work. You can easily comply with the terms of this
agreement by keeping this work in the same format with its attached
full Project Gutenberg™ License when you share it without charge
with others.
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside the
United States, check the laws of your country in addition to the
terms of this agreement before downloading, copying, displaying,
performing, distributing or creating derivative works based on this
work or any other Project Gutenberg™ work. The Foundation makes
no representations concerning the copyright status of any work in
any country other than the United States.
1.E. Unless you have removed all references to Project Gutenberg:
1.E.1. The following sentence, with active links to, or other
immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project Gutenberg™
work (any work on which the phrase “Project Gutenberg” appears,
or with which the phrase “Project Gutenberg” is associated) is
accessed, displayed, performed, viewed, copied or distributed:
79. This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it away
or re-use it under the terms of the Project Gutenberg License
included with this eBook or online at www.gutenberg.org. If you
are not located in the United States, you will have to check the
laws of the country where you are located before using this
eBook.
1.E.2. If an individual Project Gutenberg™ electronic work is derived
from texts not protected by U.S. copyright law (does not contain a
notice indicating that it is posted with permission of the copyright
holder), the work can be copied and distributed to anyone in the
United States without paying any fees or charges. If you are
redistributing or providing access to a work with the phrase “Project
Gutenberg” associated with or appearing on the work, you must
comply either with the requirements of paragraphs 1.E.1 through
1.E.7 or obtain permission for the use of the work and the Project
Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9.
1.E.3. If an individual Project Gutenberg™ electronic work is posted
with the permission of the copyright holder, your use and distribution
must comply with both paragraphs 1.E.1 through 1.E.7 and any
additional terms imposed by the copyright holder. Additional terms
will be linked to the Project Gutenberg™ License for all works posted
with the permission of the copyright holder found at the beginning
of this work.
1.E.4. Do not unlink or detach or remove the full Project
Gutenberg™ License terms from this work, or any files containing a
part of this work or any other work associated with Project
Gutenberg™.
1.E.5. Do not copy, display, perform, distribute or redistribute this
electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
80. with active links or immediate access to the full terms of the Project
Gutenberg™ License.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if you
provide access to or distribute copies of a Project Gutenberg™ work
in a format other than “Plain Vanilla ASCII” or other format used in
the official version posted on the official Project Gutenberg™ website
(www.gutenberg.org), you must, at no additional cost, fee or
expense to the user, provide a copy, a means of exporting a copy, or
a means of obtaining a copy upon request, of the work in its original
“Plain Vanilla ASCII” or other form. Any alternate format must
include the full Project Gutenberg™ License as specified in
paragraph 1.E.1.
1.E.7. Do not charge a fee for access to, viewing, displaying,
performing, copying or distributing any Project Gutenberg™ works
unless you comply with paragraph 1.E.8 or 1.E.9.
1.E.8. You may charge a reasonable fee for copies of or providing
access to or distributing Project Gutenberg™ electronic works
provided that:
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
81. about donations to the Project Gutenberg Literary Archive
Foundation.”
• You provide a full refund of any money paid by a user who
notifies you in writing (or by e-mail) within 30 days of receipt
that s/he does not agree to the terms of the full Project
Gutenberg™ License. You must require such a user to return or
destroy all copies of the works possessed in a physical medium
and discontinue all use of and all access to other copies of
Project Gutenberg™ works.
• You provide, in accordance with paragraph 1.F.3, a full refund of
any money paid for a work or a replacement copy, if a defect in
the electronic work is discovered and reported to you within 90
days of receipt of the work.
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™
electronic work or group of works on different terms than are set
forth in this agreement, you must obtain permission in writing from
the Project Gutenberg Literary Archive Foundation, the manager of
the Project Gutenberg™ trademark. Contact the Foundation as set
forth in Section 3 below.
1.F.
1.F.1. Project Gutenberg volunteers and employees expend
considerable effort to identify, do copyright research on, transcribe
and proofread works not protected by U.S. copyright law in creating
the Project Gutenberg™ collection. Despite these efforts, Project
Gutenberg™ electronic works, and the medium on which they may
be stored, may contain “Defects,” such as, but not limited to,
incomplete, inaccurate or corrupt data, transcription errors, a
copyright or other intellectual property infringement, a defective or
82. damaged disk or other medium, a computer virus, or computer
codes that damage or cannot be read by your equipment.
1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for
the “Right of Replacement or Refund” described in paragraph 1.F.3,
the Project Gutenberg Literary Archive Foundation, the owner of the
Project Gutenberg™ trademark, and any other party distributing a
Project Gutenberg™ electronic work under this agreement, disclaim
all liability to you for damages, costs and expenses, including legal
fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR
NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR
BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH
1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK
OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL
NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT,
CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF
YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE.
1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you
discover a defect in this electronic work within 90 days of receiving
it, you can receive a refund of the money (if any) you paid for it by
sending a written explanation to the person you received the work
from. If you received the work on a physical medium, you must
return the medium with your written explanation. The person or
entity that provided you with the defective work may elect to provide
a replacement copy in lieu of a refund. If you received the work
electronically, the person or entity providing it to you may choose to
give you a second opportunity to receive the work electronically in
lieu of a refund. If the second copy is also defective, you may
demand a refund in writing without further opportunities to fix the
problem.
1.F.4. Except for the limited right of replacement or refund set forth
in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO
OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
83. Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com