📄 kernelmultitasker.c
字号:
//// Visopsys// Copyright (C) 1998-2005 J. Andrew McLaughlin// // This program is free software; you can redistribute it and/or modify it// under the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 of the License, or (at your option)// any later version.// // This program is distributed in the hope that it will be useful, but// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License// for more details.// // You should have received a copy of the GNU General Public License along// with this program; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//// kernelMultitasker.c//// This file contains the C functions belonging to the kernel's // multitasker#include "kernelMultitasker.h"#include "kernelParameters.h"#include "kernelMemoryManager.h"#include "kernelMalloc.h"#include "kernelFile.h"#include "kernelMain.h"#include "kernelPageManager.h"#include "kernelProcessorX86.h"#include "kernelPic.h"#include "kernelSysTimer.h"#include "kernelEnvironment.h"#include "kernelShutdown.h"#include "kernelMiscFunctions.h"#include "kernelInterrupt.h"#include "kernelLog.h"#include "kernelError.h"#include <stdio.h>#include <string.h>#include <signal.h>// Global multitasker stuffstatic int multitaskingEnabled = 0;static volatile int processIdCounter = KERNELPROCID;static kernelProcess *kernelProc = NULL;static kernelProcess *idleProc = NULL;static kernelProcess *exceptionProc = NULL;static kernelProcess *deadProcess;static volatile int schedulerSwitchedByCall = 0;// We allow the pointer to the current process to be exported, so that// when a process uses system calls, there is an easy way for the// process to get information about itself.kernelProcess *kernelCurrentProcess = NULL;// Process queue for CPU executionstatic kernelProcess* processQueue[MAX_PROCESSES];static volatile int numQueued = 0;// Things specific to the scheduler. The scheduler process is just a// convenient place to keep things, we don't use all of it and it doesn't// go in the queuestatic kernelProcess *schedulerProc = NULL;static volatile int schedulerStop = 0;static void (*oldSysTimerHandler)(void) = NULL;static volatile unsigned schedulerTimeslices = 0;static volatile unsigned schedulerTime = 0;#define PROC_KILLABLE(proc) ((proc != kernelProc) && \ (proc != exceptionProc) && \ (proc != idleProc) && \ (proc != kernelCurrentProcess)) static kernelProcess *getProcessById(int processId){ // This routine is used to find a process' pointer based on the process // Id. Nothing fancy -- it just searches through the list. Maybe later // it can be some kind of fancy sorting/searching procedure. Returns NULL // if the process doesn't exist kernelProcess *theProcess = NULL; int count; for (count = 0; count < numQueued; count ++) if (processQueue[count]->processId == processId) { theProcess = processQueue[count]; break; } // If we didn't find it, this will still be NULL return (theProcess);}static kernelProcess *getProcessByName(const char *name){ // As above, but searches by name kernelProcess *theProcess = NULL; int count; for (count = 0; count < numQueued; count ++) if (!strcmp((char *) processQueue[count]->processName, name)) { theProcess = processQueue[count]; break; } // If we didn't find it, this will still be NULL return (theProcess);}static inline int requestProcess(kernelProcess **processPointer){ // This routine is used to allocate new process control memory. It // should be passed a reference to a pointer that will point to // the new process, if allocated successfully. int status = 0; kernelProcess *newProcess = NULL; // Make sure the pointer->pointer parameter we were passed isn't NULL if (processPointer == NULL) // Oops. return (status = ERR_NULLPARAMETER); newProcess = kernelMalloc(sizeof(kernelProcess)); if (newProcess == NULL) return (status = ERR_MEMORY); // Success. Set the pointer for the calling process *processPointer = newProcess; return (status = 0);}static inline int releaseProcess(kernelProcess *killProcess){ // This routine is used to free process control memory. It // should be passed the process Id of the process to kill. It // returns 0 on success, negative otherwise int status = 0; status = kernelFree((void *) killProcess); return (status);}static int addProcessToQueue(kernelProcess *targetProcess){ // This routine will add a process to the task queue. It returns zero // on success, negative otherwise int status = 0; int count; if (targetProcess == NULL) // The process does not exist, or is not accessible return (status = ERR_NOSUCHPROCESS); // Make sure the priority is a legal value if ((targetProcess->priority < 0) || (targetProcess->priority > (PRIORITY_LEVELS - 1))) // The process' priority is an illegal value return (status = ERR_INVALID); // Search the process queue to make sure it isn't already present for (count = 0; count < numQueued; count ++) if (processQueue[count] == targetProcess) // Oops, it's already there return (status = ERR_ALREADY); // OK, now we can add the process to the queue processQueue[numQueued++] = targetProcess; // Done return (status = 0);}static int removeProcessFromQueue(kernelProcess *targetProcess){ // This routine will remove a process from the task queue. It returns zero // on success, negative otherwise int status = 0; int processPosition = 0; int count; if (targetProcess == NULL) // The process does not exist, or is not accessible return (status = ERR_NOSUCHPROCESS); // Search the queue for the matching process for (count = 0; count < numQueued; count ++) if (processQueue[count] == targetProcess) { processPosition = count; break; } // Make sure we found the process if (processQueue[processPosition] != targetProcess) // The process is not in the task queue return (status = ERR_NOSUCHPROCESS); // Subtract one from the number of queued processes numQueued -= 1; // OK, now we can remove the process from the queue. If there are one // or more remaining processes in this queue, we will shorten the queue // by moving the LAST process into the spot we're vacating if ((numQueued > 0) && (processPosition != numQueued)) processQueue[processPosition] = processQueue[numQueued]; // Done return (status = 0);}static int createTaskStateSegment(kernelProcess *theProcess, void *processPageDir){ // This function will create a TSS (Task State Segment) for a new // process based on the attributes of the process. This function relies // on the privilege, userStackSize, and superStackSize attributes having // been previously set. Returns 0 on success, negative on error. int status = 0; // Get a free descriptor for the process' TSS status = kernelDescriptorRequest(&(theProcess->tssSelector)); if ((status < 0) || (theProcess->tssSelector == 0)) // Crap. An error getting a free descriptor. return (status); // Fill in the process' Task State Segment descriptor status = kernelDescriptorSet( theProcess->tssSelector, // TSS selector number &(theProcess->taskStateSegment), // Starts at... sizeof(kernelTSS), // Limit of a TSS segment 1, // Present in memory PRIVILEGE_SUPERVISOR, // TSSs are supervisor privilege level 0, // TSSs are system segs 0xB, // TSS, 32-bit, busy 0, // 0 for SMALL size granularity 0); // Must be 0 in TSS if (status < 0) { // Crap. An error getting a free descriptor. kernelDescriptorRelease(theProcess->tssSelector); return (status); } // Now, fill in the TSS (Task State Segment) for the new process. Parts // of this will be different depending on whether this is a user // or supervisor mode process kernelMemClear((void *) &(theProcess->taskStateSegment), sizeof(kernelTSS)); if (theProcess->privilege == PRIVILEGE_SUPERVISOR) { theProcess->taskStateSegment.CS = PRIV_CODE; theProcess->taskStateSegment.DS = PRIV_DATA; theProcess->taskStateSegment.SS = PRIV_STACK; } else { theProcess->taskStateSegment.CS = USER_CODE; theProcess->taskStateSegment.DS = USER_DATA; theProcess->taskStateSegment.SS = USER_STACK; } theProcess->taskStateSegment.ES = theProcess->taskStateSegment.DS; theProcess->taskStateSegment.FS = theProcess->taskStateSegment.DS; theProcess->taskStateSegment.GS = theProcess->taskStateSegment.DS; theProcess->taskStateSegment.ESP = ((unsigned) theProcess->userStack + (theProcess->userStackSize - sizeof(int))); if (theProcess->privilege == PRIVILEGE_USER) { theProcess->taskStateSegment.SS0 = PRIV_STACK; theProcess->taskStateSegment.ESP0 = ((unsigned) theProcess->superStack + (theProcess->superStackSize - sizeof(int))); } theProcess->taskStateSegment.EFLAGS = 0x00000202; // Interrupts enabled theProcess->taskStateSegment.CR3 = ((unsigned) processPageDir); // All remaining values will be NULL from initialization. Note that this // includes the EIP. // Return success return (status = 0);}static int createNewProcess(const char *name, int priority, int privilege, processImage *execImage, int newPageDir){ // This function is used to create a new process in the process // queue. It makes a "defaults" kind of process -- it sets up all of // the process' attributes with default values. If the calling process // wants something different, it should reset those attributes afterward. // If successful, it returns the processId of the new process. Otherwise, // it returns negative. int status = 0; kernelProcess *newProcess = NULL; void *stackMemoryAddr = NULL; void *processPageDir = NULL; void *physicalCodeData = NULL; int *args = NULL; char **argv = NULL; int argSpaceSize = 0; char *argSpace = NULL; char *newArgAddress = NULL; int length = 0; int count; // Don't bother checking the parameters, as the external functions // should have done this already. // We need to see if we can get some fresh process control memory status = requestProcess(&newProcess); if (status < 0) return (status); if (newProcess == NULL) return (status = ERR_NOFREE); // Ok, we got a new, fresh process. We need to start filling in some // of the process' data (after initializing it, of course) kernelMemClear((void *) newProcess, sizeof(kernelProcess)); // Fill in the process' Id number newProcess->processId = processIdCounter++; // By default, the type is process newProcess->type = proc_normal; // Now, if the process Id is KERNELPROCID, then we are creating the // kernel process, and it will be its own parent. Otherwise, get the // current process and make IT be the parent of this new process if (newProcess->processId == KERNELPROCID) { newProcess->parentProcessId = newProcess->processId; newProcess->userId = 1; // root // Give it "/" as current working directory strncpy((char *) newProcess->currentDirectory, "/", 2); } else { // Make sure the current process isn't NULL if (kernelCurrentProcess == NULL) { releaseProcess(newProcess); return (status = ERR_NOSUCHPROCESS); } // Fill in the process' parent Id number newProcess->parentProcessId = kernelCurrentProcess->processId; // Fill in the process' user Id number newProcess->userId = kernelCurrentProcess->userId; // Fill in the current working directory strncpy((char *) newProcess->currentDirectory, (char *) kernelCurrentProcess->currentDirectory, MAX_PATH_LENGTH); newProcess->currentDirectory[MAX_PATH_LENGTH - 1] = '\0'; } // Fill in the process name strncpy((char *) newProcess->processName, name, MAX_PROCNAME_LENGTH); newProcess->processName[MAX_PROCNAME_LENGTH - 1] = '\0'; // Fill in the process' priority level newProcess->priority = priority; // Fill in the process' privilege level newProcess->privilege = privilege; // The amount of time since started (now) newProcess->startTime = kernelSysTimerRead(); // The thread's initial state will be "stopped" newProcess->state = proc_stopped; // Do we need to create a new page directory and a set of page tables for // this process? if (newPageDir) { // We need to make a new page directory, etc. processPageDir = kernelPageNewDirectory(newProcess->processId, newProcess->privilege); if (processPageDir == NULL) { // Not able to setup a page directory releaseProcess(newProcess); return (status = ERR_NOVIRTUAL); } // Get the physical address of the code/data physicalCodeData =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -