Winsock Functions


WSAWaitForMultipleEvents Function

The WSAWaitForMultipleEvents function returns when one or all of the specified event objects are in the signaled state, when the time-out interval expires, or when an I/O completion routine has executed.

Syntax

C++
DWORD WSAWaitForMultipleEvents(
  __in  DWORD cEvents,
  __in  const WSAEVENT *lphEvents,
  __in  BOOL fWaitAll,
  __in  DWORD dwTimeout,
  __in  BOOL fAlertable
);

Parameters

cEvents [in]

The number of event object handles in the array pointed to by lphEvents. The maximum number of event object handles is WSA_MAXIMUM_WAIT_EVENTS. One or more events must be specified.

lphEvents [in]

A pointer to an array of event object handles. The array can contain handles of objects of different types. It may not contain multiple copies of the same handle if the fWaitAll parameter is set to TRUE. If one of these handles is closed while the wait is still pending, the behavior of WSAWaitForMultipleEvents is undefined. The handles must have the SYNCHRONIZE access right. For more information, see Standard Access Rights.

fWaitAll [in]

A value that specifies the wait type. If TRUE, the function returns when the state of all objects in the lphEvents array is signaled. If FALSE, the function returns when any of the event objects is signaled. In the latter case, the return value minus WSA_WAIT_EVENT_0 indicates the index of the event object whose state caused the function to return. If more than one event object became signaled during the call, this is the array index to the signaled event object with the smallest index value of all the signaled event objects.

dwTimeout [in]

The time-out interval, in milliseconds. WSAWaitForMultipleEvents returns if the time-out interval expires, even if conditions specified by the fWaitAll parameter are not satisfied. If the dwTimeout parameter is zero, WSAWaitForMultipleEvents tests the state of the specified event objects and returns immediately. If dwTimeout is WSA_INFINITE, WSAWaitForMultipleEvents waits forever; that is, the time-out interval never expires.

fAlertable [in]

A value that specifies whether the thread is placed in an alertable wait state so the system can execute I/O completion routines. If TRUE, the thread is placed in an altertable wait state and WSAWaitForMultipleEvents can return when the system executes an I/O completion routine. In this case, WSA_WAIT_IO_COMPLETION is returned and the event that was being waited on is not signaled yet. The application must call the WSAWaitForMultipleEvents function again. If FALSE, the thread is not placed in an altertable wait state and I/O completion routines are not executed.

Return Value

If the WSAWaitForMultipleEvents function succeeds, the return value upon success is one of the following values.

Return ValueMeaning
WSA_WAIT_EVENT_0 to (WSA_WAIT_EVENT_0 + cEvents - 1)

If the fWaitAll parameter is TRUE, the return value indicates that all specified event objects is signaled.

If the fWaitAll parameter is FALSE, the return value minus WSA_WAIT_EVENT_0 indicates the lphEvents array index of the signaled event object that satisfied the wait. If more than one event object became signaled during the call, the return value indicates the lphEvents array index of the signaled event object with the smallest index value of all the signaled event objects.

WSA_WAIT_IO_COMPLETION

The wait was ended by one or more I/O completion routines that were executed. The event that was being waited on is not signaled yet. The application must call the WSAWaitForMultipleEvents function again. This return value can only be returned if the fAlertable parameter is TRUE.

WSA_WAIT_TIMEOUT

The time-out interval elapsed and the conditions specified by the fWaitAll parameter were not satisfied. No I/O completion routines were executed.

 

If the WSAWaitForMultipleEvents function fails, the return value is WSA_WAIT_FAILED. The following table lists values that can be used with WSAGetLastError to get extended error information.

Error codeMeaning
WSANOTINITIALISEDA successful WSAStartup call must occur before using this function.
WSAENETDOWNThe network subsystem has failed.
WSAEINPROGRESSA blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.
WSA_NOT_ENOUGH_MEMORYNot enough free memory was available to complete the operation.
WSA_INVALID_HANDLEOne or more of the values in the lphEvents array is not a valid event object handle.
WSA_INVALID_PARAMETERThe cEvents parameter does not contain a valid handle count.

 

Remarks

The WSAWaitForMultipleEvents function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the criteria to be met. The WSAWaitForMultipleEvents function returns when any one or all of the specified objects are in the signaled state, or when the time-out interval elapses.

When the bWaitAll parameter is TRUE, the wait operation is completed only when the states of all objects have been set to signaled. The function does not modify the states of the specified objects until the states of all objects have been set to signaled.

When bWaitAll parameter is FALSE, WSAWaitForMultipleEvents checks the handles in the lphEvents array in order starting with index 0, until one of the objects is signaled. If multiple objects become signaled, the function returns the index of the first handle in the lphEvents array whose object was signaled.

This function is also used to perform an alertable wait by setting the fAltertable parameter to TRUE. This enables the function to return when the system executes an I/O completion routine by the calling thread.

