// 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 (
	
	
	
)

var (
	epfd int32 = -1 // epoll descriptor

	netpollBreakRd, netpollBreakWr uintptr // for netpollBreak

	netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak
)

func netpollinit() {
	var  uintptr
	epfd,  = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC)
	if  != 0 {
		println("runtime: epollcreate failed with", )
		throw("runtime: netpollinit failed")
	}
	, ,  := nonblockingPipe()
	if  != 0 {
		println("runtime: pipe failed with", -)
		throw("runtime: pipe failed")
	}
	 := syscall.EpollEvent{
		Events: syscall.EPOLLIN,
	}
	*(**uintptr)(unsafe.Pointer(&.Data)) = &netpollBreakRd
	 = syscall.EpollCtl(epfd, syscall.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) uintptr {
	var  syscall.EpollEvent
	.Events = syscall.EPOLLIN | syscall.EPOLLOUT | syscall.EPOLLRDHUP | syscall.EPOLLET
	 := taggedPointerPack(unsafe.Pointer(), .fdseq.Load())
	*(*taggedPointer)(unsafe.Pointer(&.Data)) = 
	return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, int32(), &)
}

func netpollclose( uintptr) uintptr {
	var  syscall.EpollEvent
	return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int32(), &)
}

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

// netpollBreak interrupts an epollwait.
func netpollBreak() {
	// Failing to cas indicates there is an in-flight wakeup, so we're done here.
	if !netpollWakeSig.CompareAndSwap(0, 1) {
		return
	}

	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, int32) {
	if epfd == -1 {
		return gList{}, 0
	}
	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]syscall.EpollEvent
:
	,  := syscall.EpollWait(epfd, [:], 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{}, 0
		}
		goto 
	}
	var  gList
	 := int32(0)
	for  := int32(0);  < ; ++ {
		 := []
		if .Events == 0 {
			continue
		}

		if *(**uintptr)(unsafe.Pointer(&.Data)) == &netpollBreakRd {
			if .Events != syscall.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()))
				netpollWakeSig.Store(0)
			}
			continue
		}

		var  int32
		if .Events&(syscall.EPOLLIN|syscall.EPOLLRDHUP|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 {
			 += 'r'
		}
		if .Events&(syscall.EPOLLOUT|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 {
			 += 'w'
		}
		if  != 0 {
			 := *(*taggedPointer)(unsafe.Pointer(&.Data))
			 := (*pollDesc)(.pointer())
			 := .tag()
			if .fdseq.Load() ==  {
				.setEventErr(.Events == syscall.EPOLLERR, )
				 += netpollready(&, , )
			}
		}
	}
	return , 
}