www.pudn.com > pebble.zip > app1.c
/*
* Copyright 1999, 2000, 2001, 2002 Lucent Technologies Inc.
* All Rights Reserved.
* Information Sciences Research Center, Bell Labs.
*
* LUCENT TECHNOLOGIES DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE
* OR THE SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The
* software is provided "as is" without expressed or implied warranty
* of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*
*/
#include "unistd.h" /* for write, sbrk, fork */
#include "types.h"
#include "pebble.h"
#include "time.h"
#include "synch.h"
#include "signal.h"
#include "log.h"
#include "lock_free.h"
#include "assert.h"
enum {
N = 10000,
N10 = N*10, /* number of mutex_lock/unlock pairs */
MEM = (1024*1024),
M = 20, /* number of timeout events */
K = 1000, /* number of condition variable operations */
NTHREAD = 7, /* number of threads for mutex test */
NP = 4, /* group size of portals to create/delete */
NLOG = 10, /* number of events log entries to create */
MAGIC_CODE = 0xdeadbeef,/* magic code for event log entries */
CLONE_MAGIC = 0x12345678,/* magic constant in cloned portals */
SIG1 = 1,
SIG2 = 2,
SIG3 = 10,
SIG4 = NSIG,
};
typedef struct {
Condition cond;
Lock lock;
int count;
vlong version;
} Cond_Barrier;
typedef struct Elem Elem;
struct Elem {
int val;
Elem *next;
};
typedef struct Chan Chan;
struct Chan {
Lock lock;
Condition cond;
Elem *head;
Elem *tail;
};
static int shared_flag;
static int rpc1, rpc2;
static Time when[M], timeout_delay[M];
/* elapsed time of N iterations of an empty loop in machine cycles */
static Time loop_overhead;
static int timeout_flag[M];
static Barrier b;
static Lock master_lock;
static Lock ring[NTHREAD];
static void *v[N];
static CQ cq;
static void *cq_buf[NTHREAD];
static Cond_Barrier cb;
static Chan chan[NTHREAD];
/* data structures for testing cond_signal_thread */
static Condition c;
static Lock l;
static volatile int nc = 0;
static void *thread_id[NTHREAD];
/* demonstrate modulu bug */
void
test_mod(ulong u)
{
int k;
k = u % (NTHREAD-1);
printf("k=%d (ulong)\n", k);
k = (long)u % (NTHREAD-1);
printf("k=%d (long)\n", k);
}
void
test_csd()
{
Lock lock, old_lock, new_lock;
int word;
printf("testing compare & swap\n");
word = 0;
if (csw(&word, 0, 1) < 0)
panic("csw 0 failed");
if (csw(&word, 1, 0) < 0)
panic("csw 1 failed");
lock.v = 0;
if (csd((vlong *)&lock, 0, 1) < 0)
panic("csd 0 failed");
lock.v = 0;
lock.s.flags = 1;
old_lock = lock;
new_lock = lock;
new_lock.s.lock = 1;
if (csd((vlong *)&lock, old_lock.v, new_lock.v) < 0)
panic("csd 1 failed");
old_lock = lock;
new_lock = old_lock;
new_lock.s.lock = 0;
if (csd((vlong *)&lock, old_lock.v, new_lock.v) < 0)
panic("csd 2 failed");
printf("csd() test ended successfully\n\n");
}
/* tests idle_time(), usleep() and sec2ticks() */
/* implicit assumption: the idle loop does one iteration per clock tick */
void
test_idle(void)
{
Time start, elapsed;
Time s2ticks = sec2ticks();
printf("testing idle_time():\n");
printf("waiting for serial output buffer to flush\n");
/* note: we wait exactly one second! */
start = hrtime();
usleep(SEC2USEC);
elapsed = hrtime() - start;
if (elapsed < s2ticks || elapsed > (5*s2ticks)/4)
panic("usleep(1sec) duration %d ticks; expected %d ticks",
(int)elapsed, (int)s2ticks);
else
printf("usleep(1sec) duration %d ticks; expected %d ticks\n",
(int)elapsed, (int)s2ticks);
start = idle_time();
if (hrsleep(hrtime() + s2ticks) < 0)
panic("hrsleep() failed:");
elapsed = idle_time() - start;
printf("idle ticks=%u %u during hrsleep for %d ticks\n",
(int)(elapsed >> 32), (int)elapsed, (int)s2ticks);
if (elapsed < (4*s2ticks)/5 || elapsed > s2ticks)
printf("idle_time() test failed\n");
else
printf("idle_time() test passed successfully\n\n");
}
int
f(unsigned long task, int i)
{
int x;
printf("RPC f(%d) thread=%08lx executes in asid %d stack at %p\n",
i, task, get_asid(), &x);
return -i;
}
int
g(unsigned long task, int i)
{
return -i;
}
void
test_mem(int *start, int *end)
{
volatile int *p;
for (p = start; p < end; p++)
*p = (int)p;
for (p = start; p < end; p++)
if (*p != (int)p)
printf("heap contents error at %p\n", p);
}
void
tout(void *val)
{
assert((int)val >= 0 && (int)val < M);
timeout_delay[(int)val] = hrtime() - when[(int)val];
timeout_flag[(int)val] = 1;
}
void *
alloc_page()
{
int psize, offset;
void *brk, *page;
psize = getpagesize();
/* allocate enough memory to align on next page boundary */
brk = sbrk(0);
if (brk == (void *)-1)
panic("sbrk(0):");
offset = ((int)brk) & (psize - 1);
if (offset != 0)
sbrk(psize - offset);
/* allocate a page of the heap */
page = sbrk(psize);
if (page == (void *)-1)
panic("sbrk(pagesize()):");
offset = ((int)page) & (psize - 1);
if (offset != 0)
panic("alloc_page() failed to allocate on page boundary");
return page;
}
void
set_mem(int *start, int len)
{
int i, *p;
for (i = 0, p = start; i < len; i += sizeof(int), p++)
*p = ~((int)p);
}
void
check_mem(int *start, int val, int len)
{
int i, *p;
for (i = 0, p = start; i < len; i += sizeof(int), p++) {
if (*p == ~(val + i))
continue;
printf("check_mem failed: addr=%p value=%08x should be=%08x\n",
p, *p, ~(val+i));
task_exit(1);
}
}
void
test_malloc(void)
{
int sz;
char *np;
printf("sbrk(0)=%p getpagesize()=%d\n", sbrk(0), getpagesize());
printf("before malloc test: TLB miss count=%d general exceptions count=%d\n",
get_tlb_excpt_count(), get_gen_excpt_count());
for (sz = 8; sz <= MEM; sz *= 2) {
if ((np = (char *)malloc(sz)) == NULL)
panic("malloc:");
printf("testing dynamic memory [%p,%p] size=%d\n",
np, np+sz, sz);
test_mem((int *)np, (int *)(np+sz));
printf("virt=%p phys=%p - virt=%p phys=%p\n",
np, virt2phys(np), np+sz-1, virt2phys(np+sz-1));
free(np);
}
printf("after malloc test: TLB miss count=%d general exceptions count=%d\n",
get_tlb_excpt_count(), get_gen_excpt_count());
printf("malloc test ended successfully\n\n");
}
/* test event logging */
void
test_log(void)
{
int i, j, head, last_head;
int errors = 0;
LogEntry entry;
uchar found[NLOG];
printf("starting events log test\n");
/* generate event log entries */
if ((last_head = get_log_head()) < 0)
panic("get_log_head:");
for (i = 0; i < NLOG; i++) {
put_log(MAGIC_CODE, i);
head = get_log_head();
if (head == last_head)
panic("put_log did not move the log head");
last_head = head;
}
memset(found, 0, sizeof(found));
/* scan the log from the oldest to the newest entry */
j = get_log_head();
for (i = 0; i < get_log_entries(); i++) {
if (get_log(j, &entry) < 0)
panic("get_log(%d) failed:", j);
j = (j + 1) % get_log_entries();
if (entry.v[LOG_ENTRY_P0] != MAGIC_CODE)
continue;
if (entry.v[LOG_ENTRY_P1] < 0 || entry.v[LOG_ENTRY_P1] >= NLOG)
panic("invalid log entry index=%d",
entry.v[LOG_ENTRY_P1]);
found[entry.v[LOG_ENTRY_P1]]++;
}
/* check that we found all entries that we placed in the events log */
for (i = 0; i < NLOG; i++) {
if (found[i] == 0) {
printf("event log entry #%d is missing from the log\n",
i);
errors++;
} else if (found[i] > 1) {
printf("event log entry #%d appears %d times in log\n",
i, found[i]);
errors++;
}
}
if (errors)
panic("events log test failed");
else
printf("events log test completed successfully\n\n");
}
/* test portal allocation and deletion */
void
test_portal_alloc(void)
{
int i, j, id, id1, id_clone, id_clone1, code;
Time start, elapsed;
char msg[NAMELEN];
printf("allocating %d portals and deleting without portal creation\n",
NP);
if ((id1 = portal_create(-1, "smtiii", 0, &f, 0)) < 0)
panic("portal_alloc failed:");
if ((id = portal_alloc(NP, 0)) < 0)
panic("portal_alloc(%d, 0) failed:", NP);
if (portal_clone(-1, id, NP, CLONE_MAGIC, 0) > 0)
panic("portal_clone of uninitialized portals did not fail");
get_error(msg);
printf("expected error message for portal_clone: %s\n", msg);
if (portal_delete(id1, 1, 0) < 0)
panic("portal_delete(%d, 1, 0) failed:", id1);
if (portal_delete(id, NP, 0) < 0)
panic("portal_delete(%d, %d, 0) failed:", id, NP);
for (j = 0; j < 2; j++) {
printf(
"iteration %d: allocating, creating and deleting %d portals\n",
j, NP);
if ((code = portal_create(-1, "smtiii", 0, &f, 0)) != id1)
panic("portal_create(-1) returned %d; expected %d:",
code, id1);
if ((code = portal_alloc(NP, 0)) != id)
panic("portal_alloc(%d, 0) returned %d; expected %d:",
NP, code, id);
printf("single portal number=%d portals group starts at %d\n",
id1, id);
start = hrtime();
for (i = 0; i < NP; i++) {
code = portal_create(id+i, "smtcii", i, &g, 0);
if (code != id+i)
panic(
"portal_alloc(%d) returned %d; expected %d\n",
id+i, code, id+i);
}
elapsed = 2 * (hrtime() - start);
printf("created %d portals. starts at %d. elapsed=%d cycles\n",
NP, id, (int)elapsed);
start = hrtime();
if ((id_clone = portal_clone(-1, id, NP, CLONE_MAGIC, 0)) < 0)
panic("portal_clone failed:");
elapsed = 2 * (hrtime() - start);
printf("cloned %d portals. starts at %d. elapsed=%d cycles\n",
NP, id_clone, (int)elapsed);
if ((id_clone1 = portal_alloc(NP, 0)) < 0)
panic("portal_alloc(%d, 0) failed:", NP);
if ((code = portal_clone(id_clone1, id, NP, CLONE_MAGIC, 0))
!= id_clone1)
panic("portal_clone returns %d; expected %d:",
code, id_clone1);
for (i = 0; i < NP; i++) {
code = portal_magic(id+i, 0);
if (code != i)
panic(
"portal_magic(%d,0) returns %d; expected %d:",
id+i, code, i);
code = portal_magic(id_clone+i, 0);
if (code != CLONE_MAGIC)
panic(
"portal_magic(%d,0) returns %d; expected %d:",
id_clone+i, code, CLONE_MAGIC);
}
/* test regular and cloned portals */
printf("testing portal calls\n");
for (i = 0; i < NP; i++) {
if ((code = call_portal(id+i)) != -i)
panic("call_portal(%d) returns %d; expected %d",
code, -i);
if ((code = call_portal(id_clone+i)) != -CLONE_MAGIC)
panic("call_portal(%d) returns %d; expected %d",
code, -CLONE_MAGIC);
}
if (portal_delete(id1, 1, 0) < 0)
panic("portal_delete(%d, 1, 0) failed:", id1);
if (portal_delete(id, NP, 0) < 0)
panic("portal_delete(%d, %d, 0) failed:", id, NP);
if (portal_delete(id_clone, NP, 0) < 0)
panic("portal_delete(%d, %d, 0) failed:",
id_clone, NP);
if (portal_delete(id_clone1, NP, 0) < 0)
panic("portal_delete(%d, %d, 0) failed:",
id_clone1, NP);
}
printf("portal allocation, cloning & deletion ended successfully\n\n");
}
void
test_portal_window(void)
{
int i, sz, fd, code, window_peek_id;
char msg[NAMELEN];
char *np;
Time start, elapsed;
sz = getpagesize();
if ((np = (char *)alloc_page()) == NULL)
panic("malloc:");
if ((fd = fd_open("fs1")) < 0)
panic("fd_open(fs1):");
printf("calling fs write(NULL,%d)\n", sz);
code = call_portal(WRITE2PORT(fd), NULL, sz);
if (code >= 0)
panic("fs write did not fail!");
get_error(msg);
printf("code=%d error msg=%s\n", code, msg);
printf("calling fs write(invalid,%d)\n", sz);
code = call_portal(WRITE2PORT(fd), sbrk(0) + 2 * getpagesize(), sz);
if (code >= 0)
panic("fs write did not fail!");
get_error(msg);
printf("code=%d error msg=%s\n", code, msg);
np[0] = 0;
printf("calling fs write(%p,%d)\n", np, sz);
call_portal(WRITE2PORT(fd), np, sz);
printf("return from fs write\n");
printf("calling fs read(%p,%d)\n", np, sz);
call_portal(READ2PORT(fd), np, sz);
printf("buf[0] after fs read %d\n", np[0]);
printf("testing access to entire window contents in fs\n");
if ((window_peek_id = portal_open("fs_window_peek", 1)) < 0)
panic("portal_open of fs_window_peek:");
set_mem((int *)np, sz);
for (i = 0; i < sz; i += sizeof(int)) {
code = call_portal(window_peek_id, np + i);
if (code == ~((ulong)np + i))
continue;
printf("window peek failed for addr=%p value=%d expected=%d\n",
np + i, code, ~((uint)np + i));
task_exit(1);
}
printf("test of window access and contents ended successfully\n");
if ((fd = fd_open("fs2")) < 0)
panic("fd_open(fs2):");
printf("before window passing test: TLB miss count=%d general exceptions count=%d\n",
get_tlb_excpt_count(), get_gen_excpt_count());
printf("calling fs write2\n");
start = hrtime();
for (i = 0; i < N; i++)
call_portal(WRITE2PORT(fd), np, sz);
elapsed = 2*(hrtime() - start) - loop_overhead;
printf(
"elapsed cycles of %d portal crossing with window open/close w/out TLB update: %d\n",
i, (int)elapsed);
printf("each portal crossing: %d cycles\n",
(int)(elapsed+N/2)/N);
printf("after window passing test: TLB miss count=%d general exceptions count=%d\n",
get_tlb_excpt_count(), get_gen_excpt_count());
printf("calling fs read2\n");
np[0] = 0;
start = hrtime();
for (i = 0; i < N; i++)
call_portal(READ2PORT(fd), np, sz);
elapsed = 2*(hrtime() - start) - loop_overhead;
printf(
"elapsed cycles of %d portal crossing with window open/close and TLB update: %d\n",
i, (int)elapsed);
printf("each portal crossing: %d cycles\n",
(int)(elapsed+N/2)/N);
printf(
"after window access test: TLB miss count=%d general exceptions count=%d\n",
get_tlb_excpt_count(), get_gen_excpt_count());
printf("portal window test ended successfully\n\n");
}
void
test_page_transfer(void)
{
int i, code, sz, npages, *p1, *p2, *p3, *pp;
void *q;
int give_id, peek_id, take_id, swap_id;
int share_id, set_id, unmap_id, count_id;
char msg[NAMELEN];
Time start, elapsed;
/* check window give/take/swap */
printf("testing window give/take/swap\n");
p1 = alloc_page();
p2 = alloc_page();
p3 = alloc_page();
sz = getpagesize();
printf("p1=%p p2=%p p3=%p pagesize=%d\n", p1, p2, p3, sz);
set_mem(p1, sz);
set_mem(p2, sz);
set_mem(p3, sz);
clean_cache(p1, sz);
clean_cache(p2, sz);
clean_cache(p3, sz);
check_mem(p1, (int)p1, sz);
check_mem(p2, (int)p2, sz);
check_mem(p3, (int)p3, sz);
if ((give_id = portal_open("fs_give", 1)) < 0)
panic("portal_open(fs_give):");
if ((peek_id = portal_open("fs_peek", 1)) < 0)
panic("portal_open(fs_peek):");
if ((take_id = portal_open("fs_take", 1)) < 0)
panic("portal_open(fs_take):");
if ((swap_id = portal_open("fs_swap", 1)) < 0)
panic("portal_open(fs_swap):");
if ((share_id = portal_open("fs_share", 1)) < 0)
panic("portal_open(fs_share):");
if ((set_id = portal_open("fs_set", 1)) < 0)
panic("portal_open(fs_set):");
if ((unmap_id = portal_open("fs_unmap", 1)) < 0)
panic("portal_open(fs_unmap):");
if ((count_id = portal_open("fs_count", 1)) < 0)
panic("portal_open(fs_count):");
/* testing fs_give */
if (call_portal(give_id, NULL, 0) >= 0)
panic("fs_give(NULL) expected to fail but did not");
get_error(msg);
printf("expected error message from fs_give(NULL): %s\n", msg);
if (call_portal(give_id, &shared_flag, 0) >= 0)
panic("fs_give() expected to fail but did not");
get_error(msg);
printf("expected error message from fs_give(): %s\n",
msg);
if (vm_count_page(&shared_flag) >= 0)
panic("vm_count_page() did not fail\n");
get_error(msg);
printf("expected error message from vm_count_page(): %s\n",
msg);
if ((code = vm_count_page(p1)) < 0)
panic("vm_count_page(p1) failed:");
if (code != 1) {
printf("fs_count(%p) returned %d; expected 1\n", p1, code);
task_exit(1);
}
if (call_portal(give_id, p1, 0) < 0)
panic("fs_give:");
/* this doamin can not access page p1 any longer */
if (vm_count_page(p1) >= 0)
panic("vm_count_page(%p) expected to fail but did not\n", p1);
get_error(msg);
printf("expected error msg from vm_count_page(p1) after fs_give: %s\n",
msg);
/* fs domain can access page p1 */
if ((code = call_portal(count_id, p1)) < 0)
panic("fs_count(p1) failed:");
if (code != 1) {
printf("fs_count(%p) returned %d; expected 1\n", p1, code);
task_exit(1);
}
if (call_portal(give_id, p1, 0) >= 0)
panic("2nd fs_give expected to fail but did not");
get_error(msg);
printf("expected error message from 2nd give: %s\n", msg);
/* verify that page is available now in the fs domain */
printf("checking page contents after transfer to fs domain\n");
for (i = 0; i < sz; i += sizeof(int)) {
code = call_portal(peek_id, (int)p1 + i);
if (code != ~((int)p1+i)) {
printf("fs_peek failed: addr=%p value=%d expected=%d\n",
(int *)((int)p1 + i), code, ~((int)p1 + i));
task_exit(1);
}
}
printf("page contents is correct when accessed from fs domain\n");
/* get the page back */
pp = (int *)call_portal(take_id, 0);
if (pp == (int *)-1)
panic("fs_take:");
if (pp != p1) {
printf("fs_take returned %p; expected %p\n", pp, p1);
task_exit(1);
}
/* verify that fs domain can not access the page any longer */
if ((code = call_portal(count_id, p1)) >= 0)
panic("fs_count(%p) expected to fail but did not\n", p1);
get_error(msg);
printf("expected error msg from fs_count(p1) after fs_take: %s\n",
msg);
/* verify that calling domain can access the page */
if ((code = vm_count_page(pp)) < 0)
panic("vm_count_page(pp) failed:");
if (code != 1) {
printf("fs_count(%p) returned %d; expected 1\n", pp, code);
task_exit(1);
}
printf("vm_count_page(p1) after fs_take: %d\n", code);
printf("checking returned page contents\n");
check_mem(pp, (int)p1, sz);
pp = (int *)call_portal(take_id, 0);
if (pp != (int *)-1) {
printf("2nd fs_take did not fail as expected");
task_exit(1);
}
get_error(msg);
printf("expected error message from 2nd fs_take: %s\n", msg);
/* give page p1; then swap it with page p2 */
printf("checking page swap\n");
if (call_portal(give_id, p1, 0) < 0)
panic("fs_give:");
if (call_portal(swap_id, NULL, 0) >= 0) {
printf("fs_swap(NULL) did not fail as expected\n");
task_exit(1);
}
get_error(msg);
printf("expected error message from fs_swap(NULL): %s\n", msg);
if (call_portal(swap_id, &shared_flag, 0) >= 0) {
printf("fs_swap() did not fail as expected\n");
task_exit(1);
}
get_error(msg);
printf("expected error message from fs_swap(): %s\n", msg);
if (call_portal(swap_id, p1, 0) >= 0) {
printf("fs_swap(p1) did not fail as expected\n");
task_exit(1);
}
get_error(msg);
printf("expected error message from fs_swap(p1): %s\n", msg);
if (call_portal(swap_id, p2, 0) < 0)
panic("fs_swap(p2):");
pp = (int *)call_portal(take_id, 0);
if (pp == (int *)-1)
panic("fs_take:");
if (pp != p1) {
printf("fs_take returned %p; expected %p\n", pp, p1);
task_exit(1);
}
printf("checking contents of swapped pages\n");
check_mem(p1, (int)p2, sz);
check_mem(p2, (int)p1, sz);
/* test page share */
if (call_portal(share_id, p3) < 0)
panic("fs_share(p3):");
/* verify that page is available now in the fs domain */
printf("checking page contents after sharing with fs domain\n");
for (i = 0; i < sz; i += sizeof(int)) {
code = call_portal(peek_id, (int)p3 + i);
if (code != ~((int)p3+i)) {
printf("fs_peek failed: addr=%p value=%d expected=%d\n",
(int *)((int)p3 + i), code, ~((int)p3 + i));
task_exit(1);
}
}
printf("correct shared page contents when accessed from fs domain\n");
if (call_portal(set_id, p3, ~0) < 0)
panic("fs_set(p3, 0):");
if (*p3 != ~0) {
printf("fs_set failed: addr=%p value=%d expected=%d\n",
p3, *p3, ~0);
task_exit(1);
}
printf("fs_set succeeded\n");
if (call_portal(unmap_id, p3) < 0)
panic("fs_unmap(p3):");
if (call_portal(unmap_id, p3) >= 0) {
printf("2nd fs_unmap(%p) did not fail as expected\n", p3);
task_exit(1);
}
get_error(msg);
printf("expected error message from 2nd fs_unmap(p3): %s\n", msg);
if (vm_unmap_page(p3) >= 0) {
printf("vm_unmap_page(%p) did not fail as expected\n", p3);
task_exit(1);
}
get_error(msg);
printf("expected error message from vm_unmap_page(p3): %s\n", msg);
/* test vm_unmap_page() when page is shared twice with fs domain */
if (call_portal(share_id, p3) < 0)
panic("1st fs_share(p3):");
if (call_portal(share_id, p3) < 0)
panic("2nd fs_share(p3):");
if ((code = vm_count_page(p3)) < 0)
panic("vm_count_page(p3) failed:");
if (code != 1) {
printf("vm_count_page(%p) returns %d; expected 1\n", p3, code);
task_exit(1);
}
if ((code = call_portal(count_id, p3)) < 0)
panic("fs_count(p3) failed:");
if (code != 2) {
printf("fs_count(%p) returns %d; expected 2\n", p3, code);
task_exit(1);
}
printf("fs_count(p3) after two sharing with fs is %d\n", code);
if (vm_unmap_page(p3) < 0)
panic("vm_unmap_page(p3):");
printf("vm_unmap_page(p3) successful\n");
if (vm_count_page(p3) >= 0) {
printf("vm_count_page(%p) did not fail as expected\n", p3);
task_exit(1);
}
/* can unmap only once, since page is shared twice with fs domain */
if (call_portal(unmap_id, p3) < 0)
panic("1st fs_unmap(p3):");
if ((code = call_portal(count_id, p3)) < 0)
panic("fs_count(p3) failed:");
if (code != 1) {
printf("fs_count(%p) returns %d; expected 1\n", p3, code);
task_exit(1);
}
if (call_portal(unmap_id, p3) >= 0) {
printf("2nd fs_unmap(%p) did not fail as expected\n", p3);
task_exit(1);
}
get_error(msg);
printf("expected error message from 2nd fs_unmap(p3): %s\n", msg);
printf("page count/give/take/swap/share/set/unmap is successful\n\n");
npages = MEM/sz;
for (i = 0; i < npages; i++) {
if ((v[i] = (void *)malloc(sz)) == NULL)
panic("malloc:");
/* to force loading TLB entry */
memset((char *)v[i], 0, sz);
}
/* time page give with prior access */
start = hrtime();
for (i = 0; i < npages; i++)
if (call_portal(give_id, v[i], i) < 0)
panic("fs_give:");
elapsed = 2*(hrtime() - start) - (loop_overhead * npages) / N;
printf("elapsed cycles of %d page give (with TLB erase) is %d\n",
i, (int)elapsed);
printf("each page give (with TLB erase): %d cycles\n",
(int)(elapsed+npages/2)/npages);
/* force loading TLB entry in fs domain */
for (i = 0; i < npages; i++)
call_portal(peek_id, v[i]);
start = hrtime();
for (i = 0; i < npages; i++)
if (call_portal(swap_id, p1, i) < 0)
panic("fs_swap:");
elapsed = 2*(hrtime() - start) - (npages * loop_overhead) / N;
printf("elapsed cycles of %d page swaps (with TLB erase) is %d\n",
i, (int)elapsed);
printf("each page swap (with TLB erase): %d cycles\n",
(int)(elapsed+npages/2)/npages);
/* force loading TLB entry in fs domain */
for (i = 0; i < npages; i++)
call_portal(peek_id, v[i]);
/* time page take with prior access */
start = hrtime();
for (i = 0; i < npages; i++) {
q = (void *)call_portal(take_id, i);
if (v[i] != q) {
printf("fs take failed. returned %p expected %p\n",
q, v[i]);
task_exit(1);
}
}
elapsed = 2*(hrtime() - start) - (npages * loop_overhead) / N;
printf("elapsed cycles of %d page take (with TLB erase) is %d\n",
i, (int)elapsed);
printf("each page take (with TLB erase): %d cycles\n",
(int)(elapsed+npages/2)/npages);
/* time page give w/out prior access */
start = hrtime();
for (i = 0; i < npages; i++)
if (call_portal(give_id, v[i], i) < 0)
panic("fs_give:");
elapsed = 2*(hrtime() - start) - (npages * loop_overhead) / N;
printf("elapsed cycles of %d page give (w/out TLB erase) is %d\n",
i, (int)elapsed);
printf("each page give (w/out TLB erase): %d cycles\n",
(int)(elapsed+npages/2)/npages);
/* time page take w/out prior access */
start = hrtime();
for (i = 0; i < npages; i++) {
q = (void *)call_portal(take_id, i);
if (v[i] != q) {
printf("fs take failed. returned %p expected %p\n",
q, v[i]);
task_exit(1);
}
}
elapsed = 2*(hrtime() - start) - (npages * loop_overhead) / N;
printf("elapsed cycles of %d page take (w/out TLB erase) is %d\n",
i, (int)elapsed);
printf("each page take (w/out TLB erase): %d cycles\n",
(int)(elapsed+npages/2)/npages);
printf("\n");
}
void
cond_barrier_init(Cond_Barrier *cb)
{
cond_init(&cb->cond);
cb->count = cb->version = 0;
mutex_init(&cb->lock, MUTEX_ERRORCHECK);
}
void
cond_barrier(Cond_Barrier *cb, int i, int n)
{
vlong old_version;
mutex_lock_safe(&cb->lock, "lock barrier");
cb->count++;
if (cb->count < n) {
old_version = cb->version;
do {
if (cond_wait(&cb->cond, &cb->lock) < 0)
panic("cond_barrier: cond_wait failed:");
} while (cb->version == old_version);
} else {
cb->count = 0;
cb->version++;
if (cond_broadcast(&cb->cond) < 0)
panic("cond_barrier: cond_broadcast failed:");
}
mutex_unlock_safe(&cb->lock, "unlock barrier");
}
void
chan_init(Chan *c)
{
mutex_init(&c->lock, MUTEX_ERRORCHECK);
cond_init(&c->cond);
c->head = c->tail = NULL;
}
/* put a value in a channel which can obtained later by */
/* cond_get() or cond_tget() */
void
cond_put(Chan *c, int val)
{
Elem *e;
if ((e = (Elem *)malloc(sizeof(Elem))) == NULL)
panic("cond_put: malloc failed:");
e->val = val;
e->next = NULL;
mutex_lock_safe(&c->lock, "cond_put: lock channel");
if (c->tail != NULL)
c->tail->next = e;
else
c->head = e;
c->tail = e;
if (cond_signal(&c->cond) < 0)
panic("cond_put: cond_signal failed:");
mutex_unlock_safe(&c->lock, "cond_put: unlock channel");
}
/* get a value from a channel without timeout (blocking) */
int
cond_get(Chan *c)
{
Elem *e;
int val;
mutex_lock_safe(&c->lock, "cond_get: lock channel");
while ((e = c->head) == NULL) {
if (cond_wait(&c->cond, &c->lock) < 0)
panic("cond_get: cond_wait %p failed:", &c->cond);
}
c->head = e->next;
if (e->next == NULL)
c->tail = NULL;
mutex_unlock_safe(&c->lock, "cond_get: unlock channel");
val = e->val;
free(e);
return val;
}
/* get a value from a channel with timeout */
int
cond_tget(Chan *c, Time t)
{
Elem *e = NULL;
int val;
mutex_lock_safe(&c->lock, "cond_tget: lock channel");
if ((e = c->head) == NULL) {
if (cond_twait(&c->cond, &c->lock, t) >= 0)
e = c->head;
}
if (e != NULL) {
c->head = e->next;
if (e->next == NULL)
c->tail = NULL;
}
mutex_unlock_safe(&c->lock, "cond_tget: unlock channel");
if (e != NULL) {
val = e->val;
free(e);
return val;
} else
return -1;
}
void
mutex_worker(int i)
{
int j, k, val;
int last_val = -1;
void *t;
static int put_count = 0;
mutex_init(&ring[i], MUTEX_ERRORCHECK);
barrier_wait(&b, i, NTHREAD);
for (j = 0; j < N; j++) {
mutex_lock_safe(&ring[i], "ring-left");
if (NTHREAD > 1)
mutex_lock_safe(&ring[(i+1)%NTHREAD], "ring-right");
mutex_lock_safe(&master_lock, "master_lock");
yield();
mutex_unlock_safe(&master_lock, "master_lock");
if (NTHREAD > 1)
mutex_unlock_safe(&ring[(i+1)%NTHREAD], "ring-right");
mutex_unlock_safe(&ring[i], "ring-left");
}
if (i == 0)
printf("testing condition variables\n");
/* test cond_wait() and cond_signal() */
for (j = 0; j < K; j++) {
val = cond_get(&chan[i]);
cond_put(&chan[(i+1)%NTHREAD], val+1);
fadd(&put_count, 1);
}
if (i == NTHREAD-1) {
if (val == (K*NTHREAD-1) && val == put_count-1)
printf("successful 1st conditional variables test\n");
else
panic("thread=%d last token value=%d expected=%d put_count=%d",
i, val, K*NTHREAD-1, put_count-1);
}
/* test cond_wait(), cond_twait(), cond_broadcast() and cond_signal() */
for (j = 0; j < K; j++) {
/* test cond_twait() and cond_signal() */
val = cond_tget(&chan[i], hrtime() + (sec2ticks()/100));
/* test cond_wait() and cond_broadcast() */
cond_barrier(&cb, i, NTHREAD);
if (val >= 0) {
cond_put(&chan[(i+1)%NTHREAD], val+1);
last_val = val;
fadd(&put_count, 1);
}
}
if (i == (put_count-1)%NTHREAD) {
if (last_val == (put_count-1))
printf("successful 2nd conditional variables test\n");
else
panic("thread=%d last token value=%d expected=%d",
i, last_val, put_count-1);
}
/* test cond_signal_thread */
if (i == 0)
printf("testing cond_signal_thread\n");
mutex_lock_safe(&l, "condition lock");
thread_id[nc++] = get_thread();
if (nc < NTHREAD) {
if (cond_wait(&c, &l) < 0)
panic("cond_wait:");
} else {
/* shuffle the threads table in order to wake threads in a */
/* random order */
for (j = 0; j < NTHREAD-1; j++) {
/* note: NTHREAD > 1 if we execute the loop body */
/* this is why NTHREAD-1 > 0 here */
k = (long)random() % (NTHREAD-1);
t = thread_id[k];
thread_id[k] = thread_id[j];
thread_id[j] = t;
}
/* signal threads */
for (j = 0; j < NTHREAD-1; j++) {
if (cond_signal_thread(&c, thread_id[j]) < 0)
panic("cond_signal_thread(%p, %p) failed:",
&c, thread_id[j]);
}
}
mutex_unlock_safe(&l, "condition lock");
if (i == 0) {
printf("test cond_signal_thread ended successfully\n");
printf("starting cyclic buffer test\n");
barrier_wait(&b, i, NTHREAD);
if (cq_dequeue(&cq, cq_buf, 0) != NULL)
panic("cq_dequeue of an empty queue did not fail");
for (j = 1; j < NTHREAD; j++) {
if (cq_enqueue(&cq, cq_buf, (void *)j) < 0)
panic("cq_enqueue master iter %d failed:", j);
}
barrier_wait(&b, i, NTHREAD);
for (j = 1; j < NTHREAD; j++) {
usleep(SEC2USEC/10);
if (cq_enqueue(&cq, cq_buf, (void *)j) < 0)
panic("cq_enqueue master iter %d failed:", j);
}
barrier_wait(&b, i, NTHREAD);
printf("cyclic buffer test ended successfully\n");
} else {
barrier_wait(&b, i, NTHREAD);
if (cq_dequeue(&cq, cq_buf, 1) == NULL)
panic("cq_dequeue of thread %d failed:", i);
barrier_wait(&b, i, NTHREAD);
if (cq_dequeue(&cq, cq_buf, 1) == NULL)
panic("cq_dequeue of thread %d failed:", i);
barrier_wait(&b, i, NTHREAD);
}
if (i == 0)
printf("master thread waiting for mutex children completion\n");
barrier_wait(&b, i, NTHREAD);
}
void
test_mutex(void)
{
int i, code;
Time start, elapsed;
Lock lock;
char msg[NAMELEN];
printf("testing mutex_lock and mutex_unlock\n");
mutex_init(&lock, 0);
start = hrtime();
for (i = 0; i < N10; i++) {
if (mutex_lock(&lock) < 0)
panic("mutex_lock:");
if (mutex_unlock(&lock) < 0)
panic("mutex_unlock:");
}
elapsed = 2*(hrtime() - start) - (N10*loop_overhead)/N;
printf("elapsed cycles of %d mutex_lock/mutex_unlock pairs is %d\n", i,
(int)elapsed);
printf("each mutex_lock/unlock pair: %d cycles\n",
(int)(elapsed+N10/2)/N10);
printf("testing mutex_lock and mutex_unlock with error checking\n");
mutex_init(&lock, MUTEX_ERRORCHECK);
start = hrtime();
for (i = 0; i < N10; i++) {
if (mutex_lock(&lock) < 0)
panic("mutex_lock:");
if (mutex_unlock(&lock) < 0)
panic("mutex_unlock:");
}
elapsed = 2*(hrtime() - start) - (N10*loop_overhead)/N;
printf("elapsed cycles of %d mutex_lock/mutex_unlock pairs is %d\n", i,
(int)elapsed);
printf("each mutex_lock/unlock with error checking pair: %d cycles\n\n",
(int)(elapsed+N10/2)/N10);
mutex_init(&master_lock, MUTEX_ERRORCHECK);
mutex_init(&l, MUTEX_ERRORCHECK);
cond_init(&c);
if (barrier_init(&b) < 0)
panic("barrier_init:");
for (i = 0; i < NTHREAD; i++)
chan_init(&chan[i]);
cond_put(&chan[0], 0);
cond_barrier_init(&cb);
if (cq_init(&cq, cq_buf, NTHREAD) < 0)
panic("cq_init failed:");
mutex_lock(&l);
if (cond_signal_thread(&c, (void *)0xdeadbeef) >= 0)
panic("cond_signal_thread(%p, 0xdeadbeef) did not fail as expected", &c);
mutex_unlock(&l);
get_error(msg);
printf("expected error message from cond_signal_thread(%p, 0): %s\n",
&c, msg);
for (i = 1; i < NTHREAD; i++) {
code = fork();
if (code == 0) {
printf("mutex thread %d (%p) started\n",
i, get_thread());
mutex_worker(i);
/* child threads wait forever here */
barrier_wait(&b, i, NTHREAD);
/* end of child thread */
}
/* parent thread */
if (code < 0)
panic("fork:");
}
/* parent thread */
printf("parent thread %p starting concurrent mutex test\n",
get_thread());
mutex_worker(0);
printf("mutex, condition variables & cyclic buffer tests ended successfully\n\n");
/* parent continues, child threads wait forever */
}
static int count[NSIG+1];
void
handler(int signo)
{
if (signo <= 0 || signo > NSIG)
panic("invalid signal number in signal handler: %d", signo);
count[signo]++;
}
void
signal_all(void)
{
int signo, i;
for (signo = 1; signo <= NSIG; signo++)
for (i = signo; i <= NSIG; i++) {
if (kill(get_asid(), i) < 0)
panic("kill(%d, %d) failed:", get_asid(), i);
/* allow the signals handler thread to run */
yield();
}
}
void
send_signals(Time delay)
{
int code;
int s;
if (delay == 0) {
signal_all();
} else {
s = sem_create(0);
if (s < 0)
panic("send_signals: sem_create() failed:");
code = fork();
if (code < 0)
panic("send_signals: fork() failed:");
if (code == 0) {
/* the child */
usleep(delay);
signal_all();
/* wait forever */
sem_wait(s);
}
}
}
void
verify(int x[], int pos1, int val1, int pos2, int val2, int n)
{
int i;
for (i = 0; i < n; i++) {
if (i == pos1) {
if (x[i] != val1)
panic("verify failed: x[%d]=%d; expected %d",
i, x[i], val1);
} else if (i == pos2) {
if (x[i] != val2)
panic("verify failed: x[%d]=%d; expected %d",
i, x[i], val2);
} else {
/* all other elements must be zero */
if (x[i] != 0)
panic("verify failed: x[%d]=%d; expected 0",
i, x[i]);
}
}
}
void
test_signal(void)
{
sigset_t set, block;
Time start, elapsed;
char msg[NAMELEN];
printf("starting signals test\n");
if (sigpending(&set) < 0)
panic("sigpending failed:");
if (set != 0)
panic("pending signals mask not zero: %08x", set);
printf("send signals when all are ignored\n");
memset(count, 0, sizeof(count));
/* send signals intially; expect all to fail since domain is not */
/* initialized */
if (kill(get_asid(), SIG1) >= 0)
panic("kill(%d, %d) did not fail as expected",
get_asid(), SIG1);
get_error(msg);
printf("expected error message=%s\n", msg);
if (sigpending(&set) < 0)
panic("sigpending failed:");
if (set != 0)
panic("pending signals mask not zero: %08x", set);
verify(count, 0, 0, 0, 0, NSIG+1);
printf("ignored signals completed correctly\n");
/* define two signal handlers */
printf("send signals when two are defined\n");
if ((int)signal(SIG1, handler) == -1)
panic("signal(%d, handler) failed:", SIG1);
if ((int)signal(SIG2, handler) == -1)
panic("signal(%d, handler) failed:", SIG2);
memset(count, 0, sizeof(count));
send_signals(0);
usleep(SEC2USEC/10);
if (sigpending(&set) < 0)
panic("sigpending failed:");
if (set != 0)
panic("pending signals mask not zero: %08x", set);
verify(count, SIG1, SIG1, SIG2, SIG2, NSIG+1);
printf("deliver two signals completed correctly\n");
/* block two signals and see what happens */
sigemptyset(&block);
sigaddset(&block, SIG1);
sigaddset(&block, SIG2);
if (sigprocmask(SIG_BLOCK, &block, NULL) < 0)
panic("sigprocmask failed:");
memset(count, 0, sizeof(count));
send_signals(0);
usleep(SEC2USEC/10);
if (sigpending(&set) < 0)
panic("sigpending failed:");
if (set != block)
panic("invalid mask of pending signals: %08x expected=%08x",
set, block);
printf("pending signals when blocked=%08x\n", set);
verify(count, 0, 0, 0, 0, NSIG+1);
/* enable signals */
if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0)
panic("sigprocmask failed:");
usleep(SEC2USEC/10);
if (sigpending(&set) < 0)
panic("sigpending failed:");
if (set != 0)
panic("pending signals mask not zero: %08x", set);
verify(count, SIG1, 1, SIG2, 1, NSIG+1);
printf("deliver two signals after blocking completed correctly\n");
/* redefine the signals and retest */
printf("redefine the signals\n");
if ((int)signal(SIG1, SIG_DFL) == -1)
panic("signal(%d, SIG_DFL) failed:", SIG1);
if ((int)signal(SIG2, SIG_IGN) == -1)
panic("signal(%d, SIG_IGN) failed:", SIG2);
if ((int)signal(SIG3, handler) == -1)
panic("signal(%d, handler) failed:", SIG3);
if ((int)signal(SIG4, handler) == -1)
panic("signal(%d, handler) failed:", SIG4);
memset(count, 0, sizeof(count));
send_signals(0);
usleep(SEC2USEC/10);
if (sigpending(&set) < 0)
panic("sigpending failed:");
if (set != 0)
panic("pending signals mask not zero: %08x", set);
verify(count, SIG3, SIG3, SIG4, SIG4, NSIG+1);
printf("deliver two new signals completed correctly\n");
/* check sigsuspend */
printf("testing sigsuspend\n");
/* block two signals and see what happens */
sigemptyset(&block);
sigaddset(&block, SIG3);
sigaddset(&block, SIG4);
if (sigprocmask(SIG_BLOCK, &block, NULL) < 0)
panic("sigprocmask failed:");
memset(count, 0, sizeof(count));
send_signals(0);
usleep(SEC2USEC/10);
if (sigpending(&set) < 0)
panic("sigpending failed:");
if (set != block)
panic("invalid mask of pending signals: %08x expected=%08x",
set, block);
/* enable signals */
printf("suspend main thread until signals are delivered\n");
sigemptyset(&block);
if (sigsuspend(&block) < 0)
panic("sigsuspend failed:");
/* note: only one of the signals is delivered, since the mask */
/* is reset immediately */
if (count[SIG3] == 0 && count[SIG4] == 0)
panic("signals not called by sigsuspend");
/* deliver all pending signals */
sigemptyset(&block);
if (sigprocmask(SIG_SETMASK, &block, NULL) < 0)
panic("sigprocmask failed:");
usleep(SEC2USEC/10);
printf("sigsuspend works correctly\n");
/* try again, now with delayed signals */
/* block two signals */
sigemptyset(&block);
sigaddset(&block, SIG3);
sigaddset(&block, SIG4);
if (sigprocmask(SIG_BLOCK, &block, NULL) < 0)
panic("sigprocmask failed:");
printf("testing sigsuspend with delayed signals\n");
memset(count, 0, sizeof(count));
start = uptime();
send_signals(SEC2USEC);
printf("suspend main thread until signals are delivered\n");
sigemptyset(&block);
if (sigsuspend(&block) < 0)
panic("sigsuspend failed:");
elapsed = uptime() - start;
/* note: only one of the signals is delivered, since the mask */
/* is reset immediately */
if (count[SIG3] == 0 && count[SIG4] == 0)
panic("signals not called by sigsuspend");
if (elapsed < SEC2USEC || elapsed > (11*SEC2USEC)/10)
panic("sigsuspend is too fast or too slow. elapsed=%d (usec.)",
(int)elapsed);
printf("sigsuspend elapsed time=%d (usec.) as expected\n",
(int)elapsed);
printf("sigsuspend test ended correctly\n");
printf("signals test ended successfully\n\n");
}
void
test_shm(void)
{
int try_id, peek_id, window_peek_id;
int sz;
int val = 0;
int *addr, *p;
int s1, s2, code;
printf("starting shared memory segment test\n");
if ((peek_id = portal_open("fs_peek", 1)) < 0)
panic("portal_open(fs_peek):");
if ((window_peek_id = portal_open("fs_window_peek", 1)) < 0)
panic("portal_open(fs_window_peek):");
if ((try_id = portal_open("fs_try", 1)) < 0)
panic("portal_open(fs_try):");
if ((addr = (int *)shm_open("shared")) == (int *)-1)
panic("shm_open(\"shared\"):");
if ((sz = shm_size(addr)) < 0)
panic("shm_size:");
printf("shared memory region start addr=%p size=%d\n", addr, sz);
set_mem(addr, sz);
printf("before clean_cache of %d bytes\n", sz);
clean_cache(addr, sz);
check_mem(addr, (int)addr, sz);
printf("check memory using fs_peek\n");
for (p = addr; p < (int *)((ulong)addr + sz); p++) {
if ((val = call_portal(peek_id, p)) == ~((int)p))
continue;
printf(
"invalid shared memory contents: addr=%p value=%08x should be=%08x\n",
p, val, ~((int)p));
task_exit(1);
}
printf("check memory using fs_window_peek\n");
for (p = addr; p < (int *)((ulong)addr + sz); p++) {
if ((val = call_portal(window_peek_id, p)) == ~((int)p))
continue;
printf(
"invalid shared memory contents: addr=%p value=%08x should be=%08x\n",
p, val, ~((int)p));
task_exit(1);
}
printf("correct shared memory contents from both domains\n");
printf("testing mutual exclusion locks in shared region\n");
mutex_init((Lock *)addr, MUTEX_ERRORCHECK);
if (mutex_trylock((Lock *)addr) < 0) {
printf("mutex_trylock failed; expected to succeed\n");
task_exit(1);
}
if (mutex_trylock((Lock *)addr) >= 0) {
printf("mutex_trylock succeeded; expected to fail\n");
task_exit(1);
}
if (call_portal(try_id, addr) >= 0) {
printf("fs trylock succeeded; expected to fail\n");
task_exit(1);
}
mutex_unlock((Lock *)addr);
if (call_portal(try_id, addr) < 0) {
printf("fs trylock failed; expected to succceed\n");
task_exit(1);
}
if (call_portal(try_id, addr) >= 0) {
printf("fs trylock succeeded; expected to fail\n");
task_exit(1);
}
if (mutex_trylock((Lock *)addr) >= 0) {
printf("mutex_trylock succeeded; expected to fail\n");
task_exit(1);
}
printf("check access to shared memory region in a child domain\n");
if ((s1 = sem_create(0)) < 0)
panic("sem_create:");
if ((s2 = sem_create(0)) < 0)
panic("sem_create:");
set_mem(addr, sz);
if ((code = domain_fork(NULL)) < 0)
panic("domain_fork:");
if (code == 0) {
/* child */
check_mem(addr, (int)addr, sz);
printf("child domain accessed shared region successfully\n");
/* wakeup parent */
sem_post(s1);
/* sleep forever */
sem_wait(s2);
}
sem_wait(s1);
printf("shared memory test ended successfully\n\n");
}
void
test_sem(void)
{
int s;
int s1, s2, i, j;
Time start, elapsed;
printf("testing semaphores\n");
if ((s = sem_open("fs_sem")) < 0)
panic("sem_open(fs_sem):");
sem_wait(s);
s1 = sem_create(0);
s2 = sem_create(0);
if (s1 < 0 || s2 < 0)
panic("sem_create:");
printf("created semaphores: s1=%d s2=%d\n", s1, s2);
printf("sem_post(%d) returns %d\n", s1, sem_post(s1));
printf("sem_wait(%d) returns %d\n", s1, sem_wait(s1));
start = hrtime();
sem_twait(s1, start + sec2ticks());
elapsed = hrtime() - start;
printf("sem_twait() for 1 second waited %u clock ticks; expected %u clock ticks\n",
(int)elapsed, (int)sec2ticks());
if (elapsed > (5*sec2ticks())/4)
panic("sem_twait() waited significantly more than one second");
start = hrtime();
sem_post(s1);
sem_twait(s1, start + sec2ticks());
elapsed = hrtime() - start;
printf("sem_twait() on an available semaphore waited %u clock ticks\n",
(int)elapsed);
if (elapsed > sec2ticks()/1000)
panic("sem_twait() on an available semphore took too long");
start = hrtime();
for (i = 0; i < N; i++) {
sem_post(s2);
sem_wait(s2);
}
elapsed = 2*(hrtime() - start) - loop_overhead;
printf("elapsed cycles of %d sem_wait/sem_post pairs is %d\n", i,
(int)elapsed);
printf("each sem_wait/sem_post pair: %d cycles\n\n",
(int)(elapsed+N/2)/N);
printf("before fork: parent status=%08lx stack at %p\n",
get_psw(), &j);
if (fork() == 0) {
printf("after fork: child status=%08lx stack at %p\n",
get_psw(), &j);
printf("the child asid=%d calling rpc1\n", get_asid());
printf("portal(%d,3)=%d\n", rpc1, call_portal(rpc1, 3));
do {
printf("shared_flag=%d\n", shared_flag);
yield();
} while(shared_flag == 0);
printf("child: shared_flag=%d\n", shared_flag);
/* semaphore ping-pong with parent */
printf("child before semaphore ping-pong\n");
for (i = 0; i < N; i++) {
sem_post(s1);
sem_wait(s2);
}
/* child waits forever */
sem_wait(s2);
}
printf("after fork: parent status=%08lx stack at %p\n",
get_psw(), &j);
yield();
shared_flag = 1;
yield();
printf("parent before semaphore ping-pong\n");
start = hrtime();
for (i = 0; i < N; i++) {
sem_wait(s1);
sem_post(s2);
}
elapsed = 2*(hrtime() - start) - loop_overhead;
printf("elapsed cycles of %d sem_wait/sem_post with child is %d\n", i,
(int)elapsed);
printf("each sem_wait/sem_post with child: %d cycles\n",
(int)(elapsed+N/2)/N);
printf("semaphore test ended successfully\n\n");
}
void
measure_timeout(char *test_name, int keep_event[])
{
Time now, max_delay, start_idle, elapsed_idle, expected_idle;
Time first_event, latest_event;
int i;
Time usec2ticks = sec2ticks() / SEC2USEC;
printf("starting %s test\n", test_name);
/* compute the largest expected delay */
latest_event = when[0];
first_event = when[0];
for (i = 1; i < M; i++) {
if (when[i] < first_event)
first_event = when[i];
if (when[i] > latest_event)
latest_event = when[i];
}
/* generate M timeout events */
start_idle = idle_time();
now = hrtime();
if (first_event < now)
panic("measure_timeout: first event=%u %u now=%u %u\n",
(int)(first_event >> 32), (int)first_event,
(int)(now >> 32), (int)now);
usec2ticks = sec2ticks() / SEC2USEC;
/* generate the M timeout events */
for (i = 0; i < M; i++) {
timeout_flag[i] = 0;
if (timeout(tout, (void*)i, when[i]) < 0) {
printf("timeout(%d) failed\n", i);
task_exit(1);
}
/* allow timeout thread to run after generating each timeout event */
usleep((first_event - now) / ((M+1)*usec2ticks));
}
/* cancel the requested events */
for (i = 0; i < M; i++) {
if (keep_event[i])
continue;
if (untimeout(tout, (void*)i, when[i]) < 0) {
printf("untimeout(%d) failed\n", i);
task_exit(1);
}
}
/* wait until all timeout events have occured */
hrsleep(latest_event + sec2ticks());
expected_idle = (latest_event + sec2ticks()) - now;
/* verify that the timeouts have occured on time */
elapsed_idle = idle_time() - start_idle;
max_delay = 0;
for (i = 0; i < M; i++) {
printf("timeout event %d @ %u %u \n",
i, (int)(when[i] >> 32), (int)when[i]);
if (timeout_flag[i])
printf("called with delay of %u ticks\n",
(int)timeout_delay[i]);
else
printf("not called\n");
if (timeout_flag[i] != keep_event[i]) {
printf("timeout_flag[%d] is %d. should be %d\n",
i, timeout_flag[i], keep_event[i]);
task_exit(1);
}
if (timeout_delay[i] > max_delay)
max_delay = timeout_delay[i];
}
printf("idle time during %s test: %u %u ticks; expected %u %u ticks\n",
test_name,
(int)(elapsed_idle >> 32), (int)elapsed_idle,
(int)(expected_idle >> 32), (int)expected_idle);
printf("maximal timeout delay during %s test: %u %u ticks\n",
test_name, (int)(max_delay >> 32), (int)max_delay);
if (max_delay > sec2ticks()/1000)
panic("*** %s test failed ***\n\n", test_name);
else
printf("%s test passed successfully\n\n", test_name);
}
void
test_timeout(void)
{
Time now;
int i;
Time s2ticks = sec2ticks();
int keep_event[M];
/* increasing timeout test */
now = hrtime();
for (i = 0; i < M; i++) {
when[i] = now + s2ticks + (s2ticks * i) / M;
keep_event[i] = 1;
}
measure_timeout("increasing timeout", keep_event);
/* decreasing timeout test */
now = hrtime();
for (i = 0; i < M; i++) {
when[i] = now + 2*s2ticks - (s2ticks * i) / M;
keep_event[i] = 1;
}
measure_timeout("decreasing timeout", keep_event);
/* generate M random timeout events, waiting between a second and two */
now = hrtime();
random(); /* get the first random number */
/* none of the timeout events has occurred yet, since they all */
/* start at least one second after "now" */
/* cancel every second timeout event */
for (i = 0; i < M; i++) {
when[i] = now + s2ticks + ((Time)random() % s2ticks);
keep_event[i] = i & 01;
}
measure_timeout("random timeout with event deletions", keep_event);
}
void
printenv(const char *name)
{
char val[NAMELEN];
if (get_env(name, val) < 0)
printf("environment variable %s not defined\n", name);
else
printf("environment variable %s = %s\n", name, val);
}
int
main(int arg, char *argv[])
{
int i, code;
int fd;
int last_time;
volatile int *q, *u;
Time start, elapsed;
Time start_usec, elapsed_usec;
char msg[NAMELEN];
printf("hello, world! arg=%d\n", arg);
printf("hr_count=%d psw=%08lx asid=%d\n",
(int)hrtime(), get_psw(), get_asid());
if ((code = get_caller_asid(0)) != get_asid())
panic("get_caller_asid(0) returned %d; expected %d :",
code, get_asid());
printf("initial TLB miss count=%d general exceptions count=%d\n",
get_tlb_excpt_count(), get_gen_excpt_count());
test_mod(1622650073);
test_idle();
printenv("hostname");
printenv("netaddr");
printenv("netmask");
printf("initial error msg=%s\n", msg);
printf("fd_open(\"?\")=%d\n", fd_open("?"));
get_error(msg);
printf("error msg=%s\n", msg);
printf("calling portal(0)\n");
code = call_portal(0);
if (code >= 0)
panic("call_portal(0) did not fail!");
get_error(msg);
printf("code=%d error msg=%s\n", code, msg);
printf("calling portal(-1)\n");
code = call_portal(-1);
if (code >= 0)
panic("call_portal(-1) did not fail!");
get_error(msg);
printf("code=%d error msg=%s\n", code, msg);
printf("calling portal(too large)\n");
code = call_portal(NPORTALS);
if (code >= 0)
panic("call_portal(NPORTALS) did not fail!");
get_error(msg);
printf("code=%d error msg=%s\n", code, msg);
/* The following yield allows the fs thread to run, so that */
/* if the debug messages are enabled, they do not appear AFTER */
/* the input prompt. Before this fix, you may miss the input prompt */
/* due to the lengthy debug messages that appear after it. */
yield();
printf("reading from console, type up to 64 chars\n");
fgets(msg, sizeof(msg), NULL);
printf("read %d chars, \"%s\" from console\n", strlen(msg), msg);
fd = 0;
printf("writing on LED display\n");
if ((fd = fd_open("led")) < 0)
panic("fd_open(led):");
if (write(fd, "d00d", 4) < 0)
panic("write:");
printf("task %d asid=%d defines rpc1 & rpc2\n", arg, get_asid());
if ((rpc1 = portal_create(-1, "smtiii", 0, &f, 0)) < 0)
panic("portal_create(rpc1):");
printf("task asid=%d portal_create(-1,\"smtiii\", 0, %p, 0) returns %d\n",
get_asid(), &f, rpc1);
if ((rpc2 = portal_create(-1, "smtiii", 0, &g, 0)) < 0)
panic("portal_create(rpc2):");
printf("task asid=%d portal_create(-1,\"smtiii\", 0, %p, 0) returns %d\n",
get_asid(), &g, rpc2);
start = hrtime();
for (i = 0; i < N; i++)
yield();
elapsed = 2*(hrtime() - start);
printf("elapsed cycles of %d yields is %d\n", i, (int)elapsed);
printf("each yield: %d cycles\n", (int)(elapsed+N/2)/N);
start = hrtime();
for (i = 0; i < N; i++)
;
loop_overhead = 2*(hrtime() - start);
printf("empty loop overhead %d iterations=%d cycles. should be %d\n",
i, (int)loop_overhead, i*3);
set_error(NULL);
printf("phys(NULL)=%p\n", virt2phys(NULL));
get_error(msg);
printf("expected error message=%s\n", msg);
set_error(NULL);
printf("&shared_flag=%p phys=%p\n",
&shared_flag, virt2phys(&shared_flag));
get_error(msg);
if (strlen(msg) != 0) {
printf("virt2phys(data address) failed. message=%s\n", msg);
task_exit(1);
}
set_error(NULL);
printf("&f=%p phys=%p\n",
&f, virt2phys(&f));
get_error(msg);
printf("expected error message=%s\n\n", msg);
printf("testing uncached access\n");
q = &shared_flag;
if ((u = (int *)uncached_window((void *)q)) == (int *)-1)
panic("uncached_window:");
printf("virt addr=%p phys addr=%p uncached addr=%p\n",
q, virt2phys((void *)q), u);
if (uncached_window((void *)q) != (void *)-1)
panic("second uncached_window did not fail");
get_error(msg);
printf("expected error from uncached_window: %s\n", msg);
*u = 0x12345678;
*q = 0xdeadbeef;
printf("before cache flush: virt mem=%08x uncached mem=%08x\n", *q, *u);
clean_cache((void *)q, sizeof(int));
if (*q != *u) {
printf("after cache flush: virt mem=%08x uncached mem=%08x\n",
*q, *u);
printf("*** uncached memory not equal to virtual memory ***\n");
task_exit(1);
}
printf("after cache flush: virt mem=%08x uncached mem=%08x\n\n",
*q, *u);
test_csd();
test_log();
test_malloc();
test_portal_alloc();
test_portal_window();
test_page_transfer();
last_time = time();
printf("current time() is %d\n", last_time);
while (time() < last_time + 10)
yield();
printf("time() after 10 seconds is %d\n\n", time());
test_mutex();
test_signal();
test_shm();
test_sem();
printf("the parent asid=%d before calling rpc1\n", get_asid());
printf("portal(%d,3)=%d\n",
rpc1, call_portal(rpc1, 3));
printf("task %d asid=%d before calling rpc2\n", arg, get_asid());
printf("portal(%d,4)=%d\n",
rpc2, call_portal(rpc2, 4));
start = hrtime();
for (i = 0; i < N; i++)
hrtime();
elapsed = 2*(hrtime() - start) - loop_overhead;
printf("elapsed time of %d hrtime=%d cycles\n", i, (int)elapsed);
printf("each hrtime: %d cycles\n", (int)(elapsed+N/2)/N);
printf("hrcount per second=%d\n", sec2ticks());
start = hrtime();
for (i = 0; i < N; i++)
uptime();
elapsed = 2*(hrtime() - start) - loop_overhead;
printf("elapsed time of %d uptime()=%d cycles\n", i, (int)elapsed);
printf("each uptime: %d cycles\n", (int)(elapsed+N/2)/N);
start_usec = uptime();
for (i = 0; i < N; i++)
uptime();
elapsed_usec = uptime() - start_usec;
printf("elapsed time of %d uptime()=%d usec.\n", i, (int)elapsed_usec);
printf("each uptime: %d usec.\n", (int)((elapsed_usec+N/2)/N));
for (i = 0; i < N; i++)
if (call_portal(rpc2, i) != -i)
printf("error in rpc2(%d)\n", i);
start = hrtime();
for (i = 0; i < N; i++)
call_portal(rpc2, i);
elapsed = 2*(hrtime() - start) - loop_overhead;
printf("elapsed time of %d rpc2=%d cycles\n", i, (int)elapsed);
printf("each RPC: %d cycles\n\n", (int)(elapsed+N/2)/N);
test_timeout();
printf("APP1 ENDING\n");
printf("parent domain asid=%d calling task exit\n", get_asid());
task_exit(0);
return(1);
}