aboutsummaryrefslogtreecommitdiffstats
path: root/include/litmus.h
blob: 7229a385e68f177114e86028cacb7792b06cccd0 (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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/**
 * @file litmus.h
 * Public API for LITMUS^RT
 */

/**
 * @mainpage
 * The LITMUS^RT patch is a (soft) real-time extension of the Linux kernel with a
 * focus on multiprocessor real-time scheduling and synchronization. The Linux
 * kernel is modified to support the sporadic task model and modular scheduler
 * plugins. Clustered, partitioned, and global scheduling are included, and
 * semi-partitioned scheduling is supported as well.
 *
 * \b liblitmus is the userspace API for LITMUS^RT. It consists of functions to
 * control scheduling protocols and parameters, mutexes as well as functionality
 * to create test suites.
 *
 * Example test programs can be found in \b bin/base_task.c and
 * \b bin/base_task_mt.c . Several test suites are given in the \b tests
 * directory.
 */

#ifndef LITMUS_H
#define LITMUS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/types.h>
#include <stdint.h>

/* Include kernel header.
 * This is required for the rt_param
 * and control_page structures.
 */
#include "litmus/rt_param.h"

#include "asm/cycles.h" /* for null_call() */

#include "migration.h"

#include "litmus/mc2_common.h"

/**
 * @private
 * Number of semaphore protocol object types
 */
#define SCHED_LITMUS 6

#define CACHELINE_SIZE 32
#define INTS_IN_CACHELINE (CACHELINE_SIZE/sizeof(int))
#define CACHELINES_IN_1KB (1024 / sizeof(cacheline_t))
typedef struct cacheline
{
        int line[INTS_IN_CACHELINE];
} __attribute__((aligned(CACHELINE_SIZE))) cacheline_t;

/**
 * Initialise a real-time task param struct
 * @param param Pointer to the struct to initialise
 */
void init_rt_task_param(struct rt_task* param);

/**
 * Set real-time task parameters for given process
 * @param pid PID of process
 * @param param Real-time task parameter struct
 * @return 0 on success
 */
int set_rt_task_param(pid_t pid, struct rt_task* param);

/**
 * Get real-time task parameters for given process
 * @param pid PID of process
 * @param param Real-time task parameter struct to fill
 * @return 0 on success
 */
int get_rt_task_param(pid_t pid, struct rt_task* param);

/**
 * Convert a partition number to a CPU identifier
 * @param partition Partition number
 * @return CPU identifier for given partition
 *
 *  Release-master-aware functions for getting the first
 * CPU in a particular cluster or partition. Use these
 * to set rt_task::cpu for cluster/partitioned scheduling.
 *
 * \deprecated{Use domain_to_first_cpu() in new code.}
 */
int partition_to_cpu(int partition);

/**
 * For given cluster, return the identifier for the first associated CPU
 * @param cluster Identifier of the cluster
 * @param cluster_size Size for this cluster
 * @return Identifier for the first associated CPU
 *
 * \deprecated{Use domain_to_first_cpu() in new code.}
 */
int cluster_to_first_cpu(int cluster, int cluster_size);


/* The following three functions are convenience functions for setting up
 * real-time tasks.  Default behaviors set by init_rt_task_params() are used.
 * Also sets affinity masks for clustered/partitions functions. Time units in
 * nanoseconds. */
/**
 * Set up a sporadic task with global scheduling
 * @param e_ns Execution time in nanoseconds
 * @param p_ns Period in nanoseconds
 * @return 0 on success
 */
int sporadic_global(lt_t e_ns, lt_t p_ns);

/**
 * Set up a sporadic task with partitioned scheduling
 * @param e_ns Execution time in nanoseconds
 * @param p_ns Period in nanoseconds
 * @param partition Identifier for partition to add this task to
 * @return 0 on success
 */
int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition);

/**
 * Set up a sporadic task with clustered scheduling
 * @param e_ns Execution time in nanoseconds
 * @param p_ns Period in nanoseconds
 * @param cluster Cluster to add this task to
 * @return 0 on success
 */
int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster);

/* simple time unit conversion macros */
/** Convert seconds to nanoseconds
 * @param s Time units in seconds */
#define s2ns(s)   ((s)*1000000000LL)

/** Convert seconds to microseconds
  * @param s Time units in seconds */
#define s2us(s)   ((s)*1000000LL)

/** Convert seconds to milliseconds
  * @param s Time units in seconds */
#define s2ms(s)   ((s)*1000LL)

/** Convert milliseconds to nanoseconds
  * @param ms Time units in milliseconds */
#define ms2ns(ms) ((ms)*1000000LL)

/** Convert milliseconds to microseconds
  * @param ms Time units in milliseconds */
#define ms2us(ms) ((ms)*1000LL)

/** Convert microseconds to nanoseconds
  * @param us Time units in microseconds */
#define us2ns(us) ((us)*1000LL)
#define ns2s(ns)  ((ns)/1000000000LL)
#define ns2ms(ns) ((ns)/1000000LL)
#define ns2us(ns) ((ns)/1000LL)
#define us2ms(us) ((us)/1000LL)
#define us2s(us)  ((us)/1000000LL)
#define ms2s(ms)  ((ms)/1000LL)

/**
 * Locking protocols for allocated shared objects
 */
typedef enum  {
	FMLP_SEM	= 0, /**< Fifo-based Multiprocessor Locking Protocol */
	SRP_SEM		= 1, /**< Stack Resource Protocol */
	MPCP_SEM	= 2, /**< Multiprocessor Priority Ceiling Protocol */
	MPCP_VS_SEM	= 3, /**< Multiprocessor Priority Ceiling Protocol with
						  Virtual Spinning */
	DPCP_SEM	= 4, /**< Distributed Priority Ceiling Protocol */
	PCP_SEM		= 5, /**< Priority Ceiling Protocol */
	DFLP_SEM	= 6, /**< Distributed FIFO Locking Protocol */
} obj_type_t;

/**
 * For given protocol name, return semaphore object type id
 * @param name String representation of protocol name
 * @return Object type ID as integer
 */
int lock_protocol_for_name(const char* name);
/**
 * For given semaphore object type id, return the name of the protocol
 * @param id Semaphore object type ID
 * @return Name of the locking protocol
 */
const char* name_for_lock_protocol(int id);

/**
 * @private
 * Do a syscall for opening a generic lock
 */
int od_openx(int fd, obj_type_t type, int obj_id, void* config);
/**
 * Close a lock, given its object descriptor
 * @param od Object descriptor for lock to close
 * @return 0 Iff the lock was successfully closed
 */
int od_close(int od);

/**
 * @private
 * Generic lock opening method
 */
static inline int od_open(int fd, obj_type_t type, int obj_id)
{
	return od_openx(fd, type, obj_id, 0);
}

/**
 * public:
 * Open a lock, mark it used by the invoking thread
 * @param protocol Desired locking protocol
 * @param lock_id Name of the lock, user-specified numerical id
 * @param name_space Path to a shared file
 * @param config_param Any extra info needed by the protocol (like CPU for SRP
 * or PCP), may be NULL
 * @return Object descriptor for this lock
 */
int litmus_open_lock(obj_type_t protocol, int lock_id, const char* name_space,
		void *config_param);

/**
 * Obtain lock
 * @param od Object descriptor obtained by litmus_open_lock()
 * @return 0 iff the lock was opened successfully
 */
int litmus_lock(int od);
/**
 * Release lock
 * @param od Object descriptor obtained by litmus_open_lock()
 * @return 0 iff the lock was released successfully
 */
int litmus_unlock(int od);

/***** job control *****/
/**
 * @todo Doxygen
 */
int get_job_no(unsigned int* job_no);
/**
 * @todo Doxygen
 */
int wait_for_job_release(unsigned int job_no);
/**
 * Sleep until next period
 * @return 0 on success
 */
int sleep_next_period(void);

/**
 * Initialises real-time properties for the entire program
 * @return 0 on success
 */
int  init_litmus(void);
/**
 * Initialises real-time properties for current thread
 * @return 0 on success
 */
int  init_rt_thread(void);
/**
 * Cleans up real-time properties for the entire program
 */
void exit_litmus(void);

/*	per-task modes */
enum rt_task_mode_t {
	BACKGROUND_TASK = 0,
	LITMUS_RT_TASK  = 1
};
/**
 * Set the task mode for current thread
 * @param target_mode Desired mode, see enum rt_task_mode_t for valid values
 * @return 0 iff taskmode was set correctly
 */
int task_mode(int target_mode);

/**
 * @todo Document
 */
void show_rt_param(struct rt_task* tp);
/**
 * @todo Document
 */
task_class_t str2class(const char* str);

/**
 * Enter non-preemtpive section for current thread
 */
