The Go Programming Language

Source file src/pkg/net/fd_linux.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Waiting for FDs via epoll(7).
     6	
     7	package net
     8	
     9	import (
    10		"os"
    11		"syscall"
    12	)
    13	
    14	const (
    15		readFlags  = syscall.EPOLLIN | syscall.EPOLLRDHUP
    16		writeFlags = syscall.EPOLLOUT
    17	)
    18	
    19	type pollster struct {
    20		epfd int
    21	
    22		// Events we're already waiting for
    23		// Must hold pollServer lock
    24		events map[int]uint32
    25	
    26		// An event buffer for EpollWait.
    27		// Used without a lock, may only be used by WaitFD.
    28		waitEventBuf [10]syscall.EpollEvent
    29		waitEvents   []syscall.EpollEvent
    30	
    31		// An event buffer for EpollCtl, to avoid a malloc.
    32		// Must hold pollServer lock.
    33		ctlEvent syscall.EpollEvent
    34	}
    35	
    36	func newpollster() (p *pollster, err os.Error) {
    37		p = new(pollster)
    38		var e int
    39	
    40		// The arg to epoll_create is a hint to the kernel
    41		// about the number of FDs we will care about.
    42		// We don't know, and since 2.6.8 the kernel ignores it anyhow.
    43		if p.epfd, e = syscall.EpollCreate(16); e != 0 {
    44			return nil, os.NewSyscallError("epoll_create", e)
    45		}
    46		p.events = make(map[int]uint32)
    47		return p, nil
    48	}
    49	
    50	func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
    51		// pollServer is locked.
    52	
    53		var already bool
    54		p.ctlEvent.Fd = int32(fd)
    55		p.ctlEvent.Events, already = p.events[fd]
    56		if !repeat {
    57			p.ctlEvent.Events |= syscall.EPOLLONESHOT
    58		}
    59		if mode == 'r' {
    60			p.ctlEvent.Events |= readFlags
    61		} else {
    62			p.ctlEvent.Events |= writeFlags
    63		}
    64	
    65		var op int
    66		if already {
    67			op = syscall.EPOLL_CTL_MOD
    68		} else {
    69			op = syscall.EPOLL_CTL_ADD
    70		}
    71		if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != 0 {
    72			return false, os.NewSyscallError("epoll_ctl", e)
    73		}
    74		p.events[fd] = p.ctlEvent.Events
    75		return false, nil
    76	}
    77	
    78	func (p *pollster) StopWaiting(fd int, bits uint) {
    79		// pollServer is locked.
    80	
    81		events, already := p.events[fd]
    82		if !already {
    83			print("Epoll unexpected fd=", fd, "\n")
    84			return
    85		}
    86	
    87		// If syscall.EPOLLONESHOT is not set, the wait
    88		// is a repeating wait, so don't change it.
    89		if events&syscall.EPOLLONESHOT == 0 {
    90			return
    91		}
    92	
    93		// Disable the given bits.
    94		// If we're still waiting for other events, modify the fd
    95		// event in the kernel.  Otherwise, delete it.
    96		events &= ^uint32(bits)
    97		if int32(events)&^syscall.EPOLLONESHOT != 0 {
    98			p.ctlEvent.Fd = int32(fd)
    99			p.ctlEvent.Events = events
   100			if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != 0 {
   101				print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
   102			}
   103			p.events[fd] = events
   104		} else {
   105			if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 {
   106				print("Epoll delete fd=", fd, ": ", os.Errno(e).String(), "\n")
   107			}
   108			p.events[fd] = 0, false
   109		}
   110	}
   111	
   112	func (p *pollster) DelFD(fd int, mode int) {
   113		// pollServer is locked.
   114	
   115		if mode == 'r' {
   116			p.StopWaiting(fd, readFlags)
   117		} else {
   118			p.StopWaiting(fd, writeFlags)
   119		}
   120	
   121		// Discard any queued up events.
   122		i := 0
   123		for i < len(p.waitEvents) {
   124			if fd == int(p.waitEvents[i].Fd) {
   125				copy(p.waitEvents[i:], p.waitEvents[i+1:])
   126				p.waitEvents = p.waitEvents[:len(p.waitEvents)-1]
   127			} else {
   128				i++
   129			}
   130		}
   131	}
   132	
   133	func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
   134		for len(p.waitEvents) == 0 {
   135			var msec int = -1
   136			if nsec > 0 {
   137				msec = int((nsec + 1e6 - 1) / 1e6)
   138			}
   139	
   140			s.Unlock()
   141			n, e := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
   142			s.Lock()
   143	
   144			if e != 0 {
   145				if e == syscall.EAGAIN || e == syscall.EINTR {
   146					continue
   147				}
   148				return -1, 0, os.NewSyscallError("epoll_wait", e)
   149			}
   150			if n == 0 {
   151				return -1, 0, nil
   152			}
   153			p.waitEvents = p.waitEventBuf[0:n]
   154		}
   155	
   156		ev := &p.waitEvents[0]
   157		p.waitEvents = p.waitEvents[1:]
   158	
   159		fd = int(ev.Fd)
   160	
   161		if ev.Events&writeFlags != 0 {
   162			p.StopWaiting(fd, writeFlags)
   163			return fd, 'w', nil
   164		}
   165		if ev.Events&readFlags != 0 {
   166			p.StopWaiting(fd, readFlags)
   167			return fd, 'r', nil
   168		}
   169	
   170		// Other events are error conditions - wake whoever is waiting.
   171		events, _ := p.events[fd]
   172		if events&writeFlags != 0 {
   173			p.StopWaiting(fd, writeFlags)
   174			return fd, 'w', nil
   175		}
   176		p.StopWaiting(fd, readFlags)
   177		return fd, 'r', nil
   178	}
   179	
   180	func (p *pollster) Close() os.Error {
   181		return os.NewSyscallError("close", syscall.Close(p.epfd))
   182	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.