Subversion Repositories shark

Rev

Blame | Last modification | View Log | RSS feed

/* Project:     OSLib
 * Description: The OS Construction Kit
 * Date:                1.6.2000
 * Idea by:             Luca Abeni & Gerardo Lamastra
 *
 * OSLib is an SO project aimed at developing a common, easy-to-use
 * low-level infrastructure for developing OS kernels and Embedded
 * Applications; it partially derives from the HARTIK project but it
 * currently is independently developed.
 *
 * OSLib is distributed under GPL License, and some of its code has
 * been derived from the Linux kernel source; also some important
 * ideas come from studying the DJGPP go32 extender.
 *
 * We acknowledge the Linux Community, Free Software Foundation,
 * D.J. Delorie and all the other developers who believe in the
 * freedom of software and ideas.
 *
 * For legalese, check out the included GPL license.
 */


/*      Stupid Scheduling Demo  */

#include <ll/i386/cons.h>
#include <ll/i386/tss-ctx.h>
#include <ll/i386/error.h>
#include <ll/sys/ll/ll-instr.h>
#include <ll/sys/ll/ll-func.h>
#include <ll/sys/ll/time.h>
#include <ll/sys/ll/event.h>
#include <ll/stdlib.h>

#define FREE 0
#define IDLE 1

struct ctx {
    WORD ll;
    struct timespec time;
    DWORD cputime;
    DWORD toexec;
    int acc;
    DWORD slice;
    int state;
};

struct trkevt {
    int thread;
    DWORD time;
    int value;
};

struct trkevt track[10000];

DWORD cpu[] = { 5000, 2000, 10000, 500, 5000, 6000, 20000, 1000, 7000 };
DWORD p[] =
    { 100000, 50000, 100000, 5000, 20000, 30000, 200000, 200000, 35000 };

#define STACK_SIZE      100000U /* Stack size in bytes          */
#define USE_FPU         0x0001

WORD th1, thm;

#define T 1000

#if 1
#define TO     ll_context_to
#define FROM   ll_context_from
#else
#define TO     ll_context_load
#define FROM   ll_context_save
#endif

/* For stack allocation checking */
BYTE stacks[STACK_SIZE];
#define N 10

struct ctx context[N];
int exec;



