This discussion is archived
1 Reply Latest reply: Feb 28, 2002 6:40 PM by 807567 RSS

WaitForMultipleObjects problem?

807567 Newbie
Currently Being Moderated
Dear Sir,

I Implemented the WaitForMultipleObjects(), CreateEvent, SetEvent(), and WSAEventSelect().
I create 2 events for my test program and create 2 threads for sending and receiving message. When there are
a lot of message coming in both threads and call SetEvent(). It lost some messages. I can show you
the print text error as below. When I try to put sleep() about 150 ms in any one thread. It's work fine. I try to
patch the OS following the patch 108828-13 it can't fix my problem. I'm running on Solaris X86 5.8 and
Win32Emulation Library Solaris[TM] Version 1.1


TID: 5 Original hWin32Obj[0] = [8082a88]
TID: 5 *(win32_obj_t * ) hWin32Obj[0] = [0]
TID: 5 tmp_win32_obj (after assignment) = [8082a88]
TID: 5 tmp_win32_obj->i_event_idx = [0]
TID: 5 Original hWin32Obj[1] = [8082ae8]
TID: 5 *(win32_obj_t * ) hWin32Obj[1] = [0]
TID: 5 tmp_win32_obj (after assignment) = [8082ae8]
TID: 5 tmp_win32_obj->i_event_idx = [1]
Inside the signalObject() ,Tid = 558
Nothing to iterate...no elements in the list!
Inside the signalObject() ,Tid = 559
Nothing to iterate...no elements in the list!
Inside the signalObject() ,Tid = 556
Nothing to iterate...no elements in the list!
Inside the signalObject() ,Tid = 554
Nothing to iterate...no elements in the list!
.....
....
....
Inside the signalObject() ,Tid = 7
Nothing to iterate...no elements in the list!
TID: 5 sorted[0]: [8082ae8] origunal hWin32Obj[Count -1]: [8082ae8]
TID: 5 Grabed all the mutexes
TID: 5 Allocated signal bucket structure
TID: 5 Allocated list_element structure
TID: 5 Mask bit is set to 1, for 0
TID: 5 Mask bit is set to 1
TID: 5 Bucket is set to 1
TID: 5 About to add element [0] into list
TID: 5 In AddToList - First element added
TID: 5 Mask bit is set to 1, for 0
TID: 5 Mask bit is set to 1
TID: 5 Bucket is set to 1
TID: 5 About to add element [1] into list
TID: 5 In AddToList - First element added
TID: 5 Enter into [for;;] loop
TID: 5 Enter into [while] loop to wait...