A thread must be in an alertable wait state in order for the system to execute I/O completion routines (asynchronous procedure calls or APCs). So if an application calls WSAWaitForMultipleEvents when there are pending asynchronous operations that have I/O completion routines and the fAlertable parameter is FALSE, then those I/O completion routines will not be executed even if those I/O operations are completed. If the fAlertable parameter is TRUE and one of the pending operations completes, the APC is executed and WSAWaitForMultipleEvents will return WSA_IO_COMPLETION. The pending event is not signaled yet. The application must call the WSAWaitForMultipleEvents function again.

Applications that require an alertable wait state without waiting for any event objects to be signaled should use the Windows SleepEx function.

The current implementation of WSAWaitForMultipleEvents calls the WaitForMultipleObjectsEx function.

Note  Use caution when calling the WSAWaitForMultipleEvents with code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses WSAWaitForMultipleEvents with no time-out limit (the dwTimeout parameter set to WSA_INFINITE) may cause the system to become deadlocked.

Example Code

The following code example shows how to use the WSAWaitForMultipleEvents function.

#include <windows.h>
#include <stdio.h>
#include "winsock2.h"

#define DATA_BUFSIZE 4096

void main() {
  //-----------------------------------------
  // Declare and initialize variables
  WSABUF DataBuf;
  char buffer[DATA_BUFSIZE];
  DWORD EventTotal = 0, 
    RecvBytes = 0, 
    Flags = 0, 
    BytesTransferred = 0, 
    CallBack = 0;
  WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
  WSAOVERLAPPED AcceptOverlapped;
  SOCKET ListenSocket, AcceptSocket;

  //-----------------------------------------
  // Initialize Winsock
  WSADATA wsaData;
  WSAStartup(MAKEWORD(2,2), &wsaData);

  //-----------------------------------------
  // Create a listening socket bound to a local
  // IP address and the port specified
  ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  u_short port = 27015;
  char* ip;
  sockaddr_in service;
  service.sin_family = AF_INET;
  service.sin_port = htons(port);
  hostent* thisHost;
  thisHost = gethostbyname("");
  ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
	
  service.sin_addr.s_addr = inet_addr(ip);

  //-----------------------------------------
  // Bind the listening socket to the local IP address
  // and port number
  bind(ListenSocket, (SOCKADDR *) &service, sizeof(SOCKADDR));

  //-----------------------------------------
  // Set the socket to listen for incoming
  // connection requests
  listen(ListenSocket, 1);
  printf("Listening...\n");

  //-----------------------------------------
  // Accept and incoming connection request
  AcceptSocket = accept(ListenSocket, NULL, NULL);
  printf("Client Accepted...\n");

  //-----------------------------------------
  // Create an event handle and setup an overlapped structure.
  EventArray[EventTotal] = WSACreateEvent();
  ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
  AcceptOverlapped.hEvent = EventArray[EventTotal];
  DataBuf.len = DATA_BUFSIZE;
  DataBuf.buf = buffer;
  EventTotal++;

  //-----------------------------------------
  // Call WSARecv to receive data into DataBuf on 
  // the accepted socket in overlapped I/O mode
  if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR) {
    if (WSAGetLastError() != WSA_IO_PENDING)
      printf("Error occurred at WSARecv()\n");
  }

  //-----------------------------------------
  // Process overlapped receives on the socket
  while (1) {
    DWORD Index;

    //-----------------------------------------
    // Wait for the overlapped I/O call to complete
    Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);

    //-----------------------------------------
    // Reset the signaled event
    WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);

    //-----------------------------------------
    // Determine the status of the overlapped event
    WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE, &Flags);

    //-----------------------------------------
    // If the connection has been closed, close the accepted socket
    if (BytesTransferred == 0) {
      printf("Closing Socket %d\n", AcceptSocket);
      closesocket(AcceptSocket);
      WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
      return;
    }

    //-----------------------------------------
    // If data has been received, echo the received data
    // from DataBuf back to the client
    if (WSASend(AcceptSocket, &DataBuf, 1, &RecvBytes, Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR)
      printf("WSASend() is busted\n");

    //-----------------------------------------		
    // Reset the changed flags and overlapped structure
    Flags = 0;
    ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));

    AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];

    //-----------------------------------------
    // Reset the data buffer
    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;
  }
}

Requirements

Minimum supported clientWindows 2000 Professional
Minimum supported serverWindows 2000 Server
HeaderWinsock2.h
LibraryWs2_32.lib
DLLWs2_32.dll

See Also

Standard Access Rights
WaitForMultipleObjectsEx
Winsock Reference
Winsock Functions
WSACloseEvent
WSACreateEvent

Send comments about this topic to Microsoft

Build date: 11/12/2009

Tags :


Community Content

rnjn
Typo
There seems to be a typo in the Remarks section. It is mentioned that the API would return WSA_IO_COMPLETION. The correct return value as mentioned in Return Value section is WSA_WAIT_IO_COMPLETION
Tags : typo

Page view tracker