Was working on some routines that need wait instructions and would have several copies of it running at the same time.. tried using a pointer to an local variable but found that didn't work... So I wrote this routines to handle to bi-directional semaphores. There is an example of use at the bottom that is also the unit test code. Enjoy.

Code:
#ifndef SEMAPHORE_H
#define SEMAPHORE_H

void sm_startup(void);
void sm_setvalues(int Index);
int sm_Allocate(void);
int sm_AllocateShared(int Key);
int sm_SharedAllocated(int ShareIndex);
int sm_GetSharedSemaphore(int ShareIndex);
void sm_Release(int Index);
int sm_Get(int Index);
void sm_Set1(int Index);
void sm_Set2(int Index);
void sm_Clear1(int Index);
void sm_Clear2(int Index);
void sm_Clear(int Index);

#define wait_semaphore1(sm1) while((sm_Get(sm1) & SM_SEMAPHORE1) == 0) wait(1); sm_Clear1(sm1)
#define wait_semaphore2(sm1) while((sm_Get(sm1) & SM_SEMAPHORE2) == 0) wait(1); sm_Clear2(sm1)
#define wait_semaphore(sm1) while(!sm_Get(sm1)) wait(1); sm_Clear(sm1).
#define wait_get_semaphore(sm1) sm1 = sm_AllocateShared(sm1); while(!sm_SharedAllocated(sm1)) wait(1); sm1 = sm_GetSharedSemaphore(sm1)
#define sm_Get1(sm1) (sm_Get(sm1) & SM_SEMAPHORE1)
#define sm_Get2(sm1) (sm_Get(sm1) & SM_SEMAPHORE2)


#define SM_SEMAPHORE1 1
#define SM_SEMAPHORE2 2
#define SM_FIRSTRELEASE 4
#define SM_SEMAPHORE_ALLOC 8

#define SM_MASK (SM_SEMAPHORE1 | SM_SEMAPHORE2 | SM_FIRSTRELEASE | SM_SEMAPHORE_ALLOC)

#endif



Code:
#ifndef SEMAPHORE_C
#define SEMAPHORE_C

//*@@Module User Semaphore ***************************************************
// Name:
//    Semaphore
//
// Author:
//    Gordon Tackett
//
// Date:
//		12/18/2011
//
// Copyright:
//		copyright 2011 by Westmarch Studios. All rights reserved.
//
// Description:
//		This module holds all functions for handeling semaphores.
//		
// History:
//		12/18/2011 original development
//		12/21/2011 comments added
//		12/22/2011 Added shared allocation routines.
//		
//*@@End----------------------------------------------------------------------

#include <acknex.h>
#include <semaphore.h>


// define size of semaphore memory 50 DWORDS is enough space for 400 semaphores
#define MAX_SIZE 50

// number of pending semaphore allocations.
#define MAX_SHARED 30

//uncomment for unit testing
//#define SM_UNIT_TEST


//@data internal sm_namespace_type -------------------------------------------
//
// Name:
//    sm_namespace_type
//
// Description:
//    This data block holds all the global data for this module.
//
//*@@End----------------------------------------------------------------------
typedef struct {
	int	LastIndex;
	DWORD Mask;
	int	Shift;
	int	Index;
	DWORD data[MAX_SIZE];
	int	SharedKey[MAX_SHARED];
	int	SharedAllocCount[MAX_SHARED];
	int	SharedSemaphore[MAX_SHARED];
} sm_namespace_type;

sm_namespace_type sm_namespace;

#define SM_BITS_PER_SEMAPHORE 4
#define SM_SEMAPHORES_PER_DWORD ((sizeof(DWORD)*8) / SM_BITS_PER_SEMAPHORE)

//@function internal sm_startup ----------------------------------------------
//
// Name:
//    sm_startup
//
// Description:
//    This function sets all the data values in the sm namespace.
//
// Usage:
//		Automatically called by system after load.
//
// Parameters:
//		None
//
// Output:
//		No return value.
//
//*@@End----------------------------------------------------------------------
void sm_startup(void)
{
	int i;
	for (i = 0; i < MAX_SIZE; i++) {
		sm_namespace.data[i] = 0;
	}
	for (i = 0; i < MAX_SHARED; i++) {
		sm_namespace.SharedKey[i] = 0;
		sm_namespace.SharedAllocCount[i] = 0;
		sm_namespace.SharedSemaphore[i] = -1;
	}
	sm_namespace.LastIndex = 0;
	sm_namespace.Mask = SM_MASK;
	sm_namespace.Shift = 0;
	sm_namespace.Index = 0;
}


