/*
 *  handfact.c
 *
 *  author:	John R. Douceur
 *  date:	26 January 1998
 *
 *  This source file provides functions that implement assignment, release, and
 *  dereferencing operations with a handle_factory.  The code is object-oriented
 *  C, transliterated from a C++ implementation.
 *
 *  The handle factory is a component that generates and validates handles.  It
 *  is intended to be used in a software module that provides client software
 *  modules with means to refer to information structures contained within the
 *  provider.  While such a means could simply be a pointer, this would not
 *  enable the deletion of the information structures without explicitly
 *  notifying the clients of such deletion.  Unlike pointers, the handles
 *  generated by the handle factory can be examined (by the handle factory)
 *  to determine their validity.
 *
 *  Handles can be invalidated in one of two ways.  The handle can be released
 *  by calling the release_HF_handle() function, indicating to the handle
 *  factory that the handle is no longer necessary and that future requests
 *  to dereference this handle should be met with a null pointer.  Alternately,
 *  the handle can be revoked by the handle factory; this will happen unter two
 *  circumstances.  If a large number of handles (more than four billion) are
 *  issued and subsequently released, it becomes necessary to reuse portions of
 *  the handle space for future assignments; under these circumstances, very
 *  old handles will be revoked well before this recycling occurs, to give the
 *  holders of those handles ample opportunity to notice that their handles
 *  have become invalid and to request new handles.  The other situation in
 *  which revokation can occur is if the amount of available memory becomes
 *  too small to allocate additional space to expand the handle database; then,
 *  if the assignment of a new handle is requested, the least-recently-assigned
 *  handle will be revoked to make room for the new request.
 *
 *  Use of the handle factory in a multi-threaded environment requires a lock.
 *  This lock must be taken by a single thread for the execution of either
 *  assign_HF_handle() or release_HF_handle().  Use of dereference_HF_handle()
 *  does not require taking a lock, since synchronization is handled internally
 *  through careful sequencing of read and write operations.
 *
 *  None of the code or comments in this file need to be understood by writers
 *  of client code; all explanatory information for clients is found in the
 *  associated header file, handfact.h.
 *
 */

#include "gpcpre.h"

/*
 *  There are a number of aspects to the handle factory that must be understood
 *  by anyone wishing to modify this code.  The description in this comment
 *  block is intended to provide a progressive overview of the handle factory.
 *
 *  The basic system comprises a table of entries.  Each assigned handle
 *  corresponds to a single, unique entry, as determined by the handle value
 *  modulo the table size.  A handle is validated by comparing the handle value
 *  to the stored handle value in the entry.  The unassigned entries are kept
 *  on a list; when an entry is released (or revoked), it is put on the tail of
 *  the list, and when an entry is needed for an assignment, it is taken from
 *  the head of the list.
 *
 *  If there are no unassigned entries in the table when a new handle is
 *  requested, a new table of twice the size is allocated, and all assigned
 *  handles are relocated to the new table.  All unassigned handles in the new
 *  table are placed on the unassigned list.
 *
 *  As handles are released, the space required for handle entries is reduced.
 *  The table can be contracted into a table of half the size if no two assigned
 *  handles will yield the same entry address.  Two handles which will yield
 *  the same entry address in a half-size table are called a pair, and the
 *  number of such pairs is tracked in the variable pair_count, which must be
 *  zero in order to contract the table.  In order to minimize the number of
 *  pairs in the table, there are actually two lists of unassigned entries.
 *  Assigning an entry from the primary list will not increase the pair count,
 *  whereas assigning an entry from the secondary list will increase the pair
 *  count.  Thus, assignments are always made from the primary list, if it is
 *  not empty.
 *
 *  Assigned handles are also kept on a list, in order of assignment.  If it
 *  becomes necessary to revoke a handle to make room for another, the oldest
 *  handle will be revoked, and it will be found at the head of this list.
 *
 */

// This macro allocates an array of HFEntry structures.  The size of the array
// is provided as an argument to the macro.
//
//#define NEW_HFEntry_array(array_size) \
//	((HFEntry *)malloc(array_size * sizeof(HFEntry)))
#define NEW_HFEntry_array(_a,array_size) \
	GpcAllocMem(&_a,array_size * sizeof(HFEntry), HandleFactoryTag)

// This macro allocates an array of integers.  The size of the array is
// provided as an argument to the macro.
//
//#define NEW_int_array(array_size) \
//	((int *)malloc(array_size * sizeof(int)))
#define NEW_int_array(_a,array_size) \
	GpcAllocMem(&_a,array_size * sizeof(int), HandleFactoryTag)

/*
 *  Following are prototypes for static functions that are used internally by
 *  the handle factory routines.
 *
 */

// This function doubles the size of the table in which the handles and pointers
// are stored.  It is called by assign_HF_handle() when there is insufficient
// space in the table to assign the newly requested handle.  If the expansion
// is successful, the function returns a value of 0.  If the expansion fails
// (due, for example, to an inability to allocate memory), the function returns
// a value of 1.
//
int expand_HF_table(
	HandleFactory *hfact);

// This function halves the size of the table in which the handles and pointers
// are stored.  In order to reduce the amount of space consumed by the handle
// factory, this function is called called by release_HF_handle() and
// revoke_ancient_HF_handles() when they determine that the table can and should
// be contracted.  The table can be contracted when pair_count == 0 and
// table_size > 2.  However, the table may not be contracted then, because
// hysteresis is employed both to keep the mean assignment and release times
// constant and to minimize the allocation chatter of rapidly expanding and
// contracting the table.  If the contraction is successful, the function
// returns a value of 0.  If the contraction fails, the function returns a
// value of 1.
//
int contract_HF_table(
	HandleFactory *hfact);

// This function revokes handles that are between handle_base and handle_base
// + 2 * HANDLE_RANGE_STEP - 1, inclusive.  It then increments the value of
// handle_base by HANDLE_RANGE_STEP.  Suspended handles will be revoked one
// revokation pass later than non-suspended handles.
//
void revoke_ancient_HF_handles(
	HandleFactory *hfact);

// Every entry is on one of three lists, and the heads and tails of these lists
// are maintained in the entry_list[] array.  The index of this array is given
// by the following three manifest constants.
//
#define LD_PRIMARY 0       // first list from which to select an entry to assign
#define LD_SECONDARY 1    // second list from which to select an entry to assign
#define LD_ASSIGNED 2    // list of assigned entries, in order of assignment age

// When the handle space is recycled, there is a danger of handle collisions.
// In order to substantially reduce the likelihood of these collisions, very
// old handles are revoked well before their recycling begins, to give the
// holders of these handles ample opportunity to notice that their handles
// have become invalid and to request new handles.  Thus, handles are revoked
// when they become more than MAX_HANDLE_RANGE less than the currently generated
// handles.  To reduce overhead, revokations are performed in batches of size
// determined by HANDLE_RANGE_STEP.
//
// A handle may be suspended by incrementing the handle value by
// HANDLE_RANGE_STEP.  This causes the comparison in dereference_HF_handle() to
// fail, so the handle is judged to be invalid.  To reinstate the handle, the
// handle value is decremented by HANDLE_RANGE_STEP, returning the handle to its
// original value.  A handle that is suspended will be revoked one revokation
// pass later than it would have been if it hadn't been suspended.
//
#define HANDLE_RANGE_STEP ((HFHandle)0x20000000)
#define MAX_HANDLE_RANGE ((HFHandle)0x90000000)

// To keep the mean assignment and release times constant (and, indirectly, to
// minimize the allocation chatter of rapidly expanding and contracting the
// table), the table is not necessarily contracted as soon as possible.
// Hysteresis is employed to postpone the contraction until the computational
// cost of previous expansions and contractions is distributed over a sufficient
// number of assignment or release operations to maintain a constant cost per
// operation ratio.  The cost of each expansion is equal to the overhead of
// memory allocation and deallocation plus the cost to split each entry into
// two entries.  The cost of each contraction is equal to the overhead of
// memory allocation and deallocation plus the cost to merge each pair of
// entries into one entry.  The cost of memory allocation and deallocation is
// equal to ALLOCATION_COST times the mean cost of a single split or merge
// operation.  This value was determined by empirical measurement.
//
#define ALLOCATION_COST 12

