-
Notifications
You must be signed in to change notification settings - Fork 43
/
link_request.go
94 lines (73 loc) · 2.26 KB
/
link_request.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//go:build linux
// +build linux
package iouring
import (
"errors"
"time"
"unsafe"
"golang.org/x/sys/unix"
iouring_syscall "github.com/iceber/iouring-go/syscall"
)
func (iour *IOURing) SubmitLinkRequests(requests []PrepRequest, ch chan<- Result) (RequestSet, error) {
return iour.submitLinkRequest(requests, ch, false)
}
func (iour *IOURing) SubmitHardLinkRequests(requests []PrepRequest, ch chan<- Result) (RequestSet, error) {
return iour.submitLinkRequest(requests, ch, true)
}
func (iour *IOURing) submitLinkRequest(requests []PrepRequest, ch chan<- Result, hard bool) (RequestSet, error) {
// TODO(iceber): no length limit
if len(requests) > int(*iour.sq.entries) {
return nil, errors.New("too many requests")
}
flags := iouring_syscall.IOSQE_FLAGS_IO_LINK
if hard {
flags = iouring_syscall.IOSQE_FLAGS_IO_HARDLINK
}
iour.submitLock.Lock()
defer iour.submitLock.Unlock()
if iour.IsClosed() {
return nil, ErrIOURingClosed
}
var sqeN uint32
userDatas := make([]*UserData, 0, len(requests))
for i := range requests {
sqe := iour.getSQEntry()
sqeN++
userData, err := iour.doRequest(sqe, requests[i], ch)
if err != nil {
iour.sq.fallback(sqeN)
return nil, err
}
userDatas = append(userDatas, userData)
sqe.CleanFlags(iouring_syscall.IOSQE_FLAGS_IO_HARDLINK | iouring_syscall.IOSQE_FLAGS_IO_LINK)
if i < len(requests)-1 {
sqe.SetFlags(flags)
}
}
// must be located before the lock operation to
// avoid the compiler's adjustment of the code order.
// issue: https://github.com/Iceber/iouring-go/issues/8
rset := newRequestSet(userDatas)
iour.userDataLock.Lock()
for _, data := range userDatas {
iour.userDatas[data.id] = data
}
iour.userDataLock.Unlock()
if _, err := iour.submit(); err != nil {
iour.userDataLock.Lock()
for _, data := range userDatas {
delete(iour.userDatas, data.id)
}
iour.userDataLock.Unlock()
return nil, err
}
return rset, nil
}
func linkTimeout(t time.Duration) PrepRequest {
timespec := unix.NsecToTimespec(t.Nanoseconds())
return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
userData.hold(×pec)
userData.request.resolver = timeoutResolver
sqe.PrepOperation(iouring_syscall.IORING_OP_LINK_TIMEOUT, -1, uint64(uintptr(unsafe.Pointer(×pec))), 1, 0)
}
}