void enter_np(void);
/**
 * Exit non-preemtpive section for current thread
 */
void exit_np(void);
/**
 * Find out whether task should have preempted
 * @return 1 iff the task was requested to preempt while running non-preemptive
 */
int  requested_to_preempt(void);

/* pgm support */
void enter_pgm_wait(void);
void exit_pgm_wait(void);
void enter_pgm_send(void);
void exit_pgm_send(void);

/***** Task System support *****/
/**
 * Wait until task master releases all real-time tasks
 * @return 0 Iff task was successfully released
 */
int wait_for_ts_release(void);
/**
 * Release all tasks in the task system
 * @param delay Time to wait
 * @return Number of tasks released
 *
 * Used by a task master to release all threads after each of them has been
 * set up.
 */
int release_ts(lt_t *delay);
/**
 * Obtain the number of currently waiting tasks
 * @return The number of waiting tasks
 */
int get_nr_ts_release_waiters(void);
/**
 * @todo Document
 */
int read_litmus_stats(int *ready, int *total);

/**
 * Sleep for given time
 * @param timeout Sleep time in nanoseconds
 * @return 0 on success
 */
int lt_sleep(lt_t timeout);

/**
 * Obtain CPU time consumed so far
 * @return CPU time in seconds
 */
double cputime(void);

/**
 * Obtain wall-clock time
 * @return Wall-clock time in seconds
 */
double wctime(void);

/***** semaphore allocation ******/
/**
 * Allocate a semaphore following the FMLP protocol
 * @param fd File descriptor to associate lock with
 * @param name Name of the lock, user-chosen integer
 * @return Object descriptor for given lock
 */
static inline int open_fmlp_sem(int fd, int name)
{
	return od_open(fd, FMLP_SEM, name);
}

/**
 * Allocate a semaphore following the SRP protocol
 * @param fd File descriptor to associate lock with
 * @param name Name of the lock, user-chosen integer
 * @return Object descriptor for given lock
 */
static inline int open_srp_sem(int fd, int name)
{
	return od_open(fd, SRP_SEM, name);
}

/**
 * Allocate a semaphore following the PCP protocol
 * @param fd File descriptor to associate lock with
 * @param name Name of the lock, user-chosen integer
 * @param cpu CPU to associate this lock with
 * @return Object descriptor for given lock
 */
static inline int open_pcp_sem(int fd, int name, int cpu)
{
	return od_openx(fd, PCP_SEM, name, &cpu);
}

/**
 * Allocate a semaphore following the MPCP protocol
 * @param fd File descriptor to associate lock with
 * @param name Name of the lock, user-chosen integer
 * @return Object descriptor for given lock
 */
static inline int open_mpcp_sem(int fd, int name)
{
	return od_open(fd, MPCP_SEM, name);
}

/**
 * Allocate a semaphore following the DPCP protocol
 * @param fd File descriptor to associate lock with
 * @param name Name of the lock, user-chosen integer
 * @param cpu CPU to associate this lock with
 * @return Object descriptor for given lock
 */
static inline int open_dpcp_sem(int fd, int name, int cpu)
{
	return od_openx(fd, DPCP_SEM, name, &cpu);
}


/**
 * Allocate a semaphore following the DFLP protocol
 * @param fd File descriptor to associate lock with
 * @param name Name of the lock, user-chosen integer
 * @param cpu CPU to associate this lock with
 * @return Object descriptor for given lock
 */
static inline int open_dflp_sem(int fd, int name, int cpu)
{
	return od_openx(fd, DFLP_SEM, name, &cpu);
}

/**
 * Do nothing as a syscall
 * @param timestamp Cyclecount before calling
 * Can be used for syscall overhead measuring */
int null_call(cycles_t *timestamp);

/**
 * Get control page:
 * @return Pointer to the current tasks control page
 *
 * Atm it is used only by preemption migration overhead code,
 * but it is very general and can be used for different purposes
 */
struct control_page* get_ctrl_page(void);

int reservation_create(int rtype, void *config);

int reservation_destroy(unsigned int reservation_id, int cpu);

int set_mc2_task_param(pid_t pid, struct mc2_task* param);

int set_page_color(int cpu);

int test_call(unsigned int param);

int run_bench(int type, int size, cacheline_t *src, cacheline_t *dst, lt_t __user *ts);

int lock_buffer(void* vaddr, size_t size, unsigned int lock_way, unsigned int unlock_way);

#ifdef __cplusplus
}
#endif
#endif