// AUTO-GENERATED by autogen.sh; DO NOT EDIT

#include "runtime.h"
#include "defs.h"
#include "arch.h"
#include "malloc.h"
#define type __type_descriptor
#define data __object
#define READY ((G*)1)
#define WAIT  ((G*)2)

#line 42 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
enum 
{ 
PollBlockSize = 4*1024 , 
} ; 
#line 47 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
struct PollDesc 
{ 
PollDesc* link; 
#line 56 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
Lock; 
uintptr fd; 
bool closing; 
uintptr seq; 
G* rg; 
Timer rt; 
int64 rd; 
G* wg; 
Timer wt; 
int64 wd; 
void* user; 
} ; 
#line 69 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static struct 
{ 
Lock; 
PollDesc* first; 
#line 78 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
} pollcache; 
#line 80 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static bool netpollblock ( PollDesc* , int32 , bool ) ; 
static G* netpollunblock ( PollDesc* , int32 , bool ) ; 
static void deadline ( Eface , uintptr ) ; 
static void readDeadline ( Eface , uintptr ) ; 
static void writeDeadline ( Eface , uintptr ) ; 
static PollDesc* allocPollDesc ( void ) ; 
static intgo checkerr ( PollDesc *pd , int32 mode ) ; 
#line 88 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static FuncVal deadlineFn = { ( void ( * ) ( void ) ) deadline } ; 
static FuncVal readDeadlineFn = { ( void ( * ) ( void ) ) readDeadline } ; 
static FuncVal writeDeadlineFn = { ( void ( * ) ( void ) ) writeDeadline } ; 
int64 net_runtimeNano() __asm__ (GOSYM_PREFIX "net.runtimeNano");
int64 net_runtimeNano()
{
  int64 ns;
#line 93 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	ns = runtime_nanotime();
return ns;
}
void net_runtime_pollServerInit() __asm__ (GOSYM_PREFIX "net.runtime_pollServerInit");
void net_runtime_pollServerInit()
{
#line 97 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	runtime_netpollinit();
}
struct net_runtime_pollOpen_ret {
  PollDesc* pd;
  intgo errno;
};
struct net_runtime_pollOpen_ret net_runtime_pollOpen(uintptr fd) __asm__ (GOSYM_PREFIX "net.runtime_pollOpen");
struct net_runtime_pollOpen_ret net_runtime_pollOpen(uintptr fd)
{
  PollDesc* pd;
  intgo errno;
#line 101 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	pd = allocPollDesc();
	runtime_lock(pd);
	if(pd->wg != nil && pd->wg != READY)
		runtime_throw("runtime_pollOpen: blocked write on free descriptor");
	if(pd->rg != nil && pd->rg != READY)
		runtime_throw("runtime_pollOpen: blocked read on free descriptor");
	pd->fd = fd;
	pd->closing = false;
	pd->seq++;
	pd->rg = nil;
	pd->rd = 0;
	pd->wg = nil;
	pd->wd = 0;
	runtime_unlock(pd);

