forked from vsamtuc/tinyos3
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkernel_threads.c
More file actions
196 lines (150 loc) · 3.71 KB
/
Copy pathkernel_threads.c
File metadata and controls
196 lines (150 loc) · 3.71 KB
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
#include "tinyos.h"
#include "kernel_sched.h"
#include "kernel_proc.h"
#include "kernel_streams.h"
#include "kernel_cc.h"
#include "unit_testing.h"
/*
This function is provided as an argument to spawn,
to execute the main thread of a process.
*/
void start_thread()
{
int exitval;
Task call = cur_thread()->ptcb->task;
int argl = cur_thread()->ptcb->argl;
void* args = cur_thread()->ptcb->args;
exitval = call(argl, args);
ThreadExit(exitval);
}
/**
@brief Create a new thread in the current process.
*/
Tid_t sys_CreateThread(Task task, int argl, void *args)
{
PCB* curproc = CURPROC; /*cache for efficiency */
PTCB* nptcb = xmalloc(sizeof(PTCB));
ASSERT(nptcb != NULL);
TCB* ntcb = spawn_thread(curproc, start_thread);
nptcb->tcb = ntcb;
ntcb->ptcb = nptcb;
nptcb->task = task;
nptcb->argl = argl;
nptcb->args = args;
nptcb->exitval = 0;
nptcb->exited = 0;
nptcb->detached = 0;
nptcb->exit_cv = COND_INIT;
nptcb->refcount = 1;
curproc->thread_count++; // bc we add a thread
rlnode_init(& nptcb->ptcb_list_node, nptcb);
/*
This should already happen in sys_Exec. However there is no
seg. fault in the CreateThread_test since we don't call Exec.
*/
// rlnode_init(& curproc->ptcb_list, & curproc);
// add nptcb to ptcb_list of CURPROC
if(task != NULL)
rlist_push_back(& curproc->ptcb_list, & nptcb->ptcb_list_node);
// probably need to wakeup, but which way?
wakeup(ntcb);
// wakeup(curproc->ptcb_list->nptcb->tcb);
// return a ptr to the new PTCB
return (Tid_t) nptcb;
}
/**
@brief Return the Tid of the current thread.
*/
Tid_t sys_ThreadSelf()
{
return (Tid_t)(cur_thread()->ptcb);
}
void PTCB_Decrease(PTCB* ptcb){
ptcb->refcount--;
if(ptcb->refcount==0)
free(ptcb);
}
/**
@brief Join the given thread.
*/
int sys_ThreadJoin(Tid_t tid, int *exitval)
{
PTCB* ptcb = (PTCB*) tid;
// if tid is NOT valid or thread is detached
// add exited check
if (rlist_find(&CURPROC->ptcb_list, ptcb, NULL) == NULL
|| sys_ThreadSelf() == tid)
return -1;
// thread count in waiting list incr
//PTCB *curptcb = (PTCB*) sys_ThreadSelf();
ptcb->refcount++;
// some checks to see if we can join
while (ptcb->exited == 0 && ptcb->detached == 0)
kernel_wait(& ptcb->exit_cv, SCHED_USER);
/*
If the loop exited because of the thread being
detached the return error.
*/
if(ptcb->detached)
{
// thread count in waiting list is decremented
PTCB_Decrease(ptcb);
//ptcb->refcount--;
return -1;
}
// store the exitval of the target thread
if (exitval != NULL)
*exitval = ptcb->exitval;
// free the ptcb
if (rlist_find(&CURPROC->ptcb_list, ptcb, NULL) != NULL)
{
rlist_remove(&ptcb->ptcb_list_node);
PTCB_Decrease(ptcb);
}
PTCB_Decrease(ptcb);
return 0;
}
/**
@brief Detach the given thread.
*/
int sys_ThreadDetach(Tid_t tid)
{
PTCB *ptcb = (PTCB*) tid;
// if tid is valid
if (rlist_find(&CURPROC->ptcb_list, ptcb, NULL) == NULL || ptcb->exited)
return -1;
// set detach flag
ptcb->detached = 1;
kernel_broadcast(& ptcb->exit_cv);
return 0;
}
/**
@brief Terminate the current thread.
*/
void sys_ThreadExit(int exitval)
{
// this function will be called from sys_Exit
PCB* curproc = CURPROC; /*cache for efficiency */
PTCB* ptcb = cur_thread()->ptcb; /*cache for efficiency */
ptcb->refcount++;
ptcb->exited=1;
if(ptcb->detached != 0)
{
rlist_remove(&ptcb->ptcb_list_node);
PTCB_Decrease(ptcb);
}
else
{
ptcb->exitval = exitval;
}
// wake up everyone waiting on this thread
kernel_broadcast(& ptcb->exit_cv);
PTCB_Decrease(ptcb);
// decrement thread_count
curproc->thread_count--;
// checks if it is the last thread
if (curproc->thread_count == 0)
last_thread(curproc);
/* Bye-bye cruel world */
kernel_sleep(EXITED, SCHED_USER);
}