00001
00014 #include "rres_config.h"
00015 #define QOS_DEBUG_LEVEL RRES_MOD_DEBUG_LEVEL
00016 #include "qos_debug.h"
00017
00018 #include "rres_ready_queue.h"
00019
00020 #include "rres.h"
00021 #include "rres_kpi_protected.h"
00022 #include "rres_dispatch.h"
00023 #include "kal_timer.h"
00024 #include "kal_sched.h"
00025 #include "qos_func.h"
00026
00027
00028
00029 kal_lock_define(rres_lock);
00030 EXPORT_SYMBOL_GPL(rres_lock);
00031
00032 server_t *exec = NULL;
00033 qres_sid_t server_id = 1;
00034 struct list_head server_list;
00035 kal_timer_t *enforce = NULL;
00036 kal_time_t last_update_time;
00037 qos_bw_t U_tot = 0;
00038 #ifdef CONFIG_RRES_DEFAULT_SRV
00039 server_t *default_srv = NULL;
00040 #endif
00041
00042 kal_time_t sched_time;
00043
00044 #define rres_dump(srv) do { \
00045 struct list_head *h; \
00046 kal_task_t *task; \
00047 char s[256]; \
00048 char *t = s; \
00049 qos_chk(srv != NULL); \
00050 if (srv != NULL) { \
00051 for_each_ready_task_in_server(srv, task, h) { \
00052 int written = snprintf(t, s + sizeof(s) - t, "%d,", kal_task_get_id(task)); \
00053 if (written >= s + sizeof(s) - t) \
00054 break; \
00055 } \
00056 for_each_blocked_task_in_server(srv, task, h) { \
00057 int written = snprintf(t, s + sizeof(s) - t, "%d,", kal_task_get_id(task)); \
00058 if (written >= s + sizeof(s) - t) \
00059 break; \
00060 } \
00061 qos_log_debug("(s:%d): rdy=%d, c=" KAL_TIME_FMT ", dl=" KAL_TIME_FMT ", rchg=%d, tasks=%s", \
00062 srv->id, in_ready_queue(srv), KAL_TIME_FMT_ARG(srv->c), KAL_TIME_FMT_ARG(srv->deadline), \
00063 kal_timer_pending(&srv->reactive), s); \
00064 } \
00065 } while (0)
00066
00067
00068
00074 static void iris_hr_reactive_timer_handler(unsigned long v) {
00075 kal_irq_state flags;
00076 server_t *srv = (server_t *) v;
00077
00078 kal_spin_lock_irqsave(rres_get_spinlock(), &flags);
00079 rres_sample_time();
00080
00081 qos_log_debug("Entering function");
00082 if (RRES_PARANOID)
00083 qos_chk_do(rres_has_ready_tasks(srv) && ! rres_empty(srv), goto out);
00084 recharge(srv);
00085 qos_chk_ok(ready_queue_add(srv));
00086 rres_schedule();
00087 out:
00088 qos_log_debug("Leaving function");
00089
00090 kal_spin_unlock_irqrestore(rres_get_spinlock(), &flags);
00091 }
00092
00101 void stop_pending_timers(server_t *srv, int pending_unexpected) {
00102 if (pending_unexpected && kal_timer_pending(&srv->reactive)) {
00103 qos_log_crit("(s:%d): Cancelling unexpected pending reactive timer", srv->id);
00104 rres_dump(srv);
00105 }
00106 kal_timer_del(&srv->reactive);
00107 }
00108
00109
00110
00112 int rres_empty(server_t *srv) {
00113 return list_empty(&srv->ready_tasks) && list_empty(&srv->blocked_tasks);
00114 }
00115 EXPORT_SYMBOL_GPL(rres_empty);
00116
00118 qos_bool_t rres_has_server(kal_task_t *task) {
00119 return rres_find_by_task(task) != NULL;
00120 }
00121 EXPORT_SYMBOL_GPL(rres_has_server);
00122
00134
00135
00136
00137
00144 server_t* rres_find_by_id(qres_sid_t sid) {
00145 struct list_head *tmp_list;
00146 server_t *srv;
00147 if (sid == QRES_SID_NULL)
00148 return rres_find_by_task(kal_task_current());
00149 for_each_server(srv, tmp_list) {
00150 if (srv->id == sid)
00151 return srv;
00152 }
00153 return NULL;
00154 }
00155 EXPORT_SYMBOL_GPL(rres_find_by_id);
00156
00164 static qos_func_define(void, set_enforce_timer, kal_time_t delta) {
00165
00166 kal_time_t exp_time = kal_time_add(sched_time, delta);
00167 kal_timer_set(enforce, exp_time);
00168 qos_log_debug("Enforce timer set to now + " KAL_TIME_FMT " = " KAL_TIME_FMT,
00169 KAL_TIME_FMT_ARG(delta), KAL_TIME_FMT_ARG(exp_time));
00170
00171 last_update_time = sched_time;
00172 }
00173
00175 qres_sid_t new_server_id(void) {
00176 while (server_id == QRES_SID_NULL || rres_find_by_id(server_id) != NULL) {
00177 qos_log_debug("Skipping sid (s:%d) already in use", server_id);
00178 ++server_id;
00179 }
00180 return server_id;
00181 }
00182
00188 qos_func_define(qos_bw_t, _rres_get_bandwidth, server_t *srv) {
00189
00190 return r2bw(srv->max_budget_us, srv->period_us);
00191 }
00192 EXPORT_SYMBOL_GPL(_rres_get_bandwidth);
00193
00195 static inline void rres_remove_from_srv_set(server_t * srv) {
00196 list_del(&(srv->slist));
00197 INIT_LIST_HEAD_NULL(&srv->slist);
00198 }
00199
00201 static inline void rres_add_to_srv_set(server_t * srv) {
00202 INIT_LIST_HEAD_NULL(&srv->slist);
00203 list_add(&(srv->slist), &server_list);
00204 }
00205
00207 static inline void tasklist_init(struct task_list *task_l, server_t *srv, kal_task_t *task) {
00208 task_l->task = task;
00209 task_l->srv = srv;
00210 task_l->is_stopped = 0;
00211 if (task_ready(task))
00212 list_add(&task_l->node, &srv->ready_tasks);
00213 else
00214 list_add(&task_l->node, &srv->blocked_tasks);
00215 kal_task_link_data(task, task_l);
00216 }
00217
00219 static inline void tasklist_cleanup(struct task_list *tl) {
00220 qos_chk(! tl->is_stopped);
00221 kal_task_unlink_data(tl->task);
00222 list_del(&tl->node);
00223 }
00224
00233 static inline qos_rv rres_add(server_t *srv, kal_task_t *task) {
00234 struct task_list *task_list_entry;
00235
00236 qos_log_debug("(s:%d): attaching task %d", srv->id, kal_task_get_id(task));
00237 task_list_entry = qos_create(struct task_list);
00238 if (task_list_entry == NULL)
00239 return QOS_E_NO_MEMORY;
00240 tasklist_init(task_list_entry, srv, task);
00241 return QOS_OK;
00242 }
00243
00248 static inline void rres_del(kal_task_t *task) {
00249 struct task_list *tl = rres_find_task_list(task);
00250 qos_chk_do(tl != NULL, return);
00251 tasklist_cleanup(tl);
00252 qos_free(tl);
00253 }
00254
00255
00256
00258 qos_func_define(void, recharge, server_t *srv) {
00259 qos_bw_t U_new;
00260 unsigned long max_budget_us;
00261
00262 qos_log_debug("(s:%d): Recharging server", srv->id);
00263 U_new = rres_update_current_bandwidth(srv);
00264
00265
00266 max_budget_us = bw2Q(U_new, srv->period_us);
00267 srv->c = kal_time_add(srv->c, kal_usec2time(max_budget_us));
00268 srv->deadline = kal_time_add(srv->deadline, srv->period);
00269
00270 if (kal_time_le(srv->deadline, sched_time)) {
00271 qos_log_warn("Recharged too late: setting deadline to now+period");
00272 srv->deadline = kal_time_add(sched_time, srv->period);
00273 }
00274 srv->stat.n_rcg++;
00275 qos_log_debug("Ending function: U_tot " QOS_BW_FMT ", max_budget " KAL_TIME_FMT ", budget " KAL_TIME_FMT ", deadline " KAL_TIME_FMT,
00276 U_tot, KAL_TIME_FMT_ARG(srv->max_budget), KAL_TIME_FMT_ARG(srv->c), KAL_TIME_FMT_ARG(srv->deadline));
00277 }
00278
00283 qos_func_define(void, recharge_reset_from_now, server_t *srv) {
00284 srv->deadline = sched_time;
00285 srv->c = KAL_TIME_US(0, 0);
00286 recharge(srv);
00287 }
00288
00289 #ifdef SHRUB
00290
00291 qos_bw_t U_active_tot = 0;
00292 unsigned int w_active_tot = 0;
00295 qos_func_define(void, shrub_update_active, void) {
00296 struct list_head *tmp_list;
00297 server_t *srv;
00298 U_active_tot = 0;
00299 w_active_tot = 0;
00300 for_each_server(srv, tmp_list) {
00301 if (rres_has_ready_tasks(srv)) {
00302 U_active_tot += rres_get_current_bandwidth(srv);
00303 w_active_tot += srv->weight;
00304 }
00305 }
00306 }
00307
00309 kal_time_t shrub_time2budget_exec(server_t *srv, kal_time_t t) {
00310 qos_bw_t avail_bw, bw;
00311 unsigned long t_us, budget_us;
00312 if (U_active_tot >= U_LUB)
00313 return t;
00314 avail_bw = (U_LUB) - U_active_tot;
00315 bw = MAX_BW - avail_bw * srv->weight / w_active_tot;
00316 t_us = kal_time2usec(t);
00317 budget_us = mul_by_bw(t_us, bw);
00318 qos_log_debug("exec (s:%d) U_active_tot=%lu, w_active_tot=%u, t_us=%lu, avail_bw=%lu, bw=" QOS_BW_FMT ", budget_us=%lu",
00319 srv->id, U_active_tot, w_active_tot, t_us, avail_bw, bw, budget_us);
00320 return kal_usec2time(budget_us);
00321 }
00322
00323 kal_time_t shrub_time2budget_noexec(server_t *srv, kal_time_t t) {
00324 qos_bw_t avail_bw, bw;
00325 unsigned long t_us, budget_us;
00326 if (U_active_tot >= U_LUB)
00327 return t;
00328 avail_bw = U_LUB - U_active_tot;
00329 bw = avail_bw * srv->weight / w_active_tot;
00330 t_us = kal_time2usec(t);
00331 budget_us = mul_by_bw(t_us, bw);
00332 qos_log_debug("noexec (s:%d) U_active_tot=%lu, w_active_tot=%u, t_us=%lu, avail_bw=%lu, bw=" QOS_BW_FMT ", budget_us=%lu",
00333 srv->id, U_active_tot, w_active_tot, t_us, avail_bw, bw, budget_us);
00334 return kal_usec2time(budget_us);
00335 }
00336
00338 kal_time_t shrub_budget2time_exec(server_t *srv, kal_time_t budget) {
00339 qos_bw_t avail_bw, bw;
00340 unsigned long t, budget_us;
00341 if (U_active_tot >= U_LUB)
00342 return budget;
00343 avail_bw = U_LUB - U_active_tot;
00344 bw = MAX_BW - avail_bw * srv->weight / w_active_tot;
00345 budget_us = kal_time2usec(budget);
00346 t = div_by_bw(budget_us, bw);
00347 qos_log_debug("exec (s:%d) U_active_tot: %lu, w_active_tot=%u, avail_bw: " QOS_BW_FMT ", bw: " QOS_BW_FMT ", budget_us: %lu, t:%lu",
00348 srv->id, U_active_tot, w_active_tot, avail_bw, bw, budget_us, t);
00349 return kal_usec2time(t);
00350 }
00351
00352
00353 kal_time_t shrub_budget2time_noexec(server_t *srv, kal_time_t budget) {
00354 qos_bw_t avail_bw, bw;
00355 unsigned long t, budget_us;
00356 if (U_active_tot >= U_LUB)
00357 return budget;
00358 avail_bw = U_LUB - U_active_tot;
00359 bw = avail_bw * srv->weight / w_active_tot;
00360 budget_us = kal_time2usec(budget);
00361 t = div_by_bw(budget_us, bw);
00362 qos_log_debug("exec (s:%d) U_active_tot: %lu, w_active_tot=%u, avail_bw: " QOS_BW_FMT ", bw: " QOS_BW_FMT ", budget_us: %lu, t:%lu",
00363 srv->id, U_active_tot, w_active_tot, avail_bw, bw, budget_us, t);
00364 return kal_usec2time(t);
00365 }
00366
00367 #endif
00368
00369 static void update_budgets(kal_time_t consumed_time) {
00370 #ifdef SHRUB
00371 kal_time_t consumed_budget;
00372 struct list_head *tmp;
00373 server_t *srv;
00374 consumed_budget = shrub_time2budget_exec(exec, consumed_time);
00375 qos_log_debug("(s:%d) consumed time: " KAL_TIME_FMT ", decreased budget: " KAL_TIME_FMT,
00376 exec->id, KAL_TIME_FMT_ARG(consumed_time), KAL_TIME_FMT_ARG(consumed_budget));
00377 exec->c = kal_time_sub(exec->c, consumed_budget);
00378 for_each_server(srv, tmp) {
00379 if (in_ready_queue(srv) && srv != exec) {
00380 consumed_budget = shrub_time2budget_noexec(srv, consumed_time);
00381 srv->c = kal_time_add(srv->c, consumed_budget);
00382 }
00383 }
00384 #else
00385 exec->c = kal_time_sub(exec->c, consumed_time);
00386 #endif
00387 }
00388
00389
00390
00399 static qos_func_define(void, rres_update_budget, void) {
00400 kal_time_t consumed_time;
00401
00402 qos_log_debug("Starting function: sched_time=" KAL_TIME_FMT ", last_upd_time=" KAL_TIME_FMT ", (s:%d), srv_c=" KAL_TIME_FMT,
00403 KAL_TIME_FMT_ARG(sched_time), KAL_TIME_FMT_ARG(last_update_time), exec->id, KAL_TIME_FMT_ARG(exec->c));
00404 if (RRES_PARANOID)
00405 qos_chk_do(exec != NULL, return);
00406
00407
00408 consumed_time = kal_time_sub(sched_time, last_update_time);
00409 update_budgets(consumed_time);
00410 exec->stat.exec_time = kal_time_add(exec->stat.exec_time, consumed_time);
00411 last_update_time = sched_time;
00412 qos_log_debug("After update: sched_time=" KAL_TIME_FMT ", last_upd_time=" KAL_TIME_FMT ", (s:%d), srv_c= " KAL_TIME_FMT,
00413 KAL_TIME_FMT_ARG(sched_time), KAL_TIME_FMT_ARG(last_update_time), exec->id, KAL_TIME_FMT_ARG(exec->c));
00414 qos_log_debug("exec_stat_time=" KAL_TIME_FMT, KAL_TIME_FMT_ARG(exec->stat.exec_time));
00415 if (kal_time_le(exec->c, KAL_TIME_US(0, 0))) {
00416 if (in_ready_queue(exec)) {
00417 ready_queue_remove(exec);
00418 qos_log_debug("(s:%d): Setting recharge to " KAL_TIME_FMT, exec->id, KAL_TIME_FMT_ARG(exec->deadline));
00419 kal_timer_set(&exec->reactive, exec->deadline);
00420 } else {
00421
00422
00423
00424
00425
00426 }
00427 }
00428
00429 }
00430
00437 static void enforce_timer_handler(kal_arg_t dummy) {
00438 kal_irq_state flags;
00439 kal_spin_lock_irqsave(rres_get_spinlock(), &flags);
00440 qos_log_debug("Entering function");
00441 rres_sample_time();
00442 rres_schedule();
00443 qos_log_debug("Leaving function");
00444 kal_spin_unlock_irqrestore(rres_get_spinlock(), &flags);
00445 }
00446
00447
00448
00453 static qos_func_define(qos_rv, rres_activate_nosched, server_t *srv) {
00454 unsigned long delta_us;
00455 unsigned long c_lim;
00456
00457 rres_dump(srv);
00458
00459 if (RRES_PARANOID) {
00460 qos_chk_do(srv != NULL, return QOS_E_INTERNAL_ERROR);
00461 qos_chk_do(rres_has_ready_tasks(srv), return QOS_E_INTERNAL_ERROR);
00462 }
00463
00464
00465 qos_log_debug("current budget: " KAL_TIME_FMT ", deadline: " KAL_TIME_FMT,
00466 KAL_TIME_FMT_ARG(srv->c), KAL_TIME_FMT_ARG(srv->deadline));
00467 delta_us = kal_time2usec(kal_time_sub(srv->deadline, sched_time));
00468 c_lim = ul_mul_div(delta_us, srv->max_budget_us, srv->period_us);
00469
00470
00471 if (kal_time_le((srv)->deadline, sched_time) || (c_lim < kal_time2usec(srv->c))) {
00472 recharge_reset_from_now(srv);
00473 } else {
00474
00475
00476
00477 }
00478
00479
00480 srv->forbid_reorder = 0;
00481
00482 qos_chk_ok_ret(ready_queue_add(srv));
00483 return QOS_OK;
00484 }
00485
00493 qos_func_define(qos_rv, rres_deactivate_nosched, server_t *srv) {
00494 rres_dump(srv);
00495
00496 if (RRES_PARANOID) {
00497 qos_chk_do(srv != NULL, return QOS_E_INTERNAL_ERROR);
00498 qos_chk_do(! rres_has_ready_tasks(srv), return QOS_E_INTERNAL_ERROR);
00499 }
00500
00501 if (in_ready_queue(srv)) {
00502
00503 qos_log_debug("Deactivating a server in ready queue");
00504 stop_pending_timers(srv, 1);
00505 ready_queue_remove(srv);
00506 } else {
00507
00508 qos_log_debug("Deactivating a server not in ready queue");
00509 stop_pending_timers(srv, 0);
00510 }
00511 return QOS_OK;
00512 }
00513
00514 int rres_has_ready_tasks(server_t *srv) {
00515 if (RRES_PARANOID)
00516 qos_chk_do(srv != NULL, return 0);
00517 return ! list_empty(&srv->ready_tasks);
00518 }
00519 EXPORT_SYMBOL_GPL(rres_has_ready_tasks);
00520
00521
00522
00531 qos_func_define(void, stop_task_safe, server_t *srv, kal_task_t *task) {
00532 struct task_list *tl;
00533 if (! task_ready(task)) {
00534 qos_log_debug("Skipping stop of non-running task");
00535 return;
00536 }
00537 tl = rres_find_task_list(task);
00538 if (RRES_PARANOID)
00539 qos_chk_do(tl != NULL, return);
00540
00541 if (! tl->is_stopped) {
00542 if (srv->flags & QOS_F_SOFT)
00543 rres_task_sched_default(task);
00544 else
00545 stop_task(task);
00546 tl->is_stopped = 1;
00547 }
00548 }
00549
00555 qos_func_define(void, dispatch_task_safe, server_t *srv, kal_task_t *task) {
00556 struct task_list *tl = rres_find_task_list(task);
00557
00558 if (RRES_PARANOID)
00559 qos_chk_do(tl != NULL, return);
00560
00561 if (tl->is_stopped) {
00562 if (srv->flags & QOS_F_SOFT)
00563 rres_init_sched_param(task);
00564 else
00565 dispatch_task(task);
00566 tl->is_stopped = 0;
00567 }
00568 }
00569
00579 static qos_func_define(qos_rv, rres_attach_task_nosched, server_t *srv, kal_task_t *task) {
00580 int was_ready;
00581 if (RRES_PARANOID)
00582 qos_chk_do(task != NULL, return QOS_E_INVALID_PARAM);
00583
00584 qos_chk_do(rres_find_by_task(task) == NULL, return QOS_E_INTERNAL_ERROR);
00585 qos_log_debug("(s:%d),t(%d)", srv->id, kal_task_get_id(task));
00586
00587 if (srv != rres_get_default_server()) {
00588
00589 rres_init_sched_param(task);
00590 }
00591 was_ready = rres_has_ready_tasks(srv);
00592 qos_chk_ok_ret(rres_add(srv, task));
00593
00594 if ((! rres_running(srv)) && srv != rres_get_default_server() && task_ready(task)) {
00595
00596 stop_task_safe(srv, task);
00597
00598 }
00599
00600 if (rres_has_ready_tasks(srv) && ! was_ready)
00601 rres_activate_nosched(srv);
00602
00603 return QOS_OK;
00604 }
00605
00611 qos_func_define(qos_rv, rres_attach_task, server_t *srv, kal_task_t *task) {
00612 qos_rv rv;
00613 server_t *old_srv = rres_find_by_task(task);
00614
00615 rres_sample_time();
00616
00617 if (! kal_task_alive(task)) {
00618 qos_log_err("Attempt to attach a task that is dying");
00619 return QOS_E_INVALID_PARAM;
00620 }
00621
00622 if (old_srv != NULL) {
00623 rv = rres_move_nosched(srv, task);
00624 } else {
00625 rv = rres_attach_task_nosched(srv, task);
00626 }
00627 rres_schedule();
00628 return rv;
00629 }
00630 EXPORT_SYMBOL_GPL(rres_attach_task);
00631
00635 qos_func_define(qos_rv, rres_check_destroy, server_t *srv) {
00636 if ((! (srv->flags & QOS_F_PERSISTENT)) && rres_empty(srv)) {
00637
00638 qos_chk_ok_ret(rres_destroy_server(srv));
00639 srv = NULL;
00640 }
00641 return QOS_OK;
00642 }
00643 EXPORT_SYMBOL_GPL(rres_check_destroy);
00644
00648 qos_func_define(qos_rv, rres_detach_task_nosched, server_t *srv, kal_task_t *task) {
00649 int was_ready = rres_has_ready_tasks(srv);
00650
00651 if (RRES_PARANOID) {
00652 qos_chk_do(srv != NULL && task != NULL, return QOS_E_INTERNAL_ERROR);
00653 qos_chk_do(qos_mem_valid(srv), return QOS_E_INTERNAL_ERROR);
00654 }
00655 qos_log_debug("(s:%d),(t:%d)", srv->id, kal_task_get_id(task));
00656
00657
00658
00659 if (srv != rres_get_default_server())
00660 dispatch_task_safe(srv, task);
00661 rres_del(task);
00662 if (srv != rres_get_default_server())
00663 rres_task_sched_default(task);
00664
00665 if (was_ready && ! rres_has_ready_tasks(srv))
00666 qos_chk_ok_ret(rres_deactivate_nosched(srv));
00667
00668 return QOS_OK;
00669 }
00670
00683 qos_func_define(qos_rv, rres_detach_task, server_t *srv, kal_task_t *task) {
00684 qos_rv rv = QOS_OK;
00685 server_t *default_srv;
00686
00687 if (rres_find_by_task(task) != srv) {
00688 qos_log_err("Supplied task is not attached to supplied server");
00689 rv = QOS_E_INVALID_PARAM;
00690 goto err;
00691 }
00692 rres_sample_time();
00693 default_srv = rres_get_default_server();
00694 if (default_srv == NULL)
00695 qos_chk_ok_do(rv = rres_detach_task_nosched(srv, task), goto err);
00696 else
00697 qos_chk_ok_do(rv = rres_move_nosched(default_srv, task), goto err);
00698
00699 rres_schedule();
00700 qos_chk((! rres_empty(srv)) || ! rres_running(srv));
00701
00702 err:
00703
00704 return rv;
00705 }
00706 EXPORT_SYMBOL_GPL(rres_detach_task);
00707
00719 qos_func_define(qos_rv, rres_detach_all_tasks_nosched, server_t * srv) {
00720 kal_task_t *task;
00721
00722 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
00723 srv->forbid_reorder = 1;
00724 while ((task = rres_any_ready_task(srv)) != NULL) {
00725 qos_log_debug("(s:%d): Detaching task %d", srv->id, task->pid);
00726 qos_chk_ok_ret(rres_detach_task_nosched(srv, task));
00727 }
00728 while ((task = rres_any_blocked_task(srv)) != NULL) {
00729 qos_log_debug("(s:%d): Detaching task %d", srv->id, task->pid);
00730 qos_chk_ok_ret(rres_detach_task_nosched(srv, task));
00731 }
00732 return QOS_OK;
00733 }
00734
00740 qos_func_define(qos_rv, rres_move_nosched, server_t * new_srv, kal_task_t *task) {
00741 server_t *old_srv = rres_find_by_task(task);
00742 qos_chk_rv(old_srv != NULL, QOS_E_INTERNAL_ERROR);
00743 qos_chk_ok_ret(rres_detach_task_nosched(old_srv, task));
00744 qos_chk_ok_ret(rres_attach_task_nosched(new_srv, task));
00745 return QOS_OK;
00746 }
00747
00748 qos_rv rres_attach_all_tasks_nosched(server_t *srv);
00749
00752
00753
00760 qos_func_define(qos_rv, rres_init_server, server_t * srv, qres_time_t max_budget, qres_time_t period, unsigned long flags) {
00761 qos_bw_t U;
00762 qres_sid_t srv_id;
00763 qos_rv rv;
00764
00765 rres_sample_time();
00766
00767 if (RRES_PARANOID)
00768 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
00769
00770 srv->get_bandwidth = &_rres_get_bandwidth;
00771 srv->cleanup = &_rres_cleanup_server;
00772
00773
00774 qos_return_if_cond(max_budget >= period,
00775 QOS_E_INVALID_PARAM, "the budget must be lower than the period");
00776 qos_return_if_cond(max_budget < MIN_SRV_MAX_BUDGET,
00777 QOS_E_INVALID_PARAM, "budget too low: minimum budget = %lu", MIN_SRV_MAX_BUDGET );
00778 if (qos_debug_enabled_for(QOS_LEVEL_DEBUG))
00779 qos_return_if_cond(period < MIN_SRV_PERIOD_DEBUG,
00780 QOS_E_INVALID_PARAM, "period too low while debugging: minimum period = %lu", MIN_SRV_PERIOD_DEBUG);
00781 else
00782 qos_return_if_cond(period < MIN_SRV_PERIOD,
00783 QOS_E_INVALID_PARAM, "period too low: minimum period = %lu", MIN_SRV_PERIOD);
00784 U = r2bw(max_budget, period);
00785 qos_log_debug("requested: max_budget " QRES_TIME_FMT ", period " QRES_TIME_FMT ", U %lu, U_max %lu, U_tot: %lu",
00786 max_budget, period, U, MAX_BW, U_tot);
00787 qos_return_if_cond(U_LUB2 - U_tot < U,
00788 QOS_E_SYSTEM_OVERLOAD, "Not enough bandwidth to allocate a new server");
00789 srv_id = new_server_id();
00790 qos_return_if_cond(srv_id == QRES_SID_NULL,
00791 QOS_E_SYSTEM_OVERLOAD, "Could not find ID for new server");
00792
00793 if (flags & QOS_F_DEFAULT) {
00794 #ifdef CONFIG_RRES_DEFAULT_SRV
00795 qos_return_if_cond(rres_get_default_server() != NULL,
00796 QOS_E_INCONSISTENT_STATE, "Default server already exists");
00797 #else
00798 qos_log_err("Default server disabled");
00799 return QOS_E_UNIMPLEMENTED;
00800 #endif
00801 }
00802
00803
00804 srv->c = KAL_TIME_US(0, 0);
00805 srv->deadline = kal_time_now();
00806 srv->U_current = 0;
00807 srv->max_budget_us = 0;
00808 srv->max_budget = KAL_TIME_US(0, 0);
00809 srv->period_us = period;
00810 srv->period = kal_usec2time(period);
00811 srv->stat.n_rcg = 0;
00812 srv->stat.exec_time = KAL_TIME_US(0, 0);
00813 srv->flags = flags;
00814 srv->forbid_reorder = 0;
00815
00816
00817 rq_placeholder_init(&srv->rq_ph);
00818
00819 INIT_LIST_HEAD(&(srv->ready_tasks));
00820 INIT_LIST_HEAD(&(srv->blocked_tasks));
00821
00822 kal_timer_init(&srv->reactive, iris_hr_reactive_timer_handler, (kal_arg_t) srv);
00823
00824 srv->id = srv_id;
00825 rres_add_to_srv_set(srv);
00826
00827
00828
00829 if ((rv = rres_set_budget(srv, max_budget)) != QOS_OK) {
00830 qos_log_err("rres_set_params() failed: %s", qos_strerror(rv));
00831 rres_remove_from_srv_set(srv);
00832 return rv;
00833 }
00834 recharge_reset_from_now(srv);
00835 qos_log_debug("(s:%d): Server created", srv->id);
00836
00837 #ifdef CONFIG_RRES_DEFAULT_SRV
00838 if (flags & QOS_F_DEFAULT) {
00839 default_srv = srv;
00840 qos_chk_ok_ret(rres_attach_all_tasks_nosched(srv));
00841 }
00842 #endif
00843
00844 srv->weight = 1;
00845 return QOS_OK;
00846 }
00847 EXPORT_SYMBOL_GPL(rres_init_server);
00848
00855 qos_func_define(qos_rv, _rres_cleanup_server, server_t *srv) {
00856 qos_rv rv = QOS_OK;
00857
00858 rres_sample_time();
00859
00860 if (RRES_PARANOID)
00861 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
00862
00863 qos_log_debug("(s:%d): Cleaning up server", srv->id);
00864
00865
00866 qos_chk_do(rres_empty(srv), return QOS_E_INTERNAL_ERROR);
00867 #ifdef CONFIG_RRES_DEFAULT_SRV
00868 if (rres_get_default_server() == srv) {
00869 default_srv = NULL;
00870 }
00871 #endif
00872
00873
00874 if (RRES_PARANOID)
00875 qos_chk(! rres_running(srv));
00876
00877
00878
00879 if (RRES_PARANOID && in_ready_queue(srv)) {
00880
00881 ready_queue_remove(srv);
00882 qos_log_crit("Server " QRES_SID_FMT " should not be in ready queue!", srv->id);
00883 rv = QOS_E_INTERNAL_ERROR;
00884 }
00885 stop_pending_timers(srv, 1);
00886 qos_log_debug("(s:%d): Execution time:" QRES_TIME_FMT, srv->id, rres_get_exec_time(srv));
00887 rres_set_current_bandwidth(srv, 0);
00888 rres_remove_from_srv_set(srv);
00889
00890 return rv;
00891 }
00892 EXPORT_SYMBOL_GPL(_rres_cleanup_server);
00893
00896 qos_func_define(qos_rv, rres_create_server, server_t ** new_srv, qres_time_t max_budget, qres_time_t period, unsigned long type) {
00897 if (RRES_PARANOID)
00898 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
00899 *new_srv = qos_create(server_t);
00900 qos_chk_rv(*new_srv != NULL, QOS_E_NO_MEMORY);
00901 qos_chk_ok_ret(rres_init_server(*new_srv, max_budget, period, type));
00902 return QOS_OK;
00903 }
00904 EXPORT_SYMBOL_GPL(rres_create_server);
00905
00909 qos_func_define(qos_rv, rres_destroy_server, server_t *srv) {
00910 kal_task_t *task;
00911 if (RRES_PARANOID) {
00912 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
00913 qos_chk_do(srv != NULL, return QOS_E_INVALID_PARAM);
00914 }
00915
00916 while ((task = rres_any_ready_task(srv)) != NULL) {
00917
00918 qos_chk_ok_ret(rres_detach_task(srv, task));
00919 }
00920 while ((task = rres_any_blocked_task(srv)) != NULL) {
00921
00922 qos_chk_ok_ret(rres_detach_task(srv, task));
00923 }
00924 qos_chk_ok_ret(rres_cleanup_server(srv));
00925 qos_free(srv);
00926 return QOS_OK;
00927 }
00928 EXPORT_SYMBOL_GPL(rres_destroy_server);
00929
00934 qos_func_define(qos_rv, rres_attach_all_tasks_nosched, server_t *srv) {
00935 kal_task_t *t;
00936
00937 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
00938
00939 for_each_task(t) {
00940 if (rres_find_by_task(t) == NULL)
00941 qos_chk_ok_ret(rres_attach_task_nosched(srv, t));
00942 }
00943 return QOS_OK;
00944 }
00945
00946
00947
00951 qres_sid_t rres_get_sid(server_t *srv) {
00952 return (srv == NULL) ? QRES_SID_NULL : srv->id;
00953 }
00954 EXPORT_SYMBOL_GPL(rres_get_sid);
00955
00956
00957
00958
00959
00970 qos_func_define(qos_rv, rres_set_params, server_t *srv, qres_time_t new_budget, qres_time_t new_period) {
00971 qos_bw_t new_bw;
00972 if (RRES_PARANOID)
00973 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
00974 if (srv == NULL)
00975 return QOS_E_INTERNAL_ERROR;
00976 qos_log_debug("(s:%d): requested (Q:" QRES_TIME_FMT ", P:" QRES_TIME_FMT ")", srv->id, new_budget, new_period);
00977 new_bw = r2bw(new_budget, new_period);
00978
00979 if (U_LUB2 - (U_tot - srv->get_bandwidth(srv)) < new_bw)
00980 return QOS_E_SYSTEM_OVERLOAD;
00981 srv->max_budget_us = new_budget;
00982 srv->max_budget = kal_usec2time(new_budget);
00983 srv->period_us = new_period;
00984 srv->period = kal_usec2time(new_period);
00985 rres_update_current_bandwidth(srv);
00986
00987 if ((! rres_has_ready_tasks(srv)) || (! kal_time_le(srv->c, srv->max_budget)))
00988 srv->c = srv->max_budget;
00989 #ifdef RRES_INSTANT_SETPARAMS
00990 else if (kal_time_lt(sched_time, srv->deadline)) {
00991
00992 kal_time_t fake_P = kal_time_sub(srv->deadline, sched_time);
00993 qos_bw_t U_avail = U_LUB2 - U_tot;
00994 qres_time_t Q_avail = bw2Q(U_avail, kal_time2usec(fake_P));
00995 qres_time_t Q_curr = kal_time2usec(srv->c);
00996 qres_time_t Q_incr = srv->max_budget_us - Q_curr;
00997 if (Q_incr > Q_avail)
00998 Q_incr = Q_avail;
00999 srv->c = kal_usec2time(Q_curr + Q_incr);
01000 }
01001 #endif
01002
01003 return QOS_OK;
01004 }
01005 EXPORT_SYMBOL_GPL(rres_set_params);
01006
01011 qos_func_define(qos_rv, rres_set_budget, server_t *srv, qres_time_t new_budget) {
01012 qos_bw_t new_bw;
01013 if (RRES_PARANOID)
01014 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
01015 if (srv == NULL)
01016 return QOS_E_INTERNAL_ERROR;
01017 new_bw = r2bw(new_budget, srv->period_us);
01018 if (U_LUB2 - (U_tot - srv->get_bandwidth(srv)) < new_bw)
01019 return QOS_E_SYSTEM_OVERLOAD;
01020 srv->max_budget_us = new_budget;
01021 srv->max_budget = kal_usec2time(new_budget);
01022 rres_update_current_bandwidth(srv);
01023
01024 if ((! rres_has_ready_tasks(srv)) || (! kal_time_le(srv->c, srv->max_budget)))
01025 srv->c = srv->max_budget;
01026 return QOS_OK;
01027 }
01028 EXPORT_SYMBOL_GPL(rres_set_budget);
01029
01030 qos_func_define(qres_time_t, rres_get_actual_budget, server_t *srv) {
01031 return bw2Q(rres_get_bandwidth(srv), srv->period_us);
01032 }
01033
01035 qos_func_define(qos_rv, rres_get_params, server_t *srv, qres_time_t *budget, qres_time_t *period) {
01036 if (RRES_PARANOID)
01037 qos_chk_do(kal_atomic(), return QOS_E_INTERNAL_ERROR);
01038 if (srv == NULL)
01039 return QOS_E_INTERNAL_ERROR;
01040 *period = srv->period_us;
01041 *budget = bw2Q(rres_get_bandwidth(srv), srv->period_us);
01042 qos_log_debug("(s:%d), (Q:" QRES_TIME_FMT ", P:" QRES_TIME_FMT ")", srv->id, *budget, *period);
01043 return QOS_OK;
01044 }
01045 EXPORT_SYMBOL_GPL(rres_get_params);
01046
01047
01048
01049
01050
01051
01055 qos_func_define(qres_time_t, rres_get_period, server_t *srv) {
01056 return srv->period_us;
01057 }
01058 EXPORT_SYMBOL_GPL(rres_get_period);
01059
01066 qos_func_define(qres_time_t, rres_get_exec_time, server_t *srv) {
01067 if (RRES_PARANOID)
01068 qos_chk_do(kal_atomic(), return 0);
01069 if (srv == NULL) {
01070 qos_log(QOS_LEVEL_ERROR, "Null server pointer");
01071 return 0;
01072 } else if (srv == exec) {
01073 kal_time_t last_used = kal_time_sub(kal_time_now(), last_update_time);
01074
01075 return kal_time2usec(kal_time_add(srv->stat.exec_time, last_used));
01076 } else {
01077 return kal_time2usec(srv->stat.exec_time);
01078 }
01079 }
01080 EXPORT_SYMBOL_GPL(rres_get_exec_time);
01081
01083 server_t * rres_get_default_server(void) {
01084 #ifdef CONFIG_RRES_DEFAULT_SRV
01085 return default_srv;
01086 #else
01087 return NULL;
01088 #endif
01089 }
01090 EXPORT_SYMBOL_GPL(rres_get_default_server);
01091
01092
01093
01106 qos_func_define(void, rres_stop, server_t * srv) {
01107 kal_task_t *t;
01108 struct list_head *h;
01109 qos_log_debug("(s:%d): Stopping server", srv != NULL? srv->id: -1);
01110 if (is_default_server(srv)) {
01111 qos_log_debug("Stopping default server");
01112 return;
01113 }
01114 if (rres_empty(srv)) {
01115 qos_log_debug("Stopping empty server");
01116 return;
01117 }
01118 #ifdef CONST_TIME_DISPATCH
01119 rq_del_tasks(RRES_DISPATCH_PRIORITY, srv->disp_tasks, 0);
01120 #else
01121 for_each_ready_task_in_server(srv, t, h) {
01122 stop_task_safe(srv, t);
01123 }
01124
01125 if (kal_task_current() && ! srv->forbid_reorder) {
01126 struct task_list *tl = rres_find_task_list(kal_task_current());
01127
01128 if (tl && tl->srv == srv && (! list_empty(&srv->ready_tasks))) {
01129
01130
01131
01132 list_del(&srv->ready_tasks);
01133
01134
01135
01136 list_add(&srv->ready_tasks, &tl->node);
01137 }
01138 }
01139 #endif
01140 }
01141
01143 qos_func_define(void, rres_dispatch, server_t *srv) {
01144 qos_log_debug("(s:%d): Dispatching server", srv->id);
01145 if(! is_default_server(srv)) {
01146 if (! rres_empty(srv)) {
01147 #ifdef CONST_TIME_DISPATCH
01148 rq_add_tasks(RRES_DISPATCH_PRIORITY, srv->disp_tasks, 0);
01149 #else
01150
01151 kal_task_t *t;
01152 struct list_head *h;
01153
01154 for_each_ready_task_in_server(srv, t, h) {
01155 dispatch_task_safe(srv, t);
01156 }
01157 #endif
01158 } else {
01159 qos_log_err("No tasks in server!");
01160 }
01161 }
01162 }
01163
01172 kal_time_t get_max_time_slice(server_t *srv) {
01173 #ifdef SHRUB
01174 shrub_update_active();
01175 return shrub_budget2time_exec(srv, srv->c);
01176 #else
01177 return srv->c;
01178 #endif
01179 }
01180
01200 qos_func_define(void, rres_schedule, void) {
01201 server_t *new_exec = NULL;
01202
01203 qos_chk_do(exec == NULL || qos_mem_valid(exec), return);
01204 qos_log_debug("> exec: (s:%d)", exec != NULL ? exec->id: -1);
01205
01206 if (exec)
01207 rres_update_budget();
01208
01209 new_exec = get_highest_priority_server();
01210 qos_chk(new_exec == NULL || ! rres_empty(new_exec));
01211
01212 if (exec != NULL && new_exec != exec) {
01218 if (rres_has_ready_tasks(exec)) {
01219 rres_stop(exec);
01220 } else {
01221
01222 stop_pending_timers(exec, 1);
01223 }
01224 }
01225
01226 if (new_exec == NULL) {
01227
01228 qos_log_debug("No server in ready list");
01229 kal_timer_del(enforce);
01230 } else {
01231 kal_time_t max_time_slice = get_max_time_slice(new_exec);
01232 set_enforce_timer(max_time_slice);
01233 if (new_exec != exec)
01234 rres_dispatch(new_exec);
01235 }
01236 qos_log_debug("[%lld] OUT: (s:%d), IN: (s:%d)",
01237 kal_time2usec(sched_time),
01238 exec != NULL ? exec->id : -1,
01239 new_exec != NULL ? new_exec->id : -1
01240 );
01241
01242 exec = new_exec;
01243
01244
01245 kal_force_reschedule();
01246
01247
01248
01249
01250
01251
01252 qos_log_debug("< exec: (s:%d)", exec != NULL ? exec->id: -1);
01253 if (exec != NULL)
01254 rres_dump(exec);
01255 }
01256
01257
01258
01262 qos_func_define(qos_rv, rres_init, void) {
01263 rres_init_time();
01264 rres_sample_time();
01265 last_update_time = sched_time;
01266 INIT_LIST_HEAD(&server_list);
01267 qos_chk_ok_ret(rres_edf_init());
01268 enforce = qos_create(kal_timer_t);
01269 qos_chk_do(enforce != NULL, return QOS_E_NO_MEMORY);
01270 kal_timer_init(enforce, &enforce_timer_handler, (kal_arg_t) 0);
01271 rres_schedule();
01272 return QOS_OK;
01273 }
01274
01288 qos_func_define(qos_rv, rres_cleanup, void) {
01289 server_t *srv;
01290 struct list_head *tmp, *tmpdel;
01291
01292
01293 for_each_server_safe(srv, tmp, tmpdel) {
01294 qos_log(QOS_LEVEL_VERB, "(s:%d): Destroying sever", srv->id);
01295 rres_destroy_server(srv);
01296 }
01297
01298 if (enforce) {
01299 kal_timer_del(enforce);
01300 qos_free(enforce);
01301 }
01302 rres_edf_cleanup();
01303 return QOS_OK;
01304 }
01305
01306 int rres_running(server_t *srv) {
01307 return (srv == exec);
01308 }
01309 EXPORT_SYMBOL_GPL(rres_running);
01310
01318 qos_func_define(qos_rv, rres_on_task_unblock, kal_task_t *task) {
01319 server_t *srv;
01320 struct task_list *tl;
01321 int was_ready;
01322
01323 rres_sample_time();
01324 tl = rres_find_task_list(task);
01325 if (tl == NULL)
01326 return QOS_OK;
01327 srv = tl->srv;
01328 qos_chk_do(srv != NULL, return QOS_E_INTERNAL_ERROR);
01329
01330 if (srv != rres_get_default_server()) {
01331 was_ready = rres_has_ready_tasks(srv);
01332 if (! rres_running(srv))
01333 stop_task_safe(srv, task);
01334 list_del(&tl->node);
01335 list_add(&tl->node, &srv->ready_tasks);
01336 if (! was_ready) {
01337 rres_activate_nosched(srv);
01338 rres_schedule();
01339 }
01340 }
01341 return QOS_OK;
01342 }
01343
01344 qos_func_define(qos_rv, rres_on_task_block, kal_task_t *task) {
01345 server_t* srv;
01346 struct task_list *tl;
01347
01348 rres_sample_time();
01349 tl = rres_find_task_list(task);
01350 if (tl == NULL)
01351 return QOS_OK;
01352 srv = tl->srv;
01353 qos_chk_do(srv != NULL, return QOS_E_INTERNAL_ERROR);
01354
01355 if (srv != rres_get_default_server()) {
01356 dispatch_task_safe(srv, task);
01357 list_del(&tl->node);
01358 list_add(&tl->node, &srv->blocked_tasks);
01359 if (! rres_has_ready_tasks(srv)) {
01360 rres_deactivate_nosched(srv);
01361 rres_schedule();
01362 }
01363 }
01364 return QOS_OK;
01365 }
01366
01367 EXPORT_SYMBOL_GPL(server_list);