// Since this is not C++, the HandleFactory structure is not self-constructing;
// therefore, the following constructor code must be called on the HandleFactory
// structure after it is allocated.  If the construction is successful, the
// function returns a value of 0.  If the construction fails (due, for example,
// to an inability to allocate memory), the function returns a value of 1.
//
int
constructHandleFactory(
	HandleFactory *hfact)
{
	// The table size is initially set to 2, and it will never be smaller.
	hfact->table_size = 2;
	// Allocate space for the initial table.
	NEW_HFEntry_array(hfact->entries,hfact->table_size);
	if (hfact->entries == 0)
	{
		// Memory could not be allocated for the array of entries created by
		// the constructor.  Therefore, we return an indication of failure to
		// the client.
		return 1;
	}
	hfact->verifier0 = 0;   // the verifiers are initialized with the same value
	hfact->verifier1 = 0;   // the verifiers are initialized with the same value
	hfact->handle_base = 0;                         // handles will start with 0
	hfact->population = 0;                      // no handles initially assigned
	hfact->pair_count = 0;                // since no assigned handles, no pairs
	hfact->hysteresis_debt = 0;
	// Initialize the two entries that are initially allocated.  Both are marked
	// as unassigned; the larger value (2) is put on the secondary list, and the
	// smaller value (1) on the secondary list.  Record 0 contains an initial
	// handle value of 2 instead of 0 because a handle value of 0 is reserved.
	hfact->entries[0].handle = hfact->handle_base + hfact->table_size;
	hfact->entries[0].next_handle = hfact->handle_base + hfact->table_size;
	hfact->entries[0].reference = 0;
	hfact->entries[0].next_entry = &hfact->entry_list[LD_SECONDARY];
	hfact->entries[0].prev_entry = &hfact->entry_list[LD_SECONDARY];
	hfact->entries[1].handle = hfact->handle_base + 1;
	hfact->entries[1].next_handle = hfact->handle_base + 1;
	hfact->entries[1].reference = 0;
	hfact->entries[1].next_entry = &hfact->entry_list[LD_PRIMARY];
	hfact->entries[1].prev_entry = &hfact->entry_list[LD_PRIMARY];
	// Initialize the primary list.  This list initially contains entry 1.
	hfact->entry_list[LD_PRIMARY].handle = 0;
	hfact->entry_list[LD_PRIMARY].next_handle = 0;
	hfact->entry_list[LD_PRIMARY].reference = 0;
	hfact->entry_list[LD_PRIMARY].next_entry = &hfact->entries[1];
	hfact->entry_list[LD_PRIMARY].prev_entry = &hfact->entries[1];
	// Initialize the secondary list.  This list initially contains entry 0.
	hfact->entry_list[LD_SECONDARY].handle = 0;
	hfact->entry_list[LD_SECONDARY].next_handle = 0;
	hfact->entry_list[LD_SECONDARY].reference = 0;
	hfact->entry_list[LD_SECONDARY].next_entry = &hfact->entries[0];
	hfact->entry_list[LD_SECONDARY].prev_entry = &hfact->entries[0];
	// Initialize the assigned list.  This list initially is empty.
	hfact->entry_list[LD_ASSIGNED].handle = 0;
	hfact->entry_list[LD_ASSIGNED].next_handle = 0;
	hfact->entry_list[LD_ASSIGNED].reference = 0;
	hfact->entry_list[LD_ASSIGNED].next_entry = &hfact->entry_list[LD_ASSIGNED];
	hfact->entry_list[LD_ASSIGNED].prev_entry = &hfact->entry_list[LD_ASSIGNED];
	// Reduce handle_base by HANDLE_RANGE_STEP so that suspended handles will
	// not slip through revokation.
	hfact->handle_base -= HANDLE_RANGE_STEP;
	// return an indication of success to the client.
	return 0;
}

// Since this is not C++, the HandleFactory structure is not self-destructing;
// therefore, the following destructor code must be called on the HandleFactory
// structure before it is deallocated.
//
void
destructHandleFactory(
	HandleFactory *hfact)
{
	// Free the space consumed by the table of handles.
	GpcFreeMem(hfact->entries, HandleFactoryTag);
}

// This function generates a new handle value, associates the handle value with
// the provided reference pointer, and returns the handle value.  Barring
// highly unusual circumstances, this handle will remain valid until it is
// explicitly released by a call to release_HF_handle().  However, there is no
// guarantee that the handle will persist for an arbitrary duration; it may
// become necessary for the handle factory to revoke the handle under some
// circumstances, particularly when the handle becomes very old or when memory
// becomes scarce.
//
// The assign_HF_handle() function will never return a handle value of zero.
// Thus, the client program is free to use a zero handle value as an escape
// indicator, if desired.
//
// In a multi-threaded environment, a single thread must take a lock prior to
// calling this function, and this must be the same lock taken before calling
// release_HF_handle().
//
HFHandle
assign_HF_handle(
	HandleFactory *hfact,
	void *reference)
{
	int list;
	HFEntry *entry;
	volatile HFEntry *seq_entry;                // volatile to ensure sequencing
	HFHandle handle;
	HFHandle handle_range;

	if (hfact->population >= hfact->table_size)
	{
		// All entries in the table are assigned, so it is necessary to
		// increase the table size.
		int expansion_failure = expand_HF_table(hfact);
		if (expansion_failure)
		{
            //
            // just fail
            //

            return 0;
#if 0

            // Expanding the table failed, presumably due to inability to
			// allocate sufficient memory.  So, instead, we revoke the least-
			// recently assigned handle.  First, remove the entry from the
			// assigned list and place it on the secondary list.
			entry = hfact->entry_list[LD_ASSIGNED].next_entry;
			entry->next_entry->prev_entry = &hfact->entry_list[LD_ASSIGNED];
			hfact->entry_list[LD_ASSIGNED].next_entry = entry->next_entry;
			entry->next_entry = &hfact->entry_list[LD_SECONDARY];
			entry->prev_entry = hfact->entry_list[LD_SECONDARY].prev_entry;
			hfact->entry_list[LD_SECONDARY].prev_entry->next_entry = entry;
			hfact->entry_list[LD_SECONDARY].prev_entry = entry;
			// Then, invalidate the handle.  The order of the operations is
			// important to correct multi-threaded operation.
			seq_entry = entry;
			seq_entry->handle = entry->next_handle;   // first invalidate handle
			seq_entry->reference = 0;                    // then clear reference
			// Decrement the pair count and population, so that when they are
			// incremented in the code below, they will have correct values.
			hfact->pair_count--;
			hfact->population--;
#endif
		}
	}
	// At this point, there is at least one available entry.  If there is any
	// entry on the primary list, it should be selected.
	list = LD_PRIMARY;
	if (hfact->entry_list[LD_PRIMARY].next_entry ==
		&hfact->entry_list[LD_PRIMARY])
	{
		// The primary list is empty, so we take from the secondary list.  By
		// definition, this will increase the pair count.
		list = LD_SECONDARY;
		hfact->pair_count++;
	}
	// Remove the entry from the head of the appropriate list and place it on
	// the assigned list.
	entry = hfact->entry_list[list].next_entry;
	handle = entry->handle;
	entry->next_entry->prev_entry = entry->prev_entry;
	entry->prev_entry->next_entry = entry->next_entry;
	entry->next_entry = &hfact->entry_list[LD_ASSIGNED];
	entry->prev_entry = hfact->entry_list[LD_ASSIGNED].prev_entry;
	hfact->entry_list[LD_ASSIGNED].prev_entry->next_entry = entry;
	hfact->entry_list[LD_ASSIGNED].prev_entry = entry;
	// Set the reference pointer to that provided as an argument.
	entry->reference = reference;
	// The next handle for this entry will be greater by the table size.  It
	// is important to set this value in this routine because unequal values of
	// handle and next_handle indicate an assigned entry.
	entry->next_handle = handle + hfact->table_size;
	if (entry->next_handle == 0)
	{
		// The handle value has wrapped around back to zero; however, zero is
		// a reserved value, so we instead set the next handle to the subsequent
		// legal value, which is the table size.
		entry->next_handle = hfact->table_size;
	}
	// The population has increased by one.
	hfact->population++;
	// We're being tricky with unsigned integer math here.  We revoke ancient
	// handles if the value of the handle we are currently issuing is greater
	// than the handle base by more than MAX_HANDLE_RANGE, modulo the size of
	// the handle space.  The modulo is implicit.
	handle_range = handle - hfact->handle_base;
	if (handle_range > MAX_HANDLE_RANGE)
	{
		revoke_ancient_HF_handles(hfact);
	}
	// This assignment operation decreases the hysteresis debt.
	if (hfact->hysteresis_debt > 0)
	{
		hfact->hysteresis_debt--;
	}
	// Return the newly assigned handle.
	return handle;
}

// This function releases a handle, indicating that further attempts to
// dereference the handle should result in a null pointer value rather than the
// pointer value that was originally assigned to the handle.  The handle factory
// checks the validity of the handle and returns a corresponding status code.
// If the handle is currently assigned, then it is released, and the function
// returns a value of 0.  If the handle is not currently assigned, the function
// aborts and returns a value of 1.
//
// In a multi-threaded environment, a single thread must take a lock prior to
// calling this function, and this must be the same lock taken before calling
// assign_HF_handle().
//
int
release_HF_handle(
	HandleFactory *hfact,
	HFHandle handle)
{
	int entry_index;
	HFEntry *entry;
	HFEntry *other_entry;
	int list;
	HFHandle adjusted_next_handle;
	HFHandle adjusted_other_next_handle;
	volatile HFEntry *seq_entry;                // volatile to ensure sequencing

	// Compute the index of the entry by taking the handle value modulo the
	// table size.  Since the table size is a power of two, we can simply
	// subtract one to produce a mask and then conjoin the mask with the
	// handle value.
	entry_index = handle & hfact->table_size - 1;
	entry = &hfact->entries[entry_index];
	if ((entry->handle != handle && entry->handle != handle + HANDLE_RANGE_STEP)
		|| entry->handle == entry->next_handle)
	{
		// Either the indexed entry does not refer to the provided handle nor to
		// the provided handle's suspension value, or the entry is unassigned.
		// In any of these cases, abort and return an error code to the client.
		return 1;
	}
	// The "other entry" is the entry that would have to be merged with the
	// indexed entry if the table size were to be contracted in half.
	other_entry = &hfact->entries[entry_index ^ hfact->table_size / 2];
	if (other_entry->handle == other_entry->next_handle)
	{
		// We're being tricky with unsigned integer math here.  Before comparing
		// the two next handles, we subtract from each the value of handle_base,
		// modulo the size of the handle space (the modulo is implicit).  This
		// allows the effective comparison of their logical acyclic values
		// rather than their actual cyclic values.
		adjusted_next_handle = entry->next_handle - hfact->handle_base;
		adjusted_other_next_handle =
			other_entry->next_handle - hfact->handle_base;
		if (adjusted_other_next_handle < adjusted_next_handle)
		{
			// The other entry is unassigned and has a smaller handle value
			// than the indexed entry.  Thus, the other entry should be moved
			// from the secondary list to the primary list, and the indexed
			// entry should be placed on the secondary list.
			other_entry->next_entry->prev_entry = other_entry->prev_entry;
			other_entry->prev_entry->next_entry = other_entry->next_entry;
			other_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
			other_entry->prev_entry = hfact->entry_list[LD_PRIMARY].prev_entry;
			hfact->entry_list[LD_PRIMARY].prev_entry->next_entry = other_entry;
			hfact->entry_list[LD_PRIMARY].prev_entry = other_entry;
			list = LD_SECONDARY;
		}
		else
		{
			// The other entry is unassigned and has a larger handle value
			// than the indexed entry.  Thus, the indexed entry should be
			// placed on the secondary list.
			list = LD_PRIMARY;
		}
	}
	else
	{
		// The other entry is assigned.  Thus, the indexed entry should be
		// placed on the secondary list.  Also, since the two entries were
		// both assigned, they formed a pair.  Since we are releasing one of
		// them, the pair count drops by one.
		list = LD_SECONDARY;
		hfact->pair_count--;
	}
	// Remove the entry from the assigned list and place it on the
	// appropriate list.
	entry->next_entry->prev_entry = entry->prev_entry;
	entry->prev_entry->next_entry = entry->next_entry;
	entry->next_entry = &hfact->entry_list[list];
	entry->prev_entry = hfact->entry_list[list].prev_entry;
	hfact->entry_list[list].prev_entry->next_entry = entry;
	hfact->entry_list[list].prev_entry = entry;
	// Invalidate the handle.  The order of the operations is important to
	// correct multi-threaded operation.
	seq_entry = entry;
	seq_entry->handle = entry->next_handle;           // first invalidate handle
	seq_entry->reference = 0;                            // then clear reference
	// The population has decreased by one.
	hfact->population--;
	// This release operation decreases the hysteresis debt.
	if (hfact->hysteresis_debt > 0)
	{
		hfact->hysteresis_debt--;
	}
	// To contract the table, there must be no pairs, because otherwise two
	// assigned handles would yield the same entry index and thereby conflict.
	// Furthermore, the table size must be greater than 2, because much of the
	// handle factory code assumes that the table is at least of size 2.  In
	// addition to these strict requirements, hysteresis is employed both to
	// keep the mean assignment and release times constant and to minimize the
	// allocation chatter of rapidly expanding and contracting the table.  Only
	// if the hysteresis debt is zero will the table be contracted.
	if (hfact->pair_count == 0 && hfact->table_size > 2 &&
		hfact->hysteresis_debt == 0)
	{
		contract_HF_table(hfact);
		// Note that we ignore the return code.  If the contraction is
		// unsuccessful, we just continue as usual.  There is no real harm in
		// not contracting the table, except that we consume more space than
		// necessary.
	}
	// return an indication of success to the client.
	return 0;
}

// This function suspends a handle, indicating that further attempts to
// dereference the handle should result in a null pointer value rather than the
// pointer value that was originally assigned to the handle, unless and until
// reinstate_HF_handle() is called on the handle value.  The handle factory
// checks the validity of the handle and returns a corresponding status code.
// If the handle is currently assigned and not suspended, then it is suspended,
// and the function returns a value of 0.  If the handle is not currently
// assigned or has already been suspended, the function aborts and returns a
// value of 1.
//
// In a multi-threaded environment, a single thread must take a lock prior to
// calling this function, and this must be the same lock taken before calling
// assign_HF_handle(), release_HF_handle(), and reinstate_HF_handle().
//
int
suspend_HF_handle(
	HandleFactory *hfact,
	HFHandle handle)
{
	int entry_index;
	HFEntry *entry;

	// Compute the index of the entry by taking the handle value modulo the
	// table size.  Since the table size is a power of two, we can simply
	// subtract one to produce a mask and then conjoin the mask with the
	// handle value.
	entry_index = handle & hfact->table_size - 1;
	entry = &hfact->entries[entry_index];
	if (entry->handle != handle || entry->handle == entry->next_handle)
	{
		// Either the indexed entry does not refer to the provided handle, or
		// the entry is unassigned.  In either case, abort and return an error
		// code to the client.
		return 1;
	}
	// Suspend the handle.
	entry->handle += HANDLE_RANGE_STEP;
	// This suspension operation decreases the hysteresis debt.
	if (hfact->hysteresis_debt > 0)
	{
		hfact->hysteresis_debt--;
	}
	// return an indication of success to the client.
	return 0;
}

