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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines