Index: lib/libc/gen/sched_getaffinity.c =================================================================== --- lib/libc/gen/sched_getaffinity.c +++ lib/libc/gen/sched_getaffinity.c @@ -33,24 +33,15 @@ int sched_getaffinity(pid_t pid, size_t cpusetsz, cpuset_t *cpuset) { - /* - * Be more Linux-compatible: - * - return EINVAL in passed size is less than size of cpuset_t - * in advance, instead of ERANGE from the syscall - * - if passed size is larger than the size of cpuset_t, be - * permissive by claming it back to sizeof(cpuset_t) and - * zeroing the rest. - */ - if (cpusetsz < sizeof(cpuset_t)) { + int error; + + error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + pid == 0 ? -1 : pid, cpusetsz, cpuset); + if (error == -1 && errno == ERANGE) errno = EINVAL; - return (-1); - } - if (cpusetsz > sizeof(cpuset_t)) { - memset((char *)cpuset + sizeof(cpuset_t), 0, - cpusetsz - sizeof(cpuset_t)); - cpusetsz = sizeof(cpuset_t); - } + if (error == 0) + return (cpusetsz < sizeof(cpuset_t) ? cpusetsz : + sizeof(cpuset_t)); - return (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, - pid == 0 ? -1 : pid, cpusetsz, cpuset)); + return (error); } Index: lib/libc/gen/sched_setaffinity.c =================================================================== --- lib/libc/gen/sched_setaffinity.c +++ lib/libc/gen/sched_setaffinity.c @@ -26,6 +26,8 @@ * SUCH DAMAGE. */ +#include +#include #include #include #include @@ -33,15 +35,28 @@ int sched_setaffinity(pid_t pid, size_t cpusetsz, const cpuset_t *cpuset) { + static int mp_maxid; cpuset_t c; - int error; + int error, lbs, cpu; + size_t len, sz; - if (cpusetsz > sizeof(cpuset_t)) { - errno = EINVAL; - return (-1); - } else { - memset(&c, 0, sizeof(c)); - memcpy(&c, cpuset, cpusetsz); + sz = cpusetsz > sizeof(cpuset_t) ? sizeof(cpuset_t) : cpusetsz; + memset(&c, 0, sizeof(c)); + memcpy(&c, cpuset, sz); + + /* Linux ignores high bits */ + if (mp_maxid == 0) { + len = sizeof(mp_maxid); + error = sysctlbyname("kern.smp.maxid", &mp_maxid, &len, + NULL, 0); + if (error == -1) + return (error); + } + lbs = CPU_FLS(&c) - 1; + if (lbs > mp_maxid) { + CPU_FOREACH_ISSET(cpu, &c) + if (cpu > mp_maxid) + CPU_CLR(cpu, &c); } error = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid == 0 ? -1 : pid, sizeof(cpuset_t), &c); Index: lib/libc/sys/cpuset_getaffinity.2 =================================================================== --- lib/libc/sys/cpuset_getaffinity.2 +++ lib/libc/sys/cpuset_getaffinity.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 23, 2017 +.Dd April 27, 2022 .Dt CPUSET_GETAFFINITY 2 .Os .Sh NAME @@ -71,14 +71,19 @@ are composed using the .Dv CPU_SET macros. -The kernel tolerates large sets as long as all CPUs specified -in the set exist. -Sets smaller than the kernel uses generate an error on calls to +If the user-supplied mask is not large enough to fit all of the matching CPUs, .Fn cpuset_getaffinity -even if the result set would fit within the user supplied set. +fails with +.Er ERANGE . Calls to .Fn cpuset_setaffinity -tolerate small sets with no restrictions. +tolerate masks of any size with no restrictions. +The kernel uses the meaningful part of the mask, where the upper bound is +the maximum CPU id present in the system. +If bits for non-existing CPUs are set, calls to +.Fn cpuset_setaffinity +fails with +.Er EINVAL . .Pp The supplied mask should have a size of .Fa setsize @@ -144,7 +149,7 @@ .It Bq Er ERANGE The .Fa cpusetsize -was either preposterously large or smaller than the kernel set size. +was smaller than needed to fit all of the matching CPUs. .It Bq Er EPERM The calling process did not have the credentials required to complete the operation. Index: share/man/man3/pthread_attr_affinity_np.3 =================================================================== --- share/man/man3/pthread_attr_affinity_np.3 +++ share/man/man3/pthread_attr_affinity_np.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 12, 2021 +.Dd April 27, 2022 .Dt PTHREAD_ATTR_AFFINITY_NP 3 .Os .Sh NAME @@ -51,14 +51,19 @@ are composed using the .Dv CPU_SET macros. -The kernel tolerates large sets as long as all CPUs specified -in the set exist. -Sets smaller than the kernel uses generate an error on calls to -.Fn pthread_attr_getaffinity_np -even if the result set would fit within the user supplied set. +If the user-supplied mask is not large enough to fit all of the matching CPUs, +.Fn cpuset_getaffinity +fails with +.Er ERANGE . Calls to -.Fn pthread_attr_setaffinity_np -tolerate small sets with no restrictions. +.Fn cpuset_setaffinity +tolerate masks of any size with no restrictions. +The kernel uses the meaningful part of the mask, where the upper bound is +the maximum CPU id present in the system. +If bits for non-existing CPUs are set, calls to +.Fn cpuset_setaffinity +fails with +.Er EINVAL . .Pp The supplied mask should have a size of .Fa cpusetsize @@ -119,10 +124,6 @@ The .Fa cpusetp specified a CPU that was outside the set supported by the kernel. -.It Bq Er ERANGE -The -.Fa cpusetsize -is too small. .It Bq Er ENOMEM Insufficient memory exists to store the cpuset mask. .El Index: sys/compat/freebsd32/freebsd32_misc.c =================================================================== --- sys/compat/freebsd32/freebsd32_misc.c +++ sys/compat/freebsd32/freebsd32_misc.c @@ -3324,7 +3324,7 @@ struct freebsd32_cpuset_setaffinity_args *uap) { - return (kern_cpuset_setaffinity(td, uap->level, uap->which, + return (user_cpuset_setaffinity(td, uap->level, uap->which, PAIR32TO64(id_t,uap->id), uap->cpusetsize, uap->mask)); } Index: sys/compat/linux/linux_misc.c =================================================================== --- sys/compat/linux/linux_misc.c +++ sys/compat/linux/linux_misc.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -2256,22 +2257,22 @@ linux_sched_getaffinity(struct thread *td, struct linux_sched_getaffinity_args *args) { - int error; struct thread *tdt; - - if (args->len < sizeof(cpuset_t)) - return (EINVAL); + int error; + id_t tid; tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); - + tid = tdt->td_tid; PROC_UNLOCK(tdt->td_proc); error = kern_cpuset_getaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, - tdt->td_tid, sizeof(cpuset_t), (cpuset_t *)args->user_mask_ptr); + tid, args->len, (cpuset_t *)args->user_mask_ptr); + if (error == ERANGE) + error = EINVAL; if (error == 0) - td->td_retval[0] = sizeof(cpuset_t); + td->td_retval[0] = min(args->len, sizeof(cpuset_t)); return (error); } @@ -2284,18 +2285,34 @@ struct linux_sched_setaffinity_args *args) { struct thread *tdt; - - if (args->len < sizeof(cpuset_t)) - return (EINVAL); + cpuset_t *mask; + int cpu, error; + size_t len; + id_t tid; tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); - + tid = tdt->td_tid; PROC_UNLOCK(tdt->td_proc); - return (kern_cpuset_setaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, - tdt->td_tid, sizeof(cpuset_t), (cpuset_t *) args->user_mask_ptr)); + len = min(args->len, sizeof(cpuset_t)); + mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO);; + error = copyin(args->user_mask_ptr, mask, len); + if (error != 0) + goto out; + /* Linux ignore high bits */ + CPU_FOREACH_ISSET(cpu, mask) + if (cpu > mp_maxid) + CPU_CLR(cpu, mask); + + error = kern_cpuset_setaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, + tid, mask); + if (error == EDEADLK) + error = EINVAL; +out: + free(mask, M_TEMP); + return (error); } struct linux_rlimit64 { Index: sys/kern/kern_cpuset.c =================================================================== --- sys/kern/kern_cpuset.c +++ sys/kern/kern_cpuset.c @@ -1896,13 +1896,10 @@ int error; size_t size; - if (cpusetsize < sizeof(cpuset_t) || cpusetsize > CPU_MAXSIZE / NBBY) - return (ERANGE); error = cpuset_check_capabilities(td, level, which, id); if (error != 0) return (error); - size = cpusetsize; - mask = malloc(size, M_TEMP, M_WAITOK | M_ZERO); + mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO); error = cpuset_which(which, id, &p, &ttd, &set); if (error) goto out; @@ -1972,8 +1969,33 @@ cpuset_rel(set); if (p) PROC_UNLOCK(p); - if (error == 0) + if (error == 0) { + if (cpusetsize < howmany(CPU_FLS(mask), NBBY)) { + error = ERANGE; + goto out; + } + size = min(cpusetsize, sizeof(cpuset_t)); error = copyout(mask, maskp, size); + if (error != 0) + goto out; + if (cpusetsize > size) { + char *end; + char *cp; + int rv; + + end = cp = (char *)&maskp->__bits; + end += cpusetsize; + cp += size; + while (cp != end) { + rv = subyte(cp, 0); + if (rv == -1) { + error = EFAULT; + goto out; + } + cp++; + } + } + } out: free(mask, M_TEMP); return (error); @@ -1992,50 +2014,25 @@ sys_cpuset_setaffinity(struct thread *td, struct cpuset_setaffinity_args *uap) { - return (kern_cpuset_setaffinity(td, uap->level, uap->which, + return (user_cpuset_setaffinity(td, uap->level, uap->which, uap->id, uap->cpusetsize, uap->mask)); } int kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, - id_t id, size_t cpusetsize, const cpuset_t *maskp) + id_t id, cpuset_t *mask) { struct cpuset *nset; struct cpuset *set; struct thread *ttd; struct proc *p; - cpuset_t *mask; int error; - if (cpusetsize < sizeof(cpuset_t) || cpusetsize > CPU_MAXSIZE / NBBY) - return (ERANGE); error = cpuset_check_capabilities(td, level, which, id); if (error != 0) return (error); - mask = malloc(cpusetsize, M_TEMP, M_WAITOK | M_ZERO); - error = copyin(maskp, mask, cpusetsize); - if (error) - goto out; - /* - * Verify that no high bits are set. - */ - if (cpusetsize > sizeof(cpuset_t)) { - char *end; - char *cp; - - end = cp = (char *)&mask->__bits; - end += cpusetsize; - cp += sizeof(cpuset_t); - while (cp != end) - if (*cp++ != 0) { - error = EINVAL; - goto out; - } - } - if (CPU_EMPTY(mask)) { - error = EDEADLK; - goto out; - } + if (CPU_EMPTY(mask)) + return (EDEADLK); switch (level) { case CPU_LEVEL_ROOT: case CPU_LEVEL_CPUSET: @@ -2057,8 +2054,7 @@ case CPU_WHICH_INTRHANDLER: case CPU_WHICH_ITHREAD: case CPU_WHICH_DOMAIN: - error = EINVAL; - goto out; + return (EINVAL); } if (level == CPU_LEVEL_ROOT) nset = cpuset_refroot(set); @@ -2098,6 +2094,47 @@ error = EINVAL; break; } + return (error); +} + +int +user_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, + id_t id, size_t cpusetsize, const cpuset_t *maskp) +{ + cpuset_t *mask; + int error; + size_t size; + + size = min(cpusetsize, sizeof(cpuset_t)); + mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO); + error = copyin(maskp, mask, size); + if (error) + goto out; + /* + * Verify that no high bits are set. + */ + if (cpusetsize > sizeof(cpuset_t)) { + const char *end, *cp; + int val; + end = cp = (const char *)&maskp->__bits; + end += cpusetsize; + cp += sizeof(cpuset_t); + + while (cp != end) { + val = fubyte(cp); + if (val == -1) { + error = EFAULT; + goto out; + } + if (val != 0) { + error = EINVAL; + goto out; + } + cp++; + } + } + error = kern_cpuset_setaffinity(td, level, which, id, mask); + out: free(mask, M_TEMP); return (error); Index: sys/sys/syscallsubr.h =================================================================== --- sys/sys/syscallsubr.h +++ sys/sys/syscallsubr.h @@ -121,6 +121,8 @@ int kern_cpuset_getaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, cpuset_t *maskp); int kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, + cpuwhich_t which, id_t id, cpuset_t *maskp); +int user_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, const cpuset_t *maskp); int kern_cpuset_getdomain(struct thread *td, cpulevel_t level, Index: tests/sys/kern/Makefile =================================================================== --- tests/sys/kern/Makefile +++ tests/sys/kern/Makefile @@ -26,6 +26,7 @@ ATF_TESTS_C+= ptrace_test TEST_METADATA.ptrace_test+= timeout="15" ATF_TESTS_C+= reaper +ATF_TESTS_C+= sched_affinity ATF_TESTS_C+= sigaltstack ATF_TESTS_C+= sigwait .if ${MACHINE_ARCH} != "i386" && ${MACHINE_ARCH:Mpowerpc*} == "" Index: tests/sys/kern/sched_affinity.c =================================================================== --- /dev/null +++ tests/sys/kern/sched_affinity.c @@ -0,0 +1,297 @@ +/*- + * Copyright (c) 2022 Dmitry Chagin + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include + +#include + +static uint32_t maxcpuid; +static uint32_t maxcpus; +static uint32_t cpus; + +static uint32_t +support_getcpus(void) +{ + uint32_t val; + size_t sz = sizeof(val); + + ATF_REQUIRE(sysctlbyname("kern.smp.cpus", &val, &sz, NULL, 0) == 0); + return (val); +} + +static uint32_t +support_getmaxcpus(void) +{ + uint32_t val; + size_t sz = sizeof(val); + + ATF_REQUIRE(sysctlbyname("kern.smp.maxcpus", &val, &sz, NULL, 0) == 0); + return (val); +} + +static uint32_t +support_getmaxcpuid(void) +{ + cpuset_t *set; + int setsize, rv; + uint32_t i, id; + + for (i = 1; i < maxcpus; i++) { + setsize = CPU_ALLOC_SIZE(i); + set = CPU_ALLOC(i); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(i, set); + rv = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, setsize, set); + if (rv == 0) { + id = __BIT_FLS(i, set) - 1; + CPU_FREE(set); + break; + } + CPU_FREE(set); + } + ATF_REQUIRE(rv == 0); + return (id); +} + +ATF_TC_WITHOUT_HEAD(test_setinvalidcpu); +ATF_TC_BODY(test_setinvalidcpu, tc) +{ + size_t cpusetsize; + cpuset_t *set; + + cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1); + set = CPU_ALLOC(maxcpuid + 1); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpuid + 1, set); + CPU_SET_S(maxcpuid + 1, maxcpuid + 1, set); + CPU_SET_S(maxcpuid - 1, maxcpuid + 1, set); + ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == 0); + CPU_FREE(set); + + cpusetsize = CPU_ALLOC_SIZE(maxcpus + 1); + set = CPU_ALLOC(maxcpus + 1); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpus + 1, set); + CPU_SET_S(maxcpuid + 1, maxcpus + 1, set); + CPU_SET_S(maxcpuid - 1, maxcpus + 1, set); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == -1); + ATF_REQUIRE_EQ(errno, EINVAL); + CPU_FREE(set); +} + +ATF_TC_WITHOUT_HEAD(test_setvalidcpu); +ATF_TC_BODY(test_setvalidcpu, tc) +{ + size_t cpusetsize; + cpuset_t *set; + int cpu; + + ATF_REQUIRE(maxcpuid < maxcpus); + cpu = maxcpuid > 1 ? maxcpuid - 1 : 0; + + cpusetsize = CPU_ALLOC_SIZE(maxcpus + 1); + set = CPU_ALLOC(maxcpus + 1); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpus + 1, set); + CPU_SET_S(cpu, maxcpus + 1, set); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == 0); + ATF_REQUIRE_EQ(cpu, sched_getcpu()); + CPU_FREE(set); +} + +ATF_TC_WITHOUT_HEAD(test_setzeroset1); +ATF_TC_BODY(test_setzeroset1, tc) +{ + size_t cpusetsize; + cpuset_t *set; + + cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1); + set = CPU_ALLOC(maxcpuid + 1); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpuid + 1, set); + ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == -1); + ATF_REQUIRE_EQ(errno, EINVAL); + CPU_FREE(set); +} + +ATF_TC_WITHOUT_HEAD(test_setzeroset2); +ATF_TC_BODY(test_setzeroset2, tc) +{ + size_t cpusetsize; + cpuset_t *set; + + cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1); + set = CPU_ALLOC(maxcpuid + 1); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpuid + 1, set); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == -1); + ATF_REQUIRE_EQ(errno, EDEADLK); + CPU_FREE(set); +} + +ATF_TC_WITHOUT_HEAD(test_setmaxsetsize); +ATF_TC_BODY(test_setmaxsetsize, tc) +{ + size_t cpusetsize; + cpuset_t *set; + + cpusetsize = CPU_ALLOC_SIZE(maxcpus * 2); + set = CPU_ALLOC(maxcpus * 2); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpus * 2, set); + ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 0); + CPU_SET_S(0, maxcpus * 2, set); + ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == 0); + + CPU_ZERO_S(maxcpus * 2, set); + CPU_SET_S(maxcpuid, maxcpus * 2, set); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == 0); + + CPU_ZERO_S(maxcpus * 2, set); + CPU_SET_S(maxcpuid + 1, maxcpus * 2, set); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == -1); + ATF_REQUIRE_EQ(errno, EINVAL); + CPU_FREE(set); +} + +ATF_TC_WITHOUT_HEAD(test_setminsetsize); +ATF_TC_BODY(test_setminsetsize, tc) +{ + size_t cpusetsize = 1; + int8_t set; + + if (cpus <= 8) + return; + + set = 1; + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, (const cpuset_t *)&set) == 0); + set = 0; + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, (const cpuset_t *)&set) == -1); + ATF_REQUIRE_EQ(errno, EDEADLK); +} + +ATF_TC_WITHOUT_HEAD(test_getminsetsize); +ATF_TC_BODY(test_getminsetsize, tc) +{ + size_t cpusetsize = 1; + int8_t set = 0; + + if (cpus < 9) + return; + ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, (cpuset_t *)&set) == -1); + ATF_REQUIRE_EQ(errno, ERANGE); +} + +ATF_TC_WITHOUT_HEAD(test_getsetsize); +ATF_TC_BODY(test_getsetsize, tc) +{ + size_t cpusetsize; + cpuset_t *set; + + cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1); + set = CPU_ALLOC(maxcpuid + 1); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpuid + 1, set); + ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == 0); + CPU_FREE(set); +} + +ATF_TC_WITHOUT_HEAD(test_schedgetsetsize); +ATF_TC_BODY(test_schedgetsetsize, tc) +{ + cpuset_t *set; + int cpusetsize; + + cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1); + set = CPU_ALLOC(maxcpuid + 1); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpuid + 1, set); + ATF_REQUIRE(sched_getaffinity(0, cpusetsize, set) == cpusetsize); + CPU_FREE(set); + + set = CPU_ALLOC(CPU_SETSIZE); + ATF_REQUIRE(set != NULL); + cpusetsize = CPU_ALLOC_SIZE(CPU_SETSIZE); + CPU_ZERO(set); + ATF_REQUIRE(sched_getaffinity(0, cpusetsize, set) == cpusetsize); + CPU_FREE(set); +} + +ATF_TC_WITHOUT_HEAD(test_holes); +ATF_TC_BODY(test_holes, tc) +{ + cpuset_t *set; + int cpusetsize; + + cpusetsize = CPU_ALLOC_SIZE(maxcpus * 2); + set = CPU_ALLOC(maxcpus * 2); + ATF_REQUIRE(set != NULL); + CPU_ZERO_S(maxcpus * 2, set); + ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 0); + CPU_SET_S(maxcpuid, maxcpus * 2, set); + ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == 0); + + CPU_ZERO_S(maxcpus * 2, set); + ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 0); + CPU_SET_S(maxcpuid + 1, maxcpus * 2, set); + ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1); + ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == -1); + ATF_REQUIRE_EQ(errno, EINVAL); + + ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1); + ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, + -1, cpusetsize, set) == 0); + ATF_REQUIRE(CPU_ISSET_S(maxcpuid + 1, maxcpus * 2, set) == false); + ATF_REQUIRE(CPU_ISSET_S(maxcpuid, maxcpus * 2, set) == true); + ATF_REQUIRE_EQ(maxcpuid, (uint32_t)sched_getcpu()); +} + +ATF_TP_ADD_TCS(tp) +{ + + cpus = support_getcpus(); + maxcpus = support_getmaxcpus(); + maxcpuid = support_getmaxcpuid(); + + ATF_TP_ADD_TC(tp, test_setinvalidcpu); + ATF_TP_ADD_TC(tp, test_setvalidcpu); + ATF_TP_ADD_TC(tp, test_setzeroset1); + ATF_TP_ADD_TC(tp, test_setzeroset2); + + ATF_TP_ADD_TC(tp, test_setminsetsize); + ATF_TP_ADD_TC(tp, test_setmaxsetsize); + + ATF_TP_ADD_TC(tp, test_getminsetsize); + ATF_TP_ADD_TC(tp, test_getsetsize); + + ATF_TP_ADD_TC(tp, test_schedgetsetsize); + + ATF_TP_ADD_TC(tp, test_holes); + + return (atf_no_error()); +}