-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsrtn.c
217 lines (185 loc) · 8.36 KB
/
srtn.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
#include "Headers/headers.h"
#include "Headers/ProcessStruct.h"
#include "Headers/ProcessHeap.h"
#include "Headers/MessageBuffer.h"
#include "Headers/EventsQueue.h"
#include <math.h>
void ProcessArrivalHandler(int);
void InitIPC();
int ReceiveProcess();
void CleanResources();
void ExecuteProcess();
void ChildHandler(int signum);
void LogEvents(unsigned int, unsigned int);
void AddEvent(enum EventType);
int gMsgQueueId = 0;
Process *gpCurrentProcess = NULL;
heap_t *gProcessHeap = NULL;
short gSwitchContext = 0;
event_queue gEventQueue = NULL;
int main(int argc, char *argv[]) {
printf("SRTN: *** Scheduler here\n");
initClk();
InitIPC();
//initialize processes heap
gProcessHeap = (heap_t *) calloc(1, sizeof(heap_t));
gEventQueue = NewEventQueue();
signal(SIGUSR1, ProcessArrivalHandler);
signal(SIGINT, CleanResources);
signal(SIGCHLD, ChildHandler);
pause(); //wait for the first process to arrive
unsigned int start_time = getClk(); //store simulation start time
while ((gpCurrentProcess = HeapPop(gProcessHeap)) != NULL) {
ExecuteProcess(); //starts the process with the least remaining time and handles context switching
gSwitchContext = 0; //toggle switch context off until a signal handler turns it on
while (!gSwitchContext)
pause(); //pause to avoid busy waiting and only wakeup to handle signals
}
unsigned int end_time = getClk(); //store simulation end time
LogEvents(start_time, end_time);
}
void ProcessArrivalHandler(int signum) {
//keep looping as long as a process was received in the current iteration
while (!ReceiveProcess());
if (!gpCurrentProcess) //if there's no process currently running no extra checking is needed
return;
//current runtime of a process = current time - (arrival time of process + total waiting time of the process)
//then subtract this quantity from total runtime to get remaining runtime
gpCurrentProcess->mRemainTime =
gpCurrentProcess->mRuntime - (getClk() - (gpCurrentProcess->mArrivalTime + gpCurrentProcess->mWaitTime));
if (HeapPeek(gProcessHeap)->mRuntime < gpCurrentProcess->mRemainTime) { //if a new process has a shorter runtime
if (kill(gpCurrentProcess->mPid, SIGTSTP) == -1) //stop current process
perror("RR: *** Error stopping process");
gpCurrentProcess->mLastStop = getClk(); //store the stop time of the current process
gSwitchContext = 1; //toggle switch context on so main loop can execute a new process
HeapPush(gProcessHeap, gpCurrentProcess->mRemainTime, gpCurrentProcess); //push current process back into heap
AddEvent(STOP);
}
}
void InitIPC() {
key_t key = ftok(gFtokFile, gFtokCode); //same parameters used in process_generator so we attach to same queue
gMsgQueueId = msgget(key, 0);
if (gMsgQueueId == -1) {
perror("SRTN: *** Scheduler IPC init failed");
raise(SIGINT);
}
printf("SRTN: *** Scheduler IPC ready!\n");
}
int ReceiveProcess() {
Message msg;
//receive a message but do not wait, if not found return immediately
while (msgrcv(gMsgQueueId, (void *) &msg, sizeof(msg.mProcess), 0, IPC_NOWAIT) == -1) {
perror("SRTN: *** Error in receive");
return -1;
}
//below is executed if a message was retrieved from the message queue
printf("SRTN: *** Received by scheduler\n");
Process *pProcess = malloc(sizeof(Process)); //allocate memory for the received process
while (!pProcess) {
perror("SRTN: *** Malloc failed");
printf("SRTN: *** Trying again");
pProcess = malloc(sizeof(Process));
}
*pProcess = msg.mProcess; //store the process received in the allocated space
//push the process pointer into the process heap, and use the process runtime as the value to sort the heap with
HeapPush(gProcessHeap, pProcess->mRemainTime, pProcess);
return 0;
}
void CleanResources() {
printf("SRTN: *** Cleaning scheduler resources\n");
Process *pProcess = NULL;
while ((pProcess = HeapPop(gProcessHeap)) != NULL) //while processes heap is not empty
free(pProcess); //free memory allocated by this process
Event *pEvent = NULL;
while (EventQueueDequeue(gEventQueue, &pEvent)) //while event queue is not empty
free(pEvent); //free memory allocated by the event
printf("SRTN: *** Scheduler clean!\n");
exit(EXIT_SUCCESS);
}
void ExecuteProcess() {
if (gpCurrentProcess->mRuntime == gpCurrentProcess->mRemainTime) { //if this process never ran before
gpCurrentProcess->mPid = fork(); //fork a new child and store its pid in the process struct
while (gpCurrentProcess->mPid == -1) { //if forking fails
perror("SRTN: *** Error forking process");
printf("SRTN: *** Trying again...\n");
gpCurrentProcess->mPid = fork();
}
if (!gpCurrentProcess->mPid) { //if child then execute the process
char buffer[10]; //buffer to convert runtime from int to string
sprintf(buffer, "%d", gpCurrentProcess->mRuntime);
char *argv[] = {"process.out", buffer, NULL};
execv("process.out", argv);
perror("SRTN: *** Process execution failed");
exit(EXIT_FAILURE);
}
AddEvent(START);
gpCurrentProcess->mWaitTime = getClk() - gpCurrentProcess->mArrivalTime;
} else { //this process was stopped and now we need to resume it
if (kill(gpCurrentProcess->mPid, SIGCONT) == -1) { //continue process
printf("SRTN: *** Error resuming process %d", gpCurrentProcess->mId);
perror(NULL);
return;
}
gpCurrentProcess->mWaitTime += getClk() - gpCurrentProcess->mLastStop; //update the waiting time of the process
AddEvent(CONT);
}
};
void ChildHandler(int signum) {
if (!waitpid(gpCurrentProcess->mPid, NULL, WNOHANG)) //if current process did not terminate
return;
gSwitchContext = 1; //set flag to 1 so main loop knows it's time to switch context
gpCurrentProcess->mRemainTime = 0; //process finished so remaining time should be zero
AddEvent(FINISH);
}
void LogEvents(unsigned int start_time, unsigned int end_time) { //prints all events in the terminal
unsigned int runtime_sum = 0, waiting_sum = 0, count = 0;
double wta_sum = 0, wta_squared_sum = 0;
FILE *pFile = fopen("Events.txt", "w");
Event *pEvent = NULL;
while (EventQueueDequeue(gEventQueue, &pEvent)) { //while event queue is not empty
PrintEvent(pEvent);
OutputEvent(pEvent, pFile);
if (pEvent->mType == FINISH) {
runtime_sum += pEvent->mpProcess->mRuntime;
waiting_sum += pEvent->mCurrentWaitTime;
count++;
wta_sum += pEvent->mWTaTime;
wta_squared_sum += pEvent->mWTaTime * pEvent->mWTaTime;
free(pEvent->mpProcess);
}
free(pEvent); //free memory allocated by the event
}
fclose(pFile);
//cpu utilization = useful time / total time
double cpu_utilization = runtime_sum * 100.0 / (end_time - start_time);
double avg_wta = wta_sum / count;
double avg_waiting = (double) waiting_sum / count;
double std_wta = sqrt((wta_squared_sum - (2 * wta_sum * avg_wta) + (avg_wta * avg_wta * count)) / count);
pFile = fopen("Stats.txt", "w");
printf("\nCPU utilization = %.2f\n", cpu_utilization);
printf("Avg WTA = %.2f\n", avg_wta);
printf("Avg Waiting = %.2f\n", avg_waiting);
printf("STD WTA = %.2f\n\n", std_wta);
fprintf(pFile, "Avg Waiting = %.2f\n", avg_waiting);
fprintf(pFile, "\nCPU utilization = %.2f\n", cpu_utilization);
fprintf(pFile, "Avg WTA = %.2f\n", avg_wta);
fprintf(pFile, "STD WTA = %.2f\n\n", std_wta);
}
void AddEvent(enum EventType type) {
Event *pEvent = malloc(sizeof(Event));
while (!pEvent) {
perror("RR: *** Malloc failed");
printf("RR: *** Trying again");
pEvent = malloc(sizeof(Event));
}
pEvent->mTimeStep = getClk();
if (type == FINISH) {
pEvent->mTaTime = getClk() - gpCurrentProcess->mArrivalTime;
pEvent->mWTaTime = (double) pEvent->mTaTime / gpCurrentProcess->mRuntime;
}
pEvent->mpProcess = gpCurrentProcess;
pEvent->mCurrentWaitTime = gpCurrentProcess->mWaitTime;
pEvent->mType = type;
pEvent->mCurrentRemTime = gpCurrentProcess->mRemainTime;
EventQueueEnqueue(gEventQueue, pEvent);
}