// This function reinstates a suspended handle, indicating that further attempts
// to dereference the handle should result in the pointer value that was
// originally assigned to the handle, rather than the null pointer value to
// which a suspended handle dereferences.  The handle factory checks the
// validity of the handle and returns a corresponding status code. If the handle
// is currently assigned and suspended, then it is reinstated, and the function
// returns a value of 0.  If the handle is not currently assigned or is not
// suspended, the function aborts and returns a value of 1.
//
// In a multi-threaded environment, a single thread must take a lock prior to
// calling this function, and this must be the same lock taken before calling
// assign_HF_handle(), release_HF_handle(), and suspend_HF_handle().
//
int
reinstate_HF_handle(
	HandleFactory *hfact,
	HFHandle handle)
{
	int entry_index;
	HFEntry *entry;

	// Compute the index of the entry by taking the handle value modulo the
	// table size.  Since the table size is a power of two, we can simply
	// subtract one to produce a mask and then conjoin the mask with the
	// handle value.
	entry_index = handle & hfact->table_size - 1;
	entry = &hfact->entries[entry_index];
	if (entry->handle != handle + HANDLE_RANGE_STEP ||
		entry->handle == entry->next_handle)
	{
		// Either the indexed entry does not refer to the provided handle's
		// suspension value, or the entry is unassigned.  In either case, abort
		// and return an error code to the client.
		return 1;
	}
	// Reinstate the handle.
	entry->handle -= HANDLE_RANGE_STEP;
	// This reinstatement operation decreases the hysteresis debt.
	if (hfact->hysteresis_debt > 0)
	{
		hfact->hysteresis_debt--;
	}
	// return an indication of success to the client.
	return 0;
}

// This function validates a handle and returns either the associated pointer
// (if the handle is valid) or a null pointer value (if the handle is invalid).
// If the handle has not been released but a null value is returned, then the
// handle has been revoked by the handle factory.  This is expected to be a
// highly unusual occurrence; however, since it can happen, any program that
// employs the handle factory must have some auxiliary mechanism for retrieving
// the desired pointer information.  Once the pointer is retrieved through this
// (presumably expensive) auxiliary means, a new handle can be reassigned to
// the pointer by another call to assign_HF_handle().
//
// Even in a multi-threaded environment, it is not necessary to take a lock
// prior to calling this function.  Careful sequencing of read and write
// operations inside the handle factory code obviates the need to explicitly
// lock the data structure for dereferencing handles.
//
void *
dereference_HF_handle(
	HandleFactory *hfact,
	HFHandle handle)
{
	HFHandle entry_handle;
	void *reference;
	//int verifier;
	int entry_index;
	/*volatile*/ HFEntry *entry;                    // volatile to ensure sequencing

	// This loop spins until the verifier variables begin and end a pass of
	// the loop with the same value. There is an extremely short sequence
	// of instructions in the expand and contract routines that modifies the
	// values of the entries and table_size variables, and these modifications
	// are bracketed by increments of the verifier variables in the reverse
	// order as they are here read.  As long as the verifiers have the same
	// value, then entries and table_size are in a consistent state.  This loop
	// should very rarely be executed more than once, since the modification in
	// the other routines is so short.
	do
	{
		//verifier = hfact->verifier1;
		// Compute the index of the entry by taking the handle value modulo the
		// table size.  Since the table size is a power of two, we can simply
		// subtract one to produce a mask and then conjoin the mask with the
		// handle value.
		entry_index = handle & hfact->table_size - 1;
		entry = &hfact->entries[entry_index];
		// Get local copies of the reference pointer and handle value.  The
		// order of the operations is important to correct multi-threaded
		// operation.
		reference = entry->reference;                     // first get reference
		entry_handle = entry->handle;       // then get handle to check validity
	}	while (0 /*verifier != hfact->verifier0*/);
	if (entry_handle == handle)
	{
		// The stored handle matches the provided handle, so the latter is
		// valid.  We thus return the reference pointer.
		return reference;
	}
	else
	{
		// The stored handle does not match the provided handle, so the latter
		// is invalid.  We thus return a null pointer.
		return 0;
	}
}



void *
dereference_HF_handle_with_cb(
	HandleFactory *hfact,
	HFHandle handle,
    ULONG    offset)
{
	HFHandle entry_handle;
	void *reference;
	//int verifier;
	int entry_index;
	/*volatile*/ HFEntry *entry;                    // volatile to ensure sequencing

	// This loop spins until the verifier variables begin and end a pass of
	// the loop with the same value. There is an extremely short sequence
	// of instructions in the expand and contract routines that modifies the
	// values of the entries and table_size variables, and these modifications
	// are bracketed by increments of the verifier variables in the reverse
	// order as they are here read.  As long as the verifiers have the same
	// value, then entries and table_size are in a consistent state.  This loop
	// should very rarely be executed more than once, since the modification in
	// the other routines is so short.
	do
	{
		//verifier = hfact->verifier1;
		// Compute the index of the entry by taking the handle value modulo the
		// table size.  Since the table size is a power of two, we can simply
		// subtract one to produce a mask and then conjoin the mask with the
		// handle value.
		entry_index = handle & hfact->table_size - 1;
		entry = &hfact->entries[entry_index];
		// Get local copies of the reference pointer and handle value.  The
		// order of the operations is important to correct multi-threaded
		// operation.

        if ((entry->reference) && (entry->handle == handle)) {

            ASSERT(((PCLASSIFICATION_BLOCK)entry->reference)->NumberOfElements > offset);
            reference = (void *)((PCLASSIFICATION_BLOCK)entry->reference)->arpBlobBlock[offset];
            TRACE(CLASSIFY, entry->reference, reference, "dereference_HF_handle_with_cb");

            return reference;

        } else {

            reference = 0;
            return 0;

        }

	}	while (0 /*verifier != hfact->verifier0*/);

}




#ifdef _TEST_HANDFACT

// This is a test routine that simply verifies the internal valididy of the
// handle factory's data structures.  By defining the constant _TEST_HANDFACT,
// this routine will be compiled and available to the client code.  It can be
// called at any time, unless running in a multi-threaded environment, in which
// case the caller must first take the same lock used for assign_HF_handle()
// and release_HF_handle.  If the routine returns any value other than zero,
// then the internal lists of records are in an inconsistent state.
//
int
verify_HF_lists(
	HandleFactory *hfact)
{
	int entry_count[3];
	int list;
	HFEntry *entry;
	for (list = 0; list < 3; list++)
	{
		entry_count[list] = 0;
		entry = &hfact->entry_list[list];
		do
		{
			entry_count[list]++;
			if (entry->next_entry->prev_entry != entry)
			{
				return 1;
			}
			entry = entry->next_entry;
		}	while (entry != &hfact->entry_list[list]);
		entry_count[list]--;
	}
	if (entry_count[2] != hfact->population)
	{
		return 2;
	}
	if (entry_count[0] + entry_count[2] - 2 * hfact->pair_count !=
		entry_count[1])
	{
		return 3;
	}
	if (entry_count[0] + entry_count[1] + entry_count[2] != hfact->table_size)
	{
		return 4;
	}
	return 0;
}

#endif /* _TEST_HANDFACT */

