aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2011-06-02 16:06:05 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2011-06-02 16:06:05 -0400
commit3d5537c160c1484e8d562b9828baf679cc53f67a (patch)
treeb595364f1b0f94ac2426c8315bc5967debc7bbb0 /include
parent7d754596756240fa918b94cd0c3011c77a638987 (diff)
Full patch for klitirqd with Nvidia GPU support.
Diffstat (limited to 'include')
-rw-r--r--include/linux/completion.h1
-rw-r--r--include/linux/interrupt.h9
-rw-r--r--include/linux/mutex.h10
-rw-r--r--include/linux/semaphore.h9
-rw-r--r--include/linux/workqueue.h18
-rw-r--r--include/litmus/affinity.h78
-rw-r--r--include/litmus/fdso.h6
-rw-r--r--include/litmus/litmus.h1
-rw-r--r--include/litmus/litmus_softirq.h199
-rw-r--r--include/litmus/nvidia_info.h37
-rw-r--r--include/litmus/preempt.h1
-rw-r--r--include/litmus/rt_param.h44
-rw-r--r--include/litmus/sched_plugin.h22
-rw-r--r--include/litmus/sched_trace.h174
-rw-r--r--include/litmus/sched_trace_external.h42
-rw-r--r--include/litmus/unistd_32.h3
-rw-r--r--include/litmus/unistd_64.h5
17 files changed, 633 insertions, 26 deletions
diff --git a/include/linux/completion.h b/include/linux/completion.h
index c63950e8a863..3ce20dd3086e 100644
--- a/include/linux/completion.h
+++ b/include/linux/completion.h
@@ -76,6 +76,7 @@ static inline void init_completion(struct completion *x)
76 init_waitqueue_head(&x->wait); 76 init_waitqueue_head(&x->wait);
77} 77}
78 78
79extern void __wait_for_completion_locked(struct completion *);
79extern void wait_for_completion(struct completion *); 80extern void wait_for_completion(struct completion *);
80extern int wait_for_completion_interruptible(struct completion *x); 81extern int wait_for_completion_interruptible(struct completion *x);
81extern int wait_for_completion_killable(struct completion *x); 82extern int wait_for_completion_killable(struct completion *x);
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index a0384a4d1e6f..5d22f5342376 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -459,6 +459,10 @@ struct tasklet_struct
459 atomic_t count; 459 atomic_t count;
460 void (*func)(unsigned long); 460 void (*func)(unsigned long);
461 unsigned long data; 461 unsigned long data;
462
463#ifdef CONFIG_LITMUS_SOFTIRQD
464 struct task_struct *owner;
465#endif
462}; 466};
463 467
464#define DECLARE_TASKLET(name, func, data) \ 468#define DECLARE_TASKLET(name, func, data) \
@@ -496,6 +500,7 @@ static inline void tasklet_unlock_wait(struct tasklet_struct *t)
496#define tasklet_unlock(t) do { } while (0) 500#define tasklet_unlock(t) do { } while (0)
497#endif 501#endif
498 502
503extern void ___tasklet_schedule(struct tasklet_struct *t);
499extern void __tasklet_schedule(struct tasklet_struct *t); 504extern void __tasklet_schedule(struct tasklet_struct *t);
500 505
501static inline void tasklet_schedule(struct tasklet_struct *t) 506static inline void tasklet_schedule(struct tasklet_struct *t)
@@ -504,6 +509,7 @@ static inline void tasklet_schedule(struct tasklet_struct *t)
504 __tasklet_schedule(t); 509 __tasklet_schedule(t);
505} 510}
506 511
512extern void ___tasklet_hi_schedule(struct tasklet_struct *t);
507extern void __tasklet_hi_schedule(struct tasklet_struct *t); 513extern void __tasklet_hi_schedule(struct tasklet_struct *t);
508 514
509static inline void tasklet_hi_schedule(struct tasklet_struct *t) 515static inline void tasklet_hi_schedule(struct tasklet_struct *t)
@@ -512,6 +518,7 @@ static inline void tasklet_hi_schedule(struct tasklet_struct *t)
512 __tasklet_hi_schedule(t); 518 __tasklet_hi_schedule(t);
513} 519}
514 520
521extern void ___tasklet_hi_schedule_first(struct tasklet_struct *t);
515extern void __tasklet_hi_schedule_first(struct tasklet_struct *t); 522extern void __tasklet_hi_schedule_first(struct tasklet_struct *t);
516 523
517/* 524/*
@@ -541,7 +548,7 @@ static inline void tasklet_disable(struct tasklet_struct *t)
541} 548}
542 549
543static inline void tasklet_enable(struct tasklet_struct *t) 550static inline void tasklet_enable(struct tasklet_struct *t)
544{ 551{
545 smp_mb__before_atomic_dec(); 552 smp_mb__before_atomic_dec();
546 atomic_dec(&t->count); 553 atomic_dec(&t->count);
547} 554}
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index f363bc8fdc74..9f3199571994 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -126,6 +126,15 @@ static inline int mutex_is_locked(struct mutex *lock)
126 return atomic_read(&lock->count) != 1; 126 return atomic_read(&lock->count) != 1;
127} 127}
128 128
129/* return non-zero to abort. only pre-side-effects may abort */
130typedef int (*side_effect_t)(unsigned long);
131extern void mutex_lock_sfx(struct mutex *lock,
132 side_effect_t pre, unsigned long pre_arg,
133 side_effect_t post, unsigned long post_arg);
134extern void mutex_unlock_sfx(struct mutex *lock,
135 side_effect_t pre, unsigned long pre_arg,
136 side_effect_t post, unsigned long post_arg);
137
129/* 138/*
130 * See kernel/mutex.c for detailed documentation of these APIs. 139 * See kernel/mutex.c for detailed documentation of these APIs.
131 * Also see Documentation/mutex-design.txt. 140 * Also see Documentation/mutex-design.txt.
@@ -145,6 +154,7 @@ extern void mutex_lock(struct mutex *lock);
145extern int __must_check mutex_lock_interruptible(struct mutex *lock); 154extern int __must_check mutex_lock_interruptible(struct mutex *lock);
146extern int __must_check mutex_lock_killable(struct mutex *lock); 155extern int __must_check mutex_lock_killable(struct mutex *lock);
147 156
157
148# define mutex_lock_nested(lock, subclass) mutex_lock(lock) 158# define mutex_lock_nested(lock, subclass) mutex_lock(lock)
149# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock) 159# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
150# define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock) 160# define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock)
diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h
index 5310d27abd2a..69e3f57661ec 100644
--- a/include/linux/semaphore.h
+++ b/include/linux/semaphore.h
@@ -49,4 +49,13 @@ extern int __must_check down_trylock(struct semaphore *sem);
49extern int __must_check down_timeout(struct semaphore *sem, long jiffies); 49extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
50extern void up(struct semaphore *sem); 50extern void up(struct semaphore *sem);
51 51
52extern void __down(struct semaphore *sem);
53extern void __up(struct semaphore *sem);
54
55struct semaphore_waiter {
56 struct list_head list;
57 struct task_struct *task;
58 int up;
59};
60
52#endif /* __LINUX_SEMAPHORE_H */ 61#endif /* __LINUX_SEMAPHORE_H */
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 25e02c941bac..5fecfb375eeb 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -83,6 +83,9 @@ struct work_struct {
83#ifdef CONFIG_LOCKDEP 83#ifdef CONFIG_LOCKDEP
84 struct lockdep_map lockdep_map; 84 struct lockdep_map lockdep_map;
85#endif 85#endif
86#ifdef CONFIG_LITMUS_SOFTIRQD
87 struct task_struct *owner;
88#endif
86}; 89};
87 90
88#define WORK_DATA_INIT() ATOMIC_LONG_INIT(WORK_STRUCT_NO_CPU) 91#define WORK_DATA_INIT() ATOMIC_LONG_INIT(WORK_STRUCT_NO_CPU)
@@ -115,11 +118,25 @@ struct execute_work {
115#define __WORK_INIT_LOCKDEP_MAP(n, k) 118#define __WORK_INIT_LOCKDEP_MAP(n, k)
116#endif 119#endif
117 120
121#ifdef CONFIG_LITMUS_SOFTIRQD
122#define __WORK_INIT_OWNER() \
123 .owner = NULL,
124
125#define PREPARE_OWNER(_work, _owner) \
126 do { \
127 (_work)->owner = (_owner); \
128 } while(0)
129#else
130#define __WORK_INIT_OWNER()
131#define PREPARE_OWNER(_work, _owner)
132#endif
133
118#define __WORK_INITIALIZER(n, f) { \ 134#define __WORK_INITIALIZER(n, f) { \
119 .data = WORK_DATA_STATIC_INIT(), \ 135 .data = WORK_DATA_STATIC_INIT(), \
120 .entry = { &(n).entry, &(n).entry }, \ 136 .entry = { &(n).entry, &(n).entry }, \
121 .func = (f), \ 137 .func = (f), \
122 __WORK_INIT_LOCKDEP_MAP(#n, &(n)) \ 138 __WORK_INIT_LOCKDEP_MAP(#n, &(n)) \
139 __WORK_INIT_OWNER() \
123 } 140 }
124 141
125#define __DELAYED_WORK_INITIALIZER(n, f) { \ 142#define __DELAYED_WORK_INITIALIZER(n, f) { \
@@ -327,6 +344,7 @@ extern void flush_workqueue(struct workqueue_struct *wq);
327extern void flush_scheduled_work(void); 344extern void flush_scheduled_work(void);
328extern void flush_delayed_work(struct delayed_work *work); 345extern void flush_delayed_work(struct delayed_work *work);
329 346
347extern int __schedule_work(struct work_struct *work);
330extern int schedule_work(struct work_struct *work); 348extern int schedule_work(struct work_struct *work);
331extern int schedule_work_on(int cpu, struct work_struct *work); 349extern int schedule_work_on(int cpu, struct work_struct *work);
332extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay); 350extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
diff --git a/include/litmus/affinity.h b/include/litmus/affinity.h
new file mode 100644
index 000000000000..877b4099c6e2
--- /dev/null
+++ b/include/litmus/affinity.h
@@ -0,0 +1,78 @@
1#ifndef __LITMUS_AFFINITY_H
2#define __LITMUS_AFFINITY_H
3
4#include <linux/cpumask.h>
5
6/*
7 L1 (instr) = depth 0
8 L1 (data) = depth 1
9 L2 = depth 2
10 L3 = depth 3
11 */
12#define NUM_CACHE_LEVELS 4
13
14struct neighborhood
15{
16 unsigned int size[NUM_CACHE_LEVELS];
17 cpumask_var_t neighbors[NUM_CACHE_LEVELS];
18};
19
20/* topology info is stored redundently in a big array for fast lookups */
21extern struct neighborhood neigh_info[NR_CPUS];
22
23void init_topology(void); /* called by Litmus module's _init_litmus() */
24
25/* Works like:
26void get_nearest_available_cpu(cpu_entry_t* nearest, cpu_entry_t* start, cpu_entry_t* entries, int release_master)
27
28Set release_master = -1 for no RM.
29 */
30#define get_nearest_available_cpu(nearest, start, entries, release_master) \
31{ \
32 (nearest) = NULL; \
33 if(!(start)->linked) \
34 { \
35 (nearest) = (start); \
36 } \
37 else \
38 { \
39 int __level; \
40 int __cpu; \
41 struct neighborhood* __neighbors = &neigh_info[(start)->cpu]; \
42 \
43 for(__level = 0; (__level < NUM_CACHE_LEVELS) && !(nearest); ++__level) \
44 { \
45 if(__neighbors->size[__level] > 1) \
46 { \
47 for_each_cpu(__cpu, __neighbors->neighbors[__level]) \
48 { \
49 if(__cpu != (release_master)) \
50 { \
51 cpu_entry_t* __entry = &per_cpu((entries), __cpu); \
52 if(!__entry->linked) \
53 { \
54 (nearest) = __entry; \
55 break; \
56 } \
57 } \
58 } \
59 } \
60 else if(__neighbors->size[__level] == 0) \
61 { \
62 break; \
63 } \
64 } \
65 } \
66 \
67 if((nearest)) \
68 { \
69 TRACE("P%d is closest available CPU to P%d\n", (nearest)->cpu, (start)->cpu); \
70 } \
71 else \
72 { \
73 TRACE("Could not find an available CPU close to P%d\n", \
74 (start)->cpu); \
75 } \
76}
77
78#endif
diff --git a/include/litmus/fdso.h b/include/litmus/fdso.h
index caf2a1e6918c..c740e8fc3e88 100644
--- a/include/litmus/fdso.h
+++ b/include/litmus/fdso.h
@@ -18,9 +18,10 @@ typedef enum {
18 MIN_OBJ_TYPE = 0, 18 MIN_OBJ_TYPE = 0,
19 19
20 FMLP_SEM = 0, 20 FMLP_SEM = 0,
21 SRP_SEM = 1, 21 KFMLP_SEM = 1,
22 SRP_SEM = 2,
22 23
23 MAX_OBJ_TYPE = 1 24 MAX_OBJ_TYPE = SRP_SEM
24} obj_type_t; 25} obj_type_t;
25 26
26struct inode_obj_id { 27struct inode_obj_id {
@@ -64,6 +65,7 @@ static inline void* od_lookup(int od, obj_type_t type)
64} 65}
65 66
66#define lookup_fmlp_sem(od)((struct pi_semaphore*) od_lookup(od, FMLP_SEM)) 67#define lookup_fmlp_sem(od)((struct pi_semaphore*) od_lookup(od, FMLP_SEM))
68#define lookup_kfmlp_sem(od)((struct pi_semaphore*) od_lookup(od, KFMLP_SEM))
67#define lookup_srp_sem(od) ((struct srp_semaphore*) od_lookup(od, SRP_SEM)) 69#define lookup_srp_sem(od) ((struct srp_semaphore*) od_lookup(od, SRP_SEM))
68#define lookup_ics(od) ((struct ics*) od_lookup(od, ICS_ID)) 70#define lookup_ics(od) ((struct ics*) od_lookup(od, ICS_ID))
69 71
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h
index e7769ca36ec0..3df242bf272f 100644
--- a/include/litmus/litmus.h
+++ b/include/litmus/litmus.h
@@ -26,6 +26,7 @@ static inline int in_list(struct list_head* list)
26 ); 26 );
27} 27}
28 28
29
29struct task_struct* __waitqueue_remove_first(wait_queue_head_t *wq); 30struct task_struct* __waitqueue_remove_first(wait_queue_head_t *wq);
30 31
31#define NO_CPU 0xffffffff 32#define NO_CPU 0xffffffff
diff --git a/include/litmus/litmus_softirq.h b/include/litmus/litmus_softirq.h
new file mode 100644
index 000000000000..34287f3cbb8d
--- /dev/null
+++ b/include/litmus/litmus_softirq.h
@@ -0,0 +1,199 @@
1#ifndef __LITMUS_SOFTIRQ_H
2#define __LITMUS_SOFTIRQ_H
3
4#include <linux/interrupt.h>
5#include <linux/workqueue.h>
6
7/*
8 Threaded tasklet handling for Litmus. Tasklets
9 are scheduled with the priority of the tasklet's
10 owner---that is, the RT task on behalf the tasklet
11 runs.
12
13 Tasklets are current scheduled in FIFO order with
14 NO priority inheritance for "blocked" tasklets.
15
16 klitirqd assumes the priority of the owner of the
17 tasklet when the tasklet is next to execute.
18
19 Currently, hi-tasklets are scheduled before
20 low-tasklets, regardless of priority of low-tasklets.
21 And likewise, low-tasklets are scheduled before work
22 queue objects. This priority inversion probably needs
23 to be fixed, though it is not an issue if our work with
24 GPUs as GPUs are owned (and associated klitirqds) for
25 exclusive time periods, thus no inversions can
26 occur.
27 */
28
29
30
31#define NR_LITMUS_SOFTIRQD CONFIG_NR_LITMUS_SOFTIRQD
32
33/* Spawns NR_LITMUS_SOFTIRQD klitirqd daemons.
34 Actual launch of threads is deffered to kworker's
35 workqueue, so daemons will likely not be immediately
36 running when this function returns, though the required
37 data will be initialized.
38
39 @affinity_set: an array expressing the processor affinity
40 for each of the NR_LITMUS_SOFTIRQD daemons. May be set
41 to NULL for global scheduling.
42
43 - Examples -
44 8-CPU system with two CPU clusters:
45 affinity[] = {0, 0, 0, 0, 3, 3, 3, 3}
46 NOTE: Daemons not actually bound to specified CPU, but rather
47 cluster in which the CPU resides.
48
49 8-CPU system, partitioned:
50 affinity[] = {0, 1, 2, 3, 4, 5, 6, 7}
51
52 FIXME: change array to a CPU topology or array of cpumasks
53
54 */
55void spawn_klitirqd(int* affinity);
56
57
58/* Raises a flag to tell klitirqds to terminate.
59 Termination is async, so some threads may be running
60 after function return. */
61void kill_klitirqd(void);
62
63
64/* Returns 1 if all NR_LITMUS_SOFTIRQD klitirqs are ready
65 to handle tasklets. 0, otherwise.*/
66int klitirqd_is_ready(void);
67
68/* Returns 1 if no NR_LITMUS_SOFTIRQD klitirqs are ready
69 to handle tasklets. 0, otherwise.*/
70int klitirqd_is_dead(void);
71
72/* Flushes all pending work out to the OS for regular
73 * tasklet/work processing of the specified 'owner'
74 *
75 * PRECOND: klitirqd_thread must have a clear entry
76 * in the GPU registry, otherwise this call will become
77 * a no-op as work will loop back to the klitirqd_thread.
78 *
79 * Pass NULL for owner to flush ALL pending items.
80 */
81void flush_pending(struct task_struct* klitirqd_thread,
82 struct task_struct* owner);
83
84struct task_struct* get_klitirqd(unsigned int k_id);
85
86
87extern int __litmus_tasklet_schedule(
88 struct tasklet_struct *t,
89 unsigned int k_id);
90
91/* schedule a tasklet on klitirqd #k_id */
92static inline int litmus_tasklet_schedule(
93 struct tasklet_struct *t,
94 unsigned int k_id)
95{
96 int ret = 0;
97 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
98 ret = __litmus_tasklet_schedule(t, k_id);
99 return(ret);
100}
101
102/* for use by __tasklet_schedule() */
103static inline int _litmus_tasklet_schedule(
104 struct tasklet_struct *t,
105 unsigned int k_id)
106{
107 return(__litmus_tasklet_schedule(t, k_id));
108}
109
110
111
112
113extern int __litmus_tasklet_hi_schedule(struct tasklet_struct *t,
114 unsigned int k_id);
115
116/* schedule a hi tasklet on klitirqd #k_id */
117static inline int litmus_tasklet_hi_schedule(struct tasklet_struct *t,
118 unsigned int k_id)
119{
120 int ret = 0;
121 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
122 ret = __litmus_tasklet_hi_schedule(t, k_id);
123 return(ret);
124}
125
126/* for use by __tasklet_hi_schedule() */
127static inline int _litmus_tasklet_hi_schedule(struct tasklet_struct *t,
128 unsigned int k_id)
129{
130 return(__litmus_tasklet_hi_schedule(t, k_id));
131}
132
133
134
135
136
137extern int __litmus_tasklet_hi_schedule_first(
138 struct tasklet_struct *t,
139 unsigned int k_id);
140
141/* schedule a hi tasklet on klitirqd #k_id on next go-around */
142/* PRECONDITION: Interrupts must be disabled. */
143static inline int litmus_tasklet_hi_schedule_first(
144 struct tasklet_struct *t,
145 unsigned int k_id)
146{
147 int ret = 0;
148 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
149 ret = __litmus_tasklet_hi_schedule_first(t, k_id);
150 return(ret);
151}
152
153/* for use by __tasklet_hi_schedule_first() */
154static inline int _litmus_tasklet_hi_schedule_first(
155 struct tasklet_struct *t,
156 unsigned int k_id)
157{
158 return(__litmus_tasklet_hi_schedule_first(t, k_id));
159}
160
161
162
163//////////////
164
165extern int __litmus_schedule_work(
166 struct work_struct* w,
167 unsigned int k_id);
168
169static inline int litmus_schedule_work(
170 struct work_struct* w,
171 unsigned int k_id)
172{
173 return(__litmus_schedule_work(w, k_id));
174}
175
176
177
178///////////// mutex operations for client threads.
179
180void down_and_set_stat(struct task_struct* t,
181 enum klitirqd_sem_status to_set,
182 struct mutex* sem);
183
184void __down_and_reset_and_set_stat(struct task_struct* t,
185 enum klitirqd_sem_status to_reset,
186 enum klitirqd_sem_status to_set,
187 struct mutex* sem);
188
189void up_and_set_stat(struct task_struct* t,
190 enum klitirqd_sem_status to_set,
191 struct mutex* sem);
192
193
194
195void release_klitirqd_lock(struct task_struct* t);
196
197int reacquire_klitirqd_lock(struct task_struct* t);
198
199#endif
diff --git a/include/litmus/nvidia_info.h b/include/litmus/nvidia_info.h
new file mode 100644
index 000000000000..579301d77cf5
--- /dev/null
+++ b/include/litmus/nvidia_info.h
@@ -0,0 +1,37 @@
1#ifndef __LITMUS_NVIDIA_H
2#define __LITMUS_NVIDIA_H
3
4#include <linux/interrupt.h>
5
6
7#include <litmus/litmus_softirq.h>
8
9
10#define NV_DEVICE_NUM NR_LITMUS_SOFTIRQD
11
12int init_nvidia_info(void);
13
14int is_nvidia_func(void* func_addr);
15
16void dump_nvidia_info(const struct tasklet_struct *t);
17
18
19// Returns the Nvidia device # associated with provided tasklet and work_struct.
20u32 get_tasklet_nv_device_num(const struct tasklet_struct *t);
21u32 get_work_nv_device_num(const struct work_struct *t);
22
23
24int init_nv_device_reg(void);
25//int get_nv_device_id(struct task_struct* owner);
26
27
28int reg_nv_device(int reg_device_id, int register_device);
29
30struct task_struct* get_nv_device_owner(u32 target_device_id);
31
32void lock_nv_registry(u32 reg_device_id, unsigned long* flags);
33void unlock_nv_registry(u32 reg_device_id, unsigned long* flags);
34
35void increment_nv_int_count(u32 device);
36
37#endif
diff --git a/include/litmus/preempt.h b/include/litmus/preempt.h
index 260c6fe17986..244924f93c48 100644
--- a/include/litmus/preempt.h
+++ b/include/litmus/preempt.h
@@ -26,6 +26,7 @@ const char* sched_state_name(int s);
26 (x), #x, __FUNCTION__); \ 26 (x), #x, __FUNCTION__); \
27 } while (0); 27 } while (0);
28 28
29//#define TRACE_SCHED_STATE_CHANGE(x, y, cpu) /* ignore */
29#define TRACE_SCHED_STATE_CHANGE(x, y, cpu) \ 30#define TRACE_SCHED_STATE_CHANGE(x, y, cpu) \
30 TRACE_STATE("[P%d] 0x%x (%s) -> 0x%x (%s)\n", \ 31 TRACE_STATE("[P%d] 0x%x (%s) -> 0x%x (%s)\n", \
31 cpu, (x), sched_state_name(x), \ 32 cpu, (x), sched_state_name(x), \
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
index 5de422c742f6..53af3ce1d955 100644
--- a/include/litmus/rt_param.h
+++ b/include/litmus/rt_param.h
@@ -69,6 +69,8 @@ struct control_page {
69/* don't export internal data structures to user space (liblitmus) */ 69/* don't export internal data structures to user space (liblitmus) */
70#ifdef __KERNEL__ 70#ifdef __KERNEL__
71 71
72#include <linux/semaphore.h>
73
72struct _rt_domain; 74struct _rt_domain;
73struct bheap_node; 75struct bheap_node;
74struct release_heap; 76struct release_heap;
@@ -94,6 +96,14 @@ struct rt_job {
94 96
95struct pfair_param; 97struct pfair_param;
96 98
99enum klitirqd_sem_status
100{
101 NEED_TO_REACQUIRE,
102 REACQUIRING,
103 NOT_HELD,
104 HELD
105};
106
97/* RT task parameters for scheduling extensions 107/* RT task parameters for scheduling extensions
98 * These parameters are inherited during clone and therefore must 108 * These parameters are inherited during clone and therefore must
99 * be explicitly set up before the task set is launched. 109 * be explicitly set up before the task set is launched.
@@ -108,6 +118,38 @@ struct rt_param {
108 /* is the task present? (true if it can be scheduled) */ 118 /* is the task present? (true if it can be scheduled) */
109 unsigned int present:1; 119 unsigned int present:1;
110 120
121#ifdef CONFIG_LITMUS_SOFTIRQD
122 /* proxy threads have minimum priority by default */
123 unsigned int is_proxy_thread:1;
124
125 /* pointer to klitirqd currently working on this
126 task_struct's behalf. only set by the task pointed
127 to by klitirqd.
128
129 ptr only valid if is_proxy_thread == 0
130 */
131 struct task_struct* cur_klitirqd;
132
133 /* Used to implement mutual execution exclusion between
134 * job and klitirqd execution. Job must always hold
135 * it's klitirqd_sem to execute. klitirqd instance
136 * must hold the semaphore before executing on behalf
137 * of a job.
138 */
139 //struct semaphore klitirqd_sem;
140 struct mutex klitirqd_sem;
141
142 /* status of held klitirqd_sem, even if the held klitirqd_sem is from
143 another task (only proxy threads do this though).
144 */
145 atomic_t klitirqd_sem_stat;
146#endif
147
148#ifdef CONFIG_LITMUS_NVIDIA
149 /* number of top-half interrupts handled on behalf of current job */
150 atomic_t nv_int_count;
151#endif
152
111#ifdef CONFIG_LITMUS_LOCKING 153#ifdef CONFIG_LITMUS_LOCKING
112 /* Is the task being priority-boosted by a locking protocol? */ 154 /* Is the task being priority-boosted by a locking protocol? */
113 unsigned int priority_boosted:1; 155 unsigned int priority_boosted:1;
@@ -128,7 +170,7 @@ struct rt_param {
128 * an increased task priority. 170 * an increased task priority.
129 */ 171 */
130 struct task_struct* inh_task; 172 struct task_struct* inh_task;
131 173
132#ifdef CONFIG_NP_SECTION 174#ifdef CONFIG_NP_SECTION
133 /* For the FMLP under PSN-EDF, it is required to make the task 175 /* For the FMLP under PSN-EDF, it is required to make the task
134 * non-preemptive from kernel space. In order not to interfere with 176 * non-preemptive from kernel space. In order not to interfere with
diff --git a/include/litmus/sched_plugin.h b/include/litmus/sched_plugin.h
index 6e7cabdddae8..df50930d14a0 100644
--- a/include/litmus/sched_plugin.h
+++ b/include/litmus/sched_plugin.h
@@ -29,7 +29,6 @@ typedef struct task_struct* (*schedule_t)(struct task_struct * prev);
29 */ 29 */
30typedef void (*finish_switch_t)(struct task_struct *prev); 30typedef void (*finish_switch_t)(struct task_struct *prev);
31 31
32
33/********************* task state changes ********************/ 32/********************* task state changes ********************/
34 33
35/* Called to setup a new real-time task. 34/* Called to setup a new real-time task.
@@ -58,6 +57,17 @@ typedef void (*task_exit_t) (struct task_struct *);
58typedef long (*allocate_lock_t) (struct litmus_lock **lock, int type, 57typedef long (*allocate_lock_t) (struct litmus_lock **lock, int type,
59 void* __user config); 58 void* __user config);
60 59
60/* Called to change inheritance levels of given task */
61typedef void (*set_prio_inh_t)(struct task_struct* t,
62 struct task_struct* prio_inh);
63typedef void (*clear_prio_inh_t)(struct task_struct* t);
64
65
66typedef void (*set_prio_inh_klitirq_t)(struct task_struct* klitirqd,
67 struct task_struct* old_owner,
68 struct task_struct* new_owner);
69typedef void (*clear_prio_inh_klitirqd_t)(struct task_struct* klitirqd,
70 struct task_struct* old_owner);
61 71
62/********************* sys call backends ********************/ 72/********************* sys call backends ********************/
63/* This function causes the caller to sleep until the next release */ 73/* This function causes the caller to sleep until the next release */
@@ -88,7 +98,7 @@ struct sched_plugin {
88 /* task state changes */ 98 /* task state changes */
89 admit_task_t admit_task; 99 admit_task_t admit_task;
90 100
91 task_new_t task_new; 101 task_new_t task_new;
92 task_wake_up_t task_wake_up; 102 task_wake_up_t task_wake_up;
93 task_block_t task_block; 103 task_block_t task_block;
94 task_exit_t task_exit; 104 task_exit_t task_exit;
@@ -96,6 +106,14 @@ struct sched_plugin {
96#ifdef CONFIG_LITMUS_LOCKING 106#ifdef CONFIG_LITMUS_LOCKING
97 /* locking protocols */ 107 /* locking protocols */
98 allocate_lock_t allocate_lock; 108 allocate_lock_t allocate_lock;
109
110 set_prio_inh_t set_prio_inh;
111 clear_prio_inh_t clear_prio_inh;
112#endif
113
114#ifdef CONFIG_LITMUS_SOFTIRQD
115 set_prio_inh_klitirq_t set_prio_inh_klitirqd;
116 clear_prio_inh_klitirqd_t clear_prio_inh_klitirqd;
99#endif 117#endif
100} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); 118} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
101 119
diff --git a/include/litmus/sched_trace.h b/include/litmus/sched_trace.h
index 7ca34cb13881..1486c778aff8 100644
--- a/include/litmus/sched_trace.h
+++ b/include/litmus/sched_trace.h
@@ -11,12 +11,12 @@ struct st_trace_header {
11 u8 cpu; /* On which CPU was it recorded? */ 11 u8 cpu; /* On which CPU was it recorded? */
12 u16 pid; /* PID of the task. */ 12 u16 pid; /* PID of the task. */
13 u32 job; /* The job sequence number. */ 13 u32 job; /* The job sequence number. */
14}; 14} __attribute__((packed));
15 15
16#define ST_NAME_LEN 16 16#define ST_NAME_LEN 16
17struct st_name_data { 17struct st_name_data {
18 char cmd[ST_NAME_LEN];/* The name of the executable of this process. */ 18 char cmd[ST_NAME_LEN];/* The name of the executable of this process. */
19}; 19} __attribute__((packed));
20 20
21struct st_param_data { /* regular params */ 21struct st_param_data { /* regular params */
22 u32 wcet; 22 u32 wcet;
@@ -25,30 +25,29 @@ struct st_param_data { /* regular params */
25 u8 partition; 25 u8 partition;
26 u8 class; 26 u8 class;
27 u8 __unused[2]; 27 u8 __unused[2];
28}; 28} __attribute__((packed));
29 29
30struct st_release_data { /* A job is was/is going to be released. */ 30struct st_release_data { /* A job is was/is going to be released. */
31 u64 release; /* What's the release time? */ 31 u64 release; /* What's the release time? */
32 u64 deadline; /* By when must it finish? */ 32 u64 deadline; /* By when must it finish? */
33}; 33} __attribute__((packed));
34 34
35struct st_assigned_data { /* A job was asigned to a CPU. */ 35struct st_assigned_data { /* A job was asigned to a CPU. */
36 u64 when; 36 u64 when;
37 u8 target; /* Where should it execute? */ 37 u8 target; /* Where should it execute? */
38 u8 __unused[7]; 38 u8 __unused[7];
39}; 39} __attribute__((packed));
40 40
41struct st_switch_to_data { /* A process was switched to on a given CPU. */ 41struct st_switch_to_data { /* A process was switched to on a given CPU. */
42 u64 when; /* When did this occur? */ 42 u64 when; /* When did this occur? */
43 u32 exec_time; /* Time the current job has executed. */ 43 u32 exec_time; /* Time the current job has executed. */
44 u8 __unused[4]; 44 u8 __unused[4];
45 45} __attribute__((packed));
46};
47 46
48struct st_switch_away_data { /* A process was switched away from on a given CPU. */ 47struct st_switch_away_data { /* A process was switched away from on a given CPU. */
49 u64 when; 48 u64 when;
50 u64 exec_time; 49 u64 exec_time;
51}; 50} __attribute__((packed));
52 51
53struct st_completion_data { /* A job completed. */ 52struct st_completion_data { /* A job completed. */
54 u64 when; 53 u64 when;
@@ -56,35 +55,92 @@ struct st_completion_data { /* A job completed. */
56 * next task automatically; set to 0 otherwise. 55 * next task automatically; set to 0 otherwise.
57 */ 56 */
58 u8 __uflags:7; 57 u8 __uflags:7;
59 u8 __unused[7]; 58 u16 nv_int_count;
60}; 59 u8 __unused[5];
60} __attribute__((packed));
61 61
62struct st_block_data { /* A task blocks. */ 62struct st_block_data { /* A task blocks. */
63 u64 when; 63 u64 when;
64 u64 __unused; 64 u64 __unused;
65}; 65} __attribute__((packed));
66 66
67struct st_resume_data { /* A task resumes. */ 67struct st_resume_data { /* A task resumes. */
68 u64 when; 68 u64 when;
69 u64 __unused; 69 u64 __unused;
70}; 70} __attribute__((packed));
71 71
72struct st_action_data { 72struct st_action_data {
73 u64 when; 73 u64 when;
74 u8 action; 74 u8 action;
75 u8 __unused[7]; 75 u8 __unused[7];
76}; 76} __attribute__((packed));
77 77
78struct st_sys_release_data { 78struct st_sys_release_data {
79 u64 when; 79 u64 when;
80 u64 release; 80 u64 release;
81}; 81} __attribute__((packed));
82
83
84struct st_tasklet_release_data {
85 u64 when;
86 u64 __unused;
87} __attribute__((packed));
88
89struct st_tasklet_begin_data {
90 u64 when;
91 u16 exe_pid;
92 u8 __unused[6];
93} __attribute__((packed));
94
95struct st_tasklet_end_data {
96 u64 when;
97 u16 exe_pid;
98 u8 flushed;
99 u8 __unused[5];
100} __attribute__((packed));
101
102
103struct st_work_release_data {
104 u64 when;
105 u64 __unused;
106} __attribute__((packed));
107
108struct st_work_begin_data {
109 u64 when;
110 u16 exe_pid;
111 u8 __unused[6];
112} __attribute__((packed));
113
114struct st_work_end_data {
115 u64 when;
116 u16 exe_pid;
117 u8 flushed;
118 u8 __unused[5];
119} __attribute__((packed));
120
121struct st_effective_priority_change_data {
122 u64 when;
123 u16 inh_pid;
124 u8 __unused[6];
125} __attribute__((packed));
126
127struct st_nv_interrupt_begin_data {
128 u64 when;
129 u32 device;
130 u8 __unused[4];
131} __attribute__((packed));
132
133struct st_nv_interrupt_end_data {
134 u64 when;
135 u32 device;
136 u8 __unused[4];
137} __attribute__((packed));
82 138
83#define DATA(x) struct st_ ## x ## _data x; 139#define DATA(x) struct st_ ## x ## _data x;
84 140
85typedef enum { 141typedef enum {
86 ST_NAME = 1, /* Start at one, so that we can spot 142 ST_NAME = 1, /* Start at one, so that we can spot
87 * uninitialized records. */ 143 * uninitialized records. */
88 ST_PARAM, 144 ST_PARAM,
89 ST_RELEASE, 145 ST_RELEASE,
90 ST_ASSIGNED, 146 ST_ASSIGNED,
@@ -94,7 +150,16 @@ typedef enum {
94 ST_BLOCK, 150 ST_BLOCK,
95 ST_RESUME, 151 ST_RESUME,
96 ST_ACTION, 152 ST_ACTION,
97 ST_SYS_RELEASE 153 ST_SYS_RELEASE,
154 ST_TASKLET_RELEASE,
155 ST_TASKLET_BEGIN,
156 ST_TASKLET_END,
157 ST_WORK_RELEASE,
158 ST_WORK_BEGIN,
159 ST_WORK_END,
160 ST_EFF_PRIO_CHANGE,
161 ST_NV_INTERRUPT_BEGIN,
162 ST_NV_INTERRUPT_END,
98} st_event_record_type_t; 163} st_event_record_type_t;
99 164
100struct st_event_record { 165struct st_event_record {
@@ -113,8 +178,17 @@ struct st_event_record {
113 DATA(resume); 178 DATA(resume);
114 DATA(action); 179 DATA(action);
115 DATA(sys_release); 180 DATA(sys_release);
181 DATA(tasklet_release);
182 DATA(tasklet_begin);
183 DATA(tasklet_end);
184 DATA(work_release);
185 DATA(work_begin);
186 DATA(work_end);
187 DATA(effective_priority_change);
188 DATA(nv_interrupt_begin);
189 DATA(nv_interrupt_end);
116 } data; 190 } data;
117}; 191} __attribute__((packed));
118 192
119#undef DATA 193#undef DATA
120 194
@@ -129,6 +203,8 @@ struct st_event_record {
129 ft_event1(id, callback, task) 203 ft_event1(id, callback, task)
130#define SCHED_TRACE2(id, callback, task, xtra) \ 204#define SCHED_TRACE2(id, callback, task, xtra) \
131 ft_event2(id, callback, task, xtra) 205 ft_event2(id, callback, task, xtra)
206#define SCHED_TRACE3(id, callback, task, xtra1, xtra2) \
207 ft_event3(id, callback, task, xtra1, xtra2)
132 208
133/* provide prototypes; needed on sparc64 */ 209/* provide prototypes; needed on sparc64 */
134#ifndef NO_TASK_TRACE_DECLS 210#ifndef NO_TASK_TRACE_DECLS
@@ -155,12 +231,45 @@ feather_callback void do_sched_trace_action(unsigned long id,
155feather_callback void do_sched_trace_sys_release(unsigned long id, 231feather_callback void do_sched_trace_sys_release(unsigned long id,
156 lt_t* start); 232 lt_t* start);
157 233
234
235feather_callback void do_sched_trace_tasklet_release(unsigned long id,
236 struct task_struct* owner);
237feather_callback void do_sched_trace_tasklet_begin(unsigned long id,
238 struct task_struct* owner);
239feather_callback void do_sched_trace_tasklet_end(unsigned long id,
240 struct task_struct* owner,
241 unsigned long flushed);
242
243feather_callback void do_sched_trace_work_release(unsigned long id,
244 struct task_struct* owner);
245feather_callback void do_sched_trace_work_begin(unsigned long id,
246 struct task_struct* owner,
247 struct task_struct* exe);
248feather_callback void do_sched_trace_work_end(unsigned long id,
249 struct task_struct* owner,
250 struct task_struct* exe,
251 unsigned long flushed);
252
253feather_callback void do_sched_trace_eff_prio_change(unsigned long id,
254 struct task_struct* task,
255 struct task_struct* inh);
256
257feather_callback void do_sched_trace_nv_interrupt_begin(unsigned long id,
258 u32 device);
259feather_callback void do_sched_trace_nv_interrupt_end(unsigned long id,
260 unsigned long unused);
261
262
263/* returns true if we're tracing an interrupt on current CPU */
264/* int is_interrupt_tracing_active(void); */
265
158#endif 266#endif
159 267
160#else 268#else
161 269
162#define SCHED_TRACE(id, callback, task) /* no tracing */ 270#define SCHED_TRACE(id, callback, task) /* no tracing */
163#define SCHED_TRACE2(id, callback, task, xtra) /* no tracing */ 271#define SCHED_TRACE2(id, callback, task, xtra) /* no tracing */
272#define SCHED_TRACE3(id, callback, task, xtra1, xtra2)
164 273
165#endif 274#endif
166 275
@@ -193,6 +302,35 @@ feather_callback void do_sched_trace_sys_release(unsigned long id,
193 SCHED_TRACE(SCHED_TRACE_BASE_ID + 10, do_sched_trace_sys_release, when) 302 SCHED_TRACE(SCHED_TRACE_BASE_ID + 10, do_sched_trace_sys_release, when)
194 303
195 304
305#define sched_trace_tasklet_release(t) \
306 SCHED_TRACE(SCHED_TRACE_BASE_ID + 11, do_sched_trace_tasklet_release, t)
307
308#define sched_trace_tasklet_begin(t) \
309 SCHED_TRACE(SCHED_TRACE_BASE_ID + 12, do_sched_trace_tasklet_begin, t)
310
311#define sched_trace_tasklet_end(t, flushed) \
312 SCHED_TRACE2(SCHED_TRACE_BASE_ID + 13, do_sched_trace_tasklet_end, t, flushed)
313
314
315#define sched_trace_work_release(t) \
316 SCHED_TRACE(SCHED_TRACE_BASE_ID + 14, do_sched_trace_work_release, t)
317
318#define sched_trace_work_begin(t, e) \
319 SCHED_TRACE2(SCHED_TRACE_BASE_ID + 15, do_sched_trace_work_begin, t, e)
320
321#define sched_trace_work_end(t, e, flushed) \
322 SCHED_TRACE3(SCHED_TRACE_BASE_ID + 16, do_sched_trace_work_end, t, e, flushed)
323
324
325#define sched_trace_eff_prio_change(t, inh) \
326 SCHED_TRACE2(SCHED_TRACE_BASE_ID + 17, do_sched_trace_eff_prio_change, t, inh)
327
328
329#define sched_trace_nv_interrupt_begin(d) \
330 SCHED_TRACE(SCHED_TRACE_BASE_ID + 18, do_sched_trace_nv_interrupt_begin, d)
331#define sched_trace_nv_interrupt_end() \
332 SCHED_TRACE(SCHED_TRACE_BASE_ID + 19, do_sched_trace_nv_interrupt_end, 0ul)
333
196#define sched_trace_quantum_boundary() /* NOT IMPLEMENTED */ 334#define sched_trace_quantum_boundary() /* NOT IMPLEMENTED */
197 335
198#endif /* __KERNEL__ */ 336#endif /* __KERNEL__ */
diff --git a/include/litmus/sched_trace_external.h b/include/litmus/sched_trace_external.h
new file mode 100644
index 000000000000..c2c872639880
--- /dev/null
+++ b/include/litmus/sched_trace_external.h
@@ -0,0 +1,42 @@
1/*
2 * sched_trace.h -- record scheduler events to a byte stream for offline analysis.
3 */
4#ifndef _LINUX_SCHED_TRACE_EXTERNAL_H_
5#define _LINUX_SCHED_TRACE_EXTERNAL_H_
6
7extern void __sched_trace_tasklet_begin_external(struct task_struct* t);
8static inline void sched_trace_tasklet_begin_external(struct task_struct* t)
9{
10 __sched_trace_tasklet_begin_external(t);
11}
12
13extern void __sched_trace_tasklet_end_external(struct task_struct* t, unsigned long flushed);
14static inline void sched_trace_tasklet_end_external(struct task_struct* t, unsigned long flushed)
15{
16 __sched_trace_tasklet_end_external(t, flushed);
17}
18
19extern void __sched_trace_work_begin_external(struct task_struct* t, struct task_struct* e);
20static inline void sched_trace_work_begin_external(struct task_struct* t, struct task_struct* e)
21{
22 __sched_trace_work_begin_external(t, e);
23}
24
25extern void __sched_trace_work_end_external(struct task_struct* t, struct task_struct* e, unsigned long f);
26static inline void sched_trace_work_end_external(struct task_struct* t, struct task_struct* e, unsigned long f)
27{
28 __sched_trace_work_end_external(t, e, f);
29}
30
31extern void __sched_trace_nv_interrupt_begin_external(u32 device);
32static inline void sched_trace_nv_interrupt_begin_external(u32 device)
33{
34 __sched_trace_nv_interrupt_begin_external(device);
35}
36
37extern void __sched_trace_nv_interrupt_end_external(void);
38static inline void sched_trace_nv_interrupt_end_external(void)
39{
40 __sched_trace_nv_interrupt_end_external();
41}
42#endif
diff --git a/include/litmus/unistd_32.h b/include/litmus/unistd_32.h
index 94264c27d9ac..c6efc4c40af2 100644
--- a/include/litmus/unistd_32.h
+++ b/include/litmus/unistd_32.h
@@ -17,5 +17,6 @@
17#define __NR_wait_for_ts_release __LSC(9) 17#define __NR_wait_for_ts_release __LSC(9)
18#define __NR_release_ts __LSC(10) 18#define __NR_release_ts __LSC(10)
19#define __NR_null_call __LSC(11) 19#define __NR_null_call __LSC(11)
20#define __NR_register_nv_device __LSC(12)
20 21
21#define NR_litmus_syscalls 12 22#define NR_litmus_syscalls 13
diff --git a/include/litmus/unistd_64.h b/include/litmus/unistd_64.h
index d5ced0d2642c..b44a7c33bdf8 100644
--- a/include/litmus/unistd_64.h
+++ b/include/litmus/unistd_64.h
@@ -29,5 +29,8 @@ __SYSCALL(__NR_wait_for_ts_release, sys_wait_for_ts_release)
29__SYSCALL(__NR_release_ts, sys_release_ts) 29__SYSCALL(__NR_release_ts, sys_release_ts)
30#define __NR_null_call __LSC(11) 30#define __NR_null_call __LSC(11)
31__SYSCALL(__NR_null_call, sys_null_call) 31__SYSCALL(__NR_null_call, sys_null_call)
32#define __NR_register_nv_device __LSC(12)
33__SYSCALL(__NR_register_nv_device, sys_register_nv_device)
32 34
33#define NR_litmus_syscalls 12 35
36#define NR_litmus_syscalls 13