| 1 |
#define PERL_NO_GET_CONTEXT |
| 2 |
|
| 3 |
#include "libcoro/coro.c" |
| 4 |
|
| 5 |
#include "EXTERN.h" |
| 6 |
#include "perl.h" |
| 7 |
#include "XSUB.h" |
| 8 |
|
| 9 |
#include "patchlevel.h" |
| 10 |
|
| 11 |
#if PERL_VERSION < 6 |
| 12 |
# ifndef PL_ppaddr |
| 13 |
# define PL_ppaddr ppaddr |
| 14 |
# endif |
| 15 |
# ifndef call_sv |
| 16 |
# define call_sv perl_call_sv |
| 17 |
# endif |
| 18 |
# ifndef get_sv |
| 19 |
# define get_sv perl_get_sv |
| 20 |
# endif |
| 21 |
# ifndef get_cv |
| 22 |
# define get_cv perl_get_cv |
| 23 |
# endif |
| 24 |
# ifndef IS_PADGV |
| 25 |
# define IS_PADGV(v) 0 |
| 26 |
# endif |
| 27 |
# ifndef IS_PADCONST |
| 28 |
# define IS_PADCONST(v) 0 |
| 29 |
# endif |
| 30 |
#endif |
| 31 |
|
| 32 |
#include <errno.h> |
| 33 |
#include <signal.h> |
| 34 |
|
| 35 |
#ifdef HAVE_MMAP |
| 36 |
# include <unistd.h> |
| 37 |
# include <sys/mman.h> |
| 38 |
# ifndef MAP_ANONYMOUS |
| 39 |
# ifdef MAP_ANON |
| 40 |
# define MAP_ANONYMOUS MAP_ANON |
| 41 |
# else |
| 42 |
# undef HAVE_MMAP |
| 43 |
# endif |
| 44 |
# endif |
| 45 |
#endif |
| 46 |
|
| 47 |
#define SUB_INIT "Coro::State::initialize" |
| 48 |
#define UCORO_STATE "_coro_state" |
| 49 |
|
| 50 |
/* The next macro should declare a variable stacklevel that contains and approximation |
| 51 |
* to the current C stack pointer. Its property is that it changes with each call |
| 52 |
* and should be unique. */ |
| 53 |
#define dSTACKLEVEL void *stacklevel = &stacklevel |
| 54 |
|
| 55 |
#define IN_DESTRUCT (PL_main_cv == Nullcv) |
| 56 |
|
| 57 |
#define labs(l) ((l) >= 0 ? (l) : -(l)) |
| 58 |
|
| 59 |
#include "CoroAPI.h" |
| 60 |
|
| 61 |
#ifdef USE_ITHREADS |
| 62 |
static perl_mutex coro_mutex; |
| 63 |
# define LOCK do { MUTEX_LOCK (&coro_mutex); } while (0) |
| 64 |
# define UNLOCK do { MUTEX_UNLOCK (&coro_mutex); } while (0) |
| 65 |
#else |
| 66 |
# define LOCK (void)0 |
| 67 |
# define UNLOCK (void)0 |
| 68 |
#endif |
| 69 |
|
| 70 |
static struct CoroAPI coroapi; |
| 71 |
static AV *main_mainstack; /* used to differentiate between $main and others */ |
| 72 |
static HV *coro_state_stash; |
| 73 |
static SV *ucoro_state_sv; |
| 74 |
static U32 ucoro_state_hash; |
| 75 |
static SV *coro_mortal; /* will be freed after next transfer */ |
| 76 |
|
| 77 |
/* this is actually not only the c stack but also c registers etc... */ |
| 78 |
typedef struct { |
| 79 |
int refcnt; /* pointer reference counter */ |
| 80 |
int usecnt; /* shared by how many coroutines */ |
| 81 |
int gencnt; /* generation counter */ |
| 82 |
|
| 83 |
coro_context cctx; |
| 84 |
|
| 85 |
void *sptr; |
| 86 |
long ssize; /* positive == mmap, otherwise malloc */ |
| 87 |
} coro_stack; |
| 88 |
|
| 89 |
struct coro { |
| 90 |
/* the top-level JMPENV for each coroutine, needed to catch dies. */ |
| 91 |
JMPENV start_env; |
| 92 |
|
| 93 |
/* the optional C context */ |
| 94 |
coro_stack *stack; |
| 95 |
void *cursp; |
| 96 |
int gencnt; |
| 97 |
|
| 98 |
/* optionally saved, might be zero */ |
| 99 |
AV *defav; |
| 100 |
SV *defsv; |
| 101 |
SV *errsv; |
| 102 |
|
| 103 |
/* saved global state not related to stacks */ |
| 104 |
U8 dowarn; |
| 105 |
I32 in_eval; |
| 106 |
|
| 107 |
/* the stacks and related info (callchain etc..) */ |
| 108 |
PERL_SI *curstackinfo; |
| 109 |
AV *curstack; |
| 110 |
AV *mainstack; |
| 111 |
SV **stack_sp; |
| 112 |
OP *op; |
| 113 |
SV **curpad; |
| 114 |
AV *comppad; |
| 115 |
CV *compcv; |
| 116 |
SV **stack_base; |
| 117 |
SV **stack_max; |
| 118 |
SV **tmps_stack; |
| 119 |
I32 tmps_floor; |
| 120 |
I32 tmps_ix; |
| 121 |
I32 tmps_max; |
| 122 |
I32 *markstack; |
| 123 |
I32 *markstack_ptr; |
| 124 |
I32 *markstack_max; |
| 125 |
I32 *scopestack; |
| 126 |
I32 scopestack_ix; |
| 127 |
I32 scopestack_max; |
| 128 |
ANY *savestack; |
| 129 |
I32 savestack_ix; |
| 130 |
I32 savestack_max; |
| 131 |
OP **retstack; |
| 132 |
I32 retstack_ix; |
| 133 |
I32 retstack_max; |
| 134 |
PMOP *curpm; |
| 135 |
COP *curcop; |
| 136 |
JMPENV *top_env; |
| 137 |
|
| 138 |
/* data associated with this coroutine (initial args) */ |
| 139 |
AV *args; |
| 140 |
}; |
| 141 |
|
| 142 |
typedef struct coro *Coro__State; |
| 143 |
typedef struct coro *Coro__State_or_hashref; |
| 144 |
|
| 145 |
/* mostly copied from op.c:cv_clone2 */ |
| 146 |
STATIC AV * |
| 147 |
clone_padlist (pTHX_ AV *protopadlist) |
| 148 |
{ |
| 149 |
AV *av; |
| 150 |
I32 ix; |
| 151 |
AV *protopad_name = (AV *) * av_fetch (protopadlist, 0, FALSE); |
| 152 |
AV *protopad = (AV *) * av_fetch (protopadlist, 1, FALSE); |
| 153 |
SV **pname = AvARRAY (protopad_name); |
| 154 |
SV **ppad = AvARRAY (protopad); |
| 155 |
I32 fname = AvFILLp (protopad_name); |
| 156 |
I32 fpad = AvFILLp (protopad); |
| 157 |
AV *newpadlist, *newpad_name, *newpad; |
| 158 |
SV **npad; |
| 159 |
|
| 160 |
newpad_name = newAV (); |
| 161 |
for (ix = fname; ix >= 0; ix--) |
| 162 |
av_store (newpad_name, ix, SvREFCNT_inc (pname[ix])); |
| 163 |
|
| 164 |
newpad = newAV (); |
| 165 |
av_fill (newpad, AvFILLp (protopad)); |
| 166 |
npad = AvARRAY (newpad); |
| 167 |
|
| 168 |
newpadlist = newAV (); |
| 169 |
AvREAL_off (newpadlist); |
| 170 |
av_store (newpadlist, 0, (SV *) newpad_name); |
| 171 |
av_store (newpadlist, 1, (SV *) newpad); |
| 172 |
|
| 173 |
av = newAV (); /* will be @_ */ |
| 174 |
av_extend (av, 0); |
| 175 |
av_store (newpad, 0, (SV *) av); |
| 176 |
AvREIFY_on (av); |
| 177 |
|
| 178 |
for (ix = fpad; ix > 0; ix--) |
| 179 |
{ |
| 180 |
SV *namesv = (ix <= fname) ? pname[ix] : Nullsv; |
| 181 |
|
| 182 |
if (namesv && namesv != &PL_sv_undef) |
| 183 |
{ |
| 184 |
char *name = SvPVX (namesv); /* XXX */ |
| 185 |
|
| 186 |
if (SvFLAGS (namesv) & SVf_FAKE || *name == '&') |
| 187 |
{ /* lexical from outside? */ |
| 188 |
npad[ix] = SvREFCNT_inc (ppad[ix]); |
| 189 |
} |
| 190 |
else |
| 191 |
{ /* our own lexical */ |
| 192 |
SV *sv; |
| 193 |
if (*name == '&') |
| 194 |
sv = SvREFCNT_inc (ppad[ix]); |
| 195 |
else if (*name == '@') |
| 196 |
sv = (SV *) newAV (); |
| 197 |
else if (*name == '%') |
| 198 |
sv = (SV *) newHV (); |
| 199 |
else |
| 200 |
sv = NEWSV (0, 0); |
| 201 |
|
| 202 |
#ifdef SvPADBUSY |
| 203 |
if (!SvPADBUSY (sv)) |
| 204 |
#endif |
| 205 |
SvPADMY_on (sv); |
| 206 |
|
| 207 |
npad[ix] = sv; |
| 208 |
} |
| 209 |
} |
| 210 |
else if (IS_PADGV (ppad[ix]) || IS_PADCONST (ppad[ix])) |
| 211 |
{ |
| 212 |
npad[ix] = SvREFCNT_inc (ppad[ix]); |
| 213 |
} |
| 214 |
else |
| 215 |
{ |
| 216 |
SV *sv = NEWSV (0, 0); |
| 217 |
SvPADTMP_on (sv); |
| 218 |
npad[ix] = sv; |
| 219 |
} |
| 220 |
} |
| 221 |
|
| 222 |
#if 0 /* return -ENOTUNDERSTOOD */ |
| 223 |
/* Now that vars are all in place, clone nested closures. */ |
| 224 |
|
| 225 |
for (ix = fpad; ix > 0; ix--) { |
| 226 |
SV* namesv = (ix <= fname) ? pname[ix] : Nullsv; |
| 227 |
if (namesv |
| 228 |
&& namesv != &PL_sv_undef |
| 229 |
&& !(SvFLAGS(namesv) & SVf_FAKE) |
| 230 |
&& *SvPVX(namesv) == '&' |
| 231 |
&& CvCLONE(ppad[ix])) |
| 232 |
{ |
| 233 |
CV *kid = cv_clone((CV*)ppad[ix]); |
| 234 |
SvREFCNT_dec(ppad[ix]); |
| 235 |
CvCLONE_on(kid); |
| 236 |
SvPADMY_on(kid); |
| 237 |
npad[ix] = (SV*)kid; |
| 238 |
} |
| 239 |
} |
| 240 |
#endif |
| 241 |
|
| 242 |
return newpadlist; |
| 243 |
} |
| 244 |
|
| 245 |
STATIC void |
| 246 |
free_padlist (pTHX_ AV *padlist) |
| 247 |
{ |
| 248 |
/* may be during global destruction */ |
| 249 |
if (SvREFCNT (padlist)) |
| 250 |
{ |
| 251 |
I32 i = AvFILLp (padlist); |
| 252 |
while (i >= 0) |
| 253 |
{ |
| 254 |
SV **svp = av_fetch (padlist, i--, FALSE); |
| 255 |
if (svp) |
| 256 |
{ |
| 257 |
SV *sv; |
| 258 |
while (&PL_sv_undef != (sv = av_pop ((AV *)*svp))) |
| 259 |
SvREFCNT_dec (sv); |
| 260 |
|
| 261 |
SvREFCNT_dec (*svp); |
| 262 |
} |
| 263 |
} |
| 264 |
|
| 265 |
SvREFCNT_dec ((SV*)padlist); |
| 266 |
} |
| 267 |
} |
| 268 |
|
| 269 |
STATIC int |
| 270 |
coro_cv_free (pTHX_ SV *sv, MAGIC *mg) |
| 271 |
{ |
| 272 |
AV *padlist; |
| 273 |
AV *av = (AV *)mg->mg_obj; |
| 274 |
|
| 275 |
/* casting is fun. */ |
| 276 |
while (&PL_sv_undef != (SV *)(padlist = (AV *)av_pop (av))) |
| 277 |
free_padlist (aTHX_ padlist); |
| 278 |
|
| 279 |
SvREFCNT_dec (av); |
| 280 |
} |
| 281 |
|
| 282 |
#define PERL_MAGIC_coro PERL_MAGIC_ext |
| 283 |
|
| 284 |
static MGVTBL vtbl_coro = {0, 0, 0, 0, coro_cv_free}; |
| 285 |
|
| 286 |
/* the next two functions merely cache the padlists */ |
| 287 |
STATIC void |
| 288 |
get_padlist (pTHX_ CV *cv) |
| 289 |
{ |
| 290 |
MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); |
| 291 |
|
| 292 |
if (mg && AvFILLp ((AV *)mg->mg_obj) >= 0) |
| 293 |
CvPADLIST (cv) = (AV *)av_pop ((AV *)mg->mg_obj); |
| 294 |
else |
| 295 |
CvPADLIST (cv) = clone_padlist (aTHX_ CvPADLIST (cv)); |
| 296 |
} |
| 297 |
|
| 298 |
STATIC void |
| 299 |
put_padlist (pTHX_ CV *cv) |
| 300 |
{ |
| 301 |
MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); |
| 302 |
|
| 303 |
if (!mg) |
| 304 |
{ |
| 305 |
sv_magic ((SV *)cv, 0, PERL_MAGIC_coro, 0, 0); |
| 306 |
mg = mg_find ((SV *)cv, PERL_MAGIC_coro); |
| 307 |
mg->mg_virtual = &vtbl_coro; |
| 308 |
mg->mg_obj = (SV *)newAV (); |
| 309 |
} |
| 310 |
|
| 311 |
av_push ((AV *)mg->mg_obj, (SV *)CvPADLIST (cv)); |
| 312 |
} |
| 313 |
|
| 314 |
#define SB do { |
| 315 |
#define SE } while (0) |
| 316 |
|
| 317 |
#define LOAD(state) load_state(aTHX_ (state)); |
| 318 |
#define SAVE(state,flags) save_state(aTHX_ (state),(flags)); |
| 319 |
|
| 320 |
#define REPLACE_SV(sv,val) SB SvREFCNT_dec(sv); (sv) = (val); (val) = 0; SE |
| 321 |
|
| 322 |
static void |
| 323 |
load_state(pTHX_ Coro__State c) |
| 324 |
{ |
| 325 |
PL_dowarn = c->dowarn; |
| 326 |
PL_in_eval = c->in_eval; |
| 327 |
|
| 328 |
PL_curstackinfo = c->curstackinfo; |
| 329 |
PL_curstack = c->curstack; |
| 330 |
PL_mainstack = c->mainstack; |
| 331 |
PL_stack_sp = c->stack_sp; |
| 332 |
PL_op = c->op; |
| 333 |
PL_curpad = c->curpad; |
| 334 |
PL_comppad = c->comppad; |
| 335 |
PL_compcv = c->compcv; |
| 336 |
PL_stack_base = c->stack_base; |
| 337 |
PL_stack_max = c->stack_max; |
| 338 |
PL_tmps_stack = c->tmps_stack; |
| 339 |
PL_tmps_floor = c->tmps_floor; |
| 340 |
PL_tmps_ix = c->tmps_ix; |
| 341 |
PL_tmps_max = c->tmps_max; |
| 342 |
PL_markstack = c->markstack; |
| 343 |
PL_markstack_ptr = c->markstack_ptr; |
| 344 |
PL_markstack_max = c->markstack_max; |
| 345 |
PL_scopestack = c->scopestack; |
| 346 |
PL_scopestack_ix = c->scopestack_ix; |
| 347 |
PL_scopestack_max = c->scopestack_max; |
| 348 |
PL_savestack = c->savestack; |
| 349 |
PL_savestack_ix = c->savestack_ix; |
| 350 |
PL_savestack_max = c->savestack_max; |
| 351 |
#if PERL_VERSION < 9 |
| 352 |
PL_retstack = c->retstack; |
| 353 |
PL_retstack_ix = c->retstack_ix; |
| 354 |
PL_retstack_max = c->retstack_max; |
| 355 |
#endif |
| 356 |
PL_curpm = c->curpm; |
| 357 |
PL_curcop = c->curcop; |
| 358 |
PL_top_env = c->top_env; |
| 359 |
|
| 360 |
if (c->defav) REPLACE_SV (GvAV (PL_defgv), c->defav); |
| 361 |
if (c->defsv) REPLACE_SV (DEFSV , c->defsv); |
| 362 |
if (c->errsv) REPLACE_SV (ERRSV , c->errsv); |
| 363 |
|
| 364 |
{ |
| 365 |
dSP; |
| 366 |
CV *cv; |
| 367 |
|
| 368 |
/* now do the ugly restore mess */ |
| 369 |
while ((cv = (CV *)POPs)) |
| 370 |
{ |
| 371 |
AV *padlist = (AV *)POPs; |
| 372 |
|
| 373 |
if (padlist) |
| 374 |
{ |
| 375 |
put_padlist (aTHX_ cv); /* mark this padlist as available */ |
| 376 |
CvPADLIST(cv) = padlist; |
| 377 |
} |
| 378 |
|
| 379 |
++CvDEPTH(cv); |
| 380 |
} |
| 381 |
|
| 382 |
PUTBACK; |
| 383 |
} |
| 384 |
} |
| 385 |
|
| 386 |
static void |
| 387 |
save_state(pTHX_ Coro__State c, int flags) |
| 388 |
{ |
| 389 |
{ |
| 390 |
dSP; |
| 391 |
I32 cxix = cxstack_ix; |
| 392 |
PERL_CONTEXT *ccstk = cxstack; |
| 393 |
PERL_SI *top_si = PL_curstackinfo; |
| 394 |
|
| 395 |
/* |
| 396 |
* the worst thing you can imagine happens first - we have to save |
| 397 |
* (and reinitialize) all cv's in the whole callchain :( |
| 398 |
*/ |
| 399 |
|
| 400 |
PUSHs (Nullsv); |
| 401 |
/* this loop was inspired by pp_caller */ |
| 402 |
for (;;) |
| 403 |
{ |
| 404 |
while (cxix >= 0) |
| 405 |
{ |
| 406 |
PERL_CONTEXT *cx = &ccstk[cxix--]; |
| 407 |
|
| 408 |
if (CxTYPE(cx) == CXt_SUB) |
| 409 |
{ |
| 410 |
CV *cv = cx->blk_sub.cv; |
| 411 |
if (CvDEPTH(cv)) |
| 412 |
{ |
| 413 |
EXTEND (SP, CvDEPTH(cv)*2); |
| 414 |
|
| 415 |
while (--CvDEPTH(cv)) |
| 416 |
{ |
| 417 |
/* this tells the restore code to increment CvDEPTH */ |
| 418 |
PUSHs (Nullsv); |
| 419 |
PUSHs ((SV *)cv); |
| 420 |
} |
| 421 |
|
| 422 |
PUSHs ((SV *)CvPADLIST(cv)); |
| 423 |
PUSHs ((SV *)cv); |
| 424 |
|
| 425 |
get_padlist (aTHX_ cv); /* this is a monster */ |
| 426 |
} |
| 427 |
} |
| 428 |
#ifdef CXt_FORMAT |
| 429 |
else if (CxTYPE(cx) == CXt_FORMAT) |
| 430 |
{ |
| 431 |
/* I never used formats, so how should I know how these are implemented? */ |
| 432 |
/* my bold guess is as a simple, plain sub... */ |
| 433 |
croak ("CXt_FORMAT not yet handled. Don't switch coroutines from within formats"); |
| 434 |
} |
| 435 |
#endif |
| 436 |
} |
| 437 |
|
| 438 |
if (top_si->si_type == PERLSI_MAIN) |
| 439 |
break; |
| 440 |
|
| 441 |
top_si = top_si->si_prev; |
| 442 |
ccstk = top_si->si_cxstack; |
| 443 |
cxix = top_si->si_cxix; |
| 444 |
} |
| 445 |
|
| 446 |
PUTBACK; |
| 447 |
} |
| 448 |
|
| 449 |
c->defav = flags & TRANSFER_SAVE_DEFAV ? (AV *)SvREFCNT_inc (GvAV (PL_defgv)) : 0; |
| 450 |
c->defsv = flags & TRANSFER_SAVE_DEFSV ? SvREFCNT_inc (DEFSV) : 0; |
| 451 |
c->errsv = flags & TRANSFER_SAVE_ERRSV ? SvREFCNT_inc (ERRSV) : 0; |
| 452 |
|
| 453 |
c->dowarn = PL_dowarn; |
| 454 |
c->in_eval = PL_in_eval; |
| 455 |
|
| 456 |
c->curstackinfo = PL_curstackinfo; |
| 457 |
c->curstack = PL_curstack; |
| 458 |
c->mainstack = PL_mainstack; |
| 459 |
c->stack_sp = PL_stack_sp; |
| 460 |
c->op = PL_op; |
| 461 |
c->curpad = PL_curpad; |
| 462 |
c->comppad = PL_comppad; |
| 463 |
c->compcv = PL_compcv; |
| 464 |
c->stack_base = PL_stack_base; |
| 465 |
c->stack_max = PL_stack_max; |
| 466 |
c->tmps_stack = PL_tmps_stack; |
| 467 |
c->tmps_floor = PL_tmps_floor; |
| 468 |
c->tmps_ix = PL_tmps_ix; |
| 469 |
c->tmps_max = PL_tmps_max; |
| 470 |
c->markstack = PL_markstack; |
| 471 |
c->markstack_ptr = PL_markstack_ptr; |
| 472 |
c->markstack_max = PL_markstack_max; |
| 473 |
c->scopestack = PL_scopestack; |
| 474 |
c->scopestack_ix = PL_scopestack_ix; |
| 475 |
c->scopestack_max = PL_scopestack_max; |
| 476 |
c->savestack = PL_savestack; |
| 477 |
c->savestack_ix = PL_savestack_ix; |
| 478 |
c->savestack_max = PL_savestack_max; |
| 479 |
#if PERL_VERSION < 9 |
| 480 |
c->retstack = PL_retstack; |
| 481 |
c->retstack_ix = PL_retstack_ix; |
| 482 |
c->retstack_max = PL_retstack_max; |
| 483 |
#endif |
| 484 |
c->curpm = PL_curpm; |
| 485 |
c->curcop = PL_curcop; |
| 486 |
c->top_env = PL_top_env; |
| 487 |
} |
| 488 |
|
| 489 |
/* |
| 490 |
* allocate various perl stacks. This is an exact copy |
| 491 |
* of perl.c:init_stacks, except that it uses less memory |
| 492 |
* on the (sometimes correct) assumption that coroutines do |
| 493 |
* not usually need a lot of stackspace. |
| 494 |
*/ |
| 495 |
STATIC void |
| 496 |
coro_init_stacks (pTHX) |
| 497 |
{ |
| 498 |
LOCK; |
| 499 |
|
| 500 |
PL_curstackinfo = new_stackinfo(96, 1024/sizeof(PERL_CONTEXT) - 1); |
| 501 |
PL_curstackinfo->si_type = PERLSI_MAIN; |
| 502 |
PL_curstack = PL_curstackinfo->si_stack; |
| 503 |
PL_mainstack = PL_curstack; /* remember in case we switch stacks */ |
| 504 |
|
| 505 |
PL_stack_base = AvARRAY(PL_curstack); |
| 506 |
PL_stack_sp = PL_stack_base; |
| 507 |
PL_stack_max = PL_stack_base + AvMAX(PL_curstack); |
| 508 |
|
| 509 |
New(50,PL_tmps_stack,96,SV*); |
| 510 |
PL_tmps_floor = -1; |
| 511 |
PL_tmps_ix = -1; |
| 512 |
PL_tmps_max = 96; |
| 513 |
|
| 514 |
New(54,PL_markstack,16,I32); |
| 515 |
PL_markstack_ptr = PL_markstack; |
| 516 |
PL_markstack_max = PL_markstack + 16; |
| 517 |
|
| 518 |
#ifdef SET_MARK_OFFSET |
| 519 |
SET_MARK_OFFSET; |
| 520 |
#endif |
| 521 |
|
| 522 |
New(54,PL_scopestack,16,I32); |
| 523 |
PL_scopestack_ix = 0; |
| 524 |
PL_scopestack_max = 16; |
| 525 |
|
| 526 |
New(54,PL_savestack,96,ANY); |
| 527 |
PL_savestack_ix = 0; |
| 528 |
PL_savestack_max = 96; |
| 529 |
|
| 530 |
#if PERL_VERSION < 9 |
| 531 |
New(54,PL_retstack,8,OP*); |
| 532 |
PL_retstack_ix = 0; |
| 533 |
PL_retstack_max = 8; |
| 534 |
#endif |
| 535 |
|
| 536 |
UNLOCK; |
| 537 |
} |
| 538 |
|
| 539 |
/* |
| 540 |
* destroy the stacks, the callchain etc... |
| 541 |
*/ |
| 542 |
STATIC void |
| 543 |
destroy_stacks(pTHX) |
| 544 |
{ |
| 545 |
if (!IN_DESTRUCT) |
| 546 |
{ |
| 547 |
/* is this ugly, I ask? */ |
| 548 |
LEAVE_SCOPE (0); |
| 549 |
|
| 550 |
/* sure it is, but more important: is it correct?? :/ */ |
| 551 |
FREETMPS; |
| 552 |
|
| 553 |
/*POPSTACK_TO (PL_mainstack);*//*D*//*use*/ |
| 554 |
} |
| 555 |
|
| 556 |
while (PL_curstackinfo->si_next) |
| 557 |
PL_curstackinfo = PL_curstackinfo->si_next; |
| 558 |
|
| 559 |
while (PL_curstackinfo) |
| 560 |
{ |
| 561 |
PERL_SI *p = PL_curstackinfo->si_prev; |
| 562 |
|
| 563 |
{ /*D*//*remove*/ |
| 564 |
dSP; |
| 565 |
SWITCHSTACK (PL_curstack, PL_curstackinfo->si_stack); |
| 566 |
PUTBACK; /* possibly superfluous */ |
| 567 |
} |
| 568 |
|
| 569 |
if (!IN_DESTRUCT) |
| 570 |
{ |
| 571 |
dounwind (-1);/*D*//*remove*/ |
| 572 |
SvREFCNT_dec (PL_curstackinfo->si_stack); |
| 573 |
} |
| 574 |
|
| 575 |
Safefree (PL_curstackinfo->si_cxstack); |
| 576 |
Safefree (PL_curstackinfo); |
| 577 |
PL_curstackinfo = p; |
| 578 |
} |
| 579 |
|
| 580 |
Safefree (PL_tmps_stack); |
| 581 |
Safefree (PL_markstack); |
| 582 |
Safefree (PL_scopestack); |
| 583 |
Safefree (PL_savestack); |
| 584 |
#if PERL_VERSION < 9 |
| 585 |
Safefree (PL_retstack); |
| 586 |
#endif |
| 587 |
} |
| 588 |
|
| 589 |
static void |
| 590 |
allocate_stack (Coro__State ctx, int alloc) |
| 591 |
{ |
| 592 |
coro_stack *stack; |
| 593 |
|
| 594 |
New (0, stack, 1, coro_stack); |
| 595 |
|
| 596 |
stack->refcnt = 1; |
| 597 |
stack->usecnt = 1; |
| 598 |
stack->gencnt = ctx->gencnt = 0; |
| 599 |
|
| 600 |
if (alloc) |
| 601 |
{ |
| 602 |
#if HAVE_MMAP |
| 603 |
stack->ssize = STACKSIZE * sizeof (long); /* mmap should do allocate-on-write for us */ |
| 604 |
stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); |
| 605 |
if (stack->sptr == (void *)-1) |
| 606 |
#endif |
| 607 |
{ |
| 608 |
/*FIXME*//*D*//* reasonable stack size! */ |
| 609 |
stack->ssize = - (STACKSIZE * sizeof (long)); |
| 610 |
New (0, stack->sptr, STACKSIZE, long); |
| 611 |
} |
| 612 |
} |
| 613 |
else |
| 614 |
stack->sptr = 0; |
| 615 |
|
| 616 |
ctx->stack = stack; |
| 617 |
} |
| 618 |
|
| 619 |
static void |
| 620 |
deallocate_stack (Coro__State ctx) |
| 621 |
{ |
| 622 |
coro_stack *stack = ctx->stack; |
| 623 |
|
| 624 |
ctx->stack = 0; |
| 625 |
|
| 626 |
if (stack) |
| 627 |
{ |
| 628 |
if (!--stack->refcnt) |
| 629 |
{ |
| 630 |
#ifdef HAVE_MMAP |
| 631 |
if (stack->ssize > 0 && stack->sptr) |
| 632 |
munmap (stack->sptr, stack->ssize); |
| 633 |
else |
| 634 |
#endif |
| 635 |
Safefree (stack->sptr); |
| 636 |
|
| 637 |
Safefree (stack); |
| 638 |
} |
| 639 |
else if (ctx->gencnt == stack->gencnt) |
| 640 |
--stack->usecnt; |
| 641 |
} |
| 642 |
} |
| 643 |
|
| 644 |
static void |
| 645 |
setup_coro (void *arg) |
| 646 |
{ |
| 647 |
/* |
| 648 |
* emulate part of the perl startup here. |
| 649 |
*/ |
| 650 |
dTHX; |
| 651 |
dSP; |
| 652 |
Coro__State ctx = (Coro__State)arg; |
| 653 |
SV *sub_init = (SV *)get_cv (SUB_INIT, FALSE); |
| 654 |
|
| 655 |
coro_init_stacks (aTHX); |
| 656 |
/*PL_curcop = 0;*/ |
| 657 |
/*PL_in_eval = PL_in_eval;*/ /* inherit */ |
| 658 |
SvREFCNT_dec (GvAV (PL_defgv)); |
| 659 |
GvAV (PL_defgv) = ctx->args; ctx->args = 0; |
| 660 |
|
| 661 |
SPAGAIN; |
| 662 |
|
| 663 |
if (ctx->stack) |
| 664 |
{ |
| 665 |
ctx->cursp = 0; |
| 666 |
|
| 667 |
PUSHMARK(SP); |
| 668 |
PUTBACK; |
| 669 |
(void) call_sv (sub_init, G_VOID|G_NOARGS|G_EVAL); |
| 670 |
|
| 671 |
if (SvTRUE (ERRSV)) |
| 672 |
croak (NULL); |
| 673 |
else |
| 674 |
croak ("FATAL: CCTXT coroutine returned!"); |
| 675 |
} |
| 676 |
else |
| 677 |
{ |
| 678 |
UNOP myop; |
| 679 |
|
| 680 |
PL_op = (OP *)&myop; |
| 681 |
|
| 682 |
Zero(&myop, 1, UNOP); |
| 683 |
myop.op_next = Nullop; |
| 684 |
myop.op_flags = OPf_WANT_VOID; |
| 685 |
|
| 686 |
PUSHMARK(SP); |
| 687 |
XPUSHs (sub_init); |
| 688 |
/* |
| 689 |
* the next line is slightly wrong, as PL_op->op_next |
| 690 |
* is actually being executed so we skip the first op. |
| 691 |
* that doesn't matter, though, since it is only |
| 692 |
* pp_nextstate and we never return... |
| 693 |
* ah yes, and I don't care anyways ;) |
| 694 |
*/ |
| 695 |
PUTBACK; |
| 696 |
PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
| 697 |
SPAGAIN; |
| 698 |
|
| 699 |
ENTER; /* necessary e.g. for dounwind */ |
| 700 |
} |
| 701 |
} |
| 702 |
|
| 703 |
static void |
| 704 |
continue_coro (void *arg) |
| 705 |
{ |
| 706 |
/* |
| 707 |
* this is a _very_ stripped down perl interpreter ;) |
| 708 |
*/ |
| 709 |
dTHX; |
| 710 |
Coro__State ctx = (Coro__State)arg; |
| 711 |
JMPENV coro_start_env; |
| 712 |
|
| 713 |
PL_top_env = &ctx->start_env; |
| 714 |
|
| 715 |
ctx->cursp = 0; |
| 716 |
PL_op = PL_op->op_next; |
| 717 |
CALLRUNOPS(aTHX); |
| 718 |
|
| 719 |
abort (); |
| 720 |
} |
| 721 |
|
| 722 |
STATIC void |
| 723 |
transfer (pTHX_ struct coro *prev, struct coro *next, int flags) |
| 724 |
{ |
| 725 |
dSTACKLEVEL; |
| 726 |
|
| 727 |
if (prev != next) |
| 728 |
{ |
| 729 |
if (next->mainstack) |
| 730 |
{ |
| 731 |
LOCK; |
| 732 |
SAVE (prev, flags); |
| 733 |
LOAD (next); |
| 734 |
UNLOCK; |
| 735 |
|
| 736 |
/* mark this state as in-use */ |
| 737 |
next->mainstack = 0; |
| 738 |
next->tmps_ix = -2; |
| 739 |
|
| 740 |
/* stacklevel changed? if yes, grab the stack for us! */ |
| 741 |
if (flags & TRANSFER_SAVE_CCTXT) |
| 742 |
{ |
| 743 |
if (!prev->stack) |
| 744 |
allocate_stack (prev, 0); |
| 745 |
else if (prev->cursp != stacklevel |
| 746 |
&& prev->stack->usecnt > 1) |
| 747 |
{ |
| 748 |
prev->gencnt = ++prev->stack->gencnt; |
| 749 |
prev->stack->usecnt = 1; |
| 750 |
} |
| 751 |
|
| 752 |
/* has our stack been invalidated? */ |
| 753 |
if (next->stack && next->stack->gencnt != next->gencnt) |
| 754 |
{ |
| 755 |
deallocate_stack (next); |
| 756 |
allocate_stack (next, 1); |
| 757 |
coro_create (&(next->stack->cctx), |
| 758 |
continue_coro, (void *)next, |
| 759 |
next->stack->sptr, labs (next->stack->ssize)); |
| 760 |
} |
| 761 |
|
| 762 |
coro_transfer (&(prev->stack->cctx), &(next->stack->cctx)); |
| 763 |
prev->cursp = stacklevel; |
| 764 |
/* don't add any code here */ |
| 765 |
} |
| 766 |
else |
| 767 |
next->cursp = stacklevel; |
| 768 |
} |
| 769 |
else if (next->tmps_ix == -2) |
| 770 |
croak ("tried to transfer to running coroutine"); |
| 771 |
else |
| 772 |
{ |
| 773 |
LOCK; |
| 774 |
SAVE (prev, -1); /* first get rid of the old state */ |
| 775 |
UNLOCK; |
| 776 |
|
| 777 |
if (flags & TRANSFER_SAVE_CCTXT) |
| 778 |
{ |
| 779 |
if (!prev->stack) |
| 780 |
allocate_stack (prev, 0); |
| 781 |
|
| 782 |
if (prev->stack->sptr && flags & TRANSFER_LAZY_STACK) |
| 783 |
{ |
| 784 |
PL_top_env = &next->start_env; |
| 785 |
|
| 786 |
setup_coro (next); |
| 787 |
next->cursp = stacklevel; |
| 788 |
|
| 789 |
prev->stack->refcnt++; |
| 790 |
prev->stack->usecnt++; |
| 791 |
next->stack = prev->stack; |
| 792 |
next->gencnt = prev->gencnt; |
| 793 |
} |
| 794 |
else |
| 795 |
{ |
| 796 |
assert (!next->stack); |
| 797 |
allocate_stack (next, 1); |
| 798 |
coro_create (&(next->stack->cctx), |
| 799 |
setup_coro, (void *)next, |
| 800 |
next->stack->sptr, labs (next->stack->ssize)); |
| 801 |
coro_transfer (&(prev->stack->cctx), &(next->stack->cctx)); |
| 802 |
prev->cursp = stacklevel; |
| 803 |
/* don't add any code here */ |
| 804 |
} |
| 805 |
} |
| 806 |
else |
| 807 |
{ |
| 808 |
setup_coro (next); |
| 809 |
next->cursp = stacklevel; |
| 810 |
} |
| 811 |
} |
| 812 |
} |
| 813 |
|
| 814 |
LOCK; |
| 815 |
if (coro_mortal) |
| 816 |
{ |
| 817 |
SvREFCNT_dec (coro_mortal); |
| 818 |
coro_mortal = 0; |
| 819 |
} |
| 820 |
UNLOCK; |
| 821 |
} |
| 822 |
|
| 823 |
#define SV_CORO(sv,func) \ |
| 824 |
do { \ |
| 825 |
if (SvROK (sv)) \ |
| 826 |
sv = SvRV (sv); \ |
| 827 |
\ |
| 828 |
if (SvTYPE (sv) == SVt_PVHV) \ |
| 829 |
{ \ |
| 830 |
HE *he = hv_fetch_ent ((HV *)sv, ucoro_state_sv, 0, ucoro_state_hash); \ |
| 831 |
\ |
| 832 |
if (!he) \ |
| 833 |
croak ("%s() -- %s is a hashref but lacks the " UCORO_STATE " key", func, # sv); \ |
| 834 |
\ |
| 835 |
(sv) = SvRV (HeVAL(he)); \ |
| 836 |
} \ |
| 837 |
\ |
| 838 |
/* must also be changed inside Coro::Cont::yield */ \ |
| 839 |
if (!SvOBJECT (sv) || SvSTASH (sv) != coro_state_stash) \ |
| 840 |
croak ("%s() -- %s is not (and contains not) a Coro::State object", func, # sv); \ |
| 841 |
\ |
| 842 |
} while(0) |
| 843 |
|
| 844 |
#define SvSTATE(sv) (struct coro *)SvIV (sv) |
| 845 |
|
| 846 |
static void |
| 847 |
api_transfer(pTHX_ SV *prev, SV *next, int flags) |
| 848 |
{ |
| 849 |
SV_CORO (prev, "Coro::transfer"); |
| 850 |
SV_CORO (next, "Coro::transfer"); |
| 851 |
|
| 852 |
transfer (aTHX_ SvSTATE (prev), SvSTATE (next), flags); |
| 853 |
} |
| 854 |
|
| 855 |
/** Coro ********************************************************************/ |
| 856 |
|
| 857 |
#define PRIO_MAX 3 |
| 858 |
#define PRIO_HIGH 1 |
| 859 |
#define PRIO_NORMAL 0 |
| 860 |
#define PRIO_LOW -1 |
| 861 |
#define PRIO_IDLE -3 |
| 862 |
#define PRIO_MIN -4 |
| 863 |
|
| 864 |
/* for Coro.pm */ |
| 865 |
static GV *coro_current, *coro_idle; |
| 866 |
static AV *coro_ready[PRIO_MAX-PRIO_MIN+1]; |
| 867 |
static int coro_nready; |
| 868 |
|
| 869 |
static void |
| 870 |
coro_enq (pTHX_ SV *sv) |
| 871 |
{ |
| 872 |
if (SvTYPE (sv) == SVt_PVHV) |
| 873 |
{ |
| 874 |
SV **xprio = hv_fetch ((HV *)sv, "prio", 4, 0); |
| 875 |
int prio = xprio ? SvIV (*xprio) : PRIO_NORMAL; |
| 876 |
|
| 877 |
prio = prio > PRIO_MAX ? PRIO_MAX |
| 878 |
: prio < PRIO_MIN ? PRIO_MIN |
| 879 |
: prio; |
| 880 |
|
| 881 |
av_push (coro_ready [prio - PRIO_MIN], sv); |
| 882 |
coro_nready++; |
| 883 |
|
| 884 |
return; |
| 885 |
} |
| 886 |
|
| 887 |
croak ("Coro::ready tried to enqueue something that is not a coroutine"); |
| 888 |
} |
| 889 |
|
| 890 |
static SV * |
| 891 |
coro_deq (pTHX_ int min_prio) |
| 892 |
{ |
| 893 |
int prio = PRIO_MAX - PRIO_MIN; |
| 894 |
|
| 895 |
min_prio -= PRIO_MIN; |
| 896 |
if (min_prio < 0) |
| 897 |
min_prio = 0; |
| 898 |
|
| 899 |
for (prio = PRIO_MAX - PRIO_MIN + 1; --prio >= min_prio; ) |
| 900 |
if (av_len (coro_ready[prio]) >= 0) |
| 901 |
{ |
| 902 |
coro_nready--; |
| 903 |
return av_shift (coro_ready[prio]); |
| 904 |
} |
| 905 |
|
| 906 |
return 0; |
| 907 |
} |
| 908 |
|
| 909 |
static void |
| 910 |
api_ready (SV *coro) |
| 911 |
{ |
| 912 |
dTHX; |
| 913 |
|
| 914 |
if (SvROK (coro)) |
| 915 |
coro = SvRV (coro); |
| 916 |
|
| 917 |
LOCK; |
| 918 |
coro_enq (aTHX_ SvREFCNT_inc (coro)); |
| 919 |
UNLOCK; |
| 920 |
} |
| 921 |
|
| 922 |
static void |
| 923 |
api_schedule (void) |
| 924 |
{ |
| 925 |
dTHX; |
| 926 |
|
| 927 |
SV *prev, *next; |
| 928 |
|
| 929 |
LOCK; |
| 930 |
|
| 931 |
prev = SvRV (GvSV (coro_current)); |
| 932 |
next = coro_deq (aTHX_ PRIO_MIN); |
| 933 |
|
| 934 |
if (!next) |
| 935 |
next = SvREFCNT_inc (SvRV (GvSV (coro_idle))); |
| 936 |
|
| 937 |
/* free this only after the transfer */ |
| 938 |
coro_mortal = prev; |
| 939 |
SV_CORO (prev, "Coro::schedule"); |
| 940 |
|
| 941 |
SvRV (GvSV (coro_current)) = next; |
| 942 |
|
| 943 |
SV_CORO (next, "Coro::schedule"); |
| 944 |
|
| 945 |
UNLOCK; |
| 946 |
|
| 947 |
transfer (aTHX_ SvSTATE (prev), SvSTATE (next), |
| 948 |
TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK); |
| 949 |
} |
| 950 |
|
| 951 |
static void |
| 952 |
api_cede (void) |
| 953 |
{ |
| 954 |
dTHX; |
| 955 |
|
| 956 |
LOCK; |
| 957 |
coro_enq (aTHX_ SvREFCNT_inc (SvRV (GvSV (coro_current)))); |
| 958 |
UNLOCK; |
| 959 |
|
| 960 |
api_schedule (); |
| 961 |
} |
| 962 |
|
| 963 |
MODULE = Coro::State PACKAGE = Coro::State |
| 964 |
|
| 965 |
PROTOTYPES: ENABLE |
| 966 |
|
| 967 |
BOOT: |
| 968 |
{ /* {} necessary for stoopid perl-5.6.x */ |
| 969 |
#ifdef USE_ITHREADS |
| 970 |
MUTEX_INIT (&coro_mutex); |
| 971 |
#endif |
| 972 |
|
| 973 |
ucoro_state_sv = newSVpv (UCORO_STATE, sizeof(UCORO_STATE) - 1); |
| 974 |
PERL_HASH(ucoro_state_hash, UCORO_STATE, sizeof(UCORO_STATE) - 1); |
| 975 |
coro_state_stash = gv_stashpv ("Coro::State", TRUE); |
| 976 |
|
| 977 |
newCONSTSUB (coro_state_stash, "SAVE_DEFAV", newSViv (TRANSFER_SAVE_DEFAV)); |
| 978 |
newCONSTSUB (coro_state_stash, "SAVE_DEFSV", newSViv (TRANSFER_SAVE_DEFSV)); |
| 979 |
newCONSTSUB (coro_state_stash, "SAVE_ERRSV", newSViv (TRANSFER_SAVE_ERRSV)); |
| 980 |
newCONSTSUB (coro_state_stash, "SAVE_CCTXT", newSViv (TRANSFER_SAVE_CCTXT)); |
| 981 |
|
| 982 |
main_mainstack = PL_mainstack; |
| 983 |
|
| 984 |
coroapi.ver = CORO_API_VERSION; |
| 985 |
coroapi.transfer = api_transfer; |
| 986 |
} |
| 987 |
|
| 988 |
Coro::State |
| 989 |
_newprocess(args) |
| 990 |
SV * args |
| 991 |
PROTOTYPE: $ |
| 992 |
CODE: |
| 993 |
Coro__State coro; |
| 994 |
|
| 995 |
if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV) |
| 996 |
croak ("Coro::State::_newprocess expects an arrayref"); |
| 997 |
|
| 998 |
Newz (0, coro, 1, struct coro); |
| 999 |
|
| 1000 |
coro->args = (AV *)SvREFCNT_inc (SvRV (args)); |
| 1001 |
/*coro->mainstack = 0; *//*actual work is done inside transfer */ |
| 1002 |
/*coro->stack = 0;*/ |
| 1003 |
|
| 1004 |
/* same as JMPENV_BOOTSTRAP */ |
| 1005 |
/* we might be able to recycle start_env, but safe is safe */ |
| 1006 |
/*Zero(&coro->start_env, 1, JMPENV);*/ |
| 1007 |
coro->start_env.je_ret = -1; |
| 1008 |
coro->start_env.je_mustcatch = TRUE; |
| 1009 |
|
| 1010 |
RETVAL = coro; |
| 1011 |
OUTPUT: |
| 1012 |
RETVAL |
| 1013 |
|
| 1014 |
void |
| 1015 |
transfer(prev, next, flags) |
| 1016 |
SV *prev |
| 1017 |
SV *next |
| 1018 |
int flags |
| 1019 |
PROTOTYPE: @ |
| 1020 |
CODE: |
| 1021 |
PUTBACK; |
| 1022 |
SV_CORO (next, "Coro::transfer"); |
| 1023 |
SV_CORO (prev, "Coro::transfer"); |
| 1024 |
transfer (aTHX_ SvSTATE (prev), SvSTATE (next), flags); |
| 1025 |
SPAGAIN; |
| 1026 |
|
| 1027 |
void |
| 1028 |
DESTROY(coro) |
| 1029 |
Coro::State coro |
| 1030 |
CODE: |
| 1031 |
|
| 1032 |
if (coro->mainstack && coro->mainstack != main_mainstack) |
| 1033 |
{ |
| 1034 |
struct coro temp; |
| 1035 |
|
| 1036 |
PUTBACK; |
| 1037 |
SAVE (aTHX_ (&temp), TRANSFER_SAVE_ALL); |
| 1038 |
LOAD (aTHX_ coro); |
| 1039 |
SPAGAIN; |
| 1040 |
|
| 1041 |
destroy_stacks (aTHX); |
| 1042 |
|
| 1043 |
LOAD ((&temp)); /* this will get rid of defsv etc.. */ |
| 1044 |
SPAGAIN; |
| 1045 |
|
| 1046 |
coro->mainstack = 0; |
| 1047 |
} |
| 1048 |
|
| 1049 |
deallocate_stack (coro); |
| 1050 |
SvREFCNT_dec (coro->args); |
| 1051 |
Safefree (coro); |
| 1052 |
|
| 1053 |
void |
| 1054 |
_exit(code) |
| 1055 |
int code |
| 1056 |
PROTOTYPE: $ |
| 1057 |
CODE: |
| 1058 |
_exit (code); |
| 1059 |
|
| 1060 |
MODULE = Coro::State PACKAGE = Coro::Cont |
| 1061 |
|
| 1062 |
# this is slightly dirty (should expose a c-level api) |
| 1063 |
|
| 1064 |
void |
| 1065 |
yield(...) |
| 1066 |
PROTOTYPE: @ |
| 1067 |
CODE: |
| 1068 |
SV *yieldstack; |
| 1069 |
SV *sv; |
| 1070 |
AV *defav = GvAV (PL_defgv); |
| 1071 |
struct coro *prev, *next; |
| 1072 |
|
| 1073 |
yieldstack = *hv_fetch ( |
| 1074 |
(HV *)SvRV (GvSV (coro_current)), |
| 1075 |
"yieldstack", sizeof ("yieldstack") - 1, |
| 1076 |
0 |
| 1077 |
); |
| 1078 |
|
| 1079 |
/* set up @_ -- ugly */ |
| 1080 |
av_clear (defav); |
| 1081 |
av_fill (defav, items - 1); |
| 1082 |
while (items--) |
| 1083 |
av_store (defav, items, SvREFCNT_inc (ST(items))); |
| 1084 |
|
| 1085 |
sv = av_pop ((AV *)SvRV (yieldstack)); |
| 1086 |
prev = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 0, 0))); |
| 1087 |
next = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 1, 0))); |
| 1088 |
SvREFCNT_dec (sv); |
| 1089 |
|
| 1090 |
transfer (aTHX_ prev, next, 0); |
| 1091 |
|
| 1092 |
MODULE = Coro::State PACKAGE = Coro |
| 1093 |
|
| 1094 |
# this is slightly dirty (should expose a c-level api) |
| 1095 |
|
| 1096 |
BOOT: |
| 1097 |
{ |
| 1098 |
int i; |
| 1099 |
HV *stash = gv_stashpv ("Coro", TRUE); |
| 1100 |
|
| 1101 |
newCONSTSUB (stash, "PRIO_MAX", newSViv (PRIO_MAX)); |
| 1102 |
newCONSTSUB (stash, "PRIO_HIGH", newSViv (PRIO_HIGH)); |
| 1103 |
newCONSTSUB (stash, "PRIO_NORMAL", newSViv (PRIO_NORMAL)); |
| 1104 |
newCONSTSUB (stash, "PRIO_LOW", newSViv (PRIO_LOW)); |
| 1105 |
newCONSTSUB (stash, "PRIO_IDLE", newSViv (PRIO_IDLE)); |
| 1106 |
newCONSTSUB (stash, "PRIO_MIN", newSViv (PRIO_MIN)); |
| 1107 |
|
| 1108 |
coro_current = gv_fetchpv ("Coro::current", TRUE, SVt_PV); |
| 1109 |
coro_idle = gv_fetchpv ("Coro::idle" , TRUE, SVt_PV); |
| 1110 |
|
| 1111 |
for (i = PRIO_MAX - PRIO_MIN + 1; i--; ) |
| 1112 |
coro_ready[i] = newAV (); |
| 1113 |
|
| 1114 |
{ |
| 1115 |
SV *sv = perl_get_sv("Coro::API", 1); |
| 1116 |
|
| 1117 |
coroapi.schedule = api_schedule; |
| 1118 |
coroapi.cede = api_cede; |
| 1119 |
coroapi.ready = api_ready; |
| 1120 |
coroapi.nready = &coro_nready; |
| 1121 |
coroapi.current = coro_current; |
| 1122 |
|
| 1123 |
GCoroAPI = &coroapi; |
| 1124 |
sv_setiv(sv, (IV)&coroapi); |
| 1125 |
SvREADONLY_on(sv); |
| 1126 |
} |
| 1127 |
} |
| 1128 |
|
| 1129 |
#if !PERL_MICRO |
| 1130 |
|
| 1131 |
void |
| 1132 |
ready(self) |
| 1133 |
SV * self |
| 1134 |
PROTOTYPE: $ |
| 1135 |
CODE: |
| 1136 |
api_ready (self); |
| 1137 |
|
| 1138 |
#endif |
| 1139 |
|
| 1140 |
int |
| 1141 |
nready(...) |
| 1142 |
PROTOTYPE: |
| 1143 |
CODE: |
| 1144 |
RETVAL = coro_nready; |
| 1145 |
OUTPUT: |
| 1146 |
RETVAL |
| 1147 |
|
| 1148 |
void |
| 1149 |
schedule(...) |
| 1150 |
PROTOTYPE: |
| 1151 |
CODE: |
| 1152 |
api_schedule (); |
| 1153 |
|
| 1154 |
void |
| 1155 |
cede(...) |
| 1156 |
PROTOTYPE: |
| 1157 |
CODE: |
| 1158 |
api_cede (); |
| 1159 |
|
| 1160 |
# and these are hacks |
| 1161 |
SV * |
| 1162 |
_aio_get_state () |
| 1163 |
CODE: |
| 1164 |
{ |
| 1165 |
struct { |
| 1166 |
int errorno; |
| 1167 |
int laststype; |
| 1168 |
int laststatval; |
| 1169 |
Stat_t statcache; |
| 1170 |
} data; |
| 1171 |
|
| 1172 |
data.errorno = errno; |
| 1173 |
data.laststype = PL_laststype; |
| 1174 |
data.laststatval = PL_laststatval; |
| 1175 |
data.statcache = PL_statcache; |
| 1176 |
|
| 1177 |
RETVAL = newSVpvn ((char *)&data, sizeof data); |
| 1178 |
} |
| 1179 |
OUTPUT: |
| 1180 |
RETVAL |
| 1181 |
|
| 1182 |
void |
| 1183 |
_aio_set_state (char *data_) |
| 1184 |
PROTOTYPE: $ |
| 1185 |
CODE: |
| 1186 |
{ |
| 1187 |
struct { |
| 1188 |
int errorno; |
| 1189 |
int laststype; |
| 1190 |
int laststatval; |
| 1191 |
Stat_t statcache; |
| 1192 |
} *data = (void *)data_; |
| 1193 |
|
| 1194 |
errno = data->errorno; |
| 1195 |
PL_laststype = data->laststype; |
| 1196 |
PL_laststatval = data->laststatval; |
| 1197 |
PL_statcache = data->statcache; |
| 1198 |
} |