From 6d3c2bd5adbcb6b3ac8fbc8c80e8913d7a68441c Mon Sep 17 00:00:00 2001
From: Glenn Elliott <gelliott@cs.unc.edu>
Date: Wed, 19 Feb 2014 16:30:21 -0500
Subject: [PATCH] ECRTS14 PGM^RT patch for liblitmus

---
 Makefile            |    2 +-
 bin/rt_launch.c     |   10 ++---
 bin/rtspin.c        |   13 ++++---
 include/litmus.h    |   34 ++++++++++-------
 include/migration.h |   22 ++++++-----
 src/kernel_iface.c  |   59 ++++++++++++++++++++++++++++-
 src/litmus.c        |   11 +++---
 src/migration.c     |  105 +++++++++++++++++++++++----------------------------
 src/task.c          |    9 +++--
 9 files changed, 161 insertions(+), 104 deletions(-)

diff --git a/Makefile b/Makefile
index e8003e8..39a79a7 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ LITMUS_KERNEL ?= ../litmus-rt
 # Internal configuration.
 
 # compiler flags
-flags-debug    = -O2 -Wall -Werror -g -Wdeclaration-after-statement
+flags-debug    = -Os -march=native -Wall -Werror -Wdeclaration-after-statement
 flags-api      = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE
 
 # architecture-specific flags
diff --git a/bin/rt_launch.c b/bin/rt_launch.c
index 93f10d5..5e29893 100644
--- a/bin/rt_launch.c
+++ b/bin/rt_launch.c
@@ -42,7 +42,7 @@ void usage(char *error) {
 }
 
 
-#define OPTSTR "p:z:c:vwq:"
+#define OPTSTR "p:c:vwq:"
 
 int main(int argc, char** argv) 
 {
@@ -51,7 +51,6 @@ int main(int argc, char** argv)
 	lt_t period;
 	int migrate = 0;
 	int cluster = 0;
-	int cluster_size = 1;
 	int opt;
 	int verbose = 0;
 	int wait = 0;
@@ -71,9 +70,6 @@ int main(int argc, char** argv)
 			cluster = atoi(optarg);
 			migrate = 1;
 			break;
-		case 'z':
-			cluster_size = atoi(optarg);
-			break;
 		case 'q':
 			priority = atoi(optarg);
 			if (!litmus_is_valid_fixed_prio(priority))
@@ -114,11 +110,11 @@ int main(int argc, char** argv)
 	info.argv      = argv + optind + 2;
 	info.wait      = wait;
 	if (migrate) {
-		ret = be_migrate_to_cluster(cluster, cluster_size);
+		ret = be_migrate_to_domain(cluster);
 		if (ret < 0)
 			bail_out("could not migrate to target partition or cluster");
 	}
-	ret = __create_rt_task(launch, &info, cluster, cluster_size, wcet, period,
+	ret = __create_rt_task(launch, &info, cluster, wcet, period,
 				priority, class);
 
 
diff --git a/bin/rtspin.c b/bin/rtspin.c
index 167741d..b518574 100644
--- a/bin/rtspin.c
+++ b/bin/rtspin.c
@@ -184,7 +184,7 @@ static int job(double exec_time, double program_end, int lock_od, double cs_leng
 	}
 }
 
-#define OPTSTR "p:z:c:wlveo:f:s:q:X:L:Q:"
+#define OPTSTR "p:c:wlveo:f:s:q:X:L:Q:n:"
 int main(int argc, char** argv)
 {
 	int ret;
@@ -192,9 +192,9 @@ int main(int argc, char** argv)
 	lt_t period;
 	double wcet_ms, period_ms;
 	unsigned int priority = LITMUS_LOWEST_PRIORITY;
+	int split_factor = 1;
 	int migrate = 0;
 	int cluster = 0;
-	int cluster_size = 1;
 	int opt;
 	int wait = 0;
 	int test_loop = 0;
@@ -226,8 +226,8 @@ int main(int argc, char** argv)
 			cluster = atoi(optarg);
 			migrate = 1;
 			break;
-		case 'z':
-			cluster_size = atoi(optarg);
+		case 'n':
+			split_factor = atoi(optarg);
 			break;
 		case 'q':
 			priority = atoi(optarg);
@@ -326,7 +326,7 @@ int main(int argc, char** argv)
 		duration += period_ms * 0.001 * (num_jobs - 1);
 
 	if (migrate) {
-		ret = be_migrate_to_cluster(cluster, cluster_size);
+		ret = be_migrate_to_domain(cluster);
 		if (ret < 0)
 			bail_out("could not migrate to target partition or cluster.");
 	}
@@ -334,12 +334,13 @@ int main(int argc, char** argv)
 	init_rt_task_param(&param);
 	param.exec_cost = wcet;
 	param.period = period;
+	param.split = split_factor;
 	param.priority = priority;
 	param.cls = class;
 	param.budget_policy = (want_enforcement) ?
 			PRECISE_ENFORCEMENT : NO_ENFORCEMENT;
 	if (migrate)
-		param.cpu = cluster_to_first_cpu(cluster, cluster_size);
+		param.cpu = domain_to_first_cpu(cluster);
 	ret = set_rt_task_param(gettid(), &param);
 	if (ret < 0)
 		bail_out("could not setup rt task params");
diff --git a/include/litmus.h b/include/litmus.h
index ef3fef3..2b0d5c2 100644
--- a/include/litmus.h
+++ b/include/litmus.h
@@ -24,20 +24,13 @@ void init_rt_task_param(struct rt_task* param);
 int set_rt_task_param(pid_t pid, struct rt_task* param);
 int get_rt_task_param(pid_t pid, struct rt_task* param);
 
-/* 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);
-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. */
 int sporadic_global(lt_t e_ns, lt_t p_ns);
 int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition);
-int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size);
+int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster);
 
 /* simple time unit conversion macros */
 #define s2ns(s)   ((s)*1000000000LL)
