⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 coroutin.cpp

📁 多任务操作系统控制的DOS环境下的实现的C语言源程序。 利用时间片的方式
💻 CPP
字号:
//--------------------------------------------------------------------------
//
//      COROUTINE.CPP: body of DOS coroutine library.
//      Copyright (c) J.English 1993.
//      Author's address: je@unix.brighton.ac.uk
//
//      Permission is granted to use copy and distribute the
//      information contained in this file provided that this
//      copyright notice is retained intact and that any software
//      or other document incorporating this file or parts thereof
//      makes the source code for the library of which this file
//      is a part freely available.
//
//--------------------------------------------------------------------------
//
//      Note: this library is highly DOS specific and hence non-portable.
//      It also involves the use of assembly language and interrupt
//      functions, so it is also very compiler-specific and will need
//      modification for use with compilers other than Borland C++.
//
//      Revision history:
//      1.0     April 1993      Initial coding
//      1.1     June 1993       Added wait, terminate; tidied private data
//                              Minor changes to schedule.
//
//--------------------------------------------------------------------------

#include "coroutine.h"
#include <dos.h>


//--------------------------------------------------------------------------
//
//      Constants.
//
const unsigned MIN_STACK  = 512;                // minimum stack size


//--------------------------------------------------------------------------
//
//      Global (static) variables.
//
static CoroutineManager* current   = 0; // current coroutine
static CoroutineManager* nextentry = 0; // current coroutine
static Coroutine*        mainitem  = 0; // coroutine for execution of "main"
static unsigned          mainsetup = 0; // flag set when constructing "main"
static volatile unsigned count     = 0; // number of active coroutines


//--------------------------------------------------------------------------
//
//      Class MainCoroutine.
//
//      A minimal derivation of Coroutine used for the main task.
//
class MainCoroutine : public Coroutine
{
  public:
    MainCoroutine ()    : Coroutine (MIN_STACK)     { }
    
  protected:
    virtual void main ()                            { }
};

//--------------------------------------------------------------------------
//
//      Class CoroutineManager.
//
//      This is a support class used for maintaining the coroutine queue.
//      The queue is represented as a circular list of CoroutineManagers.
//
class CoroutineManager
{
  public:
    CoroutineManager (Coroutine* t);
    ~CoroutineManager ()                  { delete stack; }

    CoroutineManager* next;               // next entry in list
    CoroutineManager* prev;               // previous entry in list
    Coroutine*        coroutine;          // coroutine for this entry
    char*             stack;              // coroutine stack area
    unsigned          sp,ss;              // coroutine stack pointer

    static void far start (Coroutine* t); // execute coroutine and then die

    static void create ();                // register coroutine creation
    static void destroy ();               // register coroutine destruction

    static void interrupt schedule ();    // schedule next coroutine
};


//--------------------------------------------------------------------------
//
//      CoroutineManager::CoroutineManager.
//
//      Constructor for class CoroutineManager.
//
inline CoroutineManager::CoroutineManager (Coroutine* t)
{
    next = prev = this;
    coroutine = t;
    stack = 0;
}


//--------------------------------------------------------------------------
//
//      CoroutineManager::start.
//
//      This is used to execute a coroutine by executing "main" and
//      then terminating it.
//
void far CoroutineManager::start (Coroutine* t)
{
    t->main ();
    t->terminate ();
}

//--------------------------------------------------------------------------
//
//      CoroutineManager::create.
//
//      Register the creation of a coroutine and initialise the system
//      if it is the first coroutine to be created.
//
void CoroutineManager::create ()
{
    //--- increment the number of coroutines & initialise if necessary
    if (count++ == 0)
    {   
        //--- create the main coroutine (bodged using "mainsetup")
        mainsetup = 1;
        mainitem = new MainCoroutine;
        mainsetup = 0;
        mainitem->state = Coroutine::RUNNING;

        //--- select main coroutine as the current one
        current = mainitem->entry;
    }
}


//--------------------------------------------------------------------------
//
//      CoroutineManager::destroy.
//
//      Register the destruction of a coroutine and stop scheduling if
//      the last coroutine is being destroyed.
//
void CoroutineManager::destroy ()
{
    //--- decrement coroutine count
    count--;

    //--- terminate main coroutine when no others left
    if (count == 0)
    {   current = 0;
        mainitem->state = Coroutine::TERMINATED;
        delete mainitem;
    }
}

