Below is the complete source code for MeteredSection.h and MeteredSection.c. This is the same code that you can copy from the link at the top of this article.
/************************************************************
Module Name: MeteredSection.h
Author: Dan Chou
Description: Defines the metered section synchronization object
************************************************************/
// Shared info needed for metered section
typedef struct _METSECT_SHARED_INFO {
BOOL fInitialized; // Is the metered section initialized?
LONG lSpinLock; // Used to gain access to this structure
LONG lThreadsWaiting; // Count of threads waiting
LONG lAvailableCount; // Available resource count
LONG lMaximumCount; // Maximum resource count
} METSECT_SHARED_INFO, *LPMETSECT_SHARED_INFO;
// The opaque Metered Section data structure
typedef struct _METERED_SECTION {
HANDLE hEvent; // Handle to a kernel event object
HANDLE hFileMap; // Handle to memory mapped file
LPMETSECT_SHARED_INFO lpSharedInfo;
} METERED_SECTION, *LPMETERED_SECTION;
// Interface functions
LPMETERED_SECTION
CreateMeteredSection(LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);
// Allocate memory for the metered section
lpMetSect = (LPMETERED_SECTION)malloc(sizeof(METERED_SECTION));
// If the memory for the metered section was allocated okay, initialize it
if (lpMetSect)
{
if (!InitMeteredSection(lpMetSect, lInitialCount, lMaximumCount, lpName, FALSE))
{
CloseMeteredSection(lpMetSect);
lpMetSect = NULL;
}
}
return lpMetSect;
}
if (lpName)
{
lpMetSect = (LPMETERED_SECTION)malloc(sizeof(METERED_SECTION));
// If the memory for the metered section was allocated okay
if (lpMetSect)
{
if (!InitMeteredSection(lpMetSect, 0, 0, lpName, TRUE))
{
// Metered section failed to initialize
CloseMeteredSection(lpMetSect);
lpMetSect = NULL;
}
}
}
return lpMetSect;
}
#endif
// We have access to the metered section, everything we do now will be atomic
if (lpMetSect->lpSharedInfo->lAvailableCount >= 1)
{
lpMetSect->lpSharedInfo->lAvailableCount--;
ReleaseMeteredSectionLock(lpMetSect);
return WAIT_OBJECT_0;
}
// Couldn't get in. Wait on the event object
lpMetSect->lpSharedInfo->lThreadsWaiting++;
ResetEvent(lpMetSect->hEvent);
ReleaseMeteredSectionLock(lpMetSect);
if (WaitForSingleObject(lpMetSect->hEvent, dwMilliseconds) == WAIT_TIMEOUT)
{
return WAIT_TIMEOUT;
}
}
}
/*
* LeaveMeteredSection
*/
BOOL LeaveMeteredSection(LPMETERED_SECTION lpMetSect, LONG lReleaseCount, LPLONG lpPreviousCount)
{
int iCount;
GetMeteredSectionLock(lpMetSect);
// Save the old value if they want it
if (lpPreviousCount)
{
*lpPreviousCount = lpMetSect->lpSharedInfo->lAvailableCount;
}
// We have access to the metered section, everything we do now will be atomic
if ((lReleaseCount < 0) ||
(lpMetSect->lpSharedInfo->lAvailableCount+lReleaseCount >
lpMetSect->lpSharedInfo->lMaximumCount))
{
ReleaseMeteredSectionLock(lpMetSect);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lpMetSect->lpSharedInfo->lAvailableCount += lReleaseCount;
// Set the event the appropriate number of times
lReleaseCount = min(lReleaseCount,lpMetSect->lpSharedInfo->lThreadsWaiting);
if (lpMetSect->lpSharedInfo->lThreadsWaiting)
{
for (iCount=0; iCount < lReleaseCount ; iCount++)
{
lpMetSect->lpSharedInfo->lThreadsWaiting--;
SetEvent(lpMetSect->hEvent);
}
}
ReleaseMeteredSectionLock(lpMetSect);
return TRUE;
}