diff -prauwN linux-2.4.25/arch/i386/kernel/entry.S linux-2.4.25-cpucap/arch/i386/kernel/entry.S --- linux-2.4.25/arch/i386/kernel/entry.S Fri Jun 13 15:51:29 2003 +++ linux-2.4.25-cpucap/arch/i386/kernel/entry.S Mon Mar 22 18:07:52 2004 @@ -663,7 +663,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_wait */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_remap_file_pages */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_tid_address */ - + .long SYMBOL_NAME(sys_setcpucap) /* CPU Cap Patch */ .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -prauwN linux-2.4.25/include/asm-i386/unistd.h linux-2.4.25-cpucap/include/asm-i386/unistd.h --- linux-2.4.25/include/asm-i386/unistd.h Thu Nov 28 23:53:15 2002 +++ linux-2.4.25-cpucap/include/asm-i386/unistd.h Mon Mar 22 18:07:52 2004 @@ -257,7 +257,7 @@ #define __NR_alloc_hugepages 250 #define __NR_free_hugepages 251 #define __NR_exit_group 252 - +#define __NR_setcpucap 259 /* CPU Cap Patch */ /* user-visible error numbers are in the range -1 - -124: see */ #define __syscall_return(type, res) \ diff -prauwN linux-2.4.25/include/linux/sched.h linux-2.4.25-cpucap/include/linux/sched.h --- linux-2.4.25/include/linux/sched.h Wed Feb 18 13:36:32 2004 +++ linux-2.4.25-cpucap/include/linux/sched.h Mon Mar 22 18:07:52 2004 @@ -415,6 +415,11 @@ struct task_struct { /* journalling filesystem info */ void *journal_info; + +/* CPU Cap Patch */ + unsigned long next_cap_timer; + int cap_left; + unsigned cap_cpu_limit; }; /* @@ -436,6 +441,8 @@ struct task_struct { #define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ +#define PF_CAPCPU 0x80000000 /* use Cap Processor Usage policy */ + /* * Ptrace flags */ @@ -510,6 +517,10 @@ extern struct exec_domain default_exec_d blocked: {{0}}, \ alloc_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ + /* CPU Cap Patch */ \ + next_cap_timer: 0, \ + cap_left: -1, \ + cap_cpu_limit: HZ \ } diff -prauwN linux-2.4.25/kernel/fork.c linux-2.4.25-cpucap/kernel/fork.c --- linux-2.4.25/kernel/fork.c Wed Feb 18 13:36:32 2004 +++ linux-2.4.25-cpucap/kernel/fork.c Mon Mar 22 18:07:52 2004 @@ -779,6 +779,12 @@ int do_fork(unsigned long clone_flags, u if (!current->counter) current->need_resched = 1; + /* CPU Cap Patch */ + p->cap_left = (current->cap_left + 1) >> 1; + current->cap_left >>= 1; + if (!current->cap_left && (p->flags & PF_CAPCPU)) + current->need_resched = 1; + /* * Ok, add it to the run-queues and make it * visible to the rest of the system. diff -prauwN linux-2.4.25/kernel/sched.c linux-2.4.25-cpucap/kernel/sched.c --- linux-2.4.25/kernel/sched.c Fri Nov 28 18:26:21 2003 +++ linux-2.4.25-cpucap/kernel/sched.c Mon Mar 22 18:07:52 2004 @@ -166,8 +166,13 @@ static inline int goodness(struct task_s * over.. */ weight = p->counter; - if (!weight) + if (!weight) { + /* CPU Cap Patch */ + if ((jiffies < p->next_cap_timer) && (! p->cap_left)) { + weight=-1000; + } goto out; + } #ifdef CONFIG_SMP /* Give a largish advantage to the same processor... */ @@ -618,8 +623,20 @@ repeat_schedule: spin_unlock_irq(&runqueue_lock); read_lock(&tasklist_lock); - for_each_task(p) + for_each_task(p) { p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice); + /* CPU Cap Patch */ + if (p->flags & PF_CAPCPU) { + if (p->next_cap_timer <= jiffies) { + p->next_cap_timer = jiffies + HZ; + p->cap_left=p->cap_cpu_limit; + } + if (p->counter > p->cap_left) { + p->counter = p->cap_left; + /* if the task is exhausted then p->cap_left is 0 */ + } + } /* if PF_CAPCPU */ + } /* for each task */ read_unlock(&tasklist_lock); spin_lock_irq(&runqueue_lock); goto repeat_schedule; diff -prauwN linux-2.4.25/kernel/sys.c linux-2.4.25-cpucap/kernel/sys.c --- linux-2.4.25/kernel/sys.c Fri Nov 28 18:26:21 2003 +++ linux-2.4.25-cpucap/kernel/sys.c Mon Mar 22 18:07:52 2004 @@ -213,6 +213,59 @@ static int proc_sel(struct task_struct * return 0; } +/* CPU Cap Patch - setting cap limit for process or group */ +asmlinkage long sys_setcpucap(int which, int who, int cap) +{ + struct task_struct *p; + int error; + + if (which > 2 || which < 0) + return -EINVAL; + + /* normalize (cap value is percentage) */ + error = -ESRCH; + if (cap < 1) + cap = 1; + if (cap > 100) + cap = 100; + + /* convert to jiffies, check limits as a precaution */ + cap = (cap * HZ) / 100; + if (cap < 1) + cap = 1; + if (cap > HZ) + cap = HZ; + + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!proc_sel(p, which, who)) + continue; + if (p->uid != current->euid && + p->uid != current->uid && !capable(CAP_SYS_NICE)) { + error = -EPERM; + continue; + } + if (error == -ESRCH) + error = 0; + if (cap > p->cap_cpu_limit && !capable(CAP_SYS_NICE)) + error = -EACCES; + else { + p->cap_cpu_limit = cap; + if (cap == HZ) { + p->flags &= ~PF_CAPCPU; + p->next_cap_timer = 0; + } else + p->flags |= PF_CAPCPU; + } + } + read_unlock(&tasklist_lock); + + return error; +} + + + asmlinkage long sys_setpriority(int which, int who, int niceval) { struct task_struct *p; diff -prauwN linux-2.4.25/kernel/timer.c linux-2.4.25-cpucap/kernel/timer.c --- linux-2.4.25/kernel/timer.c Thu Nov 28 23:53:15 2002 +++ linux-2.4.25-cpucap/kernel/timer.c Mon Mar 22 18:07:52 2004 @@ -599,6 +599,20 @@ void update_process_times(int user_tick) update_one_process(p, user_tick, system, cpu); if (p->pid) { + /* CPU Cap Patch */ + if (--p->cap_left == -1) { + /* the timer went down for the task, check what's going on */ + if (p->flags & PF_CAPCPU) { + /* the task is exhausted */ + p->cap_left=0; + p->counter=0; + } else { + /* the task is not subject to CPU */ + /* make it 'invisible' for a long time */ + p->cap_left = -2; + } + } + if (--p->counter <= 0) { p->counter = 0; /*