GeekOS建立一个可运行进程单位的过程
2018-03-21 10:56
381 查看
一般来说,进程创建过程为:
在进程列表中增加一项,从PCB池中申请一个空间PCB,为新进程分配唯一标识符;为新进程的进程映像分配地址空间,以便容纳进程实体,由进程管理程序确定加载至进程地址空间中的程序;
为新进程分配各种资源;
初始化PCB,如进程标识符、处理器初始状态、进程优先级等;
把新进程的状态设置为就绪态,并将其移入就绪队列;
通知操作系统某些模块,如记账程序、性能监控程序等。
以由ELF文件建立一个可运行的进程单位为例,GeekOS中内核线程的建立流程如下:
1、 Spawn_Init_Process函数的功能是调用Start_Kernel_Thread(),它以Spawner函数为进程体建立一个核心级进程,并使之准备就绪。
Spawner函数运行过程为:通过Read_Fully函数将ELF可执行文件读入内存缓冲区;通过Parse_ELF_Executable函数解析ELF文件, 并通过Spawn_Program函数执行ELF文件。最后通过Free函数释放内存缓冲区。geekos/main.c
void Spawner(unsigned long arg); static void Spawn_Init_Process(void) { /* this thread will load&run ELF files, see the rest in lprog.c */ Print("Starting the Spawner thread...\n"); Start_Kernel_Thread( Spawner, 0, PRIORITY_NORMAL, true ); }
2、Start_Kernel_Thread函数通过调用Create_Thread函数、Setup_Kernel_Thread、Make_Runnable_Atomic来创建内核进程。
geekos/kthread.c/* * Start a kernel-mode-only thread, using given function as its body * and passing given argument as its parameter. Returns pointer * to the new thread if successful, null otherwise. * * startFunc - is the function to be called by the new thread * arg - is a paramter to pass to the new function * priority - the priority of this thread (use PRIORITY_NORMAL) for * most things * detached - use false for kernel threads */ struct Kernel_Thread* Start_Kernel_Thread( Thread_Start_Func startFunc, ulong_t arg, int priority, bool detached ) { struct Kernel_Thread* kthread = Create_Thread(priority, detached); if (kthread != 0) { /* * Create the initial context for the thread to make * it schedulable. */ Setup_Kernel_Thread(kthread, startFunc, arg); /* Atomically put the thread on the run queue. */ Make_Runnable_Atomic(kthread); } return kthread; }
1)Create_Thread函数主要功能为通过Alloc_Page函数为Kernel_Thread结构体和内核进程栈区分配内存空间,并通过Init_Thread函数初始化Kernel_Thread结构体。最后将该进程结构体通过Add_To_Back_Of_All_Thread_List函数加入进程队列末尾。
PS:Kernel_Thread结构体就是GeekOS中的PCB。
geekos/kthread.c
/* * Create a new raw thread object. * Returns a null pointer if there isn't enough memory. */ static struct Kernel_Thread* Create_Thread(int priority, bool detached) { struct Kernel_Thread* kthread; void* stackPage = 0; /* * For now, just allocate one page each for the thread context * object and the thread's stack. */ kthread = Alloc_Page(); if (kthread != 0) stackPage = Alloc_Page(); /* Make sure that the memory allocations succeeded. */ if (kthread == 0) return 0; if (stackPage == 0) { Free_Page(kthread); return 0; } /*Print("New thread @ %x, stack @ %x\n", kthread, stackPage); */ /* * Initialize the stack pointer of the new thread * and accounting info */ Init_Thread(kthread, sta 4000 ckPage, priority, detached); /* Add to the list of all threads in the system. */ Add_To_Back_Of_All_Thread_List(&s_allThreadList, kthread); return kthread; }
geekos/mem.c
/* * Allocate a page of physical memory. */ void* Alloc_Page(void) { struct Page* page; void *result = 0; bool iflag = Begin_Int_Atomic(); /* See if we have a free page */ if (!Is_Page_List_Empty(&s_freeList)) { /* Remove the first page on the freelist. */ page = Get_Front_Of_Page_List(&s_freeList); KASSERT((page->flags & PAGE_ALLOCATED) == 0); Remove_From_Front_Of_Page_List(&s_freeList); /* Mark page as having been allocated. */ page->flags |= PAGE_ALLOCATED; g_freePageCount--; result = (void*) Get_Page_Address(page); } End_Int_Atomic(iflag); return result; }
geekos/kthread.c
/* * Initialize a new Kernel_Thread. */ static void Init_Thread(struct Kernel_Thread* kthread, void* stackPage, int priority, bool detached) { static int nextFreePid = 1; struct Kernel_Thread* owner = detached ? (struct Kernel_Thread*)0 : g_currentThread; memset(kthread, '\0', sizeof(*kthread)); kthread->stackPage = stackPage; kthread->esp = ((ulong_t) kthread->stackPage) + PAGE_SIZE; kthread->numTicks = 0; kthread->priority = priority; kthread->userContext = 0; kthread->owner = owner; /* * The thread has an implicit self-reference. * If the thread is not detached, then its owner * also has a reference to it. */ kthread->refCount = detached ? 1 : 2; kthread->alive = true; Clear_Thread_Queue(&kthread->joinQueue); kthread->pid = nextFreePid++; }
2)Setup_Kernel_Thread函数主要是初始化进程栈区,包括参数地址、返回地址、入口地址、寄存器值等。
geekos/kthread.c
/* * Set up the initial context for a kernel-mode-only thread. */ static void Setup_Kernel_Thread( struct Kernel_Thread* kthread, Thread_Start_Func startFunc, ulong_t arg) { /* * Push the argument to the thread start function, and the * return address (the Shutdown_Thread function, so the thread will * go away cleanly when the start function returns). */ Push(kthread, arg); Push(kthread, (ulong_t) &Shutdown_Thread); /* Push the address of the start function. */ Push(kthread, (ulong_t) startFunc); /* * To make the thread schedulable, we need to make it look * like it was suspended by an interrupt. This means pushing * an "eflags, cs, eip" sequence onto the stack, * as well as int num, error code, saved registers, etc. */ /* * The EFLAGS register will have all bits clear. * The important constraint is that we want to have the IF * bit clear, so that interrupts are disabled when the * thread starts. */ Push(kthread, 0UL); /* EFLAGS */ /* * As the "return address" specifying where the new thread will * start executing, use the Launch_Thread() function. */ Push(kthread, KERNEL_CS); Push(kthread, (ulong_t) &Launch_Thread); /* Push fake error code and interrupt number. */ Push(kthread, 0); Push(kthread, 0); /* Push initial values for general-purpose registers. */ Push_General_Registers(kthread); /* * Push values for saved segment registers. * Only the ds and es registers will contain valid selectors. * The fs and gs registers are not used by any instruction * generated by gcc. */ Push(kthread, KERNEL_DS); /* ds */ Push(kthread, KERNEL_DS); /* es */ Push(kthread, 0); /* fs */ Push(kthread, 0); /* gs */ }
3)Make_Runnable_Atomic函数将该进程设置为就绪态,加入等待执行队列。
geekos/kthread.c
/* * Atomically make a thread runnable. * Assumes interrupts are currently enabled. */ void Make_Runnable_Atomic(struct Kernel_Thread* kthread) { Disable_Interrupts(); Make_Runnable(kthread); Enable_Interrupts(); }
相关文章推荐
- Qt入门之基础篇 ( 二 ) :Qt项目建立、编译、运行和发布过程解析
- 得到一个正在运行进程的 EXE 文件所在目录
- 分析Linux内核创建一个新进程的过程(Linux)
- Qt入门之基础篇 ( 二 ) :Qt项目建立、编译、运行和发布过程解析
- linux下查看一个进程的启动时间和运行时间
- Linux内核及分析 第六周 分析Linux内核创建一个新进程的过程
- 程序运行初期检查是否已经有一个自身的进程在运行,保证一台PC机器只运行一个程序
- (小技巧六)只允许一个进程运行winform
- SQL Server 2005 sa登录失败。已成功与服务器建立连接 但是在登录过程中发生错误。 provider 共享内存提供程序 error 0 管道的另一端上无任何进程。
- 分析LINUX内核创建一个新进程的过程
- VC 程序只运行一个进程,再次运行传参数给第一个进程的问题
- Android运行出现“java.io.IOException: 您的主机中的软件放弃了一个已建立的连接。”
- 程序执行过程的跟踪:(用debug来跟踪一个程序的运行过程) 整理总结
- 举例说明一个 java程序的加载,初始化以及运行过程
- 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: 共享内存提供程序, error: 0 - 管道的另一端上无任何进程。)
- 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: 共享内存提供程序, error: 0 - 管道的另一端上无任何进程。)
- 只允许一个进程运行winform
- 已成功与服务器建立连接 但是在登录过程中发生错误。 provider 共享内存提供程序 error 0 管道的另一端上无任何进程。
- 通过一个可执行文件被执行的过程理解进程的深刻性
- 【原创】一个线程oom,进程里其他线程还能运行吗?