The Go Programming Language

Source file src/pkg/net/fd_darwin.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_RECEIPT - generate fake EV_ERROR as result of add,
    46		//	rather than waiting for real event
    47		// EV_ONESHOT - delete the event the first time it triggers
    48		flags := syscall.EV_ADD | syscall.EV_RECEIPT
    49		if !repeat {
    50			flags |= syscall.EV_ONESHOT
    51		}
    52		syscall.SetKevent(ev, fd, kmode, flags)
    53	
    54		n, e := syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
    55		if e != 0 {
    56			return false, os.NewSyscallError("kevent", e)
    57		}
    58		if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
    59			return false, os.NewError("kqueue phase error")
    60		}
    61		if ev.Data != 0 {
    62			return false, os.Errno(int(ev.Data))
    63		}
    64		return false, nil
    65	}
    66	
    67	func (p *pollster) DelFD(fd int, mode int) {
    68		// pollServer is locked.
    69	
    70		var kmode int
    71		if mode == 'r' {
    72			kmode = syscall.EVFILT_READ
    73		} else {
    74			kmode = syscall.EVFILT_WRITE
    75		}
    76		ev := &p.kbuf[0]
    77		// EV_DELETE - delete event from kqueue list
    78		// EV_RECEIPT - generate fake EV_ERROR as result of add,
    79		//	rather than waiting for real event
    80		syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE|syscall.EV_RECEIPT)
    81		syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
    82	}
    83	
    84	func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
    85		var t *syscall.Timespec
    86		for len(p.events) == 0 {
    87			if nsec > 0 {
    88				if t == nil {
    89					t = new(syscall.Timespec)
    90				}
    91				*t = syscall.NsecToTimespec(nsec)
    92			}
    93	
    94			s.Unlock()
    95			nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[0:], t)
    96			s.Lock()
    97	
    98			if e != 0 {
    99				if e == syscall.EINTR {
   100					continue
   101				}
   102				return -1, 0, os.NewSyscallError("kevent", e)
   103			}
   104			if nn == 0 {
   105				return -1, 0, nil
   106			}
   107			p.events = p.eventbuf[0:nn]
   108		}
   109		ev := &p.events[0]
   110		p.events = p.events[1:]
   111		fd = int(ev.Ident)
   112		if ev.Filter == syscall.EVFILT_READ {
   113			mode = 'r'
   114		} else {
   115			mode = 'w'
   116		}
   117		return fd, mode, nil
   118	}
   119	
   120	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.