x86: use RCU to protect the IRQ handlers list

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/arch/x86/trap.c b/kern/arch/x86/trap.c
index 15fbdc8..16cdc5c 100644
--- a/kern/arch/x86/trap.c
+++ b/kern/arch/x86/trap.c
@@ -34,7 +34,7 @@
 pseudodesc_t idt_pd;
 
 /* interrupt handler table, each element is a linked list of handlers for a
- * given IRQ.  Modification requires holding the lock (TODO: RCU) */
+ * given IRQ.  Modification requires holding the lock. */
 struct irq_handler *irq_handlers[NUM_IRQS];
 spinlock_t irq_handler_wlock = SPINLOCK_INITIALIZER_IRQSAVE;
 
@@ -717,8 +717,8 @@
 	if (hw_tf->tf_trapno != 65)	/* qemu serial tends to get this one */
 		printd("Incoming IRQ, ISR: %d on core %d\n", hw_tf->tf_trapno,
 		       core_id());
-	/* TODO: RCU read lock */
-	irq_h = irq_handlers[hw_tf->tf_trapno];
+	rcu_read_lock();
+	irq_h = rcu_dereference(irq_handlers[hw_tf->tf_trapno]);
 	if (!irq_h) {
 		warn_once("Received IRQ %d, had no handler registered!",
 		          hw_tf->tf_trapno);
@@ -735,7 +735,7 @@
 	enable_irq();
 	while (irq_h) {
 		irq_h->isr(hw_tf, irq_h->data);
-		irq_h = irq_h->next;
+		irq_h = rcu_dereference(irq_h->next);
 	}
 	// if we're a general purpose IPI function call, down the cpu_list
 	extern handler_wrapper_t handler_wrappers[NUM_HANDLER_WRAPPERS];
@@ -745,9 +745,11 @@
 			       .cpu_list);
 	disable_irq();
 	/* Keep in sync with ipi_is_pending */
-	irq_handlers[hw_tf->tf_trapno]->eoi(hw_tf->tf_trapno);
+	irq_h = rcu_dereference(irq_handlers[hw_tf->tf_trapno]);
+	irq_h->eoi(hw_tf->tf_trapno);
 	/* Fall-through */
 out_no_eoi:
+	rcu_read_unlock();
 	dec_irq_depth(pcpui);
 	if (!in_irq_ctx(pcpui))
 		__set_cpu_state(pcpui, CPU_STATE_KERNEL);
@@ -801,11 +803,9 @@
 	irq_h->isr = handler;
 	irq_h->data = irq_arg;
 	irq_h->apic_vector = vector;
-	/* RCU write lock */
 	spin_lock_irqsave(&irq_handler_wlock);
 	irq_h->next = irq_handlers[vector];
-	wmb();	/* make sure irq_h is done before publishing to readers */
-	irq_handlers[vector] = irq_h;
+	rcu_assign_pointer(irq_handlers[vector], irq_h);
 	spin_unlock_irqsave(&irq_handler_wlock);
 	/* Most IRQs other than the BusIPI should need their irq unmasked.
 	 * Might need to pass the irq_h, in case unmask needs more info.