Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2455 → Rev 2456

/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);
}