-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathThreadCB.java
More file actions
316 lines (257 loc) · 9.96 KB
/
ThreadCB.java
File metadata and controls
316 lines (257 loc) · 9.96 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
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
package osp.Threads;
import java.util.Vector;
import java.util.Enumeration;
import osp.Utilities.*;
import osp.IFLModules.*;
import osp.Tasks.*;
import osp.EventEngine.*;
import osp.Hardware.*;
import osp.Devices.*;
import osp.Memory.*;
import osp.Resources.*;
/**
Author: Logan Edwards
Email: edwardlw@email.sc.edu
Date: 2013-04-23, R1
Purpose: This class is responsible for actions related to threads, including
creating, killing, dispatching, resuming, and suspending threads.
@OSPProject Threads
*/
public class ThreadCB extends IflThreadCB {
//--------------------//
// Instance variables //
//--------------------//
// Linked list implementation for ready queue
static GenericList readyQueue;
/**
The thread constructor.
@OSPProject Threads
*/
public ThreadCB() {
super();
}
/**
This method will be called once at the beginning of the
simulation. The student can set up static variables here.
@OSPProject Threads
*/
public static void init() {
// Initialize the ready queue
readyQueue = new GenericList();
}
/**
Sets up a new thread and adds it to the given task.
The method must set the ready status
and attempt to add thread to task. If the latter fails
because there are already too many threads in this task,
so does this method, otherwise, the thread is appended
to the ready queue and dispatch() is called.
The priority of the thread can be set using the getPriority/setPriority
methods. However, OSP itself doesn't care what the actual value of
the priority is. These methods are just provided in case priority
scheduling is required.
@return thread or null
@OSPProject Threads
*/
static public ThreadCB do_create(TaskCB task) {
// Don't create a thread if the task object is null or full of threads
if ((task == null) || (task.getThreadCount() == MaxThreadsPerTask)) {
dispatch();
return null;
}
// If we passed the previous test, actually create the thread
ThreadCB thread = new ThreadCB();
// Add reference to parent task
thread.setPriority(task.getPriority());
thread.setStatus(ThreadReady);
thread.setTask(task);
// return null if FAILURE returned from addThread()
if (task.addThread(thread) == 0) {
dispatch();
return null;
}
// The final bit; add to the ready queue
readyQueue.append(thread);
dispatch();
return thread;
}
/**
Kills the specified thread.
The status must be set to ThreadKill, the thread must be
removed from the task's list of threads and its pending IORBs
must be purged from all device queues.
If some thread was on the ready queue, it must removed, if the
thread was running, the processor becomes idle, and dispatch()
must be called to resume a waiting thread.
@OSPProject Threads
*/
public void do_kill() {
TaskCB theTask = null;
// Handle the ThreadReady case
if (this.getStatus() == ThreadReady) {
readyQueue.remove(this);
this.setStatus(ThreadKill);
}
// Handle the ThreadRunning case
if (this.getStatus() == ThreadRunning) {
// Do the right stuff when we find out it is the thread
// that we want to kill
if (MMU.getPTBR().getTask().getCurrentThread() == this) {
MMU.setPTBR(null);
getTask().setCurrentThread(null);
}
}
// Handle the ThreadWaiting case
if (this.getStatus() >= ThreadWaiting) {
this.setStatus(ThreadKill);
}
// Get the associated task and kill thread
theTask = this.getTask();
theTask.removeThread(this);
this.setStatus(ThreadKill);
// Make sure IO resources are released
for (int i = 0; i < Device.getTableSize(); i++) {
Device.get(i).cancelPendingIO(this);
}
ResourceCB.giveupResources(this);
// Kill the task if no remaining threads
// Sad, but an extra task without threads
// is just a bit wasteful ;-)
if (this.getTask().getThreadCount() == 0) {
this.getTask().kill();
}
dispatch();
}
/** Suspends the thread that is currenly on the processor on the
specified event.
Note that the thread being suspended doesn't need to be
running. It can also be waiting for completion of a pagefault
and be suspended on the IORB that is bringing the page in.
Thread's status must be changed to ThreadWaiting or higher,
the processor set to idle, the thread must be in the right
waiting queue, and dispatch() must be called to give CPU
control to some other thread.
@param event - event on which to suspend this thread.
@OSPProject Threads
*/
public void do_suspend(Event event) {
boolean changedToWait = false;
// Handle the ThreadRunning case
//
if (this.getStatus() == ThreadRunning) {
if (MMU.getPTBR().getTask().getCurrentThread() == this) {
MMU.setPTBR(null);
this.getTask().setCurrentThread(null);
this.setStatus(ThreadWaiting);
event.addThread(this);
changedToWait = true; // Used so we don't enter the next if below
}
} // End of context switch
// Handle the ThreadWaiting case
if (this.getStatus() >= ThreadWaiting && !changedToWait) {
this.setStatus(this.getStatus()+1);
if (!readyQueue.contains(this)) {
event.addThread(this);
//MyOut.print("Added to the event queue");
}
}
// Call for another thread
dispatch();
}
/** Code from p.41 of OSP
Resumes the thread.
Only a thread with the status ThreadWaiting or higher
can be resumed. The status must be set to ThreadReady or
decremented, respectively.
A ready thread should be placed on the ready queue.
@OSPProject Threads
*/
public void do_resume()
{
if(getStatus() < ThreadWaiting) {
MyOut.print(this, "Attempt to resume " + this + ", which wasn't waiting");
return;
}
// Message to indicate we are attempting to resume this thread
MyOut.print(this, "Resuming " + this);
// Set the thread's status
if(this.getStatus() == ThreadWaiting) {
setStatus(ThreadReady);
} else if (this.getStatus() > ThreadWaiting) {
setStatus(getStatus()-1);
}
// Put the thread on the ready queue, if appropriate
if (getStatus() == ThreadReady) {
readyQueue.append(this);
}
dispatch(); // dispatch a thread
}
/**
Selects a thread from the run queue and dispatches it.
If there is just one thread ready to run, reschedule the thread
currently on the processor.
In addition to setting the correct thread status it must
update the PTBR.
@return SUCCESS or FAILURE
@OSPProject Threads
*/
public static int do_dispatch() {
// Null threads to be possibly used later
ThreadCB thread = null;
ThreadCB newThread = null;
// Handle the ThreadRunning case
try {
thread = MMU.getPTBR().getTask().getCurrentThread();
}
catch (NullPointerException e){
// Should something smart be done here?
// Print statements not working at compile
}
if (thread != null) {
// thread = MMU.getPTBR().getTask().getCurrentThread();
// Relinquish control of the CPU
thread.getTask().setCurrentThread(null);
MMU.setPTBR(null);
// Make ThreadReady and add to ready queue
thread.setStatus(ThreadReady);
readyQueue.append(thread);
}
// If no thread running
// Nothing in the ready queue
if (readyQueue.isEmpty()) {
MMU.setPTBR(null);
//MyOut.print("Nothing in the ready queue. Returning...");
return FAILURE; // Indicating we are not dispatching a thread
}
else {
// If the ready queue has a thread, make it go!
// Remove the head and cast as a ThreadCB object
newThread = (ThreadCB)readyQueue.removeHead();
// Get threads' task, set as the current
MMU.setPTBR(newThread.getTask().getPageTable());
newThread.getTask().setCurrentThread(newThread);
newThread.setStatus(ThreadRunning);
}
return SUCCESS; // Hip hip hooray, we did it.
}
/**
Called by OSP after printing an error message. The student can
insert code here to print various tables and data structures in
their state just after the error happened. The body can be
left empty, if this feature is not used.
@OSPProject Threads
*/
public static void atError() {
// MyOut.print("Ready Queue: " + readyQueue.length());
// MyOut.print("Crash here");
}
/** Called by OSP after printing a warning message. The student
can insert code here to print various tables and data
structures in their state just after the warning happened.
The body can be left empty, if this feature is not used.
@OSPProject Threads
*/
public static void atWarning() {
// MyOut.print("Ready Queue: " + readyQueue.length());
}
}