DosMuxSemWait

This call blocks a current thread until one of the specified semaphores is cleared.

Syntax
DosMuxSemWait (IndexNbr, ListAddr, Timeout)

Parameters

 * IndexNbr (PUSHORT) - output : Address of the index number of the semaphore in the list of semaphores that satisfies the wait request.
 * ListAddr (PVOID) - input : Address of the structure for list of descriptors that define the semaphores to be waited on.
 * semcount (USHORT) : Number of semaphores.
 * sementry (MUXSEM) : Array of MUXSEM structures:
 * reserved (USHORT) - Reserved; must be zero.
 * hsem (HSEM) - Reference to the semaphore.
 * For a system semaphore, this reference is the handle returned by a DosCreateSem or DosOpenSem request that granted the requesting thread access to the semaphore.
 * For a RAM semaphore, this reference is the address of a doubleword of storage, allocated and initialized to zero by the application. This sets the semaphore as unowned. Other than initializing the doubleword to zero, an application must not modify a RAM semaphore directly; instead it manipulates the semaphore with semaphore function calls.


 * Timeout (LONG) - input : Action taken by the requesting thread when none of the semaphores in the list is available. The values that can be specified are:
 * -1 - The requesting thread waits indefinitely for a semaphore to be cleared.
 * 0 - The requesting thread returns immediately.
 * >0 - The requesting thread waits the indicated number of milliseconds for a semaphore to be cleared before resuming execution.

Return Code

 * rc (USHORT) - return:Return code descriptions are:
 * 0 NO_ERROR
 * 95 ERROR_INTERRUPT
 * 101 ERROR_EXCL_SEM_ALREADY_OWNED
 * 121 ERROR_SEM_TIMEOUT
 * 151 ERROR_INVALID_EVENT_COUNT
 * 152 ERROR_TOO_MANY_MUXWAITERS
 * 153 ERROR_INVALID_LIST_FORMAT

Remarks
DosMuxSemWait checks a semaphore list. If any of the semaphores are clear, DosMuxSemWait returns. If all are set, DosMuxSemWait blocks until one of the semaphores is cleared or until the time out occurs.

Unlike other semaphore calls that block (DosSemRequest, DosSemWait, and DosSemSetWait), DosMuxSemWait is an edge-triggered, rather than a level-triggered, procedure. This means it returns whenever one of the semaphores on the list is cleared, regardless of how long that semaphore may remain clear. It is possible the semaphore may be reset before DosMuxSemWait returns. If a semaphore is cleared and then set prior to the thread's executing the DosMuxSemWait call, the event is lost. Events are only effective while a thread is in a DosMuxSemWait call.

This implementation allows DosMuxSemWait to be used in conjunction with one or more semaphores as a triggering or synchronizing device. One or more threads can call DosMuxSemWait for a particular semaphore. When an event occurs, another thread can clear the semaphore and then immediately set it again, arming it for the next event. Threads that were waiting on that semaphore return from DosMuxSemWait and resume execution.

C
 typedef struct _MUXSEMLIST { /* mxsl */ USHORT cmxs;               /* count of MuxSem structures */ MUXSEM amxs[16];           /* MuxSem structure */ } MUXSEMLIST;

typedef struct _MUXSEM {   /* mxs */ USHORT zero;             /* zero */ HSEM  hsem;              /* semaphore handle */ } MUXSEM;


 * 1) define INCL_DOSSEMAPHORES

USHORT rc = DosMuxSemWait(IndexNbr, ListAddr, Timeout);

PUSHORT         IndexNbr;    /* Index number of event (returned) */ PVOID           ListAddr;    /* Semaphore list */ LONG            Timeout;     /* Timeout (in milliseconds) */

USHORT          rc;          /* return code */ 

MASM
 MUXSEMLIST struc mxsl_cmxs dw ? ;count of MuxSem structures mxsl_amxs dw (size MUXSEM)/2 * 16 dup (?) ;MuxSem structure MUXSEMLIST ends

MUXSEM struc mxs_zero dw  ? ;zero mxs_hsem dd  ? ;semaphore handle MUXSEM ends

EXTRN DosMuxSemWait:FAR INCL_DOSSEMAPHORES EQU 1

PUSH@ WORD    IndexNbr      ;Index number of event (returned) PUSH@ OTHER   ListAddr      ;Semaphore list PUSH  DWORD   Timeout       ;Timeout (in milliseconds) CALL  DosMuxSemWait

Returns WORD 

Example Code
The following example illustrates notification of events between threads of the same process. The main thread sets two RAM semaphores and invokes two threads, each of which clears one of the semaphores. Meanwhile, the main thread waits for either of the two semaphores to clear, and then resumes execution, indicating the thread that notified first. 
 * 1) define INCL_DOSPROCESS
 * 2) define INCL_DOSSEMAPHORES


 * 1) include
 * 2) include


 * 1) define NUM_SEMS        2       /* Number of semaphores to wait on */
 * 2) define TIMEOUT         2000L   /* Timeout period */
 * 3) define SLEEPTIME       1000L   /* Sleep period for Thread_1 */
 * 4) define RETURN_CODE     0       /* Return Code for thread termination */

ULONG      RamSem1 = 0L;        /* Allocation and initialization of   */ ULONG      RamSem2 = 0L;        /*  two RAM semaphores                */ ULONG far  *RamSem1Handle = &RamSem1;  /* Semaphore handles */ ULONG far  *RamSem2Handle = &RamSem2; TID        ThreadID[2];         /* Thread Identification */ BYTE       ThreadStack1[4000];  /* Thread Stack Area */ BYTE       ThreadStack2[4000]; MUXSEMLIST SemList;             /* Semaphore list structure */ USHORT     IndexNbr;            /* Index number for DosMuxSemWait */ USHORT     rc;                  /* Return Code */

VOID APIENTRY Thread_1 { USHORT r;

printf("Begin Thread_1. It will sleep for 1 second. \n");

/* Give Thread_2 a chance to execute */ DosSleep(SLEEPTIME);                /* Sleep Interval */ if(!(r=DosSemClear(RamSem1Handle))) /* Semaphore handle */ printf("RamSem1 cleared. \n"); DosExit(EXIT_THREAD,                /* Action Code */          RETURN_CODE);                /* Result Code */ }

VOID APIENTRY Thread_2 { USHORT r;

printf("Begin Thread_2. It will try to clear RamSem2 now. \n"); if(!(r=DosSemClear(RamSem2Handle))) /* Semaphore Handle */ printf("RamSem2 cleared. \n"); DosExit(EXIT_THREAD,                /* Action Code */          RETURN_CODE);                /* Result Code */ }

main { USHORT  rc;                          /* Return Code */

/* Set both semaphores */ if(!(rc=DosSemSet(RamSem1Handle)))  /* Semaphore Handle */ printf("RamSem1 set. \n"); if(!(rc=DosSemSet(RamSem2Handle)))  /* Semaphore Handle */ printf("RamSem2 set. \n");

/* Initialize Semaphore list structure */ SemList.cmxs = NUM_SEMS;            /* Number of semaphores */ SemList.amxs[0].zero = 0;           /* This field must be 0 */ SemList.amxs[1].zero = 0;           /* This field must be 0 */ SemList.amxs[0].hsem = RamSem1Handle; /* Semaphore handle */ SemList.amxs[1].hsem = RamSem2Handle; /* Semaphore handle */

/* Start the two threads */ if(!(DosCreateThread((PFNTHREAD) Thread_1,  /* Thread address */                       &ThreadID[0],           /* Thread ID (returned) */                       &ThreadStack1[3999])))  /* End of thread stack */ printf("Thread_1 created. \n"); if(!(DosCreateThread((PFNTHREAD) Thread_2,  /* Thread address */                       &ThreadID[1],           /* Thread ID (returned) */                       &ThreadStack2[3999])))  /* End of thread stack */ printf("Thread_2 created. \n");

/* Wait for either semaphore to clear; then, indicate which */ /*  thread notified first. */

if(!(DosMuxSemWait(&IndexNbr,   /* Index of semaphore cleared (returned) */                     &SemList,     /* Address of sem. list structure */                     TIMEOUT)))    /* Timeout period */ printf("Back to main thread; semaphore cleared by Thread%d.\n",          IndexNbr + 1); } } 