Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2399 → Rev 2400

/branches/rcu/kernel/test/synch/rcu1.c
35,32 → 35,153
#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 called;
volatile bool finished;
typedef struct data_struc {
int number;
struct data_struc* next;
} data_t;
 
static void callback(void* data)
data_t* first;
SPINLOCK_INITIALIZE(write_lock);
 
 
 
static void reader(void* a)
{
if (!gquiet)
printf("callback called\n");
called = true;
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)
{
printf("@");
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;
printf("a1 ");
rcudata = malloc(sizeof(rcu_callback_list_t),0);
while (true)
{
i = rcu_dereference_pointer(first).number;
rcu_read_lock();
printf("a2 ");
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)
printf("i%d ",i);
if (i>RCU_MAX_I || finished)
{
printf("!");
break;
}
printf("a2b ");
thread_usleep(THREADS_SLEEP_LENGTH);
 
printf("a3 ");
newdata = malloc(sizeof(data_t),0);
printf("a4 ");
rcu_read_lock();
//prepend a new member
spinlock_lock(&write_lock);
printf("a5 ");
newdata->number = (i/10)+1;
oldata = first;
newdata->next = first;
rcu_assign_pointer(first, newdata);
printf("a6 ");
rcu_sync_callback(&rcu_callback_free, oldata, rcudata);
spinlock_unlock(&write_lock);
printf("a7 ");
rcu_read_unlock();
thread_usleep(THREADS_SLEEP_LENGTH);
printf("a8 ");
if (!gquiet)
printf(".",i);
 
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)
printf(", ",i);
 
}
rcu_read_unlock();
thread_usleep(THREADS_SLEEP_LENGTH);
}
finished = true;
}
 
char * test_rcu1(bool quiet)
{
gquiet = quiet;
called = false;
int* p;
rcu_read_lock();
rcu_assign_pointer(p,malloc(sizeof(int),0));
if (!quiet)
printf("p:%x\n",rcu_dereference_pointer(p));
rcu_read_unlock();
rcu_sync_callback(&callback, NULL);
if (!quiet)
printf("Callback scheduled\n");
// while(!called);
rcu_synchronize();
if (!quiet)
printf("Synchronized\n");
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;
free(cur);
cur = oldata;
}
free(first);
return NULL;
 
}
/branches/rcu/kernel/generic/include/synch/rcu.h
61,16 → 61,23
#define rcu_assign_pointer(p, newp) {write_barrier(); (p)=(newp);}
 
/** RCU sync callback for those who don't need custom allocation */
#define rcu_sync_callback(func, data) {\
#define rcu_sync_callback_normal_alloc(func, data) {\
rcu_callback_list_t* rd = malloc(sizeof(rcu_callback_list_t),0);\
rcu_sync_callback_custom_alloc(func, data, rd);}
rcu_sync_callback(func, data, rd);}
 
/** RCU sync callback without custom allocation, default callback (just frees the argument) */
#define rcu_sync_callback_normal_alloc_free(data) rcu_sync_callback_normal_alloc(&rcu_callback_free, data)
 
void rcu_init(void);
void rcu_synchronize(void);
void rcu_synchronize_callback_function(void* waitq);
void rcu_sync_callback_custom_alloc(void (*func)(void* data), void* data, rcu_callback_list_t* rcu_struct);
void rcu_sync_callback(void (*func)(void* data), void* data, rcu_callback_list_t* rcu_struct);
void rcu_tasklet(void* data);
void rcu_passQS(void);
void rcu_run_callbacks(void);
void rcu_callback_free(void* pointer);
 
 
 
 
#endif
/branches/rcu/kernel/generic/src/synch/rcu.c
101,7 → 101,7
#ifdef CONFIG_SMP
waitq_t wq;
waitq_initialize(&wq);
rcu_sync_callback(&rcu_synchronize_callback_function, &wq);
rcu_sync_callback_normal_alloc(&rcu_synchronize_callback_function, &wq);
//sleep until the end of the grace period
waitq_sleep(&wq);
#endif
123,7 → 123,7
* is handled in rcu_run_callbacks and in the tasklet. This is a lock free variant,
* which must be supplied with a preallocated rcu_callback_list_t structure
*/
void rcu_sync_callback_custom_alloc(void (*func)(void* data), void* data, rcu_callback_list_t* rd)
void rcu_sync_callback(void (*func)(void* data), void* data, rcu_callback_list_t* rd)
{
#ifndef CONFIG_SMP
func(data);
240,3 → 240,12
}
 
 
/**
* Generic callback for RCU, frees @paramref pointer
* @param pointer
*/
void rcu_callback_free(void* pointer)
{
free(pointer);
}