Initial commit

This commit is contained in:
Bahadir Balban
2008-01-13 13:53:52 +00:00
commit e2b791a3d8
789 changed files with 95825 additions and 0 deletions

12
src/lib/SConscript Normal file
View File

@@ -0,0 +1,12 @@
# Inherit global environment
Import('env')
Import('config_symbols')
# The set of source files associated with this SConscript file.
src_local = ['printk.c', 'putc.c', 'string.c', 'bit.c', 'wait.c', 'mutex.c', 'idpool.c', 'memcache.c']
if "ARCH_TEST" not in config_symbols:
obj = env.Object(src_local)
else:
obj = []
Return('obj')

52
src/lib/bit.c Normal file
View File

@@ -0,0 +1,52 @@
/*
* Bit manipulation functions.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/lib/bit.h>
#include INC_GLUE(memory.h)
/* Emulation of ARM's CLZ (count leading zeroes) instruction */
unsigned int __clz(unsigned int bitvector)
{
unsigned int x = 0;
while((!(bitvector & ((unsigned)1 << 31))) && (x < 32)) {
bitvector <<= 1;
x++;
}
return x;
}
int find_and_set_first_free_bit(u32 *word, unsigned int limit)
{
int success = 0;
int i;
for(i = 0; i < limit; i++) {
/* Find first unset bit */
if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) {
/* Set it */
word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i);
success = 1;
break;
}
}
/* Return bit just set */
if (success)
return i;
else
return -1;
}
int check_and_clear_bit(u32 *word, int bit)
{
/* Check that bit was set */
if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) {
word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit);
return 0;
} else {
//printf("Trying to clear already clear bit\n");
return -1;
}
}

35
src/lib/idpool.c Normal file
View File

