Home | History | Annotate | Download | only in net
      1 // Copyright 2013 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 // +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
      6 
      7 package net
      8 
      9 import (
     10 	"runtime"
     11 	"sync"
     12 	"syscall"
     13 	"time"
     14 )
     15 
     16 // runtimeNano returns the current value of the runtime clock in nanoseconds.
     17 func runtimeNano() int64
     18 
     19 func runtime_pollServerInit()
     20 func runtime_pollOpen(fd uintptr) (uintptr, int)
     21 func runtime_pollClose(ctx uintptr)
     22 func runtime_pollWait(ctx uintptr, mode int) int
     23 func runtime_pollWaitCanceled(ctx uintptr, mode int) int
     24 func runtime_pollReset(ctx uintptr, mode int) int
     25 func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
     26 func runtime_pollUnblock(ctx uintptr)
     27 
     28 type pollDesc struct {
     29 	runtimeCtx uintptr
     30 }
     31 
     32 var serverInit sync.Once
     33 
     34 func (pd *pollDesc) init(fd *netFD) error {
     35 	serverInit.Do(runtime_pollServerInit)
     36 	ctx, errno := runtime_pollOpen(uintptr(fd.sysfd))
     37 	runtime.KeepAlive(fd)
     38 	if errno != 0 {
     39 		return syscall.Errno(errno)
     40 	}
     41 	pd.runtimeCtx = ctx
     42 	return nil
     43 }
     44 
     45 func (pd *pollDesc) close() {
     46 	if pd.runtimeCtx == 0 {
     47 		return
     48 	}
     49 	runtime_pollClose(pd.runtimeCtx)
     50 	pd.runtimeCtx = 0
     51 }
     52 
     53 // Evict evicts fd from the pending list, unblocking any I/O running on fd.
     54 func (pd *pollDesc) evict() {
     55 	if pd.runtimeCtx == 0 {
     56 		return
     57 	}
     58 	runtime_pollUnblock(pd.runtimeCtx)
     59 }
     60 
     61 func (pd *pollDesc) prepare(mode int) error {
     62 	res := runtime_pollReset(pd.runtimeCtx, mode)
     63 	return convertErr(res)
     64 }
     65 
     66 func (pd *pollDesc) prepareRead() error {
     67 	return pd.prepare('r')
     68 }
     69 
     70 func (pd *pollDesc) prepareWrite() error {
     71 	return pd.prepare('w')
     72 }
     73 
     74 func (pd *pollDesc) wait(mode int) error {
     75 	res := runtime_pollWait(pd.runtimeCtx, mode)
     76 	return convertErr(res)
     77 }
     78 
     79 func (pd *pollDesc) waitRead() error {
     80 	return pd.wait('r')
     81 }
     82 
     83 func (pd *pollDesc) waitWrite() error {
     84 	return pd.wait('w')
     85 }
     86 
     87 func (pd *pollDesc) waitCanceled(mode int) {
     88 	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
     89 }
     90 
     91 func (pd *pollDesc) waitCanceledRead() {
     92 	pd.waitCanceled('r')
     93 }
     94 
     95 func (pd *pollDesc) waitCanceledWrite() {
     96 	pd.waitCanceled('w')
     97 }
     98 
     99 func convertErr(res int) error {
    100 	switch res {
    101 	case 0:
    102 		return nil
    103 	case 1:
    104 		return errClosing
    105 	case 2:
    106 		return errTimeout
    107 	}
    108 	println("unreachable: ", res)
    109 	panic("unreachable")
    110 }
    111 
    112 func (fd *netFD) setDeadline(t time.Time) error {
    113 	return setDeadlineImpl(fd, t, 'r'+'w')
    114 }
    115 
    116 func (fd *netFD) setReadDeadline(t time.Time) error {
    117 	return setDeadlineImpl(fd, t, 'r')
    118 }
    119 
    120 func (fd *netFD) setWriteDeadline(t time.Time) error {
    121 	return setDeadlineImpl(fd, t, 'w')
    122 }
    123 
    124 func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
    125 	diff := int64(time.Until(t))
    126 	d := runtimeNano() + diff
    127 	if d <= 0 && diff > 0 {
    128 		// If the user has a deadline in the future, but the delay calculation
    129 		// overflows, then set the deadline to the maximum possible value.
    130 		d = 1<<63 - 1
    131 	}
    132 	if t.IsZero() {
    133 		d = 0
    134 	}
    135 	if err := fd.incref(); err != nil {
    136 		return err
    137 	}
    138 	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
    139 	fd.decref()
    140 	return nil
    141 }
    142