runtime: add hurd netpoll and semaphore support
Patch by Svante Signell. Reviewed-on: https://go-review.googlesource.com/c/160827 From-SVN: r268465
This commit is contained in:
parent
73353297f3
commit
fc34dbfdb0
@ -1,4 +1,4 @@
|
||||
582392b80c07bd7e830e177b775dc4ef802b5fd6
|
||||
047b0aa6a29d46fde99b3e5823339ac8866f797c
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
@ -102,7 +102,7 @@ func netpollinited() bool {
|
||||
// descriptor being used by netpoll.
|
||||
func poll_runtime_isPollServerDescriptor(fd uintptr) bool {
|
||||
fds := netpolldescriptor()
|
||||
if GOOS != "aix" {
|
||||
if GOOS != "aix" && GOOS != "hurd" {
|
||||
return fd == fds
|
||||
} else {
|
||||
// AIX have a pipe in its netpoll implementation.
|
||||
@ -178,8 +178,8 @@ func poll_runtime_pollWait(pd *pollDesc, mode int) int {
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
// As for now only Solaris and AIX use level-triggered IO.
|
||||
if GOOS == "solaris" || GOOS == "aix" {
|
||||
// As for now only Solaris, AIX and Hurd use level-triggered IO.
|
||||
if GOOS == "solaris" || GOOS == "aix" || GOOS == "hurd" {
|
||||
netpollarm(pd, mode)
|
||||
}
|
||||
for !netpollblock(pd, int32(mode), false) {
|
||||
|
240
libgo/go/runtime/netpoll_hurd.go
Normal file
240
libgo/go/runtime/netpoll_hurd.go
Normal file
@ -0,0 +1,240 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
package runtime
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// FIXME: Improve network poller for hurd.
|
||||
// This is based on the former libgo/runtime/netpoll_select.c implementation
|
||||
// except that it uses poll instead of select and is written in Go.
|
||||
// It's also based on Solaris implementation for the arming mechanisms
|
||||
// Inspiration was also taken from netpoll_aix.go and netpoll_solaris.go
|
||||
|
||||
//From /usr/include/x86_64-linux-gnu/sys/poll.h
|
||||
//go:noescape
|
||||
//extern poll
|
||||
func libc_poll(pfds *pollfd, nfds int32, timeout int32) int32
|
||||
|
||||
//go:noescape
|
||||
//extern pipe2
|
||||
func libc_pipe2(fd *int32, flags int32) int32
|
||||
|
||||
//pollfd represents the poll structure for GNU/Hurd operating system.
|
||||
type pollfd struct {
|
||||
fd int32 // File descriptor to poll.
|
||||
events int16 // Types of events poller cares about.
|
||||
revents int16 // Types of events that actually occurred.
|
||||
}
|
||||
|
||||
//From /usr/include/i386-gnu/bits/poll.h
|
||||
const _POLLIN = 01 // There is data to read.
|
||||
const _POLLPRI = 02 // There is urgent data to read.
|
||||
const _POLLOUT = 04 // Writing now will not block.
|
||||
const _POLLERR = 010 // Error condition.
|
||||
const _POLLHUP = 020 // Hung up.
|
||||
const _POLLNVAL = 040 // Invalid polling request.
|
||||
|
||||
var (
|
||||
pfds []pollfd
|
||||
pds []*pollDesc
|
||||
mtxpoll mutex
|
||||
mtxset mutex
|
||||
rdwake int32
|
||||
wrwake int32
|
||||
pendingUpdates int32
|
||||
)
|
||||
|
||||
const pollVerbose = false
|
||||
|
||||
func netpollinit() {
|
||||
var p [2]int32
|
||||
|
||||
// Create the pipe we use to wakeup poll.
|
||||
if err := libc_pipe2(&p[0], _O_CLOEXEC|_O_NONBLOCK); err < 0 {
|
||||
throw("runtime:netpollinit(): failed to create pipe2")
|
||||
}
|
||||
rdwake = p[0]
|
||||
wrwake = p[1]
|
||||
|
||||
// Pre-allocate array of pollfd structures for poll.
|
||||
if pollVerbose {
|
||||
println("*** allocating")
|
||||
}
|
||||
pfds = make([]pollfd, 1, 128)
|
||||
if pollVerbose {
|
||||
println("*** allocating done", &pfds[0])
|
||||
}
|
||||
|
||||
// Poll the read side of the pipe.
|
||||
pfds[0].fd = int32(rdwake)
|
||||
pfds[0].events = int16(_POLLIN)
|
||||
pfds[0].revents = int16(0)
|
||||
|
||||
pds = make([]*pollDesc, 1, 128)
|
||||
// Checks for pd != nil are made in netpoll.
|
||||
pds[0] = nil
|
||||
}
|
||||
|
||||
func netpolldescriptor() uintptr {
|
||||
// Both fds must be returned.
|
||||
if rdwake > 0xFFFF || wrwake > 0xFFFF {
|
||||
throw("netpolldescriptor: invalid fd number")
|
||||
}
|
||||
return uintptr(rdwake<<16 | wrwake)
|
||||
}
|
||||
|
||||
// netpollwakeup writes on wrwake to wakeup poll before any changes.
|
||||
func netpollwakeup() {
|
||||
if pendingUpdates == 0 {
|
||||
pendingUpdates = 1
|
||||
if pollVerbose {
|
||||
println("*** writing 1 byte")
|
||||
}
|
||||
b := [1]byte{0}
|
||||
write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func netpollopen(fd uintptr, pd *pollDesc) int32 {
|
||||
if pollVerbose {
|
||||
println("*** netpollopen", fd)
|
||||
}
|
||||
lock(&mtxpoll)
|
||||
netpollwakeup()
|
||||
|
||||
lock(&mtxset)
|
||||
unlock(&mtxpoll)
|
||||
|
||||
pd.user = uint32(len(pfds))
|
||||
pfds = append(pfds, pollfd{fd: int32(fd)})
|
||||
pds = append(pds, pd)
|
||||
unlock(&mtxset)
|
||||
return 0
|
||||
}
|
||||
|
||||
func netpollclose(fd uintptr) int32 {
|
||||
if pollVerbose {
|
||||
println("*** netpollclose", fd)
|
||||
}
|
||||
lock(&mtxpoll)
|
||||
netpollwakeup()
|
||||
|
||||
lock(&mtxset)
|
||||
unlock(&mtxpoll)
|
||||
|
||||
for i := 0; i < len(pfds); i++ {
|
||||
if pfds[i].fd == int32(fd) {
|
||||
pfds[i] = pfds[len(pfds)-1]
|
||||
pfds = pfds[:len(pfds)-1]
|
||||
|
||||
pds[i] = pds[len(pds)-1]
|
||||
pds[i].user = uint32(i)
|
||||
pds = pds[:len(pds)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
unlock(&mtxset)
|
||||
return 0
|
||||
}
|
||||
|
||||
func netpollarm(pd *pollDesc, mode int) {
|
||||
if pollVerbose {
|
||||
println("*** netpollarm", pd.fd, mode)
|
||||
}
|
||||
lock(&mtxpoll)
|
||||
netpollwakeup()
|
||||
|
||||
lock(&mtxset)
|
||||
unlock(&mtxpoll)
|
||||
|
||||
switch mode {
|
||||
case 'r':
|
||||
pfds[pd.user].events |= _POLLIN
|
||||
case 'w':
|
||||
pfds[pd.user].events |= _POLLOUT
|
||||
}
|
||||
unlock(&mtxset)
|
||||
}
|
||||
|
||||
// polls for ready network connections
|
||||
// returns list of goroutines that become runnable
|
||||
//go:nowritebarrierrec
|
||||
func netpoll(block bool) gList {
|
||||
timeout := int32(0)
|
||||
if !block {
|
||||
timeout = 0
|
||||
return gList{}
|
||||
}
|
||||
if pollVerbose {
|
||||
println("*** netpoll", block)
|
||||
}
|
||||
retry:
|
||||
lock(&mtxpoll)
|
||||
lock(&mtxset)
|
||||
pendingUpdates = 0
|
||||
unlock(&mtxpoll)
|
||||
|
||||
if pollVerbose {
|
||||
println("*** netpoll before poll")
|
||||
}
|
||||
n := libc_poll(&pfds[0], int32(len(pfds)), timeout)
|
||||
if pollVerbose {
|
||||
println("*** netpoll after poll", n)
|
||||
}
|
||||
if n < 0 {
|
||||
e := errno()
|
||||
if e != _EINTR {
|
||||
println("errno=", e, " len(pfds)=", len(pfds))
|
||||
throw("poll failed")
|
||||
}
|
||||
if pollVerbose {
|
||||
println("*** poll failed")
|
||||
}
|
||||
unlock(&mtxset)
|
||||
goto retry
|
||||
}
|
||||
// Check if some descriptors need to be changed
|
||||
if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
|
||||
var b [1]byte
|
||||
for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 {
|
||||
if pollVerbose {
|
||||
println("*** read 1 byte from pipe")
|
||||
}
|
||||
}
|
||||
// Do not look at the other fds in this case as the mode may have changed
|
||||
// XXX only additions of flags are made, so maybe it is ok
|
||||
unlock(&mtxset)
|
||||
goto retry
|
||||
}
|
||||
var toRun gList
|
||||
for i := 0; i < len(pfds) && n > 0; i++ {
|
||||
pfd := &pfds[i]
|
||||
|
||||
var mode int32
|
||||
if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
|
||||
mode += 'r'
|
||||
pfd.events &= ^_POLLIN
|
||||
}
|
||||
if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
|
||||
mode += 'w'
|
||||
pfd.events &= ^_POLLOUT
|
||||
}
|
||||
if mode != 0 {
|
||||
if pollVerbose {
|
||||
println("*** netpollready i=", i, "revents=", pfd.revents, "events=", pfd.events, "pd=", pds[i])
|
||||
}
|
||||
netpollready(&toRun, pds[i], mode)
|
||||
n--
|
||||
}
|
||||
}
|
||||
unlock(&mtxset)
|
||||
if block && toRun.empty() {
|
||||
goto retry
|
||||
}
|
||||
if pollVerbose {
|
||||
println("*** netpoll returning end")
|
||||
}
|
||||
return toRun
|
||||
}
|
87
libgo/go/runtime/os_hurd.go
Normal file
87
libgo/go/runtime/os_hurd.go
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// This file is derived from os_solaris.go.
|
||||
|
||||
package runtime
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type mOS struct {
|
||||
waitsema uintptr // semaphore for parking on locks
|
||||
}
|
||||
|
||||
//extern malloc
|
||||
func libc_malloc(uintptr) unsafe.Pointer
|
||||
|
||||
//go:noescape
|
||||
//extern sem_init
|
||||
func sem_init(sem *_sem_t, pshared int32, value uint32) int32
|
||||
|
||||
//go:noescape
|
||||
//extern sem_wait
|
||||
func sem_wait(sem *_sem_t) int32
|
||||
|
||||
//go:noescape
|
||||
//extern sem_post
|
||||
func sem_post(sem *_sem_t) int32
|
||||
|
||||
//go:noescape
|
||||
//extern sem_timedwait
|
||||
func sem_timedwait(sem *_sem_t, timeout *timespec) int32
|
||||
|
||||
//go:nosplit
|
||||
func semacreate(mp *m) {
|
||||
if mp.mos.waitsema != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var sem *_sem_t
|
||||
|
||||
// Call libc's malloc rather than malloc. This will
|
||||
// allocate space on the C heap. We can't call malloc
|
||||
// here because it could cause a deadlock.
|
||||
sem = (*_sem_t)(libc_malloc(unsafe.Sizeof(*sem)))
|
||||
if sem_init(sem, 0, 0) != 0 {
|
||||
throw("sem_init")
|
||||
}
|
||||
mp.mos.waitsema = uintptr(unsafe.Pointer(sem))
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func semasleep(ns int64) int32 {
|
||||
_m_ := getg().m
|
||||
if ns >= 0 {
|
||||
var ts timespec
|
||||
ts.set_sec(ns / 1000000000)
|
||||
ts.set_nsec(int32(ns % 1000000000))
|
||||
|
||||
if sem_timedwait((*_sem_t)(unsafe.Pointer(_m_.mos.waitsema)), &ts) != 0 {
|
||||
err := errno()
|
||||
if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
|
||||
return -1
|
||||
}
|
||||
throw("sem_timedwait")
|
||||
}
|
||||
return 0
|
||||
}
|
||||
for {
|
||||
r1 := sem_wait((*_sem_t)(unsafe.Pointer(_m_.mos.waitsema)))
|
||||
if r1 == 0 {
|
||||
break
|
||||
}
|
||||
if errno() == _EINTR {
|
||||
continue
|
||||
}
|
||||
throw("sem_wait")
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func semawakeup(mp *m) {
|
||||
if sem_post((*_sem_t)(unsafe.Pointer(mp.mos.waitsema))) != 0 {
|
||||
throw("sem_post")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user