@@ -0,0 +1,35 @@
/*
* Used for thread and space ids.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/lib/printk.h>
#include <l4/lib/idpool.h>
#include <l4/generic/kmalloc.h>
#include INC_GLUE(memory.h)
struct id_pool *id_pool_new_init(int totalbits)
{
int nwords = BITWISE_GETWORD(totalbits);
struct id_pool *new = kzalloc((nwords * SZ_WORD)
+ sizeof(struct id_pool));
new->nwords = nwords;
return new;
}
int id_new(struct id_pool *pool)
{
int id = find_and_set_first_free_bit(pool->bitmap,
pool->nwords * WORD_BITS);
BUG_ON(id < 0);
return id;
}
int id_del(struct id_pool *pool, int id)
{
int ret = check_and_clear_bit(pool->bitmap, id);
BUG_ON(ret < 0);
return ret;
}

170
src/lib/memcache.c Normal file
View File

@@ -0,0 +1,170 @@
/*
* Bitmap-based linked-listable fixed-size memory cache.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/lib/memcache.h>
#include <l4/lib/string.h>
#include <l4/lib/printk.h>
#include INC_GLUE(memory.h)
#include <l4/lib/bit.h>
/* Allocate, clear and return element */
void *mem_cache_zalloc(struct mem_cache *cache)
{
void *elem = mem_cache_alloc(cache);
memset(elem, 0, cache->struct_size);
return elem;
}
/* Allocate another element from given @cache. Returns 0 when full. */
void *mem_cache_alloc(struct mem_cache *cache)
{
int bit;
if (cache->free > 0) {
mutex_lock(&cache->mutex);
cache->free--;
if ((bit = find_and_set_first_free_bit(cache->bitmap,
cache->total)) < 0) {
printk("Error: Anomaly in cache occupied state.\n"
"Bitmap full although cache->free > 0\n");
BUG();
}
mutex_unlock(&cache->mutex);
return (void *)(cache->start + (cache->struct_size * bit));
} else {
/* Cache full */
return 0;
}
}
/* Free element at @addr in @cache. Return negative on error. */
int mem_cache_free(struct mem_cache *cache, void *addr)
{
unsigned int struct_addr = (unsigned int)addr;
unsigned int bit;
int err = 0;
/* Check boundary */
if (struct_addr < cache->start || struct_addr > cache->end)
return -1; /* Address doesn't belong to cache */
bit = ((struct_addr - cache->start) / cache->struct_size);
/*
* Check alignment:
* Find out if there was a lost remainder in last division.
* There shouldn't have been, because addresses are allocated at
* struct_size offsets from cache->start.
*/
if (((bit * cache->struct_size) + cache->start) != struct_addr) {
printk("Error: This address is not aligned on a predefined "
"structure address in this cache.\n");
err = -1;
return err;
}
mutex_lock(&cache->mutex);
/* Check free/occupied state */
if (check_and_clear_bit(cache->bitmap, bit) < 0) {
printk("Error: Anomaly in cache occupied state:\n"
"Trying to free already free structure.\n");
err = -1;
goto out;
}
cache->free++;
if (cache->free > cache->total) {
printk("Error: Anomaly in cache occupied state:\n"
"More free elements than total.\n");
err = -1;
goto out;
}
out:
mutex_unlock(&cache->mutex);
return err;
}
struct mem_cache *mem_cache_init(void *start,
int cache_size,
int struct_size,
unsigned int aligned)
{
struct mem_cache *cache = start;
unsigned int area_start;
unsigned int *bitmap;
int bwords_in_structs;
int bwords;
int total;
int bsize;
if ((struct_size < 0) || (cache_size < 0) ||
((unsigned long)start == ~(0))) {
printk("Invalid parameters.\n");
return 0;
}
/*
* The cache definition itself is at the beginning.
* Skipping it to get to start of free memory. i.e. the cache.
*/
area_start = (unsigned long)start + sizeof(struct mem_cache);
cache_size -= sizeof(struct mem_cache);
if (cache_size < struct_size) {
printk("Cache too small for given struct_size\n");
return 0;
}
/* Get how much bitmap words occupy */
total = cache_size / struct_size;
bwords = total >> 5; /* Divide by 32 */
if (total & 0x1F) { /* Remainder? */
bwords++; /* Add one more word for remainder */
}
bsize = bwords * 4;
/* This many structures will be chucked from cache for bitmap space */
bwords_in_structs = ((bsize) / struct_size) + 1;
/* Total structs left after deducing bitmaps */
total = total - bwords_in_structs;
cache_size -= bsize;
/* This should always catch too small caches */
if (total <= 0) {
printk("Cache too small for given struct_size\n");
return 0;
}
if (cache_size <= 0) {
printk("Cache too small for given struct_size\n");
return 0;
}
bitmap = (unsigned int *)area_start;
area_start = (unsigned int)(bitmap + bwords);
if (aligned) {
unsigned int addr = area_start;
unsigned int addr_aligned = align_up(area_start, struct_size);
unsigned int diff = addr_aligned - addr;
BUG_ON(diff >= struct_size);
if (diff)
total--;
cache_size -= diff;
area_start = addr_aligned;
}
INIT_LIST_HEAD(&cache->list);
cache->start = area_start;
cache->end = area_start + cache_size;
cache->total = total;
cache->free = cache->total;
cache->struct_size = struct_size;
cache->bitmap = bitmap;
mutex_init(&cache->mutex);
memset(cache->bitmap, 0, bwords*SZ_WORD);
return cache;
}

149
src/lib/mutex.c Normal file
View File

