diff options
author | Justus Winter <justus@gnupg.org> | 2016-02-25 20:54:22 +0100 |
---|---|---|
committer | Justus Winter <justus@gnupg.org> | 2016-02-25 20:54:22 +0100 |
commit | 652cbc1f88f02f92096051a7ce13dcbf77e55fc4 (patch) | |
tree | c9072d5e57bf7b2e3a5b3ccb92341cdf93a0f898 /device | |
parent | f7c2f4ba69c3ae7df8fddcc2969e2c21e109dbd1 (diff) |
Rework/comment on the userspace interrupt handling
Diffstat (limited to 'device')
-rw-r--r-- | device/ds_routines.c | 8 | ||||
-rw-r--r-- | device/interrupt.h | 14 | ||||
-rw-r--r-- | device/intr.c | 37 |
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 () { |