Skip to contentSkip to conversation

core changes for 2.5.67-bk6

PATCH In review William Lee Irwin III 2 participants 5 messages Apr 15, 2003 – Apr 18, 2003

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

PATCH 1/3 core changes for 2.5.67-bk6

Core changes for extended cpu masks. Basically use a machine word #if NR_CPUS < BITS_PER_LONG, otherwise, use a structure with an array of unsigned longs for it. Sprinkle it around the scheduler and a few other odd places that play with the cpu bitmasks. Back-ended by a bitmap ADT capable of dealing with arbitrary-width bitmaps, with the obvious micro-optimizations for NR_CPUS < BITS_PER_LONG and UP.

NR_CPUS % BITS_PER_LONG != 0 is invalid while NR_CPUS > BITS_PER_LONG.

cpus_weight(), cpus_shift_left(), cpus_shift_right(), and cpus_complement() are from Martin Hicks.

drivers/base/node.c +11 -2
diff -urpN linux-2.5.67-bk6/drivers/base/node.c cpu-2.5.67-bk6-1/drivers/base/node.c
@@ -7,7 +7,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/node.h>
-
+#include <linux/cpumask.h>
 #include <asm/topology.h>
 
 
@@ -31,7 +31,16 @@ struct device_driver node_driver = {
 static ssize_t node_read_cpumap(struct device * dev, char * buf)
 {
 	struct node *node_dev = to_node(to_root(dev));
-        return sprintf(buf,"%lx\n",node_dev->cpumap);
+	cpumask_t tmp = node_dev->cpumap;
+	int k, len = 0;
+
+	for (k = 0; k < CPU_ARRAY_SIZE; ++k) {
+        	int j = sprintf(buf,"%lx\n", cpus_coerce(tmp));
+		len += j;
+		buf += j;
+		cpus_shift_right(tmp, tmp, BITS_PER_LONG);
+	}
+	return len;
 }
 static DEVICE_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL);
 
include/linux/bitmap.h +131 -0

131 lines not on this page · raw message

include/linux/cpumask.h +112 -0

112 lines not on this page · raw message

include/linux/init_task.h +1 -1
diff -urpN linux-2.5.67-bk6/include/linux/init_task.h cpu-2.5.67-bk6-1/include/linux/init_task.h
@@ -68,7 +68,7 @@
 	.prio		= MAX_PRIO-20,					\
 	.static_prio	= MAX_PRIO-20,					\
 	.policy		= SCHED_NORMAL,					\
-	.cpus_allowed	= ~0UL,						\
+	.cpus_allowed	= CPU_MASK_ALL,					\
 	.mm		= NULL,						\
 	.active_mm	= &init_mm,					\
 	.run_list	= LIST_HEAD_INIT(tsk.run_list),			\
include/linux/irq.h +1 -1
diff -urpN linux-2.5.67-bk6/include/linux/irq.h cpu-2.5.67-bk6-1/include/linux/irq.h
@@ -44,7 +44,7 @@ struct hw_interrupt_type {
 	void (*disable)(unsigned int irq);
 	void (*ack)(unsigned int irq);
 	void (*end)(unsigned int irq);
-	void (*set_affinity)(unsigned int irq, unsigned long mask);
+	void (*set_affinity)(unsigned int irq, unsigned long dest);
 };
 
 typedef struct hw_interrupt_type  hw_irq_controller;
include/linux/node.h +2 -1
diff -urpN linux-2.5.67-bk6/include/linux/node.h cpu-2.5.67-bk6-1/include/linux/node.h
@@ -20,9 +20,10 @@
 #define _LINUX_NODE_H_
 
 #include <linux/device.h>
+#include <linux/cpumask.h>
 
 struct node {
-	unsigned long cpumap;	/* Bitmap of CPUs on the Node */
+	cpumask_t cpumap;	/* Bitmap of CPUs on the Node */
 	struct sys_root sysroot;
 };
 
include/linux/rcupdate.h +3 -2
diff -urpN linux-2.5.67-bk6/include/linux/rcupdate.h cpu-2.5.67-bk6-1/include/linux/rcupdate.h
@@ -40,6 +40,7 @@
 #include <linux/spinlock.h>
 #include <linux/threads.h>
 #include <linux/percpu.h>
+#include <linux/cpumask.h>
 
 /**
  * struct rcu_head - callback structure for use with RCU
@@ -67,7 +68,7 @@ struct rcu_ctrlblk {
 	spinlock_t	mutex;		/* Guard this struct                  */
 	long		curbatch;	/* Current batch number.	      */
 	long		maxbatch;	/* Max requested batch number.        */
-	unsigned long	rcu_cpu_mask; 	/* CPUs that need to switch in order  */
+	cpumask_t	rcu_cpu_mask; 	/* CPUs that need to switch in order  */
 					/* for current batch to proceed.      */
 };
 
@@ -114,7 +115,7 @@ static inline int rcu_pending(int cpu) 
 	     rcu_batch_before(RCU_batch(cpu), rcu_ctrlblk.curbatch)) ||
 	    (list_empty(&RCU_curlist(cpu)) &&
 			 !list_empty(&RCU_nxtlist(cpu))) ||
-	    test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask))
+	    cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask))
 		return 1;
 	else
 		return 0;
include/linux/sched.h +4 -3
diff -urpN linux-2.5.67-bk6/include/linux/sched.h cpu-2.5.67-bk6-1/include/linux/sched.h
@@ -12,6 +12,7 @@
 #include <linux/jiffies.h>
 #include <linux/rbtree.h>
 #include <linux/thread_info.h>
+#include <linux/cpumask.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -197,7 +198,7 @@ struct mm_struct {
 	unsigned long arg_start, arg_end, env_start, env_end;
 	unsigned long rss, total_vm, locked_vm;
 	unsigned long def_flags;
-	unsigned long cpu_vm_mask;
+	cpumask_t cpu_vm_mask;
 	unsigned long swap_address;
 
 	unsigned dumpable:1;
