From 33efb47a220a3edfcb80ddf7aa20d65c26ebf916 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Mon, 18 Nov 2013 23:34:59 +0100 Subject: liblitmus: Add Doxygen documentation for public APIs --- include/common.h | 10 +- include/litmus.h | 321 ++++++++++++++++++++++++++++++++++++++++++++++------ include/migration.h | 70 ++++++++++-- include/tests.h | 59 +++++++++- 4 files changed, 414 insertions(+), 46 deletions(-) (limited to 'include') diff --git a/include/common.h b/include/common.h index d1234ba..fec3721 100644 --- a/include/common.h +++ b/include/common.h @@ -1,7 +1,15 @@ +/** + * @file common.h + * Common miscellaneous functions + */ + #ifndef COMMON_H #define COMMON_H - +/** + * End the current task with a message + * @param msg Message to output before bailing + */ void bail_out(const char* msg); #endif diff --git a/include/litmus.h b/include/litmus.h index dde5469..5a79b7d 100644 --- a/include/litmus.h +++ b/include/litmus.h @@ -1,3 +1,25 @@ +/** + * @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 @@ -18,86 +40,237 @@ extern "C" { #include "migration.h" +/** + * @private + * Number of semaphore protocol object types + */ #define SCHED_LITMUS 6 +/** + * 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); -/* Release-master-aware functions for getting the first +/** + * 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. */ 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 + */ int cluster_to_first_cpu(int cluster, int cluster_size); /* Convenience functions for setting up real-time tasks. * Default behaviors set by init_rt_task_params() 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 + * @param cluster_size Size of the cluster + * @return 0 on success + */ int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size); /* 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) -/* file descriptor attached shared objects support */ +/** + * Locking protocols for allocated shared objects + */ typedef enum { - FMLP_SEM = 0, - SRP_SEM = 1, - MPCP_SEM = 2, - MPCP_VS_SEM = 3, - DPCP_SEM = 4, - PCP_SEM = 5, + 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 */ } 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); } -int litmus_open_lock( - obj_type_t protocol, /* which locking protocol to use, e.g., FMLP_SEM */ - int lock_id, /* numerical id of the lock, user-specified */ - const char* name_space, /* path to a shared file */ - void *config_param); /* any extra info needed by the protocol (such - * as CPU under SRP and PCP), may be NULL */ +/** + * 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); -/* real-time locking protocol support */ +/** + * 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*/ +/***** 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); -/* library functions */ +/** + * 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); /* A real-time program. */ typedef int (*rt_fn_t)(void*); -/* These two functions configure the RT task to use enforced exe budgets. - * Partitioned scheduling: cluster = desired partition, cluster_size = 1 - * Global scheduling: cluster = 0, cluster_size = 0 +/** + * Create a real-time task that enforces exectution budgets + * @param rt_prog Function pointer to real-time task body + * @param arg Pointer to arguments to pass to the pointer in rt_prog + * @param cluster Cluster to schedule this task on. For partitioned scheduling, + * set to the desired partition. For global scheduling, set to 0 + * @param cluster_size Size of the cluster. For partitioned scheduling, set to + * 1, for global scheduling set to 0. + * @param wcet Worst-Case execution time for this task + * @param period Period at which this task should be launched + * @param prio Priority for this task */ int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, lt_t wcet, lt_t period, unsigned int prio); +/** + * Create a real-time task + * @param rt_prog Function pointer to real-time task body + * @param arg Pointer to arguments to pass to the pointer in rt_prog + * @param cluster Cluster to schedule this task on. For partitioned scheduling, + * set to the desired partition. For global scheduling, set to 0 + * @param cluster_size Size of the cluster. For partitioned scheduling, set to + * 1, for global scheduling set to 0. + * @param wcet Worst-Case execution time for this task + * @param period Period at which this task should be launched + * @param prio Priority for this task + * @param cls Task class (???) + */ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, lt_t wcet, lt_t period, unsigned int prio, task_class_t cls); @@ -106,65 +279,149 @@ 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); -/* non-preemptive section support */ +/** + * 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); -/* task system support */ +/***** 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 some number of nanoseconds */ +/** + * Sleep for given time + * @param timeout Sleep time in nanoseconds + * @return 0 on success + */ int lt_sleep(lt_t timeout); -/* CPU time consumed so far in seconds */ +/** + * Obtain CPU time consumed so far + * @return CPU time in seconds + */ double cputime(void); -/* wall-clock time in seconds */ +/** + * Obtain wall-clock time + * @return Wall-clock time in seconds + */ double wctime(void); -/* semaphore allocation */ - +/***** 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); } - -/* syscall overhead measuring */ +/** + * 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: - * atm it is used only by preemption migration overhead code +/** + * 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); diff --git a/include/migration.h b/include/migration.h index 2413e7c..32d933b 100644 --- a/include/migration.h +++ b/include/migration.h @@ -1,24 +1,80 @@ +/** + * @file migration.h + * Functions to migrate tasks to different CPUs, partitions, clusters... + */ typedef int pid_t; -/* obtain the PID of a thread */ +/** + * obtain the PID of a thread (TID) + * @return The PID of a thread + */ pid_t gettid(); -/* Assign a task to a cpu/partition/cluster. - * PRECOND: tid is not yet in real-time mode (it's a best effort task). - * Set tid == 0 to migrate the caller */ +/** + * Migrate and assign a task to a given CPU + * @param tid Process ID for migrated task, 0 for current task + * @param target_cpu ID for CPU to migrate to + * @pre tid is not yet in real-time mode (it's a best effort task) + * @return 0 if successful + */ int be_migrate_thread_to_cpu(pid_t tid, int target_cpu); +/** + * Migrate and assign a task to a given partition + * @param tid Process ID for migrated task, 0 for current task + * @param partition Partition ID to migrate the task to + * @pre tid is not yet in real-time mode (it's a best effort task) + * @return 0 if successful + */ int be_migrate_thread_to_partition(pid_t tid, int partition); -/* If using release master, set cluster_sz to size of largest cluster. tid - * will not be scheduled on release master. */ +/** + * Migrate current task to a given cluster + * @param tid Process ID for migrated task, 0 for current task + * @param cluster Cluster ID to migrate the task to + * @param cluster_sz Size of the cluster to migrate to + * @pre tid is not yet in real-time mode (it's a best effort task) + * @return 0 if successful + * + * If using release master, set cluster_sz to size of largest cluster. tid + * will not be scheduled on release master + */ int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz); -/* set ignore_rm == 1 to include release master in tid's cpu affinity */ +/** + * @private + * set ignore_rm == 1 to include release master in tid's cpu affinity + */ int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz, int ignore_rm); +/** + * Migrate current task to a given CPU + * @param target_cpu ID for CPU to migrate to + * @pre tid is not yet in real-time mode (it's a best effort task) + * @return 0 if successful + */ int be_migrate_to_cpu(int target_cpu); +/** + * Migrate current task to a given partition + * @param partition Partition ID to migrate the task to + * @pre tid is not yet in real-time mode (it's a best effort task) + * @return 0 if successful + */ int be_migrate_to_partition(int partition); +/** + * Migrate current task to a given cluster + * @param cluster Cluster ID to migrate the task to + * @param cluster_sz Size of the cluster to migrate to + * @pre tid is not yet in real-time mode (it's a best effort task) + * @return 0 if successful + */ int be_migrate_to_cluster(int cluster, int cluster_sz); +/** + * Return the number of CPUs currently online + * @return The number of online CPUs + */ int num_online_cpus(); +/** + * @todo Document! + */ int release_master(); diff --git a/include/tests.h b/include/tests.h index 4ca21f8..0c3248e 100644 --- a/include/tests.h +++ b/include/tests.h @@ -1,3 +1,8 @@ +/** + * @file tests.h + * Structs and macro's for use in unit test cases + */ + #ifndef TESTS_H #define TESTS_H @@ -5,6 +10,12 @@ #include #include +/** + * @private + * Print a failure message and exit + * @param fmt Error string + * @param args... Parameters for error string + */ #define fail(fmt, args...) \ do { \ fprintf(stderr, "\n!! TEST FAILURE " fmt \ @@ -16,12 +27,20 @@ exit(200); \ } while (0) +/** + * Assert given predicate, print error if it doesn't hold + * @param predicate Predicate that must hold + */ #define ASSERT(predicate) \ do { \ if (!(predicate)) \ fail("%s", #predicate); \ } while (0) +/** + * Do and trace a syscall + * @param call Syscall to execute + */ #define SYSCALL(call) \ do { \ int __test_ret = (call); \ @@ -29,6 +48,11 @@ fail("%s -> %d, %m", #call, __test_ret); \ } while (0) +/** + * Do and trace a syscall that is expected to fail + * @param expected Expected error code + * @param call Syscall to execute + */ #define SYSCALL_FAILS(expected, call) \ do { \ int __test_ret = (call); \ @@ -37,22 +61,45 @@ #call, __test_ret, #expected); \ } while (0) - +/** + * Function prototype for a single test case + */ typedef void (*testfun_t)(void); +/** + * Test case + */ struct testcase { - testfun_t function; - const char* description; + testfun_t function; /**< Function-pointer to test-case */ + const char* description; /**< Description of test-case */ }; +/** + * Suite containing several test cases + */ struct testsuite { - const char* plugin; - int* testcases; - int num_cases; + const char* plugin; /**< Lock scheduling plugin to use */ + int* testcases; /**< Pointer to array of test-cases + @todo why not struct testcase?*/ + int num_cases; /**< Number of test cases in this suite */ }; +/** + * Function descriptor for test case + * @param function Test name + * @param plugins Set of lock scheduling plugins this test case is applicable + * for, separated by | + * @param description Textual description of the test case + * + * Testcases defined with this macro will get picked up by a python test suite + * generator + */ #define TESTCASE(function, plugins, description) void test_ ## function (void) +/** + * Fork given function body as separate thread + * @param code Function body + */ #define FORK_TASK(code) ({int __pid = fork(); if (__pid == 0) {code; exit(0);}; __pid;}) #endif -- cgit v1.2.2