home *** CD-ROM | disk | FTP | other *** search
- /*=======================================================*/
- /* VCOPY.C */
- /* Copyright (C) 1993 Thomas Wölker und DMV-Verlag */
- /*-------------------------------------------------------*/
- /* Compiler: Microsoft C/C++ 7.0 */
- /* Funktion: Beispiel für die Verwendung des virtuellen */
- /* Memory Managers unter MSC 7.00 / DOS */
- /* Das Programm kopiert unter Verwendung des */
- /* VMM Dateien an einem Stück. Zu diesem Zweck */
- /* wird eine verkettete Liste von 32 KByte */
- /* großen Blöcken aus virtuellen Speicherhand- */
- /* les erzeugt. Die gesamte Sourcedatei wird */
- /* zunächst gelesen (in den virtuellen Heap) */
- /* und dann aus dem virtuellen Heap wieder */
- /* geschrieben. Dies ist zwar nicht gerade eine*/
- /* tolle Anwendung (vor allem, wenn man nur */
- /* sehr wenig XMS/EMS hat) demonstriert aber */
- /* die Handhabung der _vmemory-Funktionen doch */
- /* ganz gut. */
- /*=======================================================*/
-
- #include <vmemory.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <io.h>
- #include <sys\types.h>
- #include <sys\stat.h>
- #include <dos.h>
- #include <bios.h>
- #include <malloc.h>
- #include <conio.h>
- #include "vcopy.h"
-
- /*-------------------------------------------------------*/
- /* Name: main */
- /* Funktion: Eintrittspunkt */
- /* Der 1. Parameter ist die zu kopierende Da- */
- /* tei, der 2. der Name der Zieldatei. */
- /* Achtung: Eine bereits vorhandene Datei wird über- */
- /* schrieben). Gibt es einen dritten Parm, so */
- /* werden noch Debuginformationen */
- /* ausgegeben. */
- /*-------------------------------------------------------*/
- BOOL isDebug = FALSE;
-
- #define Use "Usage: vcopy src dest [debug]"
-
- void main(
- int argc, // Argument-Counter
- char * argv[]) // Argumentvektor
- {
- WORD nRet;
- if (argc == 4) isDebug = TRUE;
- if (argc < 3) exit(printf("\n%s", Use));
- nRet = Copy(argv[1], argv[2]);
- /*--------------------------------------------*/
- /* an dieser Stelle sollte man den Returnwert */
- /* komplett abtesten und auswerten */ */
- /*--------------------------------------------*/
- if (nRet != CP_OK) printf("\nFehler in copy()");
- exit(0);
- }
-
- /*-------------------------------------------------------*/
- /* Name: Copy */
- /* Funktion: Kopiert File Src nach Dest */
- /*-------------------------------------------------------*/
- WORD Copy(
- char * pszSrc, // Quelle
- char * pszDest ) // Ziel
- {
- int hSrc, hDest; // Quell- und Zieldatei
- long cSrcSize, // Größe der Source
- cToRead, // Noch zu lesende Bytes
- cRead; // Bereits gelesene Bytes
- int nReturn; // Return von VLRead
- VMROOT vmRoot; // Root der VL des VMM
- size_t cWritten; // Geschriebene Bytes
- unsigned iBlocks; // Index in Blöcken
-
- hSrc=_open( // Sourcefile öffnen
- pszSrc, // Name des Files
- _O_RDONLY|_O_BINARY // Open Mode
- );
-
- if (hSrc == -1) // Fehler beim Öffnen?
- return CP_ERROPENSOURCE; // zurück
- hDest = _open( // Ziel öffnen
- pszDest, // Name des Ziels
- _O_WRONLY |
- _O_BINARY |
- _O_CREAT |
- _O_TRUNC,
- _S_IREAD |
- _S_IWRITE); // Modus
- if (hDest == -1) // Fehler beim Öffnen
- {
- _close(hSrc); // Source schließen
- return CP_ERROPENDEST; // Fehler zurück
- }
- cSrcSize=_filelength(hSrc); // Größe der Quelldatei
- // Erste zu lesende
- // Blockgröße bestimmen
- if (cSrcSize <= CP_BLOCKSIZE) // Datei paßt komplett
- { // in Block
- cToRead = cSrcSize;
- }
- else // Datei braucht mehrere
- { // Blöcke
- cToRead = CP_BLOCKSIZE;
- }
- cRead = 0L; // Anzahl bisher gelesen = 0
- do // Ersten Block lesen
- {
- if ((nReturn = VLRead(hSrc, cToRead, &vmRoot))
- != CP_OK)
- { // Hier ist ein Fehler aufgetreten
- _close( hSrc ); // Source schließen
- _close( hDest ); // Ziel schließen
- VLPanicAbort( vmRoot ); // PANIK !
- return nReturn; // Fehler zurück
- }
- cRead += cToRead; // Gelesene Bytes erhöhen
- // Nächste Blockgröße festlegen
- if ((cRead + cToRead) > cSrcSize)
- cToRead = cSrcSize - cRead;
- } while (cToRead != 0);
- // Dest schreiben
- vmRoot.pAct = vmRoot.pFirst;
- // Alle Blöcke schreiben
- for (iBlocks = 0;
- iBlocks < vmRoot.cBlocks;
- iBlocks++)
- {
- int __far *pMem;
- // Speicherblock verriegeln
- if ((pMem = (int __far*)_vlock(vmRoot.pAct -> hVM))
- == NULL)
- {
- VLPanicAbort(vmRoot);
- return CP_ERRLOCK;
- }
-
- cWritten = _write( // Block schreiben
- hDest,
- pMem,
- (unsigned)
- (vmRoot.pAct -> cSize));
- // Hier wird getestet, ob geschriebene Größe
- // ungleich der gewollten Größe ist
- if (cWritten != (size_t) (vmRoot.pAct -> cSize))
- {
- VLPanicAbort(vmRoot);
- return CP_ERRWRITE;
- }
- // Block wieder entriegeln
- _vunlock(vmRoot.pAct -> hVM, _VM_CLEAN);
- // Nächster Block
- vmRoot.pAct = vmRoot.pAct -> pNext;
- }
- _close(hSrc); // Source schließen
- _close(hDest); // Ziel schließen
- // Liste deinitialisieren
- if (! VLDeinit( vmRoot)) return CP_ERRVLDEINIT;
- return CP_OK; // OK zurück
- }
-
- /*-------------------------------------------------------*/
- /* Name: VLRead */
- /* Funktion: Liest einen Block aus der Quelldatei in */
- /* einen Speicherbereich des virtuellen */
- /* Speichermanagers */
- /*-------------------------------------------------------*/
- WORD VLRead(
- int hFile, // Filehandle
- long cBlockSize, // Blockgröße
- VMROOT * vmr) // VL-VMM Rootptr
- {
- VMNODE * pvmNode; // Zeiger auf einen Knoten
- static BOOL isFirst = TRUE; // Flag, ob Erster Knoten
- if (isFirst) // Wenn erster ...
- {
- if (! VLInit(vmr)) // Liste init
- {
- return CP_ERRVLINIT; // Falls Fehler... zurück
- }
- isFirst = FALSE; // Flag zurück
- }
- // weiteren Block anfordern
- pvmNode = VLAddBlock(vmr, cBlockSize);
- if (pvmNode == (VMNODE*)NULL) return CP_ERRVMALLOC;
- // Block einlesen
- if (VLReadBlock(
- pvmNode,
- hFile,
- cBlockSize) != CP_OK)
- return CP_ERRVLREAD;
- return CP_OK;
- }
-
- /*-------------------------------------------------------*/
- /* Name: VLInit */
- /* Funktion: Initialisiert die verkettete Liste aus */
- /* VMSpeicherblöcken. Dabei tritt ein */
- /* interessantes Problem auf: Microsoft sagt */
- /* in der »Runtime Lib Reference«, daß die */
- /* ersten beiden Paramter von _vheapinit */
- /* Größen in Paragraphen angeben, sagen aber */
- /* netterweise nicht, wie groß so ein Para- */
- /* graph wohl sein mag. */
- /* Wird für DOSMAX _VM_ALLDOS verwendet, hat */
- /* man das Problem, daß vom Heap praktisch */
- /* nichts mehr überbliebt. Auf diese Weise */
- /* versagt das malloc für die einzelnen Nodes */
- /* extrem schnell, da der MemMgr den gesamten */
- /* Heap für sich beansprucht. */
- /* Mit den hier verwendeten Parametern stehen */
- /* nach dem Init noch etwa 30 K für malloc zur */
- /* Verfügung. Dies führt zu der Rechnung, daß */
- /* bei etwa 630 K freiem Speicher (DOS 5, */
- /* 386Max) 30-KByte-Exefile (mit CV info) ein */
- /* Paragraph wohl ca. 18 Byte groß sein muß... */
- /*-------------------------------------------------------*/
- BOOL VLInit(VMROOT *pRoot ) // RootZeiger
- {
- // Alles fürs swappen benutzen
- if (_vheapinit(
- 2048, // 32 KBytes in Paragraphen
- 32000, // 512 KBytes in Paragraphen
- _VM_ALLSWAP) == 0)
- {
- return FALSE;
- }
- // Liste initialisieren
- pRoot -> cBlocks = 0;
- pRoot -> pFirst = (VMNODE*)NULL;
- pRoot -> pAct = (VMNODE*)NULL;
- return TRUE;
- }
-
- /*-------------------------------------------------------*/
- /* Name: VLAddBlock */
- /* Funktion: Versucht zunächst eine neue Node auf dem */
- /* Heap zu allozieren.Wenn dies gelingt, wird */
- /* in dieser Node ein Speicherblock über den */
- /* VM angefordert. Gelingt dies, wird die Node */
- /* in die Liste eingefügt. */
- /*-------------------------------------------------------*/
- VMNODE * VLAddBlock(
- VMROOT *pRoot, // Root-Zeiger
- long cSize ) // Blockgröße
- {
- // letzer Knoten
- static VMNODE * pLast = (VMNODE*)NULL;
- // Speicher für einen Knoten holen
- pRoot -> pAct = (VMNODE*)malloc(sizeof(VMNODE));
- // Speicherstatistik anzeigen
- MemoryStatistics(); // Testen, ob Speicher vorhanden
- if (pRoot -> pAct == (VMNODE*)NULL)
- {
- return (VMNODE*)NULL; // Fehler zurück
- }
- // Versuchen, einen Speicherblock der
- // benötigten Größe zu bekommen
- if ((pRoot -> pAct -> hVM = _vmalloc(
- cSize)) == _VM_NULL)
- {
- // Wenns nicht ging, auch die Node freigeben
- free(pRoot -> pAct);
- return (VMNODE*)NULL; // Und Fehler zuück
- }
- pRoot -> cBlocks++; // Blockzahl erhöhen
- pRoot -> pAct -> cSize=cSize; // Größe des Blocks merken
- // Informationen über diesen Block anzeigen
- BlockStatistics(pRoot -> pAct, pRoot -> cBlocks);
- // Wenn dies die 1. Node ist ...
- if (pRoot -> cBlocks == 1)
- {
- pRoot -> pFirst = pRoot -> pAct; // ... pFirst merken
- }
- else // ... sonst ...
- { // ... Node in Liste einfügen
- pLast -> pNext = pRoot -> pAct;
- }
- pLast = pRoot -> pAct; // aktuelle merken
- return pLast; // und zurück damit
- }
-
- /*-------------------------------------------------------*/
- /* Name: VLReadBlock */
- /* Funktion: Liest einen Block aus der Datei in einen */
- /* Block des VMM */
- /*-------------------------------------------------------*/
- WORD VLReadBlock(
- VMNODE *pNode, // Knotenzeiger
- int hFile, // Filehandle
- long cSize ) // Blockgröße
- {
- // Pointer to VM-Block in FAR Dos Memory
- int __far *pMem;
- // Lock the block
- if((pMem = (int __far *)_vlock(pNode -> hVM)) == NULL)
- {
- return CP_ERRLOCK; // Return attempt failure
- }
- // Versuch, Datei einzulesen
- if ( _read( // Lesen
- hFile, // da raus
- pMem, // da rein
- (unsigned)cSize // soviel
- ) == -1)
- return CP_ERRVLREAD; // Fehler
- _vunlock( pNode->hVM, _VM_DIRTY ); // Unlock the Block
- return CP_OK; // OK zurück
- }
-
- /*-------------------------------------------------------*/
- /* Name: VLDeinit */
- /* Funktion: Deinitialisiert die Liste aus VM-Blöcken. */
- /* Dazu wird einfach jede einzelne Node an- */
- /* gelaufen, deren VM Handle freigegeben und */
- /* dann die Node dem Heap der Laufzeit zurück- */
- /* gegeben. */
- /*-------------------------------------------------------*/
- BOOL VLDeinit(VMROOT vmRoot) // Root Object
- {
- VMNODE * pNext; // Nächstes Element
- unsigned iBlocks; // Index in Blöcke
- vmRoot.pAct = vmRoot.pFirst;
- for (iBlocks = 0;
- iBlocks < vmRoot.cBlocks;
- iBlocks++ )
- {
- pNext = vmRoot.pAct->pNext;
- MemoryStatistics();
- BlockStatistics(vmRoot.pAct, iBlocks + 1);
- // wenn der Block noch gelocked ist,
- // ist irgendwas faul
- if (_vlockcnt(vmRoot.pAct -> hVM)) return FALSE;
- _vfree(vmRoot.pAct->hVM); // Free Node
- free(vmRoot.pAct);
- // Und weiter ...
- vmRoot.pAct = pNext;
- }
- _vheapterm(); // terminate the Mem Mng
- return TRUE;
- }
-
- /*-------------------------------------------------------*/
- /* Name: VLPanicAbort */
- /* Funktion: Gibt nur eine kurze Meldung aus, falls es */
- /* Probleme mit dem VM geben sollte */
- /*-------------------------------------------------------*/
- void VLPanicAbort(VMROOT vmRoot) // Root Objekt
- {
- printf("\nInside Panic abort");
- printf("\n%u Blocks to release", vmRoot.cBlocks);
- }
-
- /*-------------------------------------------------------*/
- /* Name: BlockStatistics */
- /* Funktion: Gibt einige Informationen über einen Block */
- /* in der VL der Blöcke aus */
- /*-------------------------------------------------------*/
- void BlockStatistics(
- VMNODE* pvmNode, // Zeiger auf Knoten
- unsigned nNode ) // Knotennummer
- {
- if (isDebug)
- printf("\nNode#:%u Adress:%p"
- "Handle:%lu LockCount:%u"
- "Size:%u",
- nNode,
- pvmNode,
- pvmNode -> hVM,
- _vlockcnt(pvmNode -> hVM),
- _vmsize(pvmNode -> hVM)
- );
- }
- /*-------------------------------------------------------*/
- /* Name: MemoryStatistics */
- /* Funktion: Gibt Informationen über den freien Heap aus.*/
- /* Die Runtime Library enthält leider keine */
- /* Funktion, mit der man die Größe des freien */
- /* Heaps ermitteln kann. DOS liefert aber */
- /* netterweise genau diese zurück, falls man */
- /* mit der Funktion 48 0xFFFF Speicher an- */
- /* fordert. Gibt weiterhin Informationen über */
- /* den Stack aus. */
- /*-------------------------------------------------------*/
- void MemoryStatistics(void)
- {
- if (isDebug)
- {
- long cMemory; // Freier Heap
- union REGS inregs, outregs;
- inregs.h.ah = 0x48; // Funktion
- inregs.x.bx = 0xFFFF; // Speicheranforderungsgröße
- // (schlägt immer fehl!;
- // aber das soll so sein)
- intdos(&inregs, &outregs); // Ab mit dem Interrupt
- // So, jetzt ist der freie
- // Heap bekannt
- cMemory = (long)outregs.x.bx;
- cMemory = cMemory * (long)16;
- printf("\nHeap: %lu Stack:%u", cMemory, _stackavail());
- }
- }
-
- /*=======================================================*/
- /* Ende von VCOPY.C */
-