Symbian3/SDK/Source/GUID-B11304D7-284A-5165-9565-F9CC4405E258.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Fri, 11 Jun 2010 12:39:03 +0100
changeset 8 ae94777fff8f
parent 0 89d6a7a84779
permissions -rw-r--r--
Week 23 contribution of SDK documentation content. See release notes for details. Fixes bugs Bug 2714, Bug 462.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-B11304D7-284A-5165-9565-F9CC4405E258" xml:lang="en"><title>How
to handle multiple asynchronous requests with a wait loop</title><shortdesc>This document describes how to handle multiple asynchronous requests
with a wait loop.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>A user thread which requires asynchronous services from more than one asynchronous
service provider uses a <i>wait loop</i>.</p>
<p>The allows a thread to issue as many request as are necessary and to handle
their completion. This construction forms the heart of almost all programs
that run under Symbian platform.</p>
<p>A typical program:</p>
<ul>
<li id="GUID-1D4A7780-CC16-5D02-A80E-C1DB031B62A1"><p>waits for any request
to complete by waiting on the thread’s request semaphore.</p> </li>
<li id="GUID-E5AEA62E-4C85-55CD-96DD-02E322D8E238"><p>scans in turn through
the asynchronous service providers for which a request is known to have been
issued and tests the relevant <codeph>TRequestStatus</codeph> for completion;
this is identified by a value other than <codeph>KRequestPending</codeph>.</p> </li>
<li id="GUID-3DA7B3E5-F5CB-5853-A29F-AE78E837B9F0"><p>when the first such
completed request has been identified, handles the completed request, possibly
by issuing a further request to an asynchronous service provider.</p> </li>
<li id="GUID-3A0108AF-7833-5D6C-88C0-6794EC8E0600"><p>goes back to the top
of the wait loop and waits again.</p> </li>
</ul>
<p>As an example, a terminal emulator must work with multiple requests simultaneously,
to deal with:</p>
<ul>
<li id="GUID-9979D5C7-72B1-53E8-BE4F-9D50ECE7AB6B"><p>key presses and user
input in general, to control the action of the program and put characters
on the emulated terminal screen and/or send them to the remote host</p> </li>
<li id="GUID-A091EA85-0697-5C6D-B843-4AB3BFC7ACEC"><p>received data and to
put characters on the emulated terminal screen or perform some control function.</p> </li>
<li id="GUID-CF81C9D8-E73F-5474-9127-10169285B30F"><p>the completion of any
transmit operation that was in progress; if successful, there may be more
data to transmit; if unsuccessful, some recovery action may be necessary</p> </li>
</ul>
<section id="GUID-30FFEA97-13E6-4269-ABD4-F5832E6D4C09"><title>Typical wait loop protocol</title> <p>The typical protocol
of a wait loop is:</p> <ul>
<li id="GUID-5810F6C5-0E37-53B0-AE99-5C9FF0295709"><p>The initialization phase
which issues the first asynchronous requests.</p> </li>
<li id="GUID-A4C2AAD7-EDDE-50B3-9B60-1DC0D7AD84A0"><p>Entry into the main
loop which waits for <i>any</i> of these requests to complete and then handles
the completion of one of them.</p> </li>
<li id="GUID-3119355F-B74D-5AB3-AC77-FD0206411F8F"><p>Detection of conditions
which imply termination of the program. Typically, one of the request completion
handlers sets appropriate flags and the wait loop terminates.</p> </li>
<li id="GUID-F4323300-37BB-5BCD-926C-E3EAB1F8018E"><p>Cleanup and final termination.</p> </li>
</ul> <codeblock id="GUID-D788337C-777D-533A-8832-8B4F669B005E" xml:space="preserve">initialize;
while (!finished())
    {
    wait for one or more requests to complete
    decide which request completed, and handle it
    }
terminate;</codeblock> <p>Note that only one request should be handled per
iteration of the loop. As part of the request completion handling process,
the request may be re-issued, or new requests issued or existing ones cancelled.
If the request cannot be identified, then the thread’s request semaphore has
been signalled invalidly; this is indicative of a programming error, a condition
is known as a stray signal - the wait loop should raise a panic.</p> </section>
<section id="GUID-1487241F-94B2-46BC-BEDD-7079E2ED968D"><title>Multiple outstanding requests</title> <p>In the case of a
terminal emulator which works with multiple outstanding requests, it must
be able to service whichever request completes and must be able to re-issue
a request, if necessary. For example, when one key has been processed, a request
for the next key must be issued.</p> <p>In the following example:</p> <ul>
<li id="GUID-E29D808F-332E-5859-8693-A94C76597BDC"><p>Call <codeph>Initialize()</codeph> to
initialize the emulator.</p> </li>
<li id="GUID-0DAA2678-04D4-584A-80C2-814457662D7B"><p>Implement <codeph>while()</codeph> to
handle events.</p> </li>
<li id="GUID-012E4941-8119-5047-A07B-FC3CB9A1A916"><p>Call the function <codeph>User::WaitForAnyRequest()</codeph> to
wait for any request to complete instead of waiting for a specific request
to complete.</p> </li>
<li id="GUID-412709CA-945B-547F-8D73-7E282BF02223"><p>Identify the particular
request that completed by checking the request status objects for a value
not equal to <codeph>KRequestPending</codeph>.</p> </li>
</ul> <codeblock id="GUID-99FCFA14-81E8-5594-A716-BDE02B237F44" xml:space="preserve">class TerminalEmulator
    {
public:
    void MainLoop(); // main loop
private:
    void Initialize(); // initialize
    void Terminate(); // clean up and terminate
    TBool IsFinished(); // whether finished
private:
    // request status objects
    TRequestStatus iKeyPressed; // whether key pressed
    ...                         // ...etc for other request status
    // handler functions
    void HandleKeyPressed();    // handle key pressed
    ...                         // ... etc other handlers
    ...
    };</codeblock> <codeblock id="GUID-1F3EBBF4-4141-5B4F-9B75-EFD3D820441B" xml:space="preserve">void TerminalEmulator::MainLoop()
    {
    Initialize();         // Initialize emulator
    while (!IsFinished()) // Handle events until finished
        {
        // wait for any request to complete
        User::WaitForAnyRequest();

        // identify and handle the completed request
        if (iKeyPressed!=KRequestPending)
            {
            HandleKeyPressed();
            }
        else if (iReceiveCompleted!=KRequestPending)
                {
                HandleReceiveCompleted();
                }
            else if (iTransmitCompleted!=KRequestPending)
                    {
                    HandleTransmitCompleted();
                    }
                else
                    {
                    // something we weren’t expecting
                    // panic !
                    }
        }
    }</codeblock> <p><b>Note</b> </p> <ul>
<li id="GUID-12F90A7C-738C-5A3D-B4BB-1604B9FA0534"><p>The request status is
set by the service provider to <codeph>KRequestPending</codeph> when a request
is issued. When the request is complete, the service provider uses an operating
system call to set the request status value to some other value — usually
a standard error code — and then to wake up the thread that requested
the service, causing its <codeph>WaitForAnyRequest()</codeph> to complete.</p> </li>
</ul> </section>
</conbody></concept>