github.com/iceber/iouring-go@v0.0.0-20230403020409-002cfd2e2a90/fixed_files.go (about) 1 // +build linux 2 3 package iouring 4 5 import ( 6 "errors" 7 "os" 8 "sync" 9 "unsafe" 10 11 iouring_syscall "github.com/iceber/iouring-go/syscall" 12 ) 13 14 func (iour *IOURing) GetFixedFileIndex(file *os.File) (int, bool) { 15 return iour.fileRegister.GetFileIndex(int32(file.Fd())) 16 } 17 18 func (iour *IOURing) RegisterFile(file *os.File) error { 19 return iour.fileRegister.RegisterFile(int32(file.Fd())) 20 } 21 22 func (iour *IOURing) RegisterFiles(files []*os.File) error { 23 fds := make([]int32, 0, len(files)) 24 for _, file := range files { 25 fds = append(fds, int32(file.Fd())) 26 } 27 28 return iour.fileRegister.RegisterFiles(fds) 29 } 30 31 func (iour *IOURing) UnregisterFile(file *os.File) error { 32 return iour.fileRegister.UnregisterFile(int32(file.Fd())) 33 } 34 35 func (iour *IOURing) UnregisterFiles(files []*os.File) error { 36 fds := make([]int32, 0, len(files)) 37 for _, file := range files { 38 fds = append(fds, int32(file.Fd())) 39 } 40 41 return iour.fileRegister.UnregisterFiles(fds) 42 } 43 44 func (iour *IOURing) FileRegister() FileRegister { 45 return iour.fileRegister 46 } 47 48 type FileRegister interface { 49 GetFileIndex(fd int32) (int, bool) 50 RegisterFile(fd int32) error 51 RegisterFiles(fds []int32) error 52 UnregisterFile(fd int32) error 53 UnregisterFiles(fds []int32) error 54 } 55 56 type fileRegister struct { 57 lock sync.Mutex 58 iouringFd int 59 60 fds []int32 61 sparseIndexs map[int]int 62 63 registered bool 64 indexs sync.Map 65 } 66 67 func (register *fileRegister) GetFileIndex(fd int32) (int, bool) { 68 if fd < 0 { 69 return -1, false 70 } 71 72 i, ok := register.indexs.Load(fd) 73 if !ok { 74 return -1, false 75 } 76 return i.(int), true 77 } 78 79 func (register *fileRegister) register() error { 80 if err := iouring_syscall.IOURingRegister( 81 register.iouringFd, 82 iouring_syscall.IORING_REGISTER_FILES, 83 unsafe.Pointer(®ister.fds[0]), 84 uint32(len(register.fds)), 85 ); err != nil { 86 return err 87 } 88 89 for i, fd := range register.fds { 90 register.indexs.Store(fd, i) 91 } 92 register.registered = true 93 return nil 94 } 95 96 func (register *fileRegister) unregister() error { 97 return iouring_syscall.IOURingRegister(register.iouringFd, iouring_syscall.IORING_UNREGISTER_FILES, nil, 0) 98 } 99 100 func (register *fileRegister) RegisterFiles(fds []int32) error { 101 if len(fds) == 0 { 102 return errors.New("file set is empty") 103 } 104 105 vfds := make([]int32, 0, len(fds)) 106 for _, fd := range fds { 107 if fd < 0 { 108 continue 109 } 110 111 if _, ok := register.indexs.Load(fd); ok { 112 continue 113 } 114 vfds = append(vfds, fd) 115 } 116 117 if len(vfds) == 0 { 118 return nil 119 } 120 fds = vfds 121 122 register.lock.Lock() 123 defer register.lock.Unlock() 124 125 if !register.registered { 126 register.fds = fds 127 return register.register() 128 } 129 130 var fdi int 131 indexs := make(map[int32]int, len(fds)) 132 updatedSpares := make(map[int]int, len(fds)) 133 for i, spares := range register.sparseIndexs { 134 updatedSpares[i] = spares 135 for si := 0; si < spares; si++ { 136 for ; fdi < len(fds); fdi++ { 137 register.fds[i+si] = fds[fdi] 138 indexs[fds[fdi]] = i + si 139 140 fdi++ 141 updatedSpares[i]-- 142 break 143 } 144 145 if fdi >= len(fds) { 146 goto update 147 } 148 } 149 } 150 register.fds = append(register.fds, fds[fdi:]...) 151 152 update: 153 if err := register.fresh(0, len(register.fds)); err != nil { 154 return err 155 } 156 157 for i, spares := range updatedSpares { 158 if spares > 0 { 159 register.sparseIndexs[i] = spares 160 continue 161 } 162 delete(register.sparseIndexs, i) 163 } 164 for i, fd := range register.fds { 165 register.indexs.Store(fd, i) 166 } 167 168 return nil 169 } 170 171 func (register *fileRegister) RegisterFile(fd int32) error { 172 if fd < 0 { 173 return nil 174 } 175 176 if _, ok := register.GetFileIndex(fd); ok { 177 return nil 178 } 179 180 register.lock.Lock() 181 defer register.lock.Unlock() 182 183 if !register.registered { 184 register.fds = []int32{fd} 185 return register.register() 186 } 187 188 var fdi int 189 var spares int 190 for fdi, spares = range register.sparseIndexs { 191 break 192 } 193 register.fds[fdi] = fd 194 195 if err := register.fresh(fdi, 1); err != nil { 196 return err 197 } 198 199 if spares == 1 { 200 delete(register.sparseIndexs, fdi) 201 } else { 202 register.sparseIndexs[fdi]-- 203 } 204 205 register.indexs.Store(fd, fdi) 206 return nil 207 } 208 209 func (register *fileRegister) UnregisterFile(fd int32) error { 210 if fd < 0 { 211 return nil 212 } 213 214 register.lock.Lock() 215 defer register.lock.Unlock() 216 217 fdi, ok := register.deleteFile(fd) 218 if !ok { 219 return nil 220 } 221 222 return register.fresh(fdi, 1) 223 } 224 225 func (register *fileRegister) UnregisterFiles(fds []int32) error { 226 register.lock.Lock() 227 defer register.lock.Unlock() 228 229 var unregistered bool 230 for _, fd := range fds { 231 if fd < 0 { 232 continue 233 } 234 235 _, ok := register.deleteFile(fd) 236 if !ok { 237 continue 238 } 239 unregistered = true 240 } 241 if unregistered { 242 return nil 243 } 244 245 return register.fresh(0, len(register.fds)) 246 } 247 248 func (register *fileRegister) deleteFile(fd int32) (fdi int, ok bool) { 249 var v interface{} 250 /* 251 go version >= 1.15 252 253 v, ok = register.index.LoadAndDelete(fd) 254 */ 255 v, ok = register.indexs.Load(fd) 256 if !ok { 257 return 258 } 259 register.indexs.Delete(fd) 260 261 fdi = v.(int) 262 register.fds[fdi] = -1 263 264 var updated bool 265 for i, sparse := range register.sparseIndexs { 266 if i+sparse == fdi { 267 register.sparseIndexs[i]++ 268 updated = true 269 break 270 } 271 } 272 273 if !updated { 274 register.sparseIndexs[fdi] = 1 275 } 276 return 277 } 278 279 func (register *fileRegister) fresh(offset int, length int) error { 280 update := iouring_syscall.IOURingFilesUpdate{ 281 Offset: uint32(offset), 282 Fds: ®ister.fds[offset], 283 } 284 return iouring_syscall.IOURingRegister( 285 register.iouringFd, 286 iouring_syscall.IORING_REGISTER_FILES_UPDATE, 287 unsafe.Pointer(&update), 288 uint32(len(register.fds)), 289 ) 290 }