00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <errno.h>
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include <unistd.h>
00007 #include <pthread.h>
00008
00009 #include <hlog.h>
00010 #include <hstructures.h>
00011 #include <hprocess.h>
00012 #include <hsqueue.h>
00013 #include <hsqlist.h>
00014 #include <hplacer.h>
00015 #include <hlist.h>
00016 #include <hevent.h>
00017
00018 #include "hdsched.h"
00019 #include "hdmsg.h"
00020
00021
00022 static void cleanup_(int exit_code);
00023
00025 static int wait_event_();
00026
00039 static int schedule_longterm_(struct hprocess* process);
00040 static int schedule_shortterm_();
00041 static int increment_process_number_();
00042 static int decrement_process_number_();
00043
00050 static struct hsqueue* create_queue_by_priority_(int list, int priority);
00051
00060 int set_next_process_(struct hprocess* process);
00061
00062
00064 static pthread_mutex_t new_hsqueue_mutex = PTHREAD_MUTEX_INITIALIZER;
00066 static int notify_server_quit = 1;
00068 static int processes_num = 0;
00069 static pthread_mutex_t processes_num_mutex = PTHREAD_MUTEX_INITIALIZER;
00071 static struct hprocess* next_process = NULL;
00072 static pthread_mutex_t next_process_mutex = PTHREAD_MUTEX_INITIALIZER;
00074 static struct hlist* resched_queue = NULL;
00075 static pthread_mutex_t resched_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
00077 static pthread_mutex_t ready_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
00079 static struct hevent* event_handler = NULL;
00080
00081
00082 static int increment_process_number_()
00083 {
00084 int ret = -1;
00085 pthread_mutex_lock( &processes_num_mutex );
00086 processes_num += 1;
00087 ret = processes_num;
00088 pthread_mutex_unlock( &processes_num_mutex );
00089
00090 return ret;
00091 }
00092
00093
00094 static int decrement_process_number_()
00095 {
00096 int ret = -1;
00097 pthread_mutex_lock( &processes_num_mutex );
00098 if (processes_num < 1)
00099 processes_num = 0;
00100 else
00101 processes_num -= 1;
00102
00103 ret = processes_num;
00104 pthread_mutex_lock( &processes_num_mutex );
00105
00106 return ret;
00107 }
00108
00109
00110 static void cleanup_(int exit_code)
00111 {
00112
00113 if (notify_server_quit) {
00114 notify_server_quit = 0;
00115 hdmsg_notify(HDME_QUIT);
00116 }
00117
00118 hdmsg_synchronize();
00119 pthread_exit(NULL);
00120 }
00121
00122
00123 static struct hsqueue* create_queue_by_priority_(int list, int priority)
00124 {
00125 struct hsqueue* queue = hsqlist_get_last_queue(list);
00126
00127
00128
00129
00130
00131 while (hsqueue_get_prev(queue) != NULL) {
00132 if ( hprocess_get_priority ( hsqueue_get_first_process(queue) ) >= priority)
00133 return queue;
00134 queue = hsqueue_get_prev(queue);
00135 }
00136
00137 if (hprocess_get_priority( hsqueue_get_first_process(queue) ) < hprocess_base_priority()) {
00138
00139
00140 queue = hsqueue_create();
00141 hsqlist_insert_queue_before(HPS_READY, hsqlist_get_first_queue(HPS_READY), queue);
00142 } else if (hprocess_get_priority( hsqueue_get_first_process(queue) ) > hprocess_base_priority()) {
00143
00144
00145 struct hsqueue* new_queue = hsqueue_create();
00146 if (hsqueue_get_next(queue) == NULL)
00147 hsqlist_add_queue(HPS_READY, new_queue);
00148 else
00149 hsqlist_insert_queue_before(HPS_READY, hsqueue_get_next(queue), new_queue);
00150 queue = new_queue;
00151 }
00152
00153 return queue;
00154 }
00155
00156
00157 static int schedule_shortterm_()
00158 {
00159
00160 pthread_mutex_lock(&ready_queue_mutex);
00161 struct hsqueue* ready_queue = hsqlist_get_first_queue(HPS_READY);
00162 struct hprocess* process = hsqueue_dequeue_process(ready_queue);
00163 pthread_mutex_unlock(&ready_queue_mutex);
00164
00165 if (process != NULL) {
00166 set_next_process_(process);
00167 }
00168
00169 return 0;
00170 }
00171
00172
00173 static int schedule_longterm_(struct hprocess* process)
00174 {
00175 if ( hdsched_processes_number() + 1 > hprocess_max_processes() )
00176 return HDSR_TOO_MANY;
00177
00178
00179 struct stat statbuffer;
00180 char* filename_full = hplacer_create_full_bitfilename(process);
00181 hlog_write(HLOG_DEBUG, "schedule_longterm_: Filename for process: ");
00182 hlog_write_text(filename_full);
00183 hlog_write_text("\n");
00184
00185 stat(filename_full, &statbuffer);
00186 free(filename_full);
00187 if ( !S_ISREG(statbuffer.st_mode) )
00188 return HDSR_NO_BITFILE;
00189
00190
00191
00192 hprocess_set_priority(process, hprocess_base_priority());
00193 pthread_mutex_lock(&ready_queue_mutex);
00194 struct hsqueue* queue = create_queue_by_priority_( HPS_READY, hprocess_base_priority() );
00195 hsqueue_enqueue_process(queue, process);
00196 pthread_mutex_unlock(&ready_queue_mutex);
00197 increment_process_number_();
00198
00199 return HDSR_READY;
00200 }
00201
00202
00203 static int wait_event_()
00204 {
00205 enum hdsevent incoming_event = (enum hdsevent)hevent_wait(event_handler);
00206
00207
00208 switch (incoming_event) {
00209 case HDSE_QUIT: {
00210
00211 notify_server_quit = 0;
00212 cleanup_(EXIT_FAILURE);
00213 break;
00214 }
00215 case HDSE_NEW_PROCESS: {
00216 struct hprocess* new_process = hdsched_get_new_process();
00217 int sched_long = schedule_longterm_(new_process);
00218 hlog_write(HLOG_DEBUG, "wait_event_: (scheduler) A new process has been added.\n");
00219 hlog_write(HLOG_DEBUG, "Return value from long-term scheduler: ");
00220 hlog_write_integer(sched_long);
00221 hlog_write_text(".\n");
00222
00223
00224
00225 if (sched_long < 0)
00226 hprocess_remove(new_process);
00227
00228 break;
00229 }
00230 case HDSE_SHORT:
00231 schedule_shortterm_();
00232 break;
00233 case HDSE_RESCHED_TIMER: {
00234 struct hprocess* resched_process = hlist_dequeue(resched_queue);
00235 if (resched_process != NULL) {
00236 struct hsqueue* ready_queue = create_queue_by_priority_(HPS_READY, hprocess_get_priority(resched_process));
00237 hsqueue_enqueue_process(ready_queue, resched_process);
00238 }
00239 break;
00240 }
00241 default:
00242 break;
00243 }
00244
00245 return 0;
00246 }
00247
00248
00249 int set_next_process_(struct hprocess* process)
00250 {
00251
00252 pthread_mutex_lock( &next_process_mutex );
00253 next_process = process;
00254 pthread_mutex_unlock( &next_process_mutex );
00255
00256 return 0;
00257 }
00258
00259
00260 int hdsched_reschedule(struct hprocess* process, enum hdsevent event)
00261 {
00262 pthread_mutex_lock( &resched_queue_mutex );
00263 hlist_enqueue(resched_queue, process);
00264 pthread_mutex_unlock( &resched_queue_mutex );
00265
00266 printf("Rescheduled process. pid=%d\n", hprocess_get_pid(process));
00267
00268 hdsched_notify(event);
00269
00270 return 0;
00271 }
00272
00273
00274 int hdsched_add_new_process(struct hprocess* process)
00275 {
00279 pthread_mutex_lock( &new_hsqueue_mutex );
00280 hsqueue_enqueue_process(hsqlist_get_first_queue(HPS_NEW), process);
00281 pthread_mutex_unlock( &new_hsqueue_mutex );
00282
00283 return 0;
00284 }
00285
00286
00287 struct hprocess* hdsched_get_new_process()
00288 {
00289 struct hprocess* new_process = NULL;
00290
00291 pthread_mutex_lock( &new_hsqueue_mutex );
00292 new_process = hsqueue_dequeue_process( hsqlist_get_first_queue(HPS_NEW) );
00293 pthread_mutex_unlock( &new_hsqueue_mutex );
00294
00295 return new_process;
00296 }
00297
00298
00299 struct hprocess* hdsched_get_next_process()
00300 {
00301 struct hprocess* ret = NULL;
00302
00303 pthread_mutex_lock( &next_process_mutex );
00304 ret = next_process;
00305 pthread_mutex_unlock( &next_process_mutex );
00306
00307 return ret;
00308 }
00309
00310
00311 int hdsched_processes_number()
00312 {
00313 int ret = -1;
00314 pthread_mutex_lock( &processes_num_mutex );
00315 ret = processes_num;
00316 pthread_mutex_unlock( &processes_num_mutex );
00317
00318 return ret;
00319 }
00320
00321
00322 int hdsched_notify(enum hdsevent event)
00323 {
00324 hevent_notify(event_handler, (int)event);
00325
00326 return 0;
00327 }
00328
00329
00330 void* hdsched_main()
00331 {
00332 hsqlist_create(HPS_READY);
00333 struct hsqueue* new_hsqueue = hsqueue_create();
00334 hsqlist_create(HPS_NEW);
00335 hsqlist_add_queue(HPS_NEW, new_hsqueue);
00336
00337
00338 event_handler = hevent_create(HEVENT_BLOCKING);
00339 if (event_handler == NULL) {
00340 notify_server_quit = 0;
00341 cleanup_(EXIT_FAILURE);
00342 }
00343
00344
00345 resched_queue = hlist_create();
00346
00347
00348 while (1) {
00349 printf("hdsched_main: Waiting\n");
00350
00351 wait_event_();
00352 }
00353
00354
00355 hevent_remove(event_handler);
00356 cleanup_(EXIT_SUCCESS);
00357 }
00358
00359
00360
00361
00362
00363