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); 
}