sched: Slightly fix up tests/prov

prov now takes core lists (e.g. "1,3-5") instead of just a core at a time,
just like perf.

prov also can spawn processes, just like perf and strace.

Other than that, it's still in need of an overhaul.  It doesn't let you
provision multiple resource types to a process at a time, such as cores and
memory.  'show' mode still uses the kernel hack.  Stylistically, it could
use some work too.

For now, since we only provision cores, it's OK.  When we update the kernel
interface, we'll update prov too.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/tests/prov.c b/tests/prov.c
index cc2cc4f..ef2ee64 100644
--- a/tests/prov.c
+++ b/tests/prov.c
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <argp.h>
@@ -5,9 +7,6 @@
 #include <parlib/parlib.h>
 #include <parlib/vcore.h>
 
-const char *argp_program_version = "prov v0.1475263";
-const char *argp_program_bug_address = "<akaros+subscribe@googlegroups.com>";
-
 static char doc[] = "prov -- control for provisioning resources";
 static char args_doc[] = "-p PID\n-c PROGRAM [ARGS]\nPROGRAM [ARGS]\n"
                          "-- PROGRAM [ARGS]\n-s";
@@ -31,9 +30,8 @@
 	{0, 0, 0, 0, "Call with exactly one of these when changing a provision:"},
 	{"value",		'v', "VAL",	0, "Type-specific value, passed to the kernel"},
 	{"max",			'm', 0,		0, "Provision all resources of the given type"},
-	{0, 0, 0, OPTION_DOC, "Cores are provisioned to processes, so the value is "
-	                      "a specific pcore id.  To undo a core's "
-	                      "provisioning, pass in pid=0."},
+	{0, 0, 0, OPTION_DOC, "VAL for cores is a list, e.g. -v 1,3-5,9"},
+	{0, 0, 0, OPTION_DOC, "To undo a core's provisioning, pass in pid=0."},
 	{ 0 }
 };
 
@@ -42,13 +40,14 @@
 #define PROV_MODE_SHOW			3
 
 struct prog_args {
-	char						*cmd;
-	char						**cmd_args;
+	char						**cmd_argv;
+	int							cmd_argc;
 	int							mode;		/* PROV_MODE_ETC */
 	pid_t						pid;
 	char						res_type;	/* cores (c), ram (m), etc */
-	long						res_val;	/* type-specific value */
-	int							max;
+	char						*res_val;	/* type-specific value, unparsed */
+	struct core_set				cores;
+	bool						max;
 	int							dummy_val_flag;
 };
 
@@ -83,11 +82,14 @@
 				argp_usage(state);
 			}
 			pargs->mode = PROV_MODE_CMD;
-			pargs->cmd = arg;
-			/* Point to the next arg.  We can also check state->arg_num, which
-			 * is how many non-arpg arguments there are */
-			pargs->cmd_args = &state->argv[state->next];
-			/* Consume all args (it's done when next == argc) */
+
+			pargs->cmd_argc = state->argc - state->next + 1;
+			pargs->cmd_argv = malloc(sizeof(char*) * (pargs->cmd_argc + 1));
+			assert(pargs->cmd_argv);
+			pargs->cmd_argv[0] = arg;
+			memcpy(&pargs->cmd_argv[1], &state->argv[state->next],
+			       sizeof(char*) * (pargs->cmd_argc - 1));
+			pargs->cmd_argv[pargs->cmd_argc] = NULL;
 			state->next = state->argc;
 			break;
 		case 'v':
@@ -97,7 +99,7 @@
 				argp_usage(state);
 			}
 			pargs->dummy_val_flag = 1;
-			pargs->res_val = atol(arg);
+			pargs->res_val = arg;
 			break;
 		case 'm':
 			if (pargs->dummy_val_flag) {
@@ -105,7 +107,7 @@
 				argp_usage(state);
 			}
 			pargs->dummy_val_flag = 1;
-			pargs->max = 1;
+			pargs->max = true;
 			break;
 		case ARGP_KEY_END:
 			/* Make sure we selected a mode */
@@ -125,66 +127,18 @@
 /* Used by both -p and -c modes (-c will use it after creating pid) */
 static int prov_pid(pid_t pid, struct prog_args *pargs)
 {
-	unsigned int kernel_res_type;
-	int retval;
 	switch (pargs->res_type) {
 		case ('c'):
 			if (pargs->max) {
-				/* TODO: don't guess the LL/CG layout and num pcores */
-				#if 1
-				for (int i = 1; i < max_vcores() + 1; i++) {
-					if ((retval = sys_provision(pid, RES_CORES, i))) {
-						perror("Failed max provisioning");
-						return retval;
-					}
-				}
-				#else
-				/* To force a vcore shuffle / least optimal ordering, change
-				 * the if 1 to 0.  Normally, we provision out in a predictable,
-				 * VCn->PCn+1 ordering.  This splits the odd and even VCs
-				 * across sockets on a 32 PC machine (c89).  This is only for
-				 * perf debugging, when using the lockprov.sh script. */
-				retval = 0;
-				retval |= sys_provision(pid, RES_CORES,  1);
-				retval |= sys_provision(pid, RES_CORES, 16);
-				retval |= sys_provision(pid, RES_CORES,  2);
-				retval |= sys_provision(pid, RES_CORES, 17);
-				retval |= sys_provision(pid, RES_CORES,  3);
-				retval |= sys_provision(pid, RES_CORES, 18);
-				retval |= sys_provision(pid, RES_CORES,  4);
-				retval |= sys_provision(pid, RES_CORES, 19);
-				retval |= sys_provision(pid, RES_CORES,  5);
-				retval |= sys_provision(pid, RES_CORES, 20);
-				retval |= sys_provision(pid, RES_CORES,  6);
-				retval |= sys_provision(pid, RES_CORES, 21);
-				retval |= sys_provision(pid, RES_CORES,  7);
-				retval |= sys_provision(pid, RES_CORES, 22);
-				retval |= sys_provision(pid, RES_CORES,  8);
-				retval |= sys_provision(pid, RES_CORES, 23);
-				retval |= sys_provision(pid, RES_CORES,  9);
-				retval |= sys_provision(pid, RES_CORES, 24);
-				retval |= sys_provision(pid, RES_CORES, 10);
-				retval |= sys_provision(pid, RES_CORES, 25);
-				retval |= sys_provision(pid, RES_CORES, 11);
-				retval |= sys_provision(pid, RES_CORES, 26);
-				retval |= sys_provision(pid, RES_CORES, 12);
-				retval |= sys_provision(pid, RES_CORES, 27);
-				retval |= sys_provision(pid, RES_CORES, 13);
-				retval |= sys_provision(pid, RES_CORES, 28);
-				retval |= sys_provision(pid, RES_CORES, 14);
-				retval |= sys_provision(pid, RES_CORES, 29);
-				retval |= sys_provision(pid, RES_CORES, 15);
-				retval |= sys_provision(pid, RES_CORES, 31);
-				retval |= sys_provision(pid, RES_CORES, 30);
-				return retval;
-				#endif
+				parlib_get_all_core_set(&pargs->cores);
 			} else {
-				if ((retval = sys_provision(pid, RES_CORES, pargs->res_val))) {
-					perror("Failed single provision");
-					return retval;
+				if (!pargs->res_val) {
+					printf("Need a list of cores to provision\n");
+					return -1;
 				}
+				parlib_parse_cores(pargs->res_val, &pargs->cores);
 			}
-			kernel_res_type = RES_CORES;
+			provision_core_set(pid, &pargs->cores);
 			break;
 		case ('m'):
 			printf("Provisioning memory is not supported yet\n");
@@ -197,14 +151,13 @@
 				printf("Unsupported resource type %c\n", pargs->res_type);
 			return -1;
 	}
-	sys_poke_ksched(pid, kernel_res_type);
 	return 0;
 }
 
-int main(int argc, char **argv)
+int main(int argc, char **argv, char **envp)
 {
-
 	struct prog_args pargs = {0};
+	pid_t pid;
 
 	argp_parse(&argp, argc, argv, 0, 0, &pargs);
 
@@ -213,16 +166,23 @@
 			return prov_pid(pargs.pid, &pargs);
 			break;
 		case (PROV_MODE_CMD):
-			printf("Launching programs not supported yet\n");
-			printf("Would have launched %s with args:", pargs.cmd);
-			if (pargs.cmd_args)
-				for (int i = 0; pargs.cmd_args[i]; i++)
-					printf(" %s", pargs.cmd_args[i]);
-			printf("\n");
+			pid = create_child_with_stdfds(pargs.cmd_argv[0], pargs.cmd_argc,
+			                               pargs.cmd_argv, envp);
+			if (pid < 0) {
+				perror("Unable to spawn child");
+				exit(-1);
+			}
+			if (prov_pid(pid, &pargs)) {
+				perror("Unable to provision to child");
+				sys_proc_destroy(pid, -1);
+				exit(-1);
+			}
+			sys_proc_run(pid);
+			waitpid(pid, NULL, 0);
 			return 0;
-			break;
 		case (PROV_MODE_SHOW):
 			printf("Show mode not supported yet, using ghetto interface\n\n");
+			printf("Check 'dmesg' if you aren't on the console\n\n");
 			sys_provision(-1, 0, 0);
 			return 0;
 			break;