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

#include "runtime.h"
#include "arch.h"

#line 24 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
typedef struct SemaWaiter SemaWaiter; 
struct SemaWaiter 
{ 
uint32 volatile* addr; 
G* g; 
int64 releasetime; 
int32 nrelease; 
SemaWaiter* prev; 
SemaWaiter* next; 
} ; 
#line 35 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
typedef struct SemaRoot SemaRoot; 
struct SemaRoot 
{ 
Lock; 
SemaWaiter* head; 
SemaWaiter* tail; 
#line 42 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
uint32 volatile nwait; 
} ; 
#line 46 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
#define SEMTABLESZ 251 
#line 48 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
struct semtable 
{ 
SemaRoot; 
uint8 pad[CacheLineSize-sizeof ( SemaRoot ) ]; 
} ; 
static struct semtable semtable[SEMTABLESZ]; 
#line 55 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
static SemaRoot* 
semroot ( uint32 volatile *addr ) 
{ 
return &semtable[ ( ( uintptr ) addr >> 3 ) % SEMTABLESZ]; 
} 
#line 61 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
static void 
semqueue ( SemaRoot *root , uint32 volatile *addr , SemaWaiter *s ) 
{ 
s->g = runtime_g ( ) ; 
s->addr = addr; 
s->next = nil; 
s->prev = root->tail; 
if ( root->tail ) 
root->tail->next = s; 
else 
root->head = s; 
root->tail = s; 
} 
#line 75 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
static void 
semdequeue ( SemaRoot *root , SemaWaiter *s ) 
{ 
if ( s->next ) 
s->next->prev = s->prev; 
else 
root->tail = s->prev; 
if ( s->prev ) 
s->prev->next = s->next; 
else 
root->head = s->next; 
s->prev = nil; 
s->next = nil; 
} 
#line 90 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
static int32 
cansemacquire ( uint32 volatile *addr ) 
{ 
uint32 v; 
#line 95 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
while ( ( v = runtime_atomicload ( addr ) ) > 0 ) 
if ( runtime_cas ( addr , v , v-1 ) ) 
return 1; 
return 0; 
} 
#line 101 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
void 
runtime_semacquire ( uint32 volatile *addr , bool profile ) 
{ 
SemaWaiter s; 
SemaRoot *root; 
int64 t0; 
#line 109 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
if ( cansemacquire ( addr ) ) 
return; 
#line 118 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
root = semroot ( addr ) ; 
t0 = 0; 
s.releasetime = 0; 
if ( profile && runtime_blockprofilerate > 0 ) { 
t0 = runtime_cputicks ( ) ; 
s.releasetime = -1; 
} 
for ( ;; ) { 
#line 127 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
runtime_lock ( root ) ; 
#line 129 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
runtime_xadd ( &root->nwait , 1 ) ; 
#line 131 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
if ( cansemacquire ( addr ) ) { 
runtime_xadd ( &root->nwait , -1 ) ; 
runtime_unlock ( root ) ; 
return; 
} 
#line 138 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
semqueue ( root , addr , &s ) ; 
runtime_parkunlock ( root , "semacquire" ) ; 
if ( cansemacquire ( addr ) ) { 
if ( t0 ) 
runtime_blockevent ( s.releasetime - t0 , 3 ) ; 
return; 
} 
} 
} 
#line 148 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
void 
runtime_semrelease ( uint32 volatile *addr ) 
{ 
SemaWaiter *s; 
SemaRoot *root; 
#line 154 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
root = semroot ( addr ) ; 
runtime_xadd ( addr , 1 ) ; 
#line 160 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
if ( runtime_atomicload ( &root->nwait ) == 0 ) 
return; 
#line 164 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
runtime_lock ( root ) ; 
if ( runtime_atomicload ( &root->nwait ) == 0 ) { 
#line 168 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
runtime_unlock ( root ) ; 
return; 
} 
for ( s = root->head; s; s = s->next ) { 
if ( s->addr == addr ) { 
runtime_xadd ( &root->nwait , -1 ) ; 
semdequeue ( root , s ) ; 
break; 
} 
} 
runtime_unlock ( root ) ; 
if ( s ) { 
if ( s->releasetime ) 
s->releasetime = runtime_cputicks ( ) ; 
runtime_ready ( s->g ) ; 
} 
} 
#line 187 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
void net_runtime_Semacquire ( uint32 *addr ) 
__asm__ ( GOSYM_PREFIX "net.runtime_Semacquire" ) ; 
#line 190 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
void net_runtime_Semacquire ( uint32 *addr ) 
{ 
runtime_semacquire ( addr , true ) ; 
} 
#line 195 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
void net_runtime_Semrelease ( uint32 *addr ) 
__asm__ ( GOSYM_PREFIX "net.runtime_Semrelease" ) ; 
#line 198 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
void net_runtime_Semrelease ( uint32 *addr ) 
{ 
runtime_semrelease ( addr ) ; 
} 
void sync_runtime_Semacquire(uint32* addr) __asm__ (GOSYM_PREFIX "sync.runtime_Semacquire");
void sync_runtime_Semacquire(uint32* addr)
{
#line 203 "../../../gcc-5.1.0/libgo/runtime/sema.goc"

	runtime_semacquire(addr, true);
}
void sync_runtime_Semrelease(uint32* addr) __asm__ (GOSYM_PREFIX "sync.runtime_Semrelease");
void sync_runtime_Semrelease(uint32* addr)
{
#line 207 "../../../gcc-5.1.0/libgo/runtime/sema.goc"

	runtime_semrelease(addr);
}

#line 211 "../../../gcc-5.1.0/libgo/runtime/sema.goc"
typedef struct SyncSema SyncSema; 
struct SyncSema 
{ 
Lock; 
SemaWaiter* head; 
SemaWaiter* tail; 
} ; 
void sync_runtime_Syncsemcheck(uintptr size) __asm__ (GOSYM_PREFIX "sync.runtime_Syncsemcheck");
void sync_runtime_Syncsemcheck(uintptr size)
{
#line 219 "../../../gcc-5.1.0/libgo/runtime/sema.goc"

	if(size != sizeof(SyncSema)) {
		runtime_printf("bad SyncSema size: sync:%D runtime:%D\n", (int64)size, (int64)sizeof(SyncSema));
		runtime_throw("bad SyncSema size");
	}
}
void sync_runtime_Syncsemacquire(SyncSema* s) __asm__ (GOSYM_PREFIX "sync.runtime_Syncsemacquire");
void sync_runtime_Syncsemacquire(SyncSema* s)
{
#line 227 "../../../gcc-5.1.0/libgo/runtime/sema.goc"

	SemaWaiter w, *wake;
	int64 t0;

	w.g = runtime_g();
	w.nrelease = -1;
	w.next = nil;
	w.releasetime = 0;
	t0 = 0;
	if(runtime_blockprofilerate > 0) {
		t0 = runtime_cputicks();
		w.releasetime = -1;
	}

	runtime_lock(s);
	if(s->head && s->head->nrelease > 0) {
		// have pending release, consume it
		wake = nil;
		s->head->nrelease--;
		if(s->head->nrelease == 0) {
			wake = s->head;
			s->head = wake->next;
			if(s->head == nil)
				s->tail = nil;
		}
		runtime_unlock(s);
		if(wake)
			runtime_ready(wake->g);
	} else {
		// enqueue itself
		if(s->tail == nil)
			s->head = &w;
		else
			s->tail->next = &w;
		s->tail = &w;
		runtime_parkunlock(s, "semacquire");
		if(t0)
			runtime_blockevent(w.releasetime - t0, 2);
	}
}
void sync_runtime_Syncsemrelease(SyncSema* s, uint32 n) __asm__ (GOSYM_PREFIX "sync.runtime_Syncsemrelease");
void sync_runtime_Syncsemrelease(SyncSema* s, uint32 n)
{
#line 269 "../../../gcc-5.1.0/libgo/runtime/sema.goc"

	SemaWaiter w, *wake;

	w.g = runtime_g();
	w.nrelease = (int32)n;
	w.next = nil;
	w.releasetime = 0;

	runtime_lock(s);
	while(w.nrelease > 0 && s->head && s->head->nrelease < 0) {
		// have pending acquire, satisfy it
		wake = s->head;
		s->head = wake->next;
		if(s->head == nil)
			s->tail = nil;
		if(wake->releasetime)
			wake->releasetime = runtime_cputicks();
		runtime_ready(wake->g);
		w.nrelease--;
	}
	if(w.nrelease > 0) {
		// enqueue itself
		if(s->tail == nil)
			s->head = &w;
		else
			s->tail->next = &w;
		s->tail = &w;
		runtime_parkunlock(s, "semarelease");
	} else
		runtime_unlock(s);
}
