plan 9 kernel history: overview | file list | diff list

2002/1017/alphapc/random.c (diff list | history)

alphapc/random.c on 2000/0609
2000/0609    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
 
struct Rb 
{ 
	QLock; 
	Rendez	producer; 
	Rendez	consumer; 
	ulong	randomcount; 
	uchar	buf[1024]; 
	uchar	*ep; 
	uchar	*rp; 
	uchar	*wp; 
	uchar	next; 
	uchar	wakeme; 
	ushort	bits; 
	ulong	randn; 
} rb; 
 
static int 
rbnotfull(void*) 
{ 
	int i; 
 
	i = rb.rp - rb.wp; 
	return i != 1 && i != (1 - sizeof(rb.buf)); 
} 
 
static int 
rbnotempty(void*) 
{ 
	return rb.wp != rb.rp; 
} 
 
void 
genrandom(void*) 
{ 
	up->basepri = PriNormal; 
	up->priority = up->basepri; 
 
	for(;;){ 
		for(;;) 
			if(++rb.randomcount > 100000) 
				break; 
		if(anyhigher()) 
			sched(); 
		if(!rbnotfull(0)) 
			sleep(&rb.producer, rbnotfull, 0); 
	} 
} 
 
/* 
 *  produce random bits in a circular buffer 
 */ 
static void 
randomclock(void) 
{ 
	if(rb.randomcount == 0 || !rbnotfull(0)) 
		return; 
 
	rb.bits = (rb.bits<<2) ^ rb.randomcount; 
	rb.randomcount = 0; 
 
	rb.next++; 
	if(rb.next != 8/2) 
		return; 
	rb.next = 0; 
 
	*rb.wp ^= rb.bits; 
	if(rb.wp+1 == rb.ep) 
		rb.wp = rb.buf; 
	else 
		rb.wp = rb.wp+1; 
 
	if(rb.wakeme) 
		wakeup(&rb.consumer); 
} 
 
2000/0618    
void 
2000/0609    
randominit(void) 
{ 
2002/1017    
	addclock0link(randomclock, 1000/HZ); 
2000/0609    
	rb.ep = rb.buf + sizeof(rb.buf); 
	rb.rp = rb.wp = rb.buf; 
	kproc("genrandom", genrandom, 0); 
} 
 
/* 
 *  consume random bytes from a circular buffer 
 */ 
2000/0618    
ulong 
2000/0609    
randomread(void *xp, ulong n) 
{ 
	uchar *e, *p; 
	ulong x; 
 
	p = xp; 
 
	if(waserror()){ 
		qunlock(&rb); 
		nexterror(); 
	} 
 
	qlock(&rb); 
	for(e = p + n; p < e; ){ 
		if(rb.wp == rb.rp){ 
			rb.wakeme = 1; 
			wakeup(&rb.producer); 
			sleep(&rb.consumer, rbnotempty, 0); 
			rb.wakeme = 0; 
			continue; 
		} 
 
		/* 
		 *  beating clocks will be precictable if 
		 *  they are synchronized.  Use a cheap pseudo 
		 *  random number generator to obscure any cycles. 
		 */ 
		x = rb.randn*1103515245 ^ *rb.rp; 
		*p++ = rb.randn = x; 
 
		if(rb.rp+1 == rb.ep) 
			rb.rp = rb.buf; 
		else 
			rb.rp = rb.rp+1; 
	} 
	qunlock(&rb); 
	poperror(); 
 
	wakeup(&rb.producer); 
 
	return n; 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)