Posted By: sayza (sayza) on 'CZprogram'
Title:     multitask source
Date:      Sun Feb 16 12:58:41 1997


 Hi programatori,

pred casom som robil s kamosom zadanie do skoly z predmetu TOS. Tvorba
Operacnych Systemov. Mno, OS sme sice ziaden nespravili, ale zato sa mi
podarilo nakodovat malu kuriozitku. Ono mi to az po case doslo, ze je to
vlastne somarina ale funguje to, takze pre vsetkych, co maju zaujem a su
zvedavi, pripajam k tomuto postu komplet zdrojovy kod. Je to v Borland
C++ 3.1 (jeden maly modul). A co to vlastne je? Zadanie znelo urobit
preemptivny multitasking. A prave to robi. Nic viac a nic menej. Jednoducho
to nacita z disku jeden COM subor (patricne jednoduchy, lebo moj 'kernel'
neswapuje obrazovku ani nic podobne, ved bezi v real mode) a ten dajme tomu
spusti 20x v pamati a prepina medzi procesami (napr. frekvenciou 200Hz).
Viem, ze to nie je nic moc ako program, ale hadzem to sem hlavne kvoli
zberatelom kuriozit, zaciatocnikom a microsoftu. Pripajam aj jeden vzorovy
COM subor (assembler) ako vzorovy proces pre to 'jadro' v cecku. Ovladanie
programu je jasne zo zdrojaku. ('1' - insertprocess, 'ESC' - koniec)

    be Happy
                                                                sayza

PS: Skoro som zabudol ... treba pouzit LARGE model ;)  (bcc -ml)
----------------------------------------------------------------------------
source PM.CPP, preklad bcc -ml PM.CPP
----------------------------------------------------------------------------
/*
1. Procesom sa vyhradi pamat a nacita sa proces PROCESS.COM
2. Vlozi sa prvy proces
3. inicializuje sa obsluha prerusenia
4. preda sa riadenie casovacu

LOOP
1. pri preruseni sa zisti, ci sa prerusil nejaky proces
        (sluzby OS a BIOS sa neprerusuju)
   preda sa riadenie inemu procesu
2. ak sa stlaci klavesa '1' => insert noveho procesu
4. ak sa stlaci klavesa ESC => preda sa riadenie naspat MAINu
*LOOP

8. uvolnenie pamati a obsluhy prerusenia
*/

#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <stdlib.h>
#include <io.h>

typedef struct _REGISTERS {
        unsigned bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
} REGISTERS;

typedef struct _PCB {
    REGISTERS  reg;
        unsigned   priority;
} PCB;

#define MK_LINEAR(px) ( (long(FP_SEG(px))<<4) + long(FP_OFF(px)) )

#ifdef __cplusplus
        #define __CPPARGS ...
#else
        #define __CPPARGS
#endif

#define PROCESS_LENGTH 256

#define MAX_PROCESS 25
PCB procesy[MAX_PROCESS]; //fronta procesov
int nprocess,curprocess;

char *pmemoryBase,*pmemoryLast,*pmemoryAlloc;
long plinearBase,plinearLast;  //segment*16+offset
char *process;

char maincall,done=0;

void InsertProcess(void);
// obsluha prerusenia **************************************
void interrupt ( *oldtimer)(__CPPARGS);
void interrupt ( *oldkeyboard)(__CPPARGS);

REGISTERS *stackr;
REGISTERS mainr;

#define ACKRET {   
 outportb(0x20,0x20); 
 return;                   
}

long linear;

void interrupt _timer_handler(__CPPARGS) {

// nastavim smernik tam, kde cecko pushlo registre
        stackr = (REGISTERS *)MK_FP(_SS,_SP);

    enable();
// ak som prerusil main (IBA raz) tak savnem jeho registre
// a prejdem na curprocess
        if (maincall) {
        maincall=0;
        mainr = *stackr;
        *stackr = procesy[curprocess].reg;
        return;
    }

// skontroljem, ci som prerusil moj proces
    linear = (long(stackr->cs)<<4) + long(stackr->ip);
        if (linear<plinearBase || linear>=plinearLast) ACKRET;

// koncime ....
    if (done) {
        *stackr = mainr;
        ACKRET;
    }

// skopirujem tieto registre do struktury aktualneho PCB
        procesy[curprocess].reg = *stackr;
        if (++curprocess>=nprocess) curprocess=0;
        *stackr = procesy[curprocess].reg;

    ACKRET;
}

void interrupt _keyboard_handler(__CPPARGS) {

    unsigned char al = inportb(0x60);

    if (al==1) done=1;                  // ESC
    if (al==2) InsertProcess();        // '1'

    al = inportb(0x61);
    outportb(0x61,al | 0x80);
    outportb(0x61,al);

    ACKRET;
}

void settimer(unsigned freq) {

    unsigned tim;

    if (freq==0) tim=0; else tim=0x1234DDlu/freq;

    outportb(0x43,0x34);
    outportb(0x40,tim&0xFF);
    outportb(0x40,tim>>8);
}

