- •Contents
- •1.1 Fundamental Types
- •1.2 T Classes
- •1.3 C Classes
- •1.4 R Classes
- •1.5 M Classes
- •1.6 Static Classes
- •1.7 Buyer Beware
- •1.8 Summary
- •2 Leaves: Symbian OS Exceptions
- •2.1 Leaving Functions
- •2.3 Constructors and Destructors
- •2.4 Working with Leaving Functions
- •2.5 Trapping a Leave Using TRAP and TRAPD
- •2.6 LeaveScan
- •2.7 Summary
- •3 The Cleanup Stack
- •3.1 Using the Cleanup Stack
- •3.2 How Does the Cleanup Stack Work?
- •3.4 Using TCleanupItem for Customized Cleanup
- •3.5 Portability
- •3.6 An Incidental Note on the Use of Casts
- •3.7 Summary
- •5 Descriptors: Symbian OS Strings
- •5.3 Pointer Descriptors
- •5.4 Stack-Based Buffer Descriptors
- •5.5 Heap-Based Buffer Descriptors
- •5.6 Literal Descriptors
- •5.7 Summary
- •6 Good Descriptor Style
- •6.1 Descriptors as Parameters and Return Types
- •6.2 Common Descriptor Methods
- •6.3 The Use of HBufC Heap Descriptors
- •6.4 Externalizing and Internalizing Descriptors
- •6.5 The Overuse of TFileName
- •6.6 Useful Classes for Descriptor Manipulation
- •6.7 Summary
- •7 Dynamic Arrays and Buffers
- •7.1 CArrayX Classes
- •7.3 Why Use RArray Instead of CArrayX?
- •7.4 Dynamic Descriptor Arrays
- •7.5 Fixed-Length Arrays
- •7.6 Dynamic Buffers
- •7.7 Summary
- •8.1 Multitasking Basics
- •8.2 Event-Driven Multitasking
- •8.3 Working with Active Objects
- •8.4 Example Code
- •8.5 Threads Without an Active Scheduler
- •8.6 Application Code and Active Objects
- •8.7 Summary
- •9 Active Objects under the Hood
- •9.1 Active Object Basics
- •9.2 Responsibilities of an Active Object
- •9.3 Responsibilities of an Asynchronous Service Provider
- •9.4 Responsibilities of the Active Scheduler
- •9.5 Starting the Active Scheduler
- •9.6 Nesting the Active Scheduler
- •9.7 Extending the Active Scheduler
- •9.8 Cancellation
- •9.9 Request Completion
- •9.10 State Machines
- •9.11 Long-Running Tasks
- •9.14 Common Mistakes
- •9.15 Summary
- •10 Symbian OS Threads and Processes
- •10.2 Thread Priorities
- •10.3 Stopping a Running Thread
- •10.5 Exception Handling
- •10.6 Processes
- •10.7 Summary
- •11.2 How Do the Client and Server Fit Together?
- •11.3 How Do the Client and Server Communicate?
- •11.5 How Do Synchronous and Asynchronous Requests Differ?
- •11.6 How Is a Server Started?
- •11.7 How Many Connections Can a Client Have?
- •11.8 What Happens When a Client Disconnects?
- •11.9 What Happens If a Client Dies?
- •11.10 What Happens If a Server Dies?
- •11.15 How Many Outstanding Requests Can a Client Make to a Server?
- •11.16 Can Server Functionality Be Extended?
- •11.17 Example Code
- •11.18 Summary
- •12.2 Client Boilerplate Code
- •12.3 Starting the Server and Connecting to It from the Client
- •12.4 Server Startup Code
- •12.5 Server Classes
- •12.6 Server Shutdown
- •12.7 Accessing the Server
- •12.8 Summary
- •13 Binary Types
- •13.1 Symbian OS EXEs
- •13.2 Symbian OS DLLs
- •13.3 Writable Static Data
- •13.4 Thread-Local Storage
- •13.5 The DLL Loader
- •13.6 UIDs
- •13.8 Summary
- •14 ECOM
- •14.1 ECOM Architecture
- •14.2 Features of an ECOM Interface
- •14.3 Factory Methods
- •14.4 Implementing an ECOM Interface
- •14.5 Resource Files
- •14.6 Example Client Code
- •14.7 Summary
- •15 Panics
- •15.2 Good Panic Style
- •15.3 Symbian OS Panic Categories
- •15.4 Panicking Another Thread
- •15.5 Faults, Leaves and Panics
- •15.6 Summary
- •16 Bug Detection Using Assertions
- •16.3 Summary
- •17 Debug Macros and Test Classes
- •17.1 Heap-Checking Macros
- •17.2 Object Invariance Macros
- •17.3 Console Tests Using RTest
- •17.4 Summary
- •18 Compatibility
- •18.1 Forward and Backward Compatibility
- •18.2 Source Compatibility
- •18.3 Binary Compatibility
- •18.4 Preventing Compatibility Breaks
- •18.5 What Can I Change Without Breaking Binary Compatibility?
- •18.6 Best Practice: Planning for Future Changes
- •18.7 Compatibility and the Symbian OS Class Types
- •18.8 Summary
- •19 Thin Templates
- •20.1 Class Layout
- •20.3 Parameters and Return Values
- •20.4 Member Data and Functional Abstraction
- •20.5 Choosing Class, Method and Parameter Names
- •20.7 Summary
- •21 Good Code Style
- •21.1 Reduce the Size of Program Code
- •21.2 Use Heap Memory Carefully
- •21.3 Use Stack Memory Carefully
- •21.5 Optimize Late
- •21.6 Summary
- •Glossary
- •Bibliography and Online Resources
- •Index
124 |
EVENT-DRIVEN MULTITASKING USING ACTIVE OBJECTS |
the event handler and additional code for construction, destruction, error-handling and cancellation. However, application code requires some understanding of active objects and requires implementation of active object code that is incidental to the purpose of the application. In addition, many other operating systems do not encapsulate event handling in the same way. This means that Symbian OS code is not directly portable to other operating systems.
For this reason, Symbian OS provides frameworks to hide active object code from high-level application code by defining handler interfaces (often mixin classes as described in Chapter 1) which a client implements. The frameworks hide the active objects, implementing initialization, cleanup and error handling, and performing generic event processing in the RunL() method. In RunL() the framework calls methods on the client-implemented interface to respond to the completed event. The appropriate client object receives the call, having ”registered” with the framework by passing a reference or pointer to its implementation of the interface. The one rule the client should be aware of is that the interface methods should be implemented to complete quickly so that the framework can handle other events without delay.
An example of this may be seen when application code runs within the GUI framework (CONE), which uses active objects to handle events associated with user input and system requests such as window redraw requests, originating from the window server. The framework implements the RunL() method to process each event, and calls an appropriate virtual function such as OfferKeyEventL() or HandlePointerEventL() in the associated control. As an application programmer, all you have to do is implement the functions defined by the framework and it takes care of the mechanics of event handling.
Likewise, server code runs inside the Symbian OS system server framework and handles requests from client messages. Server code often implements its own additional set of internal active objects, to make requests to asynchronous service providers while still remaining responsive to incoming client requests. The client–server architecture is discussed in detail in Chapters 11 and 12.
8.7 Summary
Symbian OS makes it very easy to write event-driven code without getting too involved in the implementation of the active objects which handle the events. This chapter set out to explain the basics of how active objects work, why you should prefer them to threads for multitasking and how to implement a basic active object class. If you are likely to write server code, implement an asynchronous service provider or perform more advanced GUI programming, you will probably be interested in the
SUMMARY |
125 |
next chapter, which goes deeper into the responsibilities and roles of the main components – active objects, asynchronous service providers and the active scheduler.
This chapter explained that:
•Active objects were designed for lightweight, responsive, powerefficient event-handling and are used by most applications and servers, generally in a single thread.
•Active objects are scheduled cooperatively in a single thread and,
in |
consequence, are easy to program because there is |
no need |
to |
use synchronization primitives to prevent concurrent |
access to |
shared resources.
•The kernel schedules threads pre-emptively but these are not generally used for event-driven multitasking.
•The active object framework on Symbian OS has a modular design that decouples event completion processing, performed by the active scheduler, from individual event handling, performed by active objects.
•The constructor of the active object class should set its priority and add it to the active scheduler. Any initialization required by the asynchronous service provider should be performed in a second-phase constructor.
•Active objects encapsulate an asynchronous service provider and the event handling necessary when a request to that service provider completes.
•Active objects provide request initiation functions. These usually conform to a pattern: performing a check for no previous outstanding requests, submitting the request with its iStatus member variable as a parameter, and setting the state of the active object to indicate that a request has been issued.
•Event handling is performed by implementing the pure virtual RunL() method defined in the CActive base class; RunL() is called by the active scheduler some time after the request completes.
•Because active objects cannot pre-empt each other, RunL() should complete as quickly as possible so that other active object events can be handled without delay.
•The pure virtual DoCancel() method must also be implemented by deriving classes and should call an appropriate method on the asynchronous service provider to cancel the request.
126 |
EVENT-DRIVEN MULTITASKING USING ACTIVE OBJECTS |
•The default ”do nothing” implementation of the virtual RunError() method on the base class should be overridden if the derived class can reasonably handle leaves which occur within its RunL() function.
•Symbian OS uses framework code to conceal the active object idiom. For example, the GUI framework dispatches incoming events to be handled by functions implemented by an associated control, which may be extended by individual applications as required.
The next chapter looks ”under the hood” at active objects, discusses the responsibilities of active objects, asynchronous service providers and the active scheduler, and illustrates best practice when writing and using active objects. Chapter 10 has more information about Symbian OS threads and processes, while Chapters 11 and 12 build on an understanding of active objects, threads and processes, to describe the Symbian OS client–server architecture in detail.