Thanks in advance
Wichaya
www.dstinternational.com
  • 1. Re: WaitForMultipleObjects problem?
    807567 Newbie
    Currently Being Moderated
    Please find below the modified version of the WaitForMultipleObjects.c file. This version should the problem you are facing.

    Please let me know how it goes!

    Cheers,



    WaitForMultipleObjects.c file start from here:


    static char SccsID[ ] = "@(#)WaitForMultipleObjects.c 1.15 03/13/01";


    /*
    *
    * Copyright 2000-2001 Sun Microsystems, Inc.
    * 901 San Antonio Road, Palo Alto, CA 94303.
    * All Rights Reserved.
    *
    * This software is the proprietary information of Sun Microsystems, Inc.
    * Use is subject to license terms.
    *
    */


    /*
    * Implementation of Win32 functions:
    * - WaitForMultipleObjects
    * - WaitForSingleObject
    * - WaitForSingleObjectEx
    *
    * Please refer to MSDN for complete description of these functions.
    *
    * Current implementation support waiting for the following synchronizational
    * objects:
    * - Event
    * - Semaphore
    * - Mutex
    * Current implementation supports 'un-named' object only.
    */



    /****************************************************************************/
    /* Implementation of Win32 WaitFor performed */
    /* by ACE, Sun Microsystems of Canada Inc. */
    /****************************************************************************/


    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <time.h>
    #include <errno.h>
    #include "wmutex.h"

    #define MASK 1l
    #define MAX_COUNT 64

    /* Function declarations */
    static void AddToList();
    static boolean_t ClockGetTime();
    static void DeleteFromList();
    static void sort();
    DWORD WaitForMultipleObjects();
    DWORD WaitForSingleObject();
    DWORD WaitForSingleObjectEx();


    /*
    * Implementation of Win32 function WaitForMultipleObjects
    * Please refer to MSDN for complete description of this function.
    */
    DWORD
    WaitForMultipleObjects(int Count, void **hWin32Obj,
    BOOL fWaitall, long msTimeOut)
    {
    win32_obj_t *pHandle;

    win32_obj_t *sorted[MAX_COUNT];
    long mask;

    unsigned long Result;
    bucket_t *bucket;
    List_element_t **list_element;

    int i;
    struct timespec to_time; /* time value */
    struct timespec delta_time; /* time value */
    List_element_t *q;

    /* Copy pointers to sorted and do sanity check */
    for (i = 0; i < Count; i++) {
    /* keep the original sequence in i_event_idx for
    * returning the index to caller
    */

    if (hWin32Obj[i] != NULLP) {
    pHandle = (win32_obj_t *) hWin32Obj;
    pHandle->i_event_idx = i;
    }
    else
    return(WAIT_FAILED);
    sorted[i] = hWin32Obj[i];
    }

    /* sortx handle array to prevent any race condition */
    sort(sorted, Count);

    /* Create timer */
    if (msTimeOut != -1){
    if (ClockGetTime(&to_time, msTimeOut) == B_FALSE){
    return(WAIT_FAILED);
    }
    }

    /* Grab all handle mutexes in sorted order*/
    for ( i = 0; i < Count; i++) {
    pHandle = (win32_obj_t *) sorted[i];
    Pthread_mutex_lock( &pHandle->i_mutex);
    }

    /* Allocate signalbucket structure */
    bucket = (bucket_t *)createObject(NULL, BUCKET_OBJ);

    list_element = (List_element_t **)malloc(sizeof(List_element_t *)* Count);

    /* Allocate space for List_element structute, insert
    * the pointer to its bucket (i_dog) and set the maske (i_mask).
    */
    for (i = 0; i < Count; i++) {
    pHandle = sorted[i];
    q = (List_element_t *) malloc(sizeof(List_element_t));
    /* set pointer to the bucket and initialise mask*/
    q->i_dog = bucket;
    q->i_mask = 0;

    /* Now we set the mask bit q->i_mask for the bucket.
    *For ANY all the elements should have the same mask
    */
    if (fWaitall == ALL)
    q->i_mask |= MASK << i;
    else /* ANY */
    q->i_mask = MASK;

    /* set the bucket with mask according to the state of
    * win32_obj handle.
    * If the masked bit is set to 1 - it means that thread
    * have to wait.
    */
    if (!pHandle->i_signalled)
    bucket->i_bucket |= q->i_mask;
    list_element[i]=q;
    AddToList( pHandle, q );
    }

    /* Release all handle mutexes in oposit direction from locking
    * to prevent any race condition
    */
    for ( i = Count -1; i > -1; i--) {
    pHandle = (win32_obj_t *) sorted[i];
    Pthread_mutex_unlock( &pHandle->i_mutex);
    }

    /* Everything is set for waiting. Now we'll wait until
    * all handels has been signaled i_bucket has to be 0.
    */
    for (;;) {
    Pthread_mutex_lock( &bucket->i_mutex);
    while (bucket->i_bucket != 0) {
    #ifdef DEBUG
    printf("TID: %ld Enter into [while] loop to wait...\n",
    pthread_self());
    #endif
    if (msTimeOut != -1) {
    if (pthread_cond_timedwait(&bucket->i_cv,
    &bucket->i_mutex, &to_time) == ETIMEDOUT) {
    Result = WAIT_TIMEOUT;
    break;
    }
    }
    else {
    pthread_cond_wait(&bucket->i_cv,
    &bucket->i_mutex);
    }
    } /* end of while loop */

    #ifdef DEBUG
    printf("TID: %ld Exit from waiting [while] loop\n",
    pthread_self());
    #endif

    Pthread_mutex_unlock(&bucket->i_mutex);
    if (Result == WAIT_TIMEOUT)
    break;

    /* Now looks like it's time to release the thread.
    * Let's check first siglnal state for
    * all our objects.
    * First grab all handel mutexes in sorted order
    */
    for ( i = 0; i < Count; i++) {
    pHandle = (win32_obj_t *) sorted[i];
    Pthread_mutex_lock( &pHandle->i_mutex);
    }

    /* Now check the signal state */
    #ifdef DEBUG
    printf("TID: %ld Checking the signal status\n", pthread_self());
    #endif
    for ( i = 0; i < Count; i++) {
    pHandle = (win32_obj_t *) sorted[i];
    if ((fWaitall == ALL) && (!pHandle->i_signalled)) {
    /* reset the bucket bit to 1*/
    bucket->i_bucket &= ~list_element[i]->i_mask;
    }
    if (fWaitall == ANY) {
    if (pHandle->i_signalled) {
    if (!pHandle->i_manual)
    pHandle->i_signalled = B_FALSE;
    Result = pHandle->i_event_idx;
    break;
    }
    if (i == Count -1) {/*reset the bucket bit to 1 */
    bucket->i_bucket &= ~list_element[i]->i_mask;
    }
    } /* end ANY */
    }

    /* In case if PulseEvent is waitng for us */
    for ( i = 0; i< Count; i++) {
    pHandle = (win32_obj_t *) sorted[i];
    if (pHandle->i_type == WIN32OBJ_EVENT)
    pthread_cond_signal(&pHandle->i_cv);
    }

    /* This is our final check to see is it safe
    * to release the thread and remove
    * our stuff, or to go back and wait?
    */
    if (bucket->i_bucket == 0) {
    for ( i = 0; i < Count; i++) {
    pHandle = (win32_obj_t *) sorted[i];
    if (pHandle->i_type == WIN32OBJ_MUTEX) {
    if (( pHandle->u.i_mu.i_refcount > 0)
    && (pHandle->u.i_mu.i_owner_tid ==
    pthread_self())) {
    pHandle->u.i_mu.i_refcount++;
    }
    else {
    mlist_add(pHandle);
    }
    }
    }
    if (fWaitall == ANY) {
    break;
    }
    else {
    Result = WAIT_OBJECT_0;
    break;
    }
    }

    /* unlock all the mutexes and continue to wait */

    for ( i = Count - 1; i > -1; i--) {
    pHandle = (win32_obj_t *) sorted[i];
    Pthread_mutex_unlock( &pHandle->i_mutex);
    }
    #ifdef DEBUG
    printf("TID: %ld Go back and wait\n", pthread_self());
    #endif

    } /* end of for(;;) loop */

    #ifdef DEBUG
    printf("TID: %ld Exit from [for;;] loop\n", pthread_self());
    #endif

    /*
    * Delete all the List elements created by this thread for
    * each pHandle. As well we have to reset all the signals
    * in case : ALL and automatic
    */
    if ( Result == WAIT_TIMEOUT) {
    for ( i = 0; i < Count; i++) {
    pHandle = (win32_obj_t *) sorted[i];
    Pthread_mutex_lock( &pHandle->i_mutex);
    }
    }

    for(i=0; i<Count; i++){
    pHandle = (win32_obj_t *)sorted[i];
    /* Code specific to semaphore object type.
    * if there was a timeout - we do nothing, otherwise
    * decrement the count of available resource
    */
    if ((pHandle ->i_type == WIN32OBJ_SEMA) && (Result != WAIT_TIMEOUT)) {
    if (!--pHandle ->u.i_se.i_count)
    pHandle->i_signalled = B_FALSE;
    }

    if ((fWaitall == ALL) && (!pHandle->i_manual))
    pHandle->i_signalled = B_FALSE;
    DeleteFromList(pHandle, list_element[i]);
    }

    /* unlock all the mutexes in oposit direction from locking
    * to prevent any race condition.
    * In case of event object, the function PulsEvent blocks on
    * pHandle->i_cv until all threads released.
    */
    for ( i = Count - 1; i > -1; i--) {
    pHandle = (win32_obj_t *) sorted[i];
    Pthread_mutex_unlock( &pHandle->i_mutex);
    }
    /* Destroy bucket object */
    pthread_mutex_destroy( &bucket->i_mutex);
    pthread_cond_destroy(&bucket->i_cv);
    free(bucket);
    free(list_element);
    #ifdef DEBUG
    printf("TID: %ld DONE!!!\n", pthread_self());
    #endif
    return Result;
    }


    /*
    * Implementation of Win32 function WaitForSingleObject.
    * Please refer to MSDN for complete description of this function.
    */
    DWORD
    WaitForSingleObject(void *hWin32Obj, long msTimeOut )
    {
    return (WaitForMultipleObjects( 1, &hWin32Obj, ALL, msTimeOut));
    }


    /*
    * Implementation of Win32 function WaitForSingleObjectEx.
    * Please refer to MSDN for complete description of this function.
    */
    DWORD
    WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds,
    BOOL bAlertable, HANDLE timerHandle)
    {
    HANDLE aHandles[2];
    int retVal;
    timer_handle tHandle = (timer_handle )timerHandle;

    if ((bAlertable == 0) || (timerHandle == NULL))
    return(WaitForSingleObject(hHandle, dwMilliseconds));
    else {
    aHandles[0] = hHandle;
    aHandles[1] = tHandle->hEvent;
    /* Handle to waitable timer event.*/

    retVal = WaitForMultipleObjects(2, aHandles,
    FALSE, dwMilliseconds);

    if ((retVal - WAIT_OBJECT_0) == 0) {
    return(WAIT_OBJECT_0);
    }
    else if ((retVal - WAIT_OBJECT_0) == 1) {
    /* On windows, this function would now return
    * and the APC routine would be launched as a separate
    * thread. This code may need to be changed later.
    */

    /* Call APC callback routine. */
    tHandle->APC(tHandle->APCarg, 0, 0);
    return(WAIT_IO_COMPLETION);
    }
    else {
    return(retVal);
    }
    }
    }


    /*
    * Add List_element to List of subscribers pointed by the win32_obj
    * that are waiting to be signaled.
    */
    static void
    AddToList( win32_obj_t pHandle, List_element_t new_element)
    {
    struct List_element start, end;
    struct List_element p = (struct List_element)new_element ;

    if (pHandle->i_list == NULL) {
    pHandle->i_list = (List_t*)malloc(sizeof(List_t));
    pHandle->i_list->start_list = NULL;
    pHandle->i_list->end_list = NULL;
    }

    start = pHandle->i_list->start_list;
    end = pHandle->i_list->end_list;

    if ( start == NULLP ) {
    /* First element of the list */
    start = p;
    p->next = NULLP;
    p->prev = NULLP;
    end = p;
    pHandle->i_list->start_list = p;
    pHandle->i_list->end_list = p;
    }
    else {
    /*
    * Already some elements in the list...
    * add this element at the end
    */
    end->next = p;
    p->prev = end;
    p->next = NULLP;
    end = p;
    pHandle->i_list->end_list = p;
    }
    }


    /*
    * Delete element from the list of mutex_cond_t...
    */
    static void
    DeleteFromList( win32_obj_t pHandle, List_element_t element )
    {
    struct List_element start, end, *q;
    struct List_element p = (struct List_element )element ;

    if (pHandle->i_list == NULL) {
    return; /* Nothing to delete */
    }
    start = pHandle->i_list->start_list;
    end = pHandle->i_list->end_list;

    if ( start == p && end == p )
    {
    start = end = NULLP; /* only element in the list */
    free(p);
    pHandle->i_list->start_list = NULLP;
    pHandle->i_list->end_list = NULLP;
    } else if ( start == p ) {
    q = p->next;
    start = q;
    q->prev = NULLP;
    free(p);
    pHandle->i_list->start_list = start;
    } else if ( end == p ) {
    end = p->prev;
    end->next = NULLP;
    free(p);
    pHandle->i_list->end_list = end;
    } else {    /* Element is somehwre in the middle of the list */
    (p->prev)->next = p->next;
    (p->next)->prev = p->prev;
    free(p);
    }
    }


    /*
    * Sort the elements in the array from least to most.
    */
    static void
    sort( win32_obj_t **array, int limit)
    {
    int top, search;
    win32_obj_t *temp;

    for (top = 0; top < limit -1; top++)
    for (search = top +1; search < limit; search ++)
    if (array[search] > array[top]) {
    temp = array[search];
    array[search] = array[top];
    array[top] = temp;
    }
    }


    /*
    * This method gets the actual system time at which the
    * timeout must occur, based on the timeout parametar.
    *
    * Since timeOutPeriod is in milliseconds and tv_nsec is nanoseconds,
    * and both are long integers, we'd rather extract the second and
    * nanoseconds from the timeOutPeriod and add them separately, making
    * sure we're not over 1,000,000,000 nanoseconds.
    */
    static boolean_t
    ClockGetTime(struct timespec *tp, long msTimeOut)
    {
    long seconds, nseconds; /* for time calculations */

    if (clock_gettime(CLOCK_REALTIME, tp) != 0)
    return(B_FALSE);

    seconds = msTimeOut / 1000;
    nseconds = (msTimeOut - seconds*1000)*1000000;

    tp->tv_sec += seconds;
    tp->tv_nsec += nseconds;
    if (tp->tv_nsec >= 1000000000)
    {
    tp->tv_nsec -= 1000000000;
    tp->tv_sec += 1;
    }
    return(B_TRUE);
    }