// This function doubles the size of the table in which the handles and pointers
// are stored.  It is called by assign_HF_handle() when there is insufficient
// space in the table to assign the newly requested handle.  If the expansion
// is successful, the function returns a value of 0.  If the expansion fails
// (due, for example, to an inability to allocate memory), the function returns
// a value of 1.
//
int expand_HF_table(
	HandleFactory *hfact)
{
	int double_size;
	HFEntry *new_entries;
	HFEntry *old_entries;
	HFEntry *old_entry;
	HFEntry *low_entry;
	HFEntry *high_entry;
	HFEntry *assigned_entry;
	HFEntry *secondary_entry;
	HFEntry *other_entry;
	HFHandle handle;
	HFHandle next_handle;
	HFHandle other_handle;
	void *reference;
	int other_entry_index;
	int index;

	// Expanded table is double the size of the old table.
	double_size = hfact->table_size * 2;
	// Allocate space for the expanded table.
	NEW_HFEntry_array(new_entries,double_size);
	if (new_entries == 0)
	{
		// Memory could not be allocated for the new array of entries.
		// Therefore, we return an indication of failure.
		return 1;
	}
	// Since we are doubling the table size, we will be treating one more bit
	// of each handle as a bit of the entry index.  The value of this bit
	// determines the index of the entry in the new table.  For each entry,
	// we have to determine the value of this bit and relocate the entry to
	// the indicated location.
	for (index = 0; index < hfact->table_size; index++)
	{
		old_entry = &hfact->entries[index];
		low_entry = &new_entries[index];
		high_entry = &new_entries[hfact->table_size + index];
		handle = old_entry->handle;
		next_handle = old_entry->next_handle;
		reference = old_entry->reference;
		// One of the two entries in the new table that correspond to the
		// indexed entry in the old table will have a next handle value equal
		// to the next handle value of the entry in the old table, and one will
		// have a handle value equal to the indexed entry's next handle plus
		// the old table size.
		other_handle = next_handle + hfact->table_size;
		if (other_handle == 0)
		{
			// The handle value has wrapped around back to zero; however, zero
			// is a reserved value, so we instead set the next handle to the
			// subsequent legal value, which is the new table size.
			other_handle = double_size;
		}
		if ((handle & hfact->table_size) == 0)
		{
			// The handle of the old entry has a zero in its next bit, so the
			// old entry will be located in the lower half of the new table.
			if ((next_handle & hfact->table_size) == 0)
			{
				// The next handle of the old entry has a zero in its next bit,
				// so this value will be the next handle for the lower entry
				// and the other next handle value will be the next handle
				// value for the higher entry.  The high entry handle is set
				// equal to its next handle because it is unassigned.
				high_entry->handle = other_handle;
				high_entry->next_handle = other_handle;
				low_entry->next_handle = next_handle;
			}
			else
			{
				// The next handle of the old entry has a zero in its next bit,
				// so this value will be the next handle for the higher entry
				// and the other next handle value will be the next handle
				// value for the lower entry.  The high entry handle is set
				// equal to its next handle because it is unassigned.
				high_entry->handle = next_handle;
				high_entry->next_handle = next_handle;
				low_entry->next_handle = other_handle;
			}
			// The high entry is unassigned, so set its reference to null.
			// Copy the information from the old entry to the low entry.
			// Remove the old entry from the assigned list, and replace it
			// with the low entry.
			high_entry->reference = 0;
			low_entry->handle = handle;
			low_entry->reference = reference;
			old_entry->next_entry->prev_entry = low_entry;
			old_entry->prev_entry->next_entry = low_entry;
			low_entry->next_entry = old_entry->next_entry;
			low_entry->prev_entry = old_entry->prev_entry;
		}
		else
		{
			// The handle of the old entry has a one in its next bit, so the
			// old entry will be located in the higher half of the new table.
			if ((next_handle & hfact->table_size) == 0)
			{
				// The next handle of the old entry has a zero in its next bit,
				// so this value will be the next handle for the lower entry
				// and the other next handle value will be the next handle
				// value for the higher entry.  The low entry handle is set
				// equal to its next handle because it is unassigned.
				high_entry->next_handle = other_handle;
				low_entry->handle = next_handle;
				low_entry->next_handle = next_handle;
			}
			else
			{
				// The next handle of the old entry has a zero in its next bit,
				// so this value will be the next handle for the higher entry
				// and the other next handle value will be the next handle
				// value for the lower entry.  The low entry handle is set
				// equal to its next handle because it is unassigned.
				high_entry->next_handle = next_handle;
				low_entry->handle = other_handle;
				low_entry->next_handle = other_handle;
			}
			// The low entry is unassigned, so set its reference to null.
			// Copy the information from the old entry to the high entry.
			// Remove the old entry from the assigned list, and replace it
			// with the high entry.
			low_entry->reference = 0;
			high_entry->handle = handle;
			high_entry->reference = reference;
			old_entry->next_entry->prev_entry = high_entry;
			old_entry->prev_entry->next_entry = high_entry;
			high_entry->next_entry = old_entry->next_entry;
			high_entry->prev_entry = old_entry->prev_entry;
		}
	}
	// All of the unassigned entries in the new table will be placed on the
	// secondary list.  We loop through the assigned list and place the
	// unassigned entry corresponding each assigned entry onto the secondary
	// list.  Doing the list assignment in this manner tends to approximately
	// sort the secondary list according to handle value, since the assigned
	// list is sorted according to assignment order, and this approximately
	// correlates to the handle value.
	assigned_entry = hfact->entry_list[LD_ASSIGNED].next_entry;
	secondary_entry = &hfact->entry_list[LD_SECONDARY];
	while (assigned_entry != &hfact->entry_list[LD_ASSIGNED])
	{
		other_entry_index =
			assigned_entry->handle + hfact->table_size & double_size - 1;
		other_entry = &new_entries[other_entry_index];
		secondary_entry->next_entry = other_entry;
		other_entry->prev_entry = secondary_entry;
		secondary_entry = other_entry;
		assigned_entry = assigned_entry->next_entry;
	}
	// Wrap up lists by connecting in tails.
	secondary_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
	hfact->entry_list[LD_SECONDARY].prev_entry = secondary_entry;
	// This expansion increases the hysteresis debt by the cost of one set of
	// allocation and deallocation operations plus the cost of splitting each
	// entry into two entries.
	hfact->hysteresis_debt += ALLOCATION_COST + hfact->table_size;
	// Save a pointer to the old entry table so that it can be deallocated.
	old_entries = hfact->entries;
	// Note that we have not modified the handle, next_handle, or reference
	// fields of any entries in the old table.  Therefore, any calls to the
	// dereference_HF_handle() routine that may have been made by other threads
	// during the above operations would have been performed successfully.
	// We are now about to increase the table size and update the entries
	// variable to point to the new table.  These operations must be performed
	// atomically in order for the dereference routine to perform correctly.
	// We thus bracket the operations with increments to the verifier variables.
	// When the verifiers have the same value, the table_size and entries
	// variables are in a consistent state.  This is checked by the dereference
	// routine.
	hfact->verifier0++;                                // begin critical section
	hfact->entries = new_entries;
	hfact->table_size = double_size;
	hfact->verifier1 = hfact->verifier0;                 // end critical section
	// Deallocate the old table.
	GpcFreeMem(old_entries, handleFactoryTag);
	// Since the new table was created by expanding a half-size table, the pair
	// count must be zero.
	hfact->pair_count = 0;
	// return an indication of success.
	return 0;
}