@@ -0,0 +1,149 @@
/*
* Mutex/Semaphore implementations.
*
* Copyright (c) 2007 Bahadir Balban
*/
#include <l4/lib/mutex.h>
#include <l4/generic/scheduler.h>
#include <l4/generic/tcb.h>
/*
* Semaphore usage:
*
* Producer locks/produces/unlocks data.
* Producer does semaphore up.
* --
* Consumer does semaphore down.
* Consumer locks/consumes/unlocks data.
*/
/*
* Semaphore *up* for multiple producers. If any consumer is waiting, wake them
* up, otherwise, sleep. Effectively producers and consumers use the same
* waitqueue and there's only one kind in the queue at any one time.
*/
void sem_up(struct mutex *mutex)
{
int cnt;
spin_lock(&mutex->slock);
if ((cnt = mutex_inc(&mutex->lock)) <= 0) {
struct waitqueue *wq;
struct ktcb *sleeper;
/* Each producer wakes one consumer in queue. */
mutex->sleepers--;
BUG_ON(list_empty(&mutex->wq.task_list));
list_for_each_entry(wq, &mutex->wq.task_list, task_list) {
list_del_init(&wq->task_list);
spin_unlock(&mutex->slock);
sleeper = wq->task;
printk("(%d) Waking up consumer (%d)\n", current->tid,
sleeper->tid);
sched_resume_task(sleeper);
return; /* Don't iterate, wake only one task. */
}
} else if (cnt > 0) {
DECLARE_WAITQUEUE(wq, current);
INIT_LIST_HEAD(&wq.task_list);
list_add_tail(&wq.task_list, &mutex->wq.task_list);
mutex->sleepers++;
sched_notify_sleep(current);
need_resched = 1;
printk("(%d) produced, now sleeping...\n", current->tid);
spin_unlock(&mutex->slock);
}
}
/*
* Semaphore *down* for multiple consumers. If any producer is sleeping, wake them
* up, otherwise, sleep. Effectively producers and consumers use the same
* waitqueue and there's only one kind in the queue at any one time.
*/
void sem_down(struct mutex *mutex)
{
int cnt;
spin_lock(&mutex->slock);
if ((cnt = mutex_dec(&mutex->lock)) >= 0) {
struct waitqueue *wq;
struct ktcb *sleeper;
/* Each consumer wakes one producer in queue. */
mutex->sleepers--;
BUG_ON(list_empty(&mutex->wq.task_list));
list_for_each_entry(wq, &mutex->wq.task_list, task_list) {
list_del_init(&wq->task_list);
spin_unlock(&mutex->slock);
sleeper = wq->task;
printk("(%d) Waking up producer (%d)\n", current->tid,
sleeper->tid);
sched_resume_task(sleeper);
return; /* Don't iterate, wake only one task. */
}
} else if (cnt < 0) {
DECLARE_WAITQUEUE(wq, current);
INIT_LIST_HEAD(&wq.task_list);
list_add_tail(&wq.task_list, &mutex->wq.task_list);
mutex->sleepers++;
sched_notify_sleep(current);
need_resched = 1;
printk("(%d) Waiting to consume, now sleeping...\n", current->tid);
spin_unlock(&mutex->slock);
}
}
void mutex_lock(struct mutex *mutex)
{
/* NOTE:
* Everytime we're woken up we retry acquiring the mutex. It is
* undeterministic as to how many retries will result in success.
*/
for (;;) {
spin_lock(&mutex->slock);
if (!__mutex_lock(&mutex->lock)) { /* Could not lock, sleep. */
DECLARE_WAITQUEUE(wq, current);
INIT_LIST_HEAD(&wq.task_list);
list_add_tail(&wq.task_list, &mutex->wq.task_list);
mutex->sleepers++;
sched_notify_sleep(current);
printk("(%d) sleeping...\n", current->tid);
spin_unlock(&mutex->slock);
} else
break;
}
spin_unlock(&mutex->slock);
}
void mutex_unlock(struct mutex *mutex)
{
spin_lock(&mutex->slock);
__mutex_unlock(&mutex->lock);
BUG_ON(mutex->sleepers < 0);
if (mutex->sleepers > 0) {
struct waitqueue *wq;
struct ktcb *sleeper;
/* Each unlocker wakes one other sleeper in queue. */
mutex->sleepers--;
BUG_ON(list_empty(&mutex->wq.task_list));
list_for_each_entry(wq, &mutex->wq.task_list, task_list) {
list_del_init(&wq->task_list);
spin_unlock(&mutex->slock);
/*
* Here, someone else may get the lock, well before we
* wake up the sleeper that we *hope* would get it. This
* is fine as the sleeper would retry and re-sleep. BUT,
* this may potentially starve the sleeper causing
* non-determinisim.
*/
sleeper = wq->task;
printk("(%d) Waking up (%d)\n", current->tid,
sleeper->tid);
sched_resume_task(sleeper);
return; /* Don't iterate, wake only one task. */
}
}
spin_unlock(&mutex->slock);
}