	errno = runtime_netpollopen(fd, pd);
  {
    struct net_runtime_pollOpen_ret __ret;
    __ret.pd = pd;
    __ret.errno = errno;
    return __ret;
  }
}
void net_runtime_pollClose(PollDesc* pd) __asm__ (GOSYM_PREFIX "net.runtime_pollClose");
void net_runtime_pollClose(PollDesc* pd)
{
#line 120 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	if(!pd->closing)
		runtime_throw("runtime_pollClose: close w/o unblock");
	if(pd->wg != nil && pd->wg != READY)
		runtime_throw("runtime_pollClose: blocked write on closing descriptor");
	if(pd->rg != nil && pd->rg != READY)
		runtime_throw("runtime_pollClose: blocked read on closing descriptor");
	runtime_netpollclose(pd->fd);
	runtime_lock(&pollcache);
	pd->link = pollcache.first;
	pollcache.first = pd;
	runtime_unlock(&pollcache);
}
intgo net_runtime_pollReset(PollDesc* pd, intgo mode) __asm__ (GOSYM_PREFIX "net.runtime_pollReset");
intgo net_runtime_pollReset(PollDesc* pd, intgo mode)
{
  intgo err;
#line 134 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	err = checkerr(pd, mode);
	if(err)
		goto ret;
	if(mode == 'r')
		pd->rg = nil;
	else if(mode == 'w')
		pd->wg = nil;
ret:
return err;
}
intgo net_runtime_pollWait(PollDesc* pd, intgo mode) __asm__ (GOSYM_PREFIX "net.runtime_pollWait");
intgo net_runtime_pollWait(PollDesc* pd, intgo mode)
{
  intgo err;
#line 145 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	err = checkerr(pd, mode);
	if(err == 0) {
		// As for now only Solaris uses level-triggered IO.
		if(Solaris)
			runtime_netpollarm(pd, mode);
		while(!netpollblock(pd, mode, false)) {
			err = checkerr(pd, mode);
			if(err != 0)
				break;
			// Can happen if timeout has fired and unblocked us,
			// but before we had a chance to run, timeout has been reset.
			// Pretend it has not happened and retry.
		}
	}
return err;
}
void net_runtime_pollWaitCanceled(PollDesc* pd, intgo mode) __asm__ (GOSYM_PREFIX "net.runtime_pollWaitCanceled");
void net_runtime_pollWaitCanceled(PollDesc* pd, intgo mode)
{
#line 162 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	// This function is used only on windows after a failed attempt to cancel
	// a pending async IO operation. Wait for ioready, ignore closing or timeouts.
	while(!netpollblock(pd, mode, true))
		;
}
void net_runtime_pollSetDeadline(PollDesc* pd, int64 d, intgo mode) __asm__ (GOSYM_PREFIX "net.runtime_pollSetDeadline");
void net_runtime_pollSetDeadline(PollDesc* pd, int64 d, intgo mode)
{
#line 169 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	G *rg, *wg;

	runtime_lock(pd);
	if(pd->closing) {
		runtime_unlock(pd);
		return;
	}
	pd->seq++;  // invalidate current timers
	// Reset current timers.
	if(pd->rt.fv) {
		runtime_deltimer(&pd->rt);
		pd->rt.fv = nil;
	}
	if(pd->wt.fv) {
		runtime_deltimer(&pd->wt);
		pd->wt.fv = nil;
	}
	// Setup new timers.
	if(d != 0 && d <= runtime_nanotime())
		d = -1;
	if(mode == 'r' || mode == 'r'+'w')
		pd->rd = d;
	if(mode == 'w' || mode == 'r'+'w')
		pd->wd = d;
	if(pd->rd > 0 && pd->rd == pd->wd) {
		pd->rt.fv = &deadlineFn;
		pd->rt.when = pd->rd;
		// Copy current seq into the timer arg.
		// Timer func will check the seq against current descriptor seq,
		// if they differ the descriptor was reused or timers were reset.
		pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
		pd->rt.arg.data = pd;
		pd->rt.seq = pd->seq;
		runtime_addtimer(&pd->rt);
	} else {
		if(pd->rd > 0) {
			pd->rt.fv = &readDeadlineFn;
			pd->rt.when = pd->rd;
			pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
			pd->rt.arg.data = pd;
			pd->rt.seq = pd->seq;
			runtime_addtimer(&pd->rt);
		}
		if(pd->wd > 0) {
			pd->wt.fv = &writeDeadlineFn;
			pd->wt.when = pd->wd;
			pd->wt.arg.type = nil; // should be *pollDesc type descriptor.
			pd->wt.arg.data = pd;
			pd->wt.seq = pd->seq;
			runtime_addtimer(&pd->wt);
		}
	}
	// If we set the new deadline in the past, unblock currently pending IO if any.
	rg = nil;
	runtime_atomicstorep(&wg, nil);  // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
	if(pd->rd < 0)
		rg = netpollunblock(pd, 'r', false);
	if(pd->wd < 0)
		wg = netpollunblock(pd, 'w', false);
	runtime_unlock(pd);
	if(rg)
		runtime_ready(rg);
	if(wg)
		runtime_ready(wg);
}
void net_runtime_pollUnblock(PollDesc* pd) __asm__ (GOSYM_PREFIX "net.runtime_pollUnblock");
void net_runtime_pollUnblock(PollDesc* pd)
{
#line 236 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"

	G *rg, *wg;

	runtime_lock(pd);
	if(pd->closing)
		runtime_throw("runtime_pollUnblock: already closing");
	pd->closing = true;
	pd->seq++;
	runtime_atomicstorep(&rg, nil);  // full memory barrier between store to closing and read of rg/wg in netpollunblock
	rg = netpollunblock(pd, 'r', false);
	wg = netpollunblock(pd, 'w', false);
	if(pd->rt.fv) {
		runtime_deltimer(&pd->rt);
		pd->rt.fv = nil;
	}
	if(pd->wt.fv) {
		runtime_deltimer(&pd->wt);
		pd->wt.fv = nil;
	}
	runtime_unlock(pd);
	if(rg)
		runtime_ready(rg);
	if(wg)
		runtime_ready(wg);
}