@@ -47,6 +40,13 @@ int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size);
 #define ms2us(ms) ((ms)*1000LL)
 #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)
+
 /* file descriptor attached shared objects support */
 typedef enum  {
 	FMLP_SEM	= 0,
@@ -54,7 +54,7 @@ typedef enum  {
 	MPCP_SEM	= 2,
 	MPCP_VS_SEM	= 3,
 	DPCP_SEM	= 4,
-	PCP_SEM         = 5,
+	PCP_SEM		= 5,
 } obj_type_t;
 
 int lock_protocol_for_name(const char* name);
@@ -71,7 +71,7 @@ static inline int od_open(int fd, obj_type_t type, int obj_id)
 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* namespace,	/* path to a shared file */
+	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 */
 
@@ -93,12 +93,12 @@ void exit_litmus(void);
 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
+ * Partitioned/clustered scheduling: cluster = desired partition
+ * Global scheduling: cluster = 0
  */
-int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size,
+int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster,
 			lt_t wcet, lt_t period, unsigned int prio);
-int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size,
+int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster,
 			lt_t wcet, lt_t period, unsigned int prio, task_class_t cls);
 
 /*	per-task modes */
@@ -116,6 +116,12 @@ void enter_np(void);
 void exit_np(void);
 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 */
 int wait_for_ts_release(void);
 int release_ts(lt_t *delay);
diff --git a/include/migration.h b/include/migration.h
index 2413e7c..757dd51 100644
--- a/include/migration.h
+++ b/include/migration.h
@@ -4,21 +4,25 @@ typedef int pid_t;
 /* obtain the PID of a thread */
 pid_t gettid();
 
-/* Assign a task to a cpu/partition/cluster.
+/* Assign a task to a cpu.
  * PRECOND: tid is not yet in real-time mode (it's a best effort task).
  * Set tid == 0 to migrate the caller */
 int be_migrate_thread_to_cpu(pid_t tid, int target_cpu);