void endProg(void *p)
{
    int i;
    DWORD last[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    DWORD lasttime, lastthread;

    lasttime = 0;
    lastthread = 0;
    for (i = 0; i < 120; i++) {
        if (last[track[i].thread] != 0) {
            if (lastthread == 3) {
                message("Thread %d <-- time %lu (after %lu), Thread %lu executed for %lu --- %d\n",
                     track[i].thread, track[i].time,
                     track[i].time - last[track[i].thread], lastthread,
                     track[i].time - lasttime, track[i].value);
            }
        }
        lastthread = track[i].thread;
        last[track[i].thread] = track[i].time;
        lasttime = track[i].time;
    }

    ll_abort(110);
}

int schedule(void);


void endBudget(void *p)
{
    struct ctx *c = p;
    struct timespec time, toexec, xcuted, start;
    int newthread;

    ll_gettime(TIME_NEW, &time);
    NULL_TIMESPEC(&toexec);
    ADDNANO2TIMESPEC(c->toexec, &toexec);
    SUBTIMESPEC(&(c->time), &toexec, &start);
    SUBTIMESPEC(&time, &start, &xcuted);
    NULL_TIMESPEC(&toexec);
    ADDNANO2TIMESPEC(c->cputime * 1000, &toexec);
    SUBTIMESPEC(&xcuted, &toexec, &start);
    c->acc += TIMESPEC2NANOSEC(&start);

    newthread = schedule();
    TO(context[newthread].ll);
}

int schedule(void)
{
    static int k = 0;
    int toe;
    int done;

    done = 0;
    while (!done) {
        exec = (exec + 1) % N;
        while (context[exec].state == FREE) {
            exec = (exec + 1) % N;
        }
/*
                track[k].thread = exec;
                track[k].value = context[exec].acc;
                track[k].time = ll_gettime(TIME_NEW, &(context[exec].time));
                k++;
*/

        ll_gettime(TIME_NEW, &(context[exec].time));
        toe = (context[exec].cputime * 1000 - context[exec].acc);
        if (toe <= 0) {
            context[exec].acc -= (context[exec].cputime * 1000);
            k--;
        } else {
            done = 1;
        }
    }
    context[exec].toexec = toe;
    ADDNANO2TIMESPEC(toe, &(context[exec].time));
    event_post(context[exec].time, endBudget, &(context[exec]));
    return exec;
}

void thread(void *p)
{
    int i, ii;
    int position = 0;
    char mark[11];
    int active = 1;
    WORD count = 0;

    i = *(int *) p;
    while (active) {
/*
                printf_xy(10, i * 2 + 1, WHITE, "%c", mark);
*/

        count++;
        position = (position + 1) % 10;
        for (ii = 0; ii < 10; ii++) {
            mark[ii] = ' ';
        }
        mark[10] = 0;
        mark[position] = 'O';
        printf_xy(10, i * 2 + 1, WHITE, "%s", mark);
        printf_xy(25, i * 2 + 1, WHITE, "%d %u", i, count);
        for (ii = 0; ii < 10000; ii++);

        if (count == 1000)
            active = 0;
    }
    printf_xy(20, i * 2 + 1, WHITE, "Finished %d", i);
}

void killer(void)
{
    int th;

    cli();
    context[exec].state = FREE;
    th = schedule();
    sti();
    TO(context[th].ll);
}

int main(int argc, char *argv[])
{
    DWORD sp1, sp2;
    struct ll_initparms parms;
    void *mbi;
    DWORD t, oldt, secs;
    int th;
    int i;
    int pars[N];
    struct timespec endTime;

    sp1 = get_SP();
    cli();
    parms.mode = LL_ONESHOT;
    parms.tick = T;

    mbi = ll_init();
    event_init(&parms);

    if (mbi == NULL) {
        message("Error in LowLevel initialization code...\n");
        sti();
        l1_exit(-1);
    }
    message("LowLevel started...\n");
    for (i = 0; i < N - 1; i++) {
        pars[i] = i;
        context[i].ll =
            ll_context_create(thread, &stacks[STACK_SIZE * (i + 1) / N],
                              &(pars[i]), killer, 0);
        if (context[i].ll == 0) {
            error("Unable to create thread");
            ll_abort(100);
        }
        context[i].state = IDLE;
        context[i].cputime = cpu[i];
        context[i].toexec = cpu[i];
        context[i].acc = 0;
        context[i].slice = p[i];
    }

    context[N - 1].ll = FROM();
    context[N - 1].state = IDLE;
    context[N - 1].cputime = 200;
    context[N - 1].slice = 20000;

    message("All Threads created...\n");
    NULL_TIMESPEC(&endTime);
    endTime.tv_sec = 30;

    event_post(endTime, endProg, NULL);
    sti();

    cli();
    th = schedule();
    sti();

    TO(context[th].ll);

    message("Thread MAIN restartin'\n");

    secs = 0;
    oldt = 0;
    while (secs <= 20) {
        cli();
        t = ll_gettime(TIME_NEW, NULL);
        sti();
        if (t < oldt) {
            message("ARGGGGG! %lu %lu\n", t, oldt);
            ll_abort(99);
        }
        oldt = t;
        if ((t / 1000000) > secs) {
            secs++;
            printf_xy(40, 20, WHITE, "%lu     %lu    ", secs, t);
        }
    }
    message("\n DONE: Secs = %lu\n", secs);

    cli();
    ll_end();
    sp2 = get_SP();
    message("End reached!\n");
    message("Actual stack : %lx - ", sp2);
    message("Begin stack : %lx\n", sp1);
    message("Check if same : %s\n", sp1 == sp2 ? "Ok :-)" : "No :-(");
    return 1;
}