diff options
| author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2015-08-09 07:18:48 -0400 |
|---|---|---|
| committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2017-05-26 17:12:28 -0400 |
| commit | 3baa55c19ffb567aa48568fa69dd17ad6f70d31d (patch) | |
| tree | 7e79fd398705929f2db40ba239895cc60762f61f /include/litmus/reservations | |
| parent | cbe61859a233702ed8e6723b3b133d1f2ae1ae2c (diff) | |
Add LITMUS^RT core implementation
This patch adds the core of LITMUS^RT:
- library functionality (heaps, rt_domain, prioritization, etc.)
- budget enforcement logic
- job management
- system call backends
- virtual devices (control page, etc.)
- scheduler plugin API (and dummy plugin)
This code compiles, but is not yet integrated with the rest of Linux.
Squashed changes:
LITMUS^RT Core: add get_current_budget() system call
Allow userspace to figure out the used-up and remaining budget
of a task.
Adds deadline field to control page and updates it when setting up jobs for release.
Adds control page deadline offset
ftdev: respect O_NONBLOCK flag in ftdev_read()
Don't block if userspace wants to go on doing something else.
Export job release time and job sequence number in ctrl page
Add alternate complete_job() default implementation
Let jobs sleep like regular Linux tasks by suspending and waking them
with a one-shot timer. Plugins can opt into using this implementation
instead of the classic complete_job() implementation (or custom
implementations).
Fix RCU locking in sys_get_rt_task_param()
sys_get_rt_task_param() is rarely used and apparently attracted some
bitrot.
Free before setting NULL to prevent memory leak
Add hrtimer_start_on() support
This patch replaces the previous implementation of hrtimer_start_on() by
now using smp_call_function_single_async() to arm hrtimers on remote
CPUs.
Expose LITMUS^RT system calls via control page ioctl()
Rationale: make LITMUS^RT ops available in a way that does not create
merge conflicts each time we rebase LITMUS^RT on top of a new kernel
version. This also helps with portability to different architectures,
as we no longer need to patch each architecture's syscall table.
Pick non-zero syscall ID start range
To avoid interfering with Linux's magic reserved IOCTL numbers
Don't preempt before time check in sleep_until_next_release()
Avoid preempting jobs that are about to go to sleep soon anyway.
LITMUS^RT proc: fix wrong memset()
TRACE(): add TRACE_WARN_ON() helper
Useful to replace BUG_ON() and WARN_ON() with a non-fatal
TRACE()-based equivalent.
Add void* plugin_state pointer to task_struct
LITMUS^RT: split task admission into two functions
Plugin interface: add fork_task() callback
LITMUS^RT: Enable plugins to permit RT tasks to fork
one-shot complete_job(): set completed flag
This could race with a SIGSTOP or some other forced suspension, but
we'll let plugins handle this, should they actually care.
FP: add list-based ready queue
LITMUS^RT core: add should_wait_for_stack() callback
Allow plugins to give up when waiting for a stack to become available.
LITMUS^RT core: add next_became_invalid() callback
LITMUS^RT core: add post-migration validation callback
LITMUS^RT core: be more careful when pull-migrating tasks
Close more race windows and give plugins a chance to validate
tasks after they have been migrated.
Add KConfig options for timer latency warnings
Add reservation creation API to plugin interface & syscalls
LITMUS^RT syscall: expose sys_reservation_create() via ioctl()
Add reservation configuration types to rt_param.h
Add basic generic reservation-based scheduling infrastructure
Switch to aligned quanta by default.
For first-time users, aligned quanta is likely what's expected.
LITMUS^RT core: keep track of time of last suspension
This information is needed to insert ST_COMPLETION records for
sporadic tasks.
add fields for clock_nanosleep() support
Need to communicate the intended wake-up time to the plugin wake-up handler.
LITMUS^RT core: add generic handler for sporadic job arrivals
In particular, check if a job arrival is triggered from a
clock_nanosleep() call.
add litmus->task_change_params() callback to plugin interface
Will be used by adaptive C-EDF.
Call litmus->task_change_params() from sys_set_rt_task_param()
Move trace point definition to litmus/litmus.c
If !CONFIG_SCHED_TASK_TRACE, but CONFIG_SCHED_LITMUS_TRACEPOINT, then
we still need to define the tracepoint structures.
This patch should be integrated with the earlier sched_task_trace.c
patches during one of the next major rebasing efforts.
LITMUS^RT scheduling class: mark enqueued task as present
Remove unistd_*.h
rebase fix: update to new hrtimer API
The new API is actually nicer and cleaner.
rebase fix: call lockdep_unpin_lock(&rq->lock, cookie)
The LITMUS^RT scheduling class should also do the LOCKDEP dance.
LITMUS^RT core: break out non-preemptive flag defs
Not every file including litmus.h needs to know this.
LITMUS^RT core: don't include debug_trace.h in litmus.h
Including debug_trace.h introduces the TRACE() macro, which causes
symbol clashes in some (rather obscure) drivers.
LITMUS^RT core: add litmus_preemption_in_progress flags
Used to communicate that a preemption is in progress. Set by the
scheduler; read by the plugins.
LITMUS^RT core: revise is_current_running() macro
Diffstat (limited to 'include/litmus/reservations')
| -rw-r--r-- | include/litmus/reservations/alloc.h | 15 | ||||
| -rw-r--r-- | include/litmus/reservations/budget-notifier.h | 50 | ||||
| -rw-r--r-- | include/litmus/reservations/polling.h | 19 | ||||
| -rw-r--r-- | include/litmus/reservations/reservation.h | 224 | ||||
| -rw-r--r-- | include/litmus/reservations/table-driven.h | 23 |
5 files changed, 331 insertions, 0 deletions
diff --git a/include/litmus/reservations/alloc.h b/include/litmus/reservations/alloc.h new file mode 100644 index 000000000000..b3471288c9f1 --- /dev/null +++ b/include/litmus/reservations/alloc.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef LITMUS_RESERVATIONS_ALLOC_H | ||
| 2 | #define LITMUS_RESERVATIONS_ALLOC_H | ||
| 3 | |||
| 4 | #include <litmus/reservations/reservation.h> | ||
| 5 | |||
| 6 | long alloc_polling_reservation( | ||
| 7 | int res_type, | ||
| 8 | struct reservation_config *config, | ||
| 9 | struct reservation **_res); | ||
| 10 | |||
| 11 | long alloc_table_driven_reservation( | ||
| 12 | struct reservation_config *config, | ||
| 13 | struct reservation **_res); | ||
| 14 | |||
| 15 | #endif \ No newline at end of file | ||
diff --git a/include/litmus/reservations/budget-notifier.h b/include/litmus/reservations/budget-notifier.h new file mode 100644 index 000000000000..d831fa9d5153 --- /dev/null +++ b/include/litmus/reservations/budget-notifier.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | #ifndef LITMUS_BUDGET_NOTIFIER_H | ||
| 2 | #define LITMUS_BUDGET_NOTIFIER_H | ||
| 3 | |||
| 4 | #include <linux/list.h> | ||
| 5 | #include <linux/spinlock.h> | ||
| 6 | |||
| 7 | struct budget_notifier; | ||
| 8 | |||
| 9 | typedef void (*budget_callback_t) ( | ||
| 10 | struct budget_notifier *bn | ||
| 11 | ); | ||
| 12 | |||
| 13 | struct budget_notifier { | ||
| 14 | struct list_head list; | ||
| 15 | budget_callback_t budget_exhausted; | ||
| 16 | budget_callback_t budget_replenished; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct budget_notifier_list { | ||
| 20 | struct list_head list; | ||
| 21 | raw_spinlock_t lock; | ||
| 22 | }; | ||
| 23 | |||
| 24 | void budget_notifier_list_init(struct budget_notifier_list* bnl); | ||
| 25 | |||
| 26 | static inline void budget_notifier_add( | ||
| 27 | struct budget_notifier_list *bnl, | ||
| 28 | struct budget_notifier *bn) | ||
| 29 | { | ||
| 30 | unsigned long flags; | ||
| 31 | |||
| 32 | raw_spin_lock_irqsave(&bnl->lock, flags); | ||
| 33 | list_add(&bn->list, &bnl->list); | ||
| 34 | raw_spin_unlock_irqrestore(&bnl->lock, flags); | ||
| 35 | } | ||
| 36 | |||
| 37 | static inline void budget_notifier_remove( | ||
| 38 | struct budget_notifier_list *bnl, | ||
| 39 | struct budget_notifier *bn) | ||
| 40 | { | ||
| 41 | unsigned long flags; | ||
| 42 | |||
| 43 | raw_spin_lock_irqsave(&bnl->lock, flags); | ||
| 44 | list_del(&bn->list); | ||
| 45 | raw_spin_unlock_irqrestore(&bnl->lock, flags); | ||
| 46 | } | ||
| 47 | |||
| 48 | void budget_notifiers_fire(struct budget_notifier_list *bnl, bool replenished); | ||
| 49 | |||
| 50 | #endif | ||
diff --git a/include/litmus/reservations/polling.h b/include/litmus/reservations/polling.h new file mode 100644 index 000000000000..230e12b1088a --- /dev/null +++ b/include/litmus/reservations/polling.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #ifndef LITMUS_POLLING_RESERVATIONS_H | ||
| 2 | #define LITMUS_POLLING_RESERVATIONS_H | ||
| 3 | |||
| 4 | #include <litmus/reservations/reservation.h> | ||
| 5 | |||
| 6 | struct polling_reservation { | ||
| 7 | /* extend basic reservation */ | ||
| 8 | struct reservation res; | ||
| 9 | |||
| 10 | lt_t max_budget; | ||
| 11 | lt_t period; | ||
| 12 | lt_t deadline; | ||
| 13 | lt_t offset; | ||
| 14 | }; | ||
| 15 | |||
| 16 | void polling_reservation_init(struct polling_reservation *pres, int use_edf_prio, | ||
| 17 | int use_periodic_polling, lt_t budget, lt_t period, lt_t deadline, lt_t offset); | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/include/litmus/reservations/reservation.h b/include/litmus/reservations/reservation.h new file mode 100644 index 000000000000..1752dac4e698 --- /dev/null +++ b/include/litmus/reservations/reservation.h | |||
| @@ -0,0 +1,224 @@ | |||
| 1 | #ifndef LITMUS_RESERVATION_H | ||
| 2 | #define LITMUS_RESERVATION_H | ||
| 3 | |||
| 4 | #include <linux/list.h> | ||
| 5 | #include <linux/hrtimer.h> | ||
| 6 | |||
| 7 | #include <litmus/debug_trace.h> | ||
| 8 | #include <litmus/reservations/budget-notifier.h> | ||
| 9 | |||
| 10 | struct reservation_client; | ||
| 11 | struct reservation_environment; | ||
| 12 | struct reservation; | ||
| 13 | |||
| 14 | typedef enum { | ||
| 15 | /* reservation has no clients, is not consuming budget */ | ||
| 16 | RESERVATION_INACTIVE = 0, | ||
| 17 | |||
| 18 | /* reservation has clients, consumes budget when scheduled */ | ||
| 19 | RESERVATION_ACTIVE, | ||
| 20 | |||
| 21 | /* reservation has no clients, but may be consuming budget */ | ||
| 22 | RESERVATION_ACTIVE_IDLE, | ||
| 23 | |||
| 24 | /* Reservation has no budget and waits for | ||
| 25 | * replenishment. May or may not have clients. */ | ||
| 26 | RESERVATION_DEPLETED, | ||
| 27 | } reservation_state_t; | ||
| 28 | |||
| 29 | |||
| 30 | /* ************************************************************************** */ | ||
| 31 | |||
| 32 | /* Select which task to dispatch. If NULL is returned, it means there is nothing | ||
| 33 | * to schedule right now and background work can be scheduled. */ | ||
| 34 | typedef struct task_struct * (*dispatch_t) ( | ||
| 35 | struct reservation_client *client | ||
| 36 | ); | ||
| 37 | |||
| 38 | /* Something that can be managed in a reservation and that can yield | ||
| 39 | * a process for dispatching. Contains a pointer to the reservation | ||
| 40 | * to which it "belongs". */ | ||
| 41 | struct reservation_client { | ||
| 42 | struct list_head list; | ||
| 43 | struct reservation* reservation; | ||
| 44 | dispatch_t dispatch; | ||
| 45 | }; | ||
| 46 | |||
| 47 | |||
| 48 | /* ************************************************************************** */ | ||
| 49 | |||
| 50 | /* Called by reservations to request state change. */ | ||
| 51 | typedef void (*reservation_change_state_t) ( | ||
| 52 | struct reservation_environment* env, | ||
| 53 | struct reservation *res, | ||
| 54 | reservation_state_t new_state | ||
| 55 | ); | ||
| 56 | |||
| 57 | /* Called by reservations to request replenishment while not DEPLETED. | ||
| 58 | * Useful for soft reservations that remain ACTIVE with lower priority. */ | ||
| 59 | typedef void (*request_replenishment_t)( | ||
| 60 | struct reservation_environment* env, | ||
| 61 | struct reservation *res | ||
| 62 | ); | ||
| 63 | |||
| 64 | /* The framework within wich reservations operate. */ | ||
| 65 | struct reservation_environment { | ||
| 66 | lt_t time_zero; | ||
| 67 | lt_t current_time; | ||
| 68 | |||
| 69 | /* services invoked by reservations */ | ||
| 70 | reservation_change_state_t change_state; | ||
| 71 | request_replenishment_t request_replenishment; | ||
| 72 | }; | ||
| 73 | |||
| 74 | /* ************************************************************************** */ | ||
| 75 | |||
| 76 | /* A new client is added or an existing client resumes. */ | ||
| 77 | typedef void (*client_arrives_t) ( | ||
| 78 | struct reservation *reservation, | ||
| 79 | struct reservation_client *client | ||
| 80 | ); | ||
| 81 | |||
| 82 | /* A client suspends or terminates. */ | ||
| 83 | typedef void (*client_departs_t) ( | ||
| 84 | struct reservation *reservation, | ||
| 85 | struct reservation_client *client, | ||
| 86 | int did_signal_job_completion | ||
| 87 | ); | ||
| 88 | |||
| 89 | /* A previously requested replenishment has occurred. */ | ||
| 90 | typedef void (*on_replenishment_timer_t) ( | ||
| 91 | struct reservation *reservation | ||
| 92 | ); | ||
| 93 | |||
| 94 | /* Update the reservation's budget to reflect execution or idling. */ | ||
| 95 | typedef void (*drain_budget_t) ( | ||
| 96 | struct reservation *reservation, | ||
| 97 | lt_t how_much | ||
| 98 | ); | ||
| 99 | |||
| 100 | /* Select a ready task from one of the clients for scheduling. */ | ||
| 101 | typedef struct task_struct* (*dispatch_client_t) ( | ||
| 102 | struct reservation *reservation, | ||
| 103 | lt_t *time_slice /* May be used to force rescheduling after | ||
| 104 | some amount of time. 0 => no limit */ | ||
| 105 | ); | ||
| 106 | |||
| 107 | /* Destructor: called before scheduler is deactivated. */ | ||
| 108 | typedef void (*shutdown_t)(struct reservation *reservation); | ||
| 109 | |||
| 110 | struct reservation_ops { | ||
| 111 | dispatch_client_t dispatch_client; | ||
| 112 | |||
| 113 | client_arrives_t client_arrives; | ||
| 114 | client_departs_t client_departs; | ||
| 115 | |||
| 116 | on_replenishment_timer_t replenish; | ||
| 117 | drain_budget_t drain_budget; | ||
| 118 | |||
| 119 | shutdown_t shutdown; | ||
| 120 | }; | ||
| 121 | |||
| 122 | #define RESERVATION_BACKGROUND_PRIORITY ULLONG_MAX | ||
| 123 | |||
| 124 | struct reservation { | ||
| 125 | /* used to queue in environment */ | ||
| 126 | struct list_head list; | ||
| 127 | struct list_head replenish_list; | ||
| 128 | |||
| 129 | reservation_state_t state; | ||
| 130 | unsigned int id; | ||
| 131 | unsigned int kind; | ||
| 132 | |||
| 133 | /* exact meaning defined by impl. */ | ||
| 134 | lt_t priority; | ||
| 135 | lt_t cur_budget; | ||
| 136 | lt_t next_replenishment; | ||
| 137 | |||
| 138 | /* budget stats */ | ||
| 139 | lt_t budget_consumed; /* how much budget consumed in this allocation cycle? */ | ||
| 140 | lt_t budget_consumed_total; | ||
| 141 | |||
| 142 | /* list of registered budget callbacks */ | ||
| 143 | struct budget_notifier_list budget_notifiers; | ||
| 144 | |||
| 145 | /* for memory reclamation purposes */ | ||
| 146 | struct list_head all_list; | ||
| 147 | |||
| 148 | /* interaction with framework */ | ||
| 149 | struct reservation_environment *env; | ||
| 150 | struct reservation_ops *ops; | ||
| 151 | |||
| 152 | struct list_head clients; | ||
| 153 | }; | ||
| 154 | |||
| 155 | void reservation_init(struct reservation *res); | ||
| 156 | |||
| 157 | /* Default implementations */ | ||
| 158 | |||
| 159 | /* simply select the first client in the list, set *for_at_most to zero */ | ||
| 160 | struct task_struct* default_dispatch_client( | ||
| 161 | struct reservation *res, | ||
| 162 | lt_t *for_at_most | ||
| 163 | ); | ||
| 164 | |||
| 165 | /* drain budget at linear rate, enter DEPLETED state when budget used up */ | ||
| 166 | void common_drain_budget(struct reservation *res, lt_t how_much); | ||
| 167 | |||
| 168 | /* "connector" reservation client to hook up tasks with reservations */ | ||
| 169 | struct task_client { | ||
| 170 | struct reservation_client client; | ||
| 171 | struct task_struct *task; | ||
| 172 | }; | ||
| 173 | |||
| 174 | void task_client_init(struct task_client *tc, struct task_struct *task, | ||
| 175 | struct reservation *reservation); | ||
| 176 | |||
| 177 | #define SUP_RESCHEDULE_NOW (0) | ||
| 178 | #define SUP_NO_SCHEDULER_UPDATE (ULLONG_MAX) | ||
| 179 | |||
| 180 | /* A simple uniprocessor (SUP) flat (i.e., non-hierarchical) reservation | ||
| 181 | * environment. | ||
| 182 | */ | ||
| 183 | struct sup_reservation_environment { | ||
| 184 | struct reservation_environment env; | ||
| 185 | |||
| 186 | /* ordered by priority */ | ||
| 187 | struct list_head active_reservations; | ||
| 188 | |||
| 189 | /* ordered by next_replenishment */ | ||
| 190 | struct list_head depleted_reservations; | ||
| 191 | |||
| 192 | /* unordered */ | ||
| 193 | struct list_head inactive_reservations; | ||
| 194 | |||
| 195 | /* list of all reservations */ | ||
| 196 | struct list_head all_reservations; | ||
| 197 | |||
| 198 | /* - SUP_RESCHEDULE_NOW means call sup_dispatch() now | ||
| 199 | * - SUP_NO_SCHEDULER_UPDATE means nothing to do | ||
| 200 | * any other value means program a timer for the given time | ||
| 201 | */ | ||
| 202 | lt_t next_scheduler_update; | ||
| 203 | /* set to true if a call to sup_dispatch() is imminent */ | ||
| 204 | bool will_schedule; | ||
| 205 | }; | ||
| 206 | |||
| 207 | /* Contract: | ||
| 208 | * - before calling into sup_ code, or any reservation methods, | ||
| 209 | * update the time with sup_update_time(); and | ||
| 210 | * - after calling into sup_ code, or any reservation methods, | ||
| 211 | * check next_scheduler_update and program timer or trigger | ||
| 212 | * scheduler invocation accordingly. | ||
| 213 | */ | ||
| 214 | |||
| 215 | void sup_init(struct sup_reservation_environment* sup_env); | ||
| 216 | void sup_add_new_reservation(struct sup_reservation_environment* sup_env, | ||
| 217 | struct reservation* new_res); | ||
| 218 | void sup_update_time(struct sup_reservation_environment* sup_env, lt_t now); | ||
| 219 | struct task_struct* sup_dispatch(struct sup_reservation_environment* sup_env); | ||
| 220 | |||
| 221 | struct reservation* sup_find_by_id(struct sup_reservation_environment* sup_env, | ||
| 222 | unsigned int id); | ||
| 223 | |||
| 224 | #endif | ||
diff --git a/include/litmus/reservations/table-driven.h b/include/litmus/reservations/table-driven.h new file mode 100644 index 000000000000..b6302a2f200d --- /dev/null +++ b/include/litmus/reservations/table-driven.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #ifndef LITMUS_RESERVATIONS_TABLE_DRIVEN_H | ||
| 2 | #define LITMUS_RESERVATIONS_TABLE_DRIVEN_H | ||
| 3 | |||
| 4 | #include <litmus/reservations/reservation.h> | ||
| 5 | |||
| 6 | struct table_driven_reservation { | ||
| 7 | /* extend basic reservation */ | ||
| 8 | struct reservation res; | ||
| 9 | |||
| 10 | lt_t major_cycle; | ||
| 11 | unsigned int next_interval; | ||
| 12 | unsigned int num_intervals; | ||
| 13 | struct lt_interval *intervals; | ||
| 14 | |||
| 15 | /* info about current scheduling slot */ | ||
| 16 | struct lt_interval cur_interval; | ||
| 17 | lt_t major_cycle_start; | ||
| 18 | }; | ||
| 19 | |||
| 20 | void table_driven_reservation_init(struct table_driven_reservation *tdres, | ||
| 21 | lt_t major_cycle, struct lt_interval *intervals, unsigned int num_intervals); | ||
| 22 | |||
| 23 | #endif | ||
