summaryrefslogtreecommitdiff
path: root/Source/Kernel/TaskManager/Thread.class.cpp
blob: cc2f569de054394bbfefbd695f81e982578b4b0f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "Thread.class.h"
#include <TaskManager/Task.ns.h>
#include <MemoryManager/PageAlloc.ns.h>
#include <DeviceManager/Time.ns.h>

void runThread(Thread* thread, u32int (*entry_point)()) {
	asm volatile("sti");
	thread->run(entry_point);
}

Thread::Thread() {	//Private constructor, does nothing
}

Thread::Thread(u32int (*entry_point)(), bool iskernel) {
	if (iskernel) {
		m_isKernel = true;
		u32int tmp;
		m_kernelStackFrame = (u32int)PageAlloc::alloc(&tmp);
		m_process = Task::getKernelProcess();
		setup(entry_point, m_kernelStackFrame + STACKSIZE);
	} else {
		m_isKernel = false;
		m_process = Task::currentProcess;
		setup(entry_point, m_process->stackAlloc() + STACKSIZE);
	}
}

Thread::Thread(Process* process, u32int (*entry_point)()) {
	m_isKernel = false;
	m_process = process;
	setup(entry_point, m_process->stackAlloc() + STACKSIZE);
}

Thread::~Thread() {
	if (m_isKernel)
		PageAlloc::free((void*)m_kernelStackFrame);
	Task::unregisterThread(this);
	//Don't unregister thread in process, it has probably already been done
}

void Thread::setup(u32int (*entry_point)(), u32int esp) {
	//Pass function parameters for runThread()
	u32int *stack = (u32int*)esp;
	stack--;
	*stack = (u32int)entry_point;	//Push entry point (function parameter)
	stack--;
	*stack = (u32int)this;	//Push object pointer
	stack--;
	*stack = 0;	//Null return address
	m_esp = (u32int)stack;
	m_ebp = m_esp + 8;
	m_eip = (u32int)runThread;

	m_state = T_RUNNING;
	m_process->registerThread(this);
	Task::registerThread(this);
}

void Thread::finish(u32int errcode) {
	//Needs not set m_state to a finished state, either :
	// - thread is unregistered from process and everywhere
	// - errcode is an exception or this is main thread, process exits
	m_process->threadFinishes(this, errcode);
} 

void Thread::run(u32int (*entry_point)()) {
	u32int ret = entry_point();	//Run !
	finish(ret);
}

void Thread::setState(u32int esp, u32int ebp, u32int eip) {
	m_esp = esp;
	m_ebp = ebp;
	m_eip = eip;
}

u32int Thread::getEsp() { return m_esp; }
u32int Thread::getEbp() { return m_ebp; }
u32int Thread::getEip() { return m_eip; }

Process* Thread::getProcess() { return m_process; }

void Thread::sleep(u32int msecs) {
	m_state = T_SLEEPING;
	waitfor.m_time = Time::time() + msecs;

	Task::triggerSwitch();
}

void Thread::waitIRQ(u8int irq) {
	if (m_process->m_uid != 0) return;

	m_state = T_IRQWAIT;
	waitfor.m_irq = irq;

	Task::triggerSwitch();
}

bool Thread::runnable() {
	if (m_state == T_RUNNING) return true;
	if (m_state == T_SLEEPING and Time::time() >= waitfor.m_time) {
		m_state = T_RUNNING;
		return true;
	}
	return false;
}