From: Peter Chubb <peter@chubb.wattle.id.au>
To: linux-ia64@vger.kernel.org
Subject: [Linux-ia64] First crack at preemption support for IA64
Date: Fri, 15 Nov 2002 02:22:24 +0000 [thread overview]
Message-ID: <marc-linux-ia64-105590709805442@msgid-missing> (raw)
Hi folks,
Here's my first go at preemption support for IA64. I've tested it
on the simulator and I2000 UP. It's very rough around the edges
(especially in entry.S), but someone may have some useful comments for
me... so it's being released here.
So far, it appears that response to mouse movememnts ont eh console,
etc., is *more* jerky with the preempt turned on than without.
Expect a warning from the IDE code when you boot, too. You'll get the
same thing on IA32 with CONFIG_PREEMPT.
The stuff in entry.S is hard to follow. The pseudocode works like
this:
ia64_leave_kernel(bool pKern, bool pUser, machine_context_t ctx)
{
local_irq_disable();
while (pUser && current->threadinfo->flags & (RESCHED | NOTIFY) ||
pKern && preempt_count = 0 &&
current->threadinfo->flags & RESCHED) {
if (pKern)
preempt_count() = PREEMPT_ACTIVE;
if (current->threadinfo->flags & RESCHED)
schedule();
else
notify_resume();
local_irq_disable()
if (pKern)
preempt_count() = 0;
}
set_context(ctx);
}
but the set_context is effectively done in parallel with all of the
other stuff.
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.815 -> 1.816
# arch/ia64/kernel/entry.S 1.21 -> 1.22
# include/asm-ia64/hardirq.h 1.10 -> 1.11
# arch/ia64/Config.help 1.10 -> 1.11
# arch/ia64/kernel/efivars.c 1.8 -> 1.9
# arch/ia64/hp/sim/simserial.c 1.9 -> 1.10
# include/asm-ia64/thread_info.h 1.5 -> 1.6
# arch/ia64/config.in 1.36 -> 1.37
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/11/15 peterc@gelato.unsw.edu.au 1.816
# Preliminary preemption support.
# --------------------------------------------
#
diff -Nru a/arch/ia64/Config.help b/arch/ia64/Config.help
--- a/arch/ia64/Config.help Fri Nov 15 13:07:05 2002
+++ b/arch/ia64/Config.help Fri Nov 15 13:07:05 2002
@@ -567,3 +567,13 @@
Select "16MB" for a small granule size.
Select "64MB" for a large granule size. This is the current default.
+
+CONFIG_PREEMPT
+ This option reduces the latency of the kernel when reacting to
+ real-time or interactive events by allowing a low priority process to
+ be preempted even if it is in kernel mode executing a system call.
+ This allows applications to run more reliably even when the system is
+ under load.
+
+ Say Y here if you are building a kernel for a desktop, embedded
+ or real-time system. Say N if you are unsure.
diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in
--- a/arch/ia64/config.in Fri Nov 15 13:07:05 2002
+++ b/arch/ia64/config.in Fri Nov 15 13:07:05 2002
@@ -117,6 +117,7 @@
fi
bool 'SMP support' CONFIG_SMP
+bool 'Preemptible Kernel' CONFIG_PREEMPT
bool 'Support running of Linux/x86 binaries' CONFIG_IA32_SUPPORT
bool 'Performance monitor support' CONFIG_PERFMON
tristate '/proc/pal support' CONFIG_IA64_PALINFO
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c Fri Nov 15 13:07:05 2002
+++ b/arch/ia64/hp/sim/simserial.c Fri Nov 15 13:07:05 2002
@@ -63,7 +63,6 @@
static char *serial_name = "SimSerial driver";
static char *serial_version = "0.6";
-static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
/*
* This has been extracted from asm/serial.h. We need one eventually but
@@ -235,14 +234,15 @@
if (!tty || !info->xmit.buf) return;
- spin_lock_irqsave(&serial_lock, flags);
+ local_save_flags(flags);
+ local_irq_disable();
if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) = 0) {
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
return;
}
info->xmit.buf[info->xmit.head] = ch;
info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
}
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
@@ -250,7 +250,9 @@
int count;
unsigned long flags;
- spin_lock_irqsave(&serial_lock, flags);
+
+ local_save_flags(flags);
+ local_irq_disable();
if (info->x_char) {
char c = info->x_char;
@@ -293,7 +295,7 @@
info->xmit.tail += count;
}
out:
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
}
static void rs_flush_chars(struct tty_struct *tty)
@@ -334,7 +336,8 @@
break;
}
- spin_lock_irqsave(&serial_lock, flags);
+ local_save_flags(flags);
+ local_irq_disable();
{
c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail,
SERIAL_XMIT_SIZE);
@@ -344,7 +347,7 @@
info->xmit.head = ((info->xmit.head + c) &
(SERIAL_XMIT_SIZE-1));
}
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
buf += c;
count -= c;
@@ -352,7 +355,8 @@
}
up(&tmp_buf_sem);
} else {
- spin_lock_irqsave(&serial_lock, flags);
+ local_save_flags(flags);
+ local_irq_disable();
while (1) {
c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
if (count < c)
@@ -367,7 +371,7 @@
count -= c;
ret += c;
}
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
}
/*
* Hey, we transmit directly from here in our case
@@ -398,9 +402,10 @@
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
- spin_lock_irqsave(&serial_lock, flags);
+ local_save_flags(flags);
+ local_irq_disable();
info->xmit.head = info->xmit.tail = 0;
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
wake_up_interruptible(&tty->write_wait);
@@ -573,7 +578,8 @@
state->irq);
#endif
- spin_lock_irqsave(&serial_lock, flags);
+ local_save_flags(flags);
+ local_irq_disable();
{
/*
* First unlink the serial port from the IRQ chain...
@@ -611,7 +617,7 @@
info->flags &= ~ASYNC_INITIALIZED;
}
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
}
/*
@@ -634,13 +640,14 @@
state = info->state;
- spin_lock_irqsave(&serial_lock, flags);
+ local_irq_save(flags);
+ local_irq_disable();
if (tty_hung_up_p(filp)) {
#ifdef SIMSERIAL_DEBUG
printk("rs_close: hung_up\n");
#endif
MOD_DEC_USE_COUNT;
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
return;
}
#ifdef SIMSERIAL_DEBUG
@@ -665,11 +672,11 @@
}
if (state->count) {
MOD_DEC_USE_COUNT;
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
return;
}
info->flags |= ASYNC_CLOSING;
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
/*
* Now we wait for the transmit buffer to clear; and we notify
@@ -776,7 +783,8 @@
if (!page)
return -ENOMEM;
- spin_lock_irqsave(&serial_lock, flags);
+ local_save_flags(flags);
+ local_irq_disable();
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
@@ -857,11 +865,11 @@
}
info->flags |= ASYNC_INITIALIZED;
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
return 0;
errout:
- spin_unlock_irqrestore(&serial_lock, flags);
+ local_irq_restore(flags);
return retval;
}
diff -Nru a/arch/ia64/kernel/efivars.c b/arch/ia64/kernel/efivars.c
--- a/arch/ia64/kernel/efivars.c Fri Nov 15 13:07:05 2002
+++ b/arch/ia64/kernel/efivars.c Fri Nov 15 13:07:05 2002
@@ -66,6 +66,7 @@
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/efi.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -342,6 +343,9 @@
+/*
+ * Called with BKL held
+ */
static int __init
efivars_init(void)
{
@@ -351,10 +355,11 @@
efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
unsigned long variable_name_size = 1024;
- spin_lock(&efivars_lock);
printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION);
+ BUG_ON(!kernel_locked());
+
/* Since efi.c happens before procfs is available,
we create the directory here if it doesn't
already exist. There's probably a better way
@@ -398,7 +403,6 @@
} while (status != EFI_NOT_FOUND);
kfree(variable_name);
- spin_unlock(&efivars_lock);
return 0;
}
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S Fri Nov 15 13:07:05 2002
+++ b/arch/ia64/kernel/entry.S Fri Nov 15 13:07:05 2002
@@ -570,10 +570,16 @@
GLOBAL_ENTRY(ia64_leave_kernel)
PT_REGS_UNWIND_INFO(0)
// work.need_resched etc. mustn't get changed by this CPU before it returns to userspace:
+.work_recheck:
(pUser) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUser
-(pUser) rsm psr.i
+ rsm psr.i // disable interrupts
;;
-(pUser) adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
+ adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
+(pKern) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
+ ;;
+(pKern) ld4 r21=[r20] // preempt_count ->r21
+ ;;
+(pKern) cmp.eq p6,p0=r21,r0
;;
.work_processed:
(p6) ld4 r18=[r17] // load current_thread_info()->flags
@@ -802,6 +808,11 @@
.work_pending:
tbit.z p6,p0=r18,TIF_NEED_RESCHED // current_thread_info()->need_resched=0?
(p6) br.cond.sptk.few .notify
+(pKern) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1
+ ;;
+(pKern) ssm psr.i
+(pKern) st4 [r20]=r21
+
#if __GNUC__ < 3
br.call.spnt.many rp=invoke_schedule
#else
@@ -811,6 +822,9 @@
rsm psr.i
;;
adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
+ adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
+ ;;
+ st8 [r20]=r0
br.cond.sptk.many .work_processed // re-check
.notify:
@@ -844,7 +858,7 @@
br.cond.sptk ia64_leave_kernel
END(handle_syscall_error)
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
/*
* Invoke schedule_tail(task) while preserving in0-in7, which may be needed
* in case a system call gets restarted.
@@ -861,7 +875,7 @@
br.ret.sptk.many rp
END(ia64_invoke_schedule_tail)
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_SMP || CONFIG_PREEMPT */
#if __GNUC__ < 3
diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h
--- a/include/asm-ia64/hardirq.h Fri Nov 15 13:07:05 2002
+++ b/include/asm-ia64/hardirq.h Fri Nov 15 13:07:05 2002
@@ -83,13 +83,13 @@
#define hardirq_trylock() (!in_interrupt())
#define hardirq_endlock() do { } while (0)
-#define in_atomic() (preempt_count() != 0)
#define irq_enter() (preempt_count() += HARDIRQ_OFFSET)
#if CONFIG_PREEMPT
-# error CONFIG_PREEMT currently not supported.
+# define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
#else
+# define in_atomic() (preempt_count() != 0)
# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
#endif
diff -Nru a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
--- a/include/asm-ia64/thread_info.h Fri Nov 15 13:07:05 2002
+++ b/include/asm-ia64/thread_info.h Fri Nov 15 13:07:05 2002
@@ -15,7 +15,8 @@
#define TI_ADDR_LIMIT 0x10
#define TI_PRE_COUNT 0x18
-#define PREEMPT_ACTIVE 0x4000000
+#define PREEMPT_ACTIVE_BIT 26
+#define PREEMPT_ACTIVE (1<<PREEMPT_ACTIVE_BIT)
#ifndef __ASSEMBLY__
--
Dr Peter Chubb peterc@gelato.unsw.edu.au
You are lost in a maze of BitKeeper repositories, all almost the same.
reply other threads:[~2002-11-15 2:22 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=marc-linux-ia64-105590709805442@msgid-missing \
--to=peter@chubb.wattle.id.au \
--cc=linux-ia64@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox