-
Notifications
You must be signed in to change notification settings - Fork 2
/
timer.go
154 lines (134 loc) · 3.05 KB
/
timer.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
// +build linux
package liblpc
import (
"golang.org/x/sys/unix"
"unsafe"
)
type ClockId int
const (
ClockRealtime ClockId = unix.CLOCK_REALTIME
ClockMonotonic ClockId = unix.CLOCK_MONOTONIC
)
const (
TmFdNonblock = unix.O_NONBLOCK
TmFdCloexec = unix.O_CLOEXEC
TmFdTimerAbstime = 1 << 0
)
type TimerOnTick func(*Timer)
type Timer struct {
*FdWatcher
clockId ClockId
readBuf []byte
onTick TimerOnTick
}
func NewTimerWatcher(loop EventLoop, clockId ClockId, onTick TimerOnTick) (*Timer, error) {
tfd, err := TimerFdCreate(clockId, TmFdNonblock|TmFdCloexec)
if err != nil {
return nil, err
}
tw := new(Timer)
tw.FdWatcher = NewFdWatcher(loop, int(tfd), tw)
tw.clockId = clockId
tw.readBuf = make([]byte, 8)
tw.onTick = onTick
tw.Loop().RunInLoop(func() {
tw.WantRead()
tw.Update(true)
})
return tw, nil
}
func (this *Timer) OnEvent(event EventSizeType) {
if event&Readable == 0 {
return
}
_, err := unix.Read(this.GetFd(), this.readBuf)
if err != nil {
if WOULDBLOCK(err) {
if this.WantRead() {
this.Update(true)
}
}
return
}
if this.onTick != nil {
this.onTick(this)
}
}
func (this *Timer) Stop() error {
return TimerFdSetTime(this.GetFd(),
TmFdTimerAbstime,
&ITimerSpec{},
nil)
}
func (this *Timer) StartTimer(delayMs int, intervalMs int) error {
now, err := ClockGetTime(this.clockId)
if err != nil {
return err
}
delaySec := now.Sec
delayNs := now.Nsec
if delayMs != 0 {
delayNs = int64(delayMs)*1e6 + now.Nsec
if delayNs >= 1e9 {
extSec := delayNs / 1e9
delaySec += extSec
delayNs = delayNs % 1e9
}
}
var intervalSec int64 = 0
var intervalNs int64 = 0
if intervalMs != 0 {
intervalSec = int64(0)
intervalNs = int64(intervalMs * 1e6)
if intervalNs >= 1e9 {
intervalSec = int64(intervalNs / 1e9)
intervalNs = intervalNs % 1e9
}
}
return TimerFdSetTime(this.GetFd(),
TmFdTimerAbstime,
&ITimerSpec{
ItInterval: unix.Timespec{
Sec: intervalSec,
Nsec: intervalNs,
},
ItValue: unix.Timespec{
Sec: delaySec,
Nsec: delayNs,
},
}, nil)
}
type ITimerSpec struct {
ItInterval unix.Timespec
ItValue unix.Timespec
}
func ClockGetTime(clockId ClockId) (*unix.Timespec, error) {
now := new(unix.Timespec)
_, _, err := unix.Syscall(unix.SYS_CLOCK_GETTIME, uintptr(clockId), uintptr(unsafe.Pointer(now)), 0)
if err != 0 {
return nil, err
}
return now, nil
}
func TimerFdCreate(clockId ClockId, flags int) (int, error) {
tmFd, _, err := unix.Syscall(unix.SYS_TIMERFD_CREATE, uintptr(clockId), uintptr(flags), 0)
if err != 0 {
return -1, err
}
return int(tmFd), nil
}
func TimerFdSetTime(fd int, flags int, new *ITimerSpec, old *ITimerSpec) error {
_, _, err := unix.Syscall6(unix.SYS_TIMERFD_SETTIME,
uintptr(fd), uintptr(flags), uintptr(unsafe.Pointer(new)), uintptr(unsafe.Pointer(old)), 0, 0)
if err != 0 {
return unix.Errno(err)
}
return nil
}
func TimerFdGetTime(fd int, curr *ITimerSpec) error {
_, _, err := unix.Syscall(unix.SYS_TIMERFD_GETTIME, uintptr(fd), uintptr(unsafe.Pointer(curr)), 0)
if err != 0 {
return err
}
return nil
}