Dec 062017
C++ class for virtual memory (conventional, disk, EMS).
File VMEMPP.ZIP from The Programmer’s Corner in
Category C++ Source Code
C++ class for virtual memory (conventional, disk, EMS).
File Name File Size Zip Size Zip Type
CONV.CPP 1481 500 deflated
DISK.CPP 4498 1216 deflated
EMS.CPP 5670 1428 deflated
MEMORY.CPP 1095 268 deflated
MEMORY.H 9328 2954 deflated
READ.ME 4628 1965 deflated
TEST.CPP 2135 728 deflated
TEST.DSK 3273 927 deflated
TEST.PRJ 5799 1260 deflated
VMEMMGR.CPP 3942 933 deflated
VMEMMGR.H 871 398 deflated

Download File VMEMPP.ZIP Here

Contents of the READ.ME file

The following files should be included:
test.cpp:test program
conv.cpp:source for ConvMemory class.
ems.cpp:source for EmsMemory class.
disk.cpp:source for DiskMemory class.
memory.cpp:source for VMemManager class.

VMEMPP.ZIP is public domain - use it to your heart's content, modify at
will (in particular you may want to add defragmentation methods - I know
__I__ do!), and I'm not responsible for anything!
Whew! Now that that's over, lets get into the details.
What you have downloaded is primitive virtual memory capabilities for use
with C++ (I developed it using Borland Intl's BC++ 3.0). The functionality
for any particular type of memory allocation (conventional, EMS and disk are
included) are derived from the pure abstract base class MemoryObject.
MemoryObject is a "lock-and-load" memory object. To use, you allocate()
the desired memory amount (this version only supports 1-65535 bytes per
allocation). If allocate() passes (returns non-zero), then your memory block
has been allocated, but is not necessarily ready to use. To access the
memory block as a void far *, you call lock(). This will either return a
pointer to the memory block, or 0 if it failed to lock the block. For a
MemConventional type memory (conventional memory), lock() should never fail
(unless you never allocated memory). For MemEMS type memory (EMS memory),
lock() can fail for one reason: EmsMemory::lock() could not locate enough
contiguous frame buffer pages to hold the pages that contain the block of
memory. This is an inherent restriction for EMS memory. EMS has a 64K 'frame'
buffer located in conventional memory space, which actually comprises four
16K 'pages'. When you want to access a particular portion of EMS memory,
you need to 'map' the 16K page that holds that data into one of these pages.
Since EmsMemory supports up to 65535 bytes/alloc, that means its conceivable
that to lock this block in, it has to use all 4 frame buffer pages. But if
you have previously lock()'d an EmsMemory object, its using at least one of
these pages - so the lock fails. The lesson here is to lock a block, use it,
and unlock it again as soon as you can. For MemDisk type (disk memory), lock
will fail if MemDisk::lock() cannot lock either a new ConvMemory type block,
or a EmsMemory type block. Since DiskMemory type memory resides in a disk
file, it has to be loaded __somewhere__ in memory for you to access it -
thats what the ConvMemory and EmsMemory allocations are for. And, therefore,
this has to go OK for you to have a memory block available to load the disk
data in.
To tie these classes into one memory manager, I've included a primitive
class called VMemManager. Basically, all this class does is automatically
step through all 3 types of memory trying to allocate a block. It has a
allocScheme member that you can set to one of the following:
ConvEmsDisk : try conventional, EMS, then disk.
ConvDiskEms : try conventional, disk, then EMS.
EmsConvDisk : try EMS, conventional, then disk.
EmsDiskConv : try EMS, disk, then conventional.
DiskConvEms : try disk, conventional, then EMS.
DiskEmsConv : try disk, EMS, then conventional.
This all may sound confusing, but it needn't be. To just __use__ these
classes, all you need to do is the following:
1) instantiate a memory object.
Example: EmsMemory ems;
2) allocate some memory, and ensure that it passed.
Example: if( !ems.allocate(10000) ) {... // failed }
Note: using VMemManager, these 2 steps are combined:
Example:MemoryObject *mem = VMemManager::allocate(10000);
if( mem == 0 ){... // failed }
3) Forgot how big the memory block was?
Example:size_t sz = ems.memSize();
4) When you need to access this memory, lock it; make sure it passed.
Example: void far *ptr = ems.lock();
if( ptr != 0 ){...}
5) When you're done with it, unlock the memory.
6) When you no longer need the memory, free it (it must be unlocked).
7) Want to know what the largest block of ems you can allocate is?
Example:long emsAvail = EmsMemory::maxAvail();
8) Want to know what the total free ems avail is (not necessarily contiguous)
Example:long emsTotal = EmsMemory::memAvail();

That's it! The included program test.cpp shows an example of allocating
800,000 bytes using VMemManager.

Like I said, this is still a primitive memory manager. It does not have
methods to perform defragmentation (tho' the lock-and-load method makes this
fairly simple to implement). But it __does__ work.
Pat Reilly

 December 6, 2017  Add comments

Leave a Reply