-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. */
-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 */
-int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz, int ignore_rm);
+/* Assign a task to a scheduling domain (cluster, partition, etc.)
+ * PRECOND: (1) tid is not yet in real-time mode.
+ *          (2) plugin that supports /proc/litmus/domain is active.
+ */
+int be_migrate_thread_to_cluster(pid_t tid, int domain);
 
 int be_migrate_to_cpu(int target_cpu);
-int be_migrate_to_partition(int partition);
-int be_migrate_to_cluster(int cluster, int cluster_sz);
+int be_migrate_to_domain(int domain);
 
 int num_online_cpus();
 int release_master();
+int domain_to_cpus(int domain, unsigned long long int* mask);
+int cpu_to_domains(int cpu, unsigned long long int* mask);
+
+/* Needed while rt_task::cpu field is in use.
+ * XXX: Update Litmus to not use rt_task::cpu */
+int domain_to_first_cpu(int domain);
diff --git a/src/kernel_iface.c b/src/kernel_iface.c
index ca874ff..1aa941d 100644
--- a/src/kernel_iface.c
+++ b/src/kernel_iface.c
@@ -2,7 +2,7 @@
 #include <sys/fcntl.h> /* for O_RDWR */
 #include <sys/unistd.h>
 #include <sched.h> /* for sched_yield() */
-
+#include <assert.h>
 
 #include <stdio.h>
 
@@ -140,6 +140,63 @@ int requested_to_preempt(void)
 	return (likely(ctrl_page != NULL) && ctrl_page->sched.np.preempt);
 }
 
