line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* |
2
|
|
|
|
|
|
|
* This software is copyright (c) 2010 by Leon Timmermans . |
3
|
|
|
|
|
|
|
* |
4
|
|
|
|
|
|
|
* This is free software; you can redistribute it and/or modify it under |
5
|
|
|
|
|
|
|
* the same terms as perl itself. |
6
|
|
|
|
|
|
|
* |
7
|
|
|
|
|
|
|
*/ |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#define PERL_NO_GET_CONTEXT |
10
|
|
|
|
|
|
|
#define PERL_REENTR_API 1 |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
#include "EXTERN.h" |
13
|
|
|
|
|
|
|
#include "perl.h" |
14
|
|
|
|
|
|
|
#include "XSUB.h" |
15
|
|
|
|
|
|
|
#define NEED_mg_findext |
16
|
|
|
|
|
|
|
#include "ppport.h" |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
#include |
19
|
|
|
|
|
|
|
#include |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#define die_sys(format) Perl_croak(aTHX_ format, strerror(errno)) |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
typedef struct { const char* key; STRLEN key_length; clockid_t value; } map[]; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
static map clocks = { |
26
|
|
|
|
|
|
|
{ STR_WITH_LEN("realtime") , CLOCK_REALTIME } |
27
|
|
|
|
|
|
|
#ifdef CLOCK_REALTIME_COARSE |
28
|
|
|
|
|
|
|
, { STR_WITH_LEN("realtime_coarse"), CLOCK_REALTIME_COARSE } |
29
|
|
|
|
|
|
|
#endif |
30
|
|
|
|
|
|
|
#ifdef CLOCK_REALTIME_ALARM |
31
|
|
|
|
|
|
|
, { STR_WITH_LEN("realtime_alarm"), CLOCK_REALTIME_ALARM } |
32
|
|
|
|
|
|
|
#endif |
33
|
|
|
|
|
|
|
#ifdef CLOCK_MONOTONIC |
34
|
|
|
|
|
|
|
, { STR_WITH_LEN("monotonic"), CLOCK_MONOTONIC } |
35
|
|
|
|
|
|
|
#elif defined CLOCK_HIGHRES |
36
|
|
|
|
|
|
|
, { STR_WITH_LEN("monotonic"), CLOCK_HIGHRES } |
37
|
|
|
|
|
|
|
#endif |
38
|
|
|
|
|
|
|
#ifdef CLOCK_MONOTONIC_RAW |
39
|
|
|
|
|
|
|
, { STR_WITH_LEN("monotonic_raw"), CLOCK_MONOTONIC_RAW } |
40
|
|
|
|
|
|
|
#endif |
41
|
|
|
|
|
|
|
#ifdef CLOCK_MONOTONIC_COARSE |
42
|
|
|
|
|
|
|
, { STR_WITH_LEN("monotonic_coarse"), CLOCK_MONOTONIC_COARSE } |
43
|
|
|
|
|
|
|
#endif |
44
|
|
|
|
|
|
|
#ifdef CLOCK_PROCESS_CPUTIME_ID |
45
|
|
|
|
|
|
|
, { STR_WITH_LEN("process"), CLOCK_PROCESS_CPUTIME_ID } |
46
|
|
|
|
|
|
|
#elif defined CLOCK_PROF |
47
|
|
|
|
|
|
|
, { STR_WITH_LEN("process"), CLOCK_PROF } |
48
|
|
|
|
|
|
|
#endif |
49
|
|
|
|
|
|
|
#ifdef CLOCK_THREAD_CPUTIME_ID |
50
|
|
|
|
|
|
|
, { STR_WITH_LEN("thread"), CLOCK_THREAD_CPUTIME_ID } |
51
|
|
|
|
|
|
|
#endif |
52
|
|
|
|
|
|
|
#ifdef CLOCK_UPTIME |
53
|
|
|
|
|
|
|
, { STR_WITH_LEN("uptime"), CLOCK_UPTIME } |
54
|
|
|
|
|
|
|
#endif |
55
|
|
|
|
|
|
|
#ifdef CLOCK_BOOTTIME |
56
|
|
|
|
|
|
|
, { STR_WITH_LEN("boottime"), CLOCK_BOOTTIME } |
57
|
|
|
|
|
|
|
#endif |
58
|
|
|
|
|
|
|
#ifdef CLOCK_BOOTTIME_ALARM |
59
|
|
|
|
|
|
|
, { STR_WITH_LEN("boottime_alarm"), CLOCK_BOOTTIME_ALARM } |
60
|
|
|
|
|
|
|
#endif |
61
|
|
|
|
|
|
|
#ifdef CLOCK_VIRTUAL |
62
|
|
|
|
|
|
|
, { STR_WITH_LEN("virtual"), CLOCK_VIRTUAL } |
63
|
|
|
|
|
|
|
#endif |
64
|
|
|
|
|
|
|
#ifdef CLOCK_TAI |
65
|
|
|
|
|
|
|
, { STR_WITH_LEN("tai"), CLOCK_TAI } |
66
|
|
|
|
|
|
|
#endif |
67
|
|
|
|
|
|
|
}; |
68
|
|
|
|
|
|
|
|
69
|
4
|
|
|
|
|
|
static clockid_t S_get_clockid(pTHX_ SV* clock_name) { |
70
|
|
|
|
|
|
|
int i; |
71
|
|
|
|
|
|
|
STRLEN length; |
72
|
4
|
50
|
|
|
|
|
const char* clock_ptr = SvPV(clock_name, length); |
73
|
7
|
50
|
|
|
|
|
for (i = 0; i < sizeof clocks / sizeof *clocks; ++i) { |
74
|
7
|
100
|
|
|
|
|
if (clocks[i].key_length == length && strEQ(clock_ptr, clocks[i].key)) |
|
|
50
|
|
|
|
|
|
75
|
4
|
|
|
|
|
|
return clocks[i].value; |
76
|
|
|
|
|
|
|
} |
77
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "No such timer '%s' known", clock_name); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
#define get_clockid(name) S_get_clockid(aTHX_ name) |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
#define NANO_SECONDS 1000000000 |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
static NV timespec_to_nv(struct timespec* time) { |
84
|
1
|
|
|
|
|
|
return time->tv_sec + time->tv_nsec / (double)NANO_SECONDS; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
static void nv_to_timespec(NV input, struct timespec* output) { |
88
|
11
|
|
|
|
|
|
output->tv_sec = (time_t) floor(input); |
89
|
6
|
|
|
|
|
|
output->tv_nsec = (long) ((input - output->tv_sec) * NANO_SECONDS); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
4
|
|
|
|
|
|
static int timer_destroy(pTHX_ SV* var, MAGIC* magic) { |
93
|
4
|
50
|
|
|
|
|
if (timer_delete(*(timer_t*)magic->mg_ptr)) |
94
|
0
|
|
|
|
|
|
die_sys("Can't delete timer: %s"); |
95
|
4
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
static const MGVTBL timer_magic = { NULL, NULL, NULL, NULL, timer_destroy }; |
98
|
|
|
|
|
|
|
|
99
|
2
|
|
|
|
|
|
static MAGIC* S_get_magic(pTHX_ SV* ref, const char* funcname, const MGVTBL* vtbl) { |
100
|
|
|
|
|
|
|
SV* value; |
101
|
|
|
|
|
|
|
MAGIC* magic; |
102
|
1
|
50
|
|
|
|
|
if (!SvROK(ref) || !(value = SvRV(ref)) || !SvMAGICAL(value) || (magic = mg_findext(value, PERL_MAGIC_ext, vtbl)) == NULL) |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "Could not %s: this variable is not a timer", funcname); |
104
|
1
|
|
|
|
|
|
return magic; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
#define get_magic(ref, funcname, vtbl) S_get_magic(aTHX_ ref, funcname, vtbl) |
107
|
|
|
|
|
|
|
#define get_timer(ref, funcname) (*(timer_t*)get_magic(ref, funcname, &timer_magic)->mg_ptr) |
108
|
|
|
|
|
|
|
|
109
|
28
|
|
|
|
|
|
static clockid_t S_get_clock(pTHX_ SV* ref, const char* funcname) { |
110
|
|
|
|
|
|
|
SV* value; |
111
|
14
|
50
|
|
|
|
|
if (!SvROK(ref) || !(value = SvRV(ref))) |
|
|
50
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "Could not %s: this variable is not a clock", funcname); |
113
|
14
|
50
|
|
|
|
|
return SvUV(value); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
#define get_clock(ref, func) S_get_clock(aTHX_ ref, func) |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
#if defined(SIGEV_THREAD_ID) && defined(SYS_gettid) |
118
|
|
|
|
|
|
|
#include |
119
|
|
|
|
|
|
|
#define gettid() syscall(SYS_gettid) |
120
|
|
|
|
|
|
|
#ifndef sigev_notify_thread_id |
121
|
|
|
|
|
|
|
#define sigev_notify_thread_id _sigev_un._tid |
122
|
|
|
|
|
|
|
#endif |
123
|
|
|
|
|
|
|
#endif |
124
|
|
|
|
|
|
|
|
125
|
4
|
|
|
|
|
|
static SV* S_create_clock(pTHX_ clockid_t clockid, SV* class) { |
126
|
|
|
|
|
|
|
SV *tmp, *retval; |
127
|
4
|
|
|
|
|
|
tmp = newSViv(clockid); |
128
|
4
|
|
|
|
|
|
retval = newRV_noinc(tmp); |
129
|
4
|
|
|
|
|
|
sv_bless(retval, gv_stashsv(class, 0)); |
130
|
4
|
|
|
|
|
|
SvREADONLY_on(tmp); |
131
|
4
|
|
|
|
|
|
return retval; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
#define create_clock(clockid, class) S_create_clock(aTHX_ clockid, class) |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
#if defined(_POSIX_CLOCK_SELECTION) && _POSIX_CLOCK_SELECTION >= 0 |
136
|
5
|
|
|
|
|
|
static int my_clock_nanosleep(pTHX_ clockid_t clockid, int flags, const struct timespec* request, struct timespec* remain) { |
137
|
|
|
|
|
|
|
int ret; |
138
|
5
|
|
|
|
|
|
ret = clock_nanosleep(clockid, flags, request, remain); |
139
|
5
|
100
|
|
|
|
|
if (ret != 0) { |
140
|
2
|
|
|
|
|
|
errno = ret; |
141
|
2
|
50
|
|
|
|
|
if (ret != EINTR) |
142
|
0
|
|
|
|
|
|
die_sys("Could not sleep: %s"); |
143
|
|
|
|
|
|
|
} |
144
|
5
|
|
|
|
|
|
return ret; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
#endif |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
#define clock_nanosleep(clockid, flags, request, remain) my_clock_nanosleep(aTHX_ clockid, flags, request, remain) |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
#if defined(USE_ITHREADS) && defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME >= 0 |
151
|
|
|
|
|
|
|
static pthread_t* S_get_pthread(pTHX_ SV* thread_handle) { |
152
|
|
|
|
|
|
|
SV* tmp; |
153
|
|
|
|
|
|
|
pthread_t* ret; |
154
|
|
|
|
|
|
|
dSP; |
155
|
|
|
|
|
|
|
ENTER; |
156
|
|
|
|
|
|
|
SAVETMPS; |
157
|
|
|
|
|
|
|
PUSHMARK(SP); |
158
|
|
|
|
|
|
|
PUSHs(thread_handle); |
159
|
|
|
|
|
|
|
PUTBACK; |
160
|
|
|
|
|
|
|
call_method("_handle", G_SCALAR); |
161
|
|
|
|
|
|
|
SPAGAIN; |
162
|
|
|
|
|
|
|
tmp = POPs; |
163
|
|
|
|
|
|
|
ret = INT2PTR(pthread_t* ,SvUV(tmp)); |
164
|
|
|
|
|
|
|
FREETMPS; |
165
|
|
|
|
|
|
|
LEAVE; |
166
|
|
|
|
|
|
|
return ret; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
#define get_pthread(handle) S_get_pthread(aTHX_ handle) |
169
|
|
|
|
|
|
|
#endif |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
#define undef &PL_sv_undef |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
typedef struct _timer_init { |
174
|
|
|
|
|
|
|
clockid_t clockid; |
175
|
|
|
|
|
|
|
IV signo; |
176
|
|
|
|
|
|
|
IV ident; |
177
|
|
|
|
|
|
|
struct itimerspec itimer; |
178
|
|
|
|
|
|
|
int flags; |
179
|
|
|
|
|
|
|
} timer_init; |
180
|
|
|
|
|
|
|
|
181
|
4
|
|
|
|
|
|
static void S_timer_args(pTHX_ timer_init* para, SV** begin, Size_t items) { |
182
|
|
|
|
|
|
|
int i; |
183
|
15
|
100
|
|
|
|
|
for(i = 0; i < items; i += 2) { |
184
|
|
|
|
|
|
|
const char* current; |
185
|
|
|
|
|
|
|
STRLEN curlen; |
186
|
11
|
|
|
|
|
|
SV *key = begin[i], *value = begin[i+1]; |
187
|
11
|
50
|
|
|
|
|
current = SvPV(key, curlen); |
188
|
11
|
100
|
|
|
|
|
if (curlen == 5) { |
189
|
6
|
100
|
|
|
|
|
if (strEQ(current, "clock")) |
190
|
1
|
50
|
|
|
|
|
para->clockid = SvROK(value) ? get_clock(value, "create timer") : get_clockid(value); |
191
|
5
|
100
|
|
|
|
|
else if (strEQ(current, "value")) |
192
|
4
|
50
|
|
|
|
|
nv_to_timespec(SvNV(value), ¶->itimer.it_value); |
193
|
1
|
50
|
|
|
|
|
else if (strEQ(current, "ident")) |
194
|
1
|
50
|
|
|
|
|
para->ident = SvIV(value); |
195
|
|
|
|
|
|
|
else |
196
|
|
|
|
|
|
|
goto fail; |
197
|
|
|
|
|
|
|
} |
198
|
5
|
100
|
|
|
|
|
else if (curlen == 6 && strEQ(current, "signal")) |
|
|
50
|
|
|
|
|
|
199
|
4
|
50
|
|
|
|
|
para->signo = (SvIOK(value) || looks_like_number(value)) ? SvIV(value) : whichsig(SvPV_nolen(value)); |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
200
|
1
|
50
|
|
|
|
|
else if (curlen == 8) { |
201
|
1
|
50
|
|
|
|
|
if (strEQ(current, "interval")) |
202
|
1
|
50
|
|
|
|
|
nv_to_timespec(SvNV(value), ¶->itimer.it_interval); |
203
|
0
|
0
|
|
|
|
|
else if (strEQ(current, "absolute")) |
204
|
0
|
|
|
|
|
|
para->flags |= TIMER_ABSTIME; |
205
|
|
|
|
|
|
|
else |
206
|
|
|
|
|
|
|
goto fail; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
else |
209
|
0
|
|
|
|
|
|
fail: Perl_croak(aTHX_ "Unknown option '%s'", current); |
210
|
|
|
|
|
|
|
} |
211
|
4
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
#define timer_args(para, begin, items) S_timer_args(aTHX_ para, begin, items) |
213
|
|
|
|
|
|
|
|
214
|
4
|
|
|
|
|
|
static SV* S_timer_instantiate(pTHX_ timer_init* para, const char* class, Size_t classlength) { |
215
|
|
|
|
|
|
|
timer_t* timer; |
216
|
4
|
|
|
|
|
|
struct sigevent event = { 0 }; |
217
|
|
|
|
|
|
|
SV *tmp, *retval; |
218
|
|
|
|
|
|
|
MAGIC* mg; |
219
|
|
|
|
|
|
|
|
220
|
4
|
50
|
|
|
|
|
if (para->signo < 0) |
221
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "No valid signal was given"); |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
#ifdef gettid |
224
|
|
|
|
|
|
|
event.sigev_notify = SIGEV_THREAD_ID; |
225
|
|
|
|
|
|
|
event.sigev_notify_thread_id = gettid(); |
226
|
|
|
|
|
|
|
#else |
227
|
|
|
|
|
|
|
event.sigev_notify = SIGEV_SIGNAL; |
228
|
|
|
|
|
|
|
#endif |
229
|
4
|
|
|
|
|
|
event.sigev_signo = para->signo; |
230
|
4
|
|
|
|
|
|
event.sigev_value.sival_int = para->ident; |
231
|
|
|
|
|
|
|
|
232
|
4
|
|
|
|
|
|
Newx(timer, 1, timer_t); |
233
|
|
|
|
|
|
|
|
234
|
4
|
50
|
|
|
|
|
if (timer_create(para->clockid, &event, timer) < 0) { |
235
|
0
|
|
|
|
|
|
Safefree(timer); |
236
|
0
|
|
|
|
|
|
die_sys("Couldn't create timer: %s"); |
237
|
|
|
|
|
|
|
} |
238
|
4
|
50
|
|
|
|
|
if (timer_settime(*timer, para->flags, ¶->itimer, NULL) < 0) |
239
|
0
|
|
|
|
|
|
die_sys("Couldn't set_time: %s"); |
240
|
|
|
|
|
|
|
|
241
|
4
|
|
|
|
|
|
tmp = newSV(0); |
242
|
4
|
|
|
|
|
|
retval = sv_2mortal(sv_bless(newRV_noinc(tmp), gv_stashpvn(class, classlength, 0))); |
243
|
4
|
|
|
|
|
|
SvREADONLY_on(tmp); |
244
|
|
|
|
|
|
|
|
245
|
4
|
|
|
|
|
|
mg = sv_magicext(tmp, NULL, PERL_MAGIC_ext, &timer_magic, (const char*)timer, 0); |
246
|
4
|
|
|
|
|
|
mg->mg_len = sizeof *timer; |
247
|
4
|
|
|
|
|
|
return retval; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
#define timer_instantiate(para, class, classlen) S_timer_instantiate(aTHX_ para, class, classlen) |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
MODULE = POSIX::RT::Timer PACKAGE = POSIX::RT::Timer |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
PROTOTYPES: DISABLED |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
void new(class, ...) |
256
|
|
|
|
|
|
|
SV* class; |
257
|
|
|
|
|
|
|
PREINIT: |
258
|
|
|
|
|
|
|
const char* class_str; |
259
|
|
|
|
|
|
|
Size_t length; |
260
|
|
|
|
|
|
|
PPCODE: |
261
|
3
|
50
|
|
|
|
|
class_str = SvPV(class, length); |
262
|
3
|
|
|
|
|
|
timer_init para = { CLOCK_REALTIME, 0, 0, 0, 0}; |
263
|
3
|
|
|
|
|
|
timer_args(¶, SP + 2, items - 1); |
264
|
3
|
|
|
|
|
|
PUSHs(timer_instantiate(¶, class_str, length)); |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
UV |
267
|
|
|
|
|
|
|
handle(self) |
268
|
|
|
|
|
|
|
SV* self; |
269
|
|
|
|
|
|
|
CODE: |
270
|
0
|
|
|
|
|
|
RETVAL = (UV)get_timer(self, "id"); |
271
|
|
|
|
|
|
|
OUTPUT: |
272
|
|
|
|
|
|
|
RETVAL |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
void |
275
|
|
|
|
|
|
|
get_timeout(self) |
276
|
|
|
|
|
|
|
SV* self; |
277
|
|
|
|
|
|
|
PREINIT: |
278
|
|
|
|
|
|
|
timer_t timer; |
279
|
|
|
|
|
|
|
struct itimerspec value; |
280
|
|
|
|
|
|
|
PPCODE: |
281
|
0
|
|
|
|
|
|
timer = get_timer(self, "get_timeout"); |
282
|
0
|
0
|
|
|
|
|
if (timer_gettime(timer, &value) == -1) |
283
|
0
|
|
|
|
|
|
die_sys("Couldn't get_time: %s"); |
284
|
0
|
0
|
|
|
|
|
mXPUSHn(timespec_to_nv(&value.it_value)); |
285
|
0
|
0
|
|
|
|
|
if (GIMME_V == G_ARRAY) |
|
|
0
|
|
|
|
|
|
286
|
0
|
0
|
|
|
|
|
mXPUSHn(timespec_to_nv(&value.it_interval)); |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
void |
289
|
|
|
|
|
|
|
set_timeout(self, new_value, new_interval = 0, abstime = 0) |
290
|
|
|
|
|
|
|
SV* self; |
291
|
|
|
|
|
|
|
NV new_value; |
292
|
|
|
|
|
|
|
NV new_interval; |
293
|
|
|
|
|
|
|
IV abstime; |
294
|
|
|
|
|
|
|
PREINIT: |
295
|
|
|
|
|
|
|
timer_t timer; |
296
|
|
|
|
|
|
|
struct itimerspec new_itimer, old_itimer; |
297
|
|
|
|
|
|
|
PPCODE: |
298
|
1
|
|
|
|
|
|
timer = get_timer(self, "set_timeout"); |
299
|
|
|
|
|
|
|
nv_to_timespec(new_value, &new_itimer.it_value); |
300
|
|
|
|
|
|
|
nv_to_timespec(new_interval, &new_itimer.it_interval); |
301
|
1
|
50
|
|
|
|
|
if (timer_settime(timer, (abstime ? TIMER_ABSTIME : 0), &new_itimer, &old_itimer) == -1) |
302
|
0
|
|
|
|
|
|
die_sys("Couldn't set_time: %s"); |
303
|
1
|
50
|
|
|
|
|
mXPUSHn(timespec_to_nv(&old_itimer.it_value)); |
304
|
1
|
50
|
|
|
|
|
if (GIMME_V == G_ARRAY) |
|
|
50
|
|
|
|
|
|
305
|
0
|
0
|
|
|
|
|
mXPUSHn(timespec_to_nv(&old_itimer.it_interval)); |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
IV |
308
|
|
|
|
|
|
|
get_overrun(self) |
309
|
|
|
|
|
|
|
SV* self; |
310
|
|
|
|
|
|
|
PREINIT: |
311
|
|
|
|
|
|
|
timer_t timer; |
312
|
|
|
|
|
|
|
CODE: |
313
|
0
|
|
|
|
|
|
timer = get_timer(self, "get_overrun"); |
314
|
0
|
|
|
|
|
|
RETVAL = timer_getoverrun(timer); |
315
|
0
|
0
|
|
|
|
|
if (RETVAL == -1) |
316
|
0
|
|
|
|
|
|
die_sys("Couldn't get_overrun: %s"); |
317
|
|
|
|
|
|
|
OUTPUT: |
318
|
|
|
|
|
|
|
RETVAL |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
MODULE = POSIX::RT::Timer PACKAGE = POSIX::RT::Clock |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
PROTOTYPES: DISABLED |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
SV* |
325
|
|
|
|
|
|
|
new(class, ...) |
326
|
|
|
|
|
|
|
SV* class; |
327
|
|
|
|
|
|
|
PREINIT: |
328
|
|
|
|
|
|
|
clockid_t clockid; |
329
|
|
|
|
|
|
|
CODE: |
330
|
3
|
50
|
|
|
|
|
clockid = items > 1 ? get_clockid(ST(1)) : CLOCK_REALTIME; |
331
|
3
|
|
|
|
|
|
RETVAL = create_clock(clockid, class); |
332
|
|
|
|
|
|
|
OUTPUT: |
333
|
|
|
|
|
|
|
RETVAL |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
UV |
336
|
|
|
|
|
|
|
handle(self) |
337
|
|
|
|
|
|
|
SV* self; |
338
|
|
|
|
|
|
|
CODE: |
339
|
0
|
|
|
|
|
|
RETVAL = (UV)get_clock(self, "id"); |
340
|
|
|
|
|
|
|
OUTPUT: |
341
|
|
|
|
|
|
|
RETVAL |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
#if defined(_POSIX_CPUTIME) && _POSIX_CPUTIME >= 0 |
344
|
|
|
|
|
|
|
SV* |
345
|
|
|
|
|
|
|
get_cpuclock(class, pid = undef) |
346
|
|
|
|
|
|
|
SV* class; |
347
|
|
|
|
|
|
|
SV* pid; |
348
|
|
|
|
|
|
|
PREINIT: |
349
|
|
|
|
|
|
|
clockid_t clockid; |
350
|
|
|
|
|
|
|
CODE: |
351
|
1
|
50
|
|
|
|
|
if (SvOK(pid) && SvROK(pid) && sv_derived_from(pid, "threads")) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
352
|
|
|
|
|
|
|
#if defined(USE_ITHREADS) && defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME >= 0 |
353
|
|
|
|
|
|
|
pthread_t* handle = get_pthread(pid); |
354
|
|
|
|
|
|
|
if (pthread_getcpuclockid(*handle, &clockid) != 0) |
355
|
|
|
|
|
|
|
die_sys("Could not get cpuclock"); |
356
|
|
|
|
|
|
|
#else |
357
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "Can't get CPU time for threads"); |
358
|
|
|
|
|
|
|
#endif |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
else { |
361
|
1
|
50
|
|
|
|
|
if (clock_getcpuclockid(SvOK(pid) ? SvIV(pid) : 0, &clockid) != 0) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
362
|
0
|
|
|
|
|
|
die_sys("Could not get cpuclock"); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
1
|
|
|
|
|
|
RETVAL = create_clock(clockid, class); |
366
|
|
|
|
|
|
|
OUTPUT: |
367
|
|
|
|
|
|
|
RETVAL |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
#endif |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
void |
372
|
|
|
|
|
|
|
get_clocks(class) |
373
|
|
|
|
|
|
|
SV* class; |
374
|
|
|
|
|
|
|
PREINIT: |
375
|
|
|
|
|
|
|
size_t i; |
376
|
|
|
|
|
|
|
const size_t max = sizeof clocks / sizeof *clocks; |
377
|
|
|
|
|
|
|
PPCODE: |
378
|
12
|
100
|
|
|
|
|
for (i = 0; i < max; ++i) |
379
|
11
|
50
|
|
|
|
|
mXPUSHp(clocks[i].key, clocks[i].key_length); |
380
|
1
|
|
|
|
|
|
XSRETURN(max); |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
NV |
383
|
|
|
|
|
|
|
get_time(self) |
384
|
|
|
|
|
|
|
SV* self; |
385
|
|
|
|
|
|
|
PREINIT: |
386
|
|
|
|
|
|
|
clockid_t clockid; |
387
|
|
|
|
|
|
|
struct timespec time; |
388
|
|
|
|
|
|
|
CODE: |
389
|
8
|
|
|
|
|
|
clockid = get_clock(self, "get_time"); |
390
|
8
|
50
|
|
|
|
|
if (clock_gettime(clockid, &time) == -1) |
391
|
0
|
|
|
|
|
|
die_sys("Couldn't get time: %s"); |
392
|
|
|
|
|
|
|
RETVAL = timespec_to_nv(&time); |
393
|
|
|
|
|
|
|
OUTPUT: |
394
|
|
|
|
|
|
|
RETVAL |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
void |
397
|
|
|
|
|
|
|
set_time(self, frac_time) |
398
|
|
|
|
|
|
|
SV* self; |
399
|
|
|
|
|
|
|
NV frac_time; |
400
|
|
|
|
|
|
|
PREINIT: |
401
|
|
|
|
|
|
|
clockid_t clockid; |
402
|
|
|
|
|
|
|
struct timespec time; |
403
|
|
|
|
|
|
|
CODE: |
404
|
0
|
|
|
|
|
|
clockid = get_clock(self, "set_time"); |
405
|
|
|
|
|
|
|
nv_to_timespec(frac_time, &time); |
406
|
0
|
0
|
|
|
|
|
if (clock_settime(clockid, &time) == -1) |
407
|
0
|
|
|
|
|
|
die_sys("Couldn't set time: %s"); |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
NV |
410
|
|
|
|
|
|
|
get_resolution(self) |
411
|
|
|
|
|
|
|
SV* self; |
412
|
|
|
|
|
|
|
PREINIT: |
413
|
|
|
|
|
|
|
clockid_t clockid; |
414
|
|
|
|
|
|
|
struct timespec time; |
415
|
|
|
|
|
|
|
CODE: |
416
|
1
|
|
|
|
|
|
clockid = get_clock(self, "get_resolution"); |
417
|
1
|
50
|
|
|
|
|
if (clock_getres(clockid, &time) == -1) |
418
|
0
|
|
|
|
|
|
die_sys("Couldn't get resolution: %s"); |
419
|
|
|
|
|
|
|
RETVAL = timespec_to_nv(&time); |
420
|
|
|
|
|
|
|
OUTPUT: |
421
|
|
|
|
|
|
|
RETVAL |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
void |
424
|
|
|
|
|
|
|
timer(self, ...) |
425
|
|
|
|
|
|
|
SV* self; |
426
|
|
|
|
|
|
|
PPCODE: |
427
|
1
|
|
|
|
|
|
timer_init para = { CLOCK_REALTIME, 0, 0, 0, 0}; |
428
|
1
|
|
|
|
|
|
timer_args(¶, SP + 2, items - 1); |
429
|
1
|
|
|
|
|
|
para.clockid = get_clock(self, "timer"); |
430
|
1
|
|
|
|
|
|
PUSHs(timer_instantiate(¶, "POSIX::RT::Timer", 16)); |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
#if defined(_POSIX_CLOCK_SELECTION) && _POSIX_CLOCK_SELECTION >= 0 |
433
|
|
|
|
|
|
|
NV |
434
|
|
|
|
|
|
|
sleep(self, frac_time, abstime = 0) |
435
|
|
|
|
|
|
|
SV* self; |
436
|
|
|
|
|
|
|
NV frac_time; |
437
|
|
|
|
|
|
|
int abstime; |
438
|
|
|
|
|
|
|
PREINIT: |
439
|
|
|
|
|
|
|
clockid_t clockid; |
440
|
|
|
|
|
|
|
struct timespec sleep_time, remain_time; |
441
|
|
|
|
|
|
|
int flags; |
442
|
|
|
|
|
|
|
CODE: |
443
|
3
|
|
|
|
|
|
clockid = get_clock(self, "sleep"); |
444
|
3
|
|
|
|
|
|
flags = abstime ? TIMER_ABSTIME : 0; |
445
|
|
|
|
|
|
|
nv_to_timespec(frac_time, &sleep_time); |
446
|
|
|
|
|
|
|
|
447
|
3
|
100
|
|
|
|
|
if (clock_nanosleep(clockid, flags, &sleep_time, &remain_time) == EINTR) |
448
|
1
|
50
|
|
|
|
|
RETVAL = abstime ? frac_time : timespec_to_nv(&remain_time); |
449
|
|
|
|
|
|
|
else |
450
|
|
|
|
|
|
|
RETVAL = 0; |
451
|
|
|
|
|
|
|
OUTPUT: |
452
|
|
|
|
|
|
|
RETVAL |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
NV |
455
|
|
|
|
|
|
|
sleep_deeply(self, frac_time, abstime = 0) |
456
|
|
|
|
|
|
|
SV* self; |
457
|
|
|
|
|
|
|
NV frac_time; |
458
|
|
|
|
|
|
|
int abstime; |
459
|
|
|
|
|
|
|
PREINIT: |
460
|
|
|
|
|
|
|
clockid_t clockid; |
461
|
|
|
|
|
|
|
struct timespec sleep_time; |
462
|
|
|
|
|
|
|
NV real_time; |
463
|
|
|
|
|
|
|
CODE: |
464
|
1
|
|
|
|
|
|
clockid = get_clock(self, "sleep_deeply"); |
465
|
1
|
50
|
|
|
|
|
if (abstime) |
466
|
|
|
|
|
|
|
nv_to_timespec(frac_time, &sleep_time); |
467
|
|
|
|
|
|
|
else { |
468
|
1
|
50
|
|
|
|
|
if (clock_gettime(clockid, &sleep_time) == -1) |
469
|
0
|
|
|
|
|
|
die_sys("Couldn't get time: %s"); |
470
|
1
|
|
|
|
|
|
nv_to_timespec(timespec_to_nv(&sleep_time) + frac_time, &sleep_time); |
471
|
|
|
|
|
|
|
} |
472
|
2
|
100
|
|
|
|
|
while (clock_nanosleep(clockid, TIMER_ABSTIME, &sleep_time, NULL) == EINTR); |
473
|
|
|
|
|
|
|
RETVAL = 0; |
474
|
|
|
|
|
|
|
OUTPUT: |
475
|
|
|
|
|
|
|
RETVAL |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
#endif |