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

📄 thread.c

📁 COS 0.0.1.rar Cos操作系统源代码
💻 C
字号:
/* thread.c - multi-threading support   Author:		Paul Barker Part of:		COS Created:		31/08/04 Last Modified:		05/11/04 Copyright (C) 2004 Paul Barker        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., 675 Mass Ave, Cambridge, MA 02139, USA.                     (See file "Copying")*/#include <cosbase.h>#include <cos/thread.h>#include <cos/mem.h>#include <cos/int.h>#include <cos/symbols.h>#include <cos/string.h>#include <cos/debug.h>#include <x86-asm.h>#include <cos/sysinfo.h>// implemented in thr.sextern void Schedule(interrupt_state_t* state);extern u32_t Get_EFLAGS();// pointer to the current threadstatic kthread_t* volatile pThisThread;// queue of runnable threadsstatic thread_queue_t tqRun;// defined in int.s, fake return address for creating a threadextern char FakeReturnAddr;/////////////////////////////////////////////////////////////////////// Thread Queuesbool_t thread_queue_empty(thread_queue_t* tq){	thread_node_t* p = tq->head;	return (p && p->thread);}void thread_queue_dump(thread_queue_t* tq){	thread_node_t* p = tq->head;	TRACE(("thread_queue_dump %x Head=%x\n", tq, p));		while (p)	{		TRACE(("Node %x : thread=%x, next=%x\n", p, p->thread, p->next));		p = p->next;	}}kthread_t* thread_queue_head(thread_queue_t* tq){	thread_node_t* p = tq->head;	if (!p)		return pThisThread;		tq->head = p->next;	// detach the node	kthread_t* thr = p->thread;	kfree(p);	return thr;}void queue_thread(kthread_t* thr){	thread_queue_t* q = thr->queue;	TRACE(("QueueThread %x in %x\n", thr, q));	if (!(q->head))	{		q->head = kalloc(sizeof(thread_node_t));		q->head->thread = thr;		q->head->next = NULL;		return;	}		thread_node_t* p = q->head;	while (p->next)		p = p->next;	// find end of queue	// last node will have a thread	p->next = kalloc(sizeof(thread_node_t));	p->next->thread = thr;	p->next->next = NULL;}/////////////////////////////////////////////////////////////////////// Private functions// called by low-level scheduler//	assume the current thread is already queued before the interrupt//	currently we only deal with Yield() so this is truekthread_t* do_sched(){	thread_queue_dump(&tqRun);	// assume we always have a runnable thread, for now	kthread_t* thr = thread_queue_head(&tqRun);		TRACE(("Schedule, thr=%x esp=%x\n", thr, thr->esp));	pThisThread = thr;		return thr;		// assembly code expects this in eax}// setup a child threadvoid add_child_thread(kthread_t* thr){	kthread_t* tmp = thr->parent->child;	if (tmp == NULL)	{		thr->parent->child = thr;		return;	}	// find end of child threads	while (tmp->next)		tmp = tmp->next;	tmp->next = thr;}/////////////////////////////////////////////////////////////////////// Public functionskthread_t* get_current_thread(){	return pThisThread;}void yield(){	TRACE(("Yield()\n"));	queue_thread(pThisThread);	__asm__ __volatile__ ("int $0x50"::);}void thread_init(){	TRACE(("InitThread()\n"));	// setup the current thread	pThisThread = kalloc(sizeof(kthread_t));	pThisThread->Stack = 0xA000;		// 40k	pThisThread->StackSize = 0x5000;	// 24k	pThisThread->esp = NULL;			// invalid until we store it in a stack switch	pThisThread->uTicks = START_TICKS;	// assume we just started running	pThisThread->parent = pThisThread->next = pThisThread->child = NULL;			// no parent or child, no other threads allowed at this level		pThisThread->queue = &tqRun;		install_handler(0x50, &Schedule);		init_timer();		g_kernel_state |= THREAD_ENABLED;	TRACE(("InitThread() done\n"));}// TODO: currently processor will become lost in hyperspace if fn returnskthread_t* spawn_thread(thread_function_t fn){	TRACE(("SpawnThread(fn=%x)\n", fn));	kthread_t* thr = kalloc(sizeof(kthread_t));	thr->Stack = (iptr_t)kalloc(8192);	// 2 page stack (8k)	thr->StackSize = 8192;	dword_t* p = (dword_t*)(thr->Stack + 8188);	// top dword of stack	count_t i;		// setup stack as if an interrupt happened	*p-- = Get_EFLAGS() | (1 << 9);	// eflags with interrupt flag forced	*p-- = KERNEL_CS;		// cs	*p-- = (dword_t)fn;		// eip	for (i = 0; i < 8; i++)		*p-- = 0;		// fill errorCode, intNum and registers with zeroes	*p-- = (thr->Stack + 8188);	// C frame pointer in ebp	for (i = 0; i < 4; i++)		*p-- = KERNEL_DS;	//fill segment selectors with kernel data segment		--p;	// Stack now looks as if we were in an interrupt handler	*p = (dword_t)&FakeReturnAddr;	// return address for function call, see int.s		thr->esp = (iptr_t)p;	thr->parent = pThisThread;	thr->next = thr->child = NULL;	add_child_thread(thr);		thr->queue = &tqRun;	queue_thread(thr);		return thr;}// wait on a given thread queuevoid wait(thread_queue_t* tq){	TRACE(("Thread %x waiting on queue %x\n", pThisThread, tq));	assert_ptr(tq);	pThisThread->queue = tq;	yield();}// wake first thread on a queue, returns number of threads wokencount_t wake_one(thread_queue_t* tq){	assert_ptr(tq);	kthread_t* thr = thread_queue_head(tq);		// silently fail on an empty thread queue	if (thr != pThisThread)	{		TRACE(("Waking thread %x from queue %x\n", thr, tq));		thr->queue = &tqRun;		queue_thread(thr);		return 1;	}		return 0;}// wake all threads on a queue, returns number of threads wokencount_t wake_all(thread_queue_t* tq){	assert_ptr(tq);	kthread_t* thr;	count_t i = 0;	TRACE(("Waking all threads from queue %x\n", tq));		// silently fail on an empty thread queue	while (!thread_queue_empty(tq))	{		thr = thread_queue_head(tq);		TRACE(("\tWaking Thread %x\n", thr));		thr->queue = &tqRun;		queue_thread(thr);		i++;	}	TRACE(("WakeAll() Done\n"));	return i;}//////////////////////////////////////////////////////////////////////////// Mutex functions, based on GeekOS implementationvoid do_mlock(mutex_t* m){	cli();	assert_ptr(m);	assert(m->owner != pThisThread);		// wait for the mutex to become free	while (m->state == MUTEX_LOCKED)		wait(&(m->queue));		m->state = MUTEX_LOCKED;	m->owner = pThisThread;		sti();}void do_munlock(mutex_t* m){	cli();	assert_ptr(m);	assert(m->owner == pThisThread);	assert(m->state == MUTEX_LOCKED);		m->state = MUTEX_UNLOCKED;	m->owner = NULL;		wake_one(&m->queue);		sti();}void minit(mutex_t* m){	assert_ptr(m);	m->state = MUTEX_UNLOCKED;	m->owner = NULL;	m->queue.head = NULL;}/* TODO:	this needs some serious attention	change mutex code to use test_and_set*/

⌨️ 快捷键说明

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