The Go Programming Language

Source file src/pkg/net/fd_freebsd.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 kqueue/kevent.
     6	
     7	package net
     8	
     9	import (
    10		"os"
    11		"syscall"
    12	)
    13	
    14	type pollster struct {
    15		kq       int
    16		eventbuf [10]syscall.Kevent_t
    17		events   []syscall.Kevent_t
    18	
    19		// An event buffer for AddFD/DelFD.
    20		// Must hold pollServer lock.
    21		kbuf [1]syscall.Kevent_t
    22	}
    23	
    24	func newpollster() (p *pollster, err os.Error) {
    25		p = new(pollster)
    26		var e int
    27		if p.kq, e = syscall.Kqueue(); e != 0 {
    28			return nil, os.NewSyscallError("kqueue", e)
    29		}
    30		p.events = p.eventbuf[0:0]
    31		return p, nil
    32	}
    33	
    34	func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
    35		// pollServer is locked.
    36	
    37		var kmode int
    38		if mode == 'r' {
    39			kmode = syscall.EVFILT_READ
    40		} else {
    41			kmode = syscall.EVFILT_WRITE
    42		}
    43		ev := &p.kbuf[0]
    44		// EV_ADD - add event to kqueue list
    45		// EV_ONESHOT - delete the event the first time it triggers
    46		flags := syscall.EV_ADD
    47		if !repeat {
    48			flags |= syscall.EV_ONESHOT
    49		}
    50		syscall.SetKevent(ev, fd, kmode, flags)
    51	
    52		n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
    53		if e != 0 {
    54			return false, os.NewSyscallError("kevent", e)
    55		}
    56		if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
    57			return false, os.NewSyscallError("kqueue phase error", e)
    58		}
    59		if ev.Data != 0 {
    60			return false, os.Errno(int(ev.Data))
    61		}
    62		return false, nil
    63	}
    64	
    65	func (p *pollster) DelFD(fd int, mode int) {
    66		// pollServer is locked.
    67	
    68		var kmode int
    69		if mode == 'r' {
    70			kmode = syscall.EVFILT_READ
    71		} else {
    72			kmode = syscall.EVFILT_WRITE
    73		}
    74		ev := &p.kbuf[0]
    75		// EV_DELETE - delete event from kqueue list
    76		syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
    77		syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
    78	}
    79	
    80	func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
    81		var t *syscall.Timespec
    82		for len(p.events) == 0 {
    83			if nsec > 0 {
    84				if t == nil {
    85					t = new(syscall.Timespec)
    86				}
    87				*t = syscall.NsecToTimespec(nsec)
    88			}
    89	
    90			s.Unlock()
    91			nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
    92			s.Lock()
    93	
    94			if e != 0 {
    95				if e == syscall.EINTR {
    96					continue
    97				}
    98				return -1, 0, os.NewSyscallError("kevent", e)
    99			}
   100			if nn == 0 {
   101				return -1, 0, nil
   102			}
   103			p.events = p.eventbuf[0:nn]
   104		}
   105		ev := &p.events[0]
   106		p.events = p.events[1:]
   107		fd = int(ev.Ident)
   108		if ev.Filter == syscall.EVFILT_READ {
   109			mode = 'r'
   110		} else {
   111			mode = 'w'
   112		}
   113		return fd, mode, nil
   114	}
   115	
   116	func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }

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