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
#ifndef _NXD_LIBGOLANG_TIME_H
#define _NXD_LIBGOLANG_TIME_H
// Copyright (C) 2019-2024 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
// Package time mirrors Go package time.
//
// - `now` returns current time.
// - `sleep` pauses current task.
// - `Ticker` and `Timer` provide timers integrated with channels.
// - `tick`, `after` and `after_func` are convenience wrappers to use
// tickers and timers easily.
//
// See also https://golang.org/pkg/time for Go time package documentation.
//
//
// C-level API
//
// Subset of time package functionality is also provided via C-level API:
//
// - `_tasknanosleep` pauses current task.
// - `_nanotime` returns current time.
#include <golang/libgolang.h>
#include <golang/sync.h>
// ---- C-level API ----
#ifdef __cplusplus
namespace golang {
namespace time {
extern "C" {
#endif
LIBGOLANG_API void _tasknanosleep(uint64_t dt);
LIBGOLANG_API uint64_t _nanotime(void);
#ifdef __cplusplus
}}} // golang::time:: "C"
#endif
// ---- C++ API ----
#ifdef __cplusplus
// golang::time::
namespace golang {
namespace time {
// golang/pyx/c++ - the same as std python - represents time as float
constexpr double second = 1.0;
constexpr double nanosecond = 1E-9 * second;
constexpr double microsecond = 1E-6 * second;
constexpr double millisecond = 1E-3 * second;
constexpr double minute = 60 * second;
constexpr double hour = 60 * minute;
// sleep pauses current goroutine for at least dt seconds.
LIBGOLANG_API void sleep(double dt);
// now returns current time in seconds.
LIBGOLANG_API double now();
typedef refptr<struct _Ticker> Ticker;
typedef refptr<struct _Timer> Timer;
// tick returns channel connected to dt ticker.
//
// Note: there is no way to stop created ticker.
// Note: for dt <= 0, contrary to Ticker, tick returns nil channel instead of panicking.
LIBGOLANG_API chan<double> tick(double dt);
// after returns channel connected to dt timer.
//
// Note: with after there is no way to stop/garbage-collect created timer until it fires.
LIBGOLANG_API chan<double> after(double dt);
// after_func arranges to call f after dt time.
//
// The function will be called in its own goroutine.
// Returned timer can be used to cancel the call.
LIBGOLANG_API Timer after_func(double dt, func<void()> f);
// new_ticker creates new Ticker that will be firing at dt intervals.
LIBGOLANG_API Ticker new_ticker(double dt);
// Ticker arranges for time events to be sent to .c channel on dt-interval basis.
//
// If the receiver is slow, Ticker does not queue events and skips them.
// Ticking can be canceled via .stop() .
struct _Ticker : object {
chan<double> c;
private:
double _dt;
sync::Mutex _mu;
bool _stop;
Timer _timer;
// don't new - create only via new_ticker()
private:
_Ticker();
~_Ticker();
friend Ticker LIBGOLANG_API new_ticker(double dt);
public:
LIBGOLANG_API void decref();
public:
// stop cancels the ticker.
//
// It is guaranteed that ticker channel is empty after stop completes.
LIBGOLANG_API void stop();
private:
void _tick();
};
// new_timer creates new Timer that will fire after dt.
LIBGOLANG_API Timer new_timer(double dt);
// Timer arranges for time event to be sent to .c channel after dt time.
//
// The timer can be stopped (.stop), or reinitialized to another time (.reset).
struct _Timer : object {
chan<double> c;
// don't new - create only via new_timer() & co
private:
_Timer();
~_Timer();
friend Timer _new_timer(double dt, func<void()> f);
friend class _TimerImpl;
public:
LIBGOLANG_API void decref();
public:
// stop cancels the timer.
//
// It returns:
//
// False: the timer was already expired or stopped,
// True: the timer was armed and canceled by this stop call.
//
// Note: contrary to Go version, there is no need to drain timer channel
// after stop call - it is guaranteed that after stop the channel is empty.
//
// Note: similarly to Go, if Timer is used with function - it is not
// guaranteed that after stop the function is not running - in such case
// the caller must explicitly synchronize with that function to complete.
LIBGOLANG_API bool stop();
// reset rearms the timer.
//
// the timer must be either already stopped or expired.
LIBGOLANG_API void reset(double dt);
};
}} // golang::time::
#endif // __cplusplus
#endif // _NXD_LIBGOLANG_TIME_H