github.com/pawelgaczynski/giouring@v0.0.0-20230826085535-69588b89acb9/register.go (about) 1 // MIT License 2 // 3 // Copyright (c) 2023 Paweł Gaczyński 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a 6 // copy of this software and associated documentation files (the 7 // "Software"), to deal in the Software without restriction, including 8 // without limitation the rights to use, copy, modify, merge, publish, 9 // distribute, sublicense, and/or sell copies of the Software, and to 10 // permit persons to whom the Software is furnished to do so, subject to 11 // the following conditions: 12 // 13 // The above copyright notice and this permission notice shall be included 14 // in all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 package giouring 25 26 import ( 27 "fmt" 28 "os" 29 "runtime" 30 "syscall" 31 "unsafe" 32 33 "golang.org/x/sys/unix" 34 ) 35 36 func (ring *Ring) doRegisterErrno(opCode uint32, arg unsafe.Pointer, nrArgs uint32) (uint, syscall.Errno) { 37 var fd int 38 39 if ring.intFlags&IntFlagRegRing != 0 { 40 opCode |= RegisterUseRegisteredRing 41 fd = ring.enterRingFd 42 } else { 43 fd = ring.ringFd 44 } 45 46 return ring.Register(fd, opCode, arg, nrArgs) 47 } 48 49 func (ring *Ring) doRegister(opCode uint32, arg unsafe.Pointer, nrArgs uint32) (uint, error) { 50 ret, errno := ring.doRegisterErrno(opCode, arg, nrArgs) 51 if errno != 0 { 52 return 0, os.NewSyscallError("io_uring_register", errno) 53 } 54 55 return ret, nil 56 } 57 58 // liburing: io_uring_register_buffers_update_tag - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_buffers_update_tag.3.en.html 59 func (ring *Ring) RegisterBuffersUpdateTag(off uint32, iovecs []syscall.Iovec, tags *uint64, nr uint32) (uint, error) { 60 rsrcUpdate := &RsrcUpdate2{ 61 Offset: off, 62 Data: uint64(uintptr(unsafe.Pointer(&iovecs[0]))), 63 Tags: *tags, 64 Nr: nr, 65 } 66 67 result, err := ring.doRegister(RegisterBuffersUpdate, unsafe.Pointer(rsrcUpdate), uint32(unsafe.Sizeof(*rsrcUpdate))) 68 runtime.KeepAlive(rsrcUpdate) 69 70 return result, err 71 } 72 73 // liburing: io_uring_register_buffers_tags - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_buffers_tags.3.en.html 74 func (ring *Ring) RegisterBuffersTags(iovecs []syscall.Iovec, tags []uint64) (uint, error) { 75 reg := &RsrcRegister{ 76 Nr: uint32(len(tags)), 77 Data: uint64(uintptr(unsafe.Pointer(&iovecs[0]))), 78 Tags: uint64(uintptr(unsafe.Pointer(&tags[0]))), 79 } 80 81 result, err := ring.doRegister(RegisterBuffers2, unsafe.Pointer(reg), uint32(unsafe.Sizeof(*reg))) 82 runtime.KeepAlive(reg) 83 84 return result, err 85 } 86 87 // liburing: io_uring_register_buffers_sparse - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_buffers_sparse.3.en.html 88 func (ring *Ring) RegisterBuffersSparse(nr uint32) (uint, error) { 89 reg := &RsrcRegister{ 90 Flags: RsrcRegisterSparse, 91 Nr: nr, 92 } 93 94 result, err := ring.doRegister(RegisterBuffers2, unsafe.Pointer(reg), uint32(unsafe.Sizeof(*reg))) 95 runtime.KeepAlive(reg) 96 97 return result, err 98 } 99 100 // liburing: io_uring_register_buffers - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_buffers.3.en.html 101 func (ring *Ring) RegisterBuffers(iovecs []syscall.Iovec) (uint, error) { 102 return ring.doRegister(RegisterBuffers, unsafe.Pointer(&iovecs[0]), uint32(len(iovecs))) 103 } 104 105 // liburing: io_uring_unregister_buffers - https://manpages.debian.org/unstable/liburing-dev/io_uring_unregister_buffers.3.en.html 106 func (ring *Ring) UnregisterBuffers() (uint, error) { 107 return ring.doRegister(UnregisterBuffers, unsafe.Pointer(nil), 0) 108 } 109 110 // liburing: io_uring_register_files_update_tag - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_files_update_tag.3.en.html 111 func (ring *Ring) RegisterFilesUpdateTag(off uint, files []int, tags []uint64) (uint, error) { 112 update := &RsrcUpdate2{ 113 Offset: uint32(off), 114 Data: uint64(uintptr(unsafe.Pointer(&files[0]))), 115 Tags: uint64(uintptr(unsafe.Pointer(&tags[0]))), 116 Nr: uint32(len(files)), 117 } 118 119 result, err := ring.doRegister(RegisterBuffers2, unsafe.Pointer(update), 1) 120 runtime.KeepAlive(update) 121 122 return result, err 123 } 124 125 // liburing: io_uring_register_files_update - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_files_update.3.en.html 126 func (ring *Ring) RegisterFilesUpdate(off uint, files []int) (uint, error) { 127 update := &FilesUpdate{ 128 Offset: uint32(off), 129 Fds: uint64(uintptr(unsafe.Pointer(&files[0]))), 130 } 131 132 result, err := ring.doRegister(RegisterFilesUpdate, unsafe.Pointer(update), uint32(len(files))) 133 runtime.KeepAlive(update) 134 135 return result, err 136 } 137 138 // liburing: increase_rlimit_nofile 139 func increaseRlimitNofile(nr uint64) error { 140 rlim := syscall.Rlimit{} 141 142 err := syscall.Getrlimit(unix.RLIMIT_NOFILE, &rlim) 143 if err != nil { 144 return err 145 } 146 147 if rlim.Cur < nr { 148 rlim.Cur += nr 149 150 err = syscall.Setrlimit(unix.RLIMIT_NOFILE, &rlim) 151 if err != nil { 152 return err 153 } 154 } 155 156 return nil 157 } 158 159 // liburing: io_uring_register_files_sparse - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_files_sparse.3.en.html 160 func (ring *Ring) RegisterFilesSparse(nr uint32) (uint, error) { 161 reg := &RsrcRegister{ 162 Flags: RsrcRegisterSparse, 163 Nr: nr, 164 } 165 166 var ( 167 ret uint 168 err error 169 errno syscall.Errno 170 didIncrease bool 171 ) 172 173 for { 174 ret, errno = ring.doRegisterErrno(RegisterFiles2, unsafe.Pointer(reg), uint32(unsafe.Sizeof(*reg))) 175 if errno != 0 { 176 break 177 } 178 179 if errno == syscall.EMFILE && !didIncrease { 180 didIncrease = true 181 182 err = increaseRlimitNofile(uint64(nr)) 183 if err != nil { 184 break 185 } 186 187 continue 188 } 189 190 break 191 } 192 193 return ret, err 194 } 195 196 // liburing: io_uring_register_files_tags - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_files_tags.3.en.html 197 func (ring *Ring) RegisterFilesTags(files []int, tags []uint64) (uint, error) { 198 nr := len(files) 199 reg := &RsrcRegister{ 200 Nr: uint32(nr), 201 Data: uint64(uintptr(unsafe.Pointer(&files[0]))), 202 Tags: uint64(uintptr(unsafe.Pointer(&tags[0]))), 203 } 204 205 var ( 206 ret uint 207 err error 208 errno syscall.Errno 209 didIncrease bool 210 ) 211 212 for { 213 ret, errno = ring.doRegisterErrno(RegisterFiles2, unsafe.Pointer(reg), uint32(unsafe.Sizeof(*reg))) 214 if ret > 0 { 215 break 216 } 217 if errno == syscall.EMFILE && !didIncrease { 218 didIncrease = true 219 err = increaseRlimitNofile(uint64(nr)) 220 if err != nil { 221 break 222 } 223 224 continue 225 } 226 227 break 228 } 229 230 return ret, err 231 } 232 233 // liburing: io_uring_register_files - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_files.3.en.html 234 func (ring *Ring) RegisterFiles(files []int) (uint, error) { 235 var ( 236 ret uint 237 err error 238 errno syscall.Errno 239 didIncrease bool 240 ) 241 242 for { 243 ret, errno = ring.doRegisterErrno(RegisterFiles, unsafe.Pointer(&files[0]), uint32(len(files))) 244 if ret > 0 { 245 break 246 } 247 if errno == syscall.EMFILE && !didIncrease { 248 didIncrease = true 249 err = increaseRlimitNofile(uint64(len(files))) 250 if err != nil { 251 break 252 } 253 254 continue 255 } 256 257 break 258 } 259 260 return ret, err 261 } 262 263 // liburing: io_uring_unregister_files - https://manpages.debian.org/unstable/liburing-dev/io_uring_unregister_files.3.en.html 264 func (ring *Ring) UnregisterFiles() (uint, error) { 265 return ring.doRegister(UnregisterFiles, unsafe.Pointer(nil), 0) 266 } 267 268 // liburing: io_uring_register_eventfd - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_eventfd.3.en.html 269 func (ring *Ring) RegisterEventFd(fd int) (uint, error) { 270 return ring.doRegister(RegisterEventFD, unsafe.Pointer(&fd), 1) 271 } 272 273 // liburing: io_uring_unregister_eventfd - https://manpages.debian.org/unstable/liburing-dev/io_uring_unregister_eventfd.3.en.html 274 func (ring *Ring) UnregisterEventFd(fd int) (uint, error) { 275 return ring.doRegister(UnregisterEventFD, unsafe.Pointer(&fd), 1) 276 } 277 278 // liburing: io_uring_register_eventfd_async - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_eventfd_async.3.en.html 279 func (ring *Ring) RegisterEventFdAsync(fd int) (uint, error) { 280 return ring.doRegister(RegisterEventFDAsync, unsafe.Pointer(&fd), 1) 281 } 282 283 // liburing: io_uring_register_probe 284 func (ring *Ring) RegisterProbe(probe *Probe, nrOps int) (uint, error) { 285 result, err := ring.doRegister(RegisterProbe, unsafe.Pointer(probe), uint32(nrOps)) 286 runtime.KeepAlive(probe) 287 288 return result, err 289 } 290 291 // liburing: io_uring_register_personality 292 func (ring *Ring) RegisterPersonality() (uint, error) { 293 return ring.doRegister(RegisterPersonality, unsafe.Pointer(nil), 0) 294 } 295 296 // liburing: io_uring_unregister_personality 297 func (ring *Ring) UnregisterPersonality() (uint, error) { 298 return ring.doRegister(UnregisterPersonality, unsafe.Pointer(nil), 0) 299 } 300 301 // liburing: io_uring_register_restrictions 302 func (ring *Ring) RegisterRestrictions(res []Restriction) (uint, error) { 303 return ring.doRegister(RegisterRestrictions, unsafe.Pointer(&res[0]), uint32(len(res))) 304 } 305 306 // liburing: io_uring_enable_rings 307 func (ring *Ring) EnableRings() (uint, error) { 308 return ring.doRegister(RegisterEnableRings, unsafe.Pointer(nil), 0) 309 } 310 311 // liburing: io_uring_register_iowq_aff - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_iowq_aff.3.en.html 312 func (ring *Ring) RegisterIOWQAff(cpusz uint64, mask *unix.CPUSet) error { 313 if cpusz >= 1<<31 { 314 return syscall.EINVAL 315 } 316 _, err := ring.doRegister(RegisterIOWQAff, unsafe.Pointer(mask), uint32(cpusz)) 317 318 runtime.KeepAlive(mask) 319 320 return err 321 } 322 323 // liburing: io_uring_unregister_iowq_aff - https://manpages.debian.org/unstable/liburing-dev/io_uring_unregister_iowq_aff.3.en.html 324 func (ring *Ring) UnregisterIOWQAff() (uint, error) { 325 return ring.doRegister(UnregisterIOWQAff, unsafe.Pointer(nil), 0) 326 } 327 328 const iowqMaxWorkersNrArgs = 2 329 330 // liburing: io_uring_register_iowq_max_workers - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_iowq_max_workers.3.en.html 331 func (ring *Ring) RegisterIOWQMaxWorkers(val []uint) (uint, error) { 332 return ring.doRegister(RegisterIOWQMaxWorkers, unsafe.Pointer(&val[0]), iowqMaxWorkersNrArgs) 333 } 334 335 // liburing: io_uring_register_ring_fd - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_ring_fd.3.en.html 336 func (ring *Ring) RegisterRingFd() (uint, error) { 337 if (ring.intFlags & IntFlagRegRing) != 0 { 338 return 0, syscall.EEXIST 339 } 340 341 rsrcUpdate := &RsrcUpdate{ 342 Data: uint64(ring.ringFd), 343 Offset: registerRingFdOffset, 344 } 345 346 ret, err := ring.doRegister(RegisterRingFDs, unsafe.Pointer(rsrcUpdate), 1) 347 if err != nil { 348 return ret, err 349 } 350 351 if ret == 1 { 352 ring.enterRingFd = int(rsrcUpdate.Offset) 353 ring.intFlags |= IntFlagRegRing 354 355 if ring.features&FeatRegRegRing != 0 { 356 ring.intFlags |= IntFlagRegRegRing 357 } 358 } else { 359 return ret, fmt.Errorf("unexpected return from ring.Register: %d", ret) 360 } 361 362 return ret, nil 363 } 364 365 // liburing: io_uring_unregister_ring_fd - https://manpages.debian.org/unstable/liburing-dev/io_uring_unregister_ring_fd.3.en.html 366 func (ring *Ring) UnregisterRingFd() (uint, error) { 367 rsrcUpdate := &RsrcUpdate{ 368 Offset: uint32(ring.enterRingFd), 369 } 370 371 if (ring.intFlags & IntFlagRegRing) != 0 { 372 return 0, syscall.EINVAL 373 } 374 375 ret, err := ring.doRegister(UnregisterRingFDs, unsafe.Pointer(rsrcUpdate), 1) 376 if err != nil { 377 return ret, err 378 } 379 380 if ret == 1 { 381 ring.enterRingFd = ring.ringFd 382 ring.intFlags &= ^(IntFlagRegRing | IntFlagRegRegRing) 383 } 384 385 return ret, nil 386 } 387 388 // liburing: io_uring_close_ring_fd - https://manpages.debian.org/unstable/liburing-dev/io_uring_close_ring_fd.3.en.html 389 func (ring *Ring) CloseRingFd() (uint, error) { 390 if ring.features&FeatRegRegRing == 0 { 391 return 0, syscall.EOPNOTSUPP 392 } 393 394 if (ring.intFlags & IntFlagRegRing) == 0 { 395 return 0, syscall.EINVAL 396 } 397 398 if ring.ringFd == -1 { 399 return 0, syscall.EBADF 400 } 401 402 syscall.Close(ring.ringFd) 403 ring.ringFd = -1 404 405 return 1, nil 406 } 407 408 // liburing: io_uring_register_buf_ring - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_buf_ring.3.en.html 409 func (ring *Ring) RegisterBufferRing(reg *BufReg, _ uint32) (uint, error) { 410 result, err := ring.doRegister(RegisterPbufRing, unsafe.Pointer(reg), 1) 411 runtime.KeepAlive(reg) 412 413 return result, err 414 } 415 416 // liburing: io_uring_unregister_buf_ring - https://manpages.debian.org/unstable/liburing-dev/io_uring_unregister_buf_ring.3.en.html 417 func (ring *Ring) UnregisterBufferRing(bgid int) (uint, error) { 418 reg := &BufReg{ 419 Bgid: uint16(bgid), 420 } 421 result, err := ring.doRegister(UnregisterPbufRing, unsafe.Pointer(reg), 1) 422 runtime.KeepAlive(reg) 423 424 return result, err 425 } 426 427 // liburing: io_uring_register_sync_cancel - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_sync_cancel.3.en.html 428 func (ring *Ring) RegisterSyncCancel(reg *SyncCancelReg) (uint, error) { 429 return ring.doRegister(RegisterSyncCancel, unsafe.Pointer(reg), 1) 430 } 431 432 // liburing: io_uring_register_file_alloc_range - https://manpages.debian.org/unstable/liburing-dev/io_uring_register_file_alloc_range.3.en.html 433 func (ring *Ring) RegisterFileAllocRange(off, length uint32) (uint, error) { 434 fileRange := &FileIndexRange{ 435 Off: off, 436 Len: length, 437 } 438 439 result, err := ring.doRegister(RegisterFileAllocRange, unsafe.Pointer(fileRange), 0) 440 runtime.KeepAlive(fileRange) 441 442 return result, err 443 }