// This function halves the size of the table in which the handles and pointers
// are stored.  In order to reduce the amount of space consumed by the handle
// factory, this function is called called by release_HF_handle() and
// revoke_ancient_HF_handles() when they determine that the table can and should
// be contracted.  The table can be contracted when pair_count == 0 and
// table_size > 2.  However, the table may not be contracted then, because
// hysteresis is employed both to keep the mean assignment and release times
// constant and to minimize the allocation chatter of rapidly expanding and
// contracting the table.  If the contraction is successful, the function
// returns a value of 0.  If the contraction fails, the function returns a
// value of 1.
//
int contract_HF_table(
	HandleFactory *hfact)
{
	HFEntry *new_entries;
	HFEntry *old_entries;
	int *list;
	int half_size;
	int quarter_size;
	int index;
	HFEntry *high_entry1;
	HFEntry *high_entry0;
	HFEntry *low_entry1;
	HFEntry *low_entry0;
	HFEntry *new_entry1;
	HFEntry *new_entry0;
	HFHandle adjusted_high_next_handle1;
	HFHandle adjusted_low_next_handle1;
	HFHandle next_handle1;
	HFHandle adjusted_high_next_handle0;
	HFHandle adjusted_low_next_handle0;
	HFHandle next_handle0;
	HFHandle adjusted_new_handle0;
	HFHandle adjusted_new_handle1;
	HFEntry *entry;
	HFEntry *primary_entry;
	HFEntry *secondary_entry;

	// Contracted table is half the size of the old table.
	half_size = hfact->table_size / 2;
	quarter_size = half_size / 2;
	// Allocate space for the contracted table.
	NEW_HFEntry_array(new_entries,half_size);
	if (new_entries == 0)
	{
		// Memory could not be allocated for the new array of entries, so we
		// are ironically prevented from reducing the amount of memory that
		// the handle factory is consuming. Therefore, we return an indication
		// of failure.
		return 1;
	}
	// Allocate space for auxiliary array of list indicators
	NEW_int_array(list,half_size);
	if (list == 0)
	{
		// Memory could not be allocated for the auxiliary array, so again we
		// are ironically prevented from reducing the amount of memory that
		// the handle factory is consuming. Therefore, we return an indication
		// of failure.  First, however, we must free the memory allocated for
		// the new array of entries above.
		GpcFreeMem(new_entries, handleFactoryTag);
		return 1;
	}
	// Since we are halving the size of the table, it might seem reasonable to
	// loop through each index of the new table and merge the two corresponding
	// entries from the old table.  This is in fact what the following routine
	// does; however, it does it by looping through only half of the new indices
	// and processing two merges for each index.  It does this so that it can
	// then examine the two new entries to determine on which list to place each
	// of them.
	for (index = 0; index < quarter_size; index++)
	{
		// We're looking at four entries at once.  First we merge high_entry1
		// and low_entry1, and then we independently merge high_entry0 and
		// low_entry0.  After the two merges, we examine the results jointly.
		high_entry1 = &hfact->entries[half_size + quarter_size + index];
		high_entry0 = &hfact->entries[half_size + index];
		low_entry1 = &hfact->entries[quarter_size + index];
		low_entry0 = &hfact->entries[index];
		new_entry1 = &new_entries[quarter_size + index];
		new_entry0 = &new_entries[index];
		// When merging two entries, the next handle value for the combined
		// entry is equal to the larger next handle value of the two, minus
		// the new table size.  However, the determination of which is larger
		// must be made with respect to their logical acyclic values rather
		// than their actual cyclic values, so we subtract from each the value
		// of handle_base, modulo the size of the handle space.  The modulo is
		// implicit.
		adjusted_high_next_handle1 =
			high_entry1->next_handle - hfact->handle_base;
		adjusted_low_next_handle1 =
			low_entry1->next_handle - hfact->handle_base;
		next_handle1 = __max(adjusted_high_next_handle1,
			adjusted_low_next_handle1) + hfact->handle_base - half_size;
		// Since handle 1 is -- by definition -- in either the second or fourth
		// quarter of the table, there is no need to check for the reserved
		// value of zero.
		if (high_entry1->handle != high_entry1->next_handle)
		{
			// The high entry is assigned, so we copy its handle value and
			// reference pointer.  Also, we remove it from the assigned list
			// and replace it with the new entry.
			new_entry1->handle = high_entry1->handle;
			new_entry1->reference = high_entry1->reference;
			high_entry1->next_entry->prev_entry = new_entry1;
			high_entry1->prev_entry->next_entry = new_entry1;
			new_entry1->next_entry = high_entry1->next_entry;
			new_entry1->prev_entry = high_entry1->prev_entry;
		}
		else if (low_entry1->handle != low_entry1->next_handle)
		{
			// The low entry is assigned, so we copy its handle value and
			// reference pointer.  Also, we remove it from the assigned list
			// and replace it with the new entry.
			new_entry1->handle = low_entry1->handle;
			new_entry1->reference = low_entry1->reference;
			low_entry1->next_entry->prev_entry = new_entry1;
			low_entry1->prev_entry->next_entry = new_entry1;
			new_entry1->next_entry = low_entry1->next_entry;
			new_entry1->prev_entry = low_entry1->prev_entry;
		}
		else
		{
			// Neither entry is assigned, so we indicate an unassigned condition
			// in the new entry.
			new_entry1->handle = next_handle1;
			new_entry1->reference = 0;
			if (adjusted_high_next_handle1 < adjusted_low_next_handle1)
			{
				// The high entry next handle has a lesser value than the low
				// entry next handle, so the high entry must be on the primary
				// list.  We remove it from the primary list and replace it
				// with the new entry.
				high_entry1->next_entry->prev_entry = new_entry1;
				high_entry1->prev_entry->next_entry = new_entry1;
				new_entry1->next_entry = high_entry1->next_entry;
				new_entry1->prev_entry = high_entry1->prev_entry;
			}
			else
			{
				// The low entry next handle has a lesser value than the high
				// entry next handle, so the low entry must be on the primary
				// list.  We remove it from the primary list and replace it
				// with the new entry.
				low_entry1->next_entry->prev_entry = new_entry1;
				low_entry1->prev_entry->next_entry = new_entry1;
				new_entry1->next_entry = low_entry1->next_entry;
				new_entry1->prev_entry = low_entry1->prev_entry;
			}
		}
		// Set the next handle for the new entry.
		new_entry1->next_handle = next_handle1;
		// When merging two entries, the next handle value for the combined
		// entry is equal to the larger next handle value of the two, minus
		// the new table size.  However, the determination of which is larger
		// must be made with respect to their logical acyclic values rather
		// than their actual cyclic values, so we subtract from each the value
		// of handle_base, modulo the size of the handle space.  The modulo is
		// implicit.
		adjusted_high_next_handle0 =
			high_entry0->next_handle - hfact->handle_base;
		adjusted_low_next_handle0 =
			low_entry0->next_handle - hfact->handle_base;
		next_handle0 = __max(adjusted_high_next_handle0,
			adjusted_low_next_handle0) + hfact->handle_base - half_size;
		if (next_handle0 == 0)
		{
			// The handle value has wrapped around back to zero; however, zero
			// is a reserved value, so we instead set the next handle to the
			// subsequent legal value, which is the new table size.
			next_handle0 = half_size;
		}
		if (high_entry0->handle != high_entry0->next_handle)
		{
			// The high entry is assigned, so we copy its handle value and
			// reference pointer.  Also, we remove it from the assigned list
			// and replace it with the new entry.
			new_entry0->handle = high_entry0->handle;
			new_entry0->reference = high_entry0->reference;
			high_entry0->next_entry->prev_entry = new_entry0;
			high_entry0->prev_entry->next_entry = new_entry0;
			new_entry0->next_entry = high_entry0->next_entry;
			new_entry0->prev_entry = high_entry0->prev_entry;
		}
		else if (low_entry0->handle != low_entry0->next_handle)
		{
			// The low entry is assigned, so we copy its handle value and
			// reference pointer.  Also, we remove it from the assigned list
			// and replace it with the new entry.
			new_entry0->handle = low_entry0->handle;
			new_entry0->reference = low_entry0->reference;
			low_entry0->next_entry->prev_entry = new_entry0;
			low_entry0->prev_entry->next_entry = new_entry0;
			new_entry0->next_entry = low_entry0->next_entry;
			new_entry0->prev_entry = low_entry0->prev_entry;
		}
		else
		{
			// Neither entry is assigned, so we indicate an unassigned condition
			// in the new entry.
			new_entry0->handle = next_handle0;
			new_entry0->reference = 0;
			if (adjusted_high_next_handle0 < adjusted_low_next_handle0)
			{
				// The high entry next handle has a lesser value than the low
				// entry next handle, so the high entry must be on the primary
				// list.  We remove it from the primary list and replace it
				// with the new entry.
				high_entry0->next_entry->prev_entry = new_entry0;
				high_entry0->prev_entry->next_entry = new_entry0;
				new_entry0->next_entry = high_entry0->next_entry;
				new_entry0->prev_entry = high_entry0->prev_entry;
			}
			else
			{
				// The low entry next handle has a lesser value than the high
				// entry next handle, so the low entry must be on the primary
				// list.  We remove it from the primary list and replace it
				// with the new entry.
				low_entry0->next_entry->prev_entry = new_entry0;
				low_entry0->prev_entry->next_entry = new_entry0;
				new_entry0->next_entry = low_entry0->next_entry;
				new_entry0->prev_entry = low_entry0->prev_entry;
			}
		}
		// Set the next handle for the new entry.
		new_entry0->next_handle = next_handle0;
		// Now that we have merged high_entry1 and low_entry1 into new_entry1,
		// and independently merged high_entry0 and low_entry0 into new_entry0,
		// we examine the two new entries to determine on which list to place
		// each of them.  Note that we do not actually manipulate the lists in
		// this portion of the code; we merely make decisions and record these
		// decisions for the future.
		if (new_entry0->handle == new_entry0->next_handle &&
			new_entry1->handle == new_entry1->next_handle)
		{
			// Both new_entry0 and new_entry1 are unassigned, so one of them
			// belongs on the primary list and the other on the secondary list.
			// Which goes on which is determined by a comparison of their handle
			// values.  We're being tricky with unsigned integer math here.
			// Before comparing the two handles, we subtract from each the value
			// of handle_base, modulo the size of the handle space (the modulo
			// is implicit).  This allows the effective comparison of their
			// logical acyclic values rather than their actual cyclic values.
			adjusted_new_handle0 = new_entry0->handle - hfact->handle_base;
			adjusted_new_handle1 = new_entry1->handle - hfact->handle_base;
			if (adjusted_new_handle0 < adjusted_new_handle1)
			{
				// The handle value for new_entry0 is lower, so new_entry0
				// belongs on the primary list and new_entry1 on the secondary
				// list.  We indicate this decision in the list array.
				list[index] = LD_PRIMARY;
				list[quarter_size + index] = LD_SECONDARY;
			}
			else
			{
				// The handle value for new_entry1 is lower, so new_entry1
				// belongs on the primary list and new_entry0 on the secondary
				// list.  We indicate this decision in the list array.
				list[index] = LD_SECONDARY;
				list[quarter_size + index] = LD_PRIMARY;
			}
		}
		else
		{
			// Either new_entry0 or new_entry1 (or both) is assigned, and it is
			// therefore already on the assigned list.  If one of the entries
			// is not assigned, it belongs on the secondary list.  We indicate
			// this decision in both places of the list array, which is safe to
			// do since the assigned entry's list indicator will never be
			// examined.
			list[index] = LD_SECONDARY;
			list[quarter_size + index] = LD_SECONDARY;
		}
		if (new_entry0->handle != new_entry0->next_handle &&
			new_entry1->handle != new_entry1->next_handle)
		{
			// Both new_entry0 and new_entry1 are assigned, so they form a pair.
			// We thus increment the pair count.  Note that we never set the
			// pair count to zero above, but this was not necessary since the
			// table could not be contracted unless the pair count was zero.
			hfact->pair_count++;
		}
	}
	// At this point, the table has been completely contracted except for the
	// reassembly of the unassigned lists.  In the code above, any entries that
	// had previously been on the secondary list were merged with assigned
	// entries, so they are no longer relevant.  Only those entries that had
	// previously been (and are still) on the primary list will still be
	// unassigned.  We now loop through the primary list and place each list
	// element on the appropriate list, as indicated by the list array.  Doing
	// the list assignment in these two steps preserves the general order of
	// the entries, which has some value since they will tend to be partially
	// sorted.
	entry = hfact->entry_list[LD_PRIMARY].next_entry;
	primary_entry = &hfact->entry_list[LD_PRIMARY];
	secondary_entry = &hfact->entry_list[LD_SECONDARY];
	while (entry != &hfact->entry_list[LD_PRIMARY])
	{
		if (list[entry->handle & half_size - 1] == LD_PRIMARY)
		{
			// The list array indicates the primary list, so place the entry
			// onto the primary list.
			primary_entry->next_entry = entry;
			entry->prev_entry = primary_entry;
			primary_entry = entry;
		}
		else
		{
			// The list array indicates the secondary list, so place the entry
			// onto the secondary list.
			secondary_entry->next_entry = entry;
			entry->prev_entry = secondary_entry;
			secondary_entry = entry;
		}
		entry = entry->next_entry;
	}
	// Wrap up lists by connecting in tails.
	primary_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
	hfact->entry_list[LD_PRIMARY].prev_entry = primary_entry;
	secondary_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
	hfact->entry_list[LD_SECONDARY].prev_entry = secondary_entry;
	// This contraction increases the hysteresis debt by the cost of one set of
	// allocation and deallocation operations plus the cost of merging each
	// pair of entries into a single entry.
	hfact->hysteresis_debt += ALLOCATION_COST + half_size;
	// Save a pointer to the old entry table so that it can be deallocated.
	old_entries = hfact->entries;
	// Note that we have not modified the handle, next_handle, or reference
	// fields of any entries in the old table.  Therefore, any calls to the
	// dereference_HF_handle() routine that may have been made by other threads
	// during the above operations would have been performed successfully.
	// We are now about to decrease the table size and update the entries
	// variable to point to the new table.  These operations must be performed
	// atomically in order for the dereference routine to perform correctly.
	// We thus bracket the operations with increments to the verifier variables.
	// When the verifiers have the same value, the table_size and entries
	// variables are in a consistent state.  This is checked by the dereference
	// routine.
	hfact->verifier0++;                                // begin critical section
	hfact->table_size = half_size;
	hfact->entries = new_entries;
	hfact->verifier1 = hfact->verifier0;                 // end critical section
	
    // Deallocate the old table and the auxiliary list indicator array.
	GpcFreeMem(old_entries, handleFactoryTag);
	GpcFreeMem(list, handleFactoryTag);
	// return an indication of success.
	return 0;
}

