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.6 by root, Tue Jul 17 15:42:28 2001 UTC vs.
Revision 1.68 by root, Mon Dec 12 20:28:30 2005 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines