RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Cooperative Multithreading in BREW with IThread : Page 3

Learn how to harness cooperative multithreading in BREW to avoid writing applications that block the CPU during lengthy operations.

Yielding the Processor
Yielding the processor in an IThread is done using ISHELL_Resume and ITHREAD_GetResumeCBK:

static void Thread1Main( SThreadCtx *pMe )
  AECHAR wsz[ 16 ];

  while( 1 )
    WSPRINTF( wsz, sizeof( wsz ), L"t1=%d", pMe->n );
    IDISPLAY_DrawText( pMe->pid, AEE_FONT_NORMAL, wsz, -1, 0, 0, NULL, 
                       IDF_ALIGN_CENTER | IDF_ALIGN_TOP);
    IDISPLAY_Update (pMe->pid);

    ISHELL_Resume( pMe->pis, ITHREAD_GetResumeCBK( pMe->pit ) );
    ITHREAD_Suspend( pMe->pit );
What raises eyebrows about this code for experienced BREW developers is the fifth line—an infinite loop, a definite no-no. Otherwise, it's quite straightforward, until the last two lines, which obtains the AEECallback instance for this thread at this particular point in execution, and then suspends thread execution. Under the hood, this code sets up the system's notion of the thread context at this point in your function, so when ISHELL_Resume resumes execution, it will do so at the current point in your function where you called ITHREAD_Suspend. This is functionally equivalent to a call to the Qualcomm-provided IThread_Yield, available in the BREW SDK's src/ directory in the file AEETU_Yield.c:

void IThread_Yield( IThread *me, IShell *pIShell )
  AEECallback *pcb = ITHREAD_GetResumeCBK( me );
  ISHELL_Resume( pIShell, pcb );
  ITHREAD_Suspend( me );
Why did Qualcomm break out the thread callback from the resume operation? Not just to keep us typing two lines instead of one, but to provide access to the callback for any callback-consuming function. Consider the Qualcomm-provided IThread_GetHostByName, which mimicks a blocking gethostbyname call, familiar to desktop developers using the Berkeley sockets interface:

int IThread_GetHostByName( IThread *me, INetMgr *piNet, 
                           AEEDNSResult *pRes, const char *pszHost)

  AEECallback *pcb = ITHREAD_GetResumeCBK(me);

  INETMGR_GetHostByName(piNet, pRes, pszHost, pcb);

  if (((AEEDNSResult *)0 != pRes) && 
       (pRes->nResult > 0) && (pRes->nResult <= AEEDNSMAXADDRS))
    return pRes->nResult;
    return 0;
By wrapping the INETMGR_GetHostByName interface within its own thread, you can simulate blocking behavior by using the thread's own AEECallback as the callback the InetMgr invokes upon completion. Once the INetMgr invokes the callback, execution continues on the line after the ITHREAD_Suspend invocation as if the pair of calls to INetMgr and IThread were a synchronous call. This trick should work anywhere an interface consumes an AEECallback; see the thread utilities provided by Qualcomm in recent drops of the SDK.

Obtaining the Result of an IThread's Execution
When a thread exits, it can provide a return value to the thread originator. Because of the prohibition on global variables in early versions of BREW, you must also provide the integer variable to store the return value. Remember the call to ITHREAD_Join in my EVT_APP_START handler?

CALLBACK_Init( &pMe->cbThread2Done, (PFNNOTIFY)Thread2Done, (void *)pMe );
ITHREAD_Join( pMe->stc2.pit, &pMe->cbThread2Done, &pMe->nThread2Result );
This causes the IThread to execute the callback function indicated by pMe->cbThread2Done when the thread terminates. Within this function, you can get the exit value (an integer) like this:

static void Thread2Done( CApp *pMe )
  DBGPRINTF( pMe->nThread2Result == SUCCESS ? 
               "Thread2 exit SUCCESS" : 
               "Thread2 exit FAILED" );
You can use ITHREAD_Join anytime you need a programmatic action on thread termination.

Give IThread a Second Chance!
For those new to BREW, it's important to realize that BREW has threads—they're just cooperative. And if you're an old saw with BREW, consider using BREW's IThread to replace some of your callback chains. You won't be disappointed.

Ray Rischpater is the chief architect at Rocket Mobile, Inc., specializing in the design and development of messaging and information access applications for today's wireless devices. Ray is the author of several books on software development including "eBay Application Development" and "Software Development for the QUALCOMM BREW Platform," both available from Apress, and is an active amateur radio operator.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date