Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2307 → Rev 2456

/branches/rcu/kernel/generic/src/ipc/irq.c
57,6 → 57,8
#include <syscall/copy.h>
#include <console/console.h>
#include <print.h>
#include <synch/rcu.h>
#include <adt/listrcu.h>
 
/** Execute code associated with IRQ notification.
*
171,21 → 173,27
{
ipl_t ipl;
irq_t *irq;
ipc_notif_cfg_t *new_notify, *old_notify;
 
ipl = interrupts_disable();
irq = irq_find_and_lock(inr, devno);
if (irq) {
if (irq->notif_cfg.answerbox == box) {
code_free(irq->notif_cfg.code);
irq->notif_cfg.notify = false;
irq->notif_cfg.answerbox = NULL;
irq->notif_cfg.code = NULL;
irq->notif_cfg.method = 0;
irq->notif_cfg.counter = 0;
if (rcu_dereference_pointer(irq->notif_cfg).answerbox == box) {
new_notify = malloc(sizeof(ipc_notif_cfg_t),0);
 
new_notify->notify = false;
new_notify->answerbox = NULL;
new_notify->code = NULL;
new_notify->method = 0;
new_notify->counter = 0;
old_notify = irq->notif_cfg;
copy_link_rcu(&irq->notif_cfg->link, &new_notify->link);
rcu_assign_pointer(old_notify, new_notify);
 
spinlock_lock(&box->irq_lock);
list_remove(&irq->notif_cfg.link);
list_remove_rcu(&rcu_dereference_pointer(irq->notif_cfg).link);
spinlock_unlock(&box->irq_lock);
rcu_sync_callback_normal_alloc(&ipc_notif_free_callback, irq->notif_cfg);
spinlock_unlock(&irq->lock);
}
193,6 → 201,13
interrupts_restore(ipl);
}
 
void ipc_notif_free_callback(void* notif)
{
code_free(((ipc_notif_cfg_t *)notif)->code);
free(notif);
 
}
 
/** Register an answerbox as a receiving end for IRQ notifications.
*
* @param box Receiving answerbox.
208,6 → 223,7
ipl_t ipl;
irq_code_t *code;
irq_t *irq;
ipc_notif_cfg_t *new_notify, *old_notify;
 
if (ucode) {
code = code_from_uspace(ucode);
224,21 → 240,25
return ENOENT;
}
if (irq->notif_cfg.answerbox) {
if (rcu_dereference_pointer(irq->notif_cfg).answerbox) {
spinlock_unlock(&irq->lock);
interrupts_restore(ipl);
code_free(code);
return EEXISTS;
}
irq->notif_cfg.notify = true;
irq->notif_cfg.answerbox = box;
irq->notif_cfg.method = method;
irq->notif_cfg.code = code;
irq->notif_cfg.counter = 0;
new_notify = malloc(sizeof(ipc_notif_cfg_t),0);
new_notify->notify = true;
new_notify->answerbox = box;
new_notify->method = method;
new_notify->code = code;
new_notify->counter = 0;
copy_link_rcu(&irq->notif_cfg->link, &new_notify->link);
old_notify = irq->notif_cfg;
rcu_assign_pointer(irq->notif_cfg, new_notify);
rcu_sync_callback_normal_alloc(&ipc_notif_free_callback, old_notify);
 
spinlock_lock(&box->irq_lock);
list_append(&irq->notif_cfg.link, &box->irq_head);
list_append_rcu(&new_notify->link, &box->irq_head);
spinlock_unlock(&box->irq_lock);
 
spinlock_unlock(&irq->lock);
254,11 → 274,11
*/
static void send_call(irq_t *irq, call_t *call)
{
spinlock_lock(&irq->notif_cfg.answerbox->irq_lock);
list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock);
spinlock_lock(&rcu_dereference_pointer(irq->notif_cfg).answerbox->irq_lock);
list_append_rcu(&call->link, &rcu_dereference_pointer(irq->notif_cfg).answerbox->irq_notifs);
spinlock_unlock(&rcu_dereference_pointer(irq->notif_cfg).answerbox->irq_lock);
waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST);
waitq_wakeup(&rcu_dereference_pointer(irq->notif_cfg).answerbox->wq, WAKEUP_FIRST);
}
 
/** Send notification message
270,7 → 290,7
 
spinlock_lock(&irq->lock);
 
if (irq->notif_cfg.answerbox) {
if (rcu_dereference_pointer(irq->notif_cfg).answerbox) {
call = ipc_call_alloc(FRAME_ATOMIC);
if (!call) {
spinlock_unlock(&irq->lock);
277,12 → 297,12
return;
}
call->flags |= IPC_CALL_NOTIF;
IPC_SET_METHOD(call->data, irq->notif_cfg.method);
IPC_SET_METHOD(call->data, rcu_dereference_pointer(irq->notif_cfg).method);
IPC_SET_ARG1(call->data, a1);
IPC_SET_ARG2(call->data, a2);
IPC_SET_ARG3(call->data, a3);
/* Put a counter to the message */
call->priv = ++irq->notif_cfg.counter;
call->priv = ++rcu_dereference_pointer(irq->notif_cfg).counter;
send_call(irq, call);
}
299,7 → 319,7
 
ASSERT(irq);
 
if (irq->notif_cfg.answerbox) {
if (rcu_dereference_pointer(irq->notif_cfg).answerbox) {
call = ipc_call_alloc(FRAME_ATOMIC);
if (!call) {
return;
306,12 → 326,12
}
call->flags |= IPC_CALL_NOTIF;
/* Put a counter to the message */
call->priv = ++irq->notif_cfg.counter;
call->priv = ++rcu_dereference_pointer(irq->notif_cfg).counter;
/* Set up args */
IPC_SET_METHOD(call->data, irq->notif_cfg.method);
IPC_SET_METHOD(call->data, rcu_dereference_pointer(irq->notif_cfg).method);
 
/* Execute code to handle irq */
code_execute(call, irq->notif_cfg.code);
code_execute(call, rcu_dereference_pointer(irq->notif_cfg).code);
send_call(irq, call);
}
328,6 → 348,7
void ipc_irq_cleanup(answerbox_t *box)
{
ipl_t ipl;
ipc_notif_cfg_t *new_notify, *old_notify;
loop:
ipl = interrupts_disable();
338,7 → 359,7
irq_t *irq;
DEADLOCK_PROBE_INIT(p_irqlock);
irq = list_get_instance(cur, irq_t, notif_cfg.link);
irq = list_get_instance(cur, irq_t, notif_cfg->link);
if (!spinlock_trylock(&irq->lock)) {
/*
* Avoid deadlock by trying again.
349,21 → 370,22
goto loop;
}
ASSERT(irq->notif_cfg.answerbox == box);
ASSERT(irq->notif_cfg->answerbox == box);
list_remove(&irq->notif_cfg.link);
list_remove_rcu(&irq->notif_cfg->link);
/*
* Don't forget to free any top-half pseudocode.
*/
code_free(irq->notif_cfg.code);
new_notify = malloc(sizeof(ipc_notif_cfg_t),0);
new_notify->notify = false;
new_notify->answerbox = NULL;
new_notify->method = 0;
new_notify->code = NULL;
new_notify->counter = 0;
copy_link_rcu(&irq->notif_cfg->link, &new_notify->link);
old_notify = irq->notif_cfg;
rcu_assign_pointer(irq->notif_cfg, new_notify);
rcu_sync_callback_normal_alloc(&ipc_notif_free_callback, old_notify);
 
irq->notif_cfg.notify = false;
irq->notif_cfg.answerbox = NULL;
irq->notif_cfg.code = NULL;
irq->notif_cfg.method = 0;
irq->notif_cfg.counter = 0;
 
spinlock_unlock(&irq->lock);
}