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

📄 exec.cpp

📁 一个嵌入式系统的C代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//*************************************************************************//  MODULE : Exec - Process creation and management module                *//  AUTHOR : Ron Chernich                                                 *//  PURPOSE: This object contains an array of process descriptors and a   *//           number of queues containing array indicies, plus the means   *//           to create, destroy and move them around.                     *//  HISTORY:                                                              *//    21-APR-93 First version                                             *//    14-MAY-93 Process animation "calls" inserted                        *//    02-JUN-93 "Kill" not de-allocating memory                           *//    03-FEB-94 Allow un-blocking process to pre-empt current on priority *//    18-APR-94 Kill and Fork modified to accomodate shared memory        *//    01-SEP-94 File object support added to Fork and Kill                *//    17-SEP-94 LoSked allowed unallocated PID to be scheduled!           *//    21-MAR-94 Quantum made a constructor parameter                      *//*************************************************************************#include "exec.hpp"         // related header#include "kernel.hpp"       // can't put this in header due recursion#include "fsiface.hpp"      // ..or this (see header about cheshier cat)#define PROC0_TEXT      8   // Minimum requirement for process zero code#define PROC0_STACK     60  // Minimum stack allocation for process zero#define PROC0_NAME  "CONX"  // Name for console process/////////////////////////////////////////////////////////////////////////////          Class Member Functions for the Process Control Stuff//-------------------------------------------------------------------------// Initialize Process descriptors to empty, then create (but don't start)// the primary process - this should be customizable and the Prime Proc// should be a trusted p-code program - but in this release, for simplicity,// the process is fixed and coded in C++.//Exec::Exec (Knl *pK, UINT16 nMs) : PqReady(TRUE){  pTx = pK;  uProcCnt = 0;  nQuantum = nMs;  uCurProc = NO_PROC;  memset(arrPCB, 0, sizeof(PCB) * MAX_PROC);  for (INT16 i = 0; i < MAX_PROC; i++) {    memset(&arrPCB[i], 0, sizeof(PCB));    arrPCB[i].uPid = NO_PROC;    for (INT16 j = 0; j < MAX_DEV; j++)      arrPCB[i].arrDev[j] = NO_PROC;  }  CreateCon();}//////////////////// Somewhat gracefull death for the Execution unit - really the operator// should delete any running programs, so the only operation required is// to kill off the console process, but..//Exec::~Exec (void){  for (INT16 idx = 0; idx < MAX_PROC; idx++)    if (arrPCB[idx].uPid != NO_PROC)       Kill(idx);}/////////////////////// Call here when we want to execute some application code.  Run the// scheduler if there is no current process, otherwise simply call// the p-code interpreter UNLESS the PID is ZERO (which is special, being// the first process) in which case we call the specified operator proc.// After the process has run we do accumulated and quantum time accounting.//// If the process has done something causing it to yield, it is put into// the Blocked Q.  If it has run out of Quantum allocation, it gets put// back into the Ready Q (this process temporarily reduces its priority// ensures that processes at equal priority run round-robin).//// RETURNS: TRUE  .. something got run (used by single-step logic)//          FALSE .. no go//BOOL Exec::Dispatch (void){  MSG msg;  if (uCurProc == NO_PROC)    Sked();  else {    UINT32 lMark = Clock.GetTicks();    if (arrPCB[uCurProc].uPid == 0)      RunCon(arrPCB[uCurProc]);    else      RunProc(arrPCB[uCurProc], arrMCB[uCurProc]);    UINT16 uIntVal = MAX(1, (UINT16)(Clock.GetTicks() - lMark));    arrPCB[uCurProc].luTicks += (UINT32)uIntVal;    arrPCB[uCurProc].nQuantum -= uIntVal;    switch (arrPCB[uCurProc].uStatus) {      case PS_Halted:      case PS_Illegal:        msg = message(ID_Kernel, ((arrPCB[uCurProc].uStatus = PS_Illegal) ?                      ANI_HALT_BAD : ANI_HALT_OK), uCurProc);        pTx->SendMsg(ID_ANIM, &msg);        Kill(uCurProc);        uCurProc = NO_PROC;        break;      case PS_Ready:        if (arrPCB[uCurProc].nQuantum <= 0) {          PqReady.PqAdd(arrPCB[uCurProc]);          if (arrPCB[uCurProc].nQuantum > PCD_PREEMPT) {            msg = message(ID_Kernel, ANI_RUN_RDY, uCurProc);            pTx->SendMsg(ID_ANIM, &msg);          }          uCurProc = NO_PROC;        }        break;      default:        PqBlocked.PqAdd(arrPCB[uCurProc]);        msg = message(ID_Kernel, ANI_RUN_BLK, uCurProc);        pTx->SendMsg(ID_ANIM, &msg);        uCurProc = NO_PROC;    }    return TRUE;  }  return FALSE;}////////////////////// Basic Prime Proc initialization must stop short of allocating memory// because we won't have a MMU device registered yet!//void Exec::CreateCon (void){  if (arrPCB[0].uPid == NO_PROC) {    arrPCB[0].uStatus = PS_Zombie;    arrPCB[0].uPid = arrPCB[0].uPidp = 0;    arrPCB[0].nPriority = MAX_PRIORITY;    arrPCB[0].pReply = NULL;    arrPCB[0].arrDev[0] = CLS_VDU;    arrPCB[0].uBP = 1;    if (arrPCB[0].pszName = new char[strlen(PROC0_NAME)+1])      strcpy(arrPCB[0].pszName, PROC0_NAME);    arrPCB[0].uStatus = PS_Created;    PqIn.PqAdd(arrPCB[0]);    ++uProcCnt;  }}//////////////////// Called when the supervisor "RUN" button has been clicked for the first// time - we must complete the Prime Proc initializations that could not// be done before (we should now have a MMU and FS), then call the Low// Level Scheduler which should be able to allocate a TTY and line driver// to the console and move it into the Ready Queue.//void Exec::StartCon (void){  MSG mess(ID_Kernel, KM_Open, PROC0_TEXT);  pTx->SendMsg(ID_MMU, &mess);  arrMCB[0].hText = mess.wParam;  mess = message(ID_Kernel, KM_Open, PROC0_STACK);  pTx->SendMsg(ID_MMU, &mess);  arrMCB[0].hStack = mess.wParam;  if(arrMCB[0].hText && arrMCB[0].hStack) {    MMU_MSG mms;    INT16 ret_frame[3] = {0, 0, -1 };    UINT16 csp_exec[2] = { 0x08, 0x06 };    mms.pData = (UINT16*)&csp_exec[0], mms.uOffset = 0, mms.uLen = 2;    mess = message(ID_CON, KM_WriteBlk, arrMCB[0].hText, &mms);    pTx->SendMsg(ID_MMU, &mess);    mms.pData = (UINT16*)&ret_frame[0], mms.uOffset = 0, mms.uLen = 3;    mess = message(ID_CON, KM_WriteBlk, arrMCB[0].hStack, &mms);    pTx->SendMsg(ID_MMU, &mess);    arrPCB[0].uSP = 3;    if (LoSked(0))      InitCon();  }}////////////////////// Low level scheduler starts the passed process provided it is able to// allocate the resources contained in the PID's device list. Called in// response to a console or batch GO command or to start the Prime Proc.//// Note that VDU devices are not allocated direct - we merely see if one// is free and instantiate a Line Protocol Driver (which will get the TTY).//// *** INCOMPLETE: failed startup does not release allocated devices! ***//BOOL Exec::LoSked (UINT16 uGo){  INT16 idx = 0;  BOOL bCanStart;    bCanStart = (NO_PROC == arrPCB[uGo].uPid) ? FALSE : TRUE;  while (bCanStart && (idx < MAX_DEV) &&        (arrPCB[uGo].arrDev[idx] != NO_PROC)) {    MSG msg;    UINT16 uNeed = arrPCB[uGo].arrDev[idx];    switch (uNeed) {      case CLS_VDU:        msg = message(uGo, KM_Open, CLS_VDU);        pTx->SendMsg(ID_Kernel, &msg);        if (msg.wParam == 0)          bCanStart = FALSE;        else {          msg.wMsgType = KM_Close;          pTx->SendMsg(ID_Kernel, &msg);          arrPCB[uGo].pDev =            new LnDrv(arrPCB[uGo].uPid, ID_LNDRV+arrPCB[uGo].uPid, pTx);          bCanStart = (BOOL)(arrPCB[uGo].pDev != NULL);        }        break;      case CLS_MTU:        break;      case CLS_PRN:        break;      case CLS_FSF:        break;    }    ++idx;  }  if (bCanStart) {    arrPCB[uGo].uStatus = PS_Ready;    PqReady.PqAdd(arrPCB[PqIn.PqGet(uGo)]);    MSG msg(ID_Kernel, ANI_IN_RDY, uGo);    pTx->SendMsg(ID_ANIM, &msg);  }  return bCanStart;}//////////////////////// Process scheduler - first, see if there are any blocked processes that// have become unblocked and if so, feed them back into the right Queue.// Then, if there is anything at the head of the priority Ready Queue,// make its context current, preparing it for dispatch to the CPU.//// If an unblocking process was blocked on a semaphore wait, we temporarily// elevate its priority to ensure it will re-schedule ahead of the proc// that has just signaled and hence been pre-empted (assuming they are at// the same priority) - so, after insretion to the ready Q, return its// priority to original.//void Exec::Sked (void){  INT16 i;  UINT16  arrProcs[MAX_PROC];  PqBlocked.PqImage(arrProcs);  for (i = 0; i < MAX_PROC; i++) {    if (arrProcs[i] == NO_PROC)      break;    if (!(arrPCB[arrProcs[i]].uStatus & PS_Blocked)) {      INT16 idx = PqBlocked.PqGet(arrProcs[i]);      arrPCB[idx].uStatus |= PS_Ready;      if (arrPCB[idx].uSemSet)        ++arrPCB[idx].nPriority;      PqReady.PqAdd(arrPCB[idx]);      if (arrPCB[idx].uSemSet)        --arrPCB[idx].nPriority;      MSG msg(ID_Kernel, ANI_BLK_RDY, arrPCB[idx].uPid);      pTx->SendMsg(ID_ANIM, &msg);    }  }  PqSusBlock.PqImage(arrProcs);  for (i = 0; i < MAX_PROC; i++) {    if (arrProcs[i] == NO_PROC)      break;    if (!(arrPCB[arrProcs[i]].uStatus & PS_Blocked)) {      INT16 idx = PqSusBlock.PqGet(arrProcs[i]);      arrPCB[idx].uStatus |= PS_Ready;      PqSusReady.PqAdd(arrPCB[idx]);      MSG msg(ID_Kernel, ANI_SBLK_SRDY, arrPCB[idx].uPid);      pTx->SendMsg(ID_ANIM, &msg);    }  }  PqReady.PqImage(arrProcs);  uCurProc = PqReady.PqGet();  if (uCurProc != NO_PROC) {    arrPCB[uCurProc].nQuantum = nQuantum;    MSG msg(ID_Kernel, ANI_RDY_RUN, uCurProc);    pTx->SendMsg(ID_ANIM, &msg);  }}//////////////////////// The current process has posted a message which the Kernel has decided// cannot be serviced immediatly.  Remove Ready Status and assert Blocked.// The Dispatcher will do the Queue movements later.//void Exec::Block (void){  if (uCurProc != NO_PROC) {    arrPCB[uCurProc].uStatus &= ~PS_Ready;    arrPCB[uCurProc].uStatus |= PS_Blocked;    arrPCB[uCurProc].pReply = NULL;  }}////////////////// Suspend this process - always an operator initiated action.  Find the// process and suspend the bugger (can't suspend the running process, only// ready or blocked ones).// RETURNS: TRUE  .. process suspemded//          FALSE .. unknown process or already suspended!//BOOL Exec::Suspend (UINT16 uTarg){  if (uTarg == PqReady.PqGet(uTarg)) {    arrPCB[uTarg].uStatus |= PS_Suspended;    PqSusReady.PqAdd(arrPCB[uTarg]);    MSG msg(ID_Kernel, ANI_RDY_SRDY, uTarg);    pTx->SendMsg(ID_ANIM, &msg);    return TRUE;  }  if (uTarg == PqBlocked.PqGet(uTarg)) {    arrPCB[uTarg].uStatus |= PS_Suspended;    PqSusBlock.PqAdd(arrPCB[uTarg]);    MSG msg(ID_Kernel, ANI_BLK_SBLK, uTarg);    pTx->SendMsg(ID_ANIM, &msg);    return TRUE;  }  return FALSE;}////////////////// Resume a Suspend process - always an operator initiated action.// Find the process and move her back to the appropriate queue.

⌨️ 快捷键说明

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