| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,9 +41,6 @@ PyAPI_DATA(PyTypeObject) PyGen_Type; | |||
| 41 | 41 | PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *); | |
| 42 | 42 | PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(struct _frame *, | |
| 43 | 43 | PyObject *name, PyObject *qualname); | |
| 44 | - #ifdef STACKLESS | ||
| 45 | - #define PyGen_NewWithQualName PyGenerator_NewWithQualName | ||
| 46 | - #endif | ||
| 47 | 44 | PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); | |
| 48 | 45 | PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); | |
| 49 | 46 | PyObject *_PyGen_Send(PyGenObject *, PyObject *); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -558,13 +558,8 @@ PyTypeObject PyGen_Type = { | |||
| 558 | 558 | ||
| 559 | 559 | STACKLESS_DECLARE_METHOD(&PyGen_Type, tp_iternext); | |
| 560 | 560 | ||
| 561 | - #ifdef STACKLESS | ||
| 562 | - PyObject * | ||
| 563 | - PyGenerator_NewWithQualName(PyFrameObject *f, PyObject *name, PyObject *qualname) | ||
| 564 | - #else | ||
| 565 | 561 | PyObject * | |
| 566 | 562 | PyGen_NewWithQualName(PyFrameObject *f, PyObject *name, PyObject *qualname) | |
| 567 | - #endif | ||
| 568 | 563 | { | |
| 569 | 564 | PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type); | |
| 570 | 565 | if (gen == NULL) { | |
@@ -573,19 +568,8 @@ PyGen_NewWithQualName(PyFrameObject *f, PyObject *name, PyObject *qualname) | |||
| 573 | 568 | } | |
| 574 | 569 | gen->gi_frame = f; | |
| 575 | 570 | f->f_gen = (PyObject *) gen; | |
| 576 | - #ifdef STACKLESS | ||
| 577 | - /* Support for unpickling generators. This will segmentation fault if | ||
| 578 | - called by pricklepit.c:gen_new as that passes Py_None as a placeholder. */ | ||
| 579 | - if ((PyObject*)f == Py_None) { | ||
| 580 | - Py_INCREF(Py_None); | ||
| 581 | - gen->gi_code = Py_None; | ||
| 582 | - } else { | ||
| 583 | - #endif | ||
| 584 | 571 | Py_INCREF(f->f_code); | |
| 585 | 572 | gen->gi_code = (PyObject *)(f->f_code); | |
| 586 | - #ifdef STACKLESS | ||
| 587 | - } | ||
| 588 | - #endif | ||
| 589 | 573 | gen->gi_running = 0; | |
| 590 | 574 | gen->gi_weakreflist = NULL; | |
| 591 | 575 | if (name != NULL) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,12 @@ What's New in Stackless 3.X.X? | |||
| 9 | 9 | ||
| 10 | 10 | *Release date: 20XX-XX-XX* | |
| 11 | 11 | ||
| 12 | + - https://bitbucket.org/stackless-dev/stackless/issues/111 | ||
| 13 | + Restore the Python ABI function PyGen_New(). Previously Stackless named this | ||
| 14 | + function PyGenerator_New() and used a macro the redefine PyGen_New as | ||
| 15 | + PyGenerator_New. Stackless is now again binary compatible with Python- | ||
| 16 | + extensions using PyGen_New(). | ||
| 17 | + | ||
| 12 | 18 | - https://bitbucket.org/stackless-dev/stackless/issues/107 | |
| 13 | 19 | Improve unpickling of traceback objects. Stackless now reconstructs the | |
| 14 | 20 | frame.f_back linkage in frames directly referenced by traceback objects. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -128,11 +128,7 @@ struct _frame * slp_clone_frame(struct _frame *f); | |||
| 128 | 128 | struct _frame * slp_ensure_new_frame(struct _frame *f); | |
| 129 | 129 | ||
| 130 | 130 | /* exposing some hidden types */ | |
| 131 | - | ||
| 132 | - PyAPI_DATA(PyTypeObject) PyGen_Type; | ||
| 133 | - PyAPI_FUNC(PyObject *) PyGenerator_NewWithQualName(struct _frame *f, PyObject *name, PyObject *qualname); | ||
| 134 | 131 | PyObject * slp_gen_send_ex(PyGenObject *gen, PyObject *arg, int exc); | |
| 135 | - #define PyGenerator_Check(op) PyObject_TypeCheck(op, &PyGen_Type) | ||
| 136 | 132 | ||
| 137 | 133 | PyAPI_DATA(PyTypeObject) PyMethodDescr_Type; | |
| 138 | 134 | PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2232,29 +2232,12 @@ static int init_methodwrappertype(void) | |||
| 2232 | 2232 | ||
| 2233 | 2233 | ******************************************************/ | |
| 2234 | 2234 | ||
| 2235 | - /* Note: this definition is not compatible to 2.2.3, since | ||
| 2236 | - the gi_weakreflist does not exist. Therefore, we don't | ||
| 2237 | - create the object ourselves, but use the provided function | ||
| 2238 | - with a fake frame. The gi_weakreflist is not touched. | ||
| 2239 | - */ | ||
| 2240 | - | ||
| 2241 | - typedef struct { | ||
| 2242 | - PyObject_HEAD | ||
| 2243 | - /* The gi_ prefix is intended to remind of generator-iterator. */ | ||
| 2244 | - | ||
| 2245 | - PyFrameObject *gi_frame; | ||
| 2246 | - | ||
| 2247 | - /* True if generator is being executed. */ | ||
| 2248 | - char gi_running; | ||
| 2249 | - | ||
| 2250 | - /* List of weak reference. */ | ||
| 2251 | - PyObject *gi_weakreflist; | ||
| 2252 | - } genobject; | ||
| 2253 | - | ||
| 2254 | 2235 | static PyTypeObject wrap_PyGen_Type; | |
| 2236 | + /* Used to initialize a generator created by gen_new. */ | ||
| 2237 | + static PyFrameObject *gen_exhausted_frame; | ||
| 2255 | 2238 | ||
| 2256 | 2239 | static PyObject * | |
| 2257 | - gen_reduce(genobject *gen) | ||
| 2240 | + gen_reduce(PyGenObject *gen) | ||
| 2258 | 2241 | { | |
| 2259 | 2242 | PyObject *tup; | |
| 2260 | 2243 | tup = Py_BuildValue("(O()(Oi))", | |
@@ -2268,11 +2251,13 @@ gen_reduce(genobject *gen) | |||
| 2268 | 2251 | static PyObject * | |
| 2269 | 2252 | gen_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |
| 2270 | 2253 | { | |
| 2271 | - genobject *gen; | ||
| 2272 | - | ||
| 2254 | + PyGenObject *gen; | ||
| 2273 | 2255 | if (is_wrong_type(type)) return NULL; | |
| 2274 | - Py_INCREF(Py_None); | ||
| 2275 | - gen = (genobject *) PyGenerator_NewWithQualName((PyFrameObject *) Py_None, NULL, NULL); | ||
| 2256 | + | ||
| 2257 | + /* A reference to frame is stolen by PyGen_New. */ | ||
| 2258 | + assert(gen_exhausted_frame != NULL); | ||
| 2259 | + assert(PyFrame_Check(gen_exhausted_frame)); | ||
| 2260 | + gen = (PyGenObject *) PyGen_NewWithQualName(slp_ensure_new_frame(gen_exhausted_frame), NULL, NULL); | ||
| 2276 | 2261 | if (gen == NULL) | |
| 2277 | 2262 | return NULL; | |
| 2278 | 2263 | Py_TYPE(gen) = type; | |
@@ -2282,7 +2267,7 @@ gen_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |||
| 2282 | 2267 | static PyObject * | |
| 2283 | 2268 | gen_setstate(PyObject *self, PyObject *args) | |
| 2284 | 2269 | { | |
| 2285 | - genobject *gen = (genobject *) self; | ||
| 2270 | + PyGenObject *gen = (PyGenObject *) self; | ||
| 2286 | 2271 | PyFrameObject *f; | |
| 2287 | 2272 | int gi_running; | |
| 2288 | 2273 | ||
@@ -2294,16 +2279,17 @@ gen_setstate(PyObject *self, PyObject *args) | |||
| 2294 | 2279 | if (!gi_running) { | |
| 2295 | 2280 | if ((f = slp_ensure_new_frame(f)) != NULL) { | |
| 2296 | 2281 | /* use a second one for late initialization */ | |
| 2297 | - genobject *tmpgen; | ||
| 2282 | + PyGenObject *tmpgen; | ||
| 2298 | 2283 | /* PyGenerator_New eats an existing reference */ | |
| 2299 | - if ((tmpgen = (genobject *) | ||
| 2300 | - PyGenerator_NewWithQualName(f, NULL, NULL)) == NULL) { | ||
| 2284 | + if ((tmpgen = (PyGenObject *) | ||
| 2285 | + PyGen_NewWithQualName(f, NULL, NULL)) == NULL) { | ||
| 2301 | 2286 | Py_DECREF(f); | |
| 2302 | 2287 | return NULL; | |
| 2303 | 2288 | } | |
| 2304 | 2289 | Py_INCREF(f); | |
| 2305 | - Py_CLEAR(gen->gi_frame); | ||
| 2306 | - gen->gi_frame = f; | ||
| 2290 | + Py_SETREF(gen->gi_frame, f); | ||
| 2291 | + Py_INCREF(f->f_code); | ||
| 2292 | + Py_SETREF(gen->gi_code, (PyObject *)f->f_code); | ||
| 2307 | 2293 | /* The frame the temporary generator references | |
| 2308 | 2294 | will have GeneratorExit raised on it, when the | |
| 2309 | 2295 | temporary generator is torn down. So clearing | |
@@ -2327,8 +2313,9 @@ gen_setstate(PyObject *self, PyObject *args) | |||
| 2327 | 2313 | * generator without the corresponding tasklet. | |
| 2328 | 2314 | */ | |
| 2329 | 2315 | Py_INCREF(f); | |
| 2330 | - Py_CLEAR(gen->gi_frame); | ||
| 2331 | - gen->gi_frame = f; | ||
| 2316 | + Py_SETREF(gen->gi_frame, f); | ||
| 2317 | + Py_INCREF(f->f_code); | ||
| 2318 | + Py_SETREF(gen->gi_code, (PyObject *)f->f_code); | ||
| 2332 | 2319 | gen->gi_running = gi_running; | |
| 2333 | 2320 | Py_TYPE(gen) = Py_TYPE(gen)->tp_base; | |
| 2334 | 2321 | Py_INCREF(gen); | |
@@ -2343,10 +2330,10 @@ DEF_INVALID_EXEC(gen_iternext_callback) | |||
| 2343 | 2330 | static int init_generatortype(void) | |
| 2344 | 2331 | { | |
| 2345 | 2332 | int res; | |
| 2346 | - genobject *gen = (genobject *) run_script( | ||
| 2347 | - "def f(): yield 42\n" /* define a generator */ | ||
| 2348 | - "g = f()\n" /* instanciate it */ | ||
| 2349 | - "g.__next__()\n", "g"); /* force callback frame creation */ | ||
| 2333 | + PyGenObject *gen = (PyGenObject *) run_script( | ||
| 2334 | + "def exhausted_generator(): yield 42\n" /* define a generator */ | ||
| 2335 | + "g = exhausted_generator()\n" /* instanciate it */ | ||
| 2336 | + "g.__next__()\n", "g"); /* force callback frame creation */ | ||
| 2350 | 2337 | PyFrameObject *cbframe; | |
| 2351 | 2338 | ||
| 2352 | 2339 | if (gen == NULL || gen->gi_frame->f_back == NULL) | |
@@ -2356,6 +2343,13 @@ static int init_generatortype(void) | |||
| 2356 | 2343 | gen->gi_frame->f_back->f_execute, | |
| 2357 | 2344 | REF_INVALID_EXEC(gen_iternext_callback)) | |
| 2358 | 2345 | || init_type(&wrap_PyGen_Type, initchain); | |
| 2346 | + | ||
| 2347 | + assert(gen_exhausted_frame == NULL); | ||
| 2348 | + gen_exhausted_frame = slp_ensure_new_frame(gen->gi_frame); | ||
| 2349 | + if (gen_exhausted_frame == NULL) { | ||
| 2350 | + return -1; | ||
| 2351 | + } | ||
| 2352 | + | ||
| 2359 | 2353 | Py_DECREF(gen); | |
| 2360 | 2354 | return res; | |
| 2361 | 2355 | } | |
@@ -2458,23 +2452,36 @@ slp_pickle_moduledict(PyObject *self, PyObject *args) | |||
| 2458 | 2452 | source module initialization | |
| 2459 | 2453 | ||
| 2460 | 2454 | ******************************************************/ | |
| 2455 | + static int | ||
| 2456 | + _wrapmodule_traverse(PyObject *self, visitproc visit, void *arg) | ||
| 2457 | + { | ||
| 2458 | + Py_VISIT(gen_exhausted_frame); | ||
| 2459 | + return 0; | ||
| 2460 | + } | ||
| 2461 | + | ||
| 2462 | + static int | ||
| 2463 | + _wrapmodule_clear(PyObject *self) | ||
| 2464 | + { | ||
| 2465 | + Py_CLEAR(gen_exhausted_frame); | ||
| 2466 | + return 0; | ||
| 2467 | + } | ||
| 2468 | + | ||
| 2461 | 2469 | static struct PyModuleDef _wrapmodule = { | |
| 2462 | 2470 | PyModuleDef_HEAD_INIT, | |
| 2463 | 2471 | "_stackless._wrap", | |
| 2464 | 2472 | NULL, | |
| 2465 | 2473 | -1, | |
| 2466 | 2474 | NULL, | |
| 2467 | 2475 | NULL, | |
| 2468 | - NULL, | ||
| 2469 | - NULL, | ||
| 2476 | + _wrapmodule_traverse, | ||
| 2477 | + _wrapmodule_clear, | ||
| 2470 | 2478 | NULL | |
| 2471 | 2479 | }; | |
| 2472 | 2480 | ||
| 2473 | 2481 | PyObject* | |
| 2474 | 2482 | init_prickelpit(void) | |
| 2475 | 2483 | { | |
| 2476 | 2484 | PyObject *copy_reg, *tmp; | |
| 2477 | - int ret = 0; | ||
| 2478 | 2485 | ||
| 2479 | 2486 | types_mod = PyModule_Create(&_wrapmodule); | |
| 2480 | 2487 | if (types_mod == NULL) | |
@@ -2491,7 +2498,11 @@ init_prickelpit(void) | |||
| 2491 | 2498 | Py_CLEAR(types_mod); | |
| 2492 | 2499 | return NULL; | |
| 2493 | 2500 | } | |
| 2494 | - ret = initchain(); | ||
| 2501 | + if (initchain()) { | ||
| 2502 | + Py_CLEAR(pickle_reg); | ||
| 2503 | + Py_CLEAR(types_mod); | ||
| 2504 | + return NULL; | ||
| 2505 | + } | ||
| 2495 | 2506 | Py_CLEAR(pickle_reg); | |
| 2496 | 2507 | tmp = types_mod; | |
| 2497 | 2508 | types_mod = NULL; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,7 @@ | |||
| 1 | 1 | import unittest | |
| 2 | 2 | import gc | |
| 3 | 3 | import stackless | |
| 4 | + import types | ||
| 4 | 5 | ||
| 5 | 6 | from support import StacklessTestCase | |
| 6 | 7 | ||
@@ -31,5 +32,22 @@ def testSimpleLeakage(self): | |||
| 31 | 32 | if len(leakage): | |
| 32 | 33 | self.failUnless(len(leakage) == 0, "Leaked %s" % repr(leakage)) | |
| 33 | 34 | ||
| 35 | + | ||
| 36 | + class TestGeneratorWrapper(StacklessTestCase): | ||
| 37 | + def test_run_wrap_generator(self): | ||
| 38 | + g = stackless._wrap.generator() | ||
| 39 | + self.assertIsInstance(g, types.GeneratorType) | ||
| 40 | + self.assertIsNot(type(g), types.GeneratorType) | ||
| 41 | + self.assertRaises(StopIteration, next, g) | ||
| 42 | + | ||
| 43 | + def test_wrap_generator_frame_code(self): | ||
| 44 | + g0 = stackless._wrap.generator() | ||
| 45 | + g1 = stackless._wrap.generator() | ||
| 46 | + self.assertIsInstance(g0.gi_frame, types.FrameType) | ||
| 47 | + self.assertIsInstance(g0.gi_code, types.CodeType) | ||
| 48 | + self.assertIs(g0.gi_code, g1.gi_code) | ||
| 49 | + self.assertIsNot(g0.gi_frame, g1.gi_frame) | ||
| 50 | + self.assertEqual(g0.__name__, "exhausted_generator") | ||
| 51 | + | ||
| 34 | 52 | if __name__ == '__main__': | |
| 35 | 53 | unittest.main() | |
| Back | FazBrowse Home | New Git URL |
0 commit comments