void main() {

    FILE *f;

    textmode(C80);
    clrscr();
// pridelenie pamati procesom (pre jednoduchost vsetkym naraz)
    pmemoryAlloc = (char *)malloc (64000); // cca jeden segment
    if (pmemoryAlloc==NULL) {
        puts("Neda sa alokovat 64000 bytov");
        return;
    }

// borland C++ alokuje ako SEGMENT:4, zarovnam teda pamat na hranicu segmentu
    pmemoryBase=(char *)MK_FP(FP_SEG(pmemoryAlloc)+1,0);
    pmemoryLast=pmemoryBase;
    plinearBase=MK_LINEAR(pmemoryBase);
    plinearLast=plinearBase;

// nacitanie procesu do pamati (aby sa zakazdym necital v preruseni)
// procesu sa potom vyhradi 256 bytov + 256 bytov hlavicka (COM subor)
    process = (char *)malloc(256+PROCESS_LENGTH);
    if ((f=fopen("process.com","rb"))==NULL) return;
    fread(process+256,filelength(fileno(f)),1,f);
    fclose(f);

// vytvorenie jedneho PCB a jedneho procesu
    nprocess=curprocess=0;
    InsertProcess();

    maincall=0;
// instalacia obsluhy prerusenia
    oldkeyboard = getvect(0x9);
    setvect(0x9, _keyboard_handler);
    oldtimer = getvect(0x8);
    setvect(0x8, _timer_handler);

    settimer(100);

    maincall=1;
    geninterrupt(0x8);      // umelo vytvorene prerusenie casovaca
                           // tymto sa MAIN vzdava kontroly nad systemom :))

    settimer(0);
    setvect(0x9,oldkeyboard);
    setvect(0x8,oldtimer);
    free(pmemoryAlloc);
    clrscr();
}

#include <mem.h>
void InsertProcess(void) {

    if (nprocess>=MAX_PROCESS) return;

// pridelenie pamati
// skopirujem proces do pamati a zmenim mu PID na adrese CS:0
   memcpy(pmemoryLast,process,PROCESS_LENGTH+256);
    *pmemoryLast = nprocess;

// nastavim mu inicializacne registre
    memset(&procesy[nprocess].reg,0,sizeof(REGISTERS));
    procesy[nprocess].reg.cs=FP_SEG(pmemoryLast)+FP_OFF(pmemoryLast)/16;
    procesy[nprocess].reg.ds=procesy[nprocess].reg.es=procesy[nprocess].reg.cs;
    procesy[nprocess].reg.ip=0x100;
    procesy[nprocess].reg.flags=0x3256;             // nejake rozumne flagy

    pmemoryLast+=PROCESS_LENGTH+256;
    plinearLast+=PROCESS_LENGTH+256;
    nprocess++;
}

----------------------------------------------------------------------------
source PROCESS.ASM, preklad tasm /m2 PROCESS.ASM, tlink /t /x PROCESS.OBJ
----------------------------------------------------------------------------

;-------------------------------------------------------------------------
Code    SEGMENT
        ASSUME  CS:Code,DS:Code

__start:
    org     100h
.286
;-------------------------------------------------------------------------
;STANDALONE EQU 1
LOOPCOUNT  EQU 8;00     ; toto je experimentalne nastavena hodnota ...

_start:
    jmp   _main

hlaska  DB  ' Vobec ma netesi, ze som proces '      ;// CO PROCES VYPISUJE
pid     DB ?
_endln  LABEL BYTE                     ;// ukoncuje hlasku

dlzka   DW OFFSET _endln - OFFSET hlaska    ;// dlzka hlasky

stlpec  DW ?          ;// na ktorom stlpci je scroll
zaciatokriadku DW ?
koniecriadku   DW ?   ;// adresa konca riadku

_main:
;// proces si DS na svoj segment
    push  cs
    pop   ds

;// proces si nastavi PID ako znak (PID je na adrese CS:0)
    mov   al,ds:[0]
    add   al,'A'
    mov   [pid],al

;// nastavi ES:BX na obrazovku
    mov   ax,0B800h
    mov   es,ax
    mov   al,160                ;// kolko bytov je na riadok
    mov   bl,ds:[0]             ;// * poradie = offset
    mul   bl
    mov   [zaciatokriadku],ax   ;// mam adresu zaciatku riadka
    add   ax,160
    mov   [koniecriadku],ax

    mov   [stlpec],0

;// ... a zacne scrollovat
loopscroll:
    mov   cx,[dlzka]
    mov   si,OFFSET hlaska
    mov   di,[zaciatokriadku]
    mov   ax,[stlpec]
    shr   ax,8
    add   di,ax
    add   di,ax
print:
    movsb
    inc   di
    dec   cx
    jz    koniecvypisu
    cmp   di,[koniecriadku]
    jb    print
    mov   di,[zaciatokriadku]
    jmp   print

koniecvypisu:
IFDEF STANDALONE
    mov   ah,1
    int   16h
    jnz   quit
ENDIF
    mov   cx,LOOPCOUNT
cakaj:
    loop  cakaj

    inc   [stlpec]
    cmp   [stlpec],80*256
    jb    loopscroll
    mov   [stlpec],0
    jmp   loopscroll

;// sem sa to pri multitaskingu nikdy nedostane
quit:
    mov   ax,0
    int   16h
    mov   ah,4ch
    int   21h
;-------------------------------------------------------------------------
Code ENDS
END _start

Search the boards