-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscheduler.c
1277 lines (1067 loc) · 35.9 KB
/
scheduler.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
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
10/28/2017
Authors: Connor Lundberg, Jacob Ackerman
In this project we will be making an MLFQ scheduling algorithm
that will take a PriorityQueue of PCBs and run them through our scheduler.
It will simulate the "running" of the process by incrementing the running PCB's PCB
by one on each loop through. It will also incorporate various interrupts to show
the effects it has on the scheduling simulator.
This file holds the defined functions declared in the scheduler.h header file.
*/
#include "scheduler.h"
unsigned int sysstack;
int switchCalls;
Scheduler thisScheduler;
PCB privileged[4];
int privilege_counter = 0;
int ran_term_num = 0;
int terminated = 0;
int currQuantumSize;
int quantum_tick = 0; // Use for quantum length tracking
int io_timer = 0;
time_t t;
int contextSwitchCount = 0;
// The global counts of each PCB type, the final count at end of program run
// should be roughly 50%, 25%, 12.5%, 12.5% respectively.
int compCount;
int ioCount;
int pairCount;
int sharedCount;
/*
This function is our main loop. It creates a Scheduler object and follows the
steps a normal MLFQ Priority Scheduler would to "run" for a certain length of time,
check for all interrupt types, then call the ISR, scheduler,
dispatcher, and eventually an IRET to return to the top of the loop and start
with the new process.
*/
void osLoop () {
int totalProcesses = 0, iterationCount = 1, lock = 0, unlock = 0, isSwitched = 0;
Mutex currMutex;
thisScheduler = schedulerConstructor();
totalProcesses += makePCBList(thisScheduler);
printSchedulerState(thisScheduler);
for(;;) {
if (thisScheduler->running != NULL) { // In case the first makePCBList makes 0 PCBs
if (thisScheduler->running->role == PAIR || thisScheduler->running->role == SHARED) {
isSwitched = useMutex(thisScheduler);
if (isSwitched) { // call deadlockMonitor after every 10th context switch
contextSwitchCount++;
if (contextSwitchCount == 10) {
deadlockMonitor(thisScheduler);
contextSwitchCount = 0;
}
}
}
if (!isSwitched) { //If the context wasn't switched inside of useMutex
thisScheduler->running->context->pc++;
if (timerInterrupt(iterationCount) == 1) {
pseudoISR(thisScheduler, IS_TIMER);
printf("Completed Timer Interrupt\n");
printSchedulerState(thisScheduler);
iterationCount++;
}
if (ioTrap(thisScheduler->running) == 1) {
printf("Iteration: %d\r\n", iterationCount);
printf("Initiating I/O Trap\r\n");
printf("PC when I/O Trap is Reached: %d\r\n", thisScheduler->running->context->pc);
pseudoISR(thisScheduler, IS_IO_TRAP);
printSchedulerState(thisScheduler);
iterationCount++;
printf("Completed I/O Trap\n");
}
if (thisScheduler->running != NULL)
{
if (thisScheduler->running->context->pc >= thisScheduler->running->max_pc) {
thisScheduler->running->context->pc = 0;
thisScheduler->running->term_count++; //if terminate value is > 0
}
}
if (ioInterrupt(thisScheduler->blocked) == 1) {
printf("Iteration: %d\r\n", iterationCount);
printf("Initiating I/O Interrupt\n");
pseudoISR(thisScheduler, IS_IO_INTERRUPT);
printSchedulerState(thisScheduler);
iterationCount++;
printf("Completed I/O Interrupt\n");
}
// if running PCB's terminate == running PCB's term_count, then terminate (for real).
terminate(thisScheduler);
}
} else {
iterationCount++;
printf("Idle\n");
}
if (!(iterationCount % RESET_COUNT)) {
printf("\r\nRESETTING MLFQ\r\n");
printf("iterationCount: %d\n", iterationCount);
resetMLFQ(thisScheduler);
//printf("here5.9\n");
if (rand() % MAKE_PCB_CHANCE_DOMAIN <= MAKE_PCB_CHANCE_PERCENTAGE) {
//printf("here6\n");
totalProcesses += makePCBList (thisScheduler);
}
//printf("here6.5\n");
printSchedulerState(thisScheduler);
//printf("here6.6\n");
iterationCount = 1;
}
if (totalProcesses >= MAX_PCB_TOTAL) {
printf("Reached max PCBs, ending Scheduler.\r\n");
break;
}
}
schedulerDeconstructor(thisScheduler);
}
/*
Will look through the lockR1 and lockR2 arrays in the given pcb and see if
they match the given PC value. If so, then return the array number, 0 otherwise.
(1 for lockR1, 2 for lockR2)
*/
int isLockPC (unsigned int pc, PCB pcb) {
int isLock = 0;
for (int i = 0; i < TRAP_COUNT; i++) {
if (pc == pcb->lockR1[i]) {
isLock = 1;
break;
}
}
if (pcb->role == SHARED && !isLock) {
for (int i = 0; i < TRAP_COUNT; i++) {
if (pc == pcb->lockR2[i]) {
isLock = 2;
break;
}
}
}
return isLock;
}
/*
Will look through the unlockR1 and unlockR2 arrays in the given pcb and see if
they match the given PC value. If so, then return the array number, 0 otherwise.
(1 for unlockR1, 2 for unlockR2)
*/
int isUnlockPC (unsigned int pc, PCB pcb) {
int isUnlock = 0;
for (int i = 0; i < TRAP_COUNT; i++) {
if (pc == pcb->unlockR1[i]) {
isUnlock = 1;
break;
}
}
if (pcb->role == SHARED && !isUnlock) {
for (int i = 0; i < TRAP_COUNT; i++) {
if (pc == pcb->unlockR2[i]) {
isUnlock = 2;
break;
}
}
}
return isUnlock;
}
/*
Will look through the signal_cond array in the given pcb and see if
they match the given PC value. If so, then return 1, 0 otherwise.
*/
int isSignalPC (unsigned int pc, PCB pcb) {
int isSignal = 0;
for (int i = 0; i < TRAP_COUNT; i++) {
if (pc == pcb->signal_cond[i]) {
isSignal = 1;
break;
}
}
return isSignal;
}
/*
Will look through the signal_cond array in the given pcb and see if
they match the given PC value. If so, then return 1, 0 otherwise.
*/
int isWaitPC (unsigned int pc, PCB pcb) {
int isWait = 0;
for (int i = 0; i < TRAP_COUNT; i++) {
if (pc == pcb->wait_cond[i]) {
isWait = 1;
break;
}
}
return isWait;
}
/*
Checks if the global quantum tick is greater than or equal to
the current quantum size for the running PCB. If so, then reset
the quantum tick to 0 and return 1 so the pseudoISR can occur.
If not, increase quantum tick by 1.
*/
int timerInterrupt(int iterationCount)
{
if (quantum_tick >= currQuantumSize)
{
printf("Iteration: %d\r\n", iterationCount);
printf("Initiating Timer Interrupt\n");
printf("Current quantum tick: %d\r\n", quantum_tick);
quantum_tick = 0;
return 1;
}
else
{
quantum_tick++;
return 0;
}
}
/*
Checks if the current PCB's PC is one of the premade io_traps for this
PCB. If so, then return 1 so the pseudoISR can occur. If not, return 0.
*/
int ioTrap(PCB current)
{
if (current) {
unsigned int the_pc = current->context->pc;
int c;
for (c = 0; c < TRAP_COUNT; c++)
{
if(the_pc == current->io_1_traps[c])
{
return 1;
}
}
for (c = 0; c < TRAP_COUNT; c++)
{
if(the_pc == current->io_2_traps[c])
{
return 1;
}
}
}
return 0;
}
/*
Checks if the next up PCB in the Blocked queue has reached its max
blocked_timer value yet. If so, return 1 and initiate the IO Interrupt.
*/
int ioInterrupt(ReadyQueue the_blocked)
{
if (the_blocked->first_node != NULL && q_peek(the_blocked) != NULL)
{
PCB nextup = q_peek(the_blocked);
if (io_timer >= nextup->blocked_timer)
{
io_timer = 0;
return 1;
}
else
{
io_timer++;
}
}
return 0;
}
/*
This creates the list of new PCBs for the current loop through. It simulates
the creation of each PCB, the changing of state to new, enqueueing into the
list of created PCBs, and moving each of those PCBs into the ready queue.
*/
int makePCBList (Scheduler theScheduler) {
//printf("making new PCBs\n");
// change this to make 2 at a time.
//int newPCBCount = rand() % MAX_PCB_IN_ROUND;
int newPCBCount = 2;
//int mutexCount = rand() & MAX_MUTEX_IN_ROUND;
int lottery = rand();
//for (int i = 0; i < newPCBCount; i++) {
Mutex sharedMutexR1 = mutex_create();
Mutex sharedMutexR2 = mutex_create();
PCB newPCB1 = PCB_create();
PCB newPCB2 = PCB_create();
//printf("newPCB1 == null? %d\n", (newPCB1 == NULL));
//printf("newPCB2 == null? %d\n", (newPCB2 == NULL));
newPCB2->parent = newPCB1->pid;
newPCB1->role = COMP;
newPCB2->role = COMP;
initialize_pcb_type (newPCB1, 1, sharedMutexR1, sharedMutexR2);
initialize_pcb_type (newPCB2, 0, sharedMutexR1, sharedMutexR2);
incrementRoleCount(newPCB1->role);
incrementRoleCount(newPCB2->role);
//printf("\r\nM: ");
//toStringReadyQueueMutexes(theScheduler->killedMutexes);
if (newPCB1->role == COMP || newPCB1->role == IO) { //if the role isn't one that uses a mutex, then destroy it.
//printf("Role wasn't PAIR or SHARED, freeing sharedMutexR1 M%d\r\n", sharedMutexR1->mid);
//printf("Role wasn't PAIR or SHARED, freeing sharedMutexR2 M%d\r\n", sharedMutexR2->mid);
free(sharedMutexR1);
free(sharedMutexR2);
} else {
//printf("Role was PAIR or SHARED, adding sharedMutexR1 M%d\r\n", sharedMutexR1->mid);
//printf("Role was PAIR or SHARED, adding sharedMutexR2 M%d\r\n", sharedMutexR2->mid);
if (newPCB1->role == SHARED) {
printf("=============================\n");
printf("Made Shared Resource pair\n");
if (DEADLOCK) {
populateMutexTraps1221(newPCB1, newPCB1->max_pc / MAX_DIVIDER);
populateMutexTraps2112(newPCB2, newPCB1->max_pc / MAX_DIVIDER);
} else {
populateMutexTraps1221(newPCB1, newPCB1->max_pc / MAX_DIVIDER);
populateMutexTraps1221(newPCB2, newPCB2->max_pc / MAX_DIVIDER);
}
// toStringMutexTraps(newPCB1, newPCB2);
printf("ADDING IN M%d from Shared Resource\n", sharedMutexR1->mid);
printf("ADDING IN M%d from Shared Resource\n", sharedMutexR2->mid);
add_to_mutx_map(theScheduler->mutexes, sharedMutexR1, sharedMutexR1->mid);
add_to_mutx_map(theScheduler->mutexes, sharedMutexR2, sharedMutexR2->mid);
printf("pcb1->mutex_R1_id: M%d\n", newPCB1->mutex_R1_id);
printf("pcb2->mutex_R2_id: M%d\n", newPCB2->mutex_R2_id);
} else {
/* LOOK AT THIS */
printf("=============================\n");
printf("Made Producer/Consumer\n");
populateProducerConsumerTraps(newPCB1, newPCB1->max_pc / MAX_DIVIDER, newPCB1->isProducer);
populateProducerConsumerTraps(newPCB2, newPCB2->max_pc / MAX_DIVIDER, newPCB2->isProducer);
printf("ADDING IN M%d from Producer/Consumer\n", sharedMutexR1->mid);
add_to_mutx_map(theScheduler->mutexes, sharedMutexR1, sharedMutexR1->mid);
printf("pcb1->mutex_R1_id: M%d\n", newPCB1->mutex_R1_id);
printf("pcb2->mutex_R1_id: M%d\n", newPCB2->mutex_R1_id);
free(sharedMutexR2);
}
}
newPCB1->state = STATE_NEW;
newPCB2->state = STATE_NEW;
//printf("theScheduler->created == NULL: %d\n", (theScheduler->created == NULL));
//printf("enqueueing PCBs\n");
q_enqueue(theScheduler->created, newPCB1);
//printf("enqueued pcb1\n");
q_enqueue(theScheduler->created, newPCB2);
//printf("PCBs enqueued\n");
//}
//printf("Making New PCBs: \r\n");
if (newPCBCount) {
//printf("q_is_empty: %d\r\n", q_is_empty(theScheduler->created));
while (!q_is_empty(theScheduler->created)) {
PCB nextPCB = q_dequeue(theScheduler->created);
//toStringPCB(nextPCB, 0);
nextPCB->state = STATE_READY;
//printf("\r\n");
pq_enqueue(theScheduler->ready, nextPCB);
}
//printf("\r\n");
//toStringPriorityQueue(theScheduler->ready);
if (theScheduler->isNew) {
//printf("Dequeueing PCB ");
//printf("\r\nNEW!!\r\n");
//toStringPCB(pq_peek(theScheduler->ready), 0);
//printf("\r\n\r\n");
theScheduler->running = pq_dequeue(theScheduler->ready);
if (theScheduler->running) {
theScheduler->running->state = STATE_RUNNING;
}
theScheduler->isNew = 0;
currQuantumSize = theScheduler->ready->queues[0]->quantum_size;
}
}
return newPCBCount;
}
/*
Given the roleType of the newly created PCBs, the corresponding global role
type count variable will be incremented. Results will be printed at the end of
program execution. See documentation in pcb.c chooseRole() function for
more details on percentage for each role type count.
*/
void incrementRoleCount (enum pcb_type roleType) {
switch (roleType) {
case COMP:
compCount++;
break;
case IO:
ioCount++;
break;
case PAIR:
pairCount++;
break;
case SHARED:
sharedCount++;
break;
}
}
/*
Creates a random number between 3000 and 4000 and adds it to the current PC.
It then returns that new PC value.
*/
unsigned int runProcess (unsigned int pc, int quantumSize) {
//quantumSize is the difference in time slice length between
//priority levels.
unsigned int jump;
if (quantumSize != 0) {
jump = rand() % quantumSize;
}
pc += jump;
return pc;
}
/*
Marks the running PCB as terminated. This means it will increment its term_count, if the
term_count is then over its maximum terminate amount, then it will be enqueued into the
Killed queue which will empty when it reaches its TOTAL_TERMINATED size.
*/
void terminate(Scheduler theScheduler) {
if(theScheduler->running != NULL && theScheduler->running->terminate > 0 && theScheduler->running->terminate == theScheduler->running->term_count)
{
printf("Marking for termination...\r\n");
theScheduler->running->state = STATE_HALT;
printf("...\r\n");
scheduling(IS_TERMINATING, theScheduler);
}
}
/*
This acts as an Interrupt Service Routine, but only for the Timer interrupt.
It handles changing the running PCB state to Interrupted, moving the running
PCB to interrupted, saving the PC to the SysStack and calling the scheduler.
*/
void pseudoISR (Scheduler theScheduler, int interruptType) {
if (theScheduler->running && theScheduler->running->state != STATE_HALT) {
theScheduler->running->state = STATE_INT;
theScheduler->interrupted = theScheduler->running;
}
scheduling(interruptType, theScheduler);
//printf("finished scheduling\n");
//printf("entering IRET\n");
pseudoIRET(theScheduler);
//printf("finished IRET\n");
printf("Exiting ISR\n");
}
/*
Prints the state of the Scheduler. Mostly this consists of the MLFQ, the next
highest priority PCB in line, the one that will be run on next iteration, and
the current list of "privileged PCBs" that will not be terminated.
*/
void printSchedulerState (Scheduler theScheduler) {
printf("MLFQ State\r\n");
toStringPriorityQueue(theScheduler->ready);
printf("\r\n");
int index = 0;
// PRIVILIGED PID
while(privileged[index] != NULL && index < MAX_PRIVILEGE) {
printf("PCB PID %d, PRIORITY %d, PC %d\n",
privileged[index]->pid, privileged[index]->priority,
privileged[index]->context->pc);
index++;
}
printf("blocked size: %d\r\n", theScheduler->blocked->size);
printf("killed size: %d\r\n", theScheduler->killed->size);
printf("killedMutexes size: %d\r\n", theScheduler->killedMutexes->size);
printf("\r\n");
if (pq_peek(theScheduler->ready) != NULL) {
printf("Going to be running ");
if (theScheduler->running) {
toStringPCB(theScheduler->running, 0);
} else {
printf("\r\n");
}
printf("Next highest priority PCB ");
toStringPCB(pq_peek(theScheduler->ready), 0);
printf("\r\n\r\n\r\n");
} else {
if (theScheduler->running != NULL) {
printf("Going to be running ");
toStringPCB(theScheduler->running, 0);
} else {
printf("\r\n");
}
printf("Next highest priority PCB contents: The MLFQ is empty!\r\n");
printf("\r\n\r\n\r\n");
}
}
/*
Used to move every value in the MLFQ back to the highest priority
ReadyQueue after a predetermined time. It does this by taking the first value
of each ReadyQueue (after the 0 *highest priority* queue) and setting it to
be the new last value of the 0 queue.
*/
void resetMLFQ (Scheduler theScheduler) {
int allEmpty = 1;
for (int i = 1; i < NUM_PRIORITIES; i++) {
ReadyQueue curr = theScheduler->ready->queues[i];
if (!q_is_empty(curr)) {
if (!q_is_empty(theScheduler->ready->queues[0])) {
theScheduler->ready->queues[0]->last_node->next = curr->first_node;
theScheduler->ready->queues[0]->last_node = curr->last_node;
theScheduler->ready->queues[0]->size += curr->size;
allEmpty = 0;
} else {
theScheduler->ready->queues[0]->first_node = curr->first_node;
theScheduler->ready->queues[0]->last_node = curr->last_node;
theScheduler->ready->queues[0]->size = curr->size;
}
resetReadyQueue(curr);
}
}
if (allEmpty) {
theScheduler->isNew = 1;
}
}
/*
Resets the given ReadyQueue to be empty.
*/
void resetReadyQueue (ReadyQueue queue) {
ReadyQueueNode ptr = queue->first_node;
while (ptr) {
ptr->pcb->priority = 0;
ptr = ptr->next;
}
queue->first_node = NULL;
queue->last_node = NULL;
queue->size = 0;
}
/*
If the interrupt that occurs was a Timer interrupt, it will simply set the
interrupted PCBs state to Ready and enqueue it into the Ready queue. If it is
an IO Trap, then it will put the running PCB into the Blocked queue. If it is
an IO Interrupt, then it will take the top of the Blocked queue and enqueue it
back into the MLFQ. If it is a termination, then the running PCB will be marked
as such and, if its term_count is greater than its maximum terminate amount, will
be enqueued into the Killed queue. Then, if the Killed queue is at or above its own
TOTAL_TERMINATED size, it will be emptied. It then calls the dispatcher to get the
next PCB in the queue.
*/
void scheduling (int interrupt_code, Scheduler theScheduler) {
//Mutex currMutex;
if (interrupt_code == IS_TIMER) {
printf("Entering Timer Interrupt\r\n");
theScheduler->interrupted->state = STATE_READY;
if (theScheduler->interrupted->priority < (NUM_PRIORITIES - 1)) {
theScheduler->interrupted->priority++;
} else {
theScheduler->interrupted->priority = 0;
}
printf("\r\nEnqueueing into MLFQ\r\n");
toStringPCB(theScheduler->running, 0);
//printf("after1\n");
pq_enqueue(theScheduler->ready, theScheduler->interrupted);
//printf("done enqueueing\n");
//toStringPriorityQueue(theScheduler->ready);
//printf("ENQ!\r\n");
int index = isPrivileged(theScheduler->running);
if (index != 0) {
privileged[index] = theScheduler->running;
}
printf("Exiting Timer Interrupt\r\n");
}
else if (interrupt_code == IS_IO_TRAP)
{
// Do I/O trap handling
printf("Entering IO Trap\r\n");
int timer = (rand() % TIMER_RANGE + 1);
theScheduler->interrupted->blocked_timer = timer;
theScheduler->interrupted->state = STATE_WAIT;
printf("\r\nEnqueueing into Blocked queue\r\n");
toStringPCB(theScheduler->interrupted, 0);
//printf("after\n");
//exit(0);
//printf("going to enqueue\n");
q_enqueue(theScheduler->blocked, theScheduler->interrupted);
//printf("done enqueueing\n");
theScheduler->interrupted = NULL;
// schedule a new process
printf("Exiting IO Trap\r\n");
}
else if (interrupt_code == IS_IO_INTERRUPT)
{
printf("Entering IO Interrupt\r\n");
// Do I/O interrupt handling
printf("\r\nEnqueueing into MLFQ from Blocked queue\r\n");
toStringPCB(q_peek(theScheduler->blocked), 0);
pq_enqueue(theScheduler->ready, q_dequeue(theScheduler->blocked));
//printSchedulerState(theScheduler);
if (theScheduler->interrupted != NULL)
{
theScheduler->running = theScheduler->interrupted;
theScheduler->running->state = STATE_RUNNING;
sysstack = theScheduler->running->context->pc;
}
theScheduler->interrupted = NULL;
printf("Exiting IO Interrupt\r\n");
}
if (theScheduler->interrupted != NULL && theScheduler->interrupted->state == STATE_HALT) {
printf("entering handleKilledQueueInsertion\n");
handleKilledQueueInsertion(theScheduler);
printf("finished handleKilledQueueInsertion\n");
}
// I/O interrupt does not require putting a new process
// into the running state, so we ignore this.
if(interrupt_code != IS_IO_INTERRUPT)
{
//this was calling pq_peek, why?
theScheduler->running = pq_dequeue(theScheduler->ready);
}
if (theScheduler->killed->size >= TOTAL_TERMINATED) {
handleKilledQueueEmptying(theScheduler);
}
// I/O interrupt does not require putting a new process
// into the running state, so we ignore this.
if(interrupt_code != IS_IO_INTERRUPT)
{
//printf("entering dispatcher\n");
dispatcher(theScheduler);
//printf("exited dispatcher\n");
}
}
/*
This simply gets the next ready PCB from the Ready queue and moves it into the
running state of the Scheduler.
*/
void dispatcher (Scheduler theScheduler) {
if (pq_peek(theScheduler->ready) != NULL && pq_peek(theScheduler->ready)->state != STATE_HALT) {
//printf("inside dispatcher\n");
currQuantumSize = getNextQuantumSize(theScheduler->ready);
theScheduler->running = pq_dequeue(theScheduler->ready);
theScheduler->running->state = STATE_RUNNING;
theScheduler->interrupted = NULL;
}
}
/*
This simply sets the running PCB's PC to the value in the SysStack;
*/
void pseudoIRET (Scheduler theScheduler) {
if (theScheduler->running != NULL) {
theScheduler->running->context->pc = sysstack;
}
}
/*
This will construct the Scheduler, along with its numerous ReadyQueues and
important PCBs.
*/
Scheduler schedulerConstructor () {
Scheduler newScheduler = (Scheduler) malloc (sizeof(struct scheduler));
newScheduler->created = q_create();
newScheduler->killed = q_create();
newScheduler->blocked = q_create();
newScheduler->killedMutexes = q_create();
newScheduler->mutexes = create_mutx_map();
newScheduler->ready = pq_create();
newScheduler->running = NULL;
newScheduler->interrupted = NULL;
newScheduler->isNew = 1;
return newScheduler;
}
/*
This will do the opposite of the constructor with the exception of
the interrupted PCB which checks for equivalancy of it and the running
PCB to see if they are pointing to the same freed process (so the program
doesn't crash).
*/
void schedulerDeconstructor (Scheduler theScheduler) {
//printf("\r\n");
if (theScheduler) {
if (theScheduler->ready) {
//printf("destroying ready\n");
//toStringPriorityQueue(theScheduler->ready);
pq_destroy(theScheduler->ready);
}
if (theScheduler->created) {
//printf("destroying created\n");
q_destroy(theScheduler->created);
}
if (theScheduler->killed) {
//printf("destroying killed\n");
q_destroy(theScheduler->killed);
}
if (theScheduler->blocked) {
//printf("destroying blocked\n");
q_destroy(theScheduler->blocked);
}
if (theScheduler->killedMutexes) {
//printf("destroying killedMutexes\n");
q_destroy_m(theScheduler->killedMutexes);
//printf("destroyed killedMutexes\n");
}
if (theScheduler->mutexes) {
//destroy mutex map
}
if (theScheduler->running) {
//printf("destroying running\n");
PCB_destroy(theScheduler->running);
}
if (theScheduler->interrupted && theScheduler->running && theScheduler->interrupted == theScheduler->running) {
//printf("destroying interrupted\n");
PCB_destroy(theScheduler->interrupted);
}
//printf("destroying scheduler\n");
free (theScheduler);
}
displayRoleCountResults();
}
void displayRoleCountResults() {
printf("\r\nTOTAL ROLE TYPES: %d\r\n\r\n", (compCount + ioCount + pairCount + sharedCount));
printf("COMP: \t%d\r\n", compCount);
printf("IO: \t%d\r\n", ioCount);
printf("PAIR: \t%d\r\n", pairCount);
printf("SHARED: %d\r\n", sharedCount);
}
int isPrivileged(PCB pcb) {
if (pcb != NULL) {
for (int i = 0; i < 4; i++) {
if (privileged[i] == pcb) {
return i;
}
}
}
return 0;
}
//normal main
// void main () {
// setvbuf(stdout, NULL, _IONBF, 0);
// srand((unsigned) time(&t));
// sysstack = 0;
// switchCalls = 0;
// currQuantumSize = 0;
// initialize pcb type counts
// compCount = 0;
// ioCount = 0;
// pairCount = 0;
// sharedCount = 0;
// osLoop();
// }
// lock\unlock tests
void main () {
setvbuf(stdout, NULL, _IONBF, 0);
srand((unsigned) time(&t));
int outerLoop = 100;
int innerLoop = 300;
int count = 0;
int mutexCount = rand() % MAX_MUTEX_IN_ROUND;
if (!mutexCount) {
mutexCount++;
}
Scheduler scheduler = schedulerConstructor();
for (int i = 0; i < outerLoop; i++) {
makePCBList(scheduler);
}
while (count < 30000) {
if (scheduler->running->role == PAIR || scheduler->running->role == SHARED) {
printf("the running mutex_R1_id: %d\n", scheduler->running->mutex_R1_id);
useMutex (scheduler);
}
scheduler->running->context->pc++;
if (count % 6 == 0) {
pq_enqueue(scheduler->ready, scheduler->running);
scheduler->running = pq_dequeue(scheduler->ready);
}
count++;
}
schedulerDeconstructor(scheduler);
}
/*
If the Running PCB is of role PAIR or SHARED, then this function is called. What this
does is handle the locking, unlocking, signalling, and waiting for the Mutexes and
their ConditionVariables. If it's determined to be a lock or unlock operation, it will
return a 1 or 2 from the respective isLockPC or isUnlockPC saying which of the two SHARED
resource the PC is found within, so we know which sharedMutex to look for in the MutexMap.
If a Mutex tries to lock, but the Mutex is already locked, it will simply stall the Mutex.
Meaning, it will simply perform a simple context switch on the running PCB and put it back
into the MLFQ and set the running to the MLFQ dequeue. This happens for lock and wait.
Returns 1 if a context switched happen so the osLoop knows to start over, otherwise 0.
*/
int useMutex (Scheduler thisScheduler) {
printf("the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
int wait = 0, signal = 0;
int lock = isLockPC(thisScheduler->running->context->pc, thisScheduler->running);
int unlock = isUnlockPC(thisScheduler->running->context->pc, thisScheduler->running);
printf("the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
if (thisScheduler->running->role = PAIR) {
if (thisScheduler->running->isProducer) {
signal = isSignalPC(thisScheduler->running->context->pc, thisScheduler->running);
} else {
wait = isWaitPC(thisScheduler->running->context->pc, thisScheduler->running);
}
}
printf("the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
Mutex currMutex = NULL;
if (lock) {
printf("lock the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
printPCLocations(thisScheduler->running->lockR1);
printPCLocations(thisScheduler->running->lockR2);
if (lock == 1) { //is mutex_R1_id
printf("lock the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
currMutex = get_mutx(thisScheduler->mutexes, thisScheduler->running->mutex_R1_id);
} else { //is mutex_R2_id
currMutex = get_mutx(thisScheduler->mutexes, thisScheduler->running->mutex_R2_id);
}
if (currMutex) {
mutex_lock (currMutex, thisScheduler->running);
if (currMutex->hasLock != thisScheduler->running) {
printf("M%d already locked, going to wait for unlock\r\n");
pq_enqueue(thisScheduler->ready, thisScheduler->running);
thisScheduler->running = pq_dequeue(thisScheduler->ready);
return 1;
} else {
printf("M%d locked at PC %d\n", currMutex->mid, thisScheduler->running->context->pc);
}
} else {
printf("\r\n\t\t\tcurrMutex was null!!!\r\n\r\n");
exit(0);
}
} else if (unlock) {
printf("unlock the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
if (unlock == 1) { //is mutex_R1_id
currMutex = get_mutx(thisScheduler->mutexes, thisScheduler->running->mutex_R1_id);
} else { //is mutex_R2_id
currMutex = get_mutx(thisScheduler->mutexes, thisScheduler->running->mutex_R2_id);
}
if (currMutex) {
mutex_unlock (currMutex, thisScheduler->running);
printf("M%d unlocked at PC %d\n", currMutex->mid, thisScheduler->running->context->pc);
} else {
printf("\r\n\t\t\tcurrMutex was null!!!\r\n\r\n");
exit(0);
}
} else if (signal) {
printf("signal the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
currMutex = get_mutx(thisScheduler->mutexes, thisScheduler->running->mutex_R1_id);
if (currMutex) {
cond_var_signal (currMutex->condVar);
printf("M%d condition variable signalled at PC %d\n", currMutex->mid, thisScheduler->running->context->pc);
} else {
printf("\r\n\t\t\tcurrMutex was null!!!\r\n\r\n");
exit(0);
}
} else if (wait) {
printf("wait the running mutex_R1_id: %d\n", thisScheduler->running->mutex_R1_id);
currMutex = get_mutx(thisScheduler->mutexes, thisScheduler->running->mutex_R1_id);
if (currMutex) {
int isWaiting = cond_var_wait (currMutex->condVar);
if (isWaiting) {
pq_enqueue(thisScheduler->ready, thisScheduler->running);
thisScheduler->running = pq_dequeue(thisScheduler->ready);
printf("M%d condition variable waiting at PC %d\n", currMutex->mid, thisScheduler->running->context->pc);
return 1;
} else { //this part resets the condition variable so we don't need to keep making a new one
cond_var_init(currMutex->condVar);
}
} else {
printf("\r\n\t\t\tcurrMutex was null!!!\r\n\r\n");
exit(0);
}
} else {
printf("\r\n\t\t\tSomething went wrong in useMutex!!!\r\n");
exit(0);
}
return 0;
}
//killed tests
/*void main () {