132 lines · 2.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include "ioproc.h" enum{	STACK = 32768}; voidiointerrupt(Ioproc *io){	if(!io->inuse)		return;	fprint(2, "bug: cannot iointerrupt %p yet\n", io);} static voidxioproc(void *a){	Ioproc *io, *x; 	threadsetname("ioproc");	io = a;	/*	 * first recvp acquires the ioproc.	 * second tells us that the data is ready.	 */	for(;;){		while(recv(io->c, &x) == -1)			;		if(x == 0)	/* our cue to leave */			break;		assert(x == io); 		/* caller is now committed -- even if interrupted he'll return */		while(recv(io->creply, &x) == -1)			;		if(x == 0)	/* caller backed out */			continue;		assert(x == io); 		io->ret = io->op(&io->arg);		if(io->ret < 0)			rerrstr(io->err, sizeof io->err);		while(send(io->creply, &io) == -1)			;		while(recv(io->creply, &x) == -1)			;	}} Ioproc*ioproc(void){	Ioproc *io; 	io = mallocz(sizeof(*io), 1);	if(io == nil)		sysfatal("ioproc malloc: %r");	io->c = chancreate(sizeof(void*), 0);	chansetname(io->c, "ioc%p", io->c);	io->creply = chancreate(sizeof(void*), 0);	chansetname(io->creply, "ior%p", io->c);	io->tid = proccreate(xioproc, io, STACK);	return io;} voidcloseioproc(Ioproc *io){	if(io == nil)		return;	iointerrupt(io);	while(send(io->c, 0) == -1)		;	chanfree(io->c);	chanfree(io->creply);	free(io);} longiocall(Ioproc *io, long (*op)(va_list*), ...){	char e[ERRMAX];	int ret, inted;	Ioproc *msg; 	if(send(io->c, &io) == -1){		werrstr("interrupted");		return -1;	}	assert(!io->inuse);	io->inuse = 1;	io->op = op;	va_start(io->arg, op);	msg = io;	inted = 0;	while(send(io->creply, &msg) == -1){		msg = nil;		inted = 1;	}	if(inted){		werrstr("interrupted");		return -1;	} 	/*	 * If we get interrupted, we have stick around so that	 * the IO proc has someone to talk to.  Send it an interrupt	 * and try again.	 */	inted = 0;	while(recv(io->creply, nil) == -1){		inted = 1;		iointerrupt(io);	}	USED(inted);	va_end(io->arg);	ret = io->ret;	if(ret < 0)		strecpy(e, e+sizeof e, io->err);	io->inuse = 0; 	/* release resources */	while(send(io->creply, &io) == -1)		;	if(ret < 0)		errstr(e, sizeof e);	return ret;}