//@function internal sm_setvalues --------------------------------------------
//
// Name:
//    sm_setvalues
//
// Description:
//    This function calculates the mask, shift and index of the semaphore.
//
// Usage:
//		sm_setvalues(index);
//
// Parameters:
//		Index - integer value of selected semaphore offset
//
// Output:
//		No return value.
//
//*@@End----------------------------------------------------------------------
void sm_setvalues(int Index)
{
	if (sm_namespace.LastIndex == Index) {
		return;
	}
	sm_namespace.Index = Index / SM_SEMAPHORES_PER_DWORD;
	sm_namespace.Shift = (Index % SM_SEMAPHORES_PER_DWORD) * SM_BITS_PER_SEMAPHORE;
	sm_namespace.Mask = (SM_MASK) 
		<< sm_namespace.Shift;
	sm_namespace.LastIndex = Index;
}


//@function user sm_Allocate -------------------------------------------------
//
// Name:
//    sm_Allocate
//
// Description:
//    This function searches for the first available semaphore and returns its
//		index.
//
// Usage:
//		if ((MySemaphore = sm_Allocate()) != -1) {...}
//
// Parameters:
//		None
//
// Output:
//		Index value of first available semaphore offset or -1 for no semaphor.
//
//*@@End----------------------------------------------------------------------
int sm_Allocate(void)
{
	int retval;
	int i;
	
	retval = -1;
	for (i = 0; i < (MAX_SIZE * SM_SEMAPHORES_PER_DWORD); i++) {
		if ((sm_namespace.data[i / SM_SEMAPHORES_PER_DWORD] 
		& (SM_SEMAPHORE_ALLOC << (i % SM_SEMAPHORES_PER_DWORD) * SM_BITS_PER_SEMAPHORE)) == 0) {
			sm_Clear(i);
			sm_namespace.data[i / SM_SEMAPHORES_PER_DWORD] 
				|= (SM_SEMAPHORE_ALLOC << (i % SM_SEMAPHORES_PER_DWORD) * SM_BITS_PER_SEMAPHORE);
			retval = i;
			break;
		}
	}
	return(retval);
}


//@function user sm_AllocateShared -------------------------------------------
//
// Name:
//    sm_AllocateShared
//
// Description:
//    This function searches for the first available shared semaphore slot 
//		when called the frist time with a new share key. On second call with
//		a specific share key the semaphore is allocated. In both cases the
//		index for the shared allocation slot is returned.
//
// Usage:
//		slot = sm_AllocateShared(Mykey);
//
// Parameters:
//		Key - a value that is shared between two functions for allocating a 
//			semaphore.
//
// Output:
//		Index value of first available shared semaphore slot or -1 for no slot.
//
//*@@End----------------------------------------------------------------------
int sm_AllocateShared(int Key)
{
	int i;
	
	for (i = 0; i < MAX_SHARED; i++) {
		if (sm_namespace.SharedKey[i] == Key) {
			sm_namespace.SharedAllocCount[i]++;
			sm_namespace.SharedSemaphore[i] = sm_Allocate();
			return(i);
		}
	}
	for (i = 0; i < MAX_SHARED; i++) {
		if (sm_namespace.SharedKey[i] == 0) {
			sm_namespace.SharedKey[i] = Key;
			sm_namespace.SharedAllocCount[i] = 1;
			sm_namespace.SharedSemaphore[i] = -1;
			return(i);
		}
	}
	return(-1);
}


//@function user sm_SharedAllocated ------------------------------------------
//
// Name:
//    sm_SharedAllocated
//
// Description:
//    This function returns true when a second call to sm_AllocShared is made.
//
// Usage:
//		while(!sm_SharedAllocated(SharedIndex)) waite(1);
//
// Parameters:
//		ShareIndex - offset of shared semaphore.
//
// Output:
//		true once second call is made to sm_AllocShared.
//
//*@@End----------------------------------------------------------------------
int sm_SharedAllocated(int ShareIndex)
{
	return(sm_namespace.SharedSemaphore[ShareIndex] != -1);
}


