Aw wait

From ActiveWiki
Jump to navigation Jump to search


Minimum requirements
Added in version 2.1
SDKbuild 13


int aw_wait (int milliseconds)

Description

Processes all queued packets and waits the specified time for more to arrive, calling callback and event handlers.

Callback

None

Notes

Placing calls to this method from callback or event handlers should be avoided. The reason for this being that it will in turn call such handlers. Which would cause aw_wait to indirectly call itself (e.g. aw_wait calls handler, handler calls aw_wait, repeat).

For version 4.1 and later: This method will deallocate instances that have been flagged as destroyed by aw_destroy. This is done before each iteration of processing packets for all the instances. If an application places a call to aw_destroy followed by aw_wait within a callback or event handler then it could cause the SDK to dereference a pointer to freed memory.

Blocking calls

It helps to think of blocking calls to SDK methods as placing an implicit call to aw_wait. That is, calls that have a callback but none has been registered. A blocking call will process all packets until it receives the result. This includes packets bound for other instances. The majority of these methods look like this:

int aw_address (int session_id)
{
  /* check if RC_NOT_INITIALIZED, RC_NO_INSTANCE or RC_NO_CONNECTION should be returned */
  ...

  /* send PACKET_GET_ADDRESS to the world server */
  ...

  /* 
     if this is an asynchronous call then immediately return RC_SUCCESS indicating
     that the request has been _sent_ successfully.
  */
  if (aw_callback (AW_CALLBACK_ADDRESS) != NULL)
    return RC_SUCCESS;

  /*
     wait at most 18 seconds (or return RC_TIMEOUT) for a result to PACKET_ADDRESS to come
     in for the current instance processing all packets in the meantime, calling event and
     callback handlers.
  */
  return _aw_wait (18000, PACKET_ADDRESS); 
}

That blocking SDK methods can call event and callback handlers has implications. The rule of thumb is: Never place blocking SDK method calls in an event or callback handler. It requires in-depth knowledge to know when this is safe.

For example, assume that a blocking call has been placed from within an event handler. If the event is triggered multiple times while the blocking call waits for a result then it will lead to the following problems:

Problem #1:

The first blocking call would call the event handler, which places a second blocking call. The second call must return before the first one can return. It is possible that the event is received again while the second call waits, which places a third blocking call. The third call must return before the second one can return. If more events than results are received then the call depth will increase.

Problem #2:

Assume that problem #1 occurs and leads to a big call depth. If less events than results are received then the call depth will decrease. There might be calls that will time-out due to having waited more than 18 seconds.

Problem #3:

Results will arrive in the same order that calls were placed. If there are multiple blocking calls waiting for results then the most recent call will receive the oldest result.

Arguments

If milliseconds is 0 then it will process any queued packets and return. This is typically used in single-threaded GUI applications. Where a timer is used to call this method repeatedly. A wait of around 100 ms (1000 / AW_MAX_AVCHANGE_PER_SECOND) or less between each call is recommended. See SetTimer for Windows applications.

void CALLBACK TimerProc (
    HWND hWnd,      // handle of window for timer messages
    UINT nMsg,      // WM_TIMER message
    UINT nIDEvent,  // timer identification
    DWORD dwTime)   // current system time
{
  aw_wait (0); /* process any queued packets and return */
}

/* put this together with the rest of the intialization code */
aw_init (AW_BUILD);
SetTimer (NULL, 0, 100, TimerProc); /* call aw_wait at 100 millisecond intervals */

If milliseconds is less than 0 then it will keep processing packets forever (or until aw_term is called, which is not recommended). This is typically used in simple console applications. Where any input comes through the SDK. In the form of events like chat, object clicks, and so forth.

aw_wait (-1); /* this will never return */

If milliseconds is more than 0 then it will process packets until it that amount of time has passed (or until aw_term is called, which is not recommended). This makes it possible to periodically check for input from a user. Or to perform an action at certain intervals. For example, use aw_say to say something out loud every minute. Like this,

/* say "A minute has passed" every minute */
while (1)
{
  aw_wait (60000); /* wait 60,000 milliseconds, or 60 seconds */
  aw_say ("A minute has passed");
}

This example checks for keyboard input at 100 millisecond intervals:

while (1)
{
  aw_wait (100); /* wait 100 milliseconds */
  if (_kbhit ())
  {
    int ch = _getch ();
    
    /* if 'q' was pressed then quit */
    if (_tolower (ch) == 'q')
      break;
    
    /* if 't' was pressed then print the tick count */
    if (_tolower (ch) == 't')
      printf ("Ticks: %u\n", aw_tick ());
  }
}

Note, if aw_init has not been called (or aw_term has been called) then the call will return immediately.

Argument attributes

None

Return values

RC_SUCCESS
RC_NOT_INITIALIZED
If the milliseconds argument is 0 and aw_init has not been called (or aw_term has been called).

Returned attributes

None

See also