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