Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1063 lines
28 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
buffdesc.c
Abstract:
Routines for allocating, managing and freeing buffer descriptors.
Author:
Garth Conboy Initial Coding
Nikhil Kamkolkar Rewritten for microsoft coding style. mpized
Revision History:
GC - (04/05/92): When using "on board" data, make sure the real "in
use" portion is at the END of the "on board" chunk!
GC - (06/24/92): Lotsa changes; fully documented in BuffDesc.h. The
two main additions are that a BufferDescriptor chunk
may now contain BOTH on-board and out-board data, and
the out-board buffer may now be "opaque" (some system
dependend format that we don't understand) rather
than simply a "char *" buffer.
--*/
#define IncludeBuffDescErrors 1
#include "atalk.h"
#define VerboseMesages 0
#define DebugCode 0
#if Verbose or (Iam a Primos)
static long totalChunksAllocated;
static long totalChunksFreed;
#endif
ExternForVisibleFunction BufferDescriptor FindFreeDescriptor(long size);
//
// Allocate and attach a new header to an existing buffer chain. The data
// will be marked as free-able.
//
BufferDescriptor far AllocateHeader(BufferDescriptor chain,
long size)
{
BufferDescriptor newDescriptor;
//
// Check for the various cases that we can add (prepend) to the first
// chunk in the passed chain.
//
if (chain isnt Empty) {
// Handle the "prependInPlace" case. See comments in "buffdesc.h".
if (chain->outBoardDataValid and chain->prependInPlace) {
if (chain->freeData or chain->opaqueData)
{
//
// The prependInPlace bit should never be set in a case that we've
// allocated the buffer (we don't reserve any space preceding the
// buffer for a "real prepend") or when we're just describing some
// sort of opaque thing.
//
ErrorLog("AllocateHeader", ISevError, __LINE__, UnknownPort,
IErrBuffDescBadRealPrepend, IMsgBuffDescBadRealPrepend,
Insert0());
FreeBufferChain(chain);
return(Empty);
}
//
// Just modify the out-board existing chunk; "back up" the requested
// amount.
//
chain->outBoardBuffer -= size;
chain->outBoardData = chain->outBoardBuffer;
chain->outBoardSize += size;
chain->outBoardAllocatedSize += size;
chain->data = chain->outBoardData;
return(chain);
}
//
// Is there room preceeding the "in-use" portion of the existing out-board
// buffer? Note that we can only do this if only the out-board chunk
// is in use (i.e. doesn't already have an on-board header prepended).
//
if (chain->outBoardDataValid and not chain->onBoardDataValid and
(chain->outBoardAllocatedSize - chain->outBoardSize) >= size) {
chain->outBoardData -= size;
chain->outBoardSize += size;
chain->data = chain->outBoardData;
return(chain);
}
//
// Can we use the on-board space? First check the case that the on-board
// buffer space has not be used at all yet (not valid yet).
//
if (not chain->onBoardDataValid and size <= MaxOnBoardBytes) {
chain->onBoardDataValid = True;
chain->onBoardData = chain->onBoardBuffer + (MaxOnBoardBytes - size);
chain->onBoardSize = size;
chain->data = chain->onBoardData;
return(chain);
}
//
// Now check the case that the on-board buffer space is in use, but
// has sufficient space available for a new on-board header.
//
if (chain->onBoardDataValid and
(MaxOnBoardBytes - chain->onBoardSize) >= size) {
chain->onBoardData -= size;
chain->onBoardSize += size;
chain->data = chain->onBoardData;
return(chain);
}
}
//
// Try to find a free buffer descriptor, otherwise, allocate one. If
// both fail, run away. Don't bother logging an error... our caller needs
// to check for this (and can give a more exacting error message).
//
if ((newDescriptor = FindFreeDescriptor(size)) is Empty)
newDescriptor = (BufferDescriptor)Calloc(sizeof(*newDescriptor), 1);
if (newDescriptor is Empty) {
FreeBufferChain(chain);
return(Empty);
}
//
// If we've gotten a lone descriptor, we either need to allocate an out-
// board buffer or we can use the "on board" space.
//
if (not newDescriptor->outBoardDataValid) {
if (size <= MaxOnBoardBytes)
{
newDescriptor->onBoardDataValid = True;
newDescriptor->onBoardData =
newDescriptor->onBoardBuffer + (MaxOnBoardBytes - size);
newDescriptor->onBoardSize = size;
newDescriptor->data = newDescriptor->onBoardData;
}
else {
if ((newDescriptor->outBoardBuffer = (char far *)Malloc(size)) is Empty)
{
FreeBufferChain(newDescriptor);
FreeBufferChain(chain);
return(Empty);
}
newDescriptor->freeData = True;
newDescriptor->outBoardDataValid = True;
newDescriptor->outBoardData = newDescriptor->outBoardBuffer;
newDescriptor->outBoardSize =
newDescriptor->outBoardAllocatedSize = size;
newDescriptor->data = newDescriptor->outBoardData;
}
}
else {
//
// Okay, we've gotten a descriptor complete with an existing out-board
// buffer, use the tail end of it.
//
newDescriptor->outBoardData = newDescriptor->outBoardBuffer +
(newDescriptor->outBoardAllocatedSize - size);
newDescriptor->outBoardSize = size;
newDescriptor->data = newDescriptor->outBoardData;
}
#if Verbose or (Iam a Primos)
totalChunksAllocated += 1;
#endif
//
// Okay, we have a buffer descriptor that passes the tests, prepend it
// to the existing chain, and return it.
//
newDescriptor->next = chain;
return(newDescriptor);
} // AllocateHeader
//
// Attach an existing chunk of data to an exisitng buffer chain. The data
// will be marked as non-free-able.
//
BufferDescriptor far AttachHeader(BufferDescriptor chain,
long size,
char far *data,
Boolean opaqueData)
{
BufferDescriptor newDescriptor;
//
// Try to find a free lone descriptor, otherwise allocate one, if both fail
// return empty handed.
//
if ((newDescriptor = FindFreeDescriptor(0)) is Empty)
newDescriptor = (BufferDescriptor)Calloc(sizeof(*newDescriptor), 1);
if (newDescriptor is Empty) {
FreeBufferChain(chain);
return(Empty);
}
// Attach the passed data, and set the size.
newDescriptor->outBoardDataValid = True;
newDescriptor->outBoardData = newDescriptor->outBoardBuffer = data;
newDescriptor->outBoardSize = newDescriptor->outBoardAllocatedSize = size;
newDescriptor->freeData = False;
newDescriptor->opaqueData = opaqueData;
newDescriptor->data = newDescriptor->outBoardData;
#if Verbose or (Iam a Primos)
totalChunksAllocated += 1;
#endif
// Prepend to passed chain and return the new head.
newDescriptor->next = chain;
return(newDescriptor);
} // AttachHeader
// Compute the actual, in use, data size of a buffer chain (bytes).
extern long far SizeOfBufferChain(BufferDescriptor chain)
{
long size = 0;
for ( ; chain isnt Empty; chain = chain->next)
size += (chain->outBoardSize + chain->onBoardSize);
return(size);
} // SizeOfBufferChain
//
// Given a multi-chunk buffer chain, coalesce it into a single chunk
// chain and free the original.
//
extern BufferDescriptor far CoalesceBufferChain(BufferDescriptor chain)
{
BufferDescriptor coalesced;
coalesced = CopyBufferChain(chain);
FreeBufferChain(chain);
return(coalesced);
} // CoalesceBufferChain
//
// Create a copy of a buffer descriptor (basically the same as
// CoalesceBufferChain, but don't free the orignal).
//
extern BufferDescriptor far CopyBufferChain(BufferDescriptor chain)
{
BufferDescriptor copy, chunk;
char far *data;
#if 0
extern void DumpBufferDescriptorInfo(void);
DumpBufferDescriptorInfo();
#endif
// Allocate a new chunk large enough to hold the coalesced chain.
if ((copy = NewBufferDescriptor(SizeOfBufferChain(chain))) is Empty) {
FreeBufferChain(chain);
return(Empty);
}
// Walk the chain, copying the data into the new single chunk.
for (data = copy->data, chunk = chain;
chunk isnt Empty;
chunk = chunk->next) {
if (chunk->onBoardDataValid)
{
MoveMem(data, chunk->onBoardData, chunk->onBoardSize);
data += chunk->onBoardSize;
}
if (chunk->outBoardDataValid) {
MoveOutBoardData(data, chunk, (long)0, chunk->outBoardSize);
data += chunk->outBoardSize;
}
}
// All set.
return(copy);
} // CopyBufferChain
// Free a buffer chain and its assocciated free-able data.
void far FreeBufferChain(BufferDescriptor chain)
{
BufferDescriptor next;
// Walk the chain either freeing or adding to the free list.
for ( ; chain isnt Empty; chain = next) {
next = chain->next;
//
// Logically "free" the on-board data. Make things look a little
// cleaner than they really need to be.
//
chain->onBoardDataValid = False;
chain->onBoardSize = 0;
chain->onBoardData = Empty;
chain->data = Empty;
chain->transmitCompleteHandler = Empty;
//
// If we have data to free (that's larger than we can keep) free it
// and convert the descriptor to lone one. If we're not freeing (or
// keeping) the data, make a lone descriptor.
//
if (chain->outBoardDataValid) {
//
// Note that the following if/else will leave outBoardDataValid and
// freeData either both True or both False.
//
if (chain->freeData and
chain->outBoardAllocatedSize > MaxKeptBufferBytes) {
Free(chain->outBoardBuffer);
chain->outBoardDataValid = False;
chain->freeData = False;
}
else if (not chain->freeData)
chain->outBoardDataValid = False;
if (chain->freeOpaqueDataDescriptor)
FreeOpaqueDataDescriptor(chain->outBoardBuffer);
// Clean up.
if (not chain->outBoardDataValid) {
// Not saving any out-board data.
chain->outBoardBuffer = Empty;
chain->outBoardAllocatedSize = 0;
}
chain->outBoardSize = 0;
chain->outBoardData = Empty;
chain->opaqueData = False;
chain->prependInPlace = False;
chain->freeOpaqueDataDescriptor = False;
}
//
// If we can keep another descriptor on our free list, add it. Otherwise,
// free any data and the descriptor too.
//
EnterCriticalSection();
if (freeBufferDescriptorCount < MaxFreeBufferDescriptors) {
chain->next = freeBufferDescriptorList;
freeBufferDescriptorList = chain;
freeBufferDescriptorCount += 1;
LeaveCriticalSection();
}
else {
LeaveCriticalSection();
if (chain->outBoardDataValid and chain->freeData)
Free(chain->outBoardBuffer);
Free(chain);
#if VerboseMessages
ErrorLog("FreeBufferChain", ISevError, __LINE__, UnknownPort,
IErrBuffDescFreeingDescriptor, IMsgBuffDescFreeingDescriptor,
Insert0());
#endif
}
#if Verbose or (Iam a Primos)
totalChunksFreed += 1;
#endif
}
} // FreeBufferChain
//
// Compute the Ddp checksum of a buffer chain.
//
// NOTE BENE: It is BIG performance win to recode this routine in assembly
// unless the target environment has a VERY good optimizing
// compiler.
//
// The leadingBytesToSkip is assumed to be within ONE header
// (either on-board or out-board data).
//
//
short unsigned far DdpChecksumBufferChain(BufferDescriptor chain,
long actualLength,
long leadingBytesToSkip)
{
short unsigned checksum = 0;
long bytesProcessed = leadingBytesToSkip;
long index;
char c;
//
// This checksum algorithum is from Inside AppleTalk page IV-5; designed,
// no doubt, to be slow on any 32-bit machine. Sigh.
//
for ( ;
chain isnt Empty and bytesProcessed < actualLength;
chain = chain->next) {
// First do any on-board data in this chunk.
if (chain->onBoardDataValid) {
for (index = leadingBytesToSkip;
index < chain->onBoardSize and bytesProcessed < actualLength;
index += 1, bytesProcessed += 1) {
checksum += (unsigned char)chain->onBoardData[index];
if (checksum & 0x8000) // 16-bit rotate left one bit... {
checksum <<= 1;
checksum += 1;
}
else
checksum <<= 1;
}
leadingBytesToSkip = 0;
}
// Then do any out-board data in this chunk.
if (chain->outBoardDataValid) {
for (index = leadingBytesToSkip;
index < chain->outBoardSize and bytesProcessed < actualLength;
index += 1, bytesProcessed += 1) {
if (not chain->opaqueData)
checksum += (unsigned char)chain->outBoardData[index];
else {
//
// !!!!! This will perform horrendously slowly and
// should be optimized in some system dependent
// way.
// !!!!!
//
MoveFromOpaque(&c, chain->outBoardData, index, 1);
checksum += (unsigned char)c;
}
if (checksum & 0x8000) // 16-bit rotate left one bit... {
checksum <<= 1;
checksum += 1;
}
else
checksum <<= 1;
}
leadingBytesToSkip = 0;
}
}
if (checksum is 0)
checksum = 0xFFFF;
return(checksum);
} // DdpChecksumBufferChain
//
// Given a buffer descriptor, adjust the most recent header to reflect new
// "in use" pointers and sizes. A negative adjustment cause less data to
// be considered "in use," a positive adjustment causes more data to be
// considered "in use." A negative adjustment must be no larger than the
// size of the previous "AllocateHeader." Positive adjustments must be
// preceeded by negative adjustments and may not be larger than the sum of
// previous negative adjustments. What this means is this routine may only
// be used to "move around" in the most recently allocated header and may
// not exceed its bounds. This routine will be used only on headers
// allocated by the stack -- we don't have to worry about opaque data.
//
void far AdjustBufferDescriptor(BufferDescriptor descriptor, long adjustment)
{
long maxSize, newSize;
// Validate requested adjustment.
if (descriptor->onBoardDataValid) {
maxSize = MaxOnBoardBytes;
newSize = descriptor->onBoardSize + adjustment;
}
else {
maxSize = descriptor->outBoardAllocatedSize;
newSize = descriptor->outBoardSize + adjustment;
// We can only do adjustments on headers we've allocated.
if (descriptor->opaqueData or not descriptor->freeData)
newSize = -1;
}
if (newSize < 0 or newSize > maxSize) {
ErrorLog("AdjustBufferDescriptor", ISevError, __LINE__, UnknownPort,
IErrBuffDescBadAdjustment, IMsgBuffDescBadAdjustment,
Insert0());
return;
}
// Okay, do the deed.
if (descriptor->onBoardDataValid) {
descriptor->onBoardSize = newSize;
descriptor->onBoardData -= adjustment;
descriptor->data = descriptor->onBoardData;
}
else {
descriptor->outBoardSize = newSize;
descriptor->outBoardData -= adjustment;
descriptor->data = descriptor->outBoardData;
}
return;
} // AdjustBufferDescriptor
//
// Given a buffer descriptor chain, create a new one describing a subset of
// the original. This routine generally does not copy any data, so the
// original buffer descriptor may not be freed before the subset descriptor
// is freed.
//
BufferDescriptor far SubsetBufferDescriptor(BufferDescriptor chain,
long offset, long size)
{
BufferDescriptor newDescriptor;
Boolean freeOpaqueDataDescriptor;
//
// For the "normal case" of subsetting a chain that has only one chunk
// and all of its data is out-board, just copy the descriptor and adjust
// the pointers.
//
if (chain->next is Empty and chain->outBoardDataValid and
not chain->onBoardDataValid) {
// Get a new lone descriptor.
if ((newDescriptor = FindFreeDescriptor(0)) is Empty)
newDescriptor = (BufferDescriptor)Calloc(sizeof(*newDescriptor), 1);
if (newDescriptor is Empty)
return(Empty);
// Set new values.
newDescriptor->outBoardDataValid = True;
newDescriptor->opaqueData = chain->opaqueData;
newDescriptor->freeData = False;
newDescriptor->outBoardAllocatedSize = size;
newDescriptor->outBoardSize = size;
// Make only the requested subset be described.
if (not chain->opaqueData)
newDescriptor->outBoardBuffer = chain->outBoardBuffer + offset;
else {
newDescriptor->outBoardBuffer =
SubsetOpaqueDataDescriptor(chain->outBoardBuffer, offset, size,
&freeOpaqueDataDescriptor);
chain->freeOpaqueDataDescriptor = freeOpaqueDataDescriptor;
}
newDescriptor->outBoardData = newDescriptor->outBoardBuffer;
newDescriptor->data = newDescriptor->outBoardData;
return(newDescriptor);
}
//
// Okay, now the slow case! Copy the descriptor and fudge the pointers!
// N.B. the copy will be a single chunk in one place, and won't have any
// opaque data.
//
if ((newDescriptor = CopyBufferChain(chain)) is Empty)
return(Empty);
if (newDescriptor->outBoardDataValid) {
newDescriptor->outBoardSize = size;
newDescriptor->outBoardData += offset;
newDescriptor->data = newDescriptor->outBoardData;
}
else {
newDescriptor->onBoardSize = size;
newDescriptor->onBoardData += offset;
newDescriptor->data = newDescriptor->onBoardData;
}
return(newDescriptor);
} // SubsetBufferDescriptor
//
// Move a specified amount of data from "out-board data" to a "char *"
// buffer. This routine handles both "char *" and "opaque" out-board
// data.
//
void far MoveOutBoardData(char far *target, BufferDescriptor chunk,
long offset, long size)
{
if (not chunk->opaqueData) {
MoveMem(target, chunk->outBoardData + offset, size);
return;
}
// Okay, handle (in a system specific mannor) opaque out-board data.
MoveFromOpaque(target, (void far *)chunk->outBoardData, offset, size);
return;
} // MoveOutBoardData
// Move opaque data to a "char *" buffer.
void far MoveFromOpaque(char far *target, void far *opaque,
long offset, long size)
{
#if Iam a WindowsNT
//
// Opaque data is a pointer to an MDL; copy "size" bytes from the
// MDL-described data to "target."
//
CopyDataFromMdlDescribedArea(target, opaque, offset, size);
#elif Iam a Primos
// Opaque is just "char *" here.
MoveMem(target, (char far *)opaque + offset, size);
#else
// Assume the simple case of opaque just being "char *."
MoveMem(target, (char far *)opaque + offset, size);
#endif
} // MoveFromOpaque
// Move a "char *" buffer to opaque data.
void far MoveToOpaque(void far *opaque, long offset, char far *buffer,
long size)
{
#if Iam a WindowsNT
//
// Opaque data is a pointer to an MDL; copy "size" bytes from the
// buffer to the MDL-described "target."
//
CopyDataToMdlDescribedArea(opaque, offset, buffer, size);
#elif Iam a Primos
// Opaque is just "char *" here.
MoveMem((char far *)opaque + offset, buffer, size);
#else
// Assume the simple case of opaque just being "char *."
MoveMem((char far *)opaque + offset, buffer, size);
#endif
} // MoveToOpaque
//
// Move an opaque buffer to an opaque buffer. Overlapping areas should
// work "correctly" this routine is used to "synch-up" Atp responses.
//
void far MoveOpaqueToOpaque(void far *targetOpaque, long targetOffset,
void far *sourceOpaque, long sourceOffset,
long size)
{
#if Iam a WindowsNT
//
// Opaque data is pointers to MDLs; copy "size" bytes. Be sure, also,
// that overlapping MDL-described area work "correctly."
//
MoveMdlAreaToMdlArea(targetOpaque, targetOffset, \
sourceOpaque, sourceOffset, size);
#elif Iam a Primos
// Opaques are just "char *"s here.
CarefulMoveMem((char far *)targetOpaque + targetOffset,
(char far *)sourceOpaque + sourceOffset, size);
#else
// Assume the simple case of opaques being just "char *"s here.
CarefulMoveMem((char far *)targetOpaque + targetOffset,
(char far *)sourceOpaque + sourceOffset, size);
#endif
} // MoveOpaqueToOpaque
// The "strlen()" function for opaque data.
size_t far StrlenOpaque(void far *opaque, long offset)
{
#if Iam a WindowsNT
//
// Opaque data is a pointer to an MDL; compute a "strlen()" at the
// specified offset into the MDL-described target.
//
return((size_t)StrlenMdlDescribedArea(opaque, offset));
#elif Iam a Primos
//
// Opaque is just "char *" here. The cast to "size_t" here is to avoid
// a Prime CI compiler "loss of precision warning"... the intrinsic
// version of "strlen()" is typed to return "long" rather than "long
// unsigned"... technically a bug... but, I neither think it's serious
// enough, nor do I have enough time, to fix it right now!
//
return((size_t)strlen((char far *)opaque + offset));
#else
// Assume the simple case of opaque just being "char *."
return(strlen((char far *)opaque + offset));
#endif
} // StrlenOpaque
//
// Make an opaque data descriptor for a specified "char *" buffer. The
// last argument is returned as True if the returned descriptor is a "real
// thing" that must be freed when we're done with it (this refers to the
// descriptor, not the described data).
//
// We return Empty if the requested opaque descriptor could not be created;
// if Empty is returned, DONT set freeOpaqueDataDescriptor to True.
//
void far *MakeOpaqueDataDescriptor(char far *buffer, long size,
Boolean far *freeOpaqueDataDescriptor)
{
//
// Any of the conditional compilation sections in the routine that set
// "*freeOpaqueDataDescriptor" to True will need corresponding sections
// in FreeOpaqueDataDescriptor().
//
#if Iam a WindowsNT
//
// Opaque data is pointer to an MDL; we need to create an MDL for
// the buffer, so we'll need to free it later.
//
void *newMdl;
*freeOpaqueDataDescriptor = True;
newMdl = MakeAnMdl(buffer, size);
return(newMdl);
#elif Iam a Primos
// Here the opaque guys are really just "char *"s.
*freeOpaqueDataDescriptor = False;
return((void *)buffer);
#else
// Assume simple "char *" opaques.
*freeOpaqueDataDescriptor = False;
return((void *)buffer);
#endif
} // MakeOpaqueDataDescriptor
//
// Given an opaque data descriptor, create a new opaque data descriptor that
// describes a subset of the original -- leave the original unmodified. The
// last argument is returned as True if the returned descriptor is a "real
// thing" that must be freed when we're done with it (this refers to the
// descriptor, not the described data).
//
// We return Empty if the requested opaque descriptor could not be created;
// if Empty is returned, DONT set freeOpaqueDataDescriptor to True.
//
void far *far SubsetOpaqueDataDescriptor(void far *master,
long offset,
long size,
Boolean far
*freeOpaqueDataDescriptor)
{
//
// Any of the conditional compilation sections in the routine that set
// "*freeOpaqueDataDescriptor" to True will need corresponding sections
// in FreeOpaqueDataDescriptor().
//
#if Iam a WindowsNT
//
// Opaque data is pointer to an MDL; we will need to create a new
// MDL to do this operation, so we'll need to free it later.
//
void *newMdl;
*freeOpaqueDataDescriptor = True;
newMdl = SubsetAnMdl(master, offset, size);
return(newMdl);
#elif Iam a Primos
// Here the opaque guys are really just "char *"s.
*freeOpaqueDataDescriptor = False;
return((void *)((char *)master + offset));
#else
// Assume simple "char *" opaques.
*freeOpaqueDataDescriptor = False;
return((void *)((char *)master + offset));
#endif
} // SubsetOpaqueDataDescriptor
//
// Free and opaque data descriptor; this frees the descriptor NOT the data.
// This routine will be used to free descriptors that were created by the
// stack when "subsetting" passed opaque data descriptors.
//
void far FreeOpaqueDataDescriptor(void far *descriptor)
{
#if Iam a WindowsNT
// Free the pointed-to MDL (not the described data).
FreeAnMdl(descriptor);
#endif
} // FreeOpaqueDataDescriptor
ExternForVisibleFunction BufferDescriptor FindFreeDescriptor(long size)
{
BufferDescriptor bufferDescriptor;
BufferDescriptor previousBufferDescriptor = Empty;
BufferDescriptor loneDescriptor = Empty;
BufferDescriptor previousLoneDescriptor = Empty;
//
// If we're looking for a data block bigger than we would have kept, just
// look for a lone descriptor (without data). Also if we're looking for
// a data block that could fit "on board" the descriptor, just look for
// a lone descriptor.
//
if (size > MaxKeptBufferBytes)
size = 0;
else if (size <= MaxOnBoardBytes)
size = 0;
// Walk the free list, looking for a match.
EnterCriticalSection();
for (bufferDescriptor = freeBufferDescriptorList;
bufferDescriptor isnt Empty;
previousBufferDescriptor = bufferDescriptor,
bufferDescriptor = bufferDescriptor->next)
if (not bufferDescriptor->outBoardDataValid) {
//
// A lone descriptor, use it if that's what we're looking for,
// otherwise, note that we have one that we can fall back on,
// if we don't find a better match.
//
if (size is 0)
break;
loneDescriptor = bufferDescriptor;
previousLoneDescriptor = previousBufferDescriptor;
}
else if (bufferDescriptor->outBoardDataValid and
bufferDescriptor->outBoardAllocatedSize >= size and
size isnt 0)
break; // A descriptor, with data, that can hold our request!
//
// If bufferDescriptor isnt Empty, we've either were looking for a lone
// descriptor and found one, or we were looking for a descriptor with data
// and we found one with enough room for our request. Otherwise, if we've
// found a lone descriptor, it's better than nothing for our caller (he
// can allocate a data block), so return it. Unlink the chunk from the
// list and return it.
//
if (bufferDescriptor is Empty and loneDescriptor isnt Empty) {
bufferDescriptor = loneDescriptor;
previousBufferDescriptor = previousLoneDescriptor;
}
if (bufferDescriptor isnt Empty) {
if (previousBufferDescriptor is Empty)
freeBufferDescriptorList = bufferDescriptor->next;
else
previousBufferDescriptor->next = bufferDescriptor->next;
if ((freeBufferDescriptorCount -= 1) < 0) {
LeaveCriticalSection();
ErrorLog("FindFreeDescriptor", ISevError, __LINE__, UnknownPort,
IErrBuffDescBadFreeCount, IMsgBuffDescBadFreeCount,
Insert0());
bufferDescriptor->next = Empty;
return(bufferDescriptor);
}
LeaveCriticalSection();
bufferDescriptor->next = Empty;
return(bufferDescriptor);
}
// Oh well, nobody home, return empty handed.
LeaveCriticalSection();
return(Empty);
} // FindFreeDescriptor
#if Verbose or (Iam a Primos)
void DumpBufferDescriptorInfo(void) {
BufferDescriptor chunk;
int freeCount = 0;
for (chunk = freeBufferDescriptorList;
chunk isnt Empty;
chunk = chunk->next)
freeCount += 1;
printf("\n");
printf("Total chunks allocated = %d.\n", totalChunksAllocated);
printf("Total chunks freed = %d.\n", totalChunksFreed);
printf("Current chunks in use = %d.\n", totalChunksAllocated -
totalChunksFreed);
printf("Total chunks on free list = %d (%d).\n", freeBufferDescriptorCount,
freeCount);
printf("\n");
} // DumpBufferDescriptorInfo
#endif