github.com/icexin/eggos@v0.4.2-0.20220216025428-78b167e4f349/kernel/epoll.go (about) 1 package kernel 2 3 import ( 4 "syscall" 5 "unsafe" 6 7 "github.com/icexin/eggos/kernel/isyscall" 8 "github.com/icexin/eggos/kernel/mm" 9 "gvisor.dev/gvisor/pkg/abi/linux" 10 "gvisor.dev/gvisor/pkg/abi/linux/errno" 11 ) 12 13 const ( 14 epollFd = 3 15 16 maxFds = 1024 17 ) 18 19 var ( 20 // source of fd events, set by netstack 21 // cleared by epoll_wait 22 fdevents [maxFds]uint32 23 24 // to manage epoll event 25 eventpool mm.Pool 26 27 // header of registered epoll events 28 epollEvents epollEvent 29 30 // notify of epoll events 31 epollNote note 32 ) 33 34 //go:notinheap 35 type epollEvent struct { 36 fd uintptr 37 sub linux.EpollEvent 38 39 pre, next *epollEvent 40 } 41 42 //go:nosplit 43 func newEpollEvent() *epollEvent { 44 ptr := eventpool.Alloc() 45 e := (*epollEvent)(unsafe.Pointer(ptr)) 46 e.pre = &epollEvents 47 e.next = epollEvents.next 48 if epollEvents.next != nil { 49 epollEvents.next.pre = e 50 } 51 epollEvents.next = e 52 return e 53 } 54 55 //go:nosplit 56 func freeEpollEvent(e *epollEvent) { 57 e.pre.next = e.next 58 if e.next != nil { 59 e.next.pre = e.pre 60 } 61 eventpool.Free(uintptr(unsafe.Pointer(e))) 62 } 63 64 //go:nosplit 65 func findEpollEvent(fd uintptr) *epollEvent { 66 for e := epollEvents.next; e != nil; e = e.next { 67 if e.fd == fd { 68 return e 69 } 70 } 71 return nil 72 } 73 74 //go:nosplit 75 func epollCtl(epfd, op, fd, desc uintptr) uintptr { 76 euser := (*linux.EpollEvent)(unsafe.Pointer(desc)) 77 var e *epollEvent 78 switch op { 79 case syscall.EPOLL_CTL_ADD: 80 e = findEpollEvent(fd) 81 if e == nil { 82 e = newEpollEvent() 83 } 84 e.fd = fd 85 e.sub = *euser 86 e.sub.Events |= syscall.EPOLLHUP 87 return 0 88 case syscall.EPOLL_CTL_MOD: 89 e = findEpollEvent(fd) 90 if e == nil { 91 return isyscall.Errno(errno.EINVAL) 92 } 93 e.sub = *euser 94 e.sub.Events |= syscall.EPOLLHUP 95 return 0 96 case syscall.EPOLL_CTL_DEL: 97 e = findEpollEvent(fd) 98 if e == nil { 99 return isyscall.Errno(errno.EINVAL) 100 } 101 freeEpollEvent(e) 102 return 0 103 default: 104 return isyscall.Errno(errno.EINVAL) 105 } 106 } 107 108 //go:nosplit 109 func epollWait(epfd, eventptr, len, _ms uintptr) uintptr { 110 if _ms != 0 { 111 ts := linux.Timespec{ 112 Sec: int64(_ms / 1000), 113 Nsec: int64(_ms%1000) * ms, 114 } 115 // wait fd event 116 epollNote.sleep(&ts) 117 epollNote.clear() 118 } 119 120 events := (*[256]linux.EpollEvent)(unsafe.Pointer(eventptr))[:len] 121 var cnt uintptr = 0 122 for e := epollEvents.next; e != nil && cnt < len; e = e.next { 123 event := fdevents[e.fd] 124 if event == 0 { 125 continue 126 } 127 ue := &events[cnt] 128 ue.Data = e.sub.Data 129 ue.Events = event & e.sub.Events 130 // clear events 131 // FIXME: only clear masked events? 132 fdevents[e.fd] = 0 133 cnt++ 134 } 135 return cnt 136 } 137 138 //go:nosplit 139 func epollNotify(fd, events uintptr) { 140 fdevents[fd] |= uint32(events) 141 epollNote.wakeup() 142 } 143 144 //go:nosplit 145 func epollInit() { 146 mm.PoolInit(&eventpool, unsafe.Sizeof(epollEvent{})) 147 }