//--------------------------------------------------------------------------
//
//      CoroutineManager::schedule.
//
//      Save the current coroutine and restore another one.
//
void interrupt CoroutineManager::schedule ()
{
    //--- don't schedule if no coroutines present
    if (current == 0)
        return;

    //--- switch context to "nextentry"
    asm { cli; }
    _SP = _BP;
    current->sp = _SP;
    current->ss = _SS;
    current = nextentry;
    _SS = current->ss;
    _SP = current->sp;
    _BP = _SP;
    asm { sti; }
}

//--------------------------------------------------------------------------
//
//      Coroutine::Coroutine.
//
//      Construct a new coroutine.  All new coroutines are kept in limbo
//      until they are explicitly started using "run".
//
Coroutine::Coroutine (unsigned stacksize)
    : entry (new CoroutineManager (this)),
      state (TERMINATED)
{
    //--- leave coroutine terminated if coroutine manager not allocated
    if (entry == 0)
        return;

    //--- set up new coroutine (for all but main coroutine)
    entry->stack = 0;
    if (!mainsetup)
    {   
        //--- allocate coroutine stack area
        if (stacksize < MIN_STACK)
            stacksize = MIN_STACK;
        entry->stack = new char [stacksize];
        if (entry->stack == 0)
            return;

        //--- register coroutine creation
        CoroutineManager::create ();

        //--- create coroutine stack
        unsigned* stk = (unsigned*)(entry->stack + stacksize);
        *--(Coroutine**)stk = this;     // "this" pointer for call to "start"
        stk -= 2;                       // dummy return address from "start"
        *--stk = _FLAGS;                // flags
        *--stk = FP_SEG (&CoroutineManager::start);
        *--stk = FP_OFF (&CoroutineManager::start);
        stk -= 5;                       // ax, bx, cx, dx, es
        *--stk = _DS;                   // ds
        stk -= 2;                       // si, di
        *--stk = _BP;                   // bp
        entry->ss = FP_SEG (stk);
        entry->sp = FP_OFF (stk);

        //--- set coroutine state
        state = CREATED;
    }
}

//--------------------------------------------------------------------------
//
//      Coroutine::~Coroutine.
//
//      Wait for current coroutine to terminate, and then destroy it.
//
Coroutine::~Coroutine ()
{
    //--- wait for coroutine to terminate
    wait ();

    //--- register coroutine destruction (normal coroutines only)
    if (this != mainitem)
        CoroutineManager::destroy ();

    //--- delete associated structures
    delete entry;
}


//--------------------------------------------------------------------------
//
//      Coroutine::run.
//
//      Start a new coroutine running.
//
int Coroutine::run ()
{
    //--- don't start coroutine if not newly created
    if (state != CREATED)
        return 0;

    //--- link coroutine into queue
    entry->next = current->next;
    entry->prev = current;
    entry->prev->next = entry;
    entry->next->prev = entry;

    //--- start coroutine running
    state = RUNNING;
    nextentry = entry;
    CoroutineManager::schedule ();
    return 1;
}

//--------------------------------------------------------------------------
//
//      Coroutine::terminate.
//
//      This terminates a coroutine by removing it from the queue.  If
//      a coroutine calls it to terminate itself, the next coroutine
//      is selected and then scheduled.
//
void Coroutine::terminate ()
{
    //--- check if coroutine is running and reset its state
    int running = (state == RUNNING);
    state = TERMINATED;
    if (!running)
        return;

    //--- select next coroutine to run if necessary
    if (entry == current)
        nextentry = current->next;

    //--- detach coroutine from the queue
    entry->next->prev = entry->prev;
    entry->prev->next = entry->next;

    //--- schedule next coroutine if necessary
    if (entry == current)
        CoroutineManager::schedule ();
}


//--------------------------------------------------------------------------
//
//      Coroutine::wait.
//
//      Wait for a coroutine to terminate.  If it's the current coroutine
//      waiting for itself to terminate, grant its wish by terminating it.
//      If it hasn't been started yet, terminate it immediately.
//
void Coroutine::wait ()
{
    if (current == entry)
        terminate ();
    if (state == CREATED)
        state = TERMINATED;
    while (state != TERMINATED)
        pause ();
}


//--------------------------------------------------------------------------
//
//      Coroutine::pause.
//
//      Schedule the next available coroutine.
//
void Coroutine::pause ()
{
    nextentry = current->next;
    CoroutineManager::schedule ();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -