#include <sys/types.h>
#include <sys/usched.h>
#include <sys/cpumask.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
static void usage(void);
int DebugOpt;
int
main(int ac, char **av)
{
int ch;
int res;
char *sched = NULL;
char *cpustr = NULL;
char *sched_cpustr = NULL;
char *p = NULL;
cpumask_t cpumask;
int cpuid;
pid_t pid = getpid();
CPUMASK_ASSZERO(cpumask);
while ((ch = getopt(ac, av, "d")) != -1) {
switch (ch) {
case 'd':
DebugOpt = 1;
break;
default:
usage();
}
}
ac -= optind;
av += optind;
if (ac < 2) {
usage();
}
sched_cpustr = strdup(av[0]);
sched = strsep(&sched_cpustr, ":");
if (strcmp(sched, "default") == 0)
fprintf(stderr,
"Ignoring scheduler == \"default\": "
"not implemented\n");
cpustr = strsep(&sched_cpustr, "");
if (strlen(sched) == 0 && cpustr == NULL) {
usage();
}
if (cpustr != NULL) {
uint64_t v;
int baseid;
char *ptr = cpustr;
baseid = 0;
for (;;) {
if (baseid >= CPU_SETSIZE) {
fprintf(stderr, "cpumask too large\n");
usage();
}
v = (uint64_t)strtoull(ptr, &ptr, 0);
for (cpuid = 0; cpuid < (int)sizeof(v) * 8; ++cpuid) {
if (v & (1LU << cpuid))
CPUMASK_ORBIT(cpumask, baseid + cpuid);
}
if (*ptr == 0)
break;
if (*ptr != ',') {
fprintf(stderr, "cpumask format error\n");
usage();
}
++ptr;
baseid += (int)sizeof(v) * 8;
}
}
if (strlen(sched) != 0) {
if (DebugOpt) {
fprintf(stderr,
"DEBUG: USCHED_SET_SCHEDULER: scheduler: %s\n",
sched);
}
res = usched_set(pid, USCHED_SET_SCHEDULER,
sched, strlen(sched));
if (res != 0) {
asprintf(&p,
"usched_set(%d, USCHED_SET_SCHEDULER, "
"\"%s\", %d)",
pid, sched, (int)strlen(sched));
perror(p);
exit(1);
}
}
if (CPUMASK_TESTNZERO(cpumask)) {
for (cpuid = 0; cpuid < CPU_SETSIZE; ++cpuid) {
if (CPUMASK_TESTBIT(cpumask, cpuid))
break;
}
if (DebugOpt) {
fprintf(stderr, "DEBUG: USCHED_SET_CPU: cpuid: %d\n",
cpuid);
}
res = usched_set(pid, USCHED_SET_CPU, &cpuid, sizeof(int));
if (res != 0) {
asprintf(&p, "usched_set(%d, USCHED_SET_CPU, &%d, %d)",
pid, cpuid, (int)sizeof(int));
perror(p);
exit(1);
}
CPUMASK_NANDBIT(cpumask, cpuid);
while (CPUMASK_TESTNZERO(cpumask)) {
++cpuid;
if (CPUMASK_TESTBIT(cpumask, cpuid) == 0)
continue;
CPUMASK_NANDBIT(cpumask, cpuid);
if (DebugOpt) {
fprintf(stderr,
"DEBUG: USCHED_ADD_CPU: cpuid: %d\n",
cpuid);
}
res = usched_set(pid, USCHED_ADD_CPU,
&cpuid, sizeof(int));
if (res != 0) {
asprintf(&p,
"usched_set(%d, USCHED_ADD_CPU, "
"&%d, %d)",
pid, cpuid, (int)sizeof(int));
perror(p);
exit(1);
}
}
}
execvp(av[1], av + 1);
exit(1);
}
static
void
usage(void)
{
fprintf(stderr,
"usage: usched [-d] {scheduler[:cpumask] | :cpumask} "
"program [argument ...]\n");
fprintf(stderr,
"cpumask format: val[,val[,val[,val]]] in 64-bit chunks, "
"lsb chunk first\n");
exit(1);
}