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.
430 lines
11 KiB
430 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dllsub16.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the OS/2 V1.x DosSub* API calls.
|
|
|
|
Author:
|
|
|
|
Beni Lavi (BeniL) 11-Dec-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define INCL_OS2V20_MEMORY
|
|
#define INCL_OS2V20_ERRORS
|
|
#include "os2dll.h"
|
|
#include "os2dll16.h"
|
|
|
|
#define MinPoolSize (sizeof(PoolHeader) + sizeof(BufferHeader))
|
|
#define MaxPoolSize (0x10000 - MinPoolSize)
|
|
|
|
#define RoundUp4Mask 0x3
|
|
#define RoundUp4(x) (((x) + RoundUp4Mask) & ~RoundUp4Mask)
|
|
|
|
#pragma pack(1)
|
|
typedef struct _PoolHeader {
|
|
USHORT FirstFreeBuffer;
|
|
USHORT Undefined; /* not used in this implementation */
|
|
USHORT PoolSize;
|
|
USHORT ReferenceCount; /* value is set, but not used */
|
|
} PoolHeader, *PPoolHeader;
|
|
|
|
typedef struct _BufferHeader {
|
|
USHORT NextFreeBuffer;
|
|
USHORT BufferSize;
|
|
} BufferHeader, *PBufferHeader;
|
|
#pragma pack()
|
|
|
|
|
|
//
|
|
// Od2FindAdjacentLowerFreeBuffer
|
|
//
|
|
// Return a pointer to a free buffer whose upper free byte is adjacent
|
|
// to a specified offset
|
|
//
|
|
PBufferHeader
|
|
Od2FindAdjacentLowerFreeBuffer(
|
|
PPoolHeader PoolPtr,
|
|
USHORT OffsetOfNewBuffer
|
|
)
|
|
{
|
|
PBufferHeader BufferPtr;
|
|
USHORT Offset;
|
|
|
|
Offset = PoolPtr->FirstFreeBuffer;
|
|
while (Offset != 0) {
|
|
BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
|
|
if (((USHORT)(Offset + BufferPtr->BufferSize)) == OffsetOfNewBuffer) {
|
|
return(BufferPtr);
|
|
}
|
|
else {
|
|
Offset = BufferPtr->NextFreeBuffer;
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// Od2FindFreeBufferAtOffset
|
|
//
|
|
// Return a pointer to a buffer whose first free byte is at the
|
|
// specified offset
|
|
//
|
|
PBufferHeader
|
|
Od2FindFreeBufferAtOffset(
|
|
PPoolHeader PoolPtr,
|
|
USHORT OffsetOfBuffer
|
|
)
|
|
{
|
|
PBufferHeader BufferPtr;
|
|
USHORT Offset;
|
|
|
|
Offset = PoolPtr->FirstFreeBuffer;
|
|
while (Offset != 0) {
|
|
BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
|
|
if (Offset == OffsetOfBuffer) {
|
|
return(BufferPtr);
|
|
}
|
|
else {
|
|
Offset = BufferPtr->NextFreeBuffer;
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// Od2FindPreviousFreeBuffer
|
|
//
|
|
// Return a pointer to a free buffer which preceeds the specified buffer
|
|
// in the free buffers chain. The returned pointer may point to the
|
|
// pool header instead of a buffer header if the specified buffer was
|
|
// first in the list.
|
|
//
|
|
PBufferHeader
|
|
Od2FindPreviousFreeBuffer(
|
|
PPoolHeader PoolPtr,
|
|
PBufferHeader CurrentBufferPtr
|
|
)
|
|
{
|
|
PBufferHeader BufferPtr;
|
|
USHORT Offset;
|
|
|
|
if ((PBufferHeader)((PCHAR)PoolPtr + PoolPtr->FirstFreeBuffer) == CurrentBufferPtr) {
|
|
return((PBufferHeader)PoolPtr);
|
|
}
|
|
Offset = PoolPtr->FirstFreeBuffer;
|
|
while (Offset != 0) {
|
|
BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
|
|
if ((PBufferHeader)((PCHAR)PoolPtr + BufferPtr->NextFreeBuffer) == CurrentBufferPtr) {
|
|
return(BufferPtr);
|
|
}
|
|
Offset = BufferPtr->NextFreeBuffer;
|
|
}
|
|
return(NULL); /* Should not arrive here */
|
|
}
|
|
|
|
|
|
//
|
|
// Od2LocateBufferInPool
|
|
//
|
|
// Return a pointer to a free buffer in the free buffers list whose size
|
|
// is big enough to satisfy the required size. This routine does not
|
|
// allow for remained buffer peaces to be less than the free buffer
|
|
// header since these peaces cannot be processes.
|
|
//
|
|
PBufferHeader
|
|
Od2LocateBufferInPool(
|
|
PPoolHeader PoolPtr,
|
|
USHORT BufSize
|
|
)
|
|
{
|
|
PBufferHeader BufferPtr;
|
|
USHORT Offset;
|
|
|
|
Offset = PoolPtr->FirstFreeBuffer;
|
|
while (Offset != 0) {
|
|
BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
|
|
//
|
|
// Return only buffers which are identical in size
|
|
// to the requested size, or buffers who are big enough
|
|
// to contain a free header strcture after the requested
|
|
// size is extracted.
|
|
//
|
|
if ((BufferPtr->BufferSize == BufSize) ||
|
|
(BufferPtr->BufferSize > (USHORT)(BufSize + (USHORT)sizeof(BufferHeader)))) {
|
|
return(BufferPtr);
|
|
}
|
|
Offset = BufferPtr->NextFreeBuffer;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// Od2RemoveFreeBufferFromList
|
|
//
|
|
// Remove a free buffer from the list of free buffers
|
|
//
|
|
VOID
|
|
Od2RemoveFreeBufferFromList(
|
|
PPoolHeader PoolPtr,
|
|
PBufferHeader BufferPtr
|
|
)
|
|
{
|
|
PBufferHeader PrevBufferPtr;
|
|
|
|
PrevBufferPtr = Od2FindPreviousFreeBuffer(PoolPtr, BufferPtr);
|
|
if (PrevBufferPtr == (PBufferHeader)PoolPtr) {
|
|
PoolPtr->FirstFreeBuffer = BufferPtr->NextFreeBuffer;
|
|
}
|
|
else {
|
|
PrevBufferPtr->NextFreeBuffer = BufferPtr->NextFreeBuffer;
|
|
}
|
|
}
|
|
|
|
|
|
APIRET
|
|
Dos16SubSet (
|
|
IN SEL Sel,
|
|
IN USHORT fFlags,
|
|
IN USHORT Size
|
|
)
|
|
{
|
|
ULONG PoolSize;
|
|
USHORT OldPoolSize;
|
|
USHORT NewBufferAddedSize;
|
|
USHORT NewBufferOffset;
|
|
PPoolHeader PoolPtr;
|
|
PBufferHeader FirstBufferPtr, NewBufferPtr, BufferPtr;
|
|
PVOID BaseAddress;
|
|
|
|
if (Size == 0) {
|
|
PoolSize = 0x10000;
|
|
}
|
|
else {
|
|
PoolSize = Size;
|
|
}
|
|
|
|
if (PoolSize < MinPoolSize) {
|
|
return(ERROR_DOSSUB_SHRINK);
|
|
}
|
|
|
|
if ((fFlags != 0) && (fFlags != 1)) {
|
|
return(ERROR_DOSSUB_BADFLAG);
|
|
}
|
|
|
|
PoolSize = RoundUp4(PoolSize);
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
PoolPtr = (PPoolHeader)BaseAddress;
|
|
|
|
AcquireTaskLock();
|
|
|
|
if (fFlags == 1) {
|
|
PoolPtr->FirstFreeBuffer = sizeof(PoolHeader);
|
|
PoolPtr->Undefined = 0;
|
|
PoolPtr->PoolSize = (USHORT)PoolSize - (USHORT)sizeof(PoolHeader);
|
|
PoolPtr->ReferenceCount = 0;
|
|
|
|
FirstBufferPtr = (PBufferHeader)((PCHAR)BaseAddress + sizeof(PoolHeader));
|
|
FirstBufferPtr->NextFreeBuffer = 0; /* end of list */
|
|
FirstBufferPtr->BufferSize = (USHORT)(PoolSize - sizeof(PoolHeader));
|
|
}
|
|
else /* fFlags == 0 */ {
|
|
OldPoolSize = PoolPtr->PoolSize + (USHORT)sizeof(PoolHeader);
|
|
if ((USHORT)PoolSize < OldPoolSize) {
|
|
ReleaseTaskLock();
|
|
return(ERROR_DOSSUB_SHRINK);
|
|
}
|
|
if ((OldPoolSize - (USHORT)PoolSize) < sizeof(BufferHeader)) {
|
|
ReleaseTaskLock();
|
|
return(ERROR_DOSSUB_BADSIZE);
|
|
}
|
|
|
|
NewBufferAddedSize = (USHORT)PoolSize - OldPoolSize;
|
|
NewBufferOffset = OldPoolSize;
|
|
NewBufferPtr = (PBufferHeader)((PCHAR)BaseAddress + NewBufferOffset);
|
|
|
|
BufferPtr = Od2FindAdjacentLowerFreeBuffer(
|
|
PoolPtr, NewBufferOffset);
|
|
if (BufferPtr == NULL) {
|
|
NewBufferPtr->NextFreeBuffer = PoolPtr->FirstFreeBuffer;
|
|
NewBufferPtr->BufferSize = NewBufferAddedSize;
|
|
PoolPtr->FirstFreeBuffer = NewBufferOffset;
|
|
}
|
|
else {
|
|
BufferPtr->BufferSize += NewBufferAddedSize;
|
|
}
|
|
PoolPtr->PoolSize += NewBufferAddedSize;
|
|
|
|
}
|
|
|
|
ReleaseTaskLock();
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
Dos16SubFree (
|
|
IN SEL Sel,
|
|
IN USHORT offBlock,
|
|
IN USHORT cbBlock
|
|
)
|
|
{
|
|
PPoolHeader PoolPtr;
|
|
PBufferHeader BufferPtr;
|
|
PBufferHeader PrevBufferPtr;
|
|
PBufferHeader CurrentBufferPtr;
|
|
USHORT BufferSize;
|
|
PVOID BaseAddress;
|
|
ULONG BufSize;
|
|
USHORT Offset;
|
|
|
|
if (cbBlock == 0) {
|
|
return(ERROR_DOSSUB_BADSIZE);
|
|
}
|
|
|
|
BufSize = RoundUp4(cbBlock);
|
|
if (BufSize > MaxPoolSize) {
|
|
return(ERROR_DOSSUB_BADSIZE);
|
|
}
|
|
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
PoolPtr = (PPoolHeader)BaseAddress;
|
|
CurrentBufferPtr = (PBufferHeader)((PCHAR)BaseAddress + offBlock);
|
|
|
|
AcquireTaskLock();
|
|
|
|
//
|
|
// Verify that we are freeing a non overlapping section
|
|
//
|
|
if (((offBlock + BufSize) > (PoolPtr->PoolSize + sizeof(PoolHeader))) ||
|
|
(offBlock < sizeof(PoolHeader))
|
|
) {
|
|
ReleaseTaskLock();
|
|
return(ERROR_DOSSUB_OVERLAP);
|
|
}
|
|
//
|
|
// loop over all free buffers and verify that the freed buffer is
|
|
// not contained within any of them
|
|
//
|
|
Offset = PoolPtr->FirstFreeBuffer;
|
|
while (Offset != 0) {
|
|
BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
|
|
if (((offBlock >= Offset) && (offBlock < (Offset + BufferPtr->BufferSize))) ||
|
|
((Offset >= offBlock) && (Offset < (offBlock + BufSize)))
|
|
) {
|
|
ReleaseTaskLock();
|
|
return(ERROR_DOSSUB_OVERLAP);
|
|
}
|
|
Offset = BufferPtr->NextFreeBuffer;
|
|
}
|
|
|
|
if ((BufferPtr = Od2FindAdjacentLowerFreeBuffer(PoolPtr, offBlock)) != NULL) {
|
|
BufferPtr->BufferSize += (USHORT)BufSize;
|
|
CurrentBufferPtr = BufferPtr;
|
|
//
|
|
// Try to merge the new free buffer with a free buffer which
|
|
// is adjacent in higher address.
|
|
//
|
|
if ((BufferPtr = Od2FindFreeBufferAtOffset(PoolPtr,
|
|
(USHORT)(((PCHAR)CurrentBufferPtr - (PCHAR)PoolPtr) + CurrentBufferPtr->BufferSize))) != NULL) {
|
|
BufferSize = BufferPtr->BufferSize;
|
|
Od2RemoveFreeBufferFromList(PoolPtr, BufferPtr);
|
|
CurrentBufferPtr->BufferSize += BufferSize;
|
|
}
|
|
}
|
|
else if ((BufferPtr = Od2FindFreeBufferAtOffset(PoolPtr, (USHORT)(offBlock + BufSize))) != NULL) {
|
|
PrevBufferPtr = Od2FindPreviousFreeBuffer(PoolPtr, BufferPtr);
|
|
if (PrevBufferPtr == (PBufferHeader)PoolPtr) {
|
|
PoolPtr->FirstFreeBuffer = offBlock;
|
|
CurrentBufferPtr->BufferSize = (USHORT)(BufSize + BufferPtr->BufferSize);
|
|
}
|
|
else {
|
|
PrevBufferPtr->NextFreeBuffer = offBlock;
|
|
CurrentBufferPtr->BufferSize = (USHORT)(BufSize + BufferPtr->BufferSize);
|
|
}
|
|
CurrentBufferPtr->NextFreeBuffer = BufferPtr->NextFreeBuffer;
|
|
}
|
|
else {
|
|
CurrentBufferPtr->NextFreeBuffer = PoolPtr->FirstFreeBuffer;
|
|
CurrentBufferPtr->BufferSize = (USHORT)BufSize;
|
|
PoolPtr->FirstFreeBuffer = offBlock;
|
|
}
|
|
|
|
ReleaseTaskLock();
|
|
|
|
PoolPtr->ReferenceCount++;
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
APIRET
|
|
Dos16SubAlloc (
|
|
IN SEL Sel,
|
|
OUT PUSHORT pusOffset,
|
|
IN USHORT cbBlock
|
|
)
|
|
{
|
|
ULONG BufSize;
|
|
USHORT NewBufferOffset;
|
|
PPoolHeader PoolPtr;
|
|
PBufferHeader NewBufferPtr;
|
|
PBufferHeader BufferPtr;
|
|
PVOID BaseAddress;
|
|
|
|
if (cbBlock == 0) {
|
|
return(ERROR_DOSSUB_BADSIZE);
|
|
}
|
|
|
|
BufSize = RoundUp4(cbBlock);
|
|
if ((BufSize < sizeof(BufferHeader)) || (BufSize > MaxPoolSize)) {
|
|
return(ERROR_DOSSUB_BADSIZE);
|
|
}
|
|
|
|
try {
|
|
*pusOffset = 0;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
BaseAddress = SELTOFLAT(Sel);
|
|
PoolPtr = (PPoolHeader)BaseAddress;
|
|
|
|
AcquireTaskLock();
|
|
|
|
BufferPtr = Od2LocateBufferInPool(PoolPtr, (USHORT)BufSize);
|
|
if (BufferPtr == NULL) {
|
|
ReleaseTaskLock();
|
|
return(ERROR_DOSSUB_NOMEM);
|
|
}
|
|
|
|
if (BufferPtr->BufferSize == (USHORT)BufSize) {
|
|
Od2RemoveFreeBufferFromList(PoolPtr, BufferPtr);
|
|
NewBufferOffset = (USHORT)((PCHAR)BufferPtr - (PCHAR)PoolPtr);
|
|
}
|
|
else {
|
|
NewBufferPtr =
|
|
(PBufferHeader)((PCHAR)BufferPtr + BufferPtr->BufferSize - BufSize);
|
|
NewBufferOffset = (USHORT)((PCHAR)NewBufferPtr - (PCHAR)PoolPtr);
|
|
BufferPtr->BufferSize -= (USHORT)BufSize;
|
|
}
|
|
|
|
ReleaseTaskLock();
|
|
|
|
*pusOffset = NewBufferOffset;
|
|
PoolPtr->ReferenceCount++;
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|