// This function revokes handles that are between handle_base and handle_base
// + 2 * HANDLE_RANGE_STEP - 1, inclusive.  It then increments the value of
// handle_base by HANDLE_RANGE_STEP.  Suspended handles will be revoked one
// revokation pass later than non-suspended handles.
//
void revoke_ancient_HF_handles(
	HandleFactory *hfact)
{
	HFHandle new_handle_base;
	int half_size;
	int index;
	HFEntry *high_entry;
	HFEntry *low_entry;
	HFHandle adjusted_high_handle;
	HFHandle adjusted_low_handle;
	HFHandle adjusted_high_next_handle;
	HFHandle adjusted_low_next_handle;
	HFHandle handle;
	volatile HFEntry *seq_entry;                // volatile to ensure sequencing

	// Compute new handle base.
	new_handle_base = hfact->handle_base + HANDLE_RANGE_STEP;
	// It might seem reasonable to loop through each index of the table and
	// determine whether to revoke the handle of each entry.  This is in fact
	// what the following routine does; however, it does it by looping through
	// only half of the indices and examining two entries for each index.  It
	// does this so that it can compare the two entries to determine on which
	// list to place each of them.
	half_size = hfact->table_size / 2;
	for (index = 0; index < half_size; index++)
	{
		// We're looking at two entries at once.
		high_entry = &hfact->entries[half_size + index];
		low_entry = &hfact->entries[index];
		// We're being tricky with unsigned integer math here.  Before making
		// comparisons on either handle, we subtract from it the value of
		// handle_base, modulo the size of the handle space (the modulo is
		// implicit).  This allows the effective comparison of its logical
		// acyclic value rather than its actual cyclic value.
		adjusted_high_handle = high_entry->handle - hfact->handle_base;
		adjusted_low_handle = low_entry->handle - hfact->handle_base;
		if (adjusted_high_handle < 2 * HANDLE_RANGE_STEP ||
			adjusted_low_handle < 2 * HANDLE_RANGE_STEP)
		{
			// At least one of the handles is less than twice HANDLE_RANGE_STEP
			// more than the current handle base, so it will need to be updated.
			// For the vast majority of cases, this test is expected to fail,
			// and so all of the following work can be skipped.
			if (high_entry->handle != high_entry->next_handle &&
				low_entry->handle != low_entry->next_handle)
			{
				// Both of the entries are assigned, so, since at least one of
				// them will be revoked, we will be losing one pair.
				hfact->pair_count--;
			}
			if (high_entry->handle == high_entry->next_handle ||
				adjusted_high_handle < 2 * HANDLE_RANGE_STEP)
			{
				// Either the high entry is unassigned or in need of revokation
				// (after which it will be unassigned), so we remove it from
				// whatever list it is on.  We do this because all unassigned
				// entries will be added to the appropriate list below.
				high_entry->next_entry->prev_entry = high_entry->prev_entry;
				high_entry->prev_entry->next_entry = high_entry->next_entry;
				// Zeroing these pointers is unnecessary, but it will help to
				// catch any mistakes made further down.
				high_entry->next_entry = 0;
				high_entry->prev_entry = 0;
			}
			if (adjusted_high_handle < 2 * HANDLE_RANGE_STEP)
			{
				// The high handle needs to be updated.
				if (high_entry->handle != high_entry->next_handle)
				{
					// The high handle is assigned, so this updating will
					// revoke the handle.  Thus, we decrement the population.
					hfact->population--;
				}
				// Compute the handle value as the maximum of (1) the next
				// handle and (2) the new handle base plus the entry index.
				// We're being tricky with unsigned integer math here.  The
				// maximum involves partial decomposition of the sums, from
				// which we then subtract the value of handle_base, modulo the
				// size of the handle space (the modulo is implicit).  Thus,
				// the maximum is taken with respect to the logical acyclic
				// values rather than the actual cyclic values.
				adjusted_high_next_handle =
					high_entry->next_handle - hfact->handle_base;
				handle = __max(adjusted_high_next_handle,
					HANDLE_RANGE_STEP + half_size + index) + hfact->handle_base;
				// Since the high handle is -- by definition -- in the upper
				// half of the table, there is no need to check for the reserved
				// value of zero.
				// Update the handle value.  Since this updating will invalidate
				// the handle if it is currently assigned, the order of the
				// operations is important to correct multi-threaded operation.
				seq_entry = high_entry;
				seq_entry->next_handle = handle;
				seq_entry->handle = handle;           // first invalidate handle
				seq_entry->reference = 0;                // then clear reference
			}
			if (low_entry->handle == low_entry->next_handle ||
				adjusted_low_handle < 2 * HANDLE_RANGE_STEP)
			{
				// Either the low entry is unassigned or in need of revokation
				// (after which it will be unassigned), so we remove it from
				// whatever list it is on.  We do this because all unassigned
				// entries will be added to the appropriate list below.
				low_entry->next_entry->prev_entry = low_entry->prev_entry;
				low_entry->prev_entry->next_entry = low_entry->next_entry;
				// Zeroing these pointers is unnecessary, but it will help to
				// catch any mistakes made further down.
				low_entry->next_entry = 0;
				low_entry->prev_entry = 0;
			}
			if (adjusted_low_handle < 2 * HANDLE_RANGE_STEP)
			{
				// The low handle needs to be updated.
				if (low_entry->handle != low_entry->next_handle)
				{
					// The low handle is assigned, so this updating will
					// revoke the handle.  Thus, we decrement the population.
					hfact->population--;
				}
				// Compute the handle value as the maximum of (1) the next
				// handle and (2) the new handle base plus the entry index.
				// We're being tricky with unsigned integer math here.  The
				// maximum involves partial decomposition of the sums, from
				// which we then subtract the value of handle_base, modulo the
				// size of the handle space (the modulo is implicit).  Thus,
				// the maximum is taken with respect to the logical acyclic
				// values rather than the actual cyclic values.
				adjusted_low_next_handle =
					low_entry->next_handle - hfact->handle_base;
				handle = __max(adjusted_low_next_handle,
					HANDLE_RANGE_STEP + index) + hfact->handle_base;
				if (handle == 0)
				{
					// The handle value has wrapped around back to zero;
					// however, zero is a reserved value, so we instead set the
					// handle to the subsequent legal value, which is the table
					// size.
					handle = hfact->table_size;
				}
				// Update the handle value.  Since this updating will invalidate
				// the handle if it is currently assigned, the order of the
				// operations is important to correct multi-threaded operation.
				seq_entry = low_entry;
				seq_entry->next_handle = handle;
				seq_entry->handle = handle;           // first invalidate handle
				seq_entry->reference = 0;                // then clear reference
			}
			if (high_entry->handle != high_entry->next_handle)
			{
				// The high entry is still assigned, so the low entry belongs
				// on the secondary list.
				low_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
				low_entry->prev_entry =
					hfact->entry_list[LD_SECONDARY].prev_entry;
				hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
					low_entry;
				hfact->entry_list[LD_SECONDARY].prev_entry = low_entry;
			}
			else if (low_entry->handle != low_entry->next_handle)
			{
				// The low entry is still assigned, so the high entry belongs
				// on the secondary list.
				high_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
				high_entry->prev_entry =
					hfact->entry_list[LD_SECONDARY].prev_entry;
				hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
					high_entry;
				hfact->entry_list[LD_SECONDARY].prev_entry = high_entry;
			}
			else
			{
				// Neither entry is still assigned, so one entry belongs on the
				// primary list and one on the secondary list.  Which goes on
				// which is determined by a comparison of their handle values.
				// We're being tricky with unsigned integer math here.  Before
				// comparing the two handles, we subtract from each the value
				// of handle_base, modulo the size of the handle space (the
				// modulo is implicit).  This allows the effective comparison
				// of their logical acyclic values rather than their actual
				// cyclic values.
				adjusted_high_next_handle =
					high_entry->next_handle - new_handle_base;
				adjusted_low_next_handle =
					low_entry->next_handle - new_handle_base;
				if (adjusted_low_next_handle < adjusted_high_next_handle)
				{
					// The handle value for the low entry is smaller, so it
					// belongs on the primary list and the high entry on the
					// secondary list.
					high_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
					high_entry->prev_entry =
						hfact->entry_list[LD_SECONDARY].prev_entry;
					hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
						high_entry;
					hfact->entry_list[LD_SECONDARY].prev_entry = high_entry;
					low_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
					low_entry->prev_entry =
						hfact->entry_list[LD_PRIMARY].prev_entry;
					hfact->entry_list[LD_PRIMARY].prev_entry->next_entry =
						low_entry;
					hfact->entry_list[LD_PRIMARY].prev_entry = low_entry;
				}
				else
				{
					// The handle value for the high entry is smaller, so it
					// belongs on the primary list and the low entry on the
					// secondary list.
					high_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
					high_entry->prev_entry =
						hfact->entry_list[LD_PRIMARY].prev_entry;
					hfact->entry_list[LD_PRIMARY].prev_entry->next_entry =
						high_entry;
					hfact->entry_list[LD_PRIMARY].prev_entry = high_entry;
					low_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
					low_entry->prev_entry =
						hfact->entry_list[LD_SECONDARY].prev_entry;
					hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
						low_entry;
					hfact->entry_list[LD_SECONDARY].prev_entry = low_entry;
				}
			}
		}
	}
	// Update the handle base with the new handle base.
	hfact->handle_base = new_handle_base;
	// To contract the table, there must be no pairs, because otherwise two
	// assigned handles would yield the same entry index and thereby conflict.
	// Furthermore, the table size must be greater than 2, because much of the
	// handle factory code assumes that the table is at least of size 2.  In
	// addition to these strict requirements, hysteresis is employed both to
	// keep the mean assignment and release times constant and to minimize the
	// allocation chatter of rapidly expanding and contracting the table.  Only
	// if the hysteresis debt is zero will the table be contracted.
	if (hfact->pair_count == 0 && hfact->table_size > 2 &&
		hfact->hysteresis_debt == 0)
	{
		contract_HF_table(hfact);
		// Note that we ignore the return code.  If the contraction is
		// unsuccessful, we just continue as usual.  There is no real harm in
		// not contracting the table, except that we consume more space than
		// necessary.
	}
}