@@ -331,7 +332,7 @@ struct task_struct {
 	unsigned long last_run;
 
 	unsigned long policy;
-	unsigned long cpus_allowed;
+	cpumask_t cpus_allowed;
 	unsigned int time_slice, first_time_slice;
 
 	struct list_head tasks;
@@ -467,7 +468,7 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_KSWAPD	0x00040000	/* I am kswapd */
 
 #if CONFIG_SMP
-extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
+extern void set_cpus_allowed(task_t *p, cpumask_t new_mask);
 #else
 # define set_cpus_allowed(p, new_mask) do { } while (0)
 #endif
include/linux/smp.h +0 -3
diff -urpN linux-2.5.67-bk6/include/linux/smp.h cpu-2.5.67-bk6-1/include/linux/smp.h
@@ -115,9 +115,6 @@ void smp_prepare_boot_cpu(void);
 #define on_each_cpu(func,info,retry,wait)	({ func(info); 0; })
 static inline void smp_send_reschedule(int cpu) { }
 static inline void smp_send_reschedule_all(void) { }
-#define cpu_online_map				1
-#define cpu_online(cpu)				({ BUG_ON((cpu) != 0); 1; })
-#define num_online_cpus()			1
 #define num_booting_cpus()			1
 #define cpu_possible(cpu)			({ BUG_ON((cpu) != 0); 1; })
 #define smp_prepare_boot_cpu()			do {} while (0)
kernel/fork.c +1 -1
diff -urpN linux-2.5.67-bk6/kernel/fork.c cpu-2.5.67-bk6-1/kernel/fork.c
@@ -257,7 +257,7 @@ static inline int dup_mmap(struct mm_str
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->map_count = 0;
 	mm->rss = 0;
-	mm->cpu_vm_mask = 0;
+	cpus_clear(mm->cpu_vm_mask);
 	pprev = &mm->mmap;
 
 	/*
kernel/module.c +6 -3
diff -urpN linux-2.5.67-bk6/kernel/module.c cpu-2.5.67-bk6-1/kernel/module.c
@@ -300,6 +300,7 @@ static int stopref(void *cpu)
 {
 	int irqs_disabled = 0;
 	int prepared = 0;
+	cpumask_t allowed_mask = CPU_MASK_NONE;
 
 	sprintf(current->comm, "kmodule%lu\n", (unsigned long)cpu);
 
@@ -308,7 +309,8 @@ static int stopref(void *cpu)
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 	setscheduler(current->pid, SCHED_FIFO, &param);
 #endif
-	set_cpus_allowed(current, 1UL << (unsigned long)cpu);
+	cpu_set((int)cpu, allowed_mask);
+	set_cpus_allowed(current, allowed_mask);
 
 	/* Ack: we are alive */
 	atomic_inc(&stopref_thread_ack);
@@ -361,7 +363,7 @@ static void stopref_set_state(enum stopr
 static int stop_refcounts(void)
 {
 	unsigned int i, cpu;
-	unsigned long old_allowed;
+	cpumask_t old_allowed, allowed_mask = CPU_MASK_NONE;
 	int ret = 0;
 
 	/* One thread per cpu.  We'll do our own. */
@@ -369,7 +371,8 @@ static int stop_refcounts(void)
 
 	/* FIXME: racy with set_cpus_allowed. */
 	old_allowed = current->cpus_allowed;
-	set_cpus_allowed(current, 1UL << (unsigned long)cpu);
+	cpu_set(cpu, allowed_mask);
+	set_cpus_allowed(current, allowed_mask);
 
 	atomic_set(&stopref_thread_ack, 0);
 	stopref_num_threads = 0;
kernel/rcupdate.c +6 -6
diff -urpN linux-2.5.67-bk6/kernel/rcupdate.c cpu-2.5.67-bk6-1/kernel/rcupdate.c
@@ -47,7 +47,7 @@
 /* Definition for rcupdate control block. */
 struct rcu_ctrlblk rcu_ctrlblk = 
 	{ .mutex = SPIN_LOCK_UNLOCKED, .curbatch = 1, 
-	  .maxbatch = 1, .rcu_cpu_mask = 0 };
+	  .maxbatch = 1, .rcu_cpu_mask = CPU_MASK_NONE };
 DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
 
 /* Fake initialization required by compiler */
@@ -106,7 +106,7 @@ static void rcu_start_batch(long newbatc
 		rcu_ctrlblk.maxbatch = newbatch;
 	}
 	if (rcu_batch_before(rcu_ctrlblk.maxbatch, rcu_ctrlblk.curbatch) ||
-	    (rcu_ctrlblk.rcu_cpu_mask != 0)) {
+	    !cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
 		return;
 	}
 	rcu_ctrlblk.rcu_cpu_mask = cpu_online_map;
@@ -121,7 +121,7 @@ static void rcu_check_quiescent_state(vo
 {
 	int cpu = smp_processor_id();
 
-	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) {
+	if (!cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask)) {
 		return;
 	}
 
@@ -139,13 +139,13 @@ static void rcu_check_quiescent_state(vo
 	}
 
 	spin_lock(&rcu_ctrlblk.mutex);
-	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) {
+	if (!cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask)) {
 		spin_unlock(&rcu_ctrlblk.mutex);
 		return;
 	}
-	clear_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask);
+	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
 	RCU_last_qsctr(cpu) = RCU_QSCTR_INVALID;
-	if (rcu_ctrlblk.rcu_cpu_mask != 0) {
+	if (!cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
 		spin_unlock(&rcu_ctrlblk.mutex);
 		return;
 	}
kernel/sched.c +31 -25

182 lines not on this page · raw message

kernel/softirq.c +4 -3
diff -urpN linux-2.5.67-bk6/kernel/softirq.c cpu-2.5.67-bk6-1/kernel/softirq.c
@@ -308,15 +308,16 @@ void __init softirq_init(void)
 static int ksoftirqd(void * __bind_cpu)
 {
 	int cpu = (int) (long) __bind_cpu;
+	cpumask_t allowed_mask = CPU_MASK_NONE;
 
 	daemonize("ksoftirqd/%d", cpu);
 	set_user_nice(current, 19);
 	current->flags |= PF_IOTHREAD;
 
 	/* Migrate to the right CPU */
-	set_cpus_allowed(current, 1UL << cpu);
-	if (smp_processor_id() != cpu)
-		BUG();
+	cpu_set(cpu, allowed_mask);
+	set_cpus_allowed(current, allowed_mask);
+	BUG_ON(smp_processor_id() != cpu);
 
 	__set_current_state(TASK_INTERRUPTIBLE);
 	mb();
kernel/workqueue.c +3 -1
diff -urpN linux-2.5.67-bk6/kernel/workqueue.c cpu-2.5.67-bk6-1/kernel/workqueue.c
@@ -169,6 +169,7 @@ static int worker_thread(void *__startup
 	int cpu = cwq - cwq->wq->cpu_wq;
 	DECLARE_WAITQUEUE(wait, current);
 	struct k_sigaction sa;
+	cpumask_t allowed_mask = CPU_MASK_NONE;
 
 	daemonize("%s/%d", startup->name, cpu);
 	allow_signal(SIGCHLD);
@@ -176,7 +177,8 @@ static int worker_thread(void *__startup
 	cwq->thread = current;
 
 	set_user_nice(current, -10);
-	set_cpus_allowed(current, 1UL << cpu);
+	cpu_set(cpu, allowed_mask);
+	set_cpus_allowed(current, allowed_mask);
 
 	complete(&startup->done);
 
#1 lore raw

PATCH 2/3 i386 changes for 2.5.67-bk6

Quoted 1 line · William Lee Irwin III

Core changes for extended cpu masks. Basically use a machine word

i386 changes for extended cpu masks. Basically force various things that can possibly be used with NR_CPUS > BITS_PER_LONG in arch/i386 to pass typechecking and use the cpumask_t data type. For things that simply can't be used with the larger systems, I use the cpus_coerce() escape hatch to avoid things getting awkward.

Changes made only for flat logical tinySMP boxen and NUMA-Q; voyager and "other" (not sure what "bigsmp" refers to) kind of got left out since I don't really know my way around their code and I don't have any systems of their kind to testboot on.

arch/i386/kernel/apic.c +2 -1
diff -urpN linux-2.5.67-bk6/arch/i386/kernel/apic.c cpu-2.5.67-bk6-1/arch/i386/kernel/apic.c
@@ -1136,7 +1136,8 @@ int __init APIC_init_uniprocessor (void)
 
 	connect_bsp_APIC();
 
-	phys_cpu_present_map = 1 << boot_cpu_physical_apicid;
+	cpus_clear(phys_cpu_present_map);
+	cpu_set(boot_cpu_physical_apicid, phys_cpu_present_map);
 
 	setup_local_APIC();
 
arch/i386/kernel/cpu/proc.c +1 -1
diff -urpN linux-2.5.67-bk6/arch/i386/kernel/cpu/proc.c cpu-2.5.67-bk6-1/arch/i386/kernel/cpu/proc.c
@@ -60,7 +60,7 @@ static int show_cpuinfo(struct seq_file 
 	int fpu_exception;
 
 #ifdef CONFIG_SMP
-	if (!(cpu_online_map & (1<<n)))
+	if (!cpu_online(n))
 		return 0;
 #endif
 	seq_printf(m, "processor\t: %d\n"
arch/i386/kernel/io_apic.c +28 -21

143 lines not on this page · raw message

arch/i386/kernel/irq.c +30 -13

108 lines not on this page · raw message

arch/i386/kernel/ldt.c +3 -1
diff -urpN linux-2.5.67-bk6/arch/i386/kernel/ldt.c cpu-2.5.67-bk6-1/arch/i386/kernel/ldt.c
@@ -56,9 +56,11 @@ static int alloc_ldt(mm_context_t *pc, i
 
 	if (reload) {
 #ifdef CONFIG_SMP
+		cpumask_t tmp = CPU_MASK_NONE;
 		preempt_disable();
+		cpu_set(smp_processor_id(), tmp);
 		load_LDT(pc);
-		if (current->mm->cpu_vm_mask != (1 << smp_processor_id()))
+		if (!cpu_isset(smp_processor_id(), current->mm->cpu_vm_mask))
 			smp_call_function(flush_ldt, 0, 1, 1);
 		preempt_enable();
 #else
arch/i386/kernel/mpparse.c +4 -2
diff -urpN linux-2.5.67-bk6/arch/i386/kernel/mpparse.c cpu-2.5.67-bk6-1/arch/i386/kernel/mpparse.c
@@ -70,7 +70,7 @@ unsigned int boot_cpu_logical_apicid = -
 static unsigned int __initdata num_processors;
 
 /* Bitmask of physically existing CPUs */
-unsigned long phys_cpu_present_map;
+cpumask_t phys_cpu_present_map;
 
 int x86_summit = 0;
 u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
@@ -106,6 +106,7 @@ static struct mpc_config_translation *tr
 void __init MP_processor_info (struct mpc_config_processor *m)
 {
  	int ver, apicid;
+	cpumask_t tmp;
  	
 	if (!(m->mpc_cpuflag & CPU_ENABLED))
 		return;
@@ -176,7 +177,8 @@ void __init MP_processor_info (struct mp
 	}
 	ver = m->mpc_apicver;
 
-	phys_cpu_present_map |= apicid_to_cpu_present(apicid);
+	tmp = apicid_to_cpu_present(apicid);
+	cpus_or(phys_cpu_present_map, phys_cpu_present_map, tmp);
 	
 	/*
 	 * Validate version
arch/i386/kernel/reboot.c +1 -1
diff -urpN linux-2.5.67-bk6/arch/i386/kernel/reboot.c cpu-2.5.67-bk6-1/arch/i386/kernel/reboot.c
@@ -226,7 +226,7 @@ void machine_restart(char * __unused)
 		   if its not, default to the BSP */
 		if ((reboot_cpu == -1) ||  
 		      (reboot_cpu > (NR_CPUS -1))  || 
-		      !(phys_cpu_present_map & (1<<cpuid))) 
+		      !(cpu_isset(cpuid, phys_cpu_present_map)))
 			reboot_cpu = boot_cpu_physical_apicid;
 
 		reboot_smp = 0;  /* use this as a flag to only go through this once*/
arch/i386/kernel/smp.c +47 -33

201 lines not on this page · raw message

arch/i386/kernel/smpboot.c +36 -34

225 lines not on this page · raw message

include/asm-i386/highmem.h +6 -0
diff -urpN linux-2.5.67-bk6/include/asm-i386/highmem.h cpu-2.5.67-bk6-1/include/asm-i386/highmem.h
@@ -22,6 +22,7 @@
 
 #include <linux/config.h>
 #include <linux/interrupt.h>
+#include <linux/threads.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 
@@ -39,7 +40,12 @@ extern void kmap_init(void);
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
+#if NR_CPUS <= 32
 #define PKMAP_BASE (0xff800000UL)
+#else
+#define PKMAP_BASE (0xff600000UL)
+#endif
+
 #ifdef CONFIG_X86_PAE
 #define LAST_PKMAP 512
 #else
include/asm-i386/mach-default/mach_apic.h +21 -9
diff -urpN linux-2.5.67-bk6/include/asm-i386/mach-default/mach_apic.h cpu-2.5.67-bk6-1/include/asm-i386/mach-default/mach_apic.h
@@ -3,8 +3,12 @@
 
 #define APIC_DFR_VALUE	(APIC_DFR_FLAT)
 
+/*
+ * Flat mode can't support large numbers of cpus.
+ * The first word of cpu_online_map should cover us.
+ */
 #ifdef CONFIG_SMP
- #define TARGET_CPUS (cpu_online_map)
+ #define TARGET_CPUS cpus_coerce(cpu_online_map)
 #else
  #define TARGET_CPUS 0x01
 #endif
@@ -17,12 +21,13 @@
 
 #define APIC_BROADCAST_ID      0x0F
 #define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid))
-#define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit))
+#define check_apicid_present(bit) cpu_isset(bit, phys_cpu_present_map)
 
+#if defined(CONFIG_X86_LOCAL_APIC) || defined(CONFIG_X86_UP_APIC)
 static inline int apic_id_registered(void)
 {
-	return (test_bit(GET_APIC_ID(apic_read(APIC_ID)), 
-						&phys_cpu_present_map));
+	return cpu_isset(GET_APIC_ID(apic_read(APIC_ID)),
+				phys_cpu_present_map);
 }
 
 /*
@@ -41,10 +46,14 @@ static inline void init_apic_ldr(void)
 	val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
 	apic_write_around(APIC_LDR, val);
 }
+#endif
 
-static inline ulong ioapic_phys_id_map(ulong phys_map)
+/*
+ * Only small machines use this APIC mode.
+ */
+static inline unsigned long ioapic_phys_id_map(cpumask_t phys_map)
 {
-	return phys_map;
+	return cpus_coerce(phys_map);
 }
 
 static inline void clustered_apic_check(void)
@@ -74,9 +83,12 @@ static inline int cpu_present_to_apicid(
 	return  mps_cpu;
 }
 
-static inline unsigned long apicid_to_cpu_present(int phys_apicid)
+static inline cpumask_t apicid_to_cpu_present(int phys_apicid)
 {
-	return (1ul << phys_apicid);
+	cpumask_t mask;
+	cpus_clear(mask);
+	cpu_set(phys_apicid, mask);
+	return mask;
 }
 
 static inline int mpc_apic_id(struct mpc_config_processor *m, 
@@ -96,7 +108,7 @@ static inline void setup_portio_remap(vo
 
 static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
 {
-	return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map);
+	return cpu_isset(boot_cpu_physical_apicid, phys_cpu_present_map);
 }
 
 #endif /* __ASM_MACH_APIC_H */
include/asm-i386/mach-default/mach_ipi.h +2 -2
diff -urpN linux-2.5.67-bk6/include/asm-i386/mach-default/mach_ipi.h cpu-2.5.67-bk6-1/include/asm-i386/mach-default/mach_ipi.h
@@ -1,10 +1,10 @@
 #ifndef __ASM_MACH_IPI_H
 #define __ASM_MACH_IPI_H
 
-static inline void send_IPI_mask_bitmask(int mask, int vector);
+static inline void send_IPI_mask_bitmask(cpumask_t cpumask, int vector);
 static inline void __send_IPI_shortcut(unsigned int shortcut, int vector);
 
-static inline void send_IPI_mask(int mask, int vector)
+static inline void send_IPI_mask(cpumask_t mask, int vector)
 {
 	send_IPI_mask_bitmask(mask, vector);
 }
include/asm-i386/mach-numaq/mach_apic.h +12 -7
diff -urpN linux-2.5.67-bk6/include/asm-i386/mach-numaq/mach_apic.h cpu-2.5.67-bk6-1/include/asm-i386/mach-numaq/mach_apic.h
@@ -12,12 +12,12 @@
 #define INT_DEST_MODE 0     /* physical delivery on LOCAL quad */
  
 #define APIC_BROADCAST_ID      0x0F
-#define check_apicid_used(bitmap, apicid) ((bitmap) & (1 << (apicid)))
-#define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit))
+#define check_apicid_used(bitmap, apicid) cpu_isset(apicid, bitmap)
+#define check_apicid_present(bit)	cpu_isset(bit, phys_cpu_present_map)
 
 static inline int apic_id_registered(void)
 {
-	return (1);
+	return 1;
 }
 
 static inline void init_apic_ldr(void)
@@ -40,10 +40,10 @@ static inline int multi_timer_check(int 
 	return (apic != 0 && irq == 0);
 }
 
-static inline ulong ioapic_phys_id_map(ulong phys_map)
+static inline unsigned long ioapic_phys_id_map(cpumask_t phys_map)
 {
 	/* We don't have a good way to do this yet - hack */
-	return 0xf;
+	return 0xFUL;
 }
 
 /* Mapping from cpu number to logical apicid */
@@ -68,9 +68,14 @@ static inline int apicid_to_node(int log
 	return (logical_apicid >> 4);
 }
 
-static inline unsigned long apicid_to_cpu_present(int logical_apicid)
+static inline cpumask_t apicid_to_cpu_present(int logical_apicid)
 {
-	return ( (logical_apicid&0xf) << (4*apicid_to_node(logical_apicid)) );
+	cpumask_t mask = CPU_MASK_NONE;
+	int node = apicid_to_node(logical_apicid);
+	int cpu = __ffs(logical_apicid & 0xf);
+
+	cpu_set(cpu + 4*node, mask);
+	return mask;
 }
 
 static inline int mpc_apic_id(struct mpc_config_processor *m, 
include/asm-i386/mach-numaq/mach_ipi.h +5 -4
diff -urpN linux-2.5.67-bk6/include/asm-i386/mach-numaq/mach_ipi.h cpu-2.5.67-bk6-1/include/asm-i386/mach-numaq/mach_ipi.h
@@ -1,18 +1,19 @@
 #ifndef __ASM_MACH_IPI_H
 #define __ASM_MACH_IPI_H
 
-static inline void send_IPI_mask_sequence(int mask, int vector);
+static inline void send_IPI_mask_sequence(cpumask_t, int vector);
 
-static inline void send_IPI_mask(int mask, int vector)
+static inline void send_IPI_mask(cpumask_t mask, int vector)
 {
 	send_IPI_mask_sequence(mask, vector);
 }
 
 static inline void send_IPI_allbutself(int vector)
 {
-	unsigned long mask = cpu_online_map & ~(1 << smp_processor_id());
+	cpumask_t mask = cpu_online_map;
+	cpu_clear(smp_processor_id(), mask);
 
-	if (mask)
+	if (!cpus_empty(mask))
 		send_IPI_mask(mask, vector);
 }
 
include/asm-i386/mmu_context.h +4 -5
diff -urpN linux-2.5.67-bk6/include/asm-i386/mmu_context.h cpu-2.5.67-bk6-1/include/asm-i386/mmu_context.h
@@ -26,12 +26,12 @@ static inline void switch_mm(struct mm_s
 {
 	if (likely(prev != next)) {
 		/* stop flush ipis for the previous mm */
-		clear_bit(cpu, &prev->cpu_vm_mask);
+		cpu_clear(cpu, prev->cpu_vm_mask);
 #ifdef CONFIG_SMP
 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
 		cpu_tlbstate[cpu].active_mm = next;
 #endif
-		set_bit(cpu, &next->cpu_vm_mask);
+		cpu_set(cpu, next->cpu_vm_mask);
 
 		/* Re-load page tables */
 		load_cr3(next->pgd);
@@ -45,9 +45,8 @@ static inline void switch_mm(struct mm_s
 #ifdef CONFIG_SMP
 	else {
 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
-		if (cpu_tlbstate[cpu].active_mm != next)
-			BUG();
-		if (!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+		BUG_ON(cpu_tlbstate[cpu].active_mm != next);
+		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
 			/* We were in lazy tlb mode and leave_mm disabled 
 			 * tlb flush IPI delivery. We must reload %cr3.
 			 */
include/asm-i386/mpspec.h +3 -1
diff -urpN linux-2.5.67-bk6/include/asm-i386/mpspec.h cpu-2.5.67-bk6-1/include/asm-i386/mpspec.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_MPSPEC_H
 #define __ASM_MPSPEC_H
 
+#include <linux/cpumask.h>
+
 /*
  * Structure definitions for SMP machines following the
  * Intel Multiprocessing Specification 1.1 and 1.4.
@@ -206,7 +208,7 @@ extern int quad_local_to_mp_bus_id [NR_C
 extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 
 extern unsigned int boot_cpu_physical_apicid;
-extern unsigned long phys_cpu_present_map;
+extern cpumask_t phys_cpu_present_map;
 extern int smp_found_config;
 extern void find_smp_config (void);
 extern void get_smp_config (void);
include/asm-i386/numaq.h +2 -2
diff -urpN linux-2.5.67-bk6/include/asm-i386/numaq.h cpu-2.5.67-bk6-1/include/asm-i386/numaq.h
@@ -28,7 +28,7 @@
 
 #ifdef CONFIG_X86_NUMAQ
 
-#define MAX_NUMNODES		8
+#define MAX_NUMNODES		16
 extern void get_memcfg_numaq(void);
 #define get_memcfg_numa() get_memcfg_numaq()
 
@@ -159,7 +159,7 @@ struct sys_cfg_data {
 
 static inline unsigned long *get_zholes_size(int nid)
 {
-	return 0;
+	return NULL;
 }
 #endif /* CONFIG_X86_NUMAQ */
 #endif /* NUMAQ_H */
include/asm-i386/smp.h +6 -23
diff -urpN linux-2.5.67-bk6/include/asm-i386/smp.h cpu-2.5.67-bk6-1/include/asm-i386/smp.h
@@ -8,6 +8,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/threads.h>
+#include <linux/cpumask.h>
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -31,8 +32,8 @@
  */
  
 extern void smp_alloc_memory(void);
-extern unsigned long phys_cpu_present_map;
-extern unsigned long cpu_online_map;
+extern cpumask_t phys_cpu_present_map;
+extern cpumask_t cpu_online_map;
 extern volatile unsigned long smp_invalidate_needed;
 extern int pic_mode;
 extern int smp_num_siblings;
@@ -55,37 +56,19 @@ extern void zap_low_mappings (void);
  */
 #define smp_processor_id() (current_thread_info()->cpu)
 
-extern volatile unsigned long cpu_callout_map;
+extern volatile cpumask_t cpu_callout_map;
 
-#define cpu_possible(cpu) (cpu_callout_map & (1<<(cpu)))
-#define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
-
-#define for_each_cpu(cpu, mask) \
-	for(mask = cpu_online_map; \
-	    cpu = __ffs(mask), mask != 0; \
-	    mask &= ~(1<<cpu))
-
-extern inline unsigned int num_online_cpus(void)
-{
-	return hweight32(cpu_online_map);
-}
+#define cpu_possible(cpu) cpu_isset(cpu, cpu_callout_map)
 
 /* We don't mark CPUs online until __cpu_up(), so we need another measure */
 static inline int num_booting_cpus(void)
 {
-	return hweight32(cpu_callout_map);
+	return cpus_weight(cpu_callout_map);
 }
 
 extern void map_cpu_to_logical_apicid(void);
 extern void unmap_cpu_to_logical_apicid(int cpu);
 
-extern inline int any_online_cpu(unsigned int mask)
-{
-	if (mask & cpu_online_map)
-		return __ffs(mask & cpu_online_map);
-
-	return -1;
-}
 #ifdef CONFIG_X86_LOCAL_APIC
 static __inline int hard_smp_processor_id(void)
 {
include/asm-i386/topology.h +7 -4
diff -urpN linux-2.5.67-bk6/include/asm-i386/topology.h cpu-2.5.67-bk6-1/include/asm-i386/topology.h
@@ -31,8 +31,10 @@
 
 #include <asm/mpspec.h>
 
+#include <linux/cpumask.h>
+
 /* Mappings between logical cpu number and node number */
-extern volatile unsigned long node_2_cpu_mask[];
+extern volatile cpumask_t node_2_cpu_mask[];
 extern volatile int cpu_2_node[];
 
 /* Returns the number of the node containing CPU 'cpu' */
@@ -49,7 +51,7 @@ static inline int cpu_to_node(int cpu)
 #define parent_node(node) (node)
 
 /* Returns a bitmask of CPUs on Node 'node'. */
-static inline unsigned long node_to_cpumask(int node)
+static inline cpumask_t node_to_cpumask(int node)
 {
 	return node_2_cpu_mask[node];
 }
@@ -57,14 +59,15 @@ static inline unsigned long node_to_cpum
 /* Returns the number of the first CPU on Node 'node'. */
 static inline int node_to_first_cpu(int node)
 { 
-	return __ffs(node_to_cpumask(node));
+	cpumask_t mask = node_to_cpumask(node);
+	return first_cpu(mask);
 }
 
 /* Returns the number of the first MemBlk on Node 'node' */
 #define node_to_memblk(node) (node)
 
 /* Returns the number of the node containing PCI bus 'bus' */
-static inline unsigned long pcibus_to_cpumask(int bus)
+static inline cpumask_t pcibus_to_cpumask(int bus)
 {
 	return node_to_cpumask(mp_bus_id_to_node[bus]);
 }
#2 lore raw

PATCH 3/3 ia64 changes for 2.5.67-bk6

Quoted 1 line · William Lee Irwin III

i386 changes for extended cpu masks. Basically force various things

ia64 changes for extended cpu masks. Written by Martin Hicks, with some porting between 2.5.67 virgin and 2.5.67-bk6 by me (i.e. blame me for mistakes in perfmon.c and palinfo.c, the rest is his fault =).

The same principles as i386 hold, though without quite as much cruft to work around since it's a 64-bit arch and the interrupt controller wasn't lobotomized at birth (or so it seems at first glance...).

arch/ia64/kernel/iosapic.c +7 -4
diff -urpN linux-2.5.67-bk6/arch/ia64/kernel/iosapic.c cpu-2.5.67-bk6-1/arch/ia64/kernel/iosapic.c
@@ -274,7 +274,7 @@ unmask_irq (unsigned int irq)
 
 
 static void
-iosapic_set_affinity (unsigned int irq, unsigned long mask)
+iosapic_set_affinity (unsigned int irq, unsigned long arg)
 {
 #ifdef CONFIG_SMP
 	unsigned long flags;
@@ -283,16 +283,19 @@ iosapic_set_affinity (unsigned int irq, 
 	char *addr;
 	int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
 	ia64_vector vec;
+	cpumask_t tmp, mask = *(cpumask_t *)arg;
 
 	irq &= (~IA64_IRQ_REDIRECTED);
 	vec = irq_to_vector(irq);
 
-	mask &= cpu_online_map;
+	cpus_and(mask, mask, cpu_online_map);
 
-	if (!mask || vec >= IA64_NUM_VECTORS)
+	if (cpus_empty(mask) || vec >= IA64_NUM_VECTORS)
 		return;
 
-	dest = cpu_physical_id(ffz(~mask));
+	tmp = mask;
+	cpus_complement(tmp);
+	dest = cpu_physical_id(first_cpu(tmp));
 
 	rte_index = iosapic_intr_info[vec].rte_index;
 	addr = iosapic_intr_info[vec].addr;
arch/ia64/kernel/irq.c +41 -19

134 lines not on this page · raw message

arch/ia64/kernel/perfmon.c +31 -38

193 lines not on this page · raw message

arch/ia64/kernel/setup.c +1 -1
diff -urpN linux-2.5.67-bk6/arch/ia64/kernel/setup.c cpu-2.5.67-bk6-1/arch/ia64/kernel/setup.c
@@ -541,7 +541,7 @@ static void *
 c_start (struct seq_file *m, loff_t *pos)
 {
 #ifdef CONFIG_SMP
-	while (*pos < NR_CPUS && !(cpu_online_map & (1UL << *pos)))
+	while (*pos < NR_CPUS && !cpu_isset(*pos, cpu_online_map))
 		++*pos;
 #endif
 	return *pos < NR_CPUS ? cpu_data(*pos) : NULL;
arch/ia64/kernel/smp.c +1 -1
diff -urpN linux-2.5.67-bk6/arch/ia64/kernel/smp.c cpu-2.5.67-bk6-1/arch/ia64/kernel/smp.c
@@ -81,7 +81,7 @@ stop_this_cpu (void)
 	/*
 	 * Remove this CPU:
 	 */
-	clear_bit(smp_processor_id(), &cpu_online_map);
+	cpu_clear(smp_processor_id(), cpu_online_map);
 	max_xtp();
 	local_irq_disable();
 	cpu_halt();
arch/ia64/kernel/smpboot.c +22 -18
diff -urpN linux-2.5.67-bk6/arch/ia64/kernel/smpboot.c cpu-2.5.67-bk6-1/arch/ia64/kernel/smpboot.c
@@ -79,13 +79,13 @@ int cpucount;
 task_t *task_for_booting_cpu;
 
 /* Bitmask of currently online CPUs */
-volatile unsigned long cpu_online_map;
-unsigned long phys_cpu_present_map;
+volatile cpumask_t cpu_online_map;
+cpumask_t phys_cpu_present_map;
 
 /* which logical CPU number maps to which CPU (physical APIC ID) */
 volatile int ia64_cpu_to_sapicid[NR_CPUS];
 
-static volatile unsigned long cpu_callin_map;
+static volatile cpumask_t cpu_callin_map;
 
 struct smp_boot_data smp_boot_data __initdata;
 
@@ -271,7 +271,7 @@ smp_callin (void)
 	cpuid = smp_processor_id();
 	phys_id = hard_smp_processor_id();
 
-	if (test_and_set_bit(cpuid, &cpu_online_map)) {
+	if (cpu_test_and_set(cpuid, cpu_online_map)) {
 		printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n",
 		       phys_id, cpuid);
 		BUG();
@@ -313,7 +313,7 @@ smp_callin (void)
 	/*
 	 * Allow the master to continue.
 	 */
-	set_bit(cpuid, &cpu_callin_map);
+	cpu_set(cpuid, cpu_callin_map);
 	Dprintk("Stack on CPU %d at about %p\n",cpuid, &cpuid);
 }
 
@@ -376,19 +376,19 @@ do_boot_cpu (int sapicid, int cpu)
 	 */
 	Dprintk("Waiting on callin_map ...");
 	for (timeout = 0; timeout < 100000; timeout++) {
-		if (test_bit(cpu, &cpu_callin_map))
+		if (cpu_isset(cpu, cpu_callin_map))
 			break;  /* It has booted */
 		udelay(100);
 	}
 	Dprintk("\n");
 
-	if (test_bit(cpu, &cpu_callin_map)) {
+	if (cpu_isset(cpu, cpu_callin_map)) {
 		/* number CPUs logically, starting from 1 (BSP is 0) */
 		printk(KERN_INFO "CPU%d: CPU has booted.\n", cpu);
 	} else {
 		printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid);
 		ia64_cpu_to_sapicid[cpu] = -1;
-		clear_bit(cpu, &cpu_online_map);  /* was set in smp_callin() */
+		cpu_clear(cpu, cpu_online_map);  /* was set in smp_callin() */
 		return -EINVAL;
 	}
 	return 0;
@@ -418,13 +418,14 @@ smp_build_cpu_map (void)
 		ia64_cpu_to_sapicid[cpu] = -1;
 
 	ia64_cpu_to_sapicid[0] = boot_cpu_id;
-	phys_cpu_present_map = 1;
+	cpus_clear(phys_cpu_present_map);
+	cpu_set(1, phys_cpu_present_map);
 
 	for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
 		sapicid = smp_boot_data.cpu_phys_id[i];
 		if (sapicid == -1 || sapicid == boot_cpu_id)
 			continue;
-		phys_cpu_present_map |= (1 << cpu);
+		cpu_set(cpu, phys_cpu_present_map);
 		ia64_cpu_to_sapicid[cpu] = sapicid;
 		cpu++;
 	}
@@ -435,7 +436,7 @@ smp_build_cpu_map (void)
 /* on which node is each logical CPU (one cacheline even for 64 CPUs) */
 volatile char cpu_to_node_map[NR_CPUS] __cacheline_aligned;
 /* which logical CPUs are on which nodes */
-volatile unsigned long node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
+volatile cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
 
 /*
  * Build cpu to node mapping and initialize the per node cpu masks.
@@ -446,7 +447,7 @@ build_cpu_to_node_map (void)
 	int cpu, i, node;
 
 	for(node=0; node<MAX_NUMNODES; node++)
-		node_to_cpu_mask[node] = 0;
+		cpus_clear(node_to_cpu_mask[node]);
 	for(cpu = 0; cpu < NR_CPUS; ++cpu) {
 		/*
 		 * All Itanium NUMA platforms I know use ACPI, so maybe we
@@ -464,7 +465,7 @@ build_cpu_to_node_map (void)
 #endif
 		cpu_to_node_map[cpu] = node;
 		if (node >= 0)
-			node_to_cpu_mask[node] |= (1UL << cpu);
+			cpu_set(cpu, node_to_cpu_mask[node]);
 	}
 }
 
@@ -487,8 +488,8 @@ smp_prepare_cpus (unsigned int max_cpus)
 	/*
 	 * We have the boot CPU online for sure.
 	 */
-	set_bit(0, &cpu_online_map);
-	set_bit(0, &cpu_callin_map);
+	cpu_set(0, cpu_online_map);
+	cpu_set(0, cpu_callin_map);
 
 	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
 	ia64_cpu_to_sapicid[0] = boot_cpu_id;
@@ -503,15 +504,18 @@ smp_prepare_cpus (unsigned int max_cpus)
 	 */
 	if (!max_cpus) {
 		printk(KERN_INFO "SMP mode deactivated.\n");
-		cpu_online_map = phys_cpu_present_map = 1;
+		cpus_clear(cpu_online_map);
+		cpus_clear(phys_cpu_present_map);
+		cpu_set(1, cpu_online_map);
+		cpu_set(1, phys_cpu_present_map);
 		return;
 	}
 }
 
 void __devinit smp_prepare_boot_cpu(void)
 {
-	set_bit(smp_processor_id(), &cpu_online_map);
-	set_bit(smp_processor_id(), &cpu_callin_map);
+	cpu_set(smp_processor_id(), cpu_online_map);
+	cpu_set(smp_processor_id(), cpu_callin_map);
 }
 
 void
arch/ia64/kernel/time.c +2 -2
diff -urpN linux-2.5.67-bk6/arch/ia64/kernel/time.c cpu-2.5.67-bk6-1/arch/ia64/kernel/time.c
@@ -38,13 +38,13 @@ unsigned long last_cli_ip;
 static void
 do_profile (unsigned long ip)
 {
-	extern unsigned long prof_cpu_mask;
+	extern cpumask_t prof_cpu_mask;
 	extern char _stext;
 
 	if (!prof_buffer)
 		return;
 
-	if (!((1UL << smp_processor_id()) & prof_cpu_mask))
+	if (!cpu_isset(smp_processor_id(), prof_cpu_mask))
 		return;
 
 	ip -= (unsigned long) &_stext;
include/asm-ia64/perfmon.h +1 -1
diff -urpN linux-2.5.67-bk6/include/asm-ia64/perfmon.h cpu-2.5.67-bk6-1/include/asm-ia64/perfmon.h
@@ -71,7 +71,7 @@ typedef struct {
 	int	      ctx_flags;	/* noblock/block, inherit flags */
 	void	      *ctx_smpl_vaddr;	/* returns address of BTB buffer */
 
-	unsigned long ctx_cpu_mask;	/* on which CPU to enable perfmon (systemwide) */
+	cpumask_t     ctx_cpu_mask;	/* on which CPU to enable perfmon (systemwide) */
 
 	unsigned long reserved[8];	/* for future use */
 } pfarg_context_t;
include/asm-ia64/smp.h +3 -19
diff -urpN linux-2.5.67-bk6/include/asm-ia64/smp.h cpu-2.5.67-bk6-1/include/asm-ia64/smp.h
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
+#include <linux/cpumask.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -37,8 +38,8 @@ extern struct smp_boot_data {
 
 extern char no_int_routing __initdata;
 
-extern unsigned long phys_cpu_present_map;
-extern volatile unsigned long cpu_online_map;
+extern cpumask_t phys_cpu_present_map;
+extern volatile cpumask_t cpu_online_map;
 extern unsigned long ipi_base_addr;
 extern unsigned char smp_int_redirect;
 
@@ -47,23 +48,6 @@ extern volatile int ia64_cpu_to_sapicid[
 
 extern unsigned long ap_wakeup_vector;
 
-#define cpu_possible(cpu)	(phys_cpu_present_map & (1UL << (cpu)))
-#define cpu_online(cpu)		(cpu_online_map & (1UL << (cpu)))
-
-static inline unsigned int
-num_online_cpus (void)
-{
-	return hweight64(cpu_online_map);
-}
-
-static inline int
-any_online_cpu (unsigned int mask)
-{
-	if (mask & cpu_online_map)
-		return __ffs(mask & cpu_online_map);
-	return -1;
-}
-
 /*
  * Function to map hard smp processor id to logical id.  Slow, so don't use this in
  * performance-critical code.
#3 lore raw
In reply to William Lee Irwin III

On Tue, 15 Apr 2003 15:50:36 -0700 William Lee Irwin III <[email protected]> wrote:

| Core changes for extended cpu masks. Basically use a machine word
| #if NR_CPUS < BITS_PER_LONG, otherwise, use a structure with an array
| of unsigned longs for it. Sprinkle it around the scheduler and a few
| other odd places that play with the cpu bitmasks. Back-ended by a
| bitmap ADT capable of dealing with arbitrary-width bitmaps, with the
| obvious micro-optimizations for NR_CPUS < BITS_PER_LONG and UP.
| 
| NR_CPUS % BITS_PER_LONG != 0 is invalid while NR_CPUS > BITS_PER_LONG.

Where/why this restriction (above)?
I don't see the need for it or implementation of it.

I'm only looking at the core patch.

| diff -urpN linux-2.5.67-bk6/include/linux/bitmap.h cpu-2.5.67-bk6-1/include/linux/bitmap.h
| --- linux-2.5.67-bk6/include/linux/bitmap.h	1969-12-31 16:00:00.000000000 -0800
| +++ cpu-2.5.67-bk6-1/include/linux/bitmap.h	2003-04-15 14:39:40.000000000 -0700

| +static inline void bitmap_shift_left(volatile unsigned long *,volatile unsigned long *,int,int);

Do you need this prototype? I don't see why.

Rest of core looks good to me.

--
~Randy

#4 lore raw
Quoted 7 lines · On Tue, 15 Apr 2003 15:50:36 -0700 William Lee Irwin III wrote:
| Core changes for extended cpu masks. Basically use a machine word
| #if NR_CPUS < BITS_PER_LONG, otherwise, use a structure with an array
| of unsigned longs for it. Sprinkle it around the scheduler and a few
| other odd places that play with the cpu bitmasks. Back-ended by a
| bitmap ADT capable of dealing with arbitrary-width bitmaps, with the
| obvious micro-optimizations for NR_CPUS < BITS_PER_LONG and UP.
| NR_CPUS % BITS_PER_LONG != 0 is invalid while NR_CPUS > BITS_PER_LONG.
Quoted 3 lines · Randy.Dunlap

Where/why this restriction (above)?
I don't see the need for it or implementation of it. I'm only looking at the core patch.

I leave bits dangling otherwise.

Quoted 1 line · On Tue, 15 Apr 2003 15:50:36 -0700 William Lee Irwin III wrote:

| +static inline void bitmap_shift_left(volatile unsigned long *,volatile unsigned long *,int,int);

Quoted 2 lines · Randy.Dunlap

Do you need this prototype? I don't see why. Rest of core looks good to me.

Probably not. I'll nuke it.

-- wli