This repository has been archived by the owner on Jan 20, 2021. It is now read-only.
forked from vsamtuc/tinyos3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkernel_threads.c
227 lines (191 loc) · 5.14 KB
/
kernel_threads.c
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include "tinyos.h"
#include "kernel_sched.h"
#include "kernel_proc.h"
#include "kernel_cc.h"
/**
@brief Create a new thread in the current process.
*/
Tid_t sys_CreateThread(Task task, int argl, void* args)
{
if(task == NULL){
return NOTHREAD;
}
// Just like sys_exec()
// new thread on the process
CURPROC->thread_count++;
// grab new ptcb
PTCB * ptcb = init_PTCB(task, argl, args);
// push back the ptcb
rlist_push_back(&CURPROC->ptcb_list, &ptcb->ptcb_list_node);
// spawn the new thread and make neccessary connetions
TCB * tcb = spawn_thread(CURPROC, start_thread);
ptcb->tcb = tcb;
tcb->ptcb = ptcb;
// wake up thread
wakeup(ptcb->tcb);
return (Tid_t ) ptcb;
}
/**
@brief Return the Tid of the current PTCB
*/
Tid_t sys_ThreadSelf()
{
return (Tid_t) cur_thread()->ptcb;
}
/**
@brief Join the given thread.
An exited thread needs another to join it in order to be freed
Otherwise the PTCBs are freed by the last thread of the process when exiting
Return 0 on SUCCESS -1 on FAILURE
*/
int sys_ThreadJoin(Tid_t tid, int* exitval)
{
// try to find the PTCB
rlnode* node = rlist_find(&(cur_thread()->owner_pcb->ptcb_list), (PTCB *)tid, NULL);
if(node == NULL){
return -1;
}
PTCB* ptcb = node->ptcb;
// PTCB* ptcb = (PTCB *)tid;
//assert(ptcb != NULL);
// can't join a detached thread
// can't join our selves ffs....
// can't join a thread with no ptcb obv...
if((ptcb == NULL) || (ptcb->detached) || (ptcb->tcb == cur_thread())){return -1;}
else{
// one more to the waiting list
ptcb->ref_count++;
// sleep until thread exits or thread is detached
while(!ptcb->exited && !ptcb->detached){
kernel_wait(&ptcb->exit_cv, SCHED_USER);
}
// check if thread exited w/ detached status
ptcb->ref_count--;
if(ptcb->detached){
return -1;
}else{
// set any exit value
if(exitval){
*(exitval) = ptcb->exitval;
}
// if last waiting then clear ptcb
// might change
if(ptcb->ref_count < 1){
rlist_remove(&ptcb->ptcb_list_node);
free(ptcb);
}
return 0;
}
}
}
/**
@brief Detach the given thread.
A detached thread is freed on exit from the last process thread.
A thread can detach itself
*/
int sys_ThreadDetach(Tid_t tid)
{
rlnode* node = rlist_find(&(cur_thread()->owner_pcb->ptcb_list), (PTCB *)tid, NULL);
if(node == NULL){
return -1;
}
PTCB* ptcb = node->ptcb;
// assert(ptcb != NULL);
// cant detach an exited thread
if(ptcb == NULL || ptcb->exited){
return -1;
}else{
// Mark PTCB as detached
ptcb->detached = 1;
// A detached thread cant be waited from anyone
// Mark it's references as 0
ptcb->ref_count = 0;
// Broadcast for detachment
kernel_broadcast(&ptcb->exit_cv);
return 0;
}
return -1;
}
/**
* @brief Terminate the current thread.
* The last thread cleans up the PTCB list of the process
*/
void sys_ThreadExit(int exitval)
{
kill_thread(exitval);
if(CURPROC->thread_count == 0){
PCB * curproc = CURPROC;
// cannot reparent init
// from the new updates after Oct 2020
if(get_pid(curproc) != 1){
/* Reparent any children of the exiting process to the
initial task */
PCB* initpcb = get_pcb(1);
while(!is_rlist_empty(& curproc->children_list)) {
rlnode* child = rlist_pop_front(& curproc->children_list);
child->pcb->parent = initpcb;
rlist_push_front(& initpcb->children_list, child);
}
/* Add exited children to the initial task's exited list
and signal the initial task */
if(!is_rlist_empty(& curproc->exited_list)) {
rlist_append(& initpcb->exited_list, &curproc->exited_list);
kernel_broadcast(& initpcb->child_exit);
}
/* Put me into my parent's exited list */
rlist_push_front(& curproc->parent->exited_list, &curproc->exited_node);
kernel_broadcast(& curproc->parent->child_exit);
}
assert(is_rlist_empty(& curproc->children_list));
assert(is_rlist_empty(& curproc->exited_list));
/*
Do all the other cleanup we want here, close files etc.
*/
/* Release the args data */
if(curproc->args) {
free(curproc->args);
curproc->args = NULL;
}
/* Clean up FIDT */
for(int i=0;i<MAX_FILEID;i++){
if(curproc->FIDT[i] != NULL){
FCB_decref(curproc->FIDT[i]);
curproc->FIDT[i] = NULL;
}
}
/* cleanup detached threads */
while(!is_rlist_empty(&curproc->ptcb_list)){
PTCB * ptcb_temp = rlist_pop_front(&curproc->ptcb_list)->ptcb;
assert(ptcb_temp != NULL);
free(ptcb_temp);
}
/* Disconnect my main_thread */
curproc->main_thread = NULL;
/* Now, mark the process as exited. */
curproc->pstate = ZOMBIE;
}
/* Bye-bye cruel world */
kernel_sleep(EXITED, SCHED_USER);
}
void kill_thread(int exitval){
PTCB * ptcb = cur_thread()->ptcb;
// Mark thread as exited and pass the exit value
ptcb->exited = 1;
ptcb->exitval = exitval;
// Broadcast
kernel_broadcast(&ptcb->exit_cv);
CURPROC->thread_count--;
}
PTCB * init_PTCB(Task task, int argl, void* args){
PTCB * ptcb = (PTCB *)xmalloc(sizeof(PTCB));
ptcb->task = task;
ptcb->argl = argl;
ptcb->args = args;
ptcb->exitval = 0;
ptcb->exited = 0;
ptcb->detached = 0;
ptcb->exit_cv = COND_INIT;
ptcb->ref_count = 0;
rlnode_init(&ptcb->ptcb_list_node, ptcb);
return ptcb;
}