2000-05-06 21:34:20 +02:00
|
|
|
/****************************************************************/
|
|
|
|
/* */
|
|
|
|
/* memmgr.c */
|
|
|
|
/* */
|
|
|
|
/* Memory Manager for Core Allocation */
|
|
|
|
/* */
|
|
|
|
/* Copyright (c) 1995 */
|
|
|
|
/* Pasquale J. Villani */
|
|
|
|
/* All Rights Reserved */
|
|
|
|
/* */
|
|
|
|
/* This file is part of DOS-C. */
|
|
|
|
/* */
|
|
|
|
/* DOS-C is free software; you can redistribute it and/or */
|
|
|
|
/* modify it under the terms of the GNU General Public License */
|
|
|
|
/* as published by the Free Software Foundation; either version */
|
|
|
|
/* 2, or (at your option) any later version. */
|
|
|
|
/* */
|
|
|
|
/* DOS-C is distributed in the hope that it will be useful, but */
|
|
|
|
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
|
|
|
|
/* the GNU General Public License for more details. */
|
|
|
|
/* */
|
|
|
|
/* You should have received a copy of the GNU General Public */
|
|
|
|
/* License along with DOS-C; see the file COPYING. If not, */
|
|
|
|
/* write to the Free Software Foundation, 675 Mass Ave, */
|
|
|
|
/* Cambridge, MA 02139, USA. */
|
|
|
|
/****************************************************************/
|
|
|
|
|
|
|
|
#include "portab.h"
|
|
|
|
#include "globals.h"
|
|
|
|
|
|
|
|
#ifdef VERSION_STRING
|
2001-11-18 15:01:12 +01:00
|
|
|
static BYTE *memmgrRcsId =
|
|
|
|
"$Id$";
|
2000-05-06 21:34:20 +02:00
|
|
|
#endif
|
|
|
|
|
2001-03-21 03:56:26 +01:00
|
|
|
/*#define nxtMCBsize(mcb,size) \
|
|
|
|
MK_FP(far2para((VOID FAR *) (mcb)) + (size) + 1, 0) */
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
void FAR *nxtMCBsize(mcb FAR * Mcb, int size)
|
2001-03-21 03:56:26 +01:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
return MK_FP(far2para((VOID FAR *) (Mcb)) + (size) + 1, 0);
|
2001-03-21 03:56:26 +01:00
|
|
|
}
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
#define nxtMCB(mcb) nxtMCBsize((mcb), (mcb)->m_size)
|
|
|
|
|
|
|
|
#define mcbFree(mcb) ((mcb)->m_psp == FREE_PSP)
|
|
|
|
#define mcbValid(mcb) \
|
|
|
|
((mcb)->m_type == MCB_NORMAL || (mcb)->m_type == MCB_LAST)
|
|
|
|
|
|
|
|
#define para2far(seg) (mcb FAR *)MK_FP((seg) , 0)
|
|
|
|
|
|
|
|
/*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Join any following unused MCBs to MCB 'p'.
|
|
|
|
* Return:
|
|
|
|
* SUCCESS: on success
|
|
|
|
* else: error number <<currently DE_MCBDESTRY only>>
|
2000-05-06 21:34:20 +02:00
|
|
|
*/
|
2002-01-23 23:29:41 +01:00
|
|
|
STATIC COUNT joinMCBs(mcb FAR * p)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
mcb FAR *q;
|
|
|
|
|
|
|
|
/* loop as long as the current MCB is not the last one in the chain
|
|
|
|
and the next MCB is unused */
|
|
|
|
while (p->m_type == MCB_NORMAL && mcbFree(q = nxtMCB(p)))
|
|
|
|
{
|
|
|
|
if (!mcbValid(q))
|
|
|
|
return DE_MCBDESTRY;
|
|
|
|
/* join both MCBs */
|
|
|
|
p->m_type = q->m_type; /* possibly the next MCB is the last one */
|
|
|
|
p->m_size += q->m_size + 1; /* one for q's MCB itself */
|
|
|
|
q->m_type = 'K'; /* Invalidate the magic number */
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
seg far2para(VOID FAR * p)
|
|
|
|
{
|
|
|
|
return FP_SEG(p) + (FP_OFF(p) >> 4);
|
|
|
|
}
|
|
|
|
|
2001-04-15 05:21:50 +02:00
|
|
|
seg long2para(ULONG size)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
UWORD high = size >> 16;
|
|
|
|
if ((UWORD) size > 0xfff0)
|
|
|
|
high++;
|
|
|
|
return (((UWORD) size + 0x0f) >> 4) + (high << 12);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Add a displacement to a far pointer and return the result normalized.
|
2000-05-06 21:34:20 +02:00
|
|
|
*/
|
2002-01-23 23:29:41 +01:00
|
|
|
VOID FAR * add_far(VOID FAR * fp, ULONG off)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-04-15 05:21:50 +02:00
|
|
|
UWORD off2;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
if (FP_SEG(fp) == 0xffff)
|
|
|
|
return ((BYTE FAR *) fp) + FP_OFF(off);
|
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
#ifndef I86
|
|
|
|
if (FP_SEG(fp) == 0)
|
|
|
|
return ((BYTE FAR *) fp) + FP_OFF(off);
|
|
|
|
#endif
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
off += FP_OFF(fp);
|
2001-11-18 15:01:12 +01:00
|
|
|
off2 = ((off >> 16) << 12) + ((UWORD) off >> 4);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-04-15 05:21:50 +02:00
|
|
|
return MK_FP(FP_SEG(fp) + off2, (UWORD) off & 0xf);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Return a normalized far pointer
|
2000-05-06 21:34:20 +02:00
|
|
|
*/
|
2002-08-03 18:54:09 +02:00
|
|
|
void FAR * adjust_far(const void FAR * fp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
/* and return an adddress adjusted to the nearest paragraph */
|
|
|
|
/* boundary. */
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
if (FP_SEG(fp) == 0xffff)
|
2002-08-03 18:54:09 +02:00
|
|
|
return (void FAR *)fp;
|
|
|
|
|
|
|
|
#ifndef I86
|
|
|
|
if (FP_SEG(fp) == 0)
|
|
|
|
return (void FAR *)fp;
|
|
|
|
#endif
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
return MK_FP(FP_SEG(fp) + (FP_OFF(fp) >> 4), FP_OFF(fp) & 0xf);
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef REG
|
|
|
|
#define REG
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
#if 1 /* #ifdef KERNEL KERNEL */
|
2000-05-06 21:34:20 +02:00
|
|
|
/* Allocate a new memory area. *para is assigned to the segment of the
|
|
|
|
MCB rather then the segment of the data portion */
|
|
|
|
/* If mode == LARGEST, asize MUST be != NULL and will always recieve the
|
|
|
|
largest available block, which is allocated.
|
|
|
|
If mode != LARGEST, asize maybe NULL, but if not, it is assigned to the
|
|
|
|
size of the largest available block only on failure.
|
|
|
|
size is the minimum size of the block to search for,
|
|
|
|
even if mode == LARGEST.
|
|
|
|
*/
|
2001-11-18 15:01:12 +01:00
|
|
|
COUNT DosMemAlloc(UWORD size, COUNT mode, seg FAR * para,
|
|
|
|
UWORD FAR * asize)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
REG mcb FAR *p;
|
|
|
|
mcb FAR *foundSeg;
|
|
|
|
mcb FAR *biggestSeg;
|
|
|
|
/* Initialize */
|
2001-03-19 05:50:56 +01:00
|
|
|
|
|
|
|
searchAgain:
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
p = para2far(first_mcb);
|
2000-08-06 07:50:17 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
biggestSeg = foundSeg = NULL;
|
2000-08-07 06:53:54 +02:00
|
|
|
/*
|
|
|
|
Hack to the Umb Region direct for now. Save time and program space.
|
|
|
|
*/
|
2002-08-03 18:54:09 +02:00
|
|
|
if (uppermem_link && uppermem_root != 0xffff)
|
|
|
|
{
|
|
|
|
COUNT tmpmode = (mode == LARGEST ? mem_access_mode : mode);
|
|
|
|
if ((mode != LARGEST || size == 0xffff) &&
|
|
|
|
(tmpmode & (FIRST_FIT_UO | FIRST_FIT_U)))
|
|
|
|
p = para2far(uppermem_root);
|
|
|
|
}
|
2000-08-06 07:50:17 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* Search through memory blocks */
|
|
|
|
FOREVER
|
|
|
|
{
|
|
|
|
/* check for corruption */
|
|
|
|
if (!mcbValid(p))
|
|
|
|
return DE_MCBDESTRY;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
if (mcbFree(p))
|
|
|
|
{ /* unused block, check if it applies to the rule */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (joinMCBs(p) != SUCCESS) /* join following unused blocks */
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_MCBDESTRY; /* error */
|
|
|
|
|
|
|
|
if (!biggestSeg || biggestSeg->m_size < p->m_size)
|
|
|
|
biggestSeg = p;
|
|
|
|
|
|
|
|
if (p->m_size >= size)
|
|
|
|
{ /* if the block is too small, ignore */
|
|
|
|
/* this block has a "match" size, try the rule set */
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case LAST_FIT: /* search for last possible */
|
2000-08-06 07:50:17 +02:00
|
|
|
case LAST_FIT_U:
|
|
|
|
case LAST_FIT_UO:
|
2000-05-06 21:34:20 +02:00
|
|
|
default:
|
|
|
|
foundSeg = p;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LARGEST: /* grab the biggest block */
|
|
|
|
/* it is calculated when the MCB chain
|
|
|
|
was completely checked */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BEST_FIT: /* first, but smallest block */
|
2000-08-06 07:50:17 +02:00
|
|
|
case BEST_FIT_U:
|
|
|
|
case BEST_FIT_UO:
|
2000-05-06 21:34:20 +02:00
|
|
|
if (!foundSeg || foundSeg->m_size > p->m_size)
|
|
|
|
/* better match found */
|
|
|
|
foundSeg = p;
|
|
|
|
break;
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
case FIRST_FIT: /* first possible */
|
2000-08-06 07:50:17 +02:00
|
|
|
case FIRST_FIT_U:
|
|
|
|
case FIRST_FIT_UO:
|
2000-05-06 21:34:20 +02:00
|
|
|
foundSeg = p;
|
|
|
|
goto stopIt; /* OK, rest of chain can be ignored */
|
2000-08-06 07:50:17 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->m_type == MCB_LAST)
|
|
|
|
break; /* end of chain reached */
|
|
|
|
|
|
|
|
p = nxtMCB(p); /* advance to next MCB */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode == LARGEST && biggestSeg && biggestSeg->m_size >= size)
|
|
|
|
*asize = (foundSeg = biggestSeg)->m_size;
|
|
|
|
|
|
|
|
if (!foundSeg || !foundSeg->m_size)
|
|
|
|
{ /* no block to fullfill the request */
|
2001-11-18 15:01:12 +01:00
|
|
|
if ((mode != LARGEST) && (mode & FIRST_FIT_U) &&
|
2002-02-09 01:40:33 +01:00
|
|
|
uppermem_link && uppermem_root != 0xffff)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2001-04-03 01:18:30 +02:00
|
|
|
mode &= ~FIRST_FIT_U;
|
2001-03-19 05:50:56 +01:00
|
|
|
goto searchAgain;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
if (asize)
|
|
|
|
*asize = biggestSeg ? biggestSeg->m_size : 0;
|
|
|
|
return DE_NOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
stopIt: /* reached from FIRST_FIT on match */
|
|
|
|
|
|
|
|
if (mode != LARGEST && size != foundSeg->m_size)
|
|
|
|
{
|
|
|
|
/* Split the found buffer because it is larger than requested */
|
|
|
|
/* foundSeg := pointer to allocated block
|
|
|
|
p := pointer to MCB that will form the rest of the block
|
|
|
|
*/
|
2001-11-18 15:01:12 +01:00
|
|
|
if ((mode == LAST_FIT) || (mode == LAST_FIT_UO)
|
|
|
|
|| (mode == LAST_FIT_U))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
/* allocate the block from the end of the found block */
|
|
|
|
p = foundSeg;
|
|
|
|
p->m_size -= size + 1; /* size+1 paragraphes are allocated by
|
|
|
|
the new segment (+1 for MCB itself) */
|
|
|
|
foundSeg = nxtMCB(p);
|
|
|
|
|
|
|
|
/* initialize stuff because foundSeg > p */
|
|
|
|
foundSeg->m_type = p->m_type;
|
|
|
|
p->m_type = MCB_NORMAL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* all other modes allocate from the beginning */
|
|
|
|
p = nxtMCBsize(foundSeg, size);
|
|
|
|
p->m_size = foundSeg->m_size - size - 1;
|
|
|
|
|
|
|
|
/* initialize stuff because p > foundSeg */
|
|
|
|
p->m_type = foundSeg->m_type;
|
|
|
|
foundSeg->m_type = MCB_NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Already initialized:
|
|
|
|
p->m_size, ->m_type, foundSeg->m_type
|
|
|
|
*/
|
|
|
|
p->m_psp = FREE_PSP; /* unused */
|
|
|
|
|
|
|
|
foundSeg->m_size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Already initialized:
|
|
|
|
foundSeg->m_size, ->m_type
|
|
|
|
*/
|
|
|
|
foundSeg->m_psp = cu_psp; /* the new block is for current process */
|
|
|
|
foundSeg->m_name[0] = '\0';
|
|
|
|
|
|
|
|
*para = far2para((VOID FAR *) (BYTE FAR *) foundSeg);
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Unlike the name and the original prototype could suggest, this function
|
|
|
|
* is used to return the _size_ of the largest available block rather than
|
|
|
|
* the block itself.
|
2000-05-06 21:34:20 +02:00
|
|
|
*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Known bug: a memory area with a size of the data area of 0 (zero) is
|
|
|
|
* not considered a "largest" block. <<Perhaps this is a feature ;-)>>
|
2000-05-06 21:34:20 +02:00
|
|
|
*/
|
|
|
|
COUNT DosMemLargest(UWORD FAR * size)
|
|
|
|
{
|
2002-05-09 00:49:35 +02:00
|
|
|
seg dummy;
|
|
|
|
*size = 0;
|
|
|
|
DosMemAlloc(0xffff, LARGEST, &dummy, size);
|
2002-10-22 04:40:19 +02:00
|
|
|
if (mem_access_mode & 0x80) /* then the largest block is probably low! */
|
|
|
|
{
|
|
|
|
UWORD lowsize = 0;
|
|
|
|
mem_access_mode &= ~0x80;
|
|
|
|
DosMemAlloc(0xffff, LARGEST, &dummy, &lowsize);
|
|
|
|
mem_access_mode |= 0x80;
|
|
|
|
if (lowsize > *size)
|
|
|
|
*size = lowsize;
|
|
|
|
}
|
2002-05-09 00:49:35 +02:00
|
|
|
return *size ? SUCCESS : DE_NOMEM;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Deallocate a memory block. para is the segment of the MCB itself
|
|
|
|
* This function can be called with para == 0, which eases other parts
|
|
|
|
* of the kernel.
|
2000-05-06 21:34:20 +02:00
|
|
|
*/
|
|
|
|
COUNT DosMemFree(UWORD para)
|
|
|
|
{
|
|
|
|
REG mcb FAR *p;
|
|
|
|
COUNT i;
|
|
|
|
|
|
|
|
if (!para) /* let esp. the kernel call this fct with para==0 */
|
|
|
|
return DE_INVLDMCB;
|
|
|
|
|
|
|
|
/* Initialize */
|
|
|
|
p = para2far(para);
|
|
|
|
|
|
|
|
/* check for corruption */
|
|
|
|
if (!mcbValid(p))
|
|
|
|
return DE_INVLDMCB;
|
|
|
|
|
|
|
|
/* Mark the mcb as free so that we can later */
|
|
|
|
/* merge with other surrounding free mcb's */
|
|
|
|
p->m_psp = FREE_PSP;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
p->m_name[i] = '\0';
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* Moved into allocating functions -- 1999/04/21 ska */
|
|
|
|
/* Now merge free blocks */
|
2000-08-06 07:50:17 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
for (p = (mcb FAR *) (MK_FP(first_mcb, 0)); p->m_type != MCB_LAST; p = q)
|
|
|
|
{
|
|
|
|
/* make q a pointer to the next block */
|
|
|
|
q = nxtMCB(p);
|
|
|
|
/* and test for corruption */
|
|
|
|
if (q->m_type != MCB_NORMAL && q->m_type != MCB_LAST)
|
|
|
|
return DE_MCBDESTRY;
|
|
|
|
if (p->m_psp != FREE_PSP)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* test if next is free - if so merge */
|
|
|
|
if (q->m_psp == FREE_PSP)
|
|
|
|
{
|
|
|
|
/* Always flow type down on free */
|
|
|
|
p->m_type = q->m_type;
|
|
|
|
p->m_size += q->m_size + 1;
|
|
|
|
/* and make pointers the same */
|
|
|
|
/* since the next free is now */
|
|
|
|
/* this block */
|
|
|
|
q = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Resize an allocated memory block.
|
|
|
|
* para is the segment of the data portion of the block rather than
|
|
|
|
* the segment of the MCB itself.
|
2000-05-06 21:34:20 +02:00
|
|
|
*
|
2000-06-21 20:16:46 +02:00
|
|
|
* If the block shall grow, it is resized to the maximal size less than
|
|
|
|
* or equal to size. This is the way MS DOS is reported to work.
|
2000-05-06 21:34:20 +02:00
|
|
|
*/
|
|
|
|
COUNT DosMemChange(UWORD para, UWORD size, UWORD * maxSize)
|
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
REG mcb FAR *p, FAR * q;
|
2000-05-06 21:34:20 +02:00
|
|
|
REG COUNT i;
|
|
|
|
|
|
|
|
/* Initialize */
|
|
|
|
p = para2far(para - 1); /* pointer to MCB */
|
|
|
|
|
|
|
|
/* check for corruption */
|
|
|
|
if (!mcbValid(p))
|
|
|
|
return DE_MCBDESTRY;
|
|
|
|
|
|
|
|
/* check if to grow the block */
|
|
|
|
if (size > p->m_size)
|
|
|
|
{
|
|
|
|
/* first try to make the MCB larger by joining with any following
|
|
|
|
unused blocks */
|
|
|
|
if (joinMCBs(p) != SUCCESS)
|
|
|
|
return DE_MCBDESTRY;
|
|
|
|
|
|
|
|
if (size > p->m_size)
|
|
|
|
{ /* block is still too small */
|
|
|
|
if (maxSize)
|
|
|
|
*maxSize = p->m_size;
|
|
|
|
return DE_NOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* shrink it down */
|
|
|
|
if (size < p->m_size)
|
|
|
|
{
|
|
|
|
/* make q a pointer to the new next block */
|
|
|
|
q = nxtMCBsize(p, size);
|
|
|
|
/* reduce the size of p and add difference to q */
|
|
|
|
q->m_type = p->m_type;
|
|
|
|
q->m_size = p->m_size - size - 1;
|
|
|
|
|
|
|
|
p->m_size = size;
|
|
|
|
|
|
|
|
/* Make certian the old psp is not last (if it was) */
|
|
|
|
p->m_type = MCB_NORMAL;
|
|
|
|
|
|
|
|
/* Mark the mcb as free so that we can later */
|
|
|
|
/* merge with other surrounding free mcb's */
|
|
|
|
q->m_psp = FREE_PSP;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
q->m_name[i] = '\0';
|
2002-10-22 04:40:19 +02:00
|
|
|
|
|
|
|
/* try to join q with the free mcb's following it if possible */
|
|
|
|
if (joinMCBs(q) != SUCCESS)
|
|
|
|
return DE_MCBDESTRY;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
|
|
|
|
/* MS network client NET.EXE: DosMemChange sets the PSP *
|
|
|
|
* not tested, if always, or only on success TE*
|
2001-11-18 15:01:12 +01:00
|
|
|
* only on success seems more logical to me - Bart */
|
2001-09-23 22:39:44 +02:00
|
|
|
p->m_psp = cu_psp;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-06-21 20:16:46 +02:00
|
|
|
* Check the MCB chain for allocation corruption
|
2000-05-06 21:34:20 +02:00
|
|
|
*/
|
|
|
|
COUNT DosMemCheck(void)
|
|
|
|
{
|
|
|
|
REG mcb FAR *p;
|
2001-03-30 21:30:06 +02:00
|
|
|
REG mcb FAR *pprev = 0;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Initialize */
|
|
|
|
p = para2far(first_mcb);
|
|
|
|
|
|
|
|
/* Search through memory blocks */
|
|
|
|
while (p->m_type != MCB_LAST) /* not all MCBs touched */
|
|
|
|
{
|
|
|
|
/* check for corruption */
|
|
|
|
if (p->m_type != MCB_NORMAL)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2002-10-22 04:40:19 +02:00
|
|
|
put_string("dos mem corrupt, first_mcb=");
|
|
|
|
put_unsigned(first_mcb, 16, 4);
|
|
|
|
hexd("\nprev ", pprev, 16);
|
2001-11-18 15:01:12 +01:00
|
|
|
hexd("notMZ", p, 16);
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_MCBDESTRY;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* not corrupted - but not end, bump the pointer */
|
2001-03-30 21:30:06 +02:00
|
|
|
pprev = p;
|
2000-05-06 21:34:20 +02:00
|
|
|
p = nxtMCB(p);
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
COUNT FreeProcessMem(UWORD ps)
|
|
|
|
{
|
2001-04-15 05:21:50 +02:00
|
|
|
mcb FAR *p;
|
2001-11-04 20:47:39 +01:00
|
|
|
BYTE oldumbstate = uppermem_link;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* link in upper memory to free those , too */
|
2001-11-04 20:47:39 +01:00
|
|
|
DosUmbLink(1);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* Search through all memory blocks */
|
2001-11-18 15:01:12 +01:00
|
|
|
for (p = para2far(first_mcb);; p = nxtMCB(p))
|
|
|
|
{
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (!mcbValid(p)) /* check for corruption */
|
2001-11-18 15:01:12 +01:00
|
|
|
return DE_MCBDESTRY;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
|
|
|
if (p->m_psp == ps)
|
2001-11-18 15:01:12 +01:00
|
|
|
DosMemFree(FP_SEG(p));
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (p->m_type == MCB_LAST)
|
2001-11-18 15:01:12 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
DosUmbLink(oldumbstate);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
return SUCCESS;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
#if 0
|
|
|
|
/* seems to be superceeded by DosMemLargest
|
|
|
|
-- 1999/04/21 ska */
|
2000-05-06 21:34:20 +02:00
|
|
|
COUNT DosGetLargestBlock(UWORD FAR * block)
|
|
|
|
{
|
|
|
|
UWORD sz = 0;
|
|
|
|
mcb FAR *p;
|
|
|
|
*block = sz;
|
|
|
|
|
|
|
|
/* Initialize */
|
|
|
|
p = (mcb FAR *) (MK_FP(first_mcb, 0));
|
|
|
|
|
|
|
|
/* Search through memory blocks */
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/* check for corruption */
|
|
|
|
if (p->m_type != MCB_NORMAL && p->m_type != MCB_LAST)
|
|
|
|
return DE_MCBDESTRY;
|
|
|
|
|
|
|
|
if (p->m_psp == FREE_PSP && p->m_size > sz)
|
|
|
|
sz = p->m_size;
|
|
|
|
|
|
|
|
/* not corrupted - if last we're OK! */
|
|
|
|
if (p->m_type == MCB_LAST)
|
|
|
|
break;
|
|
|
|
p = nxtMCB(p);
|
|
|
|
}
|
|
|
|
*block = sz;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-04-03 01:18:30 +02:00
|
|
|
#ifdef DEBUG
|
2000-05-06 21:34:20 +02:00
|
|
|
VOID show_chain(void)
|
|
|
|
{
|
2001-04-16 03:45:26 +02:00
|
|
|
mcb FAR *p;
|
2000-08-06 07:50:17 +02:00
|
|
|
p = para2far(first_mcb);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
mcb_print(p);
|
|
|
|
if (p->m_type == MCB_LAST || p->m_type != MCB_NORMAL)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
p = nxtMCB(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID mcb_print(mcb FAR * mcbp)
|
|
|
|
{
|
|
|
|
static BYTE buff[9];
|
|
|
|
|
2001-04-15 05:21:50 +02:00
|
|
|
fmemcpy((BYTE FAR *) buff, (BYTE FAR *) (mcbp->m_name), 8);
|
2000-05-06 21:34:20 +02:00
|
|
|
buff[8] = '\0';
|
2001-11-18 15:01:12 +01:00
|
|
|
printf
|
|
|
|
("%04x:%04x -> |%s| m_type = 0x%02x '%c'; m_psp = 0x%04x; m_size = 0x%04x\n",
|
|
|
|
FP_SEG(mcbp), FP_OFF(mcbp), *buff == '\0' ? "*NO-ID*" : buff,
|
|
|
|
mcbp->m_type, mcbp->m_type > ' ' ? mcbp->m_type : ' ', mcbp->m_psp,
|
|
|
|
mcbp->m_size);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2001-04-15 05:21:50 +02:00
|
|
|
#endif
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2000-08-06 07:50:17 +02:00
|
|
|
VOID DosUmbLink(BYTE n)
|
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
REG mcb FAR *p;
|
|
|
|
REG mcb FAR *q;
|
|
|
|
|
2002-02-09 01:40:33 +01:00
|
|
|
if (uppermem_root == 0xffff)
|
2001-11-18 15:01:12 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
q = p = para2far(first_mcb);
|
2000-08-07 06:48:50 +02:00
|
|
|
/* like a xor thing! */
|
2001-11-18 15:01:12 +01:00
|
|
|
if ((uppermem_link == 1) && (n == 0))
|
|
|
|
{
|
2002-02-03 23:40:24 +01:00
|
|
|
while (FP_SEG(p) != uppermem_root)
|
2001-03-19 05:50:56 +01:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
if (mcbFree(p))
|
|
|
|
joinMCBs(p);
|
|
|
|
if (!mcbValid(p))
|
|
|
|
goto DUL_exit;
|
|
|
|
q = p;
|
|
|
|
p = nxtMCB(p);
|
2001-03-19 05:50:56 +01:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2002-02-03 23:40:24 +01:00
|
|
|
if (q->m_type == MCB_NORMAL)
|
2001-11-18 15:01:12 +01:00
|
|
|
q->m_type = MCB_LAST;
|
|
|
|
uppermem_link = n;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if ((uppermem_link == 0) && (n == 1))
|
|
|
|
{
|
|
|
|
while (q->m_type != MCB_LAST)
|
|
|
|
{
|
|
|
|
if (!mcbValid(q))
|
|
|
|
goto DUL_exit;
|
|
|
|
q = nxtMCB(q);
|
|
|
|
}
|
|
|
|
|
2002-02-03 23:40:24 +01:00
|
|
|
q->m_type = MCB_NORMAL;
|
2001-11-18 15:01:12 +01:00
|
|
|
uppermem_link = n;
|
|
|
|
}
|
2000-08-06 07:50:17 +02:00
|
|
|
DUL_exit:
|
2001-11-18 15:01:12 +01:00
|
|
|
return;
|
2000-08-06 07:50:17 +02:00
|
|
|
}
|
2001-04-15 05:21:50 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
#endif
|
2001-11-18 00:26:45 +01:00
|
|
|
|