summaryrefslogtreecommitdiff
path: root/device
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2016-02-25 20:54:22 +0100
committerJustus Winter <justus@gnupg.org>2016-02-25 20:54:22 +0100
commit652cbc1f88f02f92096051a7ce13dcbf77e55fc4 (patch)
treec9072d5e57bf7b2e3a5b3ccb92341cdf93a0f898 /device
parentf7c2f4ba69c3ae7df8fddcc2969e2c21e109dbd1 (diff)
Rework/comment on the userspace interrupt handling
Diffstat (limited to 'device')
-rw-r--r--device/ds_routines.c8
-rw-r--r--device/interrupt.h14
-rw-r--r--device/intr.c37
3 files changed, 35 insertions, 24 deletions
diff --git a/device/ds_routines.c b/device/ds_routines.c
index 9d399ee..7a5dda5 100644
--- a/device/ds_routines.c
+++ b/device/ds_routines.c
@@ -325,9 +325,7 @@ experimental_device_intr_register (ipc_port_t master_port, int line,
#ifdef MACH_XEN
return D_INVALID_OPERATION;
#else /* MACH_XEN */
- extern int install_user_intr_handler (unsigned int line,
- unsigned long flags,
- ipc_port_t dest);
+ struct intr_entry *entry;
io_return_t ret;
/* Open must be called on the master device port. */
@@ -338,13 +336,13 @@ experimental_device_intr_register (ipc_port_t master_port, int line,
if (line < 0 || line >= 16)
return D_INVALID_OPERATION;
- ret = insert_intr_entry (line, receive_port);
+ ret = insert_intr_entry (line, receive_port, &entry);
if (ret)
return ret;
// TODO The original port should be replaced
// when the same device driver calls it again,
// in order to handle the case that the device driver crashes and restarts.
- ret = install_user_intr_handler (line, flags, receive_port);
+ ret = install_user_intr_handler (line, flags, entry);
/* If the port is installed successfully, increase its reference by 1.
* Thus, the port won't be destroyed after its task is terminated. */
diff --git a/device/interrupt.h b/device/interrupt.h
new file mode 100644
index 0000000..0de43c2
--- /dev/null
+++ b/device/interrupt.h
@@ -0,0 +1,14 @@
+#ifndef DEVICE_INTERRUPT_H
+#define DEVICE_INTERRUPT_H
+
+struct intr_entry;
+boolean_t queue_intr (struct intr_entry *e);
+int insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry);
+
+int install_user_intr_handler (unsigned int line,
+ unsigned long flags,
+ struct intr_entry *entry);
+
+void intr_thread (void);
+
+#endif /* DEVICE_INTERRUPT_H */
diff --git a/device/intr.c b/device/intr.c
index 02e0bab..986f0ee 100644
--- a/device/intr.c
+++ b/device/intr.c
@@ -3,6 +3,8 @@
#include <kern/queue.h>
#include <kern/printf.h>
+#include "interrupt.h"
+
#ifndef MACH_XEN
// TODO this is only for x86 system
#define sti() __asm__ __volatile__ ("sti": : :"memory")
@@ -35,29 +37,35 @@ search_intr (int line, ipc_port_t dest)
return NULL;
}
-void intr_thread (void);
-
/* This function can only be used in the interrupt handler. */
-void
-queue_intr (int line, ipc_port_t dest)
+boolean_t
+queue_intr (struct intr_entry *e)
{
- struct intr_entry *e;
-
+ /* The reference of the port was increased when the port was
+ * installed. If the reference is 1, it means the port should have
+ * been destroyed and I destroy it now. */
+ if (e->dest && e->dest->ip_references == 1)
+ {
+ ipc_port_release (e->dest);
+ e->dest = NULL;
+ printk ("irq handler %d: release an dead delivery port\n", e->line);
+ return FALSE;
+ }
+
cli ();
- e = search_intr (line, dest);
- assert (e);
e->interrupts++;
tot_num_intr++;
sti ();
thread_wakeup ((event_t) &intr_thread);
+ return TRUE;
}
/* insert an interrupt entry in the queue.
* This entry exists in the queue until
* the corresponding interrupt port is removed.*/
int
-insert_intr_entry (int line, ipc_port_t dest)
+insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
{
int err = 0;
struct intr_entry *e, *new;
@@ -86,19 +94,10 @@ out:
sti ();
if (free)
kfree ((vm_offset_t) new, sizeof (*new));
+ *entry = new;
return err;
}
-/* this function should be called when line is disabled. */
-void mark_intr_removed (int line, ipc_port_t dest)
-{
- struct intr_entry *e;
-
- e = search_intr (line, dest);
- if (e)
- e->dest = NULL;
-}
-
void
intr_thread ()
{