/branches/rcu/kernel/test/synch/rcu1.c |
---|
36,28 → 36,24 |
#include <arch.h> |
#include <preemption.h> |
bool gquiet; |
bool called; |
static void callback(void* data) |
{ |
if (!gquiet) |
printf("callback called\n"); |
called = true; |
} |
char * test_rcu1(bool quiet) |
{ |
gquiet = quiet; |
called = false; |
int* p; |
rcu_read_lock(); |
rcu_read_unlock(); |
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"); |
/branches/rcu/kernel/generic/include/synch/waitq.h |
---|
40,11 → 40,18 |
#include <synch/synch.h> |
#include <adt/list.h> |
/** Specifies behavior of the waitq_wakeup */ |
typedef enum { |
WAKEUP_FIRST = 0, |
WAKEUP_ALL |
} wakeup_mode_t; |
WAKEUP_FIRST = 0, /**< Wakes up only the first sleeping thread, if there |
aren't any sleeping threads increments missed wakeups */ |
WAKEUP_ALL = 1, /**< Wakes up all sleeping threads AND zeroes out |
missed_wakeups */ |
WAKEUP_ALL_INC_MISSED, /**< Wakes up all sleeping threads OR increments |
missed_wakeups if there aren't any */ |
} wakeup_all_flag_t; |
/** Wait queue structure. */ |
typedef struct { |
72,8 → 79,8 |
extern ipl_t waitq_sleep_prepare(waitq_t *wq); |
extern int waitq_sleep_timeout_unsafe(waitq_t *wq, uint32_t usec, int flags); |
extern void waitq_sleep_finish(waitq_t *wq, int rc, ipl_t ipl); |
extern void waitq_wakeup(waitq_t *wq, wakeup_mode_t mode); |
extern void _waitq_wakeup_unsafe(waitq_t *wq, wakeup_mode_t mode); |
extern void waitq_wakeup(waitq_t *wq, int all); |
extern void _waitq_wakeup_unsafe(waitq_t *wq, int all); |
extern void waitq_interrupt_sleep(struct thread *t); |
#endif |
/branches/rcu/kernel/generic/src/synch/rcu.c |
---|
95,10 → 95,9 |
waitq_t *wq = malloc(sizeof(waitq_t),0); |
waitq_initialize(wq); |
rcu_sync_callback(&rcu_synchronize_callback_function, wq); |
printf("going to sleep, tlock:%x, wqlock:%x\n", THREAD->lock.val, wq->lock.val); |
printf("going to sleep\n"); |
waitq_sleep(wq); |
printf("woken up\n"); |
free(wq); |
#endif |
} |
105,13 → 104,8 |
#ifdef CONFIG_SMP |
void rcu_synchronize_callback_function(void* waitq) |
{ |
printf("waking up, wq:%x, wq->head:%x, next:%x, tlock:%x, wqlock:%x\n", |
waitq, |
((waitq_t*)waitq)->head, |
((link_t)((waitq_t*)waitq)->head).next, |
THREAD->lock.val, |
((waitq_t*)waitq)->lock.val ); |
waitq_wakeup(((waitq_t*)waitq), WAKEUP_ALL); |
printf("waking up\n"); |
waitq_wakeup(((waitq_t*)waitq), WAKEUP_ALL_INC_MISSED); |
} |
#endif |
126,10 → 120,8 |
rd->func = func; |
rd->data = data; |
rd->next = NULL; |
printf("synccallback locking \n"); |
spinlock_lock(&rcu_global_lock); |
rd->next = _rcu_global->next_batch; |
_rcu_global->next_batch = rd; |
179,18 → 171,19 |
} else |
_rcu_global->done_batch = _rcu_global->current_batch; |
printf("setting callback %x as done\n",&_rcu_global->current_batch->func); |
_rcu_global->current_batch = _rcu_global->next_batch; |
_rcu_global->next_batch = NULL; |
#ifdef CONFIG_SMP |
for (i=0;i<config.cpu_count;i++) |
_rcu_global->cpu_mask[i]=false; |
#endif |
//we've surely passed the quiescent point just by running this method |
rcu_passQS(); |
_rcu_global->current_batch = NULL; |
} |
spinlock_unlock(&rcu_global_lock); |
_rcu_global->current_batch = _rcu_global->next_batch; |
_rcu_global->next_batch = NULL; |
if (_rcu_global->current_batch == NULL) { |
//there are no rcu callbacks registered, there is no need to monitor QS |
printf("tasklet idle disabling \n"); |
// tasklet_disable(rcu_tasklet_desc); |
spinlock_unlock(&rcu_global_lock); |
} else |
spinlock_unlock(&rcu_global_lock); |
printf("tasklet unlocking \n"); |
} |
206,16 → 199,15 |
rcu_callback_list_t* rd; |
rcu_passQS(); |
if (_rcu_global->done_batch) { |
printf("run callbacks locking\n"); |
printf("."); |
spinlock_lock(&rcu_global_lock); |
rd = _rcu_global->done_batch; |
_rcu_global->done_batch = NULL; |
spinlock_unlock(&rcu_global_lock); |
printf("run callbacks unlocking\n"); |
for (; rd; rd=rd->next) { |
for (rd = _rcu_global->done_batch; rd; rd=rd->next) { |
printf("calling %x \n",&rd->func); |
rd->func(&rd->data); |
} |
_rcu_global->done_batch = NULL; |
spinlock_unlock(&rcu_global_lock); |
printf(":"); |
} |
} |
/branches/rcu/kernel/generic/src/synch/waitq.c |
---|
383,10 → 383,13 |
* Besides its 'normal' wakeup operation, it attempts to unregister possible |
* timeout. |
* |
* @param wq Pointer to wait queue. |
* @param mode Wakeup mode. |
* @param wq Pointer to wait queue. |
* @param all If this is WAKEUP_ALL, all sleeping threads will be woken up and |
* missed count will be zeroed. WAKEUP_FIRST wakes up just one thread or |
* increments the missed count. WAKEUP_ALL_INC_MISSED wakes up all sleeping threads |
* or increments missed_wakeups if there aren't any |
*/ |
void waitq_wakeup(waitq_t *wq, wakeup_mode_t mode) |
void waitq_wakeup(waitq_t *wq, int all) |
{ |
ipl_t ipl; |
393,10 → 396,10 |
ipl = interrupts_disable(); |
spinlock_lock(&wq->lock); |
_waitq_wakeup_unsafe(wq, mode); |
_waitq_wakeup_unsafe(wq, all); |
spinlock_unlock(&wq->lock); |
interrupts_restore(ipl); |
spinlock_unlock(&wq->lock); |
interrupts_restore(ipl); |
} |
/** Internal SMP- and IRQ-unsafe version of waitq_wakeup() |
404,27 → 407,25 |
* This is the internal SMP- and IRQ-unsafe version of waitq_wakeup(). It |
* assumes wq->lock is already locked and interrupts are already disabled. |
* |
* @param wq Pointer to wait queue. |
* @param mode If mode is WAKEUP_FIRST, then the longest waiting thread, |
* if any, is woken up. If mode is WAKEUP_ALL, then all |
* waiting threads, if any, are woken up. If there are no |
* waiting threads to be woken up, the missed wakeup is |
* recorded in the wait queue. |
* @param wq Pointer to wait queue. |
* @param all If this is WAKEUP_ALL, all sleeping threads will be woken up and |
* missed count will be zeroed. WAKEUP_FIRST wakes up just one thread or |
* increments the missed count. WAKEUP_ALL_INC_MISSED wakes up all sleeping threads |
* or increments missed_wakeups if there aren't any |
*/ |
void _waitq_wakeup_unsafe(waitq_t *wq, wakeup_mode_t mode) |
void _waitq_wakeup_unsafe(waitq_t *wq, int all) |
{ |
thread_t *t; |
count_t count = 0; |
loop: |
if (list_empty(&wq->head)) { |
wq->missed_wakeups++; |
if (count && mode == WAKEUP_ALL) |
wq->missed_wakeups--; |
if (all == WAKEUP_ALL) |
wq->missed_wakeups = 0; |
else |
wq->missed_wakeups++; |
return; |
} |
loop: |
count++; |
t = list_get_instance(wq->head.next, thread_t, wq_link); |
/* |
452,8 → 453,10 |
spinlock_unlock(&t->lock); |
thread_ready(t); |
if (mode == WAKEUP_ALL) |
if (list_empty(&wq->head)) { |
return; |
} |
if (all != WAKEUP_FIRST) |
goto loop; |
} |
/branches/rcu/kernel/arch/ia32/include/cpuid.h |
---|
99,20 → 99,18 |
static inline void cpuid(uint32_t cmd, cpu_info_t *info) |
{ |
register int eax asm("eax")=cmd; |
register int ebx asm("ebx"); |
register int ecx asm("ecx"); |
register int edx asm("edx"); |
asm volatile ( |
"movl %4, %%eax\n" |
"cpuid\n" |
: "=r" (eax), "=r" (ebx), "=r" (ecx), "=r" (edx) |
: "r" (eax) |
"movl %%eax, %0\n" |
"movl %%ebx, %1\n" |
"movl %%ecx, %2\n" |
"movl %%edx, %3\n" |
: "=m" (info->cpuid_eax), "=m" (info->cpuid_ebx), "=m" (info->cpuid_ecx), "=m" (info->cpuid_edx) |
: "m" (cmd) |
: "eax", "ebx", "ecx", "edx" |
); |
info->cpuid_eax=eax; |
info->cpuid_ebx=ebx; |
info->cpuid_ecx=ecx; |
info->cpuid_edx=edx; |
} |
#endif |