… | |
… | |
170 | # define CORO_CLOCK_THREAD_CPUTIME_ID 3 |
170 | # define CORO_CLOCK_THREAD_CPUTIME_ID 3 |
171 | # endif |
171 | # endif |
172 | #endif |
172 | #endif |
173 | |
173 | |
174 | static double (*nvtime)(); /* so why doesn't it take void? */ |
174 | static double (*nvtime)(); /* so why doesn't it take void? */ |
|
|
175 | static void (*u2time)(pTHX_ UV ret[2]); |
175 | |
176 | |
176 | /* we hijack an hopefully unused CV flag for our purposes */ |
177 | /* we hijack an hopefully unused CV flag for our purposes */ |
177 | #define CVf_SLF 0x4000 |
178 | #define CVf_SLF 0x4000 |
178 | static OP *pp_slf (pTHX); |
179 | static OP *pp_slf (pTHX); |
179 | |
180 | |
… | |
… | |
204 | static CV *cv_pool_handler; |
205 | static CV *cv_pool_handler; |
205 | static CV *cv_coro_state_new; |
206 | static CV *cv_coro_state_new; |
206 | |
207 | |
207 | /* Coro::AnyEvent */ |
208 | /* Coro::AnyEvent */ |
208 | static SV *sv_activity; |
209 | static SV *sv_activity; |
|
|
210 | |
|
|
211 | /* enable processtime/realtime profiling */ |
|
|
212 | static char enable_times; |
|
|
213 | typedef U32 coro_ts[2]; |
|
|
214 | static coro_ts time_real, time_cpu; |
|
|
215 | static char times_valid; |
209 | |
216 | |
210 | static struct coro_cctx *cctx_first; |
217 | static struct coro_cctx *cctx_first; |
211 | static int cctx_count, cctx_idle; |
218 | static int cctx_count, cctx_idle; |
212 | |
219 | |
213 | enum { |
220 | enum { |
… | |
… | |
303 | |
310 | |
304 | /* on_enter/on_leave */ |
311 | /* on_enter/on_leave */ |
305 | AV *on_enter; |
312 | AV *on_enter; |
306 | AV *on_leave; |
313 | AV *on_leave; |
307 | |
314 | |
|
|
315 | /* times */ |
|
|
316 | coro_ts t_cpu, t_real; |
|
|
317 | |
308 | /* linked list */ |
318 | /* linked list */ |
309 | struct coro *next, *prev; |
319 | struct coro *next, *prev; |
310 | }; |
320 | }; |
311 | |
321 | |
312 | typedef struct coro *Coro__State; |
322 | typedef struct coro *Coro__State; |
… | |
… | |
376 | |
386 | |
377 | if (!cv) |
387 | if (!cv) |
378 | croak ("code reference expected"); |
388 | croak ("code reference expected"); |
379 | |
389 | |
380 | return cv; |
390 | return cv; |
|
|
391 | } |
|
|
392 | |
|
|
393 | INLINE void |
|
|
394 | coro_times_update () |
|
|
395 | { |
|
|
396 | #ifdef coro_clock_gettime |
|
|
397 | struct timespec ts; |
|
|
398 | |
|
|
399 | ts.tv_sec = ts.tv_nsec = 0; |
|
|
400 | coro_clock_gettime (CORO_CLOCK_THREAD_CPUTIME_ID, &ts); |
|
|
401 | time_cpu [0] = ts.tv_sec; time_cpu [1] = ts.tv_nsec; |
|
|
402 | |
|
|
403 | ts.tv_sec = ts.tv_nsec = 0; |
|
|
404 | coro_clock_gettime (CORO_CLOCK_MONOTONIC, &ts); |
|
|
405 | time_real [0] = ts.tv_sec; time_real [1] = ts.tv_nsec; |
|
|
406 | #else |
|
|
407 | UV tv[2]; |
|
|
408 | |
|
|
409 | u2time (aTHX_ &tv); |
|
|
410 | time_real [0] = tv [0]; |
|
|
411 | time_real [1] = tv [1] * 1000; |
|
|
412 | #endif |
|
|
413 | } |
|
|
414 | |
|
|
415 | INLINE void |
|
|
416 | coro_times_add (struct coro *c) |
|
|
417 | { |
|
|
418 | c->t_real [1] += time_real [1]; |
|
|
419 | if (c->t_real [1] > 1000000000) { c->t_real [1] -= 1000000000; ++c->t_real [0]; } |
|
|
420 | c->t_real [0] += time_real [0]; |
|
|
421 | |
|
|
422 | c->t_cpu [1] += time_cpu [1]; |
|
|
423 | if (c->t_cpu [1] > 1000000000) { c->t_cpu [1] -= 1000000000; ++c->t_cpu [0]; } |
|
|
424 | c->t_cpu [0] += time_cpu [0]; |
|
|
425 | } |
|
|
426 | |
|
|
427 | INLINE void |
|
|
428 | coro_times_sub (struct coro *c) |
|
|
429 | { |
|
|
430 | if (c->t_real [1] < time_real [1]) { c->t_real [1] += 1000000000; --c->t_real [0]; } |
|
|
431 | c->t_real [1] -= time_real [1]; |
|
|
432 | c->t_real [0] -= time_real [0]; |
|
|
433 | |
|
|
434 | if (c->t_cpu [1] < time_cpu [1]) { c->t_cpu [1] += 1000000000; --c->t_cpu [0]; } |
|
|
435 | c->t_cpu [1] -= time_cpu [1]; |
|
|
436 | c->t_cpu [0] -= time_cpu [0]; |
381 | } |
437 | } |
382 | |
438 | |
383 | /*****************************************************************************/ |
439 | /*****************************************************************************/ |
384 | /* magic glue */ |
440 | /* magic glue */ |
385 | |
441 | |
… | |
… | |
587 | } |
643 | } |
588 | |
644 | |
589 | slf_frame = c->slf_frame; |
645 | slf_frame = c->slf_frame; |
590 | CORO_THROW = c->except; |
646 | CORO_THROW = c->except; |
591 | |
647 | |
|
|
648 | if (expect_false (enable_times)) |
|
|
649 | { |
|
|
650 | if (expect_false (!times_valid)) |
|
|
651 | coro_times_update (); |
|
|
652 | |
|
|
653 | coro_times_sub (c); |
|
|
654 | } |
|
|
655 | |
592 | if (expect_false (c->on_enter)) |
656 | if (expect_false (c->on_enter)) |
593 | { |
657 | { |
594 | int i; |
658 | int i; |
595 | |
659 | |
596 | for (i = 0; i <= AvFILLp (c->on_enter); ++i) |
660 | for (i = 0; i <= AvFILLp (c->on_enter); ++i) |
… | |
… | |
605 | { |
669 | { |
606 | int i; |
670 | int i; |
607 | |
671 | |
608 | for (i = AvFILLp (c->on_leave); i >= 0; --i) |
672 | for (i = AvFILLp (c->on_leave); i >= 0; --i) |
609 | on_enterleave_call (aTHX_ AvARRAY (c->on_leave)[i]); |
673 | on_enterleave_call (aTHX_ AvARRAY (c->on_leave)[i]); |
|
|
674 | } |
|
|
675 | |
|
|
676 | times_valid = 0; |
|
|
677 | |
|
|
678 | if (expect_false (enable_times)) |
|
|
679 | { |
|
|
680 | coro_times_update (); times_valid = 1; |
|
|
681 | coro_times_add (c); |
610 | } |
682 | } |
611 | |
683 | |
612 | c->except = CORO_THROW; |
684 | c->except = CORO_THROW; |
613 | c->slf_frame = slf_frame; |
685 | c->slf_frame = slf_frame; |
614 | |
686 | |
… | |
… | |
978 | |
1050 | |
979 | PL_op = (OP *)&coro_setup_op; |
1051 | PL_op = (OP *)&coro_setup_op; |
980 | |
1052 | |
981 | /* copy throw, in case it was set before coro_setup */ |
1053 | /* copy throw, in case it was set before coro_setup */ |
982 | CORO_THROW = coro->except; |
1054 | CORO_THROW = coro->except; |
|
|
1055 | |
|
|
1056 | if (expect_false (enable_times)) |
|
|
1057 | { |
|
|
1058 | coro_times_update (); |
|
|
1059 | coro_times_sub (coro); |
|
|
1060 | } |
983 | } |
1061 | } |
984 | |
1062 | |
985 | static void |
1063 | static void |
986 | coro_unwind_stacks (pTHX) |
1064 | coro_unwind_stacks (pTHX) |
987 | { |
1065 | { |
… | |
… | |
2979 | |
3057 | |
2980 | if (!svp) croak ("Time::HiRes is required"); |
3058 | if (!svp) croak ("Time::HiRes is required"); |
2981 | if (!SvIOK (*svp)) croak ("Time::NVtime isn't a function pointer"); |
3059 | if (!SvIOK (*svp)) croak ("Time::NVtime isn't a function pointer"); |
2982 | |
3060 | |
2983 | nvtime = INT2PTR (double (*)(), SvIV (*svp)); |
3061 | nvtime = INT2PTR (double (*)(), SvIV (*svp)); |
|
|
3062 | |
|
|
3063 | svp = hv_fetch (PL_modglobal, "Time::U2time", 12, 0); |
|
|
3064 | u2time = INT2PTR (double (*)(), SvIV (*svp)); |
2984 | } |
3065 | } |
2985 | |
3066 | |
2986 | assert (("PRIO_NORMAL must be 0", !CORO_PRIO_NORMAL)); |
3067 | assert (("PRIO_NORMAL must be 0", !CORO_PRIO_NORMAL)); |
2987 | } |
3068 | } |
2988 | |
3069 | |
… | |
… | |
3262 | CODE: |
3343 | CODE: |
3263 | coro_state_destroy (aTHX_ self); |
3344 | coro_state_destroy (aTHX_ self); |
3264 | coro_call_on_destroy (aTHX_ self); /* actually only for Coro objects */ |
3345 | coro_call_on_destroy (aTHX_ self); /* actually only for Coro objects */ |
3265 | |
3346 | |
3266 | |
3347 | |
|
|
3348 | SV * |
|
|
3349 | enable_times (int enabled = enable_times) |
|
|
3350 | CODE: |
|
|
3351 | { |
|
|
3352 | RETVAL = boolSV (enable_times); |
|
|
3353 | |
|
|
3354 | if (enabled != enable_times) |
|
|
3355 | { |
|
|
3356 | enable_times = enabled; |
|
|
3357 | |
|
|
3358 | coro_times_update (); |
|
|
3359 | (enabled ? coro_times_sub : coro_times_add)(SvSTATE (coro_current)); |
|
|
3360 | } |
|
|
3361 | } |
|
|
3362 | OUTPUT: |
|
|
3363 | RETVAL |
|
|
3364 | |
|
|
3365 | void |
|
|
3366 | times (Coro::State self) |
|
|
3367 | PPCODE: |
|
|
3368 | { |
|
|
3369 | struct coro *current = SvSTATE (coro_current); |
|
|
3370 | |
|
|
3371 | if (expect_false (current == self)) |
|
|
3372 | { |
|
|
3373 | coro_times_update (); |
|
|
3374 | coro_times_add (SvSTATE (coro_current)); |
|
|
3375 | } |
|
|
3376 | |
|
|
3377 | EXTEND (SP, 2); |
|
|
3378 | PUSHs (sv_2mortal (newSVnv (self->t_real [0] + self->t_real [1] * 1e-9))); |
|
|
3379 | PUSHs (sv_2mortal (newSVnv (self->t_cpu [0] + self->t_cpu [1] * 1e-9))); |
|
|
3380 | |
|
|
3381 | if (expect_false (current == self)) |
|
|
3382 | coro_times_sub (SvSTATE (coro_current)); |
|
|
3383 | } |
|
|
3384 | |
3267 | MODULE = Coro::State PACKAGE = Coro |
3385 | MODULE = Coro::State PACKAGE = Coro |
3268 | |
3386 | |
3269 | BOOT: |
3387 | BOOT: |
3270 | { |
3388 | { |
3271 | sv_pool_rss = coro_get_sv (aTHX_ "Coro::POOL_RSS" , TRUE); |
3389 | sv_pool_rss = coro_get_sv (aTHX_ "Coro::POOL_RSS" , TRUE); |
… | |
… | |
3367 | if (items > 1) |
3485 | if (items > 1) |
3368 | { |
3486 | { |
3369 | if (ix) |
3487 | if (ix) |
3370 | newprio = coro->prio - newprio; |
3488 | newprio = coro->prio - newprio; |
3371 | |
3489 | |
3372 | if (newprio < PRIO_MIN) newprio = PRIO_MIN; |
3490 | if (newprio < CORO_PRIO_MIN) newprio = CORO_PRIO_MIN; |
3373 | if (newprio > PRIO_MAX) newprio = PRIO_MAX; |
3491 | if (newprio > CORO_PRIO_MAX) newprio = CORO_PRIO_MAX; |
3374 | |
3492 | |
3375 | coro->prio = newprio; |
3493 | coro->prio = newprio; |
3376 | } |
3494 | } |
3377 | } |
3495 | } |
3378 | OUTPUT: |
3496 | OUTPUT: |