home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-05-12 | 35.5 KB | 1,726 lines |
- /******************************************************************************
- *+
- ** Module Name: MOS.C
- **
- ** Description: Multi-tasking
- ** Operating
- ** System
- ** Simulation
- **
- ** Moss is a simulation of a multi-tasking operating system
- ** which uses many of the C standard algorithms.
- **
- ** Written by: John Tal
- **
- **
- **
- ** Modification History:
- **
- ** Date Programmer Mod# Modification
- ** ---------------------------------------------------------------------------
- ** 04-JUL-1991 J. Tal V1.0-000 New
- ** 01-DEC-1991 J. Tal V2.0-000 New Version, enhanced semaphores,
- ** messaging, swapping control
- ** FEB-1992 J. Tal V2.0-001 Revisions from C++ port.
- ** 25-APR-1992 J. Tal V2.1-000 Event Procs
- **
- *-
- */
-
-
- /*
-
-
- Mos Revision Documentation
-
-
- VERSION 1.0-000
-
- Mos uses concepts which are familiar to various implementations of
- multi-tasking operating systems. It has a scheduler to select a
- process (or job) to run from a list of waiting processes. It has
- inter-process-communication (IPC) and (currently) one semaphore.
-
- What it does not do is context switching. Normally, when the
- scheduler takes one job which was running and allows another
- to have some cpu, it saves the current context of the process
- which was running by saving the values of the important machine
- (cpu) registers as used by the interrupted process. When the
- interrupted process is placed back in a running state, it has
- no clue that it ever stopped running. This version of Mos
- does not perform context switching. It simply services ready
- processes (by priority order) and makes each process start at
- the beginning of its code.
-
- Another major function of an operating system which is not
- implemented here is memory management. This is management
- not only of calloc, malloc, cfree, and free requests by
- the applications, but it also deals with swapping inactive
- applications out to disk until they run again. This is
- virtual memory management and is beyond the scope of the
- humble goals of Mos.
-
- The concepts used in Mos are a subset of any multi-tasking
- operating system. A recommended book for a detailed explanation
- of the function of operating system design is 'Operating System
- Design: The XINU Approach' by Douglas Comer. There is also
- source code available in the public domain which implements XINU
- on top of PcDos. The source code is not recommended because
- of serious mistakes made in the specific implemention of sitting
- on top of dos (a non-multi-tasking operating system). But the
- book is good reference material.
-
- Mos was written in a few hours on July 4, 1991 using the Brief
- editor and Microsoft C 5.1 on an AT clone.
-
- VERSION 2.0-000
-
- The Moss name was changed to MOS for consistency with other members
- of the Algorithms volumes. The major changes/enhancements for this
- version include:
-
- o Support of n-number of semaphores
- (1 was supported with v 1.0)
-
- o Enhanced messaging. A process message waiting
- queue is now supported.
-
- o Swap control is enhanced. A process may
- specify exactly which function is to be
- called next when a process is swapped back
- into execution.
-
- Version 2 is highly source code compatible with Version 1 and
- most applications calling MOS will require only recompilation
- and linking with Version 2 libraries.
-
- A number of weeks were spent working on a full-context swapping
- implemention of MOS. This involved using assembly language to
- change the stack pointer as each process begins execution.
- The current version of MOS has provided more than adequate
- execution and elementary multi-tasking in both DOS and UNIX
- environments while maintaining the portability not possible
- in assembly language. If you are interested in extending MOS
- into full context-swapping and/or interrept driven modes, there
- is ample documentation in Dr. Dobbs Journal and C Users Group
- magazines to do so.
-
-
- VERSION 2.0-001 C++ Port - February 1992
-
- The C++ port of MOS provided quite a number of suprises.
- Once again, C++ has the ability to point out inefficiencies
- in a seemingly effective design. Specific tips which were
- learned during the MOS port are provided in a document called
- c_2_cpp.txt which is released with MOS on Volume 2 of the
- Algorithms series.
-
-
- VERSION 2.1-000
-
- Event handling has been added to allow Mos to synchronize with
- events outside of the Mos domain. Mos event handling was tested
- by assigning one Mos event to the serial port and another to the
- keyboard and thereby creating a multi-tasking telecommunications
- program.
-
- */
-
-
- #ifdef C_ANSI
- #include <string.h>
- #include <stdlib.h>
- #endif
-
- #include <stdio.h>
-
- #include <sys/types.h>
- #include <memlib.h>
- #include <time.h>
-
- #include <mos.h>
-
-
- /*
- ** MOS Defines
- */
-
- #define QUE_EMPTY(head) ((head) == NULL)
-
-
-
-
- CHAR szProcStates[PROC_STATE_MSG_WAIT + 1][32] =
- { "Non Existant",
- "Running",
- "Ready",
- "Sleeping",
- "Waiting on Semaphore",
- "Waiting on Message" };
-
- #define PROC_MAX_PROCS 16 /* 16 processes maximum */
-
-
- #include <mos.h>
-
-
- /*
- ** Moss Variables
- */
-
- CHAR fMosInitialized = C_FALSE;
-
- LONG glNumProcs = 0;
-
- CHAR fMosMemInit = C_FALSE;
-
- /*
- ** Master counter for process ids
- */
-
- SHORT sProcId = 0;
-
- /*
- ** There can only be one currently running process
- */
-
- PROC_P pstRunProc;
-
- /*
- ** Use a binary tree to track all processes
- ** This tree ordered by Process Name
- */
-
- TNODE_P pstProcNameTree;
-
-
- /*
- ** Use a linked-list to track all processes by proc id
- */
-
- LLIST_P pstProcIdList;
-
-
- /*
- ** The Ready Queue is ordered by priority so it is a heap
- */
-
- HEAP_P pstQueReady;
-
-
- /*
- ** The Sleep Queue is ordered by wake-up time so can be a linked-list
- */
-
- LLIST_P pstQueSleep;
-
-
- /*
- ** The Msg Wait Queue is ordered by priority. But since we cant predict
- ** the order of events which waiting processes are waiting for, we
- ** will make it a linked-list for maximum flexibility.
- */
-
- LLIST_P pstQueMsgWait;
-
-
-
- /* The Global Event List
- **
- */
-
- LLIST_P pstEventList;
-
- SHORT sEvents = 0;
-
-
-
- /*
- ** Semaphore Control Data
- */
-
-
-
- #define SEM_AVAIL 0
-
- SEM_P pstSems;
-
-
- /*
- ** Init Moss Environment
- */
-
- #ifdef C_ANSI
- SHORT
- MosInit(VOID)
- #else
- SHORT MosInit()
- #endif
- {
- C_DEF_MODULE("MosInit")
-
- INT i;
-
-
- fMosInitialized = C_TRUE;
-
- /*
- ** Set up main data stores
- */
-
- pstProcNameTree = NULL;
-
- pstProcIdList = NULL;
-
- pstQueSleep = NULL;
-
- pstQueMsgWait = NULL;
-
- pstSems = NULL;
-
- /*
- ** Init semaphores
- */
-
- pstSems = (SEM_P) calloc(MOS_MAX_SEMS,sizeof(SEM_T));
-
-
- for(i = 0; i < MOS_MAX_SEMS; i++)
- {
- pstSems[i].fInUse = (CHAR) C_FALSE;
- pstSems[i].sVal = SEM_AVAIL;
- }
-
-
- /*
- ** Any heaps must be initialized before use, trees and linked list
- ** families will do with a simple = NULL, but not heaps, like the
- ** ready queue
- */
-
- C_STATUS = MemHepInit(&pstQueReady,PROC_MAX_PROCS);
-
-
- /*
- ** Must always have a process on the ready queue, the NULL process
- ** does nothing. In operating systems, nothing else can EVER
- ** have access to the NULL process or the swapper process.
- ** Noone or nothing can kill them or the system dies.
- */
-
- C_STATUS = MosProcCreate(MosNullProc,"NULL_PROC",0);
-
-
- C_RETURN
- }
-
-
- /*
- ** MosCompareProcId
- **
- ** Use for node to node comparision of binary tree, for MemTreInsertNode
- */
-
- #ifdef C_ANSI
- SHORT
- MosCompareProcId(PVOID pvData1,PVOID pvData2)
- #else
- SHORT
- MosCompareProcId(pvData1,pvData2)
- PVOID pvData1;
- PVOID pvData2;
- #endif
- {
- PROC_P pstProc1;
- PROC_P pstProc2;
-
- pstProc1 = (PROC_P) pvData1;
- pstProc2 = (PROC_P) pvData2;
-
- if(pstProc1 -> sProcId == pstProc2 -> sProcId)
- return(C_EQUAL);
- else if(pstProc1 -> sProcId < pstProc2 -> sProcId)
- return(C_LOWER);
- else
- return(C_HIGHER);
- }
-
- /*
- ** MosCompareProcName2
- **
- ** Use for node to node comparision of binary tree, for MemTreInsertNode
- */
-
- #ifdef C_ANSI
- SHORT
- MosCompareProcName2(PVOID pvData1,PVOID pvData2)
- #else
- SHORT
- MosCompareProcName2(pvData1,pvData2)
- PVOID pvData1;
- PVOID pvData2;
- #endif
- {
- PCHAR pc1;
- PROC_P pstProc2;
-
- pc1 = (PCHAR) pvData1;
- pstProc2 = (PROC_P) pvData2;
-
- return(strcmp(pc1,pstProc2 -> szName));
- }
-
-
- /*
- ** MosCompareProcName
- **
- ** Use for node to node comparision of binary tree, for MemTreInsertNode
- */
-
- #ifdef C_ANSI
- SHORT
- MosCompareProcName(PVOID pvData1,PVOID pvData2)
- #else
- SHORT
- MosCompareProcName(pvData1,pvData2)
- PVOID pvData1;
- PVOID pvData2;
- #endif
- {
- PROC_P pstProc1;
- PROC_P pstProc2;
-
- pstProc1 = (PROC_P) pvData1;
- pstProc2 = (PROC_P) pvData2;
-
- return(strcmp(pstProc1 -> szName,pstProc2 -> szName));
- }
-
-
-
-
- /*
- ** Create a new process = init and place on ready queue
- */
-
- #ifdef C_ANSI
- SHORT
- MosProcCreate(SHORT (*pProc)(), PCHAR szProcName, SHORT sPriority)
- #else
- SHORT
- MosProcCreate(pProc,szProcName,sPriority)
- SHORT (*pProc)();
- PCHAR szProcName;
- SHORT sPriority;
- #endif
- {
- C_DEF_MODULE("MosProcCreate")
-
-
- PROC_P pstProc;
-
-
-
- MosProcInit(pProc,szProcName,sPriority,&pstProc);
-
-
- /*
- ** Place this process on the ready queue
- */
-
- C_STATUS = MosReschedReady(pstProc);
-
-
- C_RETURN
- }
-
- /*
- ** Internal call to init a new process
- */
-
- #ifdef C_ANSI
- SHORT
- MosProcInit(SHORT (*pProc)(), PCHAR szProcName, SHORT sPriority, PROC_P * ppstProc)
- #else
- SHORT
- MosProcInit(pProc,szProcName,sPriority,ppstProc)
- SHORT (*pProc)();
- PCHAR szProcName;
- SHORT sPriority;
- PROC_P * ppstProc;
- #endif
- {
- C_DEF_MODULE("MosProcCreate")
-
- TNODE_P pstNode;
- LLIST_P pstMember;
- PROC_P pstProc;
-
-
- if(!fMosInitialized)
- {
- printf("Error: Mos has not been initialized via MosInit()\n");
- exit(1);
- }
-
- pstProc = (PROC_P) calloc(1,sizeof(PROC_T));
-
- pstProc -> sPriority = sPriority; /* set priority */
- strcpy(pstProc -> szName, szProcName); /* set name */
- pstProc -> sProcId = sProcId; /* set proc id */
- sProcId++; /* inc global proc id */
- glNumProcs++;
-
- pstProc -> sState = PROC_STATE_READY; /* It is ready */
- pstProc -> sPrevState = PROC_STATE_NO_EXIST; /* no prvious state */
- pstProc -> pProc = pProc; /* Point to proc to run */
- pstProc -> pBlockedFunc = NULL;
-
- /*
- ** Store this process in the global process tree
- */
-
- C_STATUS = MemTreAllocNode(&pstNode);
-
- pstNode -> pvData = (PVOID) pstProc;
-
- C_STATUS = MemTreInsertNode(pstProcNameTree,
- pstNode,
- MosCompareProcName,
- &pstProcNameTree);
-
-
- /*
- ** Create member for process tracking by id
- */
-
- C_STATUS = MemLstAllocMember(&pstMember);
-
- pstMember -> pvData = (PVOID) pstProc;
-
- C_STATUS = MemLstInsertMember(pstProcIdList,
- pstMember,
- MosCompareProcId,
- &pstProcIdList);
-
-
-
- *ppstProc = pstProc;
-
- C_RETURN
- }
-
-
- /*
- ** Terminate a Process
- */
-
- #ifdef C_ANSI
- SHORT
- MosProcTerm(PROC_P pProc)
- #else
- SHORT
- MosProcTerm(pProc)
- PROC_P pProc;
- #endif
- {
- C_DEF_MODULE("MosProcTerm")
-
- LLIST_P pstList;
-
-
- C_STATUS = MemTreDeleteNode(pstProcNameTree,
- (PVOID) pProc,
- MosCompareProcName,
- &pstProcNameTree);
-
- C_STATUS = MemLstFindMember(pstProcIdList,
- (PVOID) pProc,
- MosCompareProcName,
- &pstList);
-
- C_STATUS = MemLstDeleteMember(pstProcIdList,
- pstList,
- &pstProcIdList);
-
- pProc -> sState = PROC_STATE_NO_EXIST;
-
- free(pProc);
-
- glNumProcs--;
-
- C_SET_STATUS(PROC_STATE_NO_EXIST);
-
- C_RETURN
-
- }
-
-
- /*
- ** MosScheduler
- **
- ** This is the central workhorse function
- */
-
- #ifdef C_ANSI
- SHORT
- MosScheduler(VOID)
- #else
- SHORT
- MosScheduler()
- #endif
- {
- C_DEF_MODULE("MosScheduler")
-
-
- PROC_P pstProc;
-
-
- if(!fMosInitialized)
- {
- printf("Error: Mos has not been initialized via MosInit()\n");
- exit(1);
- }
-
- while(1)
- {
-
- /* if only NULL proc is running, terminate */
-
- if(glNumProcs == 1)
- break;
-
-
- /*
- ** Run check on all events
- */
-
- C_STATUS = MosEventCheckList();
-
-
- /*
- ** You may want to put a delay here or get a character from the
- ** keyboard to see what Moss is doing on each iteration through
- ** the code
- */
-
- C_STATUS = MosCheckSleepQueue();
-
- C_STATUS = MosGetReadyProc(&pstProc);
-
- pstRunProc = pstProc;
-
- /*
- ** Invoke the process
- **
- ** In a real multi-tasking operating system, the cpu would be restored
- ** with the code segment and instruction pointer of the process where
- ** execution should resume. To simulate that, we call the function
- ** which represents the process (essentially restarting the process)
- ** and it's up to the function to pick-up where it left off
- */
-
- if(pstProc -> pBlockedFunc != NULL)
- C_STATUS = (*(pstProc -> pBlockedFunc))(pstProc -> pvWorkArea);
- else
- C_STATUS = (*(pstProc -> pProc))(pstProc);
-
-
- /*
- ** If we were running the NULL process, then MUST put it back on the
- ** ready queue. An empty ready queue = system crash
- **
- ** Also, if last process is still in running state, requeue back
- ** to ready queue.
- */
-
- if(C_STATUS != PROC_STATE_NO_EXIST)
- {
- if(pstProc -> sState == PROC_STATE_RUNNING)
- C_STATUS = MosReschedReady(pstProc);
- }
-
- }
-
- /*
- ** Some compilers will tell you that the next statement is unreachable,
- ** That is ok.
- */
-
- C_RETURN
- }
-
-
- /*
- ** MosCheckSleepQueue
- **
- ** Check the sleep queue. If anything there and is ready to be
- ** waked-up, place on the ready queue
- */
-
- #ifdef C_ANSI
- SHORT
- MosCheckSleepQueue(VOID)
- #else
- SHORT
- MosCheckSleepQueue()
- #endif
- {
- C_DEF_MODULE("MosCheckSleepQueue")
-
- LLIST_P pstList;
- PROC_P pstProc;
-
-
- while(1)
- {
- /*
- ** Loop to free all jobs which we can
- */
-
- if(!QUE_EMPTY(pstQueSleep))
- {
- pstList = pstQueSleep;
-
- pstProc = (PROC_P) pstList -> pvData;
-
- if(pstProc -> lWakeTime <= MosCurTime())
- {
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Being awakened\n", pstProc -> sProcId,
- pstProc -> szName);
- #endif
-
- /*
- ** This direct access to the linked list and assigning
- ** it to the next member is legal. It wont be possible to
- ** do this in C++. Would have to do a delete using the
- ** process name or id as a key. Whats here works for now.
- */
-
- pstQueSleep = pstQueSleep -> psNext;
-
- free(pstList);
-
- C_STATUS = MosReschedReady(pstProc);
- }
- else
- break;
- }
- else
- break;
-
- }
-
- C_RETURN
- }
-
-
-
- /*
- ** MosReschedReady
- **
- ** Places a process on the ready queue
- */
-
- #ifdef C_ANSI
- SHORT
- MosReschedReady(PROC_P pstProc)
- #else
- SHORT
- MosReschedReady(pstProc)
- PROC_P pstProc;
- #endif
- {
- C_DEF_MODULE("MosReschedReady")
-
- pstProc -> sPrevState = pstProc -> sState;
-
- pstProc -> sState = PROC_STATE_READY; /* mark as ready */
-
- C_STATUS = MemHepEnque(pstQueReady,
- pstProc -> sPriority,
- (PVOID) pstProc);
-
- C_STATUS = MosProcAnnounce(pstProc);
-
- C_RETURN
- }
-
-
- /*
- ** MosGetReadyProc
- **
- ** It retrieves the process that should be run next from the ready queue
- */
-
- #ifdef C_ANSI
- SHORT
- MosGetReadyProc(PROC_P * ppstProc)
- #else
- SHORT
- MosGetReadyProc(ppstProc)
- PROC_P * ppstProc;
- #endif
- {
- C_DEF_MODULE("MosGetReadyProc")
-
- SHORT sPriority;
-
- /*
- ** Get a process
- */
-
- C_STATUS = MemHepDeque(pstQueReady,
- &sPriority,
- (PVOID *) ppstProc);
-
-
- /*
- ** Set proc state to running
- */
-
- (*ppstProc) -> sState = PROC_STATE_RUNNING;
-
- #ifdef ANNOUNCE
- printf("\n");
- #endif
-
- C_STATUS = MosProcAnnounce(*ppstProc);
-
- C_RETURN
- }
-
- /*
- ** MosProcAnnounce
- **
- ** It is used for processes to announce when they have started running
- */
-
- #ifdef C_ANSI
- SHORT
- MosProcAnnounce(PROC_P pstProc)
- #else
- SHORT
- MosProcAnnounce(pstProc)
- PROC_P pstProc;
- #endif
- {
- C_DEF_MODULE("MosProcAnnounce")
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Is %s\n",
- pstProc -> sProcId,
- pstProc -> szName,
- szProcStates[pstProc -> sState]);
- #else
- pstProc = pstProc; /* silence compiler */
- #endif
-
- C_RETURN
- }
-
- /*
- ** MosNullProc
- **
- ** The Null Process
- **
- ** Note: If implementing on top of a 'real' multi-tasking operating system
- ** (e.g. Unix, OS/2, VMS), this process should sleep() for around
- ** 1 or more seconds. If it did nothing as it currently does,
- ** it would eat up the cpu.
- */
-
- #ifdef C_ANSI
- SHORT
- MosNullProc(PROC_P pstProc)
- #else
- SHORT
- MosNullProc(pstProc)
- PROC_P pstProc;
- #endif
- {
- C_DEF_MODULE("NullProc")
-
- C_STATUS = MosProcAnnounce(pstProc);
-
- #ifdef C_UNIX
- sleep(1);
- #endif
-
- C_RETURN
- }
-
- /*
- ** MosSemInit
- **
- ** Called to initialize a new semaphore
- */
-
- #ifdef C_ANSI
- SHORT
- MosSemInit(PROC_P pstProc,PCHAR pcSemName,PSHORT psSemHandle)
- #else
- SHORT
- MosSemInit(pstProc,pcSemName,psSemHandle)
- PROC_P pstProc;
- PCHAR pcSemName;
- PSHORT psSemHandle;
- #endif
- {
- C_DEF_MODULE("MosSemInit")
-
- SHORT i;
- CHAR fDone = C_FALSE;
- SHORT iUseSlot;
-
- pstProc = pstProc; /* silence compiler warning */
-
- for(i = 0; i < MOS_MAX_SEMS; i++)
- {
- if(strcmp(pcSemName,pstSems[i].szSemName) == 0)
- {
- *psSemHandle = i;
-
- /*
- ** Is not already initialized, then do so
- */
-
- if(!pstSems[i].fInUse)
- {
- pstSems[i].sVal = SEM_AVAIL;
- pstSems[i].fInUse = C_TRUE;
- fDone = C_TRUE;
- }
- break;
- }
-
- if(!pstSems[i].fInUse)
- {
- iUseSlot = i;
- }
-
- }
-
- if(!fDone)
- {
- if(iUseSlot != -1)
- {
- strcpy(pstSems[iUseSlot].szSemName,pcSemName);
- pstSems[iUseSlot].fInUse = C_TRUE;
- *psSemHandle = iUseSlot;
- fDone = C_TRUE;
- }
- }
-
- if(!fDone)
- *psSemHandle = -1;
-
-
- C_RETURN
- }
-
-
- /*
- ** MosSemTerm
- **
- **
- **
- */
-
- #ifdef C_ANSI
- SHORT
- MosSemTerm(PROC_P pstProc,PCHAR pcSemName,SHORT sSemHandle)
- #else
- SHORT
- MosSemTerm(pstProc,pcSemName,sSemHandle)
- PROC_P pstProc;
- PCHAR pcSemName;
- SHORT sSemHandle;
- #endif
- {
- C_DEF_MODULE("MosSemTerm")
-
- pstProc = pstProc; /* silence compiler */
-
- if(sSemHandle < MOS_MAX_SEMS)
- {
- if(strcmp(pcSemName,pstSems[sSemHandle].szSemName) == 0)
- {
- pstSems[sSemHandle].fInUse = C_FALSE;
- }
- }
-
- C_RETURN
- }
-
-
-
-
- /*
- ** MosSemWait
- **
- ** Called by a process when it wants exclusive ownership
- ** of a semaphore
- */
-
- #ifdef C_ANSI
- SHORT
- MosSemWait(PROC_P pstProc,SHORT sSemHandle)
- #else
- SHORT
- MosSemWait(pstProc,sSemHandle)
- PROC_P pstProc;
- SHORT sSemHandle;
- #endif
- {
- C_DEF_MODULE("MosSemWait")
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Requesting semaphore %s\n", pstProc -> sProcId,
- pstProc -> szName,
- pstSems[sSemHandle].szSemName);
- #endif
-
- if(pstSems[sSemHandle].sVal != SEM_AVAIL)
- {
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Queued for semaphore\n", pstProc -> sProcId,
- pstProc -> szName);
- #endif
-
- C_STATUS = MemQueEnqMember(&pstSems[sSemHandle].pstQueHead,
- &pstSems[sSemHandle].pstQueTail,
- (PVOID) pstProc);
-
- pstProc -> sState = PROC_STATE_SEM_WAIT;
-
- C_STATUS = MOS_PROC_SUSPEND;
-
- }
- else
- {
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Obtained semaphore\n", pstProc -> sProcId,
- pstProc -> szName);
- #endif
-
-
- pstSems[sSemHandle].sVal++;
- pstProc -> fCritical = C_TRUE; /* set to critical so will not swap and complete operation */
- }
-
-
- C_RETURN
- }
-
-
- /*
- ** MosSemClear
- **
- ** Called by a process to clear a semaphore
- ** Semaphore is then available for next process
- */
-
- #ifdef C_ANSI
- SHORT
- MosSemClear(PROC_P pstProc,SHORT sSemHandle)
- #else
- SHORT
- MosSemClear(pstProc,sSemHandle)
- PROC_P pstProc;
- SHORT sSemHandle;
- #endif
- {
- C_DEF_MODULE("MosSemClear")
-
- PROC_P pstReleasedProc;
-
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Clearing semaphore %s\n", pstProc -> sProcId,
- pstProc -> szName,
- pstSems[sSemHandle].szSemName);
- #endif
-
- pstProc = pstProc; /* silence compiler */
-
- pstSems[sSemHandle].sVal = SEM_AVAIL;
-
- if(!QUE_EMPTY(pstSems[sSemHandle].pstQueHead))
- {
-
- /*
- ** Retrieve the process which was waiting for the semaphore
- */
-
- C_STATUS = MemQueDeqMember(&pstSems[sSemHandle].pstQueHead,
- &pstSems[sSemHandle].pstQueTail,
- (PVOID *) &pstReleasedProc);
-
- /*
- ** Give it the semaphore
- */
-
- C_STATUS = MosSemWait(pstReleasedProc,sSemHandle);
-
-
- /*
- ** Place it back on the ready queue
- */
-
- C_STATUS = MosReschedReady(pstReleasedProc);
- }
-
- C_RETURN
- }
-
-
- /*
- ** MosSemSet
- **
- */
-
- #ifdef C_ANSI
- SHORT
- MosSemSet(PROC_P pstProc,SHORT sSemHandle)
- #else
- SHORT
- MosSemSet(pstProc,sSemHandle)
- PROC_P pstProc;
- SHORT sSemHandle;
- #endif
- {
- C_DEF_MODULE("MosSemSet")
-
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Setting semaphore %s\n", pstProc -> sProcId,
- pstProc -> szName,
- pstSems[sSemHandle].szSemName);
- #endif
-
- pstProc = pstProc; /* silence compiler */
-
- pstSems[sSemHandle].sVal = 1;
-
- C_RETURN
- }
-
-
- /*
- ** MosSemSignal
- **
- ** Called by a process when it releases exclusive access to
- ** a semaphore
- */
-
- #ifdef C_ANSI
- SHORT
- MosSemSignal(PROC_P pstProc,SHORT sSemHandle)
- #else
- SHORT
- MosSemSignal(pstProc,sSemHandle)
- PROC_P pstProc;
- SHORT sSemHandle;
- #endif
- {
- C_DEF_MODULE("MosSemSignal")
-
- PROC_P pstReleasedProc;
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Releasing semaphore %s\n", pstProc -> sProcId,
- pstProc -> szName,
- pstSems[sSemHandle].szSemName);
- #endif
-
-
- pstProc -> fCritical = C_FALSE;
-
- pstSems[sSemHandle].sVal--;
-
- if(!QUE_EMPTY(pstSems[sSemHandle].pstQueHead))
- {
-
- /*
- ** Retrieve the process which was waiting for the semaphore
- */
-
- C_STATUS = MemQueDeqMember(&pstSems[sSemHandle].pstQueHead,
- &pstSems[sSemHandle].pstQueTail,
- (PVOID *) &pstReleasedProc);
-
- /*
- ** Give it the semaphore
- */
-
- C_STATUS = MosSemWait(pstReleasedProc,sSemHandle);
-
-
- /*
- ** Place it back on the ready queue
- */
-
- C_STATUS = MosReschedReady(pstReleasedProc);
- }
-
-
- C_RETURN
- }
-
-
- /*
- ** MosCurTime
- **
- ** Mos function to get the current time
- */
-
- #ifdef C_ANSI
- LONG
- MosCurTime(VOID)
- #else
- LONG
- MosCurTime()
- #endif
- {
- time_t lTime;
-
- time(&lTime);
-
- return((LONG) lTime);
- }
-
-
- /*
- ** MosSleep
- **
- ** Called by a process to setup for sleeping
- */
-
- #ifdef C_ANSI
- SHORT
- MosSleep(PROC_P pstProc)
- #else
- SHORT
- MosSleep(pstProc)
- PROC_P pstProc;
- #endif
- {
- C_DEF_MODULE("MosSleep")
-
- LLIST_P pstList;
-
-
- pstProc -> sState = PROC_STATE_SLEEPING;
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Sleeping till %d\n", pstProc -> sProcId,
- pstProc -> szName,
- pstProc -> lWakeTime);
- #endif
-
- C_STATUS = MemLstAllocMember(&pstList);
-
- pstList -> pvData = (PVOID) pstProc;
-
- C_STATUS = MemLstInsertMember(pstQueSleep,
- pstList,
- MosCompareTime,
- &pstQueSleep);
-
- C_STATUS = MOS_PROC_SUSPEND;
-
- C_RETURN
- }
-
-
- /*
- ** MosCompareTime
- **
- ** Compare time of two PROC_P in binary tree
- */
-
- #ifdef C_ANSI
- SHORT
- MosCompareTime(PVOID pvData1,PVOID pvData2)
- #else
- SHORT
- MosCompareTime(pvData1,pvData2)
- PVOID pvData1;
- PVOID pvData2;
- #endif
- {
- PROC_P pstProc1;
- PROC_P pstProc2;
-
- pstProc1 = (PROC_P) pvData1;
- pstProc2 = (PROC_P) pvData2;
-
- if(pstProc1 -> lWakeTime == pstProc2 -> lWakeTime)
- return(C_EQUAL);
- else if(pstProc1 -> lWakeTime < pstProc2 -> lWakeTime)
- return(C_LOWER);
- else if(pstProc1 -> lWakeTime > pstProc2 -> lWakeTime)
- return(C_HIGHER);
-
- }
-
-
- /*
- ** MosCompareIdNode
- **
- ** Compare a passed in proc id with one pointed
- ** to by a binary tree node
- */
-
- #ifdef C_ANSI
- SHORT
- MosCompareIdNode(PVOID pvData1,PVOID pvData2)
- #else
- SHORT
- MosCompareIdNode(pvData1,pvData2)
- PVOID pvData1;
- PVOID pvData2;
- #endif
- {
- PROC_P pstProc;
- PSHORT psProcId;
-
-
- psProcId = (PSHORT) pvData1;
- pstProc = (PROC_P) pvData2;
-
- if(*psProcId == pstProc -> sProcId)
- return(C_EQUAL);
- else if(*psProcId < pstProc -> sProcId)
- return(C_LOWER);
- else if(*psProcId > pstProc -> sProcId)
- return(C_HIGHER);
-
- }
-
-
- /*
- ** MosGetPidByName
- **
- ** Get another processes procid by using their name
- */
-
- #ifdef C_ANSI
- SHORT
- MosGetPidByName(PCHAR pcName,PSHORT psPid)
- #else
- SHORT
- MosGetPidByName(pcName,psPid)
- PCHAR pcName;
- PSHORT psPid;
- #endif
- {
- C_DEF_MODULE("MosGetPidByName")
-
-
- TNODE_P pstNode;
- PROC_P pstDestProc;
-
-
- /*
- ** Find address of destination process
- */
-
- C_STATUS = MemTreFindNode(pstProcNameTree,
- (PVOID) pcName,
- MosCompareProcName2,
- &pstNode);
-
- if(pstNode != NULL)
- {
- pstDestProc = (PROC_P) pstNode -> pvData;
-
- *psPid = pstDestProc -> sProcId;
- }
- else
- *psPid = MOS_PROC_NULL;
-
- C_RETURN
-
- }
-
-
- /*
- ** MosMsgWrite
- **
- ** Write a message to a target process
- ** The message data is calloc'd here and should be dealloced by
- ** reader after MsgRead()
- */
-
- #ifdef C_ANSI
- SHORT
- MosMsgWrite(PROC_P pstProc,PCHAR pcData, SHORT sLen, SHORT sTargetProcId)
- #else
- SHORT
- MosMsgWrite(pstProc,pcData,sLen,sTargetProcId)
- PROC_P pstProc;
- PCHAR pcData;
- SHORT sLen;
- SHORT sTargetProcId;
- #endif
- {
- C_DEF_MODULE("MosMsgWrite")
-
- PROC_P pstDestProc;
- LLIST_P pstList;
- MSG_P pstMsg;
-
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Sending message to procid %d\n", pstProc -> sProcId,
- pstProc -> szName,
- sTargetProcId);
- #endif
-
- /*
- ** Setup message for sending
- */
-
-
- pstMsg = (MSG_P) calloc(1,sizeof(MSG_T));
-
-
- pstMsg -> pcData = (PCHAR) calloc(1,sLen);
-
- memcpy(pstMsg -> pcData,pcData,sLen);
-
- pstMsg -> sLen = sLen;
-
- pstMsg -> sSendPid = pstProc -> sProcId;
-
- pstMsg -> sDestPid = sTargetProcId;
-
-
- /*
- ** Find address of destination process
- */
-
-
- C_STATUS = MemLstFindMember(pstProcIdList,
- (PVOID) &sTargetProcId,
- MosCompareIdNode,
- &pstList);
-
- if(pstList != NULL)
- {
- pstDestProc = (PROC_P) pstList -> pvData;
-
- C_STATUS = MemQueEnqMember(&(pstDestProc -> pstMsgQueHead),
- &(pstDestProc -> pstMsgQueTail),
- (PVOID) pstMsg);
-
-
- /*
- ** Check if process was sleeping, if so, wake it up.
- **
- ** Remove it from the sleeping queue and place on ready queue
- */
-
- if(pstDestProc -> sState == PROC_STATE_SLEEPING)
- {
-
- C_STATUS = MemLstFindMember(pstQueSleep,
- &(pstDestProc -> sProcId),
- MosCompareIdNode,
- &pstList);
-
- C_STATUS = MemLstDeleteMember(pstQueSleep,
- pstList,
- &pstQueSleep);
-
- C_STATUS = MosReschedReady(pstDestProc);
-
- }
-
- /*
- ** Check if process was waiting on message, if so
- ** Remove it from the msg wait queue and place on ready queue
- */
-
- if(pstDestProc -> sState == PROC_STATE_MSG_WAIT)
- {
-
- C_STATUS = MemLstFindMember(pstQueMsgWait,
- &(pstDestProc -> sProcId),
- MosCompareIdNode,
- &pstList);
-
- C_STATUS = MemLstDeleteMember(pstQueMsgWait,
- pstList,
- &pstQueMsgWait);
-
- C_STATUS = MosReschedReady(pstDestProc);
-
- }
- }
-
- C_RETURN
- }
-
-
- /*
- ** MosTellMsgRead
- **
- ** Display the message a process read
- */
-
- #ifdef C_ANSI
- SHORT
- MosTellMsgRead(PROC_P pstProc,PCHAR pcMsgBuf)
- #else
- SHORT
- MosTellMsgRead(pstProc,pcMsgBuf)
- PROC_P pstProc;
- PCHAR pcMsgBuf;
- #endif
- {
- C_DEF_MODULE("MosTelMsgRead")
-
- #ifdef ANNOUNCE
- printf("Process %d: %s : Received Message: %s\n",
- pstProc -> sProcId,
- pstProc -> szName,
- pcMsgBuf);
- #else
- pstProc = pstProc; /* silence compiler */
- pcMsgBuf = pcMsgBuf; /* silence compiler */
- #endif
-
-
- C_RETURN
- }
-
- /*
- ** MosMsgRead
- **
- ** Read a message
- */
-
- #ifdef C_ANSI
- SHORT
- MosMsgRead(PROC_P pstProc, MSG_P * ppstMsg)
- #else
- SHORT
- MosMsgRead(pstProc,ppstMsg)
- PROC_P pstProc;
- MSG_P * ppstMsg;
- #endif
- {
- C_DEF_MODULE("MosMsgRead")
- LLIST_P pstList;
-
-
- if(!QUE_EMPTY(pstProc -> pstMsgQueHead))
- {
- C_STATUS = MemQueDeqMember(&(pstProc -> pstMsgQueHead),
- &(pstProc -> pstMsgQueTail),
- (PVOID *) ppstMsg);
- }
- else
- {
-
- /*
- ** Place in Msg Wait que (Added November 23, 1991)
- */
-
-
- pstProc -> sState = PROC_STATE_MSG_WAIT;
-
- C_STATUS = MemLstAllocMember(&pstList);
-
- pstList -> pvData = (PVOID) pstProc;
-
- C_STATUS = MemLstInsertMember(pstQueMsgWait,
- pstList,
- MosCompareTime,
- &pstQueMsgWait);
-
-
- C_STATUS = MOS_PROC_SUSPEND;
- }
-
- C_RETURN
- }
-
-
-
-
- /*
- ** Create a new event process
- */
-
- #ifdef C_ANSI
- SHORT
- MosEventCreate(SHORT (*pCheckFunc)(VOID), SHORT (*pProc)(PROC_P), PCHAR szProcName, SHORT sPriority)
- #else
- SHORT
- MosEventCreate(pCheckFunc,pProc,szProcName,sPriority)
- SHORT (*pCheckFunc)();
- SHORT (*pProc)();
- PCHAR szProcName;
- SHORT sPriority;
- #endif
- {
- C_DEF_MODULE("MosEventCreate")
-
- EVENT_P pstEvent;
- PROC_P pstProc;
- LLIST_P pstMember;
- LLIST_P pstTailMember;
-
-
- MosProcInit(pProc,szProcName,sPriority,&pstProc);
-
- pstEvent = (EVENT_P) calloc(1,sizeof(EVENT_T));
-
- pstEvent -> pCheckFunc = pCheckFunc;
- pstEvent -> pstEventProc = pstProc;
-
- /*
- ** Place this process in the event list
- */
-
- /*
- ** Create member for process tracking by id
- */
-
- C_STATUS = MemLstAllocMember(&pstMember);
-
- pstMember -> pvData = (PVOID) pstEvent;
-
- if(pstEventList == NULL)
- pstEventList = pstMember;
- else
- {
- MemLstFindTailMember(pstEventList,&pstTailMember);
-
- MemLstAddAfterMember(pstTailMember, pstMember);
- }
-
- sEvents++;
-
- C_RETURN
- }
-
- /*
- ** Terminate an Event Process
- */
- #ifdef C_ANSI
- SHORT
- MosEventTerm(PROC_P pstProc)
- #else
- SHORT
- MosEventTerm(pstProc)
- PROC_P pstProc;
- #endif
- {
- C_DEF_MODULE("MosProcTerm")
-
- LLIST_P pstList;
- EVENT_P pstEvent;
-
- /*
- ** Remove from event list first
- */
-
- pstList = pstEventList;
-
- while(pstList != NULL)
- {
- pstEvent = pstList -> pvData;
-
- if(pstEvent -> pstEventProc == pstProc)
- {
- MemLstDeleteMember(pstEventList,
- pstList,
- &pstEventList);
- break;
- }
-
- pstList = pstList -> psNext;
-
- }
-
- /*
- ** Now call normal process cleanup
- */
-
- C_STATUS = MosProcTerm(pstProc);
-
- sEvents--;
-
- C_RETURN
-
- }
-
- /*
- ** MosEventCheckList
- **
- ** Check Event List
- */
-
- #ifdef C_ANSI
- SHORT
- MosEventCheckList(VOID)
- #else
- SHORT
- MosEventCheckList()
- #endif
- {
- C_DEF_MODULE("MosEventCheckList")
-
- LLIST_P pstMember;
- EVENT_P pstEvent;
-
- if(sEvents == 0)
- C_LEAVE(C_OK);
-
- pstMember = pstEventList;
-
- while(pstMember != NULL)
- {
-
- pstEvent = (EVENT_P) pstMember -> pvData;
-
- /* check for event occurance */
-
- C_STATUS = (*(pstEvent -> pCheckFunc))();
-
- if(C_STATUS)
- {
- /*
- ** if event occurred, place back on ready/run queue
- ** processes awaiting events may be of higher priority than
- ** normal processes
- */
-
- C_STATUS = MosReschedReady(pstEvent->pstEventProc);
- }
-
- pstMember = pstMember -> psNext;
- }
-
-
- C_SET_STATUS(C_OK);
-
-
- C_MODULE_EXIT:
-
- C_RETURN
- }
-
-
-
-