forked from golangwrt/libubox
-
Notifications
You must be signed in to change notification settings - Fork 0
/
uloop_cgo.go
189 lines (159 loc) · 3.73 KB
/
uloop_cgo.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package libubox
/*
#cgo LDFLAGS: -lubox
#include <stdlib.h>
#include <libubox/uloop.h>
extern void uloop_fd_cb(struct uloop_fd* u, unsigned int events);
extern void uloop_timeout_cb(struct uloop_timeout* t);
*/
import "C"
import (
"fmt"
"os"
"sync"
"syscall"
"unsafe"
)
type UloopFDFlag int
const (
UloopRead UloopFDFlag = C.ULOOP_READ
UloopWrite UloopFDFlag = C.ULOOP_WRITE
UloopEdgeTrigger UloopFDFlag = C.ULOOP_EDGE_TRIGGER
UloopBlocking UloopFDFlag = C.ULOOP_BLOCKING
)
const (
UFDReadBufferSize = 4096
)
// UloopFDHandler encapsulates uloop_fd_handler
//
// typedef void (*uloop_fd_handler)(struct uloop_fd *u, unsigned int events)
type UloopFDHandler func(ufd *UloopFD, events uint)
type UFDReadElem struct {
Err error
Data []byte
N int
ptr *[]byte
}
// UloopFD encapsulates struct uloop_fd
type UloopFD struct {
ptr *C.struct_uloop_fd
H UloopFDHandler
}
var (
ufds struct {
Elem map[*C.struct_uloop_fd]*UloopFD
sync.RWMutex
}
ufdReadBufferPool = sync.Pool{
New: func() interface{} {
b := make([]byte, UFDReadBufferSize)
return &b
},
}
)
func init() {
ufds.Elem = make(map[*C.struct_uloop_fd]*UloopFD, 0)
}
func UloopInit() error {
_, err := C.uloop_init()
return err
}
func UloopRun() error {
_, err := C.uloop_run()
return err
}
// UloopEnd encapsualtes uloop_end
// set flag uloop_cancelled to true
func UloopEnd() error {
_, err := C.uloop_end()
return err
}
// Uloopdone encapsulates uloop_done
// do cleanup steps after uloop_run return
func UloopDone() error {
_, err := C.uloop_done()
return err
}
// NewUloopFD created an *UloopFD, and set the underlying
// UloopFDHandler (field H) to specified value
func NewUloopFD(fd int, h UloopFDHandler) *UloopFD {
ufd := &UloopFD{
H: h,
}
ufd.ptr = (*C.struct_uloop_fd)(C.calloc(1, C.sizeof_struct_uloop_fd))
ufd.ptr.cb = C.uloop_fd_handler(C.uloop_fd_cb)
ufd.ptr.fd = C.int(fd)
return ufd
}
// Add encapsulates uloop_fd_add
//
// int uloop_fd_add(struct uloop_fd *sock, unsigned int flags)
func (ufd *UloopFD) Add(flag UloopFDFlag) error {
ret, err := C.uloop_fd_add(ufd.ptr, C.uint(flag))
if err != nil {
return fmt.Errorf("ret: %d, %s", int(ret), err)
}
ufds.Lock()
ufds.Elem[ufd.ptr] = ufd
defer ufds.Unlock()
return nil
}
// Delete encapsualtes uloop_fd_delete
//
// int uloop_fd_delete(struct uloop_fd *sock)
func (ufd *UloopFD) Delete() error {
ret, err := C.uloop_fd_delete(ufd.ptr)
if err != nil {
return fmt.Errorf("ret: %d, %s", int(ret), err)
}
ufds.Lock()
delete(ufds.Elem, ufd.ptr)
ufds.Unlock()
syscall.Close(int(ufd.ptr.fd))
C.free(unsafe.Pointer(ufd.ptr))
ufd.ptr = nil
ufd.H = nil
return nil
}
func (elem *UFDReadElem) Free() {
if elem == nil || elem.ptr == nil {
return
}
ufdReadBufferPool.Put(elem.ptr)
}
// Read read from the underlying file descriptor
// this call may block if there is non data ready.
// after finished using UFDReadElem, it's Free method must be called,
// otherwise memory leak will be occurred
func (ufd *UloopFD) Read() *UFDReadElem {
buf := ufdReadBufferPool.Get().(*[]byte)
n, err := syscall.Read(int(ufd.ptr.fd), *buf)
return &UFDReadElem{
Data: (*buf)[:n],
Err: err,
N: n,
ptr: buf,
}
}
func (ufd *UloopFD) FD() int {
return int(ufd.ptr.fd)
}
func (ufd *UloopFD) Write(data []byte) (n int, err error) {
return syscall.Write(int(ufd.ptr.fd), data)
}
//export uloopFDHandlerProxy
func uloopFDHandlerProxy(ptr *C.struct_uloop_fd, events C.uint) {
ufds.RLock()
ufd, found := ufds.Elem[ptr]
ufds.RUnlock()
if !found {
fmt.Fprintf(os.Stderr, "non ufd found for uloop_fd %p, fd: %d\n", ptr, int(ptr.fd))
return
}
if ufd.H != nil {
ufd.H(ufd, uint(events))
}
}
//export uloopTimeoutHandlerProxy
func uloopTimeoutHandlerProxy(ptr *C.struct_uloop_timeout) {
}