kitten LWK waitqueue adoptation

This commit is contained in:
Balazs Gerofi
2012-05-06 12:39:39 +09:00
parent 8c34463dd4
commit c3463e7393
5 changed files with 320 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
AALDIR=$(AALBASE)/$(TARGET)
OBJS = init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o host.o
OBJS += process.o copy.o
OBJS += process.o copy.o waitq.o
DEPSRCS=$(wildcard $(SRC)/*.c)
CFLAGS += -I$(SRC)/include -mcmodel=kernel -D__KERNEL__

View File

@@ -14,9 +14,11 @@
#define PS_RUNNING 0x1
#define PS_INTERRUPTIBLE 0x2
#define PS_UNINTERRUPTIBLE 0x3
#define PS_ZOMBIE 0x4
#define PS_EXITED 0x5
#define PS_UNINTERRUPTIBLE 0x4
#define PS_ZOMBIE 0x8
#define PS_EXITED 0x10
#define PS_NORMAL (PS_INTERRUPTIBLE | PS_UNINTERRUPTIBLE)
struct vm_range {
struct list_head list;
@@ -78,5 +80,6 @@ unsigned long extend_process_region(struct process *proc,
void schedule(void);
void runq_add_proc(struct process *proc, int cpu_id);
void runq_del_proc(struct process *proc, int cpu_id);
int sched_wakeup_process(struct process *proc, int valid_states);
#endif

135
kernel/include/waitq.h Normal file
View File

@@ -0,0 +1,135 @@
#ifndef _LWK_WAITQ_H
#define _LWK_WAITQ_H
/* Kitten waitqueue adaptation */
#include <aal/lock.h>
#include <list.h>
#include <process.h>
struct waitq_entry;
typedef int (*waitq_func_t)(struct waitq_entry *wait, unsigned mode,
int flags, void *key);
int default_wake_function(struct waitq_entry *wait, unsigned mode, int flags,
void *key);
typedef struct waitq {
aal_spinlock_t lock;
struct list_head waitq;
} waitq_t;
#define WQ_FLAG_EXCLUSIVE 0x01
typedef struct waitq_entry {
struct list_head link;
void *private;
unsigned int flags;
waitq_func_t func;
} waitq_entry_t;
#define DECLARE_WAITQ(name) \
waitq_t name = __WAITQ_INITIALIZER(name);
#define __WAITQ_INITIALIZER(name) { \
.lock = SPIN_LOCK_UNLOCKED, \
.waitq = { &(name).waitq, &(name).waitq } \
}
#define DECLARE_WAITQ_ENTRY(name, tsk) \
waitq_entry_t name = { \
.private = tsk, \
.func = default_wake_function, \
.link = { &(name).link, &(name).link } \
}
extern void waitq_init(waitq_t *waitq);
extern void waitq_init_entry(waitq_entry_t *entry, struct process *proc);
extern int waitq_active(waitq_t *waitq);
extern void waitq_add_entry(waitq_t *waitq, waitq_entry_t *entry);
extern void waitq_add_entry_locked(waitq_t *waitq, waitq_entry_t *entry);
extern void waitq_prepare_to_wait(waitq_t *waitq,
waitq_entry_t *entry, int state);
extern void waitq_finish_wait(waitq_t *waitq, waitq_entry_t *entry);
extern void waitq_wakeup(waitq_t *waitq);
extern int waitq_wake_nr(waitq_t *waitq, int nr);
extern int waitq_wake_nr_locked(waitq_t *waitq, int nr);
extern void waitq_remove_entry(waitq_t *waitq, waitq_entry_t *entry);
extern void waitq_remove_entry_locked(waitq_t *waitq, waitq_entry_t *entry);
#define __wait_event(waitq, condition) \
do { \
DECLARE_WAITQ_ENTRY(__entry, current); \
for (;;) { \
waitq_prepare_to_wait(&waitq, &__entry, \
TASK_UNINTERRUPTIBLE); \
if (condition) \
break; \
schedule(); \
} \
waitq_finish_wait(&waitq, &__entry); \
} while (0)
/**
* wait_event - sleep until a condition becomes true
* @waitq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_UNINTERRUPTIBLE) until the
* @condition evaluates to true. The @condition is checked each time
* the waitqueue @waitq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*/
#define wait_event(waitq, condition) \
do { \
if (condition) \
break; \
__wait_event(waitq, condition); \
} while (0)
#define __wait_event_interruptible(waitq, condition, ret) \
do { \
DECLARE_WAITQ_ENTRY(__entry, current); \
for (;;) { \
waitq_prepare_to_wait(&waitq, &__entry, \
TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (1 /* TODO: !signal_pending(current) */) { \
schedule(); \
continue; \
} \
ret = -ERESTARTSYS; \
break; \
} \
waitq_finish_wait(&waitq, &__entry); \
} while (0)
/**
* wait_event_interruptible - sleep until a condition becomes true
* @waitq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received. The
* @condition is checked each time the waitqueue @waitq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
#define wait_event_interruptible(waitq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(waitq, condition, __ret); \
__ret; \
})
#endif

View File

@@ -5,6 +5,7 @@
#include <cls.h>
#include <aal/debug.h>
#include <page.h>
#include <cpulocal.h>
#define DEBUG_PRINT_PROCESS
@@ -307,6 +308,7 @@ void schedule(void)
aal_mc_load_page_table(next->vm->page_table);
do_arch_prctl(ARCH_SET_FS, next->vm->region.tlsblock_base);
cpu_local_var(status) = CPU_STATUS_RUNNING;
if (prev) {
aal_mc_switch_context(&prev->ctx, &next->ctx);
@@ -316,6 +318,35 @@ void schedule(void)
}
}
int sched_wakeup_process(struct process *proc, int valid_states)
{
int status;
unsigned long irqstate;
struct cpu_local_var *v = get_cpu_local_var(proc->cpu_id);
irqstate = aal_mc_spinlock_lock(&(v->runq_lock));
if (proc->status & valid_states) {
proc->status = PS_RUNNING;
status = 0;
}
else {
status = -EINVAL;
}
aal_mc_spinlock_unlock(&(v->runq_lock), irqstate);
if (!status && (proc->cpu_id != aal_mc_get_processor_id())) {
aal_mc_interrupt_cpu(get_x86_cpu_local_variable(proc->cpu_id)->apic_id,
0xd1);
}
return status;
}
/* Runq lock must be held here */
void __runq_add_proc(struct process *proc, int cpu_id)
{

147
kernel/waitq.c Normal file
View File

@@ -0,0 +1,147 @@
/* Kitten waitqueue adaptation */
#include <waitq.h>
#include <process.h>
#include <cls.h>
int
default_wake_function(waitq_entry_t *entry, unsigned mode,
int flags, void *key)
{
return sched_wakeup_process(entry->private, PS_NORMAL);
}
void
waitq_init(waitq_t *waitq)
{
aal_mc_spinlock_init(&waitq->lock);
INIT_LIST_HEAD(&waitq->waitq);
}
void
waitq_init_entry(waitq_entry_t *entry, struct process *proc)
{
entry->private = proc;
entry->func = default_wake_function;
INIT_LIST_HEAD(&entry->link);
}
int
waitq_active(waitq_t *waitq)
{
int active;
unsigned long irqstate;
irqstate = aal_mc_spinlock_lock(&waitq->lock);
active = !list_empty(&waitq->waitq);
aal_mc_spinlock_unlock(&waitq->lock, irqstate);
return active;
}
void
waitq_add_entry(waitq_t *waitq, waitq_entry_t *entry)
{
unsigned long irqstate;
irqstate = aal_mc_spinlock_lock(&waitq->lock);
waitq_add_entry_locked(waitq, entry);
aal_mc_spinlock_unlock(&waitq->lock, irqstate);
}
void
waitq_add_entry_locked(waitq_t *waitq, waitq_entry_t *entry)
{
//BUG_ON(!list_empty(&entry->link));
list_add_tail(&entry->link, &waitq->waitq);
}
void
waitq_remove_entry(waitq_t *waitq, waitq_entry_t *entry)
{
unsigned long irqstate;
irqstate = aal_mc_spinlock_lock(&waitq->lock);
waitq_remove_entry_locked(waitq, entry);
aal_mc_spinlock_unlock(&waitq->lock, irqstate);
}
void
waitq_remove_entry_locked(waitq_t *waitq, waitq_entry_t *entry)
{
//BUG_ON(list_empty(&entry->link));
list_del_init(&entry->link);
}
void
waitq_prepare_to_wait(waitq_t *waitq, waitq_entry_t *entry, int state)
{
unsigned long irqstate;
irqstate = aal_mc_spinlock_lock(&waitq->lock);
if (list_empty(&entry->link))
list_add(&entry->link, &waitq->waitq);
cpu_local_var(current)->status = state;
aal_mc_spinlock_unlock(&waitq->lock, irqstate);
}
void
waitq_finish_wait(waitq_t *waitq, waitq_entry_t *entry)
{
cpu_local_var(current)->status = PS_RUNNING;
waitq_remove_entry(waitq, entry);
}
void
waitq_wakeup(waitq_t *waitq)
{
unsigned long irqstate;
struct list_head *tmp;
waitq_entry_t *entry;
irqstate = aal_mc_spinlock_lock(&waitq->lock);
list_for_each(tmp, &waitq->waitq) {
entry = list_entry(tmp, waitq_entry_t, link);
entry->func(entry, 0, 0, NULL);
}
aal_mc_spinlock_unlock(&waitq->lock, irqstate);
}
int
waitq_wake_nr(waitq_t * waitq, int nr)
{
unsigned long irqstate;
irqstate = aal_mc_spinlock_lock(&waitq->lock);
int count = waitq_wake_nr_locked(waitq, nr);
aal_mc_spinlock_unlock(&waitq->lock, irqstate);
if (count > 0)
schedule();
return count;
}
int
waitq_wake_nr_locked( waitq_t * waitq, int nr )
{
int count = 0;
waitq_entry_t *entry;
list_for_each_entry(entry, &waitq->waitq, link) {
if (++count > nr)
break;
entry->func(entry, 0, 0, NULL);
}
return count - 1;
}