/*
* Copyright (c) 2007 Jan Hudecek
* Copyright (c) 2005 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.
*/
#include <synch/rcu.h>
#include <print.h>
#include <test.h>
#include <arch/types.h>
#include <proc/tasklet.h>
#include <arch/barrier.h>
#include <arch.h>
#include <preemption.h>
#include <proc/thread.h>
#define RCU_MAX_I 1000
#define READER_THREADS 10
#define WRITER_THREADS 10
#define THREADS_SLEEP_LENGTH (uint32_t)50
bool gquiet;
volatile bool finished;
typedef struct data_struc {
int number;
struct data_struc* next;
} data_t;
data_t* first;
SPINLOCK_INITIALIZE(write_lock);
static void reader(void* a)
{
a = (a);
data_t* cur;
int i = 0;
while (true)
{
i = 0;
rcu_read_lock();
for (cur = rcu_dereference_pointer(first).next; cur != first; cur = cur->next) {
i += rcu_dereference_pointer(cur).number;
}
rcu_read_unlock();
thread_usleep(THREADS_SLEEP_LENGTH);
if (i>RCU_MAX_I || finished)
{
break;
}
}
finished = true;
}
static void writer(void* a)
{
a = (a);
data_t* cur;
data_t* newdata, *oldata;
rcu_callback_list_t* rcudata;
int i = 0;
rcudata
= malloc(sizeof(rcu_callback_list_t
),0);
while (true)
{
i = rcu_dereference_pointer(first).number;
rcu_read_lock();
for (cur = rcu_dereference_pointer(first).next; cur != first; cur = rcu_dereference_pointer(cur).next) {
i += rcu_dereference_pointer(cur).number;
}
rcu_read_unlock();
if (!gquiet)
if (i>RCU_MAX_I || finished)
{
break;
}
thread_usleep(THREADS_SLEEP_LENGTH);
newdata
= malloc(sizeof(data_t
),0);
rcu_read_lock();
//prepend a new member
spinlock_lock(&write_lock);
newdata->number = (i/10)+1;
oldata = first;
newdata->next = first;
rcu_assign_pointer(first, newdata);
rcu_sync_callback(&rcu_callback_free, oldata, rcudata);
spinlock_unlock(&write_lock);
rcu_read_unlock();
thread_usleep(THREADS_SLEEP_LENGTH);
if (!gquiet)
rcu_read_lock();
for (cur = rcu_dereference_pointer(first).next; rcu_dereference_pointer(cur).number % 5 != 4 && cur != first; cur = rcu_dereference_pointer(cur).next) {
}
if (cur != first){
//delete the cur->next
spinlock_lock(&write_lock);
oldata = rcu_dereference_pointer(cur).next;
newdata->next = rcu_dereference_pointer(rcu_dereference_pointer(cur).next).next;
rcu_assign_pointer(rcu_dereference_pointer(cur).next, newdata);
rcu_sync_callback(&rcu_callback_free, oldata, rcudata);
spinlock_unlock(&write_lock);
if (!gquiet)
}
rcu_read_unlock();
thread_usleep(THREADS_SLEEP_LENGTH);
}
finished = true;
}
char * test_rcu1(bool quiet)
{
gquiet = quiet;
data_t* cur, *oldata;
int i;
thread_t* t;
thread_t** threads;
first
= malloc(sizeof(data_t
),0);
first->number = 10;
first->next = first;
threads
= malloc(sizeof(thread_t
*),0);
finished = false;
for(i = 0; i< WRITER_THREADS; i++) {
threads[i]=t=thread_create(writer,NULL, TASK, 0, "writerthread", false );
if (t != NULL)
thread_ready(t);
}
for(i = 0; i< READER_THREADS; i++) {
threads[WRITER_THREADS+i]=t=thread_create(reader,NULL, TASK, 0, "readerthread", false );
if (t != NULL)
thread_ready(t);
}
for (i=0;i<WRITER_THREADS+READER_THREADS;i++)
thread_join(threads[i]);
for(cur=first->next;cur->next!=first;) {
oldata = cur->next;
cur = oldata;
}
return NULL;
}