mirror of https://github.com/lianthony/NT4.0
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
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
|
|
|
|
|