/branches/rcu/kernel/generic/include/ddi/irq.h |
---|
145,7 → 145,7 |
void *arg; |
/** Notification configuration structure. */ |
ipc_notif_cfg_t notif_cfg; |
ipc_notif_cfg_t* notif_cfg; |
} irq_t; |
extern void irq_init(count_t inrs, count_t chains); |
/branches/rcu/kernel/generic/include/adt/listrcu.h |
---|
0,0 → 1,152 |
/* |
* Copyright (c) 2001-2004 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup genericadt |
* @{ |
*/ |
/** @file listrcu.h |
* @brief provides macro definitions for use with the RCU. Macros take care of memory barriers. |
*/ |
#ifndef KERN_LISTRCU_H_ |
#define KERN_LISTRCU_H_ |
#include <arch/types.h> |
#include <adt/list.h> |
#include <synch/rcu.h> |
/** Add item to the beginning of doubly-linked circular list. Emits write barriers. |
* |
* Add item to the beginning of doubly-linked circular list. |
* |
* @param link Pointer to link_t structure to be added. |
* @param head Pointer to link_t structure representing head of the list. |
*/ |
static inline void list_prepend_rcu(link_t *link, link_t *head) |
{ |
rcu_assign_pointer(link->next,head->next); |
link->prev = head; |
head->next->prev = link; |
rcu_assign_pointer(head->next,link); |
} |
/** Add item to the end of doubly-linked circular list |
* |
* Add item to the end of doubly-linked circular list. |
* |
* @param link Pointer to link_t structure to be added. |
* @param head Pointer to link_t structure representing head of the list. |
*/ |
static inline void list_append_rcu(link_t *link, link_t *head) |
{ |
link->prev = head->prev; |
rcu_assign_pointer(link->next,head); |
rcu_assign_pointer(head->prev->next,link); |
head->prev = link; |
} |
/** Remove item from doubly-linked circular list |
* |
* Remove item from doubly-linked circular list. |
* |
* @param link Pointer to link_t structure to be removed from the list it is |
* contained in. |
*/ |
static inline void list_remove_rcu(link_t *link) |
{ |
link->next->prev = link->prev; |
rcu_assign_pointer(link->prev->next,link->next); |
link_initialize(link); |
} |
/** Split or concatenate headless doubly-linked circular list |
* |
* Split or concatenate headless doubly-linked circular list. |
* |
* Note that the algorithm works both directions: |
* concatenates splitted lists and splits concatenated lists. |
* |
* @param part1 Pointer to link_t structure leading the first (half of the |
* headless) list. |
* @param part2 Pointer to link_t structure leading the second (half of the |
* headless) list. |
*/ |
static inline void headless_list_split_or_concat_rcu(link_t *part1, link_t *part2) |
{ |
link_t *hlp; |
rcu_assign_pointer(part1->prev->next,part2); |
rcu_assign_pointer(part2->prev->next,part1); |
hlp = part1->prev; |
part1->prev = part2->prev; |
part2->prev = hlp; |
} |
/** Split headless doubly-linked circular list |
* |
* Split headless doubly-linked circular list. |
* |
* @param part1 Pointer to link_t structure leading the first half of the |
* headless list. |
* @param part2 Pointer to link_t structure leading the second half of the |
* headless list. |
*/ |
static inline void headless_list_split_rcu(link_t *part1, link_t *part2) |
{ |
headless_list_split_or_concat_rcu(part1, part2); |
} |
/** Concatenate two headless doubly-linked circular lists |
* |
* Concatenate two headless doubly-linked circular lists. |
* |
* @param part1 Pointer to link_t structure leading the first headless list. |
* @param part2 Pointer to link_t structure leading the second headless list. |
*/ |
static inline void headless_list_concat_rcu(link_t *part1, link_t *part2) |
{ |
headless_list_split_or_concat_rcu(part1, part2); |
} |
/** Copy the link structure */ |
void copy_link_rcu(link_t * src, link_t* dest); |
#define list_get_instance(link,type,member) \ |
((type *)(((uint8_t *)(link)) - ((uint8_t *)&(((type *)NULL)->member)))) |
extern bool list_member_rcu(const link_t *link, const link_t *head); |
extern void list_concat_rcu(link_t *head1, link_t *head2); |
#endif |
/** @} |
*/ |
/branches/rcu/kernel/generic/include/ipc/irq.h |
---|
50,6 → 50,8 |
extern void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno); |
extern void ipc_irq_cleanup(answerbox_t *box); |
extern void ipc_notif_free_callback(void* notif); |
#endif |
/** @} |
/branches/rcu/kernel/generic/src/ddi/irq.c |
---|
71,7 → 71,9 |
#include <arch/types.h> |
#include <synch/spinlock.h> |
#include <arch.h> |
#include <synch/rcu.h> |
#define KEY_INR 0 |
#define KEY_DEVNO 1 |
145,12 → 147,13 |
irq->claim = NULL; |
irq->handler = NULL; |
irq->arg = NULL; |
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; |
link_initialize(&irq->notif_cfg.link); |
irq->notif_cfg = malloc(sizeof(ipc_notif_cfg_t), 0); |
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; |
link_initialize(&irq->notif_cfg->link); |
} |
/** Register IRQ for device. |
/branches/rcu/kernel/generic/src/adt/listrcu.c |
---|
0,0 → 1,110 |
/* |
* Copyright (c) 2004 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup genericadt |
* @{ |
*/ |
/** |
* @file listrcu.c |
* @brief Functions completing doubly linked circular list protected by RCU implementation. |
* |
* This file contains some of the functions implementing doubly linked circular lists. |
* Note that the implementation doesn't differ much as when traversing the list we use only next pointers. So changes can be considered atomic. |
* However, this ADT is mostly implemented in @ref list.h and @ref listrcu.h. |
*/ |
#include <adt/list.h> |
#include <adt/listrcu.h> |
#include <synch/rcu.h> |
/** Check for membership |
* |
* Check whether link is contained in the list head. |
* The membership is defined as pointer equivalence. |
* |
* @param link Item to look for. |
* @param head List to look in. |
* |
* @return true if link is contained in head, false otherwise. |
* |
*/ |
bool list_member_rcu(const link_t *link, const link_t *head) |
{ |
bool found = false; |
rcu_read_lock(); |
link_t *hlp = rcu_dereference_pointer(head).next; |
while (hlp != head) { |
if (hlp == link) { |
found = true; |
break; |
} |
hlp = rcu_dereference_pointer(hlp).next; |
} |
rcu_read_lock(); |
return found; |
} |
/** Concatenate two lists |
* |
* Concatenate lists head1 and head2, producing a single |
* list head1 containing items from both (in head1, head2 |
* order) and empty list head2. |
* |
* @param head1 First list and concatenated output |
* @param head2 Second list and empty output. |
* |
*/ |
void list_concat_rcu(link_t *head1, link_t *head2) |
{ |
if (list_empty(head2)) |
return; |
head2->next->prev = head1->prev; |
rcu_assign_pointer(head2->prev->next, head1); |
rcu_assign_pointer(head1->prev->next, head2->next); |
head1->prev = head2->prev; |
list_initialize(head2); |
} |
/** Copy the link structure */ |
void copy_link_rcu(link_t * src, link_t* dest) |
{ |
dest->next = src->next; |
if (dest->next) |
dest->next->prev = dest; |
dest->prev = src->prev; |
if (dest->prev) |
dest->prev->next = dest; |
} |
/** @} |
*/ |
/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); |
} |