// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build linux

package runtime

import (
	
	
)

func epollcreate( int32) int32
func epollcreate1( int32) int32

//go:noescape
func epollctl(, ,  int32,  *epollevent) int32

//go:noescape
func epollwait( int32,  *epollevent, ,  int32) int32
func closeonexec( int32)

var (
	epfd int32 = -1 // epoll descriptor

	netpollBreakRd, netpollBreakWr uintptr // for netpollBreak

	netpollWakeSig uint32 // used to avoid duplicate calls of netpollBreak
)

func netpollinit() {
	epfd = epollcreate1(_EPOLL_CLOEXEC)
	if epfd < 0 {
		epfd = epollcreate(1024)
		if epfd < 0 {
			println("runtime: epollcreate failed with", -epfd)
			throw("runtime: netpollinit failed")
		}
		closeonexec(epfd)
	}
	, ,  := nonblockingPipe()
	if  != 0 {
		println("runtime: pipe failed with", -)
		throw("runtime: pipe failed")
	}
	 := epollevent{
		events: _EPOLLIN,
	}
	*(**uintptr)(unsafe.Pointer(&.data)) = &netpollBreakRd
	 = epollctl(epfd, _EPOLL_CTL_ADD, , &)
	if  != 0 {
		println("runtime: epollctl failed with", -)
		throw("runtime: epollctl failed")
	}
	netpollBreakRd = uintptr()
	netpollBreakWr = uintptr()
}

func netpollIsPollDescriptor( uintptr) bool {
	return  == uintptr(epfd) ||  == netpollBreakRd ||  == netpollBreakWr
}

func netpollopen( uintptr,  *pollDesc) int32 {
	var  epollevent
	.events = _EPOLLIN | _EPOLLOUT | _EPOLLRDHUP | _EPOLLET
	*(**pollDesc)(unsafe.Pointer(&.data)) = 
	return -epollctl(epfd, _EPOLL_CTL_ADD, int32(), &)
}

func netpollclose( uintptr) int32 {
	var  epollevent
	return -epollctl(epfd, _EPOLL_CTL_DEL, int32(), &)
}

func netpollarm( *pollDesc,  int) {
	throw("runtime: unused")
}

// netpollBreak interrupts an epollwait.
func netpollBreak() {
	if atomic.Cas(&netpollWakeSig, 0, 1) {
		for {
			var  byte
			 := write(netpollBreakWr, unsafe.Pointer(&), 1)
			if  == 1 {
				break
			}
			if  == -_EINTR {
				continue
			}
			if  == -_EAGAIN {
				return
			}
			println("runtime: netpollBreak write failed with", -)
			throw("runtime: netpollBreak write failed")
		}
	}
}

// netpoll checks for ready network connections.
// Returns list of goroutines that become runnable.
// delay < 0: blocks indefinitely
// delay == 0: does not block, just polls
// delay > 0: block for up to that many nanoseconds
func netpoll( int64) gList {
	if epfd == -1 {
		return gList{}
	}
	var  int32
	if  < 0 {
		 = -1
	} else if  == 0 {
		 = 0
	} else if  < 1e6 {
		 = 1
	} else if  < 1e15 {
		 = int32( / 1e6)
	} else {
		// An arbitrary cap on how long to wait for a timer.
		// 1e9 ms == ~11.5 days.
		 = 1e9
	}
	var  [128]epollevent
:
	 := epollwait(epfd, &[0], int32(len()), )
	if  < 0 {
		if  != -_EINTR {
			println("runtime: epollwait on fd", epfd, "failed with", -)
			throw("runtime: netpoll failed")
		}
		// If a timed sleep was interrupted, just return to
		// recalculate how long we should sleep now.
		if  > 0 {
			return gList{}
		}
		goto 
	}
	var  gList
	for  := int32(0);  < ; ++ {
		 := &[]
		if .events == 0 {
			continue
		}

		if *(**uintptr)(unsafe.Pointer(&.data)) == &netpollBreakRd {
			if .events != _EPOLLIN {
				println("runtime: netpoll: break fd ready for", .events)
				throw("runtime: netpoll: break fd ready for something unexpected")
			}
			if  != 0 {
				// netpollBreak could be picked up by a
				// nonblocking poll. Only read the byte
				// if blocking.
				var  [16]byte
				read(int32(netpollBreakRd), noescape(unsafe.Pointer(&[0])), int32(len()))
				atomic.Store(&netpollWakeSig, 0)
			}
			continue
		}

		var  int32
		if .events&(_EPOLLIN|_EPOLLRDHUP|_EPOLLHUP|_EPOLLERR) != 0 {
			 += 'r'
		}
		if .events&(_EPOLLOUT|_EPOLLHUP|_EPOLLERR) != 0 {
			 += 'w'
		}
		if  != 0 {
			 := *(**pollDesc)(unsafe.Pointer(&.data))
			.setEventErr(.events == _EPOLLERR)
			netpollready(&, , )
		}
	}
	return 
}