aboutsummaryrefslogtreecommitdiffstats
path: root/include/litmus/litmus_softirq.h
blob: cfef081874649f197b35aab33b2c97acf4e287de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#ifndef __LITMUS_SOFTIRQ_H
#define __LITMUS_SOFTIRQ_H

#include <linux/interrupt.h>
#include <linux/workqueue.h>

/*
   Threaded tasklet/workqueue handling for Litmus.
   Items are scheduled in the following order: hi-tasklet,
   lo-tasklet, workqueue.  Items are scheduled in FIFO order
   within each of these classes.

   klmirqd assumes the priority of the owner of the
   tasklet when the tasklet is next to execute.

   The base-priority of a klimirqd thread is below all regular
   real-time tasks, but above all other Linux scheduling
   classes (klmirqd threads are within the SHCED_LITMUS class).
   Regular real-time tasks may increase the priority of
   a klmirqd thread, but klmirqd is unaware of this
   (this was not the case in prior incarnations of klmirqd).
 */


/* Initialize klmirqd */
void init_klmirqd(void);

/* Raises a flag to tell klmirqds to terminate.
 Termination is async, so some threads may be running
 after function return. */
void kill_klmirqd(void);

void kill_klmirqd_thread(struct task_struct* klmirqd_thread);

/* Returns 1 if all NR_LITMUS_SOFTIRQD klitirqs are ready
 to handle tasklets. 0, otherwise.*/
int klmirqd_is_ready(void);

/* Returns 1 if no NR_LITMUS_SOFTIRQD klitirqs are ready
 to handle tasklets. 0, otherwise.*/
int klmirqd_is_dead(void);


typedef int (*klmirqd_cb_t) (void *arg);

typedef struct
{
	klmirqd_cb_t func;
	void* arg;
} klmirqd_callback_t;

/* Launches a klmirqd thread with the provided affinity.

   Actual launch of threads is deffered to kworker's
   workqueue, so daemons will likely not be immediately
   running when this function returns, though the required
   data will be initialized.

   cpu == -1 for no affinity

   provide a name at most 31 (32, + null terminator) characters long.
   name == NULL for a default name.  (all names are appended with
   base-CPU affinity)
 */
#define MAX_KLMIRQD_NAME_LEN 31
int launch_klmirqd_thread(char* name, int cpu, klmirqd_callback_t* cb);


/* Flushes all pending work out to the OS for regular
 * tasklet/work processing.
 */
void flush_pending(struct task_struct* klmirqd_thread);

extern int __litmus_tasklet_schedule(
        struct tasklet_struct *t,
		struct task_struct *klmirqd_thread);

/* schedule a tasklet on klmirqd #k_id */
static inline int litmus_tasklet_schedule(
    struct tasklet_struct *t,
    struct task_struct *klmirqd_thread)
{
	int ret = 0;
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
		ret = __litmus_tasklet_schedule(t, klmirqd_thread);
	}
	return(ret);
}

/* for use by __tasklet_schedule() */
static inline int _litmus_tasklet_schedule(
    struct tasklet_struct *t,
    struct task_struct *klmirqd_thread)
{
    return(__litmus_tasklet_schedule(t, klmirqd_thread));
}




extern int __litmus_tasklet_hi_schedule(struct tasklet_struct *t,
                                        struct task_struct *klmirqd_thread);

/* schedule a hi tasklet on klmirqd #k_id */
static inline int litmus_tasklet_hi_schedule(struct tasklet_struct *t,
                                             struct task_struct *klmirqd_thread)
{
	int ret = 0;
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
		ret = __litmus_tasklet_hi_schedule(t, klmirqd_thread);
	}
	return(ret);
}

/* for use by __tasklet_hi_schedule() */
static inline int _litmus_tasklet_hi_schedule(struct tasklet_struct *t,
                                              struct task_struct *klmirqd_thread)
{
    return(__litmus_tasklet_hi_schedule(t, klmirqd_thread));
}





extern int __litmus_tasklet_hi_schedule_first(
    struct tasklet_struct *t,
    struct task_struct *klmirqd_thread);

/* schedule a hi tasklet on klmirqd #k_id on next go-around */
/* PRECONDITION: Interrupts must be disabled. */
static inline int litmus_tasklet_hi_schedule_first(
    struct tasklet_struct *t,
    struct task_struct *klmirqd_thread)
{
	int ret = 0;
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
		ret = __litmus_tasklet_hi_schedule_first(t, klmirqd_thread);
	}
	return(ret);
}

/* for use by __tasklet_hi_schedule_first() */
static inline int _litmus_tasklet_hi_schedule_first(
    struct tasklet_struct *t,
    struct task_struct *klmirqd_thread)
{
    return(__litmus_tasklet_hi_schedule_first(t, klmirqd_thread));
}



//////////////

extern int __litmus_schedule_work(
	struct work_struct* w,
	struct task_struct *klmirqd_thread);

static inline int litmus_schedule_work(
	struct work_struct* w,
	struct task_struct *klmirqd_thread)
{
	return(__litmus_schedule_work(w, klmirqd_thread));
}

#endif