#line 262 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
uintptr 
runtime_netpollfd ( PollDesc *pd ) 
{ 
return pd->fd; 
} 
#line 268 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
void** 
runtime_netpolluser ( PollDesc *pd ) 
{ 
return &pd->user; 
} 
#line 274 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
bool 
runtime_netpollclosing ( PollDesc *pd ) 
{ 
return pd->closing; 
} 
#line 280 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
void 
runtime_netpolllock ( PollDesc *pd ) 
{ 
runtime_lock ( pd ) ; 
} 
#line 286 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
void 
runtime_netpollunlock ( PollDesc *pd ) 
{ 
runtime_unlock ( pd ) ; 
} 
#line 293 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
void 
runtime_netpollready ( G **gpp , PollDesc *pd , int32 mode ) 
{ 
G *rg , *wg; 
#line 298 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
rg = wg = nil; 
if ( mode == 'r' || mode == 'r' +'w' ) 
rg = netpollunblock ( pd , 'r' , true ) ; 
if ( mode == 'w' || mode == 'r' +'w' ) 
wg = netpollunblock ( pd , 'w' , true ) ; 
if ( rg ) { 
rg->schedlink = *gpp; 
*gpp = rg; 
} 
if ( wg ) { 
wg->schedlink = *gpp; 
*gpp = wg; 
} 
} 
#line 313 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static intgo 
checkerr ( PollDesc *pd , int32 mode ) 
{ 
if ( pd->closing ) 
return 1; 
if ( ( mode == 'r' && pd->rd < 0 ) || ( mode == 'w' && pd->wd < 0 ) ) 
return 2; 
return 0; 
} 
#line 323 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static bool 
blockcommit ( G *gp , G **gpp ) 
{ 
return runtime_casp ( gpp , WAIT , gp ) ; 
} 
#line 331 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static bool 
netpollblock ( PollDesc *pd , int32 mode , bool waitio ) 
{ 
G **gpp , *old; 
#line 336 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
gpp = &pd->rg; 
if ( mode == 'w' ) 
gpp = &pd->wg; 
#line 341 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
for ( ;; ) { 
old = *gpp; 
if ( old == READY ) { 
*gpp = nil; 
return true; 
} 
if ( old != nil ) 
runtime_throw ( "netpollblock: double wait" ) ; 
if ( runtime_casp ( gpp , nil , WAIT ) ) 
break; 
} 
#line 356 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
if ( waitio || checkerr ( pd , mode ) == 0 ) 
runtime_park ( ( bool ( * ) ( G* , void* ) ) blockcommit , gpp , "IO wait" ) ; 
#line 359 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
old = runtime_xchgp ( gpp , nil ) ; 
if ( old > WAIT ) 
runtime_throw ( "netpollblock: corrupted state" ) ; 
return old == READY; 
} 
#line 365 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static G* 
netpollunblock ( PollDesc *pd , int32 mode , bool ioready ) 
{ 
G **gpp , *old , *new; 
#line 370 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
gpp = &pd->rg; 
if ( mode == 'w' ) 
gpp = &pd->wg; 
#line 374 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
for ( ;; ) { 
old = *gpp; 
if ( old == READY ) 
return nil; 
if ( old == nil && !ioready ) { 
#line 381 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
return nil; 
} 
new = nil; 
if ( ioready ) 
new = READY; 
if ( runtime_casp ( gpp , old , new ) ) 
break; 
} 
if ( old > WAIT ) 
return old; 
return nil; 
} 
#line 394 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static void 
deadlineimpl ( Eface arg , uintptr seq , bool read , bool write ) 
{ 
PollDesc *pd; 
G *rg , *wg; 
#line 400 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
pd = ( PollDesc* ) arg.data; 
rg = wg = nil; 
runtime_lock ( pd ) ; 
#line 405 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
if ( seq != pd->seq ) { 
#line 407 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
runtime_unlock ( pd ) ; 
return; 
} 
if ( read ) { 
if ( pd->rd <= 0 || pd->rt.fv == nil ) 
runtime_throw ( "deadlineimpl: inconsistent read deadline" ) ; 
pd->rd = -1; 
runtime_atomicstorep ( &pd->rt.fv , nil ) ; 
rg = netpollunblock ( pd , 'r' , false ) ; 
} 
if ( write ) { 
if ( pd->wd <= 0 || ( pd->wt.fv == nil && !read ) ) 
runtime_throw ( "deadlineimpl: inconsistent write deadline" ) ; 
pd->wd = -1; 
runtime_atomicstorep ( &pd->wt.fv , nil ) ; 
wg = netpollunblock ( pd , 'w' , false ) ; 
} 
runtime_unlock ( pd ) ; 
if ( rg ) 
runtime_ready ( rg ) ; 
if ( wg ) 
runtime_ready ( wg ) ; 
} 
#line 431 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static void 
deadline ( Eface arg , uintptr seq ) 
{ 
deadlineimpl ( arg , seq , true , true ) ; 
} 
#line 437 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static void 
readDeadline ( Eface arg , uintptr seq ) 
{ 
deadlineimpl ( arg , seq , true , false ) ; 
} 
#line 443 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static void 
writeDeadline ( Eface arg , uintptr seq ) 
{ 
deadlineimpl ( arg , seq , false , true ) ; 
} 
#line 449 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
static PollDesc* 
allocPollDesc ( void ) 
{ 
PollDesc *pd; 
uint32 i , n; 
#line 455 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
runtime_lock ( &pollcache ) ; 
if ( pollcache.first == nil ) { 
n = PollBlockSize/sizeof ( *pd ) ; 
if ( n == 0 ) 
n = 1; 
#line 462 "../../../gcc-5.1.0/libgo/runtime/netpoll.goc"
pd = runtime_persistentalloc ( n*sizeof ( *pd ) , 0 , &mstats.other_sys ) ; 
for ( i = 0; i < n; i++ ) { 
pd[i].link = pollcache.first; 
pollcache.first = &pd[i]; 
} 
} 
pd = pollcache.first; 
pollcache.first = pd->link; 
runtime_unlock ( &pollcache ) ; 
return pd; 
} 