+
+void enter_pgm_wait(void)
+{
+	if (likely(ctrl_page != NULL) || init_kernel_iface() == 0) {
+		assert(!ctrl_page->pgm_waiting);
+		ctrl_page->pgm_waiting = 1;
+		__sync_synchronize();
+	}
+	else {
+		fprintf(stderr, "enter_pgm_wait: control page not mapped!\n");
+	}
+}
+
+void exit_pgm_wait(void)
+{
+	if (likely(ctrl_page != NULL)) {
+		assert(ctrl_page->pgm_waiting);
+		ctrl_page->pgm_waiting = 0;
+		__sync_synchronize();
+	}
+	else {
+		fprintf(stderr, "exit_pgm_wait: control page not mapped!\n");
+	}
+}
+
+void enter_pgm_send(void)
+{
+	if (likely(ctrl_page != NULL) || init_kernel_iface() == 0) {
+		assert(!ctrl_page->pgm_sending);
+		ctrl_page->pgm_sending = 1; /* we will become boosted if
+		                               anyone tries to preempt us. */
+		__sync_synchronize();
+	}
+	else {
+		fprintf(stderr, "enter_pgm_send: control page not mapped!\n");
+	}
+}
+
+void exit_pgm_send(void)
+{
+	if (likely(ctrl_page != NULL)) {
+		assert(ctrl_page->pgm_sending);
+
+		ctrl_page->pgm_satisfied = 1;
+		__sync_synchronize();
+
+		/* re-eval priority. Should clear pgm_sending and pgm_satisfied. */
+		sched_yield();
+
+		/* double check that Litmus is doing its job */
+		assert(!ctrl_page->pgm_sending && !ctrl_page->pgm_satisfied);
+	}
+	else {
+		fprintf(stderr, "exit_pgm_send: control page not mapped!\n");
+	}
+}
+
 /* init and return a ptr to the control page for
  * preemption and migration overhead analysis
  *
diff --git a/src/litmus.c b/src/litmus.c
index dce8e1b..a05c180 100644
--- a/src/litmus.c
+++ b/src/litmus.c
@@ -103,6 +103,7 @@ void init_rt_task_param(struct rt_task* tp)
 	tp->priority = LITMUS_LOWEST_PRIORITY;
 	tp->budget_policy = NO_ENFORCEMENT;
 	tp->release_policy = TASK_SPORADIC;
+	tp->split = 1;
 }
 
 task_class_t str2class(const char* str)
@@ -135,7 +136,7 @@ int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition)
 	int ret;
 	struct rt_task param;
 
-	ret = be_migrate_to_partition(partition);
+	ret = be_migrate_to_domain(partition);
 	check("be_migrate_to_partition()");
 	if (ret != 0)
 		return ret;
@@ -143,17 +144,17 @@ int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition)
 	init_rt_task_param(&param);
 	param.exec_cost = e_ns;
 	param.period = p_ns;
-	param.cpu = partition_to_cpu(partition);
+	param.cpu = domain_to_first_cpu(partition);
 
 	return set_rt_task_param(gettid(), &param);
 }
 
-int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size)
+int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster)
 {
 	int ret;
 	struct rt_task param;
 
-	ret = be_migrate_to_cluster(cluster, cluster_size);
+	ret = be_migrate_to_domain(cluster);
 	check("be_migrate_to_cluster()");
 	if (ret != 0)
 		return ret;
@@ -161,7 +162,7 @@ int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size)
 	init_rt_task_param(&param);
 	param.exec_cost = e_ns;
 	param.period = p_ns;
-	param.cpu = cluster_to_first_cpu(cluster, cluster_size);
+	param.cpu = domain_to_first_cpu(cluster);
 
 	return set_rt_task_param(gettid(), &param);
 }
diff --git a/src/migration.c b/src/migration.c
index 5de81d5..195eeba 100644
--- a/src/migration.c
+++ b/src/migration.c
@@ -27,31 +27,48 @@ int num_online_cpus()
 	return sysconf(_SC_NPROCESSORS_ONLN);
 }
 
-int partition_to_cpu(int partition)
+static int read_mapping(int idx, const char* which, unsigned long long int* mask)
 {
-	int cpu = partition;
-	int master = release_master();
-	if (master != -1 && master <= cpu) {
-		++cpu; /* skip over the release master */
+	int	ret = -1;
+	char buf[129] = {0};
+	char fname[80] = {0};
+
+	if (num_online_cpus() > 64) {
+		/* XXX: Support more than 64 CPUs.
+		 * User can still set appropriate values directly. */
+		goto out;
 	}
-	return cpu;
-}
 
-int cluster_to_first_cpu(int cluster, int cluster_sz)
-{
-	int first_cpu;
-	int master;
+	snprintf(fname, sizeof(fname), "/proc/litmus/%s/%d", which, idx);
 
-	if (cluster_sz == 1)
-		return partition_to_cpu(cluster);
+	ret = read_file(fname, &buf, sizeof(buf)-1);
+	if (ret <= 0)
+		goto out;
 
-	master = release_master();
-	first_cpu = cluster * cluster_sz;
+	*mask = strtoull(buf, NULL, 16);
+	ret = 0;
+
+out:
+	return ret;
+}
 
-	if (master == first_cpu)
-		++first_cpu;
+int domain_to_cpus(int domain, unsigned long long int* mask)
+{
+	return read_mapping(domain, "domains", mask);
+}
 
-	return first_cpu;
+int cpu_to_domains(int cpu, unsigned long long int* mask)
+{
+	return read_mapping(cpu, "cpus", mask);
+}
+
+int domain_to_first_cpu(int domain)
+{
+	unsigned long long int mask;
+	int ret = domain_to_cpus(domain, &mask);
+	if(ret == 0)
+		return (ffsll(mask)-1);
+	return ret;
 }
 
 int be_migrate_thread_to_cpu(pid_t tid, int target_cpu)
@@ -89,44 +106,29 @@ int be_migrate_thread_to_cpu(pid_t tid, int target_cpu)
 	return ret;
 }
 