445
src/lib/printk.c Normal file
View File

@@ -0,0 +1,445 @@
/*********************************************************************
*
* Copyright (C) 2002-2004 Karlsruhe University
*
* File path: generic/printk.cc
* Description: Implementation of printf
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <stdarg.h> /* for va_list, ... comes with gcc */
#include <l4/lib/printk.h>
/* FIXME: LICENSE LICENCE */
typedef unsigned int word_t;
extern void putc(const char c);
extern int print_tid (word_t val, word_t width, word_t precision, int adjleft);
/* convert nibble to lowercase hex char */
#define hexchars(x) (((x) < 10) ? ('0' + (x)) : ('a' + ((x) - 10)))
/**
* Print hexadecimal value
*
* @param val value to print
* @param width width in caracters
* @param precision minimum number of digits to apprear
* @param adjleft left adjust the value
* @param nullpad pad with leading zeros (when right padding)
*
* Prints a hexadecimal value with leading zeroes of given width
* using putc(), or if adjleft argument is given, print
* hexadecimal value with space padding to the right.
*
* @returns the number of charaters printed (should be same as width).
*/
int print_hex64(u64 val, int width, int precision, int adjleft, int nullpad)
{
int i, n = 0;
int nwidth = 0;
u32 high, low;
high = val >> 32;
low = (u32)val;
// Find width of hexnumber
if (high) {
while ((high >> (4 * nwidth)) && ((unsigned) nwidth < 2 * sizeof (u32)))
nwidth++;
nwidth += 32;
} else {
while ((low >> (4 * nwidth)) && ((unsigned) nwidth < 2 * sizeof (u32)))
nwidth++;
}
if (nwidth == 0)
nwidth = 1;
// May need to increase number of printed digits
if (precision > nwidth)
nwidth = precision;
// May need to increase number of printed characters
if (width == 0 && width < nwidth)
width = nwidth;
// Print number with padding
if (high)
{
if (!adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (nullpad ? '0' : ' ');
for (i = 4 * (nwidth - 33); i >= 0; i -= 4, n++)
putc (hexchars ((high >> i) & 0xF));
if (adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (' ');
width -= 32;
nwidth -= 32;
nullpad = 1;
}
if (! adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (nullpad ? '0' : ' ');
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
putc (hexchars ((low >> i) & 0xF));
if (adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (' ');
return n;
}
int print_hex_3arg(const word_t val, int width, int precision)
{
long i, n = 0;
long nwidth = 0;
int adjleft = 0;
int nullpad = 0;
// Find width of hexnumber
while ((val >> (4 * nwidth)) && (word_t) nwidth < 2 * sizeof (word_t))
nwidth++;
if (nwidth == 0)
nwidth = 1;
// May need to increase number of printed digits
if (precision > nwidth)
nwidth = precision;
// May need to increase number of printed characters
if (width == 0 && width < nwidth)
width = nwidth;
// Print number with padding
if (! adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (nullpad ? '0' : ' ');
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
putc (hexchars ((val >> i) & 0xF));
if (adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (' ');
return n;
}
int print_hex_5arg(const word_t val, int width,
int precision, int adjleft, int nullpad)
{
long i, n = 0;
long nwidth = 0;
// Find width of hexnumber
while ((val >> (4 * nwidth)) && (word_t) nwidth < 2 * sizeof (word_t))
nwidth++;
if (nwidth == 0)
nwidth = 1;
// May need to increase number of printed digits
if (precision > nwidth)
nwidth = precision;
// May need to increase number of printed characters
if (width == 0 && width < nwidth)
width = nwidth;
// Print number with padding
if (! adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (nullpad ? '0' : ' ');
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
putc (hexchars ((val >> i) & 0xF));
if (adjleft)
for (i = width - nwidth; i > 0; i--, n++)
putc (' ');
return n;
}
/**
* Print a string
*
* @param s zero-terminated string to print
* @param width minimum width of printed string
*
* Prints the zero-terminated string using putc(). The printed
* string will be right padded with space to so that it will be
* at least WIDTH characters wide.
*
* @returns the number of charaters printed.
*/
int print_string_3arg(const char * s, const int width, const int precision)
{
int n = 0;
for (;;)
{
if (*s == 0)
break;
putc(*s++);
n++;
if (precision && n >= precision)
break;
}
while (n < width) { putc(' '); n++; }
return n;
}
int print_string_1arg(const char * s)
{
int n = 0;
int width = 0;
int precision = 0;
for (;;) {
if (*s == 0)
break;
putc(*s++);
n++;
if (precision && n >= precision)
break;
}
while (n < width) {
putc(' ');
n++;
}
return n;
}
/**
* Print hexadecimal value with a separator
*
* @param val value to print
* @param bits number of lower-most bits before which to
* place the separator
* @param sep the separator to print
*
* @returns the number of charaters printed.
*/
int print_hex_sep(const word_t val, const int bits, const char *sep)
{
int n = 0;
n = print_hex_3arg(val >> bits, 0, 0);
n += print_string_1arg(sep);
n += print_hex_3arg(val & ((1 << bits) - 1), 0, 0);
return n;
}
/**
* Print decimal value
*
* @param val value to print
* @param width width of field
* @param pad character used for padding value up to width
*
* Prints a value as a decimal in the given WIDTH with leading
* whitespaces.
*
* @returns the number of characters printed (may be more than WIDTH)
*/
int print_dec(const word_t val, int width)
{
word_t divisor;
int digits;
/* estimate number of spaces and digits */
for (divisor = 1, digits = 1; val/divisor >= 10; divisor *= 10, digits++);
/* print spaces */
for ( ; digits < width; digits++ )
putc(' ');
/* print digits */
do {
putc(((val/divisor) % 10) + '0');
} while (divisor /= 10);
/* report number of digits printed */
return digits;
}
/**
* Does the real printk work
*
* @param format_p pointer to format string
* @param args list of arguments, variable length
*
* Prints the given arguments as specified by the format string.
* Implements a subset of the well-known printf plus some L4-specifics.
*
* @returns the number of characters printed
*/
int do_printk(char* format_p, va_list args)
{
const char* format = format_p;
int n = 0;
int i = 0;
int width = 8;
int precision = 0;
int adjleft = 0, nullpad = 0;
#define arg(x) va_arg(args, x)
/* sanity check */
if (format == '\0')
{
return 0;
}
while (*format)
{
switch (*(format))
{
case '%':
width = precision = 0;
adjleft = nullpad = 0;
reentry:
switch (*(++format))
{
/* modifiers */
case '.':
for (format++; *format >= '0' && *format <= '9'; format++)
precision = precision * 10 + (*format) - '0';
if (*format == 'w')
{
// Set precision to printsize of a hex word
precision = sizeof (word_t) * 2;
format++;
}
format--;
goto reentry;
case '0':
nullpad = (width == 0);
case '1'...'9':
width = width*10 + (*format)-'0';
goto reentry;
case 'w':
// Set width to printsize of a hex word
width = sizeof (word_t) * 2;
goto reentry;
case '-':
adjleft = 0;
goto reentry;
case 'l':
goto reentry;
break;
case 'c':
putc(arg(int));
n++;
break;
case 'm': /* microseconds */
{
n += print_hex64(arg(u64), width, precision,
adjleft, nullpad);
break;
}
case 'd':
{
long val = arg(long);
if (val < 0)
{
putc('-');
val = -val;
}
n += print_dec(val, width);
break;
}
case 'u':
n += print_dec(arg(long), width);
break;
case 'p':
precision = sizeof (word_t) * 2;
case 'x':
n += print_hex_5arg(arg(long), width, precision, adjleft, nullpad);
break;
case 's':
{
char* s = arg(char*);
if (s)
n += print_string_3arg(s, width, precision);
else
n += print_string_3arg("(null)", width, precision);
}
break;
case 't':
case 'T':
// Do nothing for now.
//n += print_tid (arg (word_t), width, precision, adjleft);
break;
case '%':
putc('%');
n++;
format++;
continue;
default:
n += print_string_1arg("?");
break;
};
i++;
break;
default:
putc(*format);
n++;
break;
}
format++;
}
return n;
}
/**
* Flexible print function
*
* @param format string containing formatting and parameter type
* information
* @param ... variable list of parameters
*
* @returns the number of characters printed
*/
int printk(char *format, ...)
{
va_list args;
int i;
va_start(args, format);
i = do_printk(format, args);
va_end(args);
return i;
};

14
src/lib/putc.c Normal file
View File

@@ -0,0 +1,14 @@
/*
* Generic putc implementation that ties with platform-specific uart driver.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include INC_PLAT(uart.h)
void putc(char c)
{
if (c == '\n')
uart_putc('\r');
uart_putc(c);
}

69
src/lib/string.c Normal file
View File

@@ -0,0 +1,69 @@
void *memset(void *p, int c, int size)
{
char ch;
char *pp;
pp = (char *)p;
ch = (char)c;
for (int i = 0; i < size; i++) {
*pp++ = ch;
}
return p;
}
void *memcpy(void *d, void *s, int size)
{
char *dst = (char *)d;
char *src = (char *)s;
for (int i = 0; i < size; i++) {
*dst = *src;
dst++;
src++;
}
return d;
}
int strcmp(const char *s1, const char *s2)
{
unsigned int i = 0;
int d;
while(1) {
d = (unsigned char)s1[i] - (unsigned char)s2[i];
if (d != 0 || s1[i] == '\0')
return d;
i++;
}
}
/* LICENCE: Taken from linux for now BB.
* strncpy - Copy a length-limited, %NUL-terminated string
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @count: The maximum number of bytes to copy
*
* The result is not %NUL-terminated if the source exceeds
* @count bytes.
*
* In the case where the length of @src is less than that of
* count, the remainder of @dest will be padded with %NUL.
*
*/
char *strncpy(char *dest, const char *src, int count)
{
char *tmp = dest;
while (count) {
if ((*tmp = *src) != 0)
src++;
tmp++;
count--;
}
return dest;
}

60
src/lib/wait.c Normal file
View File

@@ -0,0 +1,60 @@
/*
* Implementation of wakeup/wait for processes.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/generic/scheduler.h>
#include <l4/lib/wait.h>
#include <l4/lib/spinlock.h>
/* Sleep if the given condition isn't true. */
#define wait_event(wqh, condition) \
do { \
for (;;) { \
if (condition) \
break; \
DECLARE_WAITQUEUE(wq, current); \
spin_lock(&wqh->slock); \
wqh->sleepers++; \
list_add_tail(&wq.task_list, &wqh->task_list); \
sched_tell(current, SCHED_FL_SLEEP); \
need_resched = 1; \
printk("(%d) waiting...\n", current->tid); \
spin_unlock(&wqh->slock); \
} \
} while(0);
/* Sleep without any condition */
#define wait_on(wqh) \
do { \
DECLARE_WAITQUEUE(wq, current); \
spin_lock(&wqh->slock); \
wqh->sleepers++; \
list_add_tail(&wq.task_list, &wqh->task_list); \
sched_tell(current, SCHED_FL_SLEEP); \
need_resched = 1; \
printk("(%d) waiting...\n", current->tid); \
spin_unlock(&wqh->slock); \
} while(0);
/* Wake up single waiter */
void wake_up(struct waitqueue_head *wqh)
{
BUG_ON(wqh->sleepers < 0);
spin_lock(&wqh->slock);
if (wqh->sleepers > 0) {
struct waitqueue *wq = list_entry(wqh->task_list.next,
struct waitqueue,
task_list);
struct ktcb *sleeper = wq->task;
list_del_init(&wq->task_list);
wqh->sleepers--;
BUG_ON(list_empty(&wqh->task_list));
printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid);
sched_notify_resume(sleeper);
spin_unlock(&wqh->slock);
return;
}
spin_unlock(&wqh->slock);
}