/*-------------------------------------------------------------------------
 * src\fedsrv\SWMRG.H
 * 
 * Single Writer, Multiple Reader w/ Guard
 * 
 * Owner: 
 * 
 * Copyright 1986-1998 Microsoft Corporation, All Rights Reserved
 *-----------------------------------------------------------------------*/


#define ARRAY_SIZE(Array) \
   (sizeof(Array) / sizeof((Array)[0]))

// Create a BEGINTHREADEX macro that calls the C run-time's
// _beginthreadex function. The C run-time library doesn't
// want to have any reliance on Win32 data types such as
// HANDLE. This means that a Win32 programmer needs to cast
// the return value to a HANDLE. This is terribly inconvenient,
// so I have created this macro to perform the casting.
typedef unsigned (__stdcall *PTHREAD_START) (void *);

#define BEGINTHREADEX(lpsa, cbStack, lpStartAddr, \
   lpvThreadParm, fdwCreate, lpIDThread)          \
      ((HANDLE)_beginthreadex(                    \
         (void *) (lpsa),                         \
         (unsigned) (cbStack),                    \
         (PTHREAD_START) (lpStartAddr),           \
         (void *) (lpvThreadParm),                \
         (unsigned) (fdwCreate),                  \
         (unsigned *) (lpIDThread)))

// The single-writer/multiple-reader guard 
// compound synchronization object
struct SWMRG
{
   // This mutex guards access to the other objects
   // managed by this data structure and also indicates 
   // whether any writer threads are writing.
   HANDLE hMutexNoWriter;

   // This manual-reset event is signaled when
   // no reader threads are reading.
   HANDLE hEventNoReaders;

   // This semaphore is used simply as a counter that is
   // accessible between multiple processes. It is NOT
   // used for thread synchronization.
   // The count is the number of reader threads reading.
   HANDLE hSemNumReaders;

};

typedef SWMRG * PSWMRG;


// Initializes a SWMRG structure. This structure must be 
// initialized before any writer or reader threads attempt
// to wait on it.
// The structure must be allocated by the application and 
// the structure's address is passed as the first parameter.
// The lpszName parameter is the name of the object. Pass
// NULL if you do not want to share the object.
bool FSWMRGInitialize (PSWMRG pSWMRG, LPCTSTR lpszName);


// Deletes the system resources associated with a SWMRG 
// structure. The structure must be deleted only when
// no writer or reader threads in the calling process
// will wait on it.
void  SWMRGDelete (PSWMRG pSWMRG);


// A writer thread calls this function to know when 
// it can successfully write to the shared data.
DWORD SWMRGWaitToWrite (PSWMRG pSWMRG, DWORD dwTimeout);


// A writer thread calls this function to let other threads
// know that it no longer needs to write to the shared data.
void  SWMRGDoneWriting (PSWMRG pSWMRG);


// A reader thread calls this function to know when 
// it can successfully read the shared data.
DWORD SWMRGWaitToRead  (PSWMRG pSWMRG, DWORD dwTimeout);


// A reader thread calls this function to let other threads
// know when it no longer needs to read the shared data.
void  SWMRGDoneReading (PSWMRG pSWMRG);