-int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz)
-{
-	return __be_migrate_thread_to_cluster(tid, cluster, cluster_sz, 0);
-}
-
-int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz,
-						 int ignore_rm)
+int be_migrate_thread_to_domain(pid_t tid, int domain)
 {
-	int first_cpu = cluster * cluster_sz; /* first CPU in cluster */
-	int last_cpu = first_cpu + cluster_sz - 1;
-	int master;
-	int num_cpus;
+	int	ret, num_cpus;
 	cpu_set_t *cpu_set;
 	size_t sz;
-	int i;
-	int ret;
+	unsigned long long int mask;
 
-	/* TODO: Error check to make sure that tid is not a real-time task. */
+	ret = domain_to_cpus(domain, &mask);
+	if (ret != 0)
+		return ret;
 
-	if (cluster_sz == 1) {
-		/* we're partitioned */
-		return be_migrate_thread_to_partition(tid, cluster);
-	}
-
-	master = (ignore_rm) ? -1 : release_master();
 	num_cpus = num_online_cpus();
-
-	if (num_cpus == -1 || last_cpu >= num_cpus || first_cpu < 0)
+	if (num_cpus == -1)
 		return -1;
 
 	cpu_set = CPU_ALLOC(num_cpus);
 	sz = CPU_ALLOC_SIZE(num_cpus);
 	CPU_ZERO_S(sz, cpu_set);
 
-	for (i = first_cpu; i <= last_cpu; ++i) {
-		if (i != master) {
-			CPU_SET_S(i, sz, cpu_set);
-		}
+	while(mask) {
+		int idx = ffsll(mask) - 1;
+		CPU_SET_S(idx, sz, cpu_set);
+		mask &= ~(1ull<<idx);
 	}
 
 	/* apply to caller */
@@ -140,23 +142,12 @@ int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz,
 	return ret;
 }
 
-int be_migrate_thread_to_partition(pid_t tid, int partition)
-{
-	return be_migrate_thread_to_cpu(tid, partition_to_cpu(partition));
-}
-
-
 int be_migrate_to_cpu(int target_cpu)
 {
 	return be_migrate_thread_to_cpu(0, target_cpu);
 }
 
-int be_migrate_to_cluster(int cluster, int cluster_sz)
-{
-	return be_migrate_thread_to_cluster(0, cluster, cluster_sz);
-}
-
-int be_migrate_to_partition(int partition)
+int be_migrate_to_domain(int domain)
 {
-	return be_migrate_thread_to_partition(0, partition);
+	return be_migrate_thread_to_domain(0, domain);
 }
diff --git a/src/task.c b/src/task.c
index 5f2fa26..636e5fe 100644
--- a/src/task.c
+++ b/src/task.c
@@ -40,15 +40,16 @@ int __launch_rt_task(rt_fn_t rt_prog, void *rt_arg, rt_setup_fn_t setup,
 	return rt_task;
 }
 
-int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size,
+int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster,
 		lt_t wcet, lt_t period, unsigned int priority, task_class_t class)
 {
 	struct rt_task params;
-	params.cpu       = cluster_to_first_cpu(cluster, cluster_size);
+	params.cpu       = domain_to_first_cpu(cluster);
 	params.period    = period;
 	params.exec_cost = wcet;
 	params.cls       = class;
 	params.phase     = 0;
+	params.split	 = 1;
 	params.priority = priority;
 	/* enforce budget for tasks that might not use sleep_next_period() */
 	params.budget_policy = QUANTUM_ENFORCEMENT;
@@ -57,10 +58,10 @@ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size,
 				(rt_setup_fn_t) set_rt_task_param, &params);
 }
 
-int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size,
+int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster,
 		lt_t wcet, lt_t period, unsigned int prio)
 {
-	return __create_rt_task(rt_prog, arg, cluster, cluster_size, wcet, period,
+	return __create_rt_task(rt_prog, arg, cluster, wcet, period,
 				prio, RT_CLASS_HARD);
 }
 
-- 
1.7.10.4

