aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2011-03-03 00:17:19 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2011-03-03 00:17:19 -0500
commit9765eaebc4ffb1f1bdf6998c0491d2e37de1a994 (patch)
tree31ff20e3b542b23790430a3af2b17d2a569ab44e
parent0e6a634b0b02a86c9591c1bf8c73ff0cf68475fc (diff)
Kludge work-queue processing into klitirqd.wip-kernthreads
NEEDS TESTING!
-rw-r--r--include/linux/workqueue.h17
-rw-r--r--include/litmus/litmus_softirq.h24
-rw-r--r--litmus/litmus_softirq.c151
3 files changed, 163 insertions, 29 deletions
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 25e02c941bac..a5c6cd3210be 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) { \
diff --git a/include/litmus/litmus_softirq.h b/include/litmus/litmus_softirq.h
index 712c8119ae15..e130a26685a2 100644
--- a/include/litmus/litmus_softirq.h
+++ b/include/litmus/litmus_softirq.h
@@ -2,6 +2,7 @@
2#define __LITMUS_SOFTIRQ_H 2#define __LITMUS_SOFTIRQ_H
3 3
4#include <linux/interrupt.h> 4#include <linux/interrupt.h>
5#include <linux/workqueue.h>
5 6
6/* 7/*
7 Threaded tasklet handling for Litmus. Tasklets 8 Threaded tasklet handling for Litmus. Tasklets
@@ -105,4 +106,25 @@ static inline void litmus_tasklet_hi_schedule_first(
105 __litmus_tasklet_hi_schedule_first(t, k_id); 106 __litmus_tasklet_hi_schedule_first(t, k_id);
106} 107}
107 108
108#endif \ No newline at end of file 109//////////////
110
111extern void __litmus_schedule_work(
112 struct work_struct* w,
113 unsigned int k_id);
114
115static inline void litmus_schedule_work(
116 struct work_struct* w,
117 unsigned int k_id)
118{
119 __litmus_schedule_work(w, k_id);
120}
121
122#endif
123
124
125
126
127
128
129
130
diff --git a/litmus/litmus_softirq.c b/litmus/litmus_softirq.c
index dbefcb560063..734a7dcdc9ca 100644
--- a/litmus/litmus_softirq.c
+++ b/litmus/litmus_softirq.c
@@ -21,7 +21,8 @@ static atomic_t num_ready_klitirqds = ATOMIC_INIT(0);
21enum pending_flags 21enum pending_flags
22{ 22{
23 LIT_TASKLET_LOW = 0x1, 23 LIT_TASKLET_LOW = 0x1,
24 LIT_TASKLET_HI = LIT_TASKLET_LOW<<1 24 LIT_TASKLET_HI = LIT_TASKLET_LOW<<1,
25 LIT_WORK = LIT_TASKLET_HI<<1
25}; 26};
26 27
27/* only support tasklet processing for now. */ 28/* only support tasklet processing for now. */
@@ -37,8 +38,11 @@ struct klitirqd_info
37 raw_spinlock_t lock; 38 raw_spinlock_t lock;
38 39
39 u32 pending; 40 u32 pending;
41
42 /* in order of priority */
43 struct tasklet_head pending_tasklets_hi;
40 struct tasklet_head pending_tasklets; 44 struct tasklet_head pending_tasklets;
41 struct tasklet_head pending_tasklets_hi; 45 struct list_head worklist;
42}; 46};
43 47
44/* one list for each klitirqd */ 48/* one list for each klitirqd */
@@ -66,18 +70,22 @@ inline unsigned int klitirqd_id(struct task_struct* tsk)
66inline static u32 litirq_pending_hi_irqoff(struct klitirqd_info* which) 70inline static u32 litirq_pending_hi_irqoff(struct klitirqd_info* which)
67{ 71{
68 return (which->pending & LIT_TASKLET_HI); 72 return (which->pending & LIT_TASKLET_HI);
69}; 73}
70 74
71inline static u32 litirq_pending_low_irqoff(struct klitirqd_info* which) 75inline static u32 litirq_pending_low_irqoff(struct klitirqd_info* which)
72{ 76{
73 return (which->pending & LIT_TASKLET_LOW); 77 return (which->pending & LIT_TASKLET_LOW);
74}; 78}
75 79
80inline static u32 litirq_pending_work_irqoff(struct klitirqd_info* which)
81{
82 return (which->pending & LIT_WORK);
83}
76 84
77inline static u32 litirq_pending_irqoff(struct klitirqd_info* which) 85inline static u32 litirq_pending_irqoff(struct klitirqd_info* which)
78{ 86{
79 return(which->pending); 87 return(which->pending);
80}; 88}
81 89
82 90
83inline static u32 litirq_pending(struct klitirqd_info* which) 91inline static u32 litirq_pending(struct klitirqd_info* which)
@@ -93,9 +101,15 @@ inline static u32 litirq_pending(struct klitirqd_info* which)
93}; 101};
94 102
95 103
104/* returns true if thread needs to change priority to continue processing
105 pending tasklets.
106 */
96static int needs_prio_change(struct klitirqd_info* which, 107static int needs_prio_change(struct klitirqd_info* which,
97 struct tasklet_head* pending_tasklets) 108 struct tasklet_head* pending_tasklets)
98{ 109{
110 /* this function doesn't have to look at work objects since they have
111 priority below tasklets. */
112
99 unsigned long flags; 113 unsigned long flags;
100 int ret = 0; 114 int ret = 0;
101 115
@@ -126,33 +140,41 @@ static int needs_prio_change(struct klitirqd_info* which,
126 140
127static void __reeval_prio(struct klitirqd_info* which) 141static void __reeval_prio(struct klitirqd_info* which)
128{ 142{
129 u32 pending = 0;
130 struct task_struct* tsk = which->klitirqd; 143 struct task_struct* tsk = which->klitirqd;
131 struct task_struct* new_prio = tsk_rt(tsk)->inh_task; 144 struct task_struct* new_prio = tsk_rt(tsk)->inh_task;
132 145
133 if(litirq_pending_irqoff(which)) 146 /* Check in prio-order */
134 { 147 u32 pending = litirq_pending_irqoff(which);
135 pending = 1; 148 if(pending & LIT_TASKLET_HI)
136 if(which->pending_tasklets.head->owner != tsk_rt(tsk)->inh_task) 149 {
137 { 150 if(which->pending_tasklets_hi.head->owner != tsk_rt(tsk)->inh_task)
138 new_prio = which->pending_tasklets.head->owner; 151 {
139 } 152 new_prio = which->pending_tasklets_hi.head->owner;
140 } 153 }
141 154 }
142 if(litirq_pending_hi_irqoff(which)) 155 else if(pending & LIT_TASKLET_LOW)
143 { 156 {
144 pending = 1; 157 if(which->pending_tasklets.head->owner != tsk_rt(tsk)->inh_task)
145 if(which->pending_tasklets_hi.head->owner != tsk_rt(tsk)->inh_task) 158 {
146 { 159 new_prio = which->pending_tasklets.head->owner;
147 new_prio = which->pending_tasklets_hi.head->owner; 160 }
148 } 161 }
149 } 162 else if(pending & LIT_WORK)
150 163 {
151 if(!pending) 164 struct work_struct* work =
165 list_entry(&which->worklist, struct work_struct, entry);
166 if(work->owner != tsk_rt(tsk)->inh_task)
167 {
168 new_prio = work->owner;
169 }
170 }
171 else
152 { 172 {
153 new_prio = NULL; 173 new_prio = NULL;
154 } 174 }
155 175
176
177 /* inherit the proper priority */
156 if(new_prio != tsk_rt(tsk)->inh_task) 178 if(new_prio != tsk_rt(tsk)->inh_task)
157 { 179 {
158 if(new_prio != NULL) 180 if(new_prio != NULL)
@@ -301,6 +323,30 @@ static void do_lit_tasklet(struct klitirqd_info* which,
301 } 323 }
302} 324}
303 325
326static void do_lit_work(struct klitirqd_info* which)
327{
328 unsigned long flags;
329 work_func_t f;
330 struct work_struct* work;
331
332 // only execute one work-queue item to yield to tasklets.
333 // ...is this a good idea?
334
335 raw_spin_lock_irqsave(&which->lock, flags);
336
337 work = list_entry(&which->worklist, struct work_struct, entry);
338 list_del_init(&work->entry);
339
340 raw_spin_unlock_irqrestore(&which->lock, flags);
341
342 // do the work!
343 work_clear_pending(work);
344 f = work->func;
345 f(work); /* can't touch 'work' after this point,
346 the user may have free'd it. */
347}
348
349
304static void do_litirq(struct klitirqd_info* which) 350static void do_litirq(struct klitirqd_info* which)
305{ 351{
306 u32 pending; 352 u32 pending;
@@ -351,6 +397,15 @@ static void do_litirq(struct klitirqd_info* which)
351 do_lit_tasklet(which, &which->pending_tasklets); 397 do_lit_tasklet(which, &which->pending_tasklets);
352 resched = needs_prio_change(which, &which->pending_tasklets); 398 resched = needs_prio_change(which, &which->pending_tasklets);
353 } 399 }
400
401 if(!resched && (pending & LIT_WORK))
402 {
403 TRACE_CUR("%s: Invoking work object.\n", __FUNCTION__);
404 /* Let's pray this doesn't take a long time to execute and
405 block tasklets. TODO: TEST THIS POSSIBILITY
406 */
407 do_lit_work(which);
408 }
354 } 409 }
355} 410}
356 411
@@ -641,7 +696,7 @@ void __litmus_tasklet_hi_schedule_first(struct tasklet_struct *t, unsigned int k
641 696
642 if(unlikely(k_id >= NR_LITMUS_SOFTIRQD)) 697 if(unlikely(k_id >= NR_LITMUS_SOFTIRQD))
643 { 698 {
644 TRACE("%s: No klitirqd_th%d!\n", __FUNCTION__, k_id); 699 TRACE("%s: No klitirqd_th%u!\n", __FUNCTION__, k_id);
645 BUG(); 700 BUG();
646 } 701 }
647 702
@@ -659,3 +714,43 @@ void __litmus_tasklet_hi_schedule_first(struct tasklet_struct *t, unsigned int k
659 714
660EXPORT_SYMBOL(__litmus_tasklet_hi_schedule_first); 715EXPORT_SYMBOL(__litmus_tasklet_hi_schedule_first);
661 716
717
718static void ___litmus_schedule_work(struct work_struct *w,
719 struct klitirqd_info *which,
720 int wakeup)
721{
722 unsigned long flags;
723
724 raw_spin_lock_irqsave(&which->lock, flags);
725
726 work_pending(w);
727 list_add_tail(&w->entry, &which->worklist);
728
729 which->pending |= LIT_WORK;
730
731 if(wakeup)
732 {
733 wakeup_litirqd_locked(which); /* wakeup the klitirqd */
734 }
735
736 raw_spin_unlock_irqrestore(&which->lock, flags);
737}
738
739void __litmus_schedule_work(struct work_struct *w, unsigned int k_id)
740{
741 if(unlikely(w->owner == NULL) || !is_realtime(w->owner))
742 {
743 TRACE("%s: No owner associated with this work object!\n", __FUNCTION__);
744 BUG();
745 }
746
747 if(unlikely(k_id >= NR_LITMUS_SOFTIRQD))
748 {
749 TRACE("%s: No klitirqd_th%u!\n", k_id);
750 BUG();
751 }
752
753 ___litmus_schedule_work(w, &klitirqds[k_id], 1);
754}
755
756EXPORT_SYMBOL(__litmus_schedule_work);