From cf46e561b2be3b15649fe029ffa8dc02fca6459a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 14 Mar 2013 19:42:25 +0000 Subject: [PATCH] runtime, net: fix arm build Bring net/fd_linux.go back (it was deleted this morning) because it is still needed for ARM. Fix a few typos in the runtime reorg. R=golang-dev, r CC=golang-dev https://golang.org/cl/7759046 --- src/pkg/net/fd_linux.go | 194 +++++++++++++++++++++++++++++ src/pkg/runtime/defs_linux_arm.h | 7 +- src/pkg/runtime/signal_arm.c | 4 +- src/pkg/runtime/signal_linux_arm.h | 1 + 4 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 src/pkg/net/fd_linux.go diff --git a/src/pkg/net/fd_linux.go b/src/pkg/net/fd_linux.go new file mode 100644 index 0000000000..b83d0348c1 --- /dev/null +++ b/src/pkg/net/fd_linux.go @@ -0,0 +1,194 @@ +// Copyright 2009 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. + +// +build arm + +// Waiting for FDs via epoll(7). + +package net + +import ( + "os" + "syscall" +) + +const ( + readFlags = syscall.EPOLLIN | syscall.EPOLLRDHUP + writeFlags = syscall.EPOLLOUT +) + +type pollster struct { + epfd int + + // Events we're already waiting for + // Must hold pollServer lock + events map[int]uint32 + + // An event buffer for EpollWait. + // Used without a lock, may only be used by WaitFD. + waitEventBuf [10]syscall.EpollEvent + waitEvents []syscall.EpollEvent + + // An event buffer for EpollCtl, to avoid a malloc. + // Must hold pollServer lock. + ctlEvent syscall.EpollEvent +} + +func newpollster() (p *pollster, err error) { + p = new(pollster) + if p.epfd, err = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); err != nil { + if err != syscall.ENOSYS { + return nil, os.NewSyscallError("epoll_create1", err) + } + // The arg to epoll_create is a hint to the kernel + // about the number of FDs we will care about. + // We don't know, and since 2.6.8 the kernel ignores it anyhow. + if p.epfd, err = syscall.EpollCreate(16); err != nil { + return nil, os.NewSyscallError("epoll_create", err) + } + syscall.CloseOnExec(p.epfd) + } + p.events = make(map[int]uint32) + return p, nil +} + +// First return value is whether the pollServer should be woken up. +// This version always returns false. +func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) { + // pollServer is locked. + + var already bool + p.ctlEvent.Fd = int32(fd) + p.ctlEvent.Events, already = p.events[fd] + if !repeat { + p.ctlEvent.Events |= syscall.EPOLLONESHOT + } + if mode == 'r' { + p.ctlEvent.Events |= readFlags + } else { + p.ctlEvent.Events |= writeFlags + } + + var op int + if already { + op = syscall.EPOLL_CTL_MOD + } else { + op = syscall.EPOLL_CTL_ADD + } + if err := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); err != nil { + return false, os.NewSyscallError("epoll_ctl", err) + } + p.events[fd] = p.ctlEvent.Events + return false, nil +} + +func (p *pollster) StopWaiting(fd int, bits uint) { + // pollServer is locked. + + events, already := p.events[fd] + if !already { + // The fd returned by the kernel may have been + // cancelled already; return silently. + return + } + + // If syscall.EPOLLONESHOT is not set, the wait + // is a repeating wait, so don't change it. + if events&syscall.EPOLLONESHOT == 0 { + return + } + + // Disable the given bits. + // If we're still waiting for other events, modify the fd + // event in the kernel. Otherwise, delete it. + events &= ^uint32(bits) + if int32(events)&^syscall.EPOLLONESHOT != 0 { + p.ctlEvent.Fd = int32(fd) + p.ctlEvent.Events = events + if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); err != nil { + print("Epoll modify fd=", fd, ": ", err.Error(), "\n") + } + p.events[fd] = events + } else { + if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); err != nil { + print("Epoll delete fd=", fd, ": ", err.Error(), "\n") + } + delete(p.events, fd) + } +} + +// Return value is whether the pollServer should be woken up. +// This version always returns false. +func (p *pollster) DelFD(fd int, mode int) bool { + // pollServer is locked. + + if mode == 'r' { + p.StopWaiting(fd, readFlags) + } else { + p.StopWaiting(fd, writeFlags) + } + + // Discard any queued up events. + i := 0 + for i < len(p.waitEvents) { + if fd == int(p.waitEvents[i].Fd) { + copy(p.waitEvents[i:], p.waitEvents[i+1:]) + p.waitEvents = p.waitEvents[:len(p.waitEvents)-1] + } else { + i++ + } + } + return false +} + +func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) { + for len(p.waitEvents) == 0 { + var msec int = -1 + if nsec > 0 { + msec = int((nsec + 1e6 - 1) / 1e6) + } + + s.Unlock() + n, err := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec) + s.Lock() + + if err != nil { + if err == syscall.EAGAIN || err == syscall.EINTR { + continue + } + return -1, 0, os.NewSyscallError("epoll_wait", err) + } + if n == 0 { + return -1, 0, nil + } + p.waitEvents = p.waitEventBuf[0:n] + } + + ev := &p.waitEvents[0] + p.waitEvents = p.waitEvents[1:] + + fd = int(ev.Fd) + + if ev.Events&writeFlags != 0 { + p.StopWaiting(fd, writeFlags) + return fd, 'w', nil + } + if ev.Events&readFlags != 0 { + p.StopWaiting(fd, readFlags) + return fd, 'r', nil + } + + // Other events are error conditions - wake whoever is waiting. + events, _ := p.events[fd] + if events&writeFlags != 0 { + p.StopWaiting(fd, writeFlags) + return fd, 'w', nil + } + p.StopWaiting(fd, readFlags) + return fd, 'r', nil +} + +func (p *pollster) Close() error { + return os.NewSyscallError("close", syscall.Close(p.epfd)) +} diff --git a/src/pkg/runtime/defs_linux_arm.h b/src/pkg/runtime/defs_linux_arm.h index f72ec3d1b7..82442b23e0 100644 --- a/src/pkg/runtime/defs_linux_arm.h +++ b/src/pkg/runtime/defs_linux_arm.h @@ -1,9 +1,10 @@ -// godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c - -// MACHINE GENERATED - DO NOT EDIT. +// TODO: Generate using cgo like defs_linux_{386,amd64}.h // Constants enum { + ENOMEM = 0xc, + EAGAIN = 0xb, + PROT_NONE = 0, PROT_READ = 0x1, PROT_WRITE = 0x2, diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c index d493984ddb..0763cd6dd0 100644 --- a/src/pkg/runtime/signal_arm.c +++ b/src/pkg/runtime/signal_arm.c @@ -61,7 +61,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) // the unwinding code. gp->sig = sig; gp->sigcode0 = SIG_CODE0(info, ctxt); - gp->sigcode1 = SIG_FAULT_ADDRESS(info, ctxt); + gp->sigcode1 = SIG_FAULT(info, ctxt); gp->sigpc = SIG_PC(info, ctxt); // We arrange lr, and pc to pretend the panicking @@ -113,7 +113,7 @@ Throw: runtime·traceback((void*)SIG_PC(info, ctxt), (void*)SIG_SP(info, ctxt), (void*)SIG_LR(info, ctxt), gp); runtime·tracebackothers(gp); runtime·printf("\n"); - runtime·dumpregs(r); + runtime·dumpregs(info, ctxt); } runtime·exit(2); diff --git a/src/pkg/runtime/signal_linux_arm.h b/src/pkg/runtime/signal_linux_arm.h index cc16c079e8..a674c0d573 100644 --- a/src/pkg/runtime/signal_linux_arm.h +++ b/src/pkg/runtime/signal_linux_arm.h @@ -25,3 +25,4 @@ #define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap_no) #define SIG_ERROR(info, ctxt) (SIG_REGS(ctxt).error_code) #define SIG_OLDMASK(info, ctxt) (SIG_REGS(ctxt).oldmask) +#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)