ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/State.xs
(Generate patch)

Comparing Coro/Coro/State.xs (file contents):
Revision 1.269 by root, Fri Nov 14 06:50:11 2008 UTC vs.
Revision 1.280 by root, Sun Nov 16 09:43:18 2008 UTC

142#define NOINLINE attribute ((noinline)) 142#define NOINLINE attribute ((noinline))
143 143
144#include "CoroAPI.h" 144#include "CoroAPI.h"
145 145
146#ifdef USE_ITHREADS 146#ifdef USE_ITHREADS
147
148static perl_mutex coro_lock;
149# define LOCK do { MUTEX_LOCK (&coro_lock); } while (0)
150# define UNLOCK do { MUTEX_UNLOCK (&coro_lock); } while (0)
151# if CORO_PTHREAD 147# if CORO_PTHREAD
152static void *coro_thx; 148static void *coro_thx;
153# endif 149# endif
154
155#else
156
157# define LOCK (void)0
158# define UNLOCK (void)0
159
160#endif 150#endif
161
162# undef LOCK
163# define LOCK (void)0
164# undef UNLOCK
165# define UNLOCK (void)0
166 151
167/* helper storage struct for Coro::AIO */ 152/* helper storage struct for Coro::AIO */
168struct io_state 153struct io_state
169{ 154{
170 AV *res; 155 AV *res;
183static JMPENV *main_top_env; 168static JMPENV *main_top_env;
184static HV *coro_state_stash, *coro_stash; 169static HV *coro_state_stash, *coro_stash;
185static volatile SV *coro_mortal; /* will be freed/thrown after next transfer */ 170static volatile SV *coro_mortal; /* will be freed/thrown after next transfer */
186static volatile struct coro *transfer_next; 171static volatile struct coro *transfer_next;
187 172
188struct transfer_args
189{
190 struct coro *prev, *next;
191};
192
193static GV *irsgv; /* $/ */ 173static GV *irsgv; /* $/ */
194static GV *stdoutgv; /* *STDOUT */ 174static GV *stdoutgv; /* *STDOUT */
195static SV *rv_diehook; 175static SV *rv_diehook;
196static SV *rv_warnhook; 176static SV *rv_warnhook;
197static HV *hv_sig; /* %SIG */ 177static HV *hv_sig; /* %SIG */
215 CC_TRACE_LINE = 0x10, /* trace each statement */ 195 CC_TRACE_LINE = 0x10, /* trace each statement */
216 CC_TRACE_ALL = CC_TRACE_SUB | CC_TRACE_LINE, 196 CC_TRACE_ALL = CC_TRACE_SUB | CC_TRACE_LINE,
217}; 197};
218 198
219/* this is a structure representing a c-level coroutine */ 199/* this is a structure representing a c-level coroutine */
220typedef struct coro_cctx { 200typedef struct coro_cctx
201{
221 struct coro_cctx *next; 202 struct coro_cctx *next;
222 203
223 /* the stack */ 204 /* the stack */
224 void *sptr; 205 void *sptr;
225 size_t ssize; 206 size_t ssize;
243 CF_NEW = 0x0004, /* has never been switched to */ 224 CF_NEW = 0x0004, /* has never been switched to */
244 CF_DESTROYED = 0x0008, /* coroutine data has been freed */ 225 CF_DESTROYED = 0x0008, /* coroutine data has been freed */
245}; 226};
246 227
247/* the structure where most of the perl state is stored, overlaid on the cxstack */ 228/* the structure where most of the perl state is stored, overlaid on the cxstack */
248typedef struct { 229typedef struct
230{
249 SV *defsv; 231 SV *defsv;
250 AV *defav; 232 AV *defav;
251 SV *errsv; 233 SV *errsv;
252 SV *irsgv; 234 SV *irsgv;
253#define VAR(name,type) type name; 235#define VAR(name,type) type name;
257 239
258#define SLOT_COUNT ((sizeof (perl_slots) + sizeof (PERL_CONTEXT) - 1) / sizeof (PERL_CONTEXT)) 240#define SLOT_COUNT ((sizeof (perl_slots) + sizeof (PERL_CONTEXT) - 1) / sizeof (PERL_CONTEXT))
259 241
260/* this is a structure representing a perl-level coroutine */ 242/* this is a structure representing a perl-level coroutine */
261struct coro { 243struct coro {
262 /* the c coroutine allocated to this perl coroutine, if any */ 244 /* the C coroutine allocated to this perl coroutine, if any */
263 coro_cctx *cctx; 245 coro_cctx *cctx;
264 246
265 /* process data */ 247 /* process data */
248 struct CoroSLF slf_frame; /* saved slf frame */
266 AV *mainstack; 249 AV *mainstack;
267 perl_slots *slot; /* basically the saved sp */ 250 perl_slots *slot; /* basically the saved sp */
268 251
269 AV *args; /* data associated with this coroutine (initial args) */ 252 AV *args; /* data associated with this coroutine (initial args) */
270 int refcnt; /* coroutines are refcounted, yes */ 253 int refcnt; /* coroutines are refcounted, yes */
271 int flags; /* CF_ flags */ 254 int flags; /* CF_ flags */
272 HV *hv; /* the perl hash associated with this coro, if any */ 255 HV *hv; /* the perl hash associated with this coro, if any */
256 void (*on_destroy)(pTHX_ struct coro *coro);
273 257
274 /* statistics */ 258 /* statistics */
275 int usecount; /* number of transfers to this coro */ 259 int usecount; /* number of transfers to this coro */
276 260
277 /* coro process data */ 261 /* coro process data */
285 struct coro *next, *prev; 269 struct coro *next, *prev;
286}; 270};
287 271
288typedef struct coro *Coro__State; 272typedef struct coro *Coro__State;
289typedef struct coro *Coro__State_or_hashref; 273typedef struct coro *Coro__State_or_hashref;
274
275static struct CoroSLF slf_frame; /* the current slf frame */
290 276
291/** Coro ********************************************************************/ 277/** Coro ********************************************************************/
292 278
293#define PRIO_MAX 3 279#define PRIO_MAX 3
294#define PRIO_HIGH 1 280#define PRIO_HIGH 1
299 285
300/* for Coro.pm */ 286/* for Coro.pm */
301static SV *coro_current; 287static SV *coro_current;
302static SV *coro_readyhook; 288static SV *coro_readyhook;
303static AV *coro_ready [PRIO_MAX - PRIO_MIN + 1]; 289static AV *coro_ready [PRIO_MAX - PRIO_MIN + 1];
304static int coro_nready;
305static struct coro *coro_first; 290static struct coro *coro_first;
291#define coro_nready coroapi.nready
306 292
307/** lowlevel stuff **********************************************************/ 293/** lowlevel stuff **********************************************************/
308 294
309static SV * 295static SV *
310coro_get_sv (pTHX_ const char *name, int create) 296coro_get_sv (pTHX_ const char *name, int create)
514 CvPADLIST (cv) = (AV *)POPs; 500 CvPADLIST (cv) = (AV *)POPs;
515 } 501 }
516 502
517 PUTBACK; 503 PUTBACK;
518 } 504 }
505
506 slf_frame = c->slf_frame;
519} 507}
520 508
521static void 509static void
522save_perl (pTHX_ Coro__State c) 510save_perl (pTHX_ Coro__State c)
523{ 511{
512 c->slf_frame = slf_frame;
513
524 { 514 {
525 dSP; 515 dSP;
526 I32 cxix = cxstack_ix; 516 I32 cxix = cxstack_ix;
527 PERL_CONTEXT *ccstk = cxstack; 517 PERL_CONTEXT *ccstk = cxstack;
528 PERL_SI *top_si = PL_curstackinfo; 518 PERL_SI *top_si = PL_curstackinfo;
595 #undef VAR 585 #undef VAR
596 } 586 }
597} 587}
598 588
599/* 589/*
600 * allocate various perl stacks. This is an exact copy 590 * allocate various perl stacks. This is almost an exact copy
601 * of perl.c:init_stacks, except that it uses less memory 591 * of perl.c:init_stacks, except that it uses less memory
602 * on the (sometimes correct) assumption that coroutines do 592 * on the (sometimes correct) assumption that coroutines do
603 * not usually need a lot of stackspace. 593 * not usually need a lot of stackspace.
604 */ 594 */
605#if CORO_PREFER_PERL_FUNCTIONS 595#if CORO_PREFER_PERL_FUNCTIONS
712#endif 702#endif
713 } 703 }
714 } 704 }
715 705
716 return rss; 706 return rss;
717}
718
719/** set stacklevel support **************************************************/
720
721/* we sometimes need to create the effect of pp_slf calling us */
722#define SLF_HEAD (void)0
723/* we sometimes need to create the effect of leaving via pp_slf */
724#define SLF_TAIL slf_tail (aTHX)
725
726INLINE void
727slf_tail (pTHX)
728{
729 dSP;
730 SV **bot = SP;
731
732 int gimme = GIMME_V;
733
734 /* make sure we put something on the stack in scalar context */
735 if (gimme == G_SCALAR)
736 {
737 if (sp == bot)
738 XPUSHs (&PL_sv_undef);
739
740 SP = bot + 1;
741 }
742
743 PUTBACK;
744} 707}
745 708
746/** coroutine stack handling ************************************************/ 709/** coroutine stack handling ************************************************/
747 710
748static int (*orig_sigelem_get) (pTHX_ SV *sv, MAGIC *mg); 711static int (*orig_sigelem_get) (pTHX_ SV *sv, MAGIC *mg);
834 797
835 return orig_sigelem_set ? orig_sigelem_set (aTHX_ sv, mg) : 0; 798 return orig_sigelem_set ? orig_sigelem_set (aTHX_ sv, mg) : 0;
836} 799}
837 800
838static void 801static void
802prepare_nop (pTHX_ struct coro_transfer_args *ta)
803{
804 /* kind of mega-hacky, but works */
805 ta->next = ta->prev = (struct coro *)ta;
806}
807
808static int
809slf_check_nop (pTHX_ struct CoroSLF *frame)
810{
811 return 0;
812}
813
814static void
839coro_setup (pTHX_ struct coro *coro) 815coro_setup (pTHX_ struct coro *coro)
840{ 816{
841 /* 817 /*
842 * emulate part of the perl startup here. 818 * emulate part of the perl startup here.
843 */ 819 */
882 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); 858 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX);
883 SPAGAIN; 859 SPAGAIN;
884 } 860 }
885 861
886 /* this newly created coroutine might be run on an existing cctx which most 862 /* this newly created coroutine might be run on an existing cctx which most
887 * likely was suspended in set_stacklevel, called from pp_set_stacklevel, 863 * likely was suspended in pp_slf, so we have to emulate entering pp_slf here.
888 * so we have to emulate entering pp_set_stacklevel here.
889 */ 864 */
890 SLF_HEAD; 865 slf_frame.prepare = prepare_nop; /* provide a nop function for an eventual pp_slf */
866 slf_frame.check = slf_check_nop; /* signal pp_slf to not repeat */
891} 867}
892 868
893static void 869static void
894coro_destruct (pTHX_ struct coro *coro) 870coro_destruct (pTHX_ struct coro *coro)
895{ 871{
1059 TAINT_NOT; 1035 TAINT_NOT;
1060 return 0; 1036 return 0;
1061} 1037}
1062 1038
1063static void 1039static void
1064prepare_set_stacklevel (struct transfer_args *ta, struct coro_cctx *cctx) 1040prepare_set_stacklevel (struct coro_transfer_args *ta, struct coro_cctx *cctx)
1065{ 1041{
1066 ta->prev = (struct coro *)cctx; 1042 ta->prev = (struct coro *)cctx;
1067 ta->next = 0; 1043 ta->next = 0;
1068} 1044}
1069 1045
1103 struct coro *next = (struct coro *)transfer_next; 1079 struct coro *next = (struct coro *)transfer_next;
1104 assert (!(transfer_next = 0)); /* just used for the side effect when asserts are enabled */ 1080 assert (!(transfer_next = 0)); /* just used for the side effect when asserts are enabled */
1105 assert (("FATAL: next coroutine was zero in transfer_tail (please report)", next)); 1081 assert (("FATAL: next coroutine was zero in transfer_tail (please report)", next));
1106 1082
1107 free_coro_mortal (aTHX); 1083 free_coro_mortal (aTHX);
1108 UNLOCK;
1109 1084
1110 if (expect_false (next->throw)) 1085 if (expect_false (next->throw))
1111 { 1086 {
1112 SV *exception = sv_2mortal (next->throw); 1087 SV *exception = sv_2mortal (next->throw);
1113 1088
1129# endif 1104# endif
1130#endif 1105#endif
1131 { 1106 {
1132 dTHX; 1107 dTHX;
1133 1108
1134 /* we are the alternative tail to pp_set_stacklevel */ 1109 /* normally we would need to skip the entersub here */
1135 /* so do the same things here */ 1110 /* not doing so will re-execute it, which is exactly what we want */
1136 SLF_TAIL;
1137
1138 /* we now skip the op that did lead to transfer() */
1139 PL_op = PL_op->op_next; 1111 /* PL_nop = PL_nop->op_next */
1140 1112
1141 /* inject a fake subroutine call to cctx_init */ 1113 /* inject a fake subroutine call to cctx_init */
1142 cctx_prepare (aTHX_ (coro_cctx *)arg); 1114 cctx_prepare (aTHX_ (coro_cctx *)arg);
1143 1115
1144 /* cctx_run is the alternative tail of transfer() */ 1116 /* cctx_run is the alternative tail of transfer() */
1117 /* TODO: throwing an exception here might be deadly, VERIFY */
1145 transfer_tail (aTHX); 1118 transfer_tail (aTHX);
1146 1119
1147 /* somebody or something will hit me for both perl_run and PL_restartop */ 1120 /* somebody or something will hit me for both perl_run and PL_restartop */
1148 PL_restartop = PL_op; 1121 PL_restartop = PL_op;
1149 perl_run (PL_curinterp); 1122 perl_run (PL_curinterp);
1308transfer_check (pTHX_ struct coro *prev, struct coro *next) 1281transfer_check (pTHX_ struct coro *prev, struct coro *next)
1309{ 1282{
1310 if (expect_true (prev != next)) 1283 if (expect_true (prev != next))
1311 { 1284 {
1312 if (expect_false (!(prev->flags & (CF_RUNNING | CF_NEW)))) 1285 if (expect_false (!(prev->flags & (CF_RUNNING | CF_NEW))))
1313 croak ("Coro::State::transfer called with non-running/new prev Coro::State, but can only transfer from running or new states"); 1286 croak ("Coro::State::transfer called with non-running/new prev Coro::State, but can only transfer from running or new states,");
1314 1287
1315 if (expect_false (next->flags & CF_RUNNING)) 1288 if (expect_false (next->flags & CF_RUNNING))
1316 croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states"); 1289 croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states,");
1317 1290
1318 if (expect_false (next->flags & CF_DESTROYED)) 1291 if (expect_false (next->flags & CF_DESTROYED))
1319 croak ("Coro::State::transfer called with destroyed next Coro::State, but can only transfer to inactive states"); 1292 croak ("Coro::State::transfer called with destroyed next Coro::State, but can only transfer to inactive states,");
1320 1293
1321#if !PERL_VERSION_ATLEAST (5,10,0) 1294#if !PERL_VERSION_ATLEAST (5,10,0)
1322 if (expect_false (PL_lex_state != LEX_NOTPARSING)) 1295 if (expect_false (PL_lex_state != LEX_NOTPARSING))
1323 croak ("Coro::State::transfer called while parsing, but this is not supported in your perl version"); 1296 croak ("Coro::State::transfer called while parsing, but this is not supported in your perl version,");
1324#endif 1297#endif
1325 } 1298 }
1326} 1299}
1327 1300
1328/* always use the TRANSFER macro */ 1301/* always use the TRANSFER macro */
1332 dSTACKLEVEL; 1305 dSTACKLEVEL;
1333 1306
1334 /* sometimes transfer is only called to set idle_sp */ 1307 /* sometimes transfer is only called to set idle_sp */
1335 if (expect_false (!next)) 1308 if (expect_false (!next))
1336 { 1309 {
1337 ((coro_cctx *)prev)->idle_sp = stacklevel; 1310 ((coro_cctx *)prev)->idle_sp = (void *)stacklevel;
1338 assert (((coro_cctx *)prev)->idle_te = PL_top_env); /* just for the side-effect when asserts are enabled */ 1311 assert (((coro_cctx *)prev)->idle_te = PL_top_env); /* just for the side-effect when asserts are enabled */
1339 } 1312 }
1340 else if (expect_true (prev != next)) 1313 else if (expect_true (prev != next))
1341 { 1314 {
1342 coro_cctx *prev__cctx; 1315 coro_cctx *prev__cctx;
1349 prev->flags |= CF_RUNNING; 1322 prev->flags |= CF_RUNNING;
1350 } 1323 }
1351 1324
1352 prev->flags &= ~CF_RUNNING; 1325 prev->flags &= ~CF_RUNNING;
1353 next->flags |= CF_RUNNING; 1326 next->flags |= CF_RUNNING;
1354
1355 LOCK;
1356 1327
1357 /* first get rid of the old state */ 1328 /* first get rid of the old state */
1358 save_perl (aTHX_ prev); 1329 save_perl (aTHX_ prev);
1359 1330
1360 if (expect_false (next->flags & CF_NEW)) 1331 if (expect_false (next->flags & CF_NEW))
1369 1340
1370 prev__cctx = prev->cctx; 1341 prev__cctx = prev->cctx;
1371 1342
1372 /* possibly untie and reuse the cctx */ 1343 /* possibly untie and reuse the cctx */
1373 if (expect_true ( 1344 if (expect_true (
1374 prev__cctx->idle_sp == stacklevel 1345 prev__cctx->idle_sp == (void *)stacklevel
1375 && !(prev__cctx->flags & CC_TRACE) 1346 && !(prev__cctx->flags & CC_TRACE)
1376 && !force_cctx 1347 && !force_cctx
1377 )) 1348 ))
1378 { 1349 {
1379 /* I assume that stacklevel is a stronger indicator than PL_top_env changes */ 1350 /* I assume that stacklevel is a stronger indicator than PL_top_env changes */
1418coro_state_destroy (pTHX_ struct coro *coro) 1389coro_state_destroy (pTHX_ struct coro *coro)
1419{ 1390{
1420 if (coro->flags & CF_DESTROYED) 1391 if (coro->flags & CF_DESTROYED)
1421 return 0; 1392 return 0;
1422 1393
1394 if (coro->on_destroy)
1395 coro->on_destroy (aTHX_ coro);
1396
1423 coro->flags |= CF_DESTROYED; 1397 coro->flags |= CF_DESTROYED;
1424 1398
1425 if (coro->flags & CF_READY) 1399 if (coro->flags & CF_READY)
1426 { 1400 {
1427 /* reduce nready, as destroying a ready coro effectively unreadies it */ 1401 /* reduce nready, as destroying a ready coro effectively unreadies it */
1428 /* alternative: look through all ready queues and remove the coro */ 1402 /* alternative: look through all ready queues and remove the coro */
1429 LOCK;
1430 --coro_nready; 1403 --coro_nready;
1431 UNLOCK;
1432 } 1404 }
1433 else 1405 else
1434 coro->flags |= CF_READY; /* make sure it is NOT put into the readyqueue */ 1406 coro->flags |= CF_READY; /* make sure it is NOT put into the readyqueue */
1435 1407
1436 if (coro->mainstack && coro->mainstack != main_mainstack) 1408 if (coro->mainstack && coro->mainstack != main_mainstack)
1437 { 1409 {
1438 struct coro temp; 1410 struct coro temp;
1439 1411
1440 if (coro->flags & CF_RUNNING) 1412 assert (("FATAL: tried to destroy currently running coroutine (please report)", !(coro->flags & CF_RUNNING)));
1441 croak ("FATAL: tried to destroy currently running coroutine");
1442 1413
1443 save_perl (aTHX_ &temp); 1414 save_perl (aTHX_ &temp);
1444 load_perl (aTHX_ coro); 1415 load_perl (aTHX_ coro);
1445 1416
1446 coro_destruct (aTHX_ coro); 1417 coro_destruct (aTHX_ coro);
1497# define MGf_DUP 0 1468# define MGf_DUP 0
1498#endif 1469#endif
1499}; 1470};
1500 1471
1501static void 1472static void
1502prepare_transfer (pTHX_ struct transfer_args *ta, SV *prev_sv, SV *next_sv) 1473prepare_transfer (pTHX_ struct coro_transfer_args *ta, SV *prev_sv, SV *next_sv)
1503{ 1474{
1504 ta->prev = SvSTATE (prev_sv); 1475 ta->prev = SvSTATE (prev_sv);
1505 ta->next = SvSTATE (next_sv); 1476 ta->next = SvSTATE (next_sv);
1506 TRANSFER_CHECK (*ta); 1477 TRANSFER_CHECK (*ta);
1507} 1478}
1508 1479
1509static void 1480static void
1510api_transfer (SV *prev_sv, SV *next_sv) 1481api_transfer (pTHX_ SV *prev_sv, SV *next_sv)
1511{ 1482{
1512 dTHX;
1513 struct transfer_args ta; 1483 struct coro_transfer_args ta;
1514 1484
1515 prepare_transfer (aTHX_ &ta, prev_sv, next_sv); 1485 prepare_transfer (aTHX_ &ta, prev_sv, next_sv);
1516 TRANSFER (ta, 1); 1486 TRANSFER (ta, 1);
1517} 1487}
1518 1488
1535 1505
1536 return 0; 1506 return 0;
1537} 1507}
1538 1508
1539static int 1509static int
1540api_ready (SV *coro_sv) 1510api_ready (pTHX_ SV *coro_sv)
1541{ 1511{
1542 dTHX;
1543 struct coro *coro; 1512 struct coro *coro;
1544 SV *sv_hook; 1513 SV *sv_hook;
1545 void (*xs_hook)(void); 1514 void (*xs_hook)(void);
1546 1515
1547 if (SvROK (coro_sv)) 1516 if (SvROK (coro_sv))
1552 if (coro->flags & CF_READY) 1521 if (coro->flags & CF_READY)
1553 return 0; 1522 return 0;
1554 1523
1555 coro->flags |= CF_READY; 1524 coro->flags |= CF_READY;
1556 1525
1557 LOCK;
1558
1559 sv_hook = coro_nready ? 0 : coro_readyhook; 1526 sv_hook = coro_nready ? 0 : coro_readyhook;
1560 xs_hook = coro_nready ? 0 : coroapi.readyhook; 1527 xs_hook = coro_nready ? 0 : coroapi.readyhook;
1561 1528
1562 coro_enq (aTHX_ SvREFCNT_inc_NN (coro_sv)); 1529 coro_enq (aTHX_ SvREFCNT_inc_NN (coro_sv));
1563 ++coro_nready; 1530 ++coro_nready;
1564 1531
1565 UNLOCK;
1566
1567 if (sv_hook) 1532 if (sv_hook)
1568 { 1533 {
1569 dSP; 1534 dSP;
1570 1535
1571 ENTER; 1536 ENTER;
1585 1550
1586 return 1; 1551 return 1;
1587} 1552}
1588 1553
1589static int 1554static int
1590api_is_ready (SV *coro_sv) 1555api_is_ready (pTHX_ SV *coro_sv)
1591{ 1556{
1592 dTHX;
1593
1594 return !!(SvSTATE (coro_sv)->flags & CF_READY); 1557 return !!(SvSTATE (coro_sv)->flags & CF_READY);
1595} 1558}
1596 1559
1597INLINE void 1560INLINE void
1598prepare_schedule (pTHX_ struct transfer_args *ta) 1561prepare_schedule (pTHX_ struct coro_transfer_args *ta)
1599{ 1562{
1600 SV *prev_sv, *next_sv; 1563 SV *prev_sv, *next_sv;
1601 1564
1602 for (;;) 1565 for (;;)
1603 { 1566 {
1604 LOCK;
1605 next_sv = coro_deq (aTHX); 1567 next_sv = coro_deq (aTHX);
1606 1568
1607 /* nothing to schedule: call the idle handler */ 1569 /* nothing to schedule: call the idle handler */
1608 if (expect_false (!next_sv)) 1570 if (expect_false (!next_sv))
1609 { 1571 {
1610 dSP; 1572 dSP;
1611 UNLOCK;
1612 1573
1613 ENTER; 1574 ENTER;
1614 SAVETMPS; 1575 SAVETMPS;
1615 1576
1616 PUSHMARK (SP); 1577 PUSHMARK (SP);
1626 ta->next = SvSTATE (next_sv); 1587 ta->next = SvSTATE (next_sv);
1627 1588
1628 /* cannot transfer to destroyed coros, skip and look for next */ 1589 /* cannot transfer to destroyed coros, skip and look for next */
1629 if (expect_false (ta->next->flags & CF_DESTROYED)) 1590 if (expect_false (ta->next->flags & CF_DESTROYED))
1630 { 1591 {
1631 UNLOCK;
1632 SvREFCNT_dec (next_sv); 1592 SvREFCNT_dec (next_sv);
1633 /* coro_nready has already been taken care of by destroy */ 1593 /* coro_nready has already been taken care of by destroy */
1634 continue; 1594 continue;
1635 } 1595 }
1636 1596
1637 --coro_nready; 1597 --coro_nready;
1638 UNLOCK;
1639 break; 1598 break;
1640 } 1599 }
1641 1600
1642 /* free this only after the transfer */ 1601 /* free this only after the transfer */
1643 prev_sv = SvRV (coro_current); 1602 prev_sv = SvRV (coro_current);
1645 TRANSFER_CHECK (*ta); 1604 TRANSFER_CHECK (*ta);
1646 assert (("FATAL: next coroutine isn't marked as ready in Coro (please report)", ta->next->flags & CF_READY)); 1605 assert (("FATAL: next coroutine isn't marked as ready in Coro (please report)", ta->next->flags & CF_READY));
1647 ta->next->flags &= ~CF_READY; 1606 ta->next->flags &= ~CF_READY;
1648 SvRV_set (coro_current, next_sv); 1607 SvRV_set (coro_current, next_sv);
1649 1608
1650 LOCK;
1651 free_coro_mortal (aTHX); 1609 free_coro_mortal (aTHX);
1652 coro_mortal = prev_sv; 1610 coro_mortal = prev_sv;
1653 UNLOCK;
1654} 1611}
1655 1612
1656INLINE void 1613INLINE void
1657prepare_cede (pTHX_ struct transfer_args *ta) 1614prepare_cede (pTHX_ struct coro_transfer_args *ta)
1658{ 1615{
1659 api_ready (coro_current); 1616 api_ready (aTHX_ coro_current);
1660 prepare_schedule (aTHX_ ta); 1617 prepare_schedule (aTHX_ ta);
1661} 1618}
1662 1619
1663static void 1620INLINE void
1664prepare_cede_notself (pTHX_ struct transfer_args *ta) 1621prepare_cede_notself (pTHX_ struct coro_transfer_args *ta)
1665{ 1622{
1666 SV *prev = SvRV (coro_current); 1623 SV *prev = SvRV (coro_current);
1667 1624
1668 if (coro_nready) 1625 if (coro_nready)
1669 { 1626 {
1670 prepare_schedule (aTHX_ ta); 1627 prepare_schedule (aTHX_ ta);
1671 api_ready (prev); 1628 api_ready (aTHX_ prev);
1672 } 1629 }
1673 else 1630 else
1674 ta->prev = ta->next = SvSTATE (prev); 1631 prepare_nop (aTHX_ ta);
1675} 1632}
1676 1633
1677static void 1634static void
1678api_schedule (void) 1635api_schedule (pTHX)
1679{ 1636{
1680 dTHX;
1681 struct transfer_args ta; 1637 struct coro_transfer_args ta;
1682 1638
1683 prepare_schedule (aTHX_ &ta); 1639 prepare_schedule (aTHX_ &ta);
1684 TRANSFER (ta, 1); 1640 TRANSFER (ta, 1);
1685} 1641}
1686 1642
1687static int 1643static int
1688api_cede (void) 1644api_cede (pTHX)
1689{ 1645{
1690 dTHX;
1691 struct transfer_args ta; 1646 struct coro_transfer_args ta;
1692 1647
1693 prepare_cede (aTHX_ &ta); 1648 prepare_cede (aTHX_ &ta);
1694 1649
1695 if (expect_true (ta.prev != ta.next)) 1650 if (expect_true (ta.prev != ta.next))
1696 { 1651 {
1700 else 1655 else
1701 return 0; 1656 return 0;
1702} 1657}
1703 1658
1704static int 1659static int
1705api_cede_notself (void) 1660api_cede_notself (pTHX)
1706{ 1661{
1707 if (coro_nready) 1662 if (coro_nready)
1708 { 1663 {
1709 dTHX;
1710 struct transfer_args ta; 1664 struct coro_transfer_args ta;
1711 1665
1712 prepare_cede_notself (aTHX_ &ta); 1666 prepare_cede_notself (aTHX_ &ta);
1713 TRANSFER (ta, 1); 1667 TRANSFER (ta, 1);
1714 return 1; 1668 return 1;
1715 } 1669 }
1716 else 1670 else
1717 return 0; 1671 return 0;
1718} 1672}
1719 1673
1720static void 1674static void
1721api_trace (SV *coro_sv, int flags) 1675api_trace (pTHX_ SV *coro_sv, int flags)
1722{ 1676{
1723 dTHX;
1724 struct coro *coro = SvSTATE (coro_sv); 1677 struct coro *coro = SvSTATE (coro_sv);
1725 1678
1726 if (flags & CC_TRACE) 1679 if (flags & CC_TRACE)
1727 { 1680 {
1728 if (!coro->cctx) 1681 if (!coro->cctx)
1729 coro->cctx = cctx_new_run (); 1682 coro->cctx = cctx_new_run ();
1730 else if (!(coro->cctx->flags & CC_TRACE)) 1683 else if (!(coro->cctx->flags & CC_TRACE))
1731 croak ("cannot enable tracing on coroutine with custom stack"); 1684 croak ("cannot enable tracing on coroutine with custom stack,");
1732 1685
1733 coro->cctx->flags |= CC_NOREUSE | (flags & (CC_TRACE | CC_TRACE_ALL)); 1686 coro->cctx->flags |= CC_NOREUSE | (flags & (CC_TRACE | CC_TRACE_ALL));
1734 } 1687 }
1735 else if (coro->cctx && coro->cctx->flags & CC_TRACE) 1688 else if (coro->cctx && coro->cctx->flags & CC_TRACE)
1736 { 1689 {
1741 else 1694 else
1742 coro->slot->runops = RUNOPS_DEFAULT; 1695 coro->slot->runops = RUNOPS_DEFAULT;
1743 } 1696 }
1744} 1697}
1745 1698
1746#if 0
1747static int
1748coro_gensub_free (pTHX_ SV *sv, MAGIC *mg)
1749{
1750 AV *padlist;
1751 AV *av = (AV *)mg->mg_obj;
1752
1753 abort ();
1754
1755 return 0;
1756}
1757
1758static MGVTBL coro_gensub_vtbl = {
1759 0, 0, 0, 0,
1760 coro_gensub_free
1761};
1762#endif
1763
1764/*****************************************************************************/ 1699/*****************************************************************************/
1765/* PerlIO::cede */ 1700/* PerlIO::cede */
1766 1701
1767typedef struct 1702typedef struct
1768{ 1703{
1795 PerlIOCede *self = PerlIOSelf (f, PerlIOCede); 1730 PerlIOCede *self = PerlIOSelf (f, PerlIOCede);
1796 double now = nvtime (); 1731 double now = nvtime ();
1797 1732
1798 if (now >= self->next) 1733 if (now >= self->next)
1799 { 1734 {
1800 api_cede (); 1735 api_cede (aTHX);
1801 self->next = now + self->every; 1736 self->next = now + self->every;
1802 } 1737 }
1803 1738
1804 return PerlIOBuf_flush (aTHX_ f); 1739 return PerlIOBuf_flush (aTHX_ f);
1805} 1740}
1841static const CV *slf_cv; /* for quick consistency check */ 1776static const CV *slf_cv; /* for quick consistency check */
1842 1777
1843static UNOP slf_restore; /* restore stack as entersub did, for first-re-run */ 1778static UNOP slf_restore; /* restore stack as entersub did, for first-re-run */
1844static SV *slf_arg0; 1779static SV *slf_arg0;
1845static SV *slf_arg1; 1780static SV *slf_arg1;
1781static SV *slf_arg2;
1846 1782
1847/* this restores the stack in the case we patched the entersub, to */ 1783/* this restores the stack in the case we patched the entersub, to */
1848/* recreate the stack frame as perl will on following calls */ 1784/* recreate the stack frame as perl will on following calls */
1849/* since entersub cleared the stack */ 1785/* since entersub cleared the stack */
1850static OP * 1786static OP *
1855 PUSHMARK (SP); 1791 PUSHMARK (SP);
1856 1792
1857 EXTEND (SP, 3); 1793 EXTEND (SP, 3);
1858 if (slf_arg0) PUSHs (sv_2mortal (slf_arg0)); 1794 if (slf_arg0) PUSHs (sv_2mortal (slf_arg0));
1859 if (slf_arg1) PUSHs (sv_2mortal (slf_arg1)); 1795 if (slf_arg1) PUSHs (sv_2mortal (slf_arg1));
1796 if (slf_arg2) PUSHs (sv_2mortal (slf_arg2));
1860 PUSHs ((SV *)CvGV (slf_cv)); 1797 PUSHs ((SV *)CvGV (slf_cv));
1861 1798
1862 RETURNOP (slf_restore.op_first); 1799 RETURNOP (slf_restore.op_first);
1863} 1800}
1864 1801
1865#define OPpENTERSUB_SLF 15 /* the part of op_private entersub hopefully doesn't use */ 1802static void
1803slf_prepare_set_stacklevel (pTHX_ struct coro_transfer_args *ta)
1804{
1805 prepare_set_stacklevel (ta, (struct coro_cctx *)slf_frame.data);
1806}
1866 1807
1867/* declare prototype */ 1808static void
1868XS(XS_Coro__State__set_stacklevel); 1809slf_init_set_stacklevel (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
1810{
1811 assert (("FATAL: set_stacklevel needs the coro cctx as sole argument", items == 1));
1812
1813 frame->prepare = slf_prepare_set_stacklevel;
1814 frame->check = slf_check_nop;
1815 frame->data = (void *)SvIV (arg [0]);
1816}
1817
1818static void
1819slf_prepare_transfer (pTHX_ struct coro_transfer_args *ta)
1820{
1821 SV **arg = (SV **)slf_frame.data;
1822
1823 prepare_transfer (aTHX_ ta, arg [0], arg [1]);
1824}
1825
1826static void
1827slf_init_transfer (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
1828{
1829 if (items != 2)
1830 croak ("Coro::State::transfer (prev, next) expects two arguments, not %d,", items);
1831
1832 frame->prepare = slf_prepare_transfer;
1833 frame->check = slf_check_nop;
1834 frame->data = (void *)arg; /* let's hope it will stay valid */
1835}
1836
1837static void
1838slf_init_schedule (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
1839{
1840 frame->prepare = prepare_schedule;
1841 frame->check = slf_check_nop;
1842}
1843
1844static void
1845slf_init_cede (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
1846{
1847 frame->prepare = prepare_cede;
1848 frame->check = slf_check_nop;
1849}
1850
1851static void
1852slf_init_cede_notself (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
1853{
1854 frame->prepare = prepare_cede_notself;
1855 frame->check = slf_check_nop;
1856}
1857
1858/* we hijack an hopefully unused CV flag for our purposes */
1859#define CVf_SLF 0x4000
1869 1860
1870/* 1861/*
1871 * these not obviously related functions are all rolled into one 1862 * these not obviously related functions are all rolled into one
1872 * function to increase chances that they all will call transfer with the same 1863 * function to increase chances that they all will call transfer with the same
1873 * stack offset 1864 * stack offset
1874 * SLF stands for "schedule-like-function". 1865 * SLF stands for "schedule-like-function".
1875 */ 1866 */
1876static OP * 1867static OP *
1877pp_slf (pTHX) 1868pp_slf (pTHX)
1878{ 1869{
1870 I32 checkmark; /* mark SP to see how many elements check has pushed */
1871
1872 /* set up the slf frame, unless it has already been set-up */
1873 /* the latter happens when a new coro has been started */
1874 /* or when a new cctx was attached to an existing coroutine */
1875 if (expect_true (!slf_frame.prepare))
1876 {
1877 /* first iteration */
1879 dSP; 1878 dSP;
1880 struct transfer_args ta;
1881 SV **arg = PL_stack_base + TOPMARK + 1; 1879 SV **arg = PL_stack_base + TOPMARK + 1;
1882 int items = SP - arg; /* args without function object */ 1880 int items = SP - arg; /* args without function object */
1881 SV *gv = *sp;
1883 1882
1884 /* do a quick consistency check on the "function" object, and if it isn't */ 1883 /* do a quick consistency check on the "function" object, and if it isn't */
1885 /* for us, divert to the real entersub */ 1884 /* for us, divert to the real entersub */
1886 if (SvTYPE (*sp) != SVt_PVGV || CvXSUB (GvCV (*sp)) != XS_Coro__State__set_stacklevel) 1885 if (SvTYPE (gv) != SVt_PVGV || !(CvFLAGS (GvCV (gv)) & CVf_SLF))
1887 return PL_ppaddr[OP_ENTERSUB](aTHX); 1886 return PL_ppaddr[OP_ENTERSUB](aTHX);
1888 1887
1889 /* pop args */ 1888 /* pop args */
1890 SP = PL_stack_base + POPMARK; 1889 SP = PL_stack_base + POPMARK;
1891 1890
1892 if (!(PL_op->op_flags & OPf_STACKED)) 1891 if (!(PL_op->op_flags & OPf_STACKED))
1893 { 1892 {
1894 /* ampersand-form of call, use @_ instead of stack */ 1893 /* ampersand-form of call, use @_ instead of stack */
1895 AV *av = GvAV (PL_defgv); 1894 AV *av = GvAV (PL_defgv);
1896 arg = AvARRAY (av); 1895 arg = AvARRAY (av);
1897 items = AvFILLp (av) + 1; 1896 items = AvFILLp (av) + 1;
1897 }
1898
1899 PUTBACK;
1900
1901 /* now call the init function, which needs to set up slf_frame */
1902 ((coro_slf_cb)CvXSUBANY (GvCV (gv)).any_ptr)
1903 (aTHX_ &slf_frame, GvCV (gv), arg, items);
1904 }
1905
1906 /* now that we have a slf_frame, interpret it! */
1907 /* we use a callback system not to make the code needlessly */
1908 /* complicated, but so we can run multiple perl coros from one cctx */
1909
1910 do
1911 {
1912 struct coro_transfer_args ta;
1913
1914 slf_frame.prepare (aTHX_ &ta);
1915 TRANSFER (ta, 0);
1916
1917 checkmark = PL_stack_sp - PL_stack_base;
1918 }
1919 while (slf_frame.check (aTHX_ &slf_frame));
1920
1921 {
1922 dSP;
1923 SV **bot = PL_stack_base + checkmark;
1924 int gimme = GIMME_V;
1925
1926 slf_frame.prepare = 0; /* invalidate the frame, so it gets initialised again next time */
1927
1928 /* make sure we put something on the stack in scalar context */
1929 if (gimme == G_SCALAR)
1930 {
1931 if (sp == bot)
1932 XPUSHs (&PL_sv_undef);
1933
1934 SP = bot + 1;
1898 } 1935 }
1899 1936
1900 PUTBACK; 1937 PUTBACK;
1901 switch (PL_op->op_private & OPpENTERSUB_SLF)
1902 {
1903 case 0:
1904 prepare_set_stacklevel (&ta, (struct coro_cctx *)SvIV (arg [0]));
1905 break;
1906
1907 case 1:
1908 if (items != 2)
1909 croak ("Coro::State::transfer (prev, next) expects two arguments, not %d.", items);
1910
1911 prepare_transfer (aTHX_ &ta, arg [0], arg [1]);
1912 break;
1913
1914 case 2:
1915 prepare_schedule (aTHX_ &ta);
1916 break;
1917
1918 case 3:
1919 prepare_cede (aTHX_ &ta);
1920 break;
1921
1922 case 4:
1923 prepare_cede_notself (aTHX_ &ta);
1924 break;
1925
1926 case 5:
1927 abort ();
1928
1929 default:
1930 abort ();
1931 } 1938 }
1932 1939
1933 TRANSFER (ta, 0); 1940 return NORMAL;
1934 SPAGAIN;
1935
1936 PUTBACK;
1937 SLF_TAIL;
1938 SPAGAIN;
1939 RETURN;
1940} 1941}
1941 1942
1942static void 1943static void
1943coro_slf_patch (pTHX_ CV *cv, int ix, SV **args, int items) 1944api_execute_slf (pTHX_ CV *cv, coro_slf_cb init_cb, SV **arg, int items)
1944{ 1945{
1945 assert (("FATAL: SLF call recursion in Coro module (please report)", PL_op->op_ppaddr != pp_slf));
1946
1947 assert (("FATAL: SLF call with illegal CV value", CvGV (cv))); 1946 assert (("FATAL: SLF call with illegal CV value", !CvANON (cv)));
1947
1948 if (PL_op->op_ppaddr != PL_ppaddr [OP_ENTERSUB]
1949 && PL_op->op_ppaddr != pp_slf)
1950 croak ("FATAL: Coro SLF calls can only be made normally, not via goto or any other means, caught");
1951
1952 if (items > 3)
1953 croak ("Coro only supports up to three arguments to SLF functions currently (not %d), caught", items);
1954
1955 CvFLAGS (cv) |= CVf_SLF;
1956 CvXSUBANY (cv).any_ptr = (void *)init_cb;
1948 slf_cv = cv; 1957 slf_cv = cv;
1949 1958
1950 /* we patch the op, and then re-run the whole call */ 1959 /* we patch the op, and then re-run the whole call */
1951 /* we have to put the same argument on the stack for this to work */ 1960 /* we have to put the same argument on the stack for this to work */
1952 /* and this will be done by pp_restore */ 1961 /* and this will be done by pp_restore */
1953 slf_restore.op_next = (OP *)&slf_restore; 1962 slf_restore.op_next = (OP *)&slf_restore;
1954 slf_restore.op_type = OP_NULL; 1963 slf_restore.op_type = OP_CUSTOM;
1955 slf_restore.op_ppaddr = pp_restore; 1964 slf_restore.op_ppaddr = pp_restore;
1956 slf_restore.op_first = PL_op; 1965 slf_restore.op_first = PL_op;
1957 1966
1958 slf_arg0 = items > 0 ? SvREFCNT_inc (args [0]) : 0; 1967 slf_arg0 = items > 0 ? SvREFCNT_inc (arg [0]) : 0;
1959 slf_arg1 = items > 1 ? SvREFCNT_inc (args [1]) : 0; 1968 slf_arg1 = items > 1 ? SvREFCNT_inc (arg [1]) : 0;
1969 slf_arg2 = items > 2 ? SvREFCNT_inc (arg [2]) : 0;
1960 1970
1961 PL_op->op_ppaddr = pp_slf; 1971 PL_op->op_ppaddr = pp_slf;
1962 PL_op->op_private = PL_op->op_private & ~OPpENTERSUB_SLF | ix; /* we potentially share our private flags with entersub */
1963 1972
1964 PL_op = (OP *)&slf_restore; 1973 PL_op = (OP *)&slf_restore;
1965} 1974}
1975
1976/*****************************************************************************/
1977
1978static void
1979coro_semaphore_adjust (AV *av, int adjust)
1980{
1981 SV *count_sv = AvARRAY (av)[0];
1982 IV count = SvIVX (count_sv);
1983
1984 count += adjust;
1985 SvIVX (count_sv) = count;
1986
1987 /* now wake up as many waiters as possible */
1988 while (count > 0 && AvFILLp (av) >= count)
1989 {
1990 SV *cb;
1991
1992 /* swap first two elements so we can shift a waiter */
1993 AvARRAY (av)[0] = AvARRAY (av)[1];
1994 AvARRAY (av)[1] = count_sv;
1995 cb = av_shift (av);
1996
1997 if (SvOBJECT (cb))
1998 api_ready (aTHX_ cb);
1999 else
2000 croak ("callbacks not yet supported");
2001
2002 SvREFCNT_dec (cb);
2003
2004 --count;
2005 }
2006}
2007
2008static void
2009coro_semaphore_on_destroy (pTHX_ struct coro *coro)
2010{
2011 /* call $sem->adjust (0) to possibly wake up some waiters */
2012 coro_semaphore_adjust ((AV *)coro->slf_frame.data, 0);
2013}
2014
2015static int
2016slf_check_semaphore_down (pTHX_ struct CoroSLF *frame)
2017{
2018 AV *av = (AV *)frame->data;
2019 SV *count_sv = AvARRAY (av)[0];
2020
2021 if (SvIVX (count_sv) > 0)
2022 {
2023 SvSTATE (coro_current)->on_destroy = 0;
2024 SvIVX (count_sv) = SvIVX (count_sv) - 1;
2025 return 0;
2026 }
2027 else
2028 {
2029 int i;
2030 /* if we were woken up but can't down, we look through the whole */
2031 /* waiters list and only add us if we aren't in there already */
2032 /* this avoids some degenerate memory usage cases */
2033
2034 for (i = 1; i <= AvFILLp (av); ++i)
2035 if (AvARRAY (av)[i] == SvRV (coro_current))
2036 return 1;
2037
2038 av_push (av, SvREFCNT_inc (SvRV (coro_current)));
2039 return 1;
2040 }
2041}
2042
2043static void
2044slf_init_semaphore_down (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
2045{
2046 AV *av = (AV *)SvRV (arg [0]);
2047
2048 if (SvIVX (AvARRAY (av)[0]) > 0)
2049 {
2050 frame->data = (void *)av;
2051 frame->prepare = prepare_nop;
2052 }
2053 else
2054 {
2055 av_push (av, SvREFCNT_inc (SvRV (coro_current)));
2056
2057 frame->data = (void *)sv_2mortal (SvREFCNT_inc ((SV *)av));
2058 frame->prepare = prepare_schedule;
2059
2060 /* to avoid race conditions when a woken-up coro gets terminated */
2061 /* we arrange for a temporary on_destroy that calls adjust (0) */
2062 SvSTATE (coro_current)->on_destroy = coro_semaphore_on_destroy;
2063 }
2064
2065 frame->check = slf_check_semaphore_down;
2066
2067}
2068
2069/*****************************************************************************/
2070
2071#define GENSUB_ARG CvXSUBANY (cv).any_ptr
2072
2073/* create a closure from XS, returns a code reference */
2074/* the arg can be accessed via GENSUB_ARG from the callback */
2075/* the callback must use dXSARGS/XSRETURN */
2076static SV *
2077gensub (pTHX_ void (*xsub)(pTHX_ CV *), void *arg)
2078{
2079 CV *cv = (CV *)NEWSV (0, 0);
2080
2081 sv_upgrade ((SV *)cv, SVt_PVCV);
2082
2083 CvANON_on (cv);
2084 CvISXSUB_on (cv);
2085 CvXSUB (cv) = xsub;
2086 GENSUB_ARG = arg;
2087
2088 return newRV_noinc ((SV *)cv);
2089}
2090
2091/*****************************************************************************/
1966 2092
1967MODULE = Coro::State PACKAGE = Coro::State PREFIX = api_ 2093MODULE = Coro::State PACKAGE = Coro::State PREFIX = api_
1968 2094
1969PROTOTYPES: DISABLE 2095PROTOTYPES: DISABLE
1970 2096
2000 main_top_env = PL_top_env; 2126 main_top_env = PL_top_env;
2001 2127
2002 while (main_top_env->je_prev) 2128 while (main_top_env->je_prev)
2003 main_top_env = main_top_env->je_prev; 2129 main_top_env = main_top_env->je_prev;
2004 2130
2131 {
2132 SV *slf = sv_2mortal (newSViv (PTR2IV (pp_slf)));
2133
2134 if (!PL_custom_op_names) PL_custom_op_names = newHV ();
2135 hv_store_ent (PL_custom_op_names, slf,
2136 newSVpv ("coro_slf", 0), 0);
2137
2138 if (!PL_custom_op_descs) PL_custom_op_descs = newHV ();
2139 hv_store_ent (PL_custom_op_descs, slf,
2140 newSVpv ("coro schedule like function", 0), 0);
2141 }
2142
2005 coroapi.ver = CORO_API_VERSION; 2143 coroapi.ver = CORO_API_VERSION;
2006 coroapi.rev = CORO_API_REVISION; 2144 coroapi.rev = CORO_API_REVISION;
2145
2007 coroapi.transfer = api_transfer; 2146 coroapi.transfer = api_transfer;
2147
2148 coroapi.sv_state = SvSTATE_;
2149 coroapi.execute_slf = api_execute_slf;
2150 coroapi.prepare_nop = prepare_nop;
2151 coroapi.prepare_schedule = prepare_schedule;
2152 coroapi.prepare_cede = prepare_cede;
2153 coroapi.prepare_cede_notself = prepare_cede_notself;
2008 2154
2009 { 2155 {
2010 SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0); 2156 SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0);
2011 2157
2012 if (!svp) croak ("Time::HiRes is required"); 2158 if (!svp) croak ("Time::HiRes is required");
2047 OUTPUT: 2193 OUTPUT:
2048 RETVAL 2194 RETVAL
2049 2195
2050void 2196void
2051_set_stacklevel (...) 2197_set_stacklevel (...)
2052 ALIAS: 2198 CODE:
2053 Coro::State::transfer = 1 2199 api_execute_slf (aTHX_ cv, slf_init_set_stacklevel, &ST (0), items);
2054 Coro::schedule = 2 2200
2055 Coro::cede = 3 2201void
2056 Coro::cede_notself = 4 2202transfer (...)
2057 CODE: 2203 PROTOTYPE: $$
2058 coro_slf_patch (aTHX_ cv, ix, &ST (0), items); 2204 CODE:
2205 api_execute_slf (aTHX_ cv, slf_init_transfer, &ST (0), items);
2059 2206
2060bool 2207bool
2061_destroy (SV *coro_sv) 2208_destroy (SV *coro_sv)
2062 CODE: 2209 CODE:
2063 RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv)); 2210 RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv));
2070 CODE: 2217 CODE:
2071 _exit (code); 2218 _exit (code);
2072 2219
2073int 2220int
2074cctx_stacksize (int new_stacksize = 0) 2221cctx_stacksize (int new_stacksize = 0)
2222 PROTOTYPE: ;$
2075 CODE: 2223 CODE:
2076 RETVAL = cctx_stacksize; 2224 RETVAL = cctx_stacksize;
2077 if (new_stacksize) 2225 if (new_stacksize)
2078 { 2226 {
2079 cctx_stacksize = new_stacksize; 2227 cctx_stacksize = new_stacksize;
2082 OUTPUT: 2230 OUTPUT:
2083 RETVAL 2231 RETVAL
2084 2232
2085int 2233int
2086cctx_max_idle (int max_idle = 0) 2234cctx_max_idle (int max_idle = 0)
2235 PROTOTYPE: ;$
2087 CODE: 2236 CODE:
2088 RETVAL = cctx_max_idle; 2237 RETVAL = cctx_max_idle;
2089 if (max_idle > 1) 2238 if (max_idle > 1)
2090 cctx_max_idle = max_idle; 2239 cctx_max_idle = max_idle;
2091 OUTPUT: 2240 OUTPUT:
2092 RETVAL 2241 RETVAL
2093 2242
2094int 2243int
2095cctx_count () 2244cctx_count ()
2245 PROTOTYPE:
2096 CODE: 2246 CODE:
2097 RETVAL = cctx_count; 2247 RETVAL = cctx_count;
2098 OUTPUT: 2248 OUTPUT:
2099 RETVAL 2249 RETVAL
2100 2250
2101int 2251int
2102cctx_idle () 2252cctx_idle ()
2253 PROTOTYPE:
2103 CODE: 2254 CODE:
2104 RETVAL = cctx_idle; 2255 RETVAL = cctx_idle;
2105 OUTPUT: 2256 OUTPUT:
2106 RETVAL 2257 RETVAL
2107 2258
2108void 2259void
2109list () 2260list ()
2261 PROTOTYPE:
2110 PPCODE: 2262 PPCODE:
2111{ 2263{
2112 struct coro *coro; 2264 struct coro *coro;
2113 for (coro = coro_first; coro; coro = coro->next) 2265 for (coro = coro_first; coro; coro = coro->next)
2114 if (coro->hv) 2266 if (coro->hv)
2181 SvREFCNT_dec (self->throw); 2333 SvREFCNT_dec (self->throw);
2182 self->throw = SvOK (throw) ? newSVsv (throw) : 0; 2334 self->throw = SvOK (throw) ? newSVsv (throw) : 0;
2183 2335
2184void 2336void
2185api_trace (SV *coro, int flags = CC_TRACE | CC_TRACE_SUB) 2337api_trace (SV *coro, int flags = CC_TRACE | CC_TRACE_SUB)
2338 PROTOTYPE: $;$
2339 C_ARGS: aTHX_ coro, flags
2186 2340
2187SV * 2341SV *
2188has_cctx (Coro::State coro) 2342has_cctx (Coro::State coro)
2189 PROTOTYPE: $ 2343 PROTOTYPE: $
2190 CODE: 2344 CODE:
2214 OUTPUT: 2368 OUTPUT:
2215 RETVAL 2369 RETVAL
2216 2370
2217void 2371void
2218force_cctx () 2372force_cctx ()
2373 PROTOTYPE:
2219 CODE: 2374 CODE:
2220 struct coro *coro = SvSTATE (coro_current); 2375 struct coro *coro = SvSTATE (coro_current);
2221 coro->cctx->idle_sp = 0; 2376 coro->cctx->idle_sp = 0;
2222 2377
2223void 2378void
2225 PROTOTYPE: $ 2380 PROTOTYPE: $
2226 ALIAS: 2381 ALIAS:
2227 swap_defav = 1 2382 swap_defav = 1
2228 CODE: 2383 CODE:
2229 if (!self->slot) 2384 if (!self->slot)
2230 croak ("cannot swap state with coroutine that has no saved state"); 2385 croak ("cannot swap state with coroutine that has no saved state,");
2231 else 2386 else
2232 { 2387 {
2233 SV **src = ix ? (SV **)&GvAV (PL_defgv) : &GvSV (PL_defgv); 2388 SV **src = ix ? (SV **)&GvAV (PL_defgv) : &GvSV (PL_defgv);
2234 SV **dst = ix ? (SV **)&self->slot->defav : (SV **)&self->slot->defsv; 2389 SV **dst = ix ? (SV **)&self->slot->defav : (SV **)&self->slot->defsv;
2235 2390
2267 coroapi.schedule = api_schedule; 2422 coroapi.schedule = api_schedule;
2268 coroapi.cede = api_cede; 2423 coroapi.cede = api_cede;
2269 coroapi.cede_notself = api_cede_notself; 2424 coroapi.cede_notself = api_cede_notself;
2270 coroapi.ready = api_ready; 2425 coroapi.ready = api_ready;
2271 coroapi.is_ready = api_is_ready; 2426 coroapi.is_ready = api_is_ready;
2272 coroapi.nready = &coro_nready; 2427 coroapi.nready = coro_nready;
2273 coroapi.current = coro_current; 2428 coroapi.current = coro_current;
2274 2429
2275 GCoroAPI = &coroapi; 2430 GCoroAPI = &coroapi;
2276 sv_setiv (sv, (IV)&coroapi); 2431 sv_setiv (sv, (IV)&coroapi);
2277 SvREADONLY_on (sv); 2432 SvREADONLY_on (sv);
2278 } 2433 }
2279} 2434}
2435
2436void
2437schedule (...)
2438 CODE:
2439 api_execute_slf (aTHX_ cv, slf_init_schedule, &ST (0), 0);
2440
2441void
2442cede (...)
2443 CODE:
2444 api_execute_slf (aTHX_ cv, slf_init_cede, &ST (0), 0);
2445
2446void
2447cede_notself (...)
2448 CODE:
2449 api_execute_slf (aTHX_ cv, slf_init_cede_notself, &ST (0), 0);
2280 2450
2281void 2451void
2282_set_current (SV *current) 2452_set_current (SV *current)
2283 PROTOTYPE: $ 2453 PROTOTYPE: $
2284 CODE: 2454 CODE:
2287 2457
2288void 2458void
2289_set_readyhook (SV *hook) 2459_set_readyhook (SV *hook)
2290 PROTOTYPE: $ 2460 PROTOTYPE: $
2291 CODE: 2461 CODE:
2292 LOCK;
2293 SvREFCNT_dec (coro_readyhook); 2462 SvREFCNT_dec (coro_readyhook);
2294 coro_readyhook = SvOK (hook) ? newSVsv (hook) : 0; 2463 coro_readyhook = SvOK (hook) ? newSVsv (hook) : 0;
2295 UNLOCK;
2296 2464
2297int 2465int
2298prio (Coro::State coro, int newprio = 0) 2466prio (Coro::State coro, int newprio = 0)
2467 PROTOTYPE: $;$
2299 ALIAS: 2468 ALIAS:
2300 nice = 1 2469 nice = 1
2301 CODE: 2470 CODE:
2302{ 2471{
2303 RETVAL = coro->prio; 2472 RETVAL = coro->prio;
2318 2487
2319SV * 2488SV *
2320ready (SV *self) 2489ready (SV *self)
2321 PROTOTYPE: $ 2490 PROTOTYPE: $
2322 CODE: 2491 CODE:
2323 RETVAL = boolSV (api_ready (self)); 2492 RETVAL = boolSV (api_ready (aTHX_ self));
2324 OUTPUT: 2493 OUTPUT:
2325 RETVAL 2494 RETVAL
2326 2495
2327int 2496int
2328nready (...) 2497nready (...)
2367 { 2536 {
2368 av_fill (defav, len - 1); 2537 av_fill (defav, len - 1);
2369 for (i = 0; i < len; ++i) 2538 for (i = 0; i < len; ++i)
2370 av_store (defav, i, SvREFCNT_inc_NN (AvARRAY (invoke_av)[i + 1])); 2539 av_store (defav, i, SvREFCNT_inc_NN (AvARRAY (invoke_av)[i + 1]));
2371 } 2540 }
2372
2373 SvREFCNT_dec (invoke);
2374} 2541}
2375 2542
2376void 2543void
2377_pool_2 (SV *cb) 2544_pool_2 (SV *cb)
2378 CODE: 2545 CODE:
2398 newSVpvn ("[async_pool idle]", sizeof ("[async_pool idle]") - 1), 0); 2565 newSVpvn ("[async_pool idle]", sizeof ("[async_pool idle]") - 1), 0);
2399 2566
2400 coro->prio = 0; 2567 coro->prio = 0;
2401 2568
2402 if (coro->cctx && (coro->cctx->flags & CC_TRACE)) 2569 if (coro->cctx && (coro->cctx->flags & CC_TRACE))
2403 api_trace (coro_current, 0); 2570 api_trace (aTHX_ coro_current, 0);
2404 2571
2405 av_push (av_async_pool, newSVsv (coro_current)); 2572 av_push (av_async_pool, newSVsv (coro_current));
2406} 2573}
2407
2408#if 0
2409
2410void
2411_generator_call (...)
2412 PROTOTYPE: @
2413 PPCODE:
2414 fprintf (stderr, "call %p\n", CvXSUBANY(cv).any_ptr);
2415 xxxx
2416 abort ();
2417
2418SV *
2419gensub (SV *sub, ...)
2420 PROTOTYPE: &;@
2421 CODE:
2422{
2423 struct coro *coro;
2424 MAGIC *mg;
2425 CV *xcv;
2426 CV *ncv = (CV *)newSV_type (SVt_PVCV);
2427 int i;
2428
2429 CvGV (ncv) = CvGV (cv);
2430 CvFILE (ncv) = CvFILE (cv);
2431
2432 Newz (0, coro, 1, struct coro);
2433 coro->args = newAV ();
2434 coro->flags = CF_NEW;
2435
2436 av_extend (coro->args, items - 1);
2437 for (i = 1; i < items; i++)
2438 av_push (coro->args, newSVsv (ST (i)));
2439
2440 CvISXSUB_on (ncv);
2441 CvXSUBANY (ncv).any_ptr = (void *)coro;
2442
2443 xcv = GvCV (gv_fetchpv ("Coro::_generator_call", 0, SVt_PVCV));
2444
2445 CvXSUB (ncv) = CvXSUB (xcv);
2446 CvANON_on (ncv);
2447
2448 mg = sv_magicext ((SV *)ncv, 0, CORO_MAGIC_type_state, &coro_gensub_vtbl, (char *)coro, 0);
2449 RETVAL = newRV_noinc ((SV *)ncv);
2450}
2451 OUTPUT:
2452 RETVAL
2453
2454#endif
2455 2574
2456 2575
2457MODULE = Coro::State PACKAGE = Coro::AIO 2576MODULE = Coro::State PACKAGE = Coro::AIO
2458 2577
2459void 2578void
2460_get_state (SV *self) 2579_get_state (SV *self)
2580 PROTOTYPE: $
2461 PPCODE: 2581 PPCODE:
2462{ 2582{
2463 AV *defav = GvAV (PL_defgv); 2583 AV *defav = GvAV (PL_defgv);
2464 AV *av = newAV (); 2584 AV *av = newAV ();
2465 int i; 2585 int i;
2480 2600
2481 av_push (av, data_sv); 2601 av_push (av, data_sv);
2482 2602
2483 XPUSHs (sv_2mortal (newRV_noinc ((SV *)av))); 2603 XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
2484 2604
2485 api_ready (self); 2605 api_ready (aTHX_ self);
2486} 2606}
2487 2607
2488void 2608void
2489_set_state (SV *state) 2609_set_state (SV *state)
2490 PROTOTYPE: $ 2610 PROTOTYPE: $
2508MODULE = Coro::State PACKAGE = Coro::AnyEvent 2628MODULE = Coro::State PACKAGE = Coro::AnyEvent
2509 2629
2510BOOT: 2630BOOT:
2511 sv_activity = coro_get_sv (aTHX_ "Coro::AnyEvent::ACTIVITY", TRUE); 2631 sv_activity = coro_get_sv (aTHX_ "Coro::AnyEvent::ACTIVITY", TRUE);
2512 2632
2513SV * 2633void
2514_schedule (...) 2634_schedule (...)
2515 PROTOTYPE: @
2516 CODE: 2635 CODE:
2517{ 2636{
2518 static int incede; 2637 static int incede;
2519 2638
2520 api_cede_notself (); 2639 api_cede_notself (aTHX);
2521 2640
2522 ++incede; 2641 ++incede;
2523 while (coro_nready >= incede && api_cede ()) 2642 while (coro_nready >= incede && api_cede (aTHX))
2524 ; 2643 ;
2525 2644
2526 sv_setsv (sv_activity, &PL_sv_undef); 2645 sv_setsv (sv_activity, &PL_sv_undef);
2527 if (coro_nready >= incede) 2646 if (coro_nready >= incede)
2528 { 2647 {
2539MODULE = Coro::State PACKAGE = PerlIO::cede 2658MODULE = Coro::State PACKAGE = PerlIO::cede
2540 2659
2541BOOT: 2660BOOT:
2542 PerlIO_define_layer (aTHX_ &PerlIO_cede); 2661 PerlIO_define_layer (aTHX_ &PerlIO_cede);
2543 2662
2663MODULE = Coro::State PACKAGE = Coro::Semaphore
2664
2665SV *
2666new (SV *klass, SV *count_ = 0)
2667 CODE:
2668{
2669 /* a semaphore contains a counter IV in $sem->[0] and any waiters after that */
2670 AV *av = newAV ();
2671 av_push (av, newSViv (count_ && SvOK (count_) ? SvIV (count_) : 1));
2672 RETVAL = sv_bless (newRV_noinc ((SV *)av), GvSTASH (CvGV (cv)));
2673}
2674 OUTPUT:
2675 RETVAL
2676
2677SV *
2678count (SV *self)
2679 CODE:
2680 RETVAL = newSVsv (AvARRAY ((AV *)SvRV (self))[0]);
2681 OUTPUT:
2682 RETVAL
2683
2684void
2685up (SV *self, int adjust = 1)
2686 ALIAS:
2687 adjust = 1
2688 CODE:
2689 coro_semaphore_adjust ((AV *)SvRV (self), ix ? adjust : 1);
2690
2691void
2692down (SV *self)
2693 CODE:
2694 api_execute_slf (aTHX_ cv, slf_init_semaphore_down, &ST (0), 1);
2695
2696void
2697try (SV *self)
2698 PPCODE:
2699{
2700 AV *av = (AV *)SvRV (self);
2701 SV *count_sv = AvARRAY (av)[0];
2702 IV count = SvIVX (count_sv);
2703
2704 if (count > 0)
2705 {
2706 --count;
2707 SvIVX (count_sv) = count;
2708 XSRETURN_YES;
2709 }
2710 else
2711 XSRETURN_NO;
2712}
2713
2714void
2715waiters (SV *self)
2716 CODE:
2717{
2718 AV *av = (AV *)SvRV (self);
2719
2720 if (GIMME_V == G_SCALAR)
2721 XPUSHs (sv_2mortal (newSVsv (AvARRAY (av)[0])));
2722 else
2723 {
2724 int i;
2725 EXTEND (SP, AvFILLp (av) + 1 - 1);
2726 for (i = 1; i <= AvFILLp (av); ++i)
2727 PUSHs (newSVsv (AvARRAY (av)[i]));
2728 }
2729}
2730

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines