--- ./lib/rwsem.c.org Mon Feb 10 19:37:57 2003 +++ ./lib/rwsem.c Sun Apr 27 06:56:41 2003 @@ -15,6 +15,8 @@ #define RWSEM_WAITING_FOR_WRITE 0x00000002 }; +extern void show_task(struct task_struct *tsk); + #if RWSEM_DEBUG #undef rwsemtrace void rwsemtrace(struct rw_semaphore *sem, const char *str) @@ -126,6 +128,7 @@ { struct task_struct *tsk = current; signed long count; + int ticks = 0; set_task_state(tsk,TASK_UNINTERRUPTIBLE); @@ -150,7 +153,17 @@ for (;;) { if (!waiter->flags) break; - schedule(); + if (!schedule_timeout(1000) && sem->owner) { + struct task_struct *tsk = (struct task_struct *) sem->owner; + ticks += 1000; + printk(KERN_DEBUG "%d:%d starved %d secs by %d:%d who last ran %lu ticks ago.\n", + current->pid, current->prio - 100, ticks/HZ, tsk->pid, + tsk->prio - 100, jiffies - tsk->last_run); + if (ticks >= 5000) + show_task(sem->owner); + printk(KERN_DEBUG "semaphore downed at %s:%d.\n\n", + sem->file, sem->line); + } set_task_state(tsk, TASK_UNINTERRUPTIBLE); } --- ./arch/i386/kernel/semaphore.c.org Mon Feb 10 19:38:28 2003 +++ ./arch/i386/kernel/semaphore.c Sun Apr 27 06:29:27 2003 @@ -58,6 +58,7 @@ struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); unsigned long flags; + int ticks = 0; tsk->state = TASK_UNINTERRUPTIBLE; spin_lock_irqsave(&sem->wait.lock, flags); @@ -79,7 +80,17 @@ sem->sleepers = 1; /* us - see -1 above */ spin_unlock_irqrestore(&sem->wait.lock, flags); - schedule(); + if (!schedule_timeout(1000) && sem->owner) { + struct task_struct *tsk = (struct task_struct *) sem->owner; + ticks += 1000; + printk(KERN_DEBUG "%d:%d starved %d secs by %d:%d who last ran %lu ticks ago.\n", + current->pid, current->prio - 100, ticks/HZ, tsk->pid, + tsk->prio - 100, jiffies - tsk->last_run); + if (ticks >= 5000) + show_task(sem->owner); + printk(KERN_DEBUG "semaphore downed at %s:%d.\n\n", + sem->file, sem->line); + } spin_lock_irqsave(&sem->wait.lock, flags); tsk->state = TASK_UNINTERRUPTIBLE; @@ -96,6 +107,7 @@ struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); unsigned long flags; + int ticks = 0; tsk->state = TASK_INTERRUPTIBLE; spin_lock_irqsave(&sem->wait.lock, flags); @@ -132,7 +144,17 @@ sem->sleepers = 1; /* us - see -1 above */ spin_unlock_irqrestore(&sem->wait.lock, flags); - schedule(); + if (!schedule_timeout(1000) && sem->owner) { + struct task_struct *tsk = (struct task_struct *) sem->owner; + ticks += 1000; + printk(KERN_DEBUG "%d:%d starved %d secs by %d:%d who last ran %lu ticks ago.\n", + current->pid, current->prio - 100, ticks/HZ, tsk->pid, + tsk->prio - 100, jiffies - tsk->last_run); + if (ticks >= 5000) + show_task(sem->owner); + printk(KERN_DEBUG "semaphore downed at %s:%d.\n\n", + sem->file, sem->line); + } spin_lock_irqsave(&sem->wait.lock, flags); tsk->state = TASK_INTERRUPTIBLE; --- ./include/linux/fs.h.org Fri Apr 25 11:35:25 2003 +++ ./include/linux/fs.h Fri Apr 25 12:29:03 2003 @@ -19,6 +19,7 @@ #include #include #include +#include #include struct iovec; --- ./include/linux/rwsem.h.org Mon Feb 10 19:38:17 2003 +++ ./include/linux/rwsem.h Fri Apr 25 07:55:15 2003 @@ -38,18 +38,26 @@ /* * lock for reading */ -static inline void down_read(struct rw_semaphore *sem) +static inline void _down_read(struct rw_semaphore *sem) { might_sleep(); rwsemtrace(sem,"Entering down_read"); __down_read(sem); rwsemtrace(sem,"Leaving down_read"); } +#define down_read(sem) \ +do { \ + _down_read((sem)); \ + current->sem_count++; \ + (sem)->owner = current; \ + (sem)->file = __FILE__; \ + (sem)->line = __LINE__; \ +} while(0); /* * trylock for reading -- returns 1 if successful, 0 if contention */ -static inline int down_read_trylock(struct rw_semaphore *sem) +static inline int _down_read_trylock(struct rw_semaphore *sem) { int ret; rwsemtrace(sem,"Entering down_read_trylock"); @@ -57,22 +65,41 @@ rwsemtrace(sem,"Leaving down_read_trylock"); return ret; } +#define down_read_trylock(sem) \ +({ \ + int _ret =_down_read_trylock((sem)); \ + if (_ret) { \ + current->sem_count++; \ + (sem)->owner = current; \ + (sem)->file = __FILE__; \ + (sem)->line = __LINE__; \ + } \ + _ret; \ +}) /* * lock for writing */ -static inline void down_write(struct rw_semaphore *sem) +static inline void _down_write(struct rw_semaphore *sem) { might_sleep(); rwsemtrace(sem,"Entering down_write"); __down_write(sem); rwsemtrace(sem,"Leaving down_write"); } +#define down_write(sem) \ +do { \ + _down_write((sem)); \ + current->sem_count++; \ + (sem)->owner = current; \ + (sem)->file = __FILE__; \ + (sem)->line = __LINE__; \ +} while (0); /* * trylock for writing -- returns 1 if successful, 0 if contention */ -static inline int down_write_trylock(struct rw_semaphore *sem) +static inline int _down_write_trylock(struct rw_semaphore *sem) { int ret; rwsemtrace(sem,"Entering down_write_trylock"); @@ -80,26 +107,49 @@ rwsemtrace(sem,"Leaving down_write_trylock"); return ret; } +#define down_write_trylock(sem) \ +({ \ + int _ret = _down_write_trylock((sem)); \ + if (_ret) { \ + current->sem_count++; \ + (sem)->owner = current; \ + (sem)->file = __FILE__; \ + (sem)->line = __LINE__; \ + } \ + _ret; \ +}) /* * release a read lock */ -static inline void up_read(struct rw_semaphore *sem) +static inline void _up_read(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering up_read"); __up_read(sem); rwsemtrace(sem,"Leaving up_read"); } +#define up_read(sem) \ +do { \ + current->sem_count--; \ + (sem)->owner = NULL; \ + _up_read((sem)); \ +} while(0); /* * release a write lock */ -static inline void up_write(struct rw_semaphore *sem) +static inline void _up_write(struct rw_semaphore *sem) { rwsemtrace(sem,"Entering up_write"); __up_write(sem); rwsemtrace(sem,"Leaving up_write"); } +#define up_write(sem) \ +do { \ + current->sem_count--; \ + (sem)->owner = NULL; \ + _up_write((sem)); \ +} while(0); /* * downgrade write lock to read lock --- ./include/linux/sched.h.org Fri Apr 25 06:24:33 2003 +++ ./include/linux/sched.h Fri Apr 25 07:59:50 2003 @@ -167,6 +167,7 @@ #define MAX_SCHEDULE_TIMEOUT LONG_MAX extern signed long FASTCALL(schedule_timeout(signed long timeout)); asmlinkage void schedule(void); +extern void show_task(task_t *p); struct namespace; @@ -322,6 +323,7 @@ unsigned long ptrace; int lock_depth; /* Lock depth */ + int sem_count; /* NR semaphores held */ int prio, static_prio; struct list_head run_list; --- ./include/asm-i386/rwsem.h.org Fri Apr 25 06:22:19 2003 +++ ./include/asm-i386/rwsem.h Fri Apr 25 07:56:57 2003 @@ -64,6 +64,9 @@ #if RWSEM_DEBUG int debug; #endif + void *owner; + char *file; + int line; }; /* --- ./include/asm-i386/semaphore.h.org Fri Apr 25 10:50:46 2003 +++ ./include/asm-i386/semaphore.h Fri Apr 25 11:57:28 2003 @@ -48,6 +48,9 @@ #ifdef WAITQUEUE_DEBUG long __magic; #endif + void *owner; + char *file; + int line; }; #ifdef WAITQUEUE_DEBUG @@ -111,7 +114,7 @@ * "__down_failed" is a special asm handler that calls the C * routine that actually waits. See arch/i386/kernel/semaphore.c */ -static inline void down(struct semaphore * sem) +static inline void _down(struct semaphore * sem) { #ifdef WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -130,12 +133,20 @@ :"c" (sem) :"memory"); } +#define down(sem) \ +do { \ + _down((sem)); \ + current->sem_count++; \ + (sem)->owner = current; \ + (sem)->file = __FILE__; \ + (sem)->line = __LINE__; \ +} while (0); /* * Interruptible try to acquire a semaphore. If we obtained * it, return zero. If we were interrupted, returns -EINTR */ -static inline int down_interruptible(struct semaphore * sem) +static inline int _down_interruptible(struct semaphore * sem) { int result; @@ -158,12 +169,23 @@ :"memory"); return result; } +#define down_interruptible(sem) \ +({ \ + int _ret = _down_interruptible((sem)); \ + if (!_ret) { \ + (sem)->owner = current; \ + current->sem_count++; \ + (sem)->file = __FILE__; \ + (sem)->line = __LINE__; \ + } \ + _ret; \ +}) /* * Non-blockingly attempt to down() a semaphore. * Returns zero if we acquired it */ -static inline int down_trylock(struct semaphore * sem) +static inline int _down_trylock(struct semaphore * sem) { int result; @@ -186,6 +208,17 @@ :"memory"); return result; } +#define down_trylock(sem) \ +({ \ + int _ret = _down_trylock((sem)); \ + if (!_ret) { \ + (sem)->owner = current; \ + current->sem_count++; \ + (sem)->file = __FILE__; \ + (sem)->line = __LINE__; \ + } \ + _ret; \ +}) /* * Note! This is subtle. We jump to wake people up only if @@ -193,7 +226,7 @@ * The default case (no contention) will result in NO * jumps for both down() and up(). */ -static inline void up(struct semaphore * sem) +static inline void _up(struct semaphore * sem) { #ifdef WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -212,6 +245,12 @@ :"c" (sem) :"memory"); } +#define up(sem) \ +do { \ + current->sem_count--; \ + (sem)->owner = NULL; \ + _up((sem)); \ +} while (0); #endif #endif --- ./fs/fat/misc.c.org Fri Apr 25 12:24:19 2003 +++ ./fs/fat/misc.c Fri Apr 25 12:24:33 2003 @@ -6,6 +6,7 @@ * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) */ +#include #include #include #include --- ./kernel/fork.c.org Fri Apr 25 06:24:34 2003 +++ ./kernel/fork.c Fri Apr 25 07:41:35 2003 @@ -854,6 +854,7 @@ p->cutime = p->cstime = 0; p->array = NULL; p->lock_depth = -1; /* -1 = no lock */ + p->sem_count = 0; p->start_time = get_jiffies_64(); p->security = NULL; --- ./kernel/printk.c.org Fri Apr 25 06:24:34 2003 +++ ./kernel/printk.c Fri Apr 25 08:04:29 2003 @@ -510,8 +510,10 @@ console_may_schedule = 0; up(&console_sem); spin_unlock_irqrestore(&logbuf_lock, flags); +#if 0 if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) wake_up_interruptible(&log_wait); +#endif } /** console_conditional_schedule - yield the CPU if required --- ./kernel/sched.c.org Fri Apr 25 06:24:34 2003 +++ ./kernel/sched.c Sun Apr 27 07:00:04 2003 @@ -75,6 +75,8 @@ #define STARVATION_LIMIT (10*HZ) #define NODE_THRESHOLD 125 +#define TIMESLICE_GRANULARITY (HZ/20 ?: 1) + /* * If a task is 'interactive' then we reinsert it in the active * array after it has expired its current timeslice. (it will not @@ -1248,6 +1250,27 @@ enqueue_task(p, rq->expired); } else enqueue_task(p, rq->active); + } else { + /* + * Prevent a too long timeslice allowing a task to monopolize + * the CPU. We do this by splitting up the timeslice into + * smaller pieces. + * + * Note: this does not mean the task's timeslices expire or + * get lost in any way, they just might be preempted by + * another task of equal priority. (one with higher + * priority would have preempted this task already.) We + * requeue this task to the end of the list on this priority + * level, which is in essence a round-robin of tasks with + * equal priority. + */ + if (0 && !(p->time_slice % TIMESLICE_GRANULARITY) && + (p->array == rq->active)) { + dequeue_task(p, rq->active); + set_tsk_need_resched(p); + p->prio = effective_prio(p); + enqueue_task(p, rq->active); + } } out: spin_unlock(&rq->lock); @@ -1993,6 +2016,10 @@ if (likely(!rt_task(current))) { dequeue_task(current, array); enqueue_task(current, rq->expired); + if (current->sem_count) { + printk(KERN_DEBUG "%d yielded holding sem.\n", current->pid); + show_task(current); + } } else { list_del(¤t->run_list); list_add_tail(¤t->run_list, array->queue + current->prio); @@ -2155,7 +2182,7 @@ return list_entry(p->sibling.next,struct task_struct,sibling); } -static void show_task(task_t * p) +void show_task(task_t * p) { unsigned long free = 0; task_t *relative; --- ./kernel/ksyms.c.org Fri Apr 25 06:24:34 2003 +++ ./kernel/ksyms.c Fri Apr 25 07:49:02 2003 @@ -466,6 +466,7 @@ EXPORT_SYMBOL(interruptible_sleep_on); EXPORT_SYMBOL(interruptible_sleep_on_timeout); EXPORT_SYMBOL(schedule); +EXPORT_SYMBOL(show_task); #ifdef CONFIG_PREEMPT EXPORT_SYMBOL(preempt_schedule); #endif