/* * cpu_reserve.c: code to support CPU reservations * * Copyright (C) 2000 TimeSys Corporation * * This is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * This file is derived from software distributed under the following terms: * * Real-time and Multimedia Systems Laboratory * Copyright (c) 2000 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Real-Time and Multimedia Systems Laboratory * Attn: Prof. Raj Rajkumar * Electrical and Computer Engineering, and Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * or via email to raj@ece.cmu.edu * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ #include #include #include #include #include #include #include #include #ifdef CONFIG_MEASURE #include /* cdm */ #include /* /cdm/ */ #endif /* CONFIG_MEASURE */ /* cdm */ int gStatic_scaling_boost; /* cdm */ #define _DEBUG_CDM_ /* /cdm/ */ //#define EARLY_ENFORCE #define CHECK_TICKET_EXPIRE #define DELAY 5 extern struct task_struct *expected_current; int current_critical = 0; extern struct list_head rk_resource_set_root; extern void rk_resource_set_schedule(struct rs_proc_list *rs_proc, unsigned int arg); extern void rk_resource_set_adjust_accounting(void); extern int cpu_reserve_eligible(rk_reserve_t rsv); /* * Function prototypes */ /* cdm */ static void set_SPM_boost(void); /* cdm\ */ static int cpu_reserve_destroy(rk_reserve_t); static void cpu_reserve_start_account(rk_reserve_t); static void cpu_reserve_stop_account(rk_reserve_t, cpu_tick_t); static void cpu_reserve_replenish(rk_reserve_t, cpu_tick_t, cpu_tick_t); static void cpu_reserve_enforce(rk_reserve_t); static void cpu_reserve_sleep_on(rk_reserve_t); static void cpu_reserve_attach(rk_reserve_t, struct rs_proc_list *); static void cpu_reserve_detach(rk_reserve_t, struct rs_proc_list *); static void cpu_reserve_update_ticket(rk_reserve_t, unsigned long); static void cpu_reserve_ticket_query(rk_reserve_t, unsigned long *); static void cpu_reserve_wait_one_ticket(rk_reserve_t); static int cpu_reserve_read_proc(rk_reserve_t, char *); static void check_enforce_reserve_type(cpu_reserve_attr_t cpu_attr); static int set_scheduling_policy(int policy); /* Obtain the rk spinlock before calling these */ void cpu_reserve_sched(struct rs_proc_list *, cpu_reserve_t cpu); void cpu_reserve_sched_realtime(struct rs_proc_list *, unsigned priority_index); void cpu_reserve_sched_timeshare(struct rs_proc_list *, unsigned priority_index); void cpu_reserve_sched_timeshare_self(void); //Gaurav //extern void rk_sleep_on(struct wait_queue **p, struct list_head *lhead); extern void rk_sleep_on(wait_queue_t **p, struct list_head *lhead); /* static int rk_cpu_reserves_set_scheduling_policy(int policy); */ /* static int rk_cpu_reserves_get_num(void); */ /* static int set_scheduling_policy(int policy); */ /* static int rk_cpu_reserves_get_scheduling_policy(void); */ #define SUPER_CHARGED 1 #ifdef SUPER_CHARGED #define RATE_MONOTONIC 0 #define DEADLINE_MONOTONIC 1 #define EDF 2 #define NUM_CPU_RESERVE_POLICIES (EDF + 1) #define BLOCKING_PRIORITY -1 static int cpu_reserves_scheduling_policy = DEADLINE_MONOTONIC; #endif /* SUPER_CHARGED */ struct rk_reserve_ops cpu_reserve_ops = { cpu_reserve_destroy, cpu_reserve_start_account, cpu_reserve_stop_account, cpu_reserve_replenish, cpu_reserve_enforce, cpu_reserve_attach, cpu_reserve_detach, #ifdef linux cpu_reserve_sleep_on, cpu_reserve_read_proc, #endif cpu_reserve_update_ticket, /* update the used tickets */ cpu_reserve_ticket_query, /* ask for the available tickets */ cpu_reserve_wait_one_ticket, /* (wait_on_quota)if no tickets , sleep */ }; /* * Global variables */ struct list_head cpu_reserve_head; cpu_capacity_t cpu_reserve_current_capacity; #define CAPACITY_INT(x) ((x)/100) #define CAPACITY_FRAC(x) ((x)-(x/100)*100) #define INT2CAPACITY(x) ((x)*10000) #define CAPACITY2INT(x) ((x)/10000) #define PERCENT2CAPACITY(x) ((x)*100) #define CAPACITY_OF(c,t) (INT2CAPACITY(c)/(t)) /* * 66% ... is the maximum available capacity for reserves. */ #define CPU_CAPACITY_MAX PERCENT2CAPACITY(66) /* cdm */ #define CPU_SPEED_BOOST_0 (300) #define CPU_SPEED_BOOST_33 (400) #define CPU_SPEED_BOOST_66 (500) #define CPU_SPEED_BOOST_100 (600) #define MAX_CPU_SPEED (CPU_SPEED_BOOST_100) /* This function calculates our desired boost level, then iterates ** through the entire list of processes and sets each processes boost ** accordingly. ** ** It is called when a new cpu reserve is created, or when one is ** modified via cpu_reserve_ctl. */ static void set_SPM_boost() { struct task_struct *p; int setBoostTo; int percentMax; int load; //percent of current capacity load = CAPACITY_INT( cpu_reserve_current_capacity ); /* First calculate the desired boost level */ percentMax = load * MAX_CPU_SPEED; percentMax = percentMax/100; /* Debugging code */ printk("CDM: set_SPM_boost called with capacity %d, ideal clock %d\n", load, percentMax ); if( percentMax < CPU_SPEED_BOOST_0 ) setBoostTo = 0; else if( percentMax < CPU_SPEED_BOOST_33 ) setBoostTo = 33; else if( percentMax < CPU_SPEED_BOOST_66 ) setBoostTo = 66; else setBoostTo = 100; printk("CDM: setting global boost value to %d\n", setBoostTo ); /* loop through all our tasks and set the boost of each one */ for_each_task(p) { p->boost = setBoostTo; } } /* \cdm\ */ #define cpu_reserve_entry(list) list_entry((list), struct cpu_reserve, cpu_link) /* * More function prototypes */ static int admit_reserve_request(cpu_reserve_t cpu); static void priority_list_add(cpu_reserve_t cpu, struct list_head *head); static int priority_list_remove(cpu_reserve_t cpu, struct list_head *head); static int efficient_timespec_ceil(struct timespec dividend, struct timespec divider); static int ceiling(unsigned long dividend, unsigned long divider); static int timespec_ceiling(struct timespec dividend, struct timespec divider); static struct timespec timespec_mult(struct timespec multiplicand, int multiplier); static struct timespec timespec_mult(struct timespec, int); /* * */ void cpu_reserve_init(void) { INIT_LIST_HEAD(&cpu_reserve_head); cpu_reserve_current_capacity = 0; } rk_reserve_t cpu_reserve_create(rk_resource_set_t rs, cpu_reserve_attr_t cpu_attr) { rk_reserve_t rsv; cpu_reserve_t cpu; cpu_capacity_t capacity; cpu_capacity_t new_capacity; cpu_capacity_quad_t qc, qt, qd; cpu_tick_data_t now; struct timespec cur_time; if (rs == NULL) return NULL_RESERVE; /* check for validity of "rs" first */ if (!rk_valid_rset(rs)) return NULL_RESERVE; #if 0 if (rs->rs_cpu) { /* pre-existing cpu reserve */ return NULL_RESERVE; } #endif #ifdef DEBUG_RK printk ("cpu_reserve_create: rs(0x%x) c(%d,%d) t(%d,%d) d(%d,%d) mode(%d,%d,%d)", (int) rs, (int) cpu_attr->compute_time.tv_sec,http://rita.thegourmet.com/computers.html (int) cpu_attr->compute_time.tv_nsec, (int) cpu_attr->period.tv_sec, (int) cpu_attr->period.tv_nsec, (int) cpu_attr->deadline.tv_sec, (int) cpu_attr->deadline.tv_nsec, cpu_attr->reserve_type.enf_mode, cpu_attr->reserve_type.rep_mode, cpu_attr->reserve_type.sch_mode); #endif /* admission control */ qc = cpu_attr->compute_time.tv_sec; qc *= NANOSEC; qc += cpu_attr->compute_time.tv_nsec; qt = cpu_attr->period.tv_sec; qt *= NANOSEC; qt += cpu_attr->period.tv_nsec; qd = cpu_attr->deadline.tv_sec; qd *= NANOSEC; qd += cpu_attr->deadline.tv_nsec; if (!qt) return NULL_RESERVE; capacity = CAPACITY_OF(qc, qt); /* check for zero reservation */ #if 0 /* This function calculates our desired boost level, then iterates ** through the entire list of processes and sets each processes boost ** accordingly */ if (!timespec_nonzero(cpu_attr->compute_time)) { /* zero compute time: unacceptable value */ return NULL_RESERVE; } #endif /* check deadline */ if (timespec_gt(cpu_attr->deadline, cpu_attr->period)) { /* deadline cannot be greater than the period */ return NULL_RESERVE; } /* check for sane start_time value */ if (cpu_attr->start_time.tv_nsec >= NANOSEC) { return NULL_RESERVE; } /* create cpu reserve object */ cpu = malloc(sizeof(struct cpu_reserve)); bzero(cpu, sizeof(struct cpu_reserve)); memcpy(&(cpu->cpu_res_attr), cpu_attr, sizeof(cpu_reserve_attr_data_t)); cpu->cpu_capacity = capacity; /* assigned scheduling policy */ cpu->scheduling_policy = SCHED_FIFO; /* * EDF stuff: In order to insert the reservation in the list, * we have to assign an absolute deadline to it... The correct * deadline is Start Time + Deadline. * (P.S.: the update in ``replenish'' is no more needed...) * Luca */ rk_cur_time(&cur_time); rk_rdtsc(&now); timespec_set(cpu->absdl, cpu_attr->start_time); timespec_sub(cpu->absdl, cur_time); if (cpu->absdl.tv_sec < 0) { cpu->absdl.tv_sec = cpu->absdl.tv_nsec = 0; } cur_time.tv_sec = TICK2USEC(&now) / 1000000; cur_time.tv_nsec = (TICK2USEC(&now) % 1000000) * 1000; timespec_add(cpu->absdl, cur_time); timespec_add(cpu->absdl, cpu->cpu_res_attr.deadline); /* add reservation to reservation list in descending priority * order expecting successful inclusion. */ priority_list_add(cpu, &cpu_reserve_head); /* do an admission control test */ if (!admit_reserve_request(cpu)) { /* admission control failed */ priority_list_remove(cpu, &cpu_reserve_head); free(cpu); return NULL_RESERVE; /* error */ } #ifdef CONFIG_MEASURE measure_newreserve(cpu); #endif /* CONFIG_MEASURE */ new_capacity = capacity + cpu_reserve_current_capacity; cpu_reserve_current_capacity = new_capacity; #ifdef DEBUG_RK printk ("cpu_reserve_create: capacity(%lu.%02lu) new total(%lu.%02lu)\n", CAPACITY_INT(capacity), CAPACITY_FRAC(capacity), CAPACITY_INT(new_capacity), CAPACITY_FRAC(new_capacity)); #endif /* calculate cpu ticks per capacity */ nanosec2tick(&qt, &cpu->cpu_period_ticks); nanosec2tick(&qd, &cpu->cpu_deadline_ticks); nanosec2tick(&qc, &cpu->cpu_time_ticks); #ifdef DEBUG_RK printk("c=%d, p=%d\n", (int) cpu->cpu_time_ticks, (int) cpu->cpu_period_ticks); #endif /* DEBUG_RK */ cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; cpu->cpu_period_used_ticks = 0; /* init waitqueue */ // init_waitqueue(&cpu->depleted_wait); //Gaurav init_waitqueue_head(&cpu->depleted_wait); /* check reservation type */ check_enforce_reserve_type(cpu_attr); /* create generic reserve object */ rsv = rk_reserve_create(rs, RSV_CPU); rsv->rsv_state = RSV_IS_NULL; rsv->rsv_rsv = cpu; rsv->rsv_ops = &cpu_reserve_ops; rsv->rsv_reserve_param = cpu_attr->reserve_type; cpu->rsv = rsv; /* Check if this reserve enables tickets */ if (cpu->cpu_res_attr.ticket_type != DISABLE) { cpu->tickets.quota_tickets = cpu->cpu_res_attr.quota_tickets; cpu->tickets.ticket_age = cpu->cpu_res_attr.ticket_age; cpu->tickets.available_tickets = 0; cpu->tickets.expiration = 0; } // init_waitqueue(&cpu->ticket_wait); // Gaurav init_waitqueue_head(&cpu->ticket_wait); /* create a timer for it */ /* XXX: we must later have one timer per resource instance in set */ rk_replenish_timer_create(rsv, cpu_attr->start_time); /* cdm */ #ifdef _DEBUG_CDM_ printk("CDM: Calling set_SPM_boost from create_cpu_reserve\n"); #endif set_SPM_boost(); return rsv; /* success */ } int cpu_reserve_ctl(rk_reserve_t rsv, cpu_reserve_attr_t cpu_attr) { cpu_reserve_t cpu; cpu_reserve_attr_data_t old_local_attr; cpu_capacity_t capacity; cpu_capacity_t new_capacity, old_capacity; cpu_capacity_quad_t qc, qt, qd; int admit_ok = FALSE; int pos_adjust = FALSE; /* check for validity of "rs" first */ if ((rsv == NULL) || (!rk_valid_rsv(rsv))) return -EINVAL; if ((void *) (cpu = rsv->rsv_rsv) == NULL_RESERVE) return -EINVAL; /* check for zero reservation request */ if (!timespec_nonzero(cpu_attr->compute_time)) { /* zero compute time: unacceptable value */ return -EINVAL; } /* check deadline */ if (timespec_gt(cpu_attr->deadline, cpu_attr->period)) { /* deadline cannot be greater than the period */ return -EINVAL; } #ifdef DEBUG_RK printk ("cpu_reserve_ctl: rsv(0x%x) OLD: c(%ld,%ld) t(%ld,%ld) NEW: c(%ld,%ld) t(%ld,%ld)\n", (int) rsv, cpu->cpu_res_attr.compute_time.tv_sec, cpu->cpu_res_attr.compute_time.tv_nsec, cpu->cpu_res_attr.period.tv_sec, cpu->cpu_res_attr.period.tv_nsec, cpu_attr->compute_time.tv_sec, cpu_attr->compute_time.tv_nsec, cpu_attr->period.tv_sec, cpu_attr->period.tv_nsec); #endif /* calculate a new capacity */ qc = cpu_attr->compute_time.tv_sec; qc *= NANOSEC; qc += cpu_attr->compute_time.tv_nsec; qt = cpu_attr->period.tv_sec; qt *= NANOSEC; qt += cpu_attr->period.tv_nsec; qd = cpu_attr->deadline.tv_sec; qd *= NANOSEC; qd += cpu_attr->deadline.tv_nsec; capacity = CAPACITY_OF(qc, qt); /* save the old parameters */ memcpy(&old_local_attr, &(cpu->cpu_res_attr), sizeof(cpu_reserve_attr_data_t)); old_capacity = cpu->cpu_capacity; /* load the new parameters */ memcpy(&(cpu->cpu_res_attr), cpu_attr, sizeof(cpu_reserve_attr_data_t)); cpu->cpu_capacity = capacity; /* we must re-locate the reserve in the list if its period or * deadline changed. */ #ifdef SUPER_CHARGED { int adjust = FALSE; switch (cpu_reserves_scheduling_policy) { case RATE_MONOTONIC: if (timespec_ne(old_local_attr.period, cpu_attr->period)) { adjust = TRUE; break; } if ((timespec_eq(old_local_attr.deadline, cpu_attr->deadline)) && (timespec_ge (old_local_attr.blocking_time, cpu_attr->blocking_time)) && (timespec_ge (old_local_attr.compute_time, cpu_attr->compute_time))) { /* same period, same deadline, less compute time: must be ok */ admit_ok = TRUE; } break; case DEADLINE_MONOTONIC: if (timespec_ne(old_local_attr.deadline, cpu_attr->deadline)) { adjust = TRUE; break; } if ((timespec_eq(old_local_attr.period, cpu_attr->period)) && (timespec_eq(old_local_attr.deadline, cpu_attr->deadline)) && (timespec_ge(old_local_attr.blocking_time, cpu_attr->blocking_time)) && (timespec_ge(old_local_attr.compute_time, cpu_attr->compute_time))) { /* same period, same deadline, less compute time: must be ok */ admit_ok = TRUE; } break; /* Added the test for EDF: (same as for DM) * Luca */ case EDF: if (timespec_ne(old_local_attr.deadline, cpu_attr->deadline)) { adjust = TRUE; break; } if ((timespec_eq(old_local_attr.period, cpu_attr->period)) && (timespec_ge(old_local_attr.blocking_time, cpu_attr->blocking_time)) && (timespec_ge(old_local_attr.compute_time, cpu_attr->compute_time))) { /* same period, same deadline, less compute time: must be ok */ admit_ok = TRUE; } break; } if (adjust) { pos_adjust = TRUE; /* need this for possible resetting later */ priority_list_remove(cpu, &cpu_reserve_head); priority_list_add(cpu, &cpu_reserve_head); } } #else /* SUPER_CHARGED */ if (timespec_ne(old_local_attr.period, cpu_attr->period)) { priority_list_remove(cpu, &cpu_reserve_head); priority_list_add(cpu, &cpu_reserve_head); } #endif /* SUPER_CHARGED */ /* do a new admission control test */ if ((!admit_ok) && (!admit_reserve_request(cpu))) { /* admission control failed: return to original values */ memcpy(&(cpu->cpu_res_attr), &old_local_attr, sizeof(cpu_reserve_attr_data_t)); cpu->cpu_capacity = old_capacity; if (pos_adjust) { /* remove and add from list again */ priority_list_remove(cpu, &cpu_reserve_head); priority_list_add(cpu, &cpu_reserve_head); } return RK_ERROR; /* error since change failed */ } /* available utilization: is this really needed? */ new_capacity = capacity + cpu_reserve_current_capacity - cpu->cpu_capacity; cpu_reserve_current_capacity = new_capacity; #ifdef DEBUG_RK printk("cpu_reserve_ctl: capacity(%lu.%02lu) new total(%lu.%02lu)\n", CAPACITY_INT(capacity), CAPACITY_FRAC(capacity), CAPACITY_INT(new_capacity), CAPACITY_FRAC(new_capacity)); #endif /* DEBUG_RK */ /* check reservation type */ check_enforce_reserve_type(cpu_attr); { unsigned long flags; rk_spin_lock(flags); /* update reserve parameters */ rsv->rsv_reserve_param = cpu_attr->reserve_type; /* calculate cpu ticks per capacity */ nanosec2tick(&qt, &cpu->cpu_period_ticks); nanosec2tick(&qc, &cpu->cpu_time_ticks); nanosec2tick(&qd, &cpu->cpu_deadline_ticks); cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; /* fix 7.5.00 */ if (cpu->cpu_period_used_ticks > cpu->cpu_time_ticks) { cpu->cpu_period_used_ticks = cpu->cpu_time_ticks - 1; } rk_spin_unlock(flags); } /* Check if this reserve enables tickets */ if (cpu->cpu_res_attr.ticket_type != DISABLE) { cpu->tickets.quota_tickets = cpu->cpu_res_attr.quota_tickets; cpu->tickets.ticket_age = cpu->cpu_res_attr.ticket_age; } /* CDM -- Look at the total utilization and set our boost */ #ifdef _DEBUG_CDM_ printk("Calling set_SPM_boost from cpu_reserve_ctl\n"); #endif set_SPM_boost(); return RK_SUCCESS; /* success set_SPM_boost*/ } static int cpu_reserve_destroy(rk_reserve_t rsv) { cpu_reserve_t cpu = rsv->rsv_rsv; #ifdef DEBUG_RK printk("cpu_reserve_destroy: rsv(0x%x) cpu(0x%x)\n", (int) rsv, (int) cpu); #endif /* DEBUG_RK */ /* destroy timer */ rk_replenish_timer_destroy(rsv); #ifdef CONFIG_MEASURE measure_endreserve(cpu); #endif /* CONFIG_MEASURE */ /* return capacity */ cpu_reserve_current_capacity -= cpu->cpu_capacity; if ((int) cpu_reserve_current_capacity < 0) { cpu_reserve_current_capacity = 0; } list_del(&cpu->cpu_link); INIT_LIST_HEAD(&cpu->cpu_link); /* for sure */ kfree(cpu); rsv->rsv_rsv = NULL_RESERVE; rk_reserve_destroy(rsv); /* CDM */ set_SPM_boost( ); return RK_SUCCESS; /* success */ } /* * */ static inline void cpu_reserve_summation_of_used_ticks(cpu_reserve_t cpu, cpu_tick_t now) { cpu->cpu_period_used_ticks += (*now - cpu->cpu_period_start_ticks); cpu->cpu_period_start_ticks = *now; } /* * Enable scheduler to make a process eligible for execution. */ inline void cpu_reserve_sched_enable(struct rs_proc_list *rs_proc, unsigned int arg) { rs_proc->rs_proc_task->rk_cannot_schedule = FALSE; current->need_resched = 1; } /* * Disable scheduler from making process eligible for execution. */ inline void cpu_reserve_sched_disable(struct rs_proc_list *rs_proc, unsigned int arg) { rs_proc->rs_proc_task->rk_cannot_schedule = TRUE; current->need_resched = 1; } /* * Replenish & Enforce a reserve */ /* Add parameter start_ticks which is the start time of each period * of the reserve. This is for computing the eligible deadline of * the reserve. */ static void cpu_reserve_replenish(rk_reserve_t rsv, cpu_tick_t period, cpu_tick_t start_ticks) { cpu_reserve_t cpu = rsv->rsv_rsv; cpu_capacity_t c; long long ticks; struct list_head *ptr; cpu_reserve_t r; int done; long flags; #ifdef PREEMPT_FIX /* Let's try the Apple fix... */ int safe_preemption = 0; if (current->rk_resource_set == rk_current_resource_set) { /* Well.... It can happen that the replenish timer interruptsi * the scheduler - the kernel lock is released immediately before * calling rk_sched_hook :( - in this case, current can be the * previos task, and it is completely wrong to use it :( */ safe_preemption = 1; } #endif #ifdef APPLE_DEBUG printk("replenish rsv (%x) \n", (unsigned int) rsv); #endif /* APPLE_DEBUG */ rk_spin_lock(flags); *period = cpu->cpu_period_ticks; #ifdef SUPER_CHARGED /* * This is the terrible thing... For CBS, we do not * need replenish here (it only confuses everything...) * Luca, FIX IT!!! */ if ((rsv->rsv_reserve_param.enf_mode == RSV_SOFT) && (cpu_reserves_scheduling_policy == EDF)) { rk_spin_unlock(flags); return; } #endif /* update eligible time */ /* set up the next deadline of the eligible time */ cpu->cpu_eligible_deadline_ticks = *start_ticks + cpu->cpu_deadline_ticks; if (rsv->rsv_state & RSV_IS_RUNNING) { cpu_tick_data_t now; rk_rdtsc(&now); cpu_reserve_summation_of_used_ticks(cpu, &now); #ifdef SUPER_CHARGED /* * EDF: We also need to adjust the absolute deadline.... * ...for some strange reason, if replenishment and enforcement * should be simultaneous, replenish could raise first... * ...so, IT has to postpone deadline!!! * Luca */ if (cpu_reserves_scheduling_policy == EDF) { timespec_add(cpu->absdl, cpu->cpu_res_attr.deadline); priority_list_remove(cpu, &cpu_reserve_head); priority_list_add(cpu, &cpu_reserve_head); #ifdef DEBUG_RK printk("Postponing DL: %ld %ld\n", cpu->absdl.tv_sec, cpu->absdl.tv_nsec); #endif /* Let's set all the priorities in the proper way... */ ptr = cpu_reserve_head.next; done = 0; while (!done) { r = cpu_reserve_entry(ptr); if ((r->rsv->rsv_reserve_param.enf_mode == RSV_SOFT) || ((r->rsv->rsv_state & RSV_IS_DEPLETED) == 0)) { rs_proc_list_apply(&(r->rsv->rsv_rs->rs_proc_list), cpu_reserve_sched_realtime, r->cpu_priority_index); } if (cpu_reserve_entry(ptr) == cpu) { done = 1; } ptr = ptr->next; } current->need_resched = 1; } #endif /* SUPER_CHARGED */ } /* update statistics */ cpu->cpu_period_prev_used_ticks = cpu->cpu_period_used_ticks; c = CAPACITY_OF(cpu->cpu_period_used_ticks, cpu->cpu_period_ticks); if (cpu->cpu_max_utilization < c) { cpu->cpu_max_utilization = c; } else if ((cpu->cpu_min_utilization > c) || (cpu->cpu_min_utilization == 0)) { cpu->cpu_min_utilization = c; } /* summation for average */ cpu->cpu_average.total_utils += c; cpu->cpu_average.total_count++; #ifdef DEBUG_RK2 printk("cpu_reserve_replenish: rsv(0x%x) used(%lu/%lu)\n", (int) rsv, (unsigned long) cpu->cpu_period_used_ticks, (unsigned long) cpu->cpu_period_available_ticks); #endif /* DEBUG_RK2 */ /* refill the capacity */ switch (rsv->rsv_reserve_param.rep_mode) { case RSV_SOFT: cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; break; case RSV_FIRM: ticks = cpu->cpu_period_used_ticks - cpu->cpu_time_ticks; /* when excessively used */ if (ticks > 0) { cpu_tick_data_t next; next = cpu->cpu_time_ticks - ticks; if (cpu->cpu_time_ticks >= ticks) { cpu->cpu_period_available_ticks = next; } else { cpu->cpu_period_available_ticks = 0; } } else { cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; } break; case RSV_HARD: ticks = cpu->cpu_period_used_ticks - cpu->cpu_period_available_ticks; /* when excessively used */ if (ticks > 0) { cpu_tick_data_t next; next = cpu->cpu_time_ticks - ticks; if (cpu->cpu_time_ticks >= ticks) { cpu->cpu_period_available_ticks = next; } else { cpu->cpu_period_available_ticks = 0; } } else { cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; } break; default: printk("replenish: unknown rep mode!\n"); break; } /* reset the used ticks */ cpu->cpu_period_used_ticks = 0; #ifdef DEBUG_RK2 printk ("cpu_reserve_replenish: rsv(0x%x) state(%x) next available(%lu)\n", (int) rsv, (int) rsv->rsv_state, (unsigned long) cpu->cpu_period_available_ticks); #endif /* DEBUG_RK2 */ /* issue tickets */ switch (cpu->cpu_res_attr.ticket_type) { case CONSTANT: cpu->tickets.available_tickets = cpu->tickets.quota_tickets; cpu->tickets.expiration = *start_ticks + cpu->tickets.ticket_age; wake_up(&cpu->ticket_wait); break; default: cpu->tickets.available_tickets = 0; /* disable other types at this moment */ break; } if (rsv->rsv_state & RSV_IS_DEPLETED) rsv->rsv_state &= ~RSV_IS_DEPLETED; /* update cpu reserve of the resource set */ { rk_reserve_t rk_resource_set_update_cpu(rk_resource_set_t); rk_resource_set_update_cpu(rsv->rsv_rs); } if (rsv->rsv_rs->rs_cpu) { rs_proc_list_apply(&rsv->rsv_rs->rs_proc_list, rk_resource_set_schedule, 0); } #ifdef PREEMPT_FIX if (safe_preemption) { #endif /* Make sure the enforcement timer is set */ /* stop old accounting */ if (rk_current_cpu_reserve) { cpu_tick_data_t now; rk_rdtsc(&now); rk_current_cpu_reserve->rsv_ops-> stop_account(rk_current_cpu_reserve, &now); } #ifndef PREEMPT_FIX /* This is critical; if current is not the same as expected current, * we shouldn't touch anything to rk_current_resource_set yet -Apple */ if ((expected_current != (void *) -1) && (expected_current != current)) { #ifdef APPLE_DEBUG_RK printk("Danger interrupt (replenish rsv(0x%x)) during schedule: data in sync current (%d) but expect (%d)\n", (int) rsv, current->pid, expected_current->pid); #endif current_critical = 1; } else current_critical = 0; if (!current_critical) { #endif /* update rk_current_resource_set and rk_current_cpu_reserve */ rk_current_resource_set = current->rk_resource_set; if (rk_current_resource_set) { rk_current_cpu_reserve = current->rk_resource_set->rs_cpu; /* start new accounting */ if (rk_current_cpu_reserve) { rk_current_cpu_reserve->rsv_ops-> start_account(rk_current_cpu_reserve); } } else { rk_current_cpu_reserve = NULL_RESERVE; } } #ifndef PREEMPT_FIX else { /* update rk_current_resource_set and rk_current_cpu_reserve */ rk_current_resource_set = expected_current->rk_resource_set; if (rk_current_resource_set) { rk_current_cpu_reserve = expected_current->rk_resource_set->rs_cpu; /* start new accounting */ if (rk_current_cpu_reserve) { rk_current_cpu_reserve->rsv_ops->start_account(rk_current_cpu_reserve); } } else { rk_current_cpu_reserve = NULL_RESERVE; } } #endif rk_spin_unlock(flags); } void signal_tasks(struct rs_proc_list *rs_proc, unsigned int priority_index); static void cpu_reserve_enforce(rk_reserve_t rsv) { rk_resource_set_t rs; struct list_head *ptr; cpu_reserve_t cpu = rsv->rsv_rsv; cpu_reserve_t r; int done; long flags; rk_spin_lock(flags); if (!(rsv->rsv_state & RSV_IS_DEPLETED)) { #ifdef DEBUG_RK2 #ifdef DEBUG_RK_ENFORCE debug_rk_enforce_flag = 1; #endif /* DEBUG_RK_ENFORCE */ printk("cpu_reserve_enforce: rsv(0x%x)\n", (int) rsv); #endif /* DEBUG_RK2 */ rsv->rsv_state |= RSV_IS_DEPLETED; } #ifdef SUPER_CHARGED /* * EDF: Let's update the absolute deadline!!! * Simply increase by the period... * Luca */ if (cpu_reserves_scheduling_policy == EDF) { /* set up the next deadline of the eligible time */ cpu->cpu_eligible_deadline_ticks += cpu->cpu_deadline_ticks; timespec_add(cpu->absdl, cpu->cpu_res_attr.period); #ifdef DEBUG_RK { struct timespec now; rk_cur_time(&now); printk ("[%d] 0x%x: Postponing deadline at %d %d | Time %ld %ld\n", current->pid, rsv->rsv_rs, cpu->absdl.tv_sec, cpu->absdl.tv_nsec, now.tv_sec, now.tv_nsec); } #endif priority_list_remove(cpu, &cpu_reserve_head); priority_list_add(cpu, &cpu_reserve_head); /* Let's update the kernel priorities in the proper way */ ptr = cpu_reserve_head.next; done = 0; while (!done) { r = cpu_reserve_entry(ptr); if ((r->rsv->rsv_reserve_param.enf_mode == RSV_SOFT) || ((r->rsv->rsv_state & RSV_IS_DEPLETED) == 0)) { rsv->rsv_state &= ~RSV_IS_DEPLETED; rs_proc_list_condition_rs_apply(& (r->rsv->rsv_rs-> rs_proc_list), r->rsv->rsv_rs, cpu_reserve_sched, r); rsv->rsv_state |= RSV_IS_DEPLETED; } if (cpu_reserve_entry(ptr) == cpu) { done = 1; } ptr = ptr->next; } current->need_resched = 1; } #endif /* SUPER_CHARGED */ /* cancel tickets */ { cpu_reserve_t cpu = rsv->rsv_rsv; cpu->tickets.available_tickets = 0; } /* Notify the enforcement to process through a RT signal */ //rs_proc_list_apply(&rsv->rsv_rs->rs_proc_list, signal_tasks, 0); #ifdef SUPER_CHARGED if (cpu_reserves_scheduling_policy == EDF) { if (rsv->rsv_reserve_param.enf_mode == RSV_SOFT) { /* CBS!!! */ if (rsv->rsv_state & RSV_IS_RUNNING) { cpu_tick_data_t now; rk_rdtsc(&now); cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; cpu->cpu_period_used_ticks = 0; cpu_reserve_stop_account(rsv, &now); rsv->rsv_state &= ~RSV_IS_DEPLETED; cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; cpu->cpu_period_used_ticks = 0; ptr = cpu_reserve_head.next; } rsv->rsv_state &= ~RSV_IS_DEPLETED; } } #endif rs = rsv->rsv_rs; /* update the current cpu of the resource set */ { rk_reserve_t rk_resource_set_update_cpu(rk_resource_set_t); rk_resource_set_update_cpu(rs); } /* If this resource set is still eligible, * we can just update the scheduling parameters of all tasks bound * to this resource set using the new cpu reserve */ if (rs->rs_cpu) { rs_proc_list_condition_rs_apply(&rs->rs_proc_list, rs, cpu_reserve_sched, (cpu_reserve_t) (rs->rs_cpu-> rsv_rsv)); } /* This resource set is not eligible, each task that uses this resource * set needs to reschedule another resource set */ else { rs_proc_list_condition_rs_apply(&rs->rs_proc_list, rs, rk_resource_set_schedule, 0); } /* If there is an update of the current reserve of the current task, * adjust the accounting of the current resource set if there is * a change */ if ((expected_current!=(void *)-1) && (expected_current!=current)) { #ifdef APPLE_DEBUG_RK printk("Danger Interrupt (enforce -rsv (0x%x)) during scheduling: current (%d) but expect (%d) \n", rsv, current->pid, expected_current->pid); #endif /*APPLE_DEBUG_RK*/ current_critical = 1; } else { current_critical = 0; } if (current_critical) { extern void rk_resource_set_adjust_expect_accounting(void); rk_resource_set_adjust_expect_accounting(); } else { rk_resource_set_adjust_accounting(); } rk_spin_unlock(flags); } static void cpu_reserve_sleep_on(rk_reserve_t rsv) { #if 0 cpu_reserve_t cpu = rsv->rsv_rsv; // interruptible_sleep_on(&cpu->depleted_wait); list_entry(rsv->rsv_rs->rs_proc_list.next, struct rs_proc_list, rs_proc_list)->rs_proc_task->state = TASK_INTERRUPTIBLE; schedule(); #else /* RAJ_RK */ rs_proc_list_apply(&rsv->rsv_rs->rs_proc_list, cpu_reserve_sched_disable, 0); /* re-schedule */ schedule(); #endif /* RAJ_RK */ } /* * Start & Stop the account of CPU utilization. */ static void cpu_reserve_start_account(rk_reserve_t rsv) { cpu_reserve_t cpu = rsv->rsv_rsv; long long next; long long eligible_ticks; int no_more_eligible = 0; if (cpu->cpu_period_available_ticks < cpu->cpu_period_used_ticks) { cpu->cpu_period_used_ticks = cpu->cpu_period_available_ticks - DELAY; } next = cpu->cpu_period_available_ticks - cpu->cpu_period_used_ticks; #ifdef SUPER_CHARGED if ((cpu_reserves_scheduling_policy == EDF) && (rsv->rsv_reserve_param.enf_mode == RSV_SOFT)) { } else #endif { /* check the eligible_ticks */ cpu_tick_data_t now; rk_rdtsc(&now); eligible_ticks = cpu->cpu_eligible_deadline_ticks - now; if (eligible_ticks < next) { no_more_eligible = 1; next = eligible_ticks; } } switch (rsv->rsv_state) { case RSV_IS_NULL: printk ("cpu_reserve_start_account: rsv(0x%x) illegal state(NULL)\n", (int) rsv); case RSV_IS_STARTED: rsv->rsv_state |= RSV_IS_RUNNING; if (next > DELAY) { rk_enforce_timer_start(rsv, &next, &cpu->cpu_period_start_ticks); } else { if (!no_more_eligible) { /* Just to avoid useless warnings... */ #ifdef EXTRA_WARN printk("start_account with no time left, but not depleted?\n"); #endif } #ifdef EARLY_ENFORCE rsv->rsv_state |= RSV_IS_DEPLETED; /*should do enforcement */ cpu_reserve_enforce(rsv); #else next = DELAY; /* Very small value... */ rk_enforce_timer_start(rsv, &next, &cpu->cpu_period_start_ticks); #endif } break; case RSV_IS_RUNNING | RSV_IS_STARTED: /* must not be so */ case RSV_IS_RUNNING: /* must not be so */ printk ("cpu_reserve_start_account: rsv(0x%x) illegal state(RUNNING)\n", (int) rsv); if (next > 0) { rk_enforce_timer_start(rsv, &next, &cpu->cpu_period_start_ticks); } else { rsv->rsv_state |= RSV_IS_DEPLETED; rk_rdtsc(&cpu->cpu_period_start_ticks); } break; case RSV_IS_RUNNING | RSV_IS_DEPLETED: /* must not be so */ case RSV_IS_STARTED | RSV_IS_RUNNING | RSV_IS_DEPLETED: /* must not be so */ printk ("cpu_reserve_start_account: rsv(0x%x) illegal state(RUNNING|DEPLETED)\n", (int) rsv); break; default: /* unknown */ printk ("cpu_reserve_start_account: rsv(0x%x) unknown state(0x%x) next available(%lu)\n", (int) rsv, (int) rsv->rsv_state, (unsigned long) next); rsv->rsv_state = RSV_IS_RUNNING; if (next > 0) { rk_enforce_timer_start(rsv, &next, &cpu->cpu_period_start_ticks); } else { rsv->rsv_state |= RSV_IS_DEPLETED; rk_rdtsc(&cpu->cpu_period_start_ticks); } break; } } static inline void cpu_reserve_check_enforce(rk_reserve_t rsv, cpu_reserve_t cpu, cpu_tick_t now) { if (cpu->cpu_period_used_ticks >= cpu->cpu_period_available_ticks) { #ifdef DEBUG_RK printk ("cpu_reserve_check_enforce: enforce rsv(0x%x) used(%lu/%lu)\n", (int) rsv, (unsigned long) cpu->cpu_period_used_ticks, (unsigned long) cpu->cpu_period_available_ticks); #endif /* DEBUG_RK */ /* enforcing a reserve */ #ifdef EARLY_ENFORCE cpu_reserve_enforce(rsv); #else #ifdef EXTRA_WARN printk("Early enforcing disabled\n"); #endif #endif } #ifdef SUPER_CHARGED if ((cpu_reserves_scheduling_policy == EDF) && (rsv->rsv_reserve_param.enf_mode == RSV_SOFT)) { } else #endif /* If eligible? */ if (*now >= cpu->cpu_eligible_deadline_ticks) { #ifdef DEBUG_RK printk ("cpu_reserve_check_enforce: enforce rsv(0x%x) used(%lu/%lu) eligible(%lu) time(%lu)-eligible \n", (int) rsv, (unsigned long) cpu->cpu_period_used_ticks, (unsigned long) cpu->cpu_period_available_ticks, (unsigned long) cpu->cpu_eligible_deadline_ticks, (unsigned long) *now); #endif /* DEBUG_RK */ #ifdef EARLY_ENFORCING /* enforcing a reserve */ cpu_reserve_enforce(rsv); #else cpu->cpu_period_used_ticks = cpu->cpu_period_available_ticks - 1; #endif return; } } static void cpu_reserve_stop_account(rk_reserve_t rsv, cpu_tick_t now) { cpu_reserve_t cpu = rsv->rsv_rsv; cpu_reserve_summation_of_used_ticks(cpu, now); rk_enforce_timer_cancel(); if (rsv == rk_current_cpu_reserve) rk_current_cpu_reserve = NULL_RESERVE; switch (rsv->rsv_state) { case RSV_IS_RUNNING: case RSV_IS_STARTED | RSV_IS_RUNNING: /* Original... */ rsv->rsv_state &= ~RSV_IS_RUNNING; cpu_reserve_check_enforce(rsv, cpu, now); break; case RSV_IS_RUNNING | RSV_IS_DEPLETED: case RSV_IS_STARTED | RSV_IS_RUNNING | RSV_IS_DEPLETED: rsv->rsv_state &= ~RSV_IS_RUNNING; break; case RSV_IS_NULL: /* must not be so */ case RSV_IS_STARTED: /* must not be so */ printk("cpu_reserve_stop_account: rsv(0x%x) illegal state(NULL)\n", (int) rsv); cpu_reserve_check_enforce(rsv, cpu, now); break; case RSV_IS_DEPLETED: /* must not be so */ case RSV_IS_STARTED | RSV_IS_DEPLETED: /* must not be so */ printk ("cpu_reserve_stop_account: rsv(0x%x) illegal state(NULL|DEPLETED)\n", (int) rsv); break; default: /* unkown */ printk ("cpu_reserve_stop_account: rsv(0x%x) unknown state(0x%x))\n", (int) rsv, (int) rsv->rsv_state); rsv->rsv_state = RSV_IS_NULL; cpu_reserve_check_enforce(rsv, cpu, now); break; } } static void cpu_reserve_attach(rk_reserve_t rsv, struct rs_proc_list *rs_proc) { unsigned long flags; #ifdef CONFIG measure_reserv_attach_process(rsv, rs_proc->rs_proc_task->pid); #endif /* CONFIG */ #ifdef DEBUG_RK printk("(attach)"); #endif /* DEBUG_RK */ if (!cpu_reserve_eligible(rsv)) { /* something wrong */ rs_proc->rs_proc_task->rk_cannot_schedule = TRUE; printk("(depleted)"); cpu_reserve_enforce(rsv); return; } rk_spin_lock(flags); cpu_reserve_sched(rs_proc, (cpu_reserve_t) rsv->rsv_rsv); rk_spin_unlock(flags); } static void cpu_reserve_detach(rk_reserve_t rsv, struct rs_proc_list *rs_proc) { unsigned long flags; rk_spin_lock(flags); /* Avoid crashes when a RS is destroyed byt the timer is still active */ if (rs_proc->rs_proc_task->period_timer != NULL) { rs_proc->rs_proc_task->period_timer->tmr_rsv = NULL_RESERVE; } rk_spin_unlock(flags); #ifdef CONFIG measure_reserv_detach_process(rsv, rs_proc->rs_proc_task->pid); #endif /* CONFIG */ } static void cpu_reserve_update_ticket(rk_reserve_t rsv, unsigned long tickets) { cpu_tick_data_t now; cpu_reserve_t cpu = rsv->rsv_rsv; rk_rdtsc(&now); switch (cpu->cpu_res_attr.ticket_type) { case CONSTANT: /* If there is not enough tickets */ if (cpu->tickets.available_tickets < tickets) { /* Something wrong! */ printk("Someone is using tikcets over the quota \n"); cpu->tickets.available_tickets = 0; return; } /* Tickets are expired */ if (now > cpu->tickets.expiration) { printk("Tickets are expired, throw them away \n"); cpu->tickets.available_tickets = 0; return; } cpu->tickets.available_tickets -= tickets; break; default: /* Something wrong! */ printk("Someone is using tikcets w/o permission \n"); cpu->tickets.available_tickets = 0; break; } } static void cpu_reserve_ticket_query(rk_reserve_t rsv, unsigned long *tickets) { cpu_tick_data_t now; cpu_reserve_t cpu = rsv->rsv_rsv; rk_rdtsc(&now); switch (cpu->cpu_res_attr.ticket_type) { case CONSTANT: /* Tickets are expired */ if (now > cpu->tickets.expiration) { printk("Tickets are expired, throw them away \n"); cpu->tickets.available_tickets = 0; } *tickets = cpu->tickets.available_tickets; break; default: /* Something wrong! */ printk("Someone is using tikcets w/o permission \n"); *tickets = 0; break; } } static void cpu_reserve_wait_one_ticket(rk_reserve_t rsv) { cpu_tick_data_t now; // struct wait_queue wait = { current, NULL }; // Gaurav DECLARE_WAITQUEUE(wait, current); cpu_reserve_t cpu = rsv->rsv_rsv; rk_rdtsc(&now); if ((cpu->tickets.available_tickets) #ifdef CHECK_TICKET_EXPIRE && (now <= cpu->tickets.expiration) #endif /* CHECK_TICKET_EXPIRE */ ) { cpu->tickets.available_tickets--; return; } //add_wait_queue(&cpu->ticket_wait, &wait); //Gaurav __add_wait_queue(&cpu->ticket_wait, &wait); while (1) { current->state = TASK_INTERRUPTIBLE; rk_rdtsc(&now); if ((cpu->tickets.available_tickets) #ifdef CHECK_TICKET_EXPIRE && (now <= cpu->tickets.expiration) #endif /* CHECK_TICKET_EXPIRE */ ) { cpu->tickets.available_tickets--; break; } schedule(); } //remove_wait_queue(&cpu->ticket_wait, &wait); //Gaurav __remove_wait_queue(&cpu->ticket_wait, &wait); current->state = TASK_RUNNING; } /* * admission control for CPU reserves */ int admit_reserve_request(cpu_reserve_t cpu) { struct timespec completion_time, prev_completion_time; struct timespec result; cpu_reserve_t curr, r; int ceil_value; cpu_reserve_attr_t attr = &(cpu->cpu_res_attr); struct list_head *ptr, *p2; /* This are used by the EDF capacity-based guarantee */ cpu_capacity_t guarcap; cpu_capacity_quad_t qc, qt; #ifdef DEBUG_RK printk("admit_reserve_request: "); #endif /* DEBUG_RK */ guarcap = PERCENT2CAPACITY(0); /* the admission control policy for a reserve is as follows. * We check the completion times of the incoming reserve and ALL * lower priority reserves assuming that the reserve is admitted. * If the completion times of all these reserves are less than their * respective deadlines, then the incoming reserve can be admitted. */ #ifdef LOG_RESERVES if (log_messages) { log_start = clock_ttime(clockrt); } #endif /* LOG_RESERVES */ /* do basic checks quickly */ if (timespec_gt(attr->compute_time, attr->period) || timespec_gt(attr->compute_time, attr->deadline)) { #ifdef DEBUG_RK printk("false (0)\n"); #endif /* DEBUG_RK */ return FALSE; } /* perform the "completion time test" */ for (ptr = cpu_reserve_head.next; ptr != &cpu_reserve_head; ptr = ptr->next) { cpu_reserve_attr_t curr_attr; curr = cpu_reserve_entry(ptr); curr_attr = &(curr->cpu_res_attr); /* repeat for each reserve in the current set of reserves */ /* Optimization: skip reserves with shorter deadlines for * deadline-monotonic scheduling policy or with shorter periods for * rate-monotonic scheduling. */ #ifdef SUPER_CHARGED { int cont = FALSE; switch (cpu_reserves_scheduling_policy) { case RATE_MONOTONIC: if (timespec_lt(curr_attr->period, attr->period)) { /* shorter period reservation: must have been tested earlier */ cont = TRUE; } break; case DEADLINE_MONOTONIC: if (timespec_lt(curr_attr->deadline, attr->deadline)) { /* shorter deadline reservation: must have been tested earlier */ cont = TRUE; } break; case EDF: /* The EDF admission control uses the simple test Sum(Ci/Di) < 1 * Luca */ qc = curr_attr->compute_time.tv_sec; qc *= NANOSEC; qc += curr_attr->compute_time.tv_nsec; qt = curr_attr->period.tv_sec; qt *= NANOSEC; qt += curr_attr->period.tv_nsec; guarcap += CAPACITY_OF(qc, qt); if (guarcap > PERCENT2CAPACITY(100)) return FALSE; cont = TRUE; break; } if (cont) continue; } #else /* SUPER_CHARGED */ if (timespec_lt(curr_attr->period, attr->period)) { /* shorter period reservation: must have been tested earlier */ continue; } #endif /* SUPER_CHARGED */ timespec_zero(prev_completion_time); timespec_set(completion_time, curr_attr->compute_time); timespec_add(completion_time, curr_attr->blocking_time); /* calculate the worst-case completion time */ while (timespec_le(prev_completion_time, curr_attr->deadline) && timespec_lt(prev_completion_time, completion_time)) { timespec_set(prev_completion_time, completion_time); timespec_zero(completion_time); for (p2 = cpu_reserve_head.next; p2 != &cpu_reserve_head; p2 = p2->next) { cpu_reserve_attr_t r_attr; r = cpu_reserve_entry(p2); /* We compute preemption time from the HIGHER priority reserves and * any EQUAL priority reserves. This is necessary because the * deadlines can be different for reserves with the same period. */ if (r == curr) { /* self */ continue; } r_attr = &(r->cpu_res_attr); #ifdef SUPER_CHARGED { int done = FALSE; switch (cpu_reserves_scheduling_policy) { case RATE_MONOTONIC: if (timespec_gt(r_attr->period, curr_attr->period)) { done = TRUE; } break; case DEADLINE_MONOTONIC: if (timespec_gt (r_attr->deadline, curr_attr->deadline)) { /* we have found a reserve with a longer period/deadline and * therefore a lower priority, break from loop */ done = TRUE; } break; } if (done) break; } #else /* SUPER_CHARGED */ if (timespec_gt(r_attr->period, curr_attr->period)) break; #endif /* SUPER_CHARGED */ ceil_value = efficient_timespec_ceil(prev_completion_time, r_attr->period); result = timespec_mult(r_attr->compute_time, ceil_value); timespec_add(completion_time, result); } /* add computation time and blocking time of self */ timespec_add(completion_time, curr_attr->compute_time); timespec_add(completion_time, curr_attr->blocking_time); } /* end while */ if (timespec_gt(completion_time, curr_attr->period) || timespec_gt(completion_time, curr_attr->deadline)) { /* deadline already missed; return failure */ #ifdef DEBUG_RK printk("false\n"); #endif /* DEBUG_RK */ return FALSE; } } #ifdef LOG_RESERVES if (log_messages) { log_end = clock_ttime(clockrt); timespec_sub(log_end, log_start); sprintf(LINEA, " admission control %d %d \n", log_end.seconds, log_end.nanoseconds); kern_msg_log(LINEA); } #endif /* LOG_RESERVES */ /* everything seems fine */ #ifdef DEBUG_RK printk("true\n"); #endif /* DEBUG_RK */ return TRUE; } int cpu_reserve_delete(rk_resource_set_t rs) { rk_reserve_t rsv; cpu_reserve_t cpu; /* check validity of "rs" first */ if ((rs == NULL) || (!rk_valid_rset(rs))) return RK_ERROR; rsv = rs->rs_cpu; if (rsv == NULL) return RK_ERROR; /* get cpu reserve */ cpu = rsv->rsv_rsv; #ifdef DEBUG_RK printk("cpu_reserve_delete: cpu(0x%x)\n", (int) cpu); #endif /* DEBUG_RK */ /* destroy timer */ rk_replenish_timer_destroy(rsv); /* return capacity */ cpu_reserve_current_capacity -= cpu->cpu_capacity; if ((int) cpu_reserve_current_capacity < 0) { cpu_reserve_current_capacity = 0; } #ifdef CONFIG_MEASURE measure_endreserve(cpu); #endif /* CONFIG_MEASURE */ list_del(&cpu->cpu_link); INIT_LIST_HEAD(&cpu->cpu_link); /* for sure */ rsv->rsv_rsv = NULL_RESERVE; kfree(cpu); rk_reserve_destroy(rsv); return RK_SUCCESS; /* success */ } /* * Linux-specific */ #ifdef linux /* * Notify enforcements to tasks through the first Linux RT signal */ void signal_tasks(struct rs_proc_list *rs_proc, unsigned int arg) { struct siginfo info; struct task_struct *p; rk_resource_set_t rs; rk_reserve_t rsv; cpu_reserve_t cpu; struct timespec err; int l; p = rs_proc->rs_proc_task; rs = p->rk_resource_set; if (rs == NULL) { printk("signlal_tasks: NULL RS\n"); return; } rsv = rs->rs_cpu; if (rsv == NULL) { printk("signlal_tasks: NULL rs_cpu\n"); return; } cpu = rsv->rsv_rsv; if (cpu == NULL) { printk("signlal_tasks: NULL cpu\n"); return; } timespec_set(err, cpu->absdl); #ifdef DEBUG_RK_SIGNAL printk("lastdl %ld %ld\n", cpu->absdl.tv_sec, cpu->absdl.tv_nsec); printk("lastarrv %ld %ld\n", current->last_start.tv_sec, current->last_start.tv_nsec); #endif timespec_sub(err, current->last_start); l = timespec2micro(err); #ifdef DEBUG_RK_SIGNAL printk("Signaling task %d\n", p); #endif memset(&info, 0, sizeof(info)); info.si_signo = SIGRTMIN + 1 + ENFORCE_SIGNAL; /* info.si_signo = SIGRTMIN + 1; */ info.si_errno = 0; info.si_code = SI_KERNEL; info.si_pid = 0; info.si_uid = 0; info._sifields._rt._sigval.sival_int = l; send_sig_info(SIGRTMIN + 1 + ENFORCE_SIGNAL, &info, p); } /* * Linux proc file system interface */ asmlinkage int sys_rk_blocked(int pid) { struct task_struct *tsk = __rk_find_process_by_pid(pid); if (tsk != NULL) { #ifdef DEBUG_RK printk("rk_blocked: pid found cannot_sched = %d\n",tsk->rk_cannot_schedule); #endif return tsk->rk_cannot_schedule; } printk("rk_blocked: pid not found\n"); return -1; } asmlinkage rk_reserve_t sys_rk_cpu_reserve_create(rk_resource_set_t rs, cpu_reserve_attr_t cpu_attr) { cpu_reserve_attr_data_t local_attr; #ifdef DEBUG_RK printk("cpu_rsv_create: rs(0x%x)\n", (int) rs); #endif /* DEBUG_RK */ /* check region before access */ if ((!cpu_attr) || (verify_area(VERIFY_READ, cpu_attr, sizeof(cpu_reserve_attr_data_t)))) { return NULL_RESERVE; } if (copy_from_user(&local_attr, cpu_attr, sizeof(cpu_reserve_attr_data_t))) { return NULL_RESERVE; } return cpu_reserve_create(rs, &local_attr); } asmlinkage int sys_rk_cpu_reserve_ctl(rk_reserve_t rsv, cpu_reserve_attr_t cpu_attr) { cpu_reserve_attr_data_t local_attr; #ifdef DEBUG_RK printk("cpu_rsv_ctl: rsv(0x%x)\n", (int) rsv); #endif /* DEBUG_RK */ if (copy_from_user(&local_attr, cpu_attr, sizeof(cpu_reserve_attr_data_t))) { return -EFAULT; } return cpu_reserve_ctl(rsv, &local_attr); } asmlinkage int sys_rk_cpu_reserve_delete(rk_resource_set_t rs) { #ifdef DEBUG_RK printk("cpu_rsv_delete: rs(0x%x)\n", (int) rs); #endif /* DEBUG_RK */ return cpu_reserve_delete(rs); } asmlinkage int sys_rk_cpu_reserves_set_scheduling_policy(int policy) { #ifdef DEBUG_RK printk("cpu_rsv_set_sch: pol(0x%x)\n", (int) policy); #endif /* DEBUG_RK */ return rk_cpu_reserves_set_scheduling_policy(policy); } asmlinkage int sys_rk_cpu_reserves_get_scheduling_policy(void) { #ifdef DEBUG_RK printk("cpu_rsv_get_sch "); #endif /* DEBUG_RK */ return rk_cpu_reserves_get_scheduling_policy(); } asmlinkage int sys_rk_cpu_reserves_get_num(void) { #ifdef DEBUG_RK printk("cpu_rsv_get_num "); #endif /* DEBUG_RK */ return rk_cpu_reserves_get_num(); } asmlinkage int sys_rk_cpu_reserves_get_list(rk_reserve_t * rsv, int size) { cpu_reserve_t cpu; struct list_head *e; int local_count, i; #ifdef DEBUG_RK printk("cpu_rsv_get_list: rsv(0x%x) size %d\n", rsv, size); #endif /* DEBUG_RK */ local_count = rk_cpu_reserves_get_num() * sizeof(rk_reserve_t); if (size < local_count) return -EINVAL; if (verify_area(VERIFY_WRITE, rsv, local_count)) { return -EFAULT; } /* copy known cpu reserves to list */ for (e = cpu_reserve_head.next, i = 0; e != &cpu_reserve_head; e = e->next, i++) { cpu = cpu_reserve_entry(e); /* this must be changed for reserves other than CPU */ if (copy_to_user(&(rsv[i]), &(cpu->rsv), sizeof(rk_reserve_t))) { return -EFAULT; } } return rk_cpu_reserves_get_num(); } asmlinkage int sys_rk_cpu_reserve_get_attr(rk_reserve_t rsv, cpu_reserve_attr_t cpu_params) { cpu_reserve_t cpu; #ifdef DEBUG_RK printk("cpu_rsv_get_attr: rsv(0x%x)\n", rsv); #endif /* DEBUG_RK */ /* verify validity of reserve first */ if (!rk_valid_rsv(rsv)) return -EINVAL; /* check region before access */ cpu = rsv->rsv_rsv; if ((!cpu) || (verify_area(VERIFY_WRITE, cpu_params, sizeof(cpu_reserve_attr_data_t)))) { return -EFAULT; } if (copy_to_user(cpu_params, &(cpu->cpu_res_attr), sizeof(cpu_reserve_attr_data_t))) { return -EINVAL; } return RK_SUCCESS; } //Sourav asmlinkage int sys_rk_cpu_reserve_get_history(rk_reserve_t rsv, rk_reserve_history_t data) { return -EINVAL; } /* We will use priorities above 256 to ensure that other unreserved * Linux can be preempted automatically by reserved processes. */ /* XXX: should be (MAX_LINUX_PRIORITY+1) */ #define LINUX_REALTIME_PRIORITY 257 #define LINUX_TIMESHARE_PRIORITY 0 void cpu_reserve_setscheduler(struct task_struct *p, unsigned long policy, unsigned long rt_priority) { p->rk_cannot_schedule = FALSE; p->policy = policy; rt_adjbaseprio(p, policy, rt_priority); current->need_resched = 1; if (p->rt_priority == BLOCKING_PRIORITY) { p->rt_priority = 0; p->rk_cannot_schedule = TRUE; } } void cpu_reserve_set_base_sched_params(struct task_struct *tsk, cpu_reserve_t cpu) { /* for priority inheritance, set the base rs */ switch (cpu->scheduling_policy) { case SCHED_FIFO: cpu_reserve_setscheduler(tsk, SCHED_FIFO, cpu->cpu_priority_index + LINUX_REALTIME_PRIORITY); break; case SCHED_OTHER: cpu_reserve_setscheduler(tsk, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY); break; default: cpu_reserve_setscheduler(tsk, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY); } } /* To set the scheduling parameter of the task accoding * to the specified cpu reserve. * This cpu_reserve_sched functions must be called w/ the rk spinlock */ void cpu_reserve_sched(struct rs_proc_list *rs_proc, cpu_reserve_t cpu) { struct task_struct *p = rs_proc->rs_proc_task; p->rk_cannot_schedule = FALSE; switch (cpu->scheduling_policy) { case SCHED_FIFO: cpu_reserve_setscheduler(p, SCHED_FIFO, (LINUX_REALTIME_PRIORITY + cpu->cpu_priority_index)); break; case SCHED_OTHER: cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY); break; default: /* ?? */ cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY); } } /* The cpu_reserve_sched functions must be called with the rk spinlock */ void cpu_reserve_sched_blocking(struct rs_proc_list *rs_proc, unsigned int priority_index) { struct task_struct *p = rs_proc->rs_proc_task; #ifdef DEBUG_RK printk("cpu_reserve_sched_realtime\n"); #endif #ifdef DEBUG_RK printk("RT:%d (%d)", p->pid, priority_index); #endif /* DEBUG_RK */ /* enable scheduling of process */ p->rk_cannot_schedule = FALSE; cpu_reserve_setscheduler(p, SCHED_OTHER, BLOCKING_PRIORITY); } void cpu_reserve_sched_realtime(struct rs_proc_list *rs_proc, unsigned int priority_index) { struct task_struct *p = rs_proc->rs_proc_task; #ifdef DEBUG_RK printk("cpu_reserve_sched_realtime(%d)--> ", p->pid); #endif #ifdef DEBUG_RK printk("RT: %d\n", priority_index); #endif /* DEBUG_RK */ /* enable scheduling of process */ p->rk_cannot_schedule = FALSE; cpu_reserve_setscheduler(p, SCHED_FIFO, #ifdef linux (LINUX_REALTIME_PRIORITY + priority_index) #else REALTIME_PRIORITY #endif /* linux */ ); } void cpu_reserve_sched_timeshare(struct rs_proc_list *rs_proc, unsigned priority_index) { struct task_struct *p = rs_proc->rs_proc_task; #ifdef DEBUG_RK printk("cpu_reserve_sched_timeshare\n"); #endif /* enable scheduling of process */ p->rk_cannot_schedule = FALSE; cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY); } void cpu_reserve_sched_timeshare_self(void) { struct task_struct *p = current; if (p->policy & SCHED_FIFO) { #ifdef DEBUG_RK2 printk("cpu_reserve_sched_timeshare_self: pid(%d)\n", p->pid); #endif /* DEBUG_RK2 */ /* enable scheduling of process */ p->rk_cannot_schedule = FALSE; cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY); } } static int cpu_reserve_read_proc(rk_reserve_t rsv, char *buf) { char *p = buf; cpu_reserve_t cpu = rsv->rsv_rsv; unsigned long used_cpu_time; cpu_capacity_t ave, cur, prv; used_cpu_time = TICK2USEC(&cpu->cpu_period_used_ticks); cur = CAPACITY_OF(cpu->cpu_period_used_ticks, cpu->cpu_period_ticks); prv = CAPACITY_OF(cpu->cpu_period_prev_used_ticks, cpu->cpu_period_ticks); if (cpu->cpu_average.total_count) { ave = cpu->cpu_average.total_utils / cpu->cpu_average.total_count; } else { ave = cur; } /* 1st line: enf_mode, rep_mode */ p += sprintf(p, "%d %d\n", (int) rsv->rsv_reserve_param.enf_mode, (int) rsv->rsv_reserve_param.rep_mode); /* 2nd line: utilization statistics * reseved, previous, average, max, min */ p += sprintf(p, "%lu.%02lu %lu.%02lu %lu.%02lu %lu.%02lu %lu.%02lu\n", CAPACITY_INT(cpu->cpu_capacity), CAPACITY_FRAC(cpu->cpu_capacity), CAPACITY_INT(prv), CAPACITY_FRAC(prv), CAPACITY_INT(ave), CAPACITY_FRAC(ave), CAPACITY_INT(cpu->cpu_max_utilization), CAPACITY_FRAC(cpu->cpu_max_utilization), CAPACITY_INT(cpu->cpu_min_utilization), CAPACITY_FRAC(cpu->cpu_min_utilization)); /* 3rd line: current CPU usage * used available requested */ p += sprintf(p, "%lu %lu %lu\n", used_cpu_time, TICK2USEC(&cpu->cpu_period_available_ticks), TICK2USEC(&cpu->cpu_time_ticks)); /* 4th line: count of replenishment */ p += sprintf(p, "%lu\n", cpu->cpu_average.total_count); return (p - buf); } int cpu_reserve_status_proc(char *buf) { char *p = buf; /* cpu ticks per second, CPU capacity taken for reserves */ p += sprintf(p, "%lu %lu.%02lu\n", (unsigned long) rk_cpu_ticks_per_second, CAPACITY_INT(cpu_reserve_current_capacity), CAPACITY_FRAC(cpu_reserve_current_capacity)); return (p - buf); } #endif /* linux */ /* * Add specified reservation into reservation list in priority order. * Adjust reservation_priority index of list members accordingly. */ void priority_list_add(cpu_reserve_t cpu, struct list_head *head) { cpu_reserve_t r; int i, done = FALSE; struct list_head *ptr; if (head->next == head) { /* insert at the head */ cpu->cpu_priority_index = 0; list_add(&(cpu->cpu_link), head); return; } for (ptr = head->next; ptr != head; ptr = ptr->next) { r = cpu_reserve_entry(ptr); i = r->cpu_priority_index + 1; #ifdef SUPER_CHARGED switch (cpu_reserves_scheduling_policy) { case RATE_MONOTONIC: if (timespec_lt (cpu->cpu_res_attr.period, r->cpu_res_attr.period)) { done = TRUE; } break; case DEADLINE_MONOTONIC: if (timespec_lt (cpu->cpu_res_attr.deadline, r->cpu_res_attr.deadline)) { done = TRUE; } break; case EDF: /* EDF scheduler added: tasks are scheduled by absolute deadlines... * Luca */ if (timespec_lt(cpu->absdl, r->absdl)) { done = TRUE; } break; } #else /* SUPER_CHARGED */ if (timespec_lt(cpu->cpu_res_attr.period, r->cpu_res_attr.period)) { done = TRUE; } #endif /* SUPER_CHARGED */ if ((done) || (ptr == head)) { /* insert reservation here: subsequent indices will be fine as is! */ cpu->cpu_priority_index = i; list_add(&(cpu->cpu_link), ptr->prev); break; } else { /* this increments the priority index of this entry */ r->cpu_priority_index = i; } } if (!done) { cpu->cpu_priority_index = 0; /* Added by Luca */ list_add(&cpu->cpu_link, ptr->prev); } } int rk_cpu_reserves_get_num(void) { int count = 0; struct list_head *ptr; for (ptr = cpu_reserve_head.next; ptr != &cpu_reserve_head; ptr = ptr->next) { count++; } return count; } int rk_cpu_reserves_set_scheduling_policy(int policy) { #ifdef SUPER_CHARGED /* check for root privileges */ #ifdef linux if (current->flags | PF_SUPERPRIV) { return set_scheduling_policy(policy); } #else /* linux */ return set_scheduling_policy(policy); #endif /* linux */ #endif /* SUPER_CHARGED */ return RK_ERROR; } int set_scheduling_policy(int policy) { #ifdef SUPER_CHARGED /* 0 is a valid scheduling policy... Fixed by Luca */ if ((policy >= 0) && (policy < NUM_CPU_RESERVE_POLICIES)) { cpu_reserves_scheduling_policy = policy; return RK_SUCCESS; } #endif /* SUPER_CHARGED */ return -1; } int rk_cpu_reserves_get_scheduling_policy(void) { #ifdef SUPER_CHARGED return cpu_reserves_scheduling_policy; #endif /* SUPER_CHARGED */ return -1; } /* * Remove specified reservation from reservation list. * Adjust reservation_priority index of remaining list members accordingly. */ int priority_list_remove(cpu_reserve_t cpu, struct list_head *head) { cpu_reserve_t r; int i; struct list_head *ptr; if (head->next == head) { /* empty list */ return -1; } if (head->next == &(cpu->cpu_link)) { /* remove item to make empty list */ list_del(&(cpu->cpu_link)); return 0; } /* search through list to find item */ for (ptr = head->next; ptr != head; ptr = ptr->next) { r = cpu_reserve_entry(ptr); i = r->cpu_priority_index - 1; if (r == cpu) { /* delete reservation */ list_del(&(cpu->cpu_link)); /* we are done; subsequent entries already have valid priority indices */ return 0; } else { /* this decrements the priority index of this entry */ r->cpu_priority_index = i; } } /* we should not reach here, but just in case, we set the priority * index correctly. */ for (ptr = head->prev, i = 0; ptr != head; ptr = ptr->prev, i++) { r = cpu_reserve_entry(ptr); r->cpu_priority_index = i; } return (-1); } /* this ceiling computation works faster by assuming that the seconds * field is less than 1000 seconds, and by truncating the nanoseconds field. * If the seconds field is greater than 1000 seconds, a valid but VERY * inefficient response will result! */ int efficient_timespec_ceil(struct timespec dividend, struct timespec divider) { unsigned long dividend_microsecs, divider_microsecs; if ((divider.tv_sec == 0) && (divider.tv_nsec == 0)) { return -1; } if ((dividend.tv_sec >= 1000) || (divider.tv_sec >= 1000)) { /* be ready to pay a BIG penalty now! */ return (timespec_ceiling(dividend, divider)); } #define MICROSECS_PER_SECOND 1000000 /* truncate nanoseconds */ dividend_microsecs = (dividend.tv_sec % 1000) * MICROSECS_PER_SECOND + (dividend.tv_nsec / 1000); divider_microsecs = (divider.tv_sec % 1000) * MICROSECS_PER_SECOND + (divider.tv_nsec / 1000); return (ceiling(dividend_microsecs, divider_microsecs)); } int ceiling(unsigned long dividend, unsigned long divider) { int quotient; quotient = dividend / divider; if (divider * quotient == dividend) return (quotient); else return (++quotient); } int timespec_ceiling(struct timespec dividend, struct timespec divider) { int quotient = 1; struct timespec divider1; divider1 = divider; while (timespec_gt(dividend, divider1)) { timespec_add(divider1, divider); quotient++; } return (quotient); } struct timespec timespec_mult(struct timespec multiplicand, int multiplier) { struct timespec result; result.tv_sec = 0; result.tv_nsec = 0; do { timespec_add(result, multiplicand); } while (--multiplier); return (result); } static void check_enforce_reserve_type(cpu_reserve_attr_t cpu_attr) { rk_reserve_param_t rtype = &(cpu_attr->reserve_type); if (!((rtype->enf_mode == RSV_HARD) || (rtype->enf_mode == RSV_SOFT) || (rtype->enf_mode == RSV_FIRM))) { #ifdef DEBUG_RK printk("BAD enf value %d\n", rtype->enf_mode); #endif /* DEBUG_RK */ rtype->enf_mode = RSV_HARD; } if (!((rtype->rep_mode == RSV_HARD) || (rtype->rep_mode == RSV_SOFT) || (rtype->rep_mode == RSV_FIRM))) { #ifdef DEBUG_RK printk("BAD rep value %d\n", rtype->rep_mode); #endif /* DEBUG_RK */ rtype->rep_mode = RSV_HARD; } if (!((rtype->sch_mode == RSV_HARD) || (rtype->sch_mode == RSV_SOFT) || (rtype->sch_mode == RSV_FIRM))) { #ifdef DEBUG_RK printk("BAD sch value %d\n", rtype->sch_mode); #endif /* DEBUG_RK */ rtype->sch_mode = RSV_HARD; } } /* The cpu reserve for measurement only. * This is for default and idle resource sets. * No need to apply admission control to these reserves. * We apply the 100% capacity reserve. * The parameter duration is the measurement granularity we want * to keep track the cpu usage. */ rk_reserve_t cpu_reserve_dummy_create(rk_resource_set_t rs, time_t duration) { cpu_reserve_t cpu; cpu_capacity_quad_t qc, qt, qd; cpu_reserve_attr_t cpu_attr; rk_reserve_t rsv; /* create cpu reserve object */ cpu = malloc(sizeof(struct cpu_reserve)); bzero(cpu, sizeof(struct cpu_reserve)); cpu_attr = &(cpu->cpu_res_attr); cpu_attr->compute_time.tv_sec = duration; cpu_attr->compute_time.tv_nsec = 0; cpu_attr->period.tv_sec = duration; cpu_attr->period.tv_nsec = 0; cpu_attr->deadline.tv_sec = duration; cpu_attr->deadline.tv_nsec = 0; cpu_attr->blocking_time.tv_sec = 0; cpu_attr->blocking_time.tv_nsec = 0; /* start it, whenever the system is ready */ cpu_attr->start_time.tv_sec = 0; cpu_attr->start_time.tv_nsec = 10000000; cpu_attr->reserve_type.sch_mode = RSV_HARD; cpu_attr->reserve_type.enf_mode = RSV_HARD; cpu_attr->reserve_type.rep_mode = RSV_HARD; qc = cpu_attr->compute_time.tv_sec; qc *= NANOSEC; qc += cpu_attr->compute_time.tv_nsec; qt = cpu_attr->period.tv_sec; qt *= NANOSEC; qt += cpu_attr->period.tv_nsec; qd = cpu_attr->deadline.tv_sec; qd *= NANOSEC; qd += cpu_attr->deadline.tv_nsec; cpu->cpu_capacity = CAPACITY_OF(qc, qt); /* No need to add this to cpu_reserve_list for admission control */ INIT_LIST_HEAD(&cpu->cpu_link); /* for sure */ cpu->scheduling_policy = SCHED_OTHER; cpu->cpu_priority_index = LINUX_TIMESHARE_PRIORITY; /* calculate cpu ticks per capacity */ nanosec2tick(&qt, &cpu->cpu_period_ticks); nanosec2tick(&qc, &cpu->cpu_time_ticks); nanosec2tick(&qd, &cpu->cpu_deadline_ticks); cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; /* init waitqueue */ // init_waitqueue(&cpu->depleted_wait); //Gaurav init_waitqueue_head(&cpu->depleted_wait); /* check reservation type */ check_enforce_reserve_type(cpu_attr); /* create generic reserve object */ rsv = rk_reserve_create(rs, RSV_CPU); rsv->rsv_state = RSV_IS_NULL; rsv->rsv_rsv = cpu; rsv->rsv_ops = &cpu_reserve_ops; rsv->rsv_reserve_param = cpu_attr->reserve_type; cpu->rsv = rsv; /* create a timer for it */ /* XXX: we must later have one timer per resource instance in set */ rk_replenish_timer_create(rsv, cpu_attr->start_time); return rsv; } rk_reserve_t cpu_ceiling_reserve_create(rk_resource_set_t rs, cpu_reserve_attr_t par_cpu_attr, int priority_index) { cpu_reserve_t cpu; cpu_capacity_quad_t qc, qt, qd; cpu_reserve_attr_t cpu_attr; rk_reserve_t rsv; #ifdef PCP_DEBUG printk("RK ceiling_reserve_create\n"); #endif /* create cpu reserve object */ cpu = malloc(sizeof(struct cpu_reserve)); bzero(cpu, sizeof(struct cpu_reserve)); cpu_attr = &(cpu->cpu_res_attr); cpu_attr->compute_time.tv_sec = par_cpu_attr->compute_time.tv_sec; //duration; cpu_attr->compute_time.tv_nsec = par_cpu_attr->compute_time.tv_nsec; cpu_attr->period.tv_sec = par_cpu_attr->period.tv_sec; cpu_attr->period.tv_nsec = par_cpu_attr->period.tv_nsec; cpu_attr->deadline.tv_sec = par_cpu_attr->deadline.tv_sec; cpu_attr->deadline.tv_nsec = par_cpu_attr->deadline.tv_nsec; cpu_attr->blocking_time.tv_sec = par_cpu_attr->blocking_time.tv_sec; cpu_attr->blocking_time.tv_nsec = par_cpu_attr->blocking_time.tv_nsec; /* start it, whenever the system is ready */ cpu_attr->start_time.tv_sec = 0; cpu_attr->start_time.tv_nsec = 0; cpu_attr->reserve_type.sch_mode = RSV_HARD; cpu_attr->reserve_type.enf_mode = RSV_HARD; cpu_attr->reserve_type.rep_mode = RSV_HARD; qc = cpu_attr->compute_time.tv_sec; qc *= NANOSEC; qc += cpu_attr->compute_time.tv_nsec; qt = cpu_attr->period.tv_sec; qt *= NANOSEC; qt += cpu_attr->period.tv_nsec; qd = cpu_attr->deadline.tv_sec; qd *= NANOSEC; qd += cpu_attr->deadline.tv_nsec; #ifdef PCP_DEBUG printk("RK ceiling create capacity of t.s(%ld), t.ns(%ld), c.s(%ld), c.ns(%ld)\n", cpu_attr->period.tv_sec, cpu_attr->period.tv_nsec, cpu_attr->compute_time.tv_sec, cpu_attr->compute_time.tv_nsec); #endif cpu->cpu_capacity = CAPACITY_OF(qc, qt); /* No need to add this to cpu_reserve_list for admission control */ INIT_LIST_HEAD(&cpu->cpu_link); /* for sure */ cpu->scheduling_policy = SCHED_FIFO; cpu->cpu_priority_index = priority_index; /* calculate cpu ticks per capacity */ nanosec2tick(&qt, &cpu->cpu_period_ticks); nanosec2tick(&qc, &cpu->cpu_time_ticks); nanosec2tick(&qd, &cpu->cpu_deadline_ticks); cpu->cpu_period_available_ticks = cpu->cpu_time_ticks; /* init waitqueue */ // init_waitqueue(&cpu->depleted_wait); //Gaurav init_waitqueue_head(&cpu->depleted_wait); /* check reservation type */ check_enforce_reserve_type(cpu_attr); /* create generic reserve object */ rsv = rk_reserve_create(rs, RSV_CPU); rsv->rsv_state = RSV_IS_NULL; rsv->rsv_rsv = cpu; rsv->rsv_ops = &cpu_reserve_ops; rsv->rsv_reserve_param = cpu_attr->reserve_type; cpu->rsv = rsv; /* create a timer for it */ /* XXX: we must later have one timer per resource instance in set */ rk_replenish_timer_create(rsv, cpu_attr->start_time); return rsv; } /* Check the eligibility of the cpu reserve */ int cpu_reserve_eligible(rk_reserve_t rsv) { cpu_reserve_t cpu = rsv->rsv_rsv; cpu_tick_data_t now; #ifdef SUPER_CHARGED /* A CBS reserve is ALWAYS eligible... */ if ((cpu_reserves_scheduling_policy == EDF) && (rsv->rsv_reserve_param.enf_mode == RSV_SOFT)) { return 1; } #endif /* reserve's state needs not to be RSV_IS_NULL */ /* It needs to be in the duration of eligible reserve */ rk_rdtsc(&now); if ((!(rsv->rsv_state & RSV_IS_DEPLETED)) && (rsv->rsv_state & RSV_IS_STARTED) && (cpu->cpu_period_available_ticks > 0) && (now < cpu->cpu_eligible_deadline_ticks)) return 1; else return 0; } inline void cpu_reserve_sched_reserve_enable(struct rs_proc_list *rs_proc, cpu_reserve_t cpu) { /* set schedulable */ cpu_reserve_sched_enable(rs_proc, 0); /* set scheduling paramter */ #if 0 cpu_reserve_sched_realtime(rs_proc, cpu->cpu_priority_index); #else cpu_reserve_sched(rs_proc, cpu); #endif } inline void cpu_reserve_sched_reserve_disable(struct rs_proc_list *rs_proc) { cpu_reserve_sched_disable(rs_proc, 0); } void cpu_reserve_start(rk_reserve_t rsv, cpu_tick_t start_ticks) { cpu_tick_data_t now; cpu_reserve_t cpu = rsv->rsv_rsv; rsv->rsv_state |= RSV_IS_STARTED; cpu->cpu_eligible_deadline_ticks = *start_ticks + cpu->cpu_deadline_ticks; rk_rdtsc(&now); //printk("cpu reserve starting\n"); /* set up the next deadline of the eligible time */ cpu->cpu_eligible_deadline_ticks = now + cpu->cpu_deadline_ticks; } int rk_valid_rsv(rk_reserve_t rsv) { cpu_reserve_t p; struct list_head *e; for (e = cpu_reserve_head.next; e != &cpu_reserve_head; e = e->next) { p = cpu_reserve_entry(e); /* this must be changed for other CPU reserves */ if (p->rsv == rsv) { #ifdef DEBUG_RK printk("true\n"); #endif /* DEBUG_RK */ return TRUE; } } #ifdef DEBUG_RK printk("false\n"); #endif /* DEBUG_RK */ return FALSE; } asmlinkage rk_reserve_t sys_rk_cpu_reserve_dummy_create(rk_resource_set_t rs, time_t duration) { return cpu_reserve_dummy_create(rs, duration); }