diff -durN linux-2.6.9-rc4/arch/i386/Kconfig linux-2.6.9-rc4.prw/arch/i386/Kconfig --- linux-2.6.9-rc4/arch/i386/Kconfig 2005-02-25 18:13:58.037135296 +0100 +++ linux-2.6.9-rc4.prw/arch/i386/Kconfig 2005-02-25 17:39:55.000000000 +0100 @@ -586,6 +586,19 @@ system. Say N if you are unsure. +config PRW + bool "PRW-Locks" + default y if PREEMPT_REALTIME + depends on PREEMPT_REALTIME + help + Use Witold Jaworski's preemtible read-write locks instead of original kernel read-write locks. The new Locks are based on a mutex implementation with priority inheriting. It is safe to use these locks, because the original kernel read-write locks are not repleaced yet. + +config MAX_READER + int "Maximum number of READER in a Read-Write Lock (1-100000)" + range 1 100000 + depends on PRW + default "4" + config SUB_PMUTEX bool "Replace spinlocks with priority inheriting mutex." default y if PREEMPT_REALTIME diff -durN linux-2.6.9-rc4/include/linux/prw.h linux-2.6.9-rc4.prw/include/linux/prw.h --- linux-2.6.9-rc4/include/linux/prw.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9-rc4.prw/include/linux/prw.h 2005-02-25 17:39:09.000000000 +0100 @@ -0,0 +1,60 @@ +/* + * pmutex.h -- mutex implementation with priority inheritance + * + * See + * http://inf33-www.informatik.unibw-muenchen.de/research/linux/mutex.html + * for details of the used priority inheritance protocol. + * + * Copyright (C) 2002, 2003, 2004 Dirk Grambow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + _> + */ + +#include +#include + +#define RW_WRITE 1 +#define RW_READ 0 +#define MAX_READER CONFIG_MAX_READER + +struct prw_sleeper_list { + struct list_head list; + int prw_type; + unsigned long initial_prio; + struct task_struct *task; +}; + +typedef struct prw_sleeper_list prw_sleeper_list_t; + +typedef struct prw { + int mrw_reader; + int mrw_wwriter; + int mrw_status; + raw_spinlock_t mrw_spin_lock; + struct list_head mrw_owner; + struct list_head mrw_waiter; +} prw_t; + +#define MAX_PRIORI 100 +#define DECLARE_PRW(x) prw_t (x) = {0, 0, RW_READ, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((x).mrw_owner), LIST_HEAD_INIT((x).mrw_waiter)} + + +extern void prw_init(prw_t *mtx); +extern void prw_read_lock(prw_t *mtx); +extern void prw_read_unlock(prw_t *mtx); +extern void prw_write_lock(prw_t *mtx); +extern void prw_write_unlock(prw_t *mtx); diff -durN linux-2.6.9-rc4/kernel/Makefile linux-2.6.9-rc4.prw/kernel/Makefile --- linux-2.6.9-rc4/kernel/Makefile 2005-02-25 18:14:12.000000000 +0100 +++ linux-2.6.9-rc4.prw/kernel/Makefile 2005-02-25 17:01:04.000000000 +0100 @@ -34,6 +34,7 @@ obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_CRASH_DUMP) += crash.o obj-$(CONFIG_SUB_PMUTEX) += pmutex.o +obj-$(CONFIG_PRW) += prw.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -durN linux-2.6.9-rc4/kernel/prw.c linux-2.6.9-rc4.prw/kernel/prw.c --- linux-2.6.9-rc4/kernel/prw.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9-rc4.prw/kernel/prw.c 2005-02-25 17:51:53.000000000 +0100 @@ -0,0 +1,298 @@ +/* + * pmutex.c -- mutex implementation with priority inheritance + * + * See + * http://inf33-www.informatik.unibw-muenchen.de/research/linux/mutex.html + * for details of the used priority inheritance protocol. + * + * Copyright (C) 2002, 2003, 2004 Dirk Grambow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +extern void setscheduler_pi(task_t *p, int policy, unsigned long prio); + +inline void prw_init(prw_t *mtx) +{ + preempt_disable(); + _spin_lock_init(&mtx->mrw_spin_lock); + preempt_enable(); + + _spin_lock(&mtx->mrw_spin_lock); + mtx->mrw_reader = 0; + mtx->mrw_wwriter = 0; + mtx->mrw_status = RW_READ; + INIT_LIST_HEAD(&mtx->mrw_owner); + INIT_LIST_HEAD(&mtx->mrw_waiter); + _spin_unlock(&mtx->mrw_spin_lock); +} + + +void prw_read_lock(prw_t *mtx) +{ + mtx, current->pid, current->rt_priority); + struct list_head *pos; + struct prw_sleeper_list *new; + task_t *owner; + int highest, act; + struct list_head *next = 0; + prw_sleeper_list_t *entry = 0; + + new = kmalloc (sizeof (struct prw_sleeper_list), GFP_KERNEL); + memset (new, 0, sizeof (*new)); + + INIT_LIST_HEAD(&new->list); + new->task = current; + new->initial_prio = current->rt_priority; + new->prw_type = RW_READ; + _spin_lock(&mtx->mrw_spin_lock); + + /*Keine wartendende Writer*/ + if (mtx->mrw_wwriter == 0) { + /*Reader belegt LOCK*/ + if (mtx->mrw_readermrw_status==RW_READ) { + mtx->mrw_reader++; + list_add_tail(&new->list, &mtx->mrw_owner); + _spin_unlock(&mtx->mrw_spin_lock); + return; + } + else { + list_add_tail(&new->list, &mtx->mrw_waiter); + list_for_each(pos, &mtx->mrw_owner) { + owner = list_entry(pos, prw_sleeper_list_t, list)->task; + if (current->rt_priority > owner->rt_priority) { + //sys_sched_setscheduler(owner->pid, owner->rt_priority ? -1 : SCHED_FIFO, (struct sched_param *)&(current->rt_priority)); + setscheduler_pi(owner, owner->rt_priority ? -1 : SCHED_FIFO, + current->rt_priority); + break; + } + } + current->state = TASK_UNINTERRUPTIBLE; + _spin_unlock(&mtx->mrw_spin_lock); + schedule(); + return; + } + } + + /*Es gibt wartendende Writer*/ + else { + /*Suche Priorität des höchstprioren wartenden Writers*/ + highest = 0; + list_for_each(pos, &mtx->mrw_waiter) { + entry = list_entry(pos, prw_sleeper_list_t, list); + if ( entry->prw_type == RW_WRITE) { + act = entry->task->rt_priority; + if (act > highest) { + highest = act; + next = pos; + } + } + } + /*Gefundene Priorität niedriger als aktueller Reader -> dieser belegt LOCK*/ + if ( mtx->mrw_readermrw_status==RW_READ\ + && current->rt_priority > highest ){ + mtx->mrw_reader++; + list_add_tail(&new->list, &mtx->mrw_owner); + _spin_unlock(&mtx->mrw_spin_lock); + return; + } + /*Ab in die Warteliste*/ + list_add_tail(&new->list, &mtx->mrw_waiter); + list_for_each(pos, &mtx->mrw_owner) { + owner = list_entry(pos, prw_sleeper_list_t, list)->task; + if (current->rt_priority > owner->rt_priority) { + //sys_sched_setscheduler(owner->pid, owner->rt_priority ? -1 : SCHED_FIFO, (struct sched_param *)&(current->rt_priority)); + setscheduler_pi(owner, owner->rt_priority ? -1 : SCHED_FIFO, + current->rt_priority); + break; + } + } + current->state = TASK_UNINTERRUPTIBLE; + _spin_unlock(&mtx->mrw_spin_lock); + schedule(); + } +} + +void prw_read_unlock(prw_t *mtx) +{ + mtx, current->pid, current->rt_priority); + int highest, act; + struct list_head *pos; + struct list_head *next = 0; + prw_sleeper_list_t *entry = 0; + task_t *owner; + + _spin_lock(&mtx->mrw_spin_lock); + + /*Finde aktuellen Prozess in der Ownerliste und lösche dich daraus*/ + mtx->mrw_reader--; + list_for_each(pos, &mtx->mrw_owner) { + owner = list_entry(pos, prw_sleeper_list_t, list)->task; + if (owner->pid == current->pid) { + entry = list_entry(pos, prw_sleeper_list_t, list); + break; + } + } + list_del(pos); + + if (entry->initial_prio != current->rt_priority) { + //sys_sched_setscheduler(current->pid, entry->initial_prio ? -1 : SCHED_NORMAL, (struct sched_param *)&(entry->initial_prio)); + setscheduler_pi(current, entry->initial_prio ? -1 : SCHED_FIFO, + entry->initial_prio); + } + + /* Niemand will das LOCK*/ + if (list_empty(&mtx->mrw_waiter)) { + _spin_unlock(&mtx->mrw_spin_lock); + return; + } + + /* Prozess mit höchster Priorität gesucht */ + highest = 0; + list_for_each(pos, &mtx->mrw_waiter) { + entry = list_entry(pos, prw_sleeper_list_t, list); + act = entry->task->rt_priority; + if (act > highest) { + highest = act; + next = pos; + } + } + entry = list_entry(next, prw_sleeper_list_t, list); + + /*gefundener Prozess ist ein Writer und es gibt noch aktive Reader*/ + if (entry->prw_type == RW_WRITE && mtx->mrw_reader > 0 ) { + _spin_unlock(&mtx->mrw_spin_lock); + return; + } + /*gefundener Prozess ist ein Writer */ + if (entry->prw_type == RW_WRITE) { + mtx->mrw_status = RW_WRITE; + mtx->mrw_wwriter--; + } + /*gefundener Prozess ist ein Reader*/ + else + mtx->mrw_reader++; + list_del(next); + list_add_tail(next, &mtx->mrw_owner); + + wake_up_process(entry->task); + _spin_unlock(&mtx->mrw_spin_lock); +} + +void prw_write_lock(prw_t *mtx) +{ + mtx, current->pid, current->rt_priority); + struct list_head *pos; + struct prw_sleeper_list *new; + task_t *owner; + + new = kmalloc (sizeof (struct prw_sleeper_list), GFP_KERNEL); + memset (new, 0, sizeof (*new)); + + INIT_LIST_HEAD(&new->list); + new->task = current; + new->initial_prio = current->rt_priority; + new->prw_type = RW_WRITE; + _spin_lock(&mtx->mrw_spin_lock); + + if (mtx->mrw_reader == 0 && mtx->mrw_status == RW_READ) { + mtx->mrw_status = RW_WRITE; + list_add_tail(&new->list, &mtx->mrw_owner); + _spin_unlock(&mtx->mrw_spin_lock); + return; + } + list_add_tail(&new->list, &mtx->mrw_waiter); + list_for_each(pos, &mtx->mrw_owner) { + owner = list_entry(pos, prw_sleeper_list_t, list)->task; + if (current->rt_priority > owner->rt_priority) { + setscheduler_pi(owner, owner->rt_priority ? -1 : SCHED_FIFO, + current->rt_priority); + } + } + mtx->mrw_wwriter++; + + current->state = TASK_UNINTERRUPTIBLE; + _spin_unlock(&mtx->mrw_spin_lock); + schedule(); +} + + +void prw_write_unlock(prw_t *mtx) +{ + int highest, act; + struct list_head *pos; + struct list_head *next = 0; + prw_sleeper_list_t *entry; + + _spin_lock(&mtx->mrw_spin_lock); + + /* Nur ein Eintrag in der Owner-Liste, da WRITE-LOCK - keine Suche!*/ + pos = mtx->mrw_owner.next; + entry = list_entry(pos, prw_sleeper_list_t, list); + list_del(pos); + + if (entry->initial_prio != current->rt_priority) { + setscheduler_pi(current, entry->initial_prio ? -1 : SCHED_FIFO, + entry->initial_prio); + } + + /* Niemand will das LOCK*/ + if (list_empty(&mtx->mrw_waiter)) { + mtx->mrw_status = RW_READ; + _spin_unlock(&mtx->mrw_spin_lock); + return; + } + + /* Nächster hochpriorer Prozeß erhält LOCK (Reader oder Writer)*/ + highest = 0; + list_for_each(pos, &mtx->mrw_waiter) { + act = (list_entry(pos, prw_sleeper_list_t, list)->task)->rt_priority; + if (act > highest) { + highest = act; + next = pos; + } + } + + entry = list_entry(next, prw_sleeper_list_t, list); + if (likely(entry->prw_type == RW_READ)) { + mtx->mrw_reader++; + mtx->mrw_status = RW_READ; + } + else { + mtx->mrw_wwriter--; + } + list_del(next); + list_add_tail(next, &mtx->mrw_owner); + wake_up_process(entry->task); + _spin_unlock(&mtx->mrw_spin_lock); +} + +EXPORT_SYMBOL(prw_read_lock); +EXPORT_SYMBOL(prw_read_unlock); +EXPORT_SYMBOL(prw_write_lock); +EXPORT_SYMBOL(prw_write_unlock); +