00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <l4/env/errno.h>
00016 #include <l4/log/l4log.h>
00017 #include <l4/sys/types.h>
00018 #include <l4/sys/ktrace.h>
00019 #include <l4/util/macros.h>
00020 #include <l4/util/parse_cmd.h>
00021 #include <l4/util/irq.h>
00022 #include <l4/sys/rt_sched.h>
00023 #include <l4/names/libnames.h>
00024 #include <l4/cpu_reserve/sched.h>
00025 #include "cpu_reserve-server.h"
00026 #include <l4/dm_mem/dm_mem.h>
00027 #include <l4/thread/thread.h>
00028 #include "sched.h"
00029 #include "granularity.h"
00030 #include "watch.h"
00031 #include "monitor.h"
00032
00033 static int verbose;
00034 int watch_verbose;
00035 int monitor_enable;
00036 l4_ssize_t l4libc_heapsize = 64*1024;
00037 l4_threadid_t main_id;
00038
00039 int l4cpu_reserve_add_component(l4_threadid_t *caller,
00040 const l4_threadid_t *thread,
00041 const char *name,
00042 int prio,
00043 int period,
00044 int *wcet,
00045 int deadline,
00046 int *id_p,
00047 CORBA_Server_Environment *env){
00048 int pos, check;
00049 sched_t *sched;
00050 const char*ncopy;
00051 int err=0, id=1;
00052
00053 LOGd(verbose, l4util_idfmt " \"%s\": p=%d T=%d C=%d D=%d",
00054 l4util_idstr(*thread), name, prio, period, *wcet, deadline);
00055
00056 *wcet = granularity_roundup(*wcet);
00057 if(period==0) return -L4_EINVAL;
00058 if(sched_cur_threads == sched_max_threads) return -L4_ENOMEM;
00059
00060
00061 for(pos=0;pos<sched_cur_threads;pos++){
00062 if(!is_dp(scheds[pos]) &&
00063 l4_thread_equal(scheds[pos]->thread, *thread)){
00064 if(scheds[pos]->period != period) return -L4_EINVAL;
00065 id++;
00066 }
00067 }
00068
00069 if((sched = (sched_t*)calloc(1,sizeof(sched_t)))==0){
00070 return -L4_ENOMEM;
00071 }
00072 if((ncopy = (const char*)malloc(strlen(name)+1))==0){
00073 return -L4_ENOMEM;
00074 }
00075 memcpy((char*)ncopy, name, strlen(name)+1);
00076
00077 *sched = (sched_t){name:ncopy, thread:*thread, id:id,
00078 creator:*caller,
00079 prio:prio, period: period,
00080 wcet:*wcet, deadline:deadline,
00081 watcher:L4THREAD_INVALID_ID};
00082 pos = sched_index(prio);
00083 if(deadline){
00084 int w;
00085 w = sched_response_time(sched, pos, 0);
00086 if(verbose) printf(" reserved wcet: %d, response_time: %d\n",
00087 *wcet, w);
00088 if(w<0){
00089 err = -L4_ETIME;
00090 goto e_sched;
00091 }
00092 }
00093
00094 for(check=0; check<sched_cur_threads; check++){
00095 if(scheds[check]->prio > prio) break;
00096
00097
00098 if(!is_dp(scheds[check]) && scheds[check]->deadline){
00099 int p2 = sched_index(scheds[check]->prio);
00100 int w = sched_response_time(scheds[check], p2, sched);
00101 if(verbose) printf(
00102 " ->" l4util_idfmt "/%d \"%s\" p=%d T=%d C=%d D=%d: time=%d\n",
00103 l4util_idstr(scheds[check]->thread),
00104 scheds[check]->id,
00105 scheds[check]->name,
00106 scheds[check]->prio, scheds[check]->period,
00107 scheds[check]->wcet, scheds[check]->deadline, w);
00108 if(w<0){
00109 err = -L4_ETIME;
00110 goto e_sched;
00111 }
00112 }
00113 }
00114
00115
00116 if((err = l4_rt_add_timeslice(*thread, prio, *wcet))!=0){
00117 LOG_Error("l4_rt_add_timeslice("l4util_idfmt", p=%d C=%d)=%d",
00118 l4util_idstr(*thread), prio, *wcet, err);
00119 err = -L4_EPERM;
00120 goto e_sched;
00121 }
00122
00123 if(id==1){
00124
00125 if(verbose) printf(" setting period at kernel to %d\n", period);
00126 l4_rt_set_period (*thread, period);
00127 }
00128
00129 lock_scheds();
00130
00131 memmove(scheds+pos+1, scheds+pos,
00132 sizeof(sched_t*)*(sched_cur_threads-pos));
00133 sched_cur_threads++;
00134 scheds[pos]=sched;
00135 unlock_scheds();
00136 *id_p = id;
00137 return 0;
00138
00139 e_sched:
00140 free((char*)sched->name);
00141 free(sched);
00142 return err;
00143 }
00144
00145 int l4cpu_reserve_delayed_preempt_component(l4_threadid_t *caller,
00146 const l4_threadid_t *thread,
00147 int id,
00148 int prio,
00149 int *delay,
00150 CORBA_Server_Environment *env){
00151 sched_t *sched, *dp;
00152 char*ncopy;
00153 int len, pos, err;
00154
00155 LOGd(verbose, l4util_idfmt ": id=%d C=%d",
00156 l4util_idstr(*thread), id, *delay);
00157
00158
00159
00160 if(sched_cur_threads == sched_max_threads) return -L4_ENOMEM;
00161
00162 sched=0;
00163 for(pos=0;pos<sched_cur_threads;pos++){
00164 if(!l4_thread_equal(scheds[pos]->thread, *thread) ||
00165 id!=scheds[pos]->id) continue;
00166 if(is_dp(scheds[pos])) return -L4_EINVAL;
00167 sched=scheds[pos];
00168 }
00169 if(sched==0 && id) return -L4_EINVAL;
00170
00171 if((dp = (sched_t*)calloc(1,sizeof(sched_t)))==0){
00172 return -L4_ENOMEM;
00173 }
00174 if(sched) len = strlen(sched->name);
00175 else len=0;
00176 if((ncopy = (char*)malloc(len+1+strlen(".dp")))==0){
00177 return -L4_ENOMEM;
00178 }
00179 if(sched)memcpy(ncopy, sched->name, len);
00180 memcpy(ncopy+len, ".dp", strlen(".dp")+1);
00181
00182 *dp = (sched_t){name:ncopy, thread:*thread, id:id,
00183 creator:*caller,
00184 prio:sched?sched->prio:0, period: 0,
00185 wcet:*delay, deadline:0,
00186 watcher:L4THREAD_INVALID_ID};
00187
00188 for(pos=0; pos<sched_cur_threads; pos++){
00189 if(!is_dp(scheds[pos]) && scheds[pos]->deadline){
00190 int p2 = sched_index(scheds[pos]->prio);
00191 int w = sched_response_time(scheds[pos], p2, dp);
00192 if(verbose) printf(
00193 " ->" l4util_idfmt "/%d \"%s\" p=%d T=%d C=%d D=%d: time=%d\n",
00194 l4util_idstr(scheds[pos]->thread),
00195 scheds[pos]->id,
00196 scheds[pos]->name,
00197 scheds[pos]->prio, scheds[pos]->period,
00198 scheds[pos]->wcet, scheds[pos]->deadline, w);
00199 if(w<0){
00200 err = -L4_ETIME;
00201 goto e_dp;
00202 }
00203 }
00204 }
00205
00206
00207 pos = sched_index(dp->prio);
00208 lock_scheds();
00209 memmove(scheds+pos+1, scheds+pos,
00210 sizeof(sched_t*)*(sched_cur_threads-pos));
00211 sched_cur_threads++;
00212 scheds[pos]=dp;
00213 unlock_scheds();
00214 return 0;
00215
00216 e_dp:
00217 free((char*)dp->name);
00218 free(dp);
00219 return err;
00220
00221
00222 }
00223
00224 int l4cpu_reserve_change_component(l4_threadid_t *caller,
00225 const l4_threadid_t *thread,
00226 int id,
00227 int new_prio,
00228 int *new_wcet,
00229 int new_deadline,
00230 CORBA_Server_Environment *env){
00231 sched_t *sched;
00232 int pos, err=0;
00233 int check_local=0, check_others=0;
00234 sched_t sched_copy;
00235
00236 LOGd(verbose, l4util_idfmt ": p=%d C=%d D=%d",
00237 l4util_idstr(*thread), new_prio, *new_wcet, new_deadline);
00238 if(*new_wcet>=0) *new_wcet = granularity_roundup(*new_wcet);
00239
00240 for(pos=0;pos<sched_cur_threads;pos++){
00241 if(!is_dp(scheds[pos]) &&
00242 l4_thread_equal(scheds[pos]->thread, *thread) &&
00243 scheds[pos]->id == id){
00244 break;
00245 }
00246 }
00247 if(pos==sched_cur_threads) return -L4_ENOTFOUND;
00248
00249 sched = scheds[pos];
00250 memcpy(&sched_copy, sched, sizeof(sched_t));
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 if(new_prio>=0){
00262 sched->prio = new_prio;
00263 check_others=1;
00264 if(new_prio < sched_copy.prio) check_local=1;
00265 }
00266 if(*new_wcet>=0){
00267 sched->wcet = *new_wcet;
00268 if(*new_wcet > sched_copy.wcet){
00269 check_others = check_local = 1;
00270 }
00271 }
00272 if(new_deadline>=0){
00273 sched->deadline = new_deadline;
00274 if(!sched_copy.deadline || (new_deadline &&
00275 new_deadline < sched_copy.deadline)){
00276 check_local=1;
00277 }
00278 }
00279
00280 if(check_local && new_deadline){
00281 int w, i;
00282 i = sched_index(sched->prio);
00283
00284 w = sched_response_time(sched, i, 0);
00285 if(verbose) printf(" reserved wcet: %d, response_time: %d\n",
00286 sched->wcet, w);
00287 if(w<0){
00288 err = -L4_ETIME;
00289 goto e_back;
00290 }
00291 }
00292 if(check_others){
00293 int i;
00294
00295 for(i=0; i<sched_cur_threads; i++){
00296 int p2, w;
00297
00298 if(scheds[i]->prio > sched->prio) break;
00299 if(is_dp(scheds[i]) ||
00300 scheds[i]==sched ||
00301 scheds[i]->deadline==0 ) continue;
00302
00303 p2 = sched_index(scheds[i]->prio);
00304
00305 w = sched_response_time(scheds[i], p2, 0);
00306 if(verbose)printf(
00307 " ->" l4util_idfmt "/%d \"%s\" p=%d T=%d C=%d D=%d: time=%d\n",
00308 l4util_idstr(scheds[i]->thread),
00309 scheds[i]->id,
00310 scheds[i]->name,
00311 scheds[i]->prio, scheds[i]->period,
00312 scheds[i]->wcet, scheds[i]->deadline, w);
00313 if(w<0){
00314 err = -L4_ETIME;
00315 goto e_back;
00316 }
00317 }
00318 }
00319
00320
00321
00322 if(l4_rt_change_timeslice(sched->thread, sched->id,
00323 sched->prio, sched->wcet)){
00324 err = -L4_EPERM;
00325 goto e_back;
00326 }
00327
00328 if(new_prio>=0){
00329 int new_pos;
00330
00331 lock_scheds();
00332 sched_cur_threads--;
00333
00334 if(pos!=sched_cur_threads){
00335 memmove(scheds+pos, scheds+pos+1,
00336 sizeof(sched_t*)*(sched_cur_threads-pos));
00337 }
00338
00339 new_pos = sched_index(new_prio);
00340 memmove(scheds+new_pos+1, scheds+new_pos,
00341 sizeof(sched_t*)*(sched_cur_threads-new_pos));
00342 sched_cur_threads++;
00343 scheds[new_pos]=sched;
00344 unlock_scheds();
00345 }
00346
00347 return 0;
00348
00349 e_back:
00350 memcpy(sched, &sched_copy, sizeof(sched_t));
00351 return err;
00352 }
00353
00354
00355
00356 int l4cpu_reserve_delete_thread_component(l4_threadid_t *caller,
00357 const l4_threadid_t *thread,
00358 CORBA_Server_Environment *env){
00359 int i, err;
00360
00361 LOGd(verbose, l4util_idfmt, l4util_idstr(*thread));
00362
00363
00364 for(i=0;i<sched_cur_threads;i++){
00365 if(l4_thread_equal(scheds[i]->thread, *thread)) break;
00366 }
00367 if(i==sched_cur_threads) return -L4_ENOTFOUND;
00368
00369
00370 err = l4_rt_remove(*thread);
00371 if(err){
00372 LOG_Error("l4_rt_remove("l4util_idfmt")=%d",
00373 l4util_idstr(*thread), err);
00374 return -L4_EPERM;
00375 }
00376
00377
00378 for(i=0;i<sched_cur_threads;i++){
00379 if(l4_thread_equal(scheds[i]->thread, *thread)){
00380 sched_prepare_free(i);
00381 }
00382 }
00383
00384 lock_scheds();
00385
00386 for(i=0;i<sched_cur_threads;i++){
00387 if(l4_thread_equal(scheds[i]->thread, *thread)){
00388 sched_free(i);
00389 i--;
00390 }
00391 }
00392 unlock_scheds();
00393 return 0;
00394 }
00395
00396 int l4cpu_reserve_delete_task_component(l4_threadid_t *caller,
00397 const l4_threadid_t *task,
00398 CORBA_Server_Environment *env){
00399 int i, found=0;
00400
00401 LOGd(verbose, l4util_idfmt, l4util_idstr(*task));
00402
00403
00404 for(i=0;i<sched_cur_threads;i++){
00405 if(l4_task_equal(scheds[i]->thread, *task)){
00406 sched_prepare_free(i);
00407 }
00408 }
00409 lock_scheds();
00410 for(i=0;i<sched_cur_threads;i++){
00411 if(l4_task_equal(scheds[i]->thread, *task)){
00412
00413
00414 l4_rt_remove(scheds[i]->thread);
00415 sched_free(i);
00416 i--;
00417 found=1;
00418 }
00419 }
00420 unlock_scheds();
00421 return found?0:-L4_ENOTFOUND;
00422 }
00423
00424 int l4cpu_reserve_begin_strictly_periodic_component(
00425 l4_threadid_t *caller,
00426 const l4_threadid_t *thread,
00427 l4_kernel_clock_t clock,
00428 CORBA_Server_Environment *env){
00429
00430 int err;
00431
00432 LOGd(verbose, l4util_idfmt " at clock=%lld", l4util_idstr(*thread), clock);
00433
00434
00435 LOGk("start periodic("l4util_idfmt",%lld)...",
00436 l4util_idstr(*thread),clock);
00437 err = l4_rt_begin_strictly_periodic(*thread, clock);
00438 LOGk("periodic("l4util_idfmt")=%d", l4util_idstr(*thread), err);
00439 if(err){
00440 LOG_Error("l4_rt_begin_strictly_periodic("l4util_idfmt") failed",
00441 l4util_idstr(*thread));
00442 }
00443 return err?-L4_EPERM:0;
00444 }
00445
00446 int l4cpu_reserve_begin_minimal_periodic_component(
00447 l4_threadid_t *caller,
00448 const l4_threadid_t *thread,
00449 l4_kernel_clock_t clock,
00450 CORBA_Server_Environment *env){
00451
00452 int err;
00453
00454 LOGd(verbose, l4util_idfmt " at clock=%lld", l4util_idstr(*thread), clock);
00455
00456 err = l4_rt_begin_minimal_periodic(*thread, clock);
00457 return err?-L4_EPERM:0;
00458 }
00459
00460 int l4cpu_reserve_end_periodic_component(l4_threadid_t *caller,
00461 const l4_threadid_t *thread,
00462 CORBA_Server_Environment *env){
00463
00464 int err;
00465
00466 LOGd(verbose, l4util_idfmt, l4util_idstr(*thread));
00467
00468 err = l4_rt_end_periodic(*thread);
00469 return err?-L4_EPERM:0;
00470 }
00471
00472 int l4cpu_reserve_watch_component(l4_threadid_t *caller,
00473 const l4_threadid_t *thread,
00474 l4dm_dataspace_t *ds,
00475 l4_threadid_t *preempter,
00476 CORBA_Server_Environment *env){
00477 int i;
00478
00479 LOGd(verbose,
00480 "thread="l4util_idfmt, l4util_idstr(*thread));
00481
00482 for(i=0;i<sched_cur_threads;i++){
00483 if(l4_thread_equal(scheds[i]->thread, *thread) &&
00484 scheds[i]->id == 1 &&
00485 !is_dp(scheds[i])){
00486 void *addr;
00487 int err;
00488
00489
00490 if(scheds[i]->watch) return -L4_EBUSY;
00491
00492 if((addr = l4dm_mem_ds_allocate_named(L4_PAGESIZE, 0, "watch",
00493 ds))==0)
00494 return -L4_EINVAL;
00495 memset(addr, 0, L4_PAGESIZE);
00496
00497 if((err = l4dm_share(ds, *caller, L4DM_RW))!=0){
00498 goto e_mem;
00499 }
00500
00501
00502 if(monitor_enable && (err = monitor_start(scheds[i], thread))!=0){
00503 goto e_mem;
00504 }
00505
00506 scheds[i]->watcher_end_sem = L4SEMAPHORE_LOCKED;
00507 if((err = l4thread_create_named(watcher_fn,
00508 ".watcher",
00509 &scheds[i]->watcher_end_sem,
00510 L4THREAD_CREATE_ASYNC))<0){
00511 l4dm_mem_release(addr);
00512 return err;
00513 }
00514 scheds[i]->watcher = err;
00515
00516
00517 *preempter = l4thread_l4_id(scheds[i]->watcher);
00518 scheds[i]->watch = (unsigned*)addr;
00519
00520 return 0;
00521
00522 e_mem:
00523 l4dm_mem_release(addr);
00524 return err;
00525 }
00526 }
00527 return -L4_ENOTFOUND;
00528
00529 }
00530
00531 int l4cpu_reserve_scheds_count_component(l4_threadid_t *caller,
00532 CORBA_Server_Environment *env){
00533 LOGd_Enter(verbose, "returning %d", sched_cur_threads);
00534 return sched_cur_threads;
00535 }
00536
00537 int l4cpu_reserve_scheds_get_component(l4_threadid_t *caller,
00538 int idx,
00539 char **name,
00540 l4_threadid_t *thread,
00541 l4_threadid_t *creator,
00542 int *id,
00543 int *prio,
00544 int *period,
00545 int *wcet,
00546 int *deadline,
00547 CORBA_Server_Environment *env){
00548 if(idx>=sched_cur_threads || idx<0) return -L4_EINVAL;
00549 *name = (char*)scheds[idx]->name;
00550 *thread = scheds[idx]->thread;
00551 *creator = scheds[idx]->creator;
00552 *id = scheds[idx]->id;
00553 *prio = scheds[idx]->prio;
00554 *wcet = scheds[idx]->wcet;
00555 *period = scheds[idx]->period;
00556 *deadline = scheds[idx]->deadline;
00557 return 0;
00558 }
00559
00560 int l4cpu_reserve_time_demand_component(l4_threadid_t *caller,
00561 const l4_threadid_t *thread,
00562 int id,
00563 CORBA_Server_Environment *env){
00564 int i;
00565
00566
00567 for(i=0;i<sched_cur_threads;i++){
00568 if(l4_thread_equal(scheds[i]->thread, *thread) &&
00569 scheds[i]->id==id && !is_dp(scheds[i])){
00570 int delay;
00571 delay = sched_response_time(scheds[i], i, 0);
00572 return delay>=0?delay:-L4_ETIME;
00573 }
00574 }
00575 return -L4_EINVAL;
00576 }
00577
00578 int main(int argc, const char**argv){
00579 int err;
00580
00581 main_id = l4_myself();
00582 if(parse_cmdline(&argc, &argv,
00583 't', "threads", "max number of threads to manage",
00584 PARSE_CMD_INT, 1000, &sched_max_threads,
00585 'v', "verbose", "verbose mode",
00586 PARSE_CMD_SWITCH, 1, &verbose,
00587 'w', "watch", "verbose: log watch preemptions",
00588 PARSE_CMD_SWITCH, 1, &watch_verbose,
00589 'm', "monitor", "monitor preemptions to rt_mon",
00590 PARSE_CMD_SWITCH, 1, &monitor_enable,
00591 0,0)) return 1;
00592 if((err = sched_init())!=0){
00593 l4env_perror("sched_init()", -err);
00594 return 1;
00595 }
00596
00597 if(names_register(l4cpu_reserve_name)==0){
00598 LOG_Error("names_register failed");
00599 return 1;
00600 }
00601 printf("Scheduling granularity: %dµs\n", granularity());
00602 l4cpu_reserve_server_loop(0);
00603 }