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.
 
 
 
 
 
 

1037 lines
32 KiB

/* buffdesc.c, /atalk-ii/source, Garth Conboy, 03/30/92 */
/* Copyright (c) 1992 by Pacer Software Inc., La Jolla, CA */
/* GC - Initial coding.
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.
GC - (12/04/92): Some changes to ease future Xyplex ports.
*** Make the PVCS source control system happy:
$Header$
$Log$
***
Routines for allocating, managing and freeing buffer descriptors.
See comments in "buffdesc.h" for a full explination of what we're
up to here.
No critical sections or locking are required when modifying buffer
descriptor chains... these chains are always "private" to a single
"thread" of execution. Critical sections are used when handling the
shared free buffer chunk list.
*/
#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 defined(Xyplex)
/* See commentary in "buffdesc.h" -- GetNewPacket() and
DataForPacket() need to be filled in by Xyplex. */
if ((newDescriptor->outBoardBuffer = GetNewPacket()) is Empty)
{
FreeBufferChain(newDescriptor);
FreeBufferChain(chain);
return(Empty);
}
newDescriptor->outBoardAllocatedSize =
size + MaximumHeaderLength + LongDdpHeaderLength;
newDescriptor->outBoardData =
DataForPacket(newDescriptor->outBoardBuffer) +
MaximumHeaderLength + LongDdpHeaderLength;
newDescriptor->outBoardSize= size;
newDescriptor->data = newDescriptor->outBoardData;
newDescriptor->freeData = True;
newDescriptor->outBoardDataValid = True;
#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;
#endif
}
}
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. The OpenSocket that we may be
holding on to is only valid in the first chunk of a chain. */
newDescriptor->next = chain;
if (chain isnt Empty)
{
newDescriptor->openSocket = chain->openSocket;
chain->openSocket = Empty;
}
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;
if (chain isnt Empty)
{
newDescriptor->openSocket = chain->openSocket;
chain->openSocket = Empty;
}
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;
/* If only one chunk and all in outBoard or onBoard area, just return
what we have. Pretty exciting, this may be the first time I've ever
had a use for the "bitwise exclusive or" operator! */
if (chain->next is Empty and
(chain->outBoardDataValid ^ chain->onBoardDataValid))
return(chain);
/* Otherwise, copy into a single chunk and free the original. */
coalesced = CopyBufferChain(chain);
if (coalesced isnt Empty)
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;
}
}
/* If the source has a valid OpenSocket link, we need to create one for
the destination too. */
TakeLock(DdpLock);
if (chain->openSocket isnt Empty);
copy->openSocket = Link(chain->openSocket);
ReleaseLock(DdpLock);
/* All set. */
return(copy);
} /* CopyBufferChain */
/* Free a buffer chain and its assocciated free-able data. */
void far FreeBufferChain(BufferDescriptor chain)
{
BufferDescriptor next;
/* In the first chunk, there may be a valid OpenSocket link -- we want
to hold on to this link until we've really finished the "transmit,"
now is a pretty good time! */
if (chain is Empty)
return;
UnlinkOpenSocket(chain->openSocket);
/* 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;
chain->errorCode = ATnoError;
chain->openSocket = 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)
{
#if defined(Xyplex)
/* See commentary in "buffdesc.h" -- ReturnPacket will need
to be fleshed out by Xyplex. */
ReturnPacket(chain->outBoardBuffer);
#else
Free(chain->outBoardBuffer);
#endif
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;
newDescriptor->outBoardData = chain->outBoardData + offset;
}
else
{
newDescriptor->outBoardBuffer =
SubsetOpaqueDataDescriptor(chain->outBoardBuffer, offset, size,
&freeOpaqueDataDescriptor);
newDescriptor->outBoardData = newDescriptor->outBoardBuffer;
chain->freeOpaqueDataDescriptor = freeOpaqueDataDescriptor;
}
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 or MaxKeptBufferBytes 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