//@function user sm_GetSharedSemaphore ---------------------------------------
//
// Name:
//    sm_GetSharedSemaphore
//
// Description:
//    This function returns a semaphore back calling function. on second call
//		with the same share index the shared allocation slot will be returned to
//		the pool for reuse.
//
// Usage:
//		MySemaphore = sm_GetSharedSemaphore(shareIndex);
//
// Parameters:
//		ShareIndex - offset of shared semaphore.
//
// Output:
//		shared semaphore or -1 for error.
//
//*@@End----------------------------------------------------------------------
int sm_GetSharedSemaphore(int ShareIndex)
{
	int retval;
	
	retval = -1; // error value for trying to call this 3 or  more times.
	`
	if (sm_namespace.SharedSemaphore[ShareIndex]) {
		sm_namespace.SharedAllocCount[ShareIndex]--;
		retval = sm_namespace.SharedSemaphore[ShareIndex];
		if (sm_namespace.SharedAllocCount[ShareIndex] == 0) {
			sm_namespace.SharedSemaphore[ShareIndex] = 0;
			sm_namespace.SharedKey[ShareIndex] = 0;
		}
	}
	return(retval);
}


//@function user sm_Release --------------------------------------------------
//
// Name:
//    sm_Release
//
// Description:
//    This function returns a semaphore back to the free semaphore pool.
//
// Usage:
//		sm_Release(MySemaphore);
//
// Parameters:
//		Index - offset of semaphore.
//
// Output:
//		no return value.
//
//*@@End----------------------------------------------------------------------
void sm_Release(int Index)
{
	sm_setvalues(Index);
	if (sm_namespace.data[sm_namespace.Index] & (SM_FIRSTRELEASE << sm_namespace.Shift)) {
		sm_namespace.data[sm_namespace.Index] &= ~sm_namespace.Mask;
	} else {
		sm_namespace.data[sm_namespace.Index] |= (SM_FIRSTRELEASE << sm_namespace.Shift);
	}
}


//@function user sm_get ------------------------------------------------------
//
// Name:
//    sm_get
//
// Description:
//    This function returns a semaphore back to the free semaphore pool.
//
// Usage:
//		val = sm_get(MySemaphore);
//
// Parameters:
//		Index - offset of semaphore.
//
// Output:
//		value of semaphore flag.
//
//*@@End----------------------------------------------------------------------
int sm_Get(int Index)
{
	int val;
	sm_setvalues(Index);
	val = ((sm_namespace.data[sm_namespace.Index] & sm_namespace.Mask) 
		>> sm_namespace.Shift) 
		& (SM_SEMAPHORE1 | SM_SEMAPHORE2);
	return(val);
}


//@function user sm_Set1 -----------------------------------------------------
//
// Name:
//    sm_Set1
//
// Description:
//    This function sets the first semaphore in the block.
//
// Usage:
//		sm_Set1(MySemaphore);
//
// Parameters:
//		Index - offset of semaphore.
//
// Output:
//		no return value.
//
//*@@End----------------------------------------------------------------------
void sm_Set1(int Index)
{
	sm_setvalues(Index);
	sm_namespace.data[sm_namespace.Index] |= (SM_SEMAPHORE1 << sm_namespace.Shift);
}


//@function user sm_Set2 -----------------------------------------------------
//
// Name:
//    sm_Set2
//
// Description:
//    This function sets the second semaphore in the block.
//
// Usage:
//		sm_Set2(MySemaphore);
//
// Parameters:
//		Index - offset of semaphore.
//
// Output:
//		no return value.
//
//*@@End----------------------------------------------------------------------
void sm_Set2(int Index)
{
	sm_setvalues(Index);
	sm_namespace.data[sm_namespace.Index] |= (SM_SEMAPHORE2 << sm_namespace.Shift);
}


//@function user sm_Clear1 ---------------------------------------------------
//
// Name:
//    sm_Clear1
//
// Description:
//    This function clears the semaphore number 1.
//
// Usage:
//		sm_Clear1MySemaphore);
//
// Parameters:
//		Index - offset of semaphore.
//
// Output:
//		no return value.
//
//*@@End----------------------------------------------------------------------
void sm_Clear1(int Index)
{
	sm_setvalues(Index);
	sm_namespace.data[sm_namespace.Index] &= ~(SM_SEMAPHORE1 << sm_namespace.Shift);
}


//@function user sm_Clear2 ---------------------------------------------------
//
// Name:
//    sm_Clear2
//
// Description:
//    This function clears the semaphore number 2.
//
// Usage:
//		sm_Clear2(MySemaphore);
//
// Parameters:
//		Index - offset of semaphore.
//
// Output:
//		no return value.
//
//*@@End----------------------------------------------------------------------
void sm_Clear2(int Index)
{
	sm_setvalues(Index);
	sm_namespace.data[sm_namespace.Index] &= ~(SM_SEMAPHORE2 << sm_namespace.Shift);
}



//@function user sm_Clear ---------------------------------------------------
//
// Name:
//    sm_Clear
//
// Description:
//    This function clears the both hores
//
// Usage:
//		sm_Clear(MySemaphore);
//
// Parameters:
//		Index - offset of semaphore.
//
// Output:
//		no return value.
//
//*@@End----------------------------------------------------------------------
void sm_Clear(int Index)
{
	sm_setvalues(Index);
	sm_namespace.data[sm_namespace.Index] 
		&= ~((SM_SEMAPHORE1 | SM_SEMAPHORE2) << sm_namespace.Shift);
}


#ifdef SM_UNIT_TEST

void test1()
{
	int semaphore;
	
	diag("\ntest 1 start");
	wait(1);
	semaphore = 42;
	diag("\ntest 1 start get semaphore wait");
	wait_get_semaphore(semaphore);
	diag("\ntest 1 got semaphore");
	sm_Set1(semaphore);
	diag("\ntest 1 start wait on semaphore");
	wait_semaphore2(semaphore);
	sm_Clear2(semaphore);
	diag("\ntest 1 got semaphore 2");
	sm_Release(semaphore);
}

void test2()
{
	int semaphore;
	
	diag("\ntest 2 start");
	wait(1);
	semaphore = 86;
	diag("\ntest 2 start get semaphore wait");
	wait_get_semaphore(semaphore);
	diag("\ntest 2 got semaphore");
	sm_Set1(semaphore);
	wait(1);
	diag("\ntest 2 start wait on semaphore");
	wait_semaphore2(semaphore);
	sm_Clear2(semaphore);
	diag("\ntest 2 got semaphore 2");
	sm_Release(semaphore);
}
	var semaphore;

void test3()
{
	
	diag("\ntest 3 start");
	wait(1);
	semaphore = 42;
	diag("\ntest 3 start get semaphore wait");
	wait_get_semaphore(semaphore);
	diag("\ntest 3 got semaphore");
	wait(1);
	sm_Set2(semaphore);
	diag("\ntest 3 start wait on semaphore");
	wait_semaphore1(semaphore);
	sm_Clear1(semaphore);
	diag("\ntest 3 got semaphore 1");
	while (sm_Get(semaphore) & SM_SEMAPHORE2) wait(1);
	diag("\ntest 3 got semaphore 2 cleared");
	sm_Release(semaphore);
}

void test4()
{
	int semaphore;
	
	diag("\ntest 4 start");
	wait(1);
	semaphore = 86;
	diag("\ntest 4 start get semaphore wait");
	wait_get_semaphore(semaphore);
	diag("\ntest 4 got semaphore");
	sm_Set2(semaphore);
	diag("\ntest 4 start wait on semaphore");
	wait_semaphore1(semaphore);
	diag("\ntest 4 got semaphore 1");
	sm_Clear1(semaphore);
	while (sm_Get(semaphore) & SM_SEMAPHORE2) wait(1);
	diag("\ntest 4 got semaphore 2 cleared");
	sm_Release(semaphore);
}

void main(void)
{
	test1();
	test2();
	test3();
	test4();
}

#endif

#endif




Our new web site:Westmarch Studios