2.5: (better) syscalls for setting task affinity
PATCH 1/1 2.5: (better) syscalls for setting task affinity
[ This post adds length and pointer checks to the syscalls such that we can portably change the size of cpus_allowed. ]
The attached patch implements a syscall interface for setting and retrieving a task's CPU affinity (task->cpus_allowed):
int sched_set_affinity(pid_t pid, unsigned int len,
unsigned long *new_mask_ptr);
int sched_get_affinity(pid_t pid, unsigned int *user_len_ptr,
unsigned long *user_mask_ptr)
sched_set_affinity uses the set_cpus_allowed function in Ingo's new scheduler to do all the hard work. Additionally, this patch is based off Ingo's previous syscall affinity patch and my proc-based affinity patch. Much credit to Ingo for this past work and his current scheduler.
Security is enforced: calling user must match task's uid or euid or possess CAP_SYS_NICE.
We can safely change the size of cpus_allowed. One can use:
sched_get_affinity(0, &len, NULL);
to get the size of cpus_allowed. The use of this interface, thus, should be portable as we scale cpus_allowed over sizeof(long).
I think exporting cpus_allowed as a bit mask is the proper user interface for CPU affinity. Certainly more complicated solutions exist, but this should get the job done. I have also updated my proc-based solution although Ingo and others have flamed^Wconvinced me a syscall-based interface is ideal. I agree, mostly on the basis that /proc may not be mounted but I have posted an updated proc-based solution anyhow for proper discussion.
Patch is against 2.5.6-pre1. Enjoy,
Robert Love
arch/i386/kernel/entry.S +2 -0
@@ -716,6 +716,8 @@ .long SYMBOL_NAME(sys_lremovexattr) .long SYMBOL_NAME(sys_fremovexattr) .long SYMBOL_NAME(sys_tkill) + .long SYMBOL_NAME(sys_sched_set_affinity) + .long SYMBOL_NAME(sys_sched_get_affinity) /* 240 */ .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall)
include/asm-i386/unistd.h +2 -0
@@ -243,6 +243,8 @@#define __NR_lremovexattr 236#define __NR_fremovexattr 237#define __NR_tkill 238 +#define __NR_sched_set_affinity 239 +#define __NR_sched_get_affinity 240/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
kernel/sched.c +93 -0
99 lines not on this page · raw message
Quoted 2 lines · Robert Love
The attached patch implements a syscall interface for setting and retrieving a task's CPU affinity (
task->cpus_allowed):
I should posted a test program to demonstrate the syscalls - find such an attachment below. It demonstrates using sched_get_affinity to find the length of the cpu bitmask and then get and set a new value.
`pid_t p' is the process in question.
`unsigned long new_mask' is the new bitmask.
Robert Love
/*
* Example of sched_set_affinity and sched_get_affinity
* Robert Love, 20020227
*/
#include <stdio.h>
#include <stdlib.h>
#include <linux/unistd.h>
#include <unistd.h>
#define __NR_sched_set_affinity 239
#define __NR_sched_get_affinity 240
_syscall3 (int, sched_set_affinity, pid_t, pid, unsigned int, len, unsigned long *, new_mask_ptr) _syscall3 (int, sched_get_affinity, pid_t, pid, unsigned int *, user_len_ptr, unsigned long *, user_mask_ptr)
int main(int argc, char * argv[])
{
unsigned long new_mask = 2;
unsigned int len;
unsigned long cur_mask;
pid_t p = getpid();
int ret;
ret = sched_get_affinity(p, &len, NULL);
printf(" len = %u\n", len);
ret = sched_get_affinity(p, &len, &cur_mask);
printf(" sched_get_affinity = %d, cur_mask = %ld\n", ret, cur_mask);
ret = sched_set_affinity(p, len, &new_mask);
printf(" sched_set_affinity = %d, new_mask = %ld\n", ret, new_mask);
ret = sched_get_affinity(p, &len, &cur_mask);
printf(" sched_get_affinity = %d, cur_mask = %ld\n", ret, cur_mask);
return 0;
}Quoted 2 lines · Robert Love
[ This post adds length and pointer checks to the syscalls such that we can portably change the size of
cpus_allowed. ]
Great! That is what I was going to suggest to your first patch.
Signature · 1 line
Mike