From c5a740cdb23a6dc9973a8142303b67f830c67b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Wed, 22 May 2024 18:09:42 +0200 Subject: [PATCH] gnu: add pthread_setaffinity_np()/pthread_getaffinity_np() * also sched_setaffinity/sched_getaffinity() added. * add a test Change-Id: Id8c308788f6364f5340b4991def2fbb9a05da728 Reviewed-on: https://review.haiku-os.org/c/haiku/+/7675 Reviewed-by: waddlesplash Tested-by: Commit checker robot --- headers/compatibility/gnu/pthread.h | 6 +++ headers/compatibility/gnu/sched.h | 36 +++++++++++++ src/libs/gnu/Jamfile | 3 +- src/libs/gnu/sched_affinity.cpp | 62 ++++++++++++++++++++++ src/tests/libs/Jamfile | 1 + src/tests/libs/gnu/Jamfile | 1 + src/tests/libs/gnu/sched_affinity_test.cpp | 43 +++++++++++++++ 7 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/libs/gnu/sched_affinity.cpp create mode 100644 src/tests/libs/gnu/sched_affinity_test.cpp diff --git a/headers/compatibility/gnu/pthread.h b/headers/compatibility/gnu/pthread.h index 802d0c9d2b..c1f4db958d 100644 --- a/headers/compatibility/gnu/pthread.h +++ b/headers/compatibility/gnu/pthread.h @@ -12,6 +12,9 @@ #ifdef _GNU_SOURCE +#include + + #ifdef __cplusplus extern "C" { #endif @@ -22,6 +25,9 @@ extern int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr); extern int pthread_getname_np(pthread_t thread, char* buffer, size_t length); extern int pthread_setname_np(pthread_t thread, const char* name); +extern int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpuset_t* mask); +extern int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpuset_t* mask); + #ifdef __cplusplus } diff --git a/headers/compatibility/gnu/sched.h b/headers/compatibility/gnu/sched.h index eaa5221071..3107d820e8 100644 --- a/headers/compatibility/gnu/sched.h +++ b/headers/compatibility/gnu/sched.h @@ -8,15 +8,51 @@ #include_next +#include +#include + #ifdef _GNU_SOURCE +#ifndef CPU_SETSIZE +#define CPU_SETSIZE 1024 +#endif + + +typedef __haiku_uint32 cpuset_mask; + +#ifndef _howmany +#define _howmany(x, y) (((x) + ((y) - 1)) / (y)) +#endif + +#define NCPUSETBITS (sizeof(cpuset_mask) * 8) /* bits per mask */ + +typedef struct _cpuset { + cpuset_mask bits[_howmany(CPU_SETSIZE, NCPUSETBITS)]; +} cpuset_t; + + +#define _CPUSET_BITSINDEX(cpu) ((cpu) / NCPUSETBITS) +#define _CPUSET_BIT(cpu) (1L << ((cpu) % NCPUSETBITS)) + +/* FD_ZERO uses memset */ +#include + +#define CPUSET_ZERO(set) memset((set), 0, sizeof(cpuset_t)) +#define CPUSET_SET(cpu, set) ((set)->bits[_CPUSET_BITSINDEX(cpu)] |= _CPUSET_BIT(cpu)) +#define CPUSET_CLR(cpu, set) ((set)->bits[_CPUSET_BITSINDEX(cpu)] &= ~_CPUSET_BIT(cpu)) +#define CPUSET_ISSET(cpu, set) ((set)->bits[_CPUSET_BITSINDEX(cpu)] & _CPUSET_BIT(cpu)) +#define CPUSET_COPY(source, target) (*(target) = *(source)) + + #ifdef __cplusplus extern "C" { #endif extern int sched_getcpu(void); +extern int sched_setaffinity(pid_t id, size_t cpusetsize, const cpuset_t* mask); +extern int sched_getaffinity(pid_t id, size_t cpusetsize, cpuset_t* mask); #ifdef __cplusplus } diff --git a/src/libs/gnu/Jamfile b/src/libs/gnu/Jamfile index 8f3f110247..d506f3d55e 100644 --- a/src/libs/gnu/Jamfile +++ b/src/libs/gnu/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src libs gnu ; UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility gnu ] : true ; -UsePrivateHeaders shared ; +UsePrivateHeaders libroot shared ; SubDirCcFlags [ FDefines _GNU_SOURCE=1 ] ; SubDirC++Flags [ FDefines _GNU_SOURCE=1 ] ; @@ -19,6 +19,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { crypt.cpp memmem.c qsort.c + sched_affinity.cpp sched_getcpu.cpp xattr.cpp ; diff --git a/src/libs/gnu/sched_affinity.cpp b/src/libs/gnu/sched_affinity.cpp new file mode 100644 index 0000000000..b9c45f017c --- /dev/null +++ b/src/libs/gnu/sched_affinity.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2023, Jérôme Duval, jerome.duval@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include + + +int +pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpuset_t* mask) +{ + return _kern_set_thread_affinity(thread->id, mask, cpusetsize); +} + + +int +pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpuset_t* mask) +{ + status_t status = _kern_get_thread_affinity(thread->id, mask, cpusetsize); + if (status != B_OK) { + if (status == B_BAD_THREAD_ID) + return ESRCH; + + return status; + } + + return 0; +} + + +int +sched_setaffinity(pid_t id, size_t cpusetsize, const cpuset_t* mask) +{ + status_t status = _kern_set_thread_affinity(id, mask, cpusetsize); + if (status != B_OK) { + if (status == B_BAD_THREAD_ID) + return ESRCH; + + return status; + } + + return 0; +} + + +int +sched_getaffinity(pid_t id, size_t cpusetsize, cpuset_t* mask) +{ + status_t status = _kern_get_thread_affinity(id, mask, cpusetsize); + if (status != B_OK) { + if (status == B_BAD_THREAD_ID) + return ESRCH; + + return status; + } + + return 0; +} diff --git a/src/tests/libs/Jamfile b/src/tests/libs/Jamfile index 7ead288a61..4109724621 100644 --- a/src/tests/libs/Jamfile +++ b/src/tests/libs/Jamfile @@ -2,5 +2,6 @@ SubDir HAIKU_TOP src tests libs ; SubInclude HAIKU_TOP src tests libs alm ; SubInclude HAIKU_TOP src tests libs bsd ; +SubInclude HAIKU_TOP src tests libs gnu ; SubInclude HAIKU_TOP src tests libs linprog ; diff --git a/src/tests/libs/gnu/Jamfile b/src/tests/libs/gnu/Jamfile index 9e26cfc3eb..f0f2070022 100644 --- a/src/tests/libs/gnu/Jamfile +++ b/src/tests/libs/gnu/Jamfile @@ -4,5 +4,6 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility gnu ] : true ; SubDirC++Flags [ FDefines _GNU_SOURCE=1 ] ; SimpleTest sched_getcpu_test : sched_getcpu_test.cpp : libgnu.so ; +SimpleTest sched_affinity_test : sched_affinity_test.cpp : libgnu.so ; diff --git a/src/tests/libs/gnu/sched_affinity_test.cpp b/src/tests/libs/gnu/sched_affinity_test.cpp new file mode 100644 index 0000000000..a0b58e5d3c --- /dev/null +++ b/src/tests/libs/gnu/sched_affinity_test.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2023, Jérôme Duval, jerome.duval@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include + + +int +main(int argc, char** argv) +{ + if (argc != 2) + exit(1); + if (strcmp(argv[1], "off") != 0) { + printf("with affinity on CPU 1\n"); + pthread_t thread = pthread_self(); + cpuset_t cpuset; + CPUSET_ZERO(&cpuset); + CPUSET_SET(1, &cpuset); + if (pthread_setaffinity_np(thread, sizeof(cpuset_t), &cpuset) != 0) { + fprintf(stderr, "pthread_setaffinity_np failed\n"); + exit(1); + } + if (pthread_getaffinity_np(thread, sizeof(cpuset_t), &cpuset) != 0) { + fprintf(stderr, "pthread_getaffinity_np failed\n"); + exit(1); + } + if (!CPUSET_ISSET(1, &cpuset)) + fprintf(stderr, "affinity not on CPU 1\n"); + if (sched_getcpu() != 1) + fprintf(stderr, "not running on CPU 1\n"); + } else { + printf("without affinity\n"); + } + int* p; + while (true) + (*p)++; + return *p; +}