Skip to content

Commit 7047bf0

Browse files
author
Anselm Kruis
committed
Stackless issue python#218: Cleanups and test infrastructure for embedded SLP
- Fix test_outside to reset cstack_base and cstack_root. Now the simulation of a call from outside is complete. - Add test_slp_embed to test embedding Stackless
1 parent 8ae5fe5 commit 7047bf0

File tree

8 files changed

+120
-13
lines changed

8 files changed

+120
-13
lines changed

Include/slp_structs.h

+5
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ typedef struct _cstack {
144144
struct _cstack *next;
145145
struct _cstack *prev;
146146
PY_LONG_LONG serial;
147+
/* A borrowed reference to the tasklet, that owns this cstack. NULL after
148+
* the stack has been restored. Always NULL for an initial stub.
149+
*/
147150
struct _tasklet *task;
148151
int nesting_level;
149152
PyThreadState *tstate;
@@ -155,6 +158,8 @@ typedef struct _cstack {
155158
*/
156159
unsigned long exception_list;
157160
#endif
161+
/* The end-address (sic!) of the stack stored in the cstack.
162+
*/
158163
intptr_t *startaddr;
159164
intptr_t stack[
160165
#if defined(_WINDOWS_) && defined(SLP_SEH32)

Makefile.pre.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile
786786
Programs/python.o: $(srcdir)/Programs/python.c
787787
$(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Programs/python.c
788788

789-
Programs/_testembed.o: $(srcdir)/Programs/_testembed.c
789+
Programs/_testembed.o: $(srcdir)/Programs/_testembed.c $(srcdir)/Stackless/unittests/_testembed_slp.c
790790
$(MAINCC) -c $(PY_CORE_CFLAGS) -o $@ $(srcdir)/Programs/_testembed.c
791791

792792
Modules/_sre.o: $(srcdir)/Modules/_sre.c $(srcdir)/Modules/sre.h $(srcdir)/Modules/sre_constants.h $(srcdir)/Modules/sre_lib.h

Programs/_testembed.c

+4
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,10 @@ static struct TestCase TestCases[] = {
620620
{ NULL, NULL }
621621
};
622622

623+
#ifdef STACKLESS
624+
#include "../Stackless/unittests/_testembed_slp.c"
625+
#endif
626+
623627
int main(int argc, char *argv[])
624628
{
625629
if (argc > 1) {

Stackless/core/stacklesseval.c

+10-9
Original file line numberDiff line numberDiff line change
@@ -348,17 +348,18 @@ slp_eval_frame(PyFrameObject *f)
348348
if (ts->st.cstack_base == NULL)
349349
ts->st.cstack_base = stackref - SLP_CSTACK_GOODGAP;
350350
if (stackref > ts->st.cstack_base) {
351-
PyCStackObject *cst;
351+
PyCStackObject *initial_stub;
352352
retval = climb_stack_and_eval_frame(f);
353-
cst = ts->st.initial_stub;
354-
/* might be NULL in OOM conditions */
355-
if (cst != NULL) {
356-
PyCStackObject *other;
353+
initial_stub = ts->st.initial_stub;
354+
/* cst might be NULL in OOM conditions */
355+
if (initial_stub != NULL) {
356+
PyCStackObject *cst;
357357
register int found = 0;
358-
assert(cst->startaddr == ts->st.cstack_base);
359-
for (other = cst->next; other != cst; other = other->next) {
360-
if (Py_SIZE(other) != 0 && other->task != NULL && other->tstate == ts) {
361-
assert(other->startaddr == ts->st.cstack_base);
358+
assert(initial_stub->startaddr == ts->st.cstack_base);
359+
for (cst = initial_stub->next; cst != initial_stub; cst = cst->next) {
360+
if (Py_SIZE(cst) != 0 && cst->task != NULL &&
361+
cst->tstate == ts) {
362+
assert(cst->startaddr == ts->st.cstack_base);
362363
found = 1;
363364
break;
364365
}

Stackless/module/stacklessmodule.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -969,15 +969,22 @@ test_outside(PyObject *self)
969969
{
970970
PyThreadState *ts = PyThreadState_GET();
971971
PyTaskletObject *stmain = ts->st.main;
972-
PyCStackObject *cst = ts->st.initial_stub;
972+
PyCStackObject *initial_stub = ts->st.initial_stub;
973973
PyFrameObject *f = SLP_CURRENT_FRAME(ts);
974974
int recursion_depth = ts->recursion_depth;
975975
int nesting_level = ts->st.nesting_level;
976+
intptr_t *cstack_base = ts->st.cstack_base;
977+
intptr_t *cstack_root = ts->st.cstack_root;
976978
PyObject *ret = Py_None;
977979
PY_LONG_LONG jump = ts->st.serial_last_jump;
978980

979981
Py_INCREF(ret);
980982
ts->st.main = NULL;
983+
assert(initial_stub->startaddr == cstack_base);
984+
if (ts->interp != _PyRuntime.interpreters.main) {
985+
ts->st.cstack_base = NULL;
986+
ts->st.cstack_root = NULL;
987+
}
981988
ts->st.initial_stub = NULL;
982989
ts->st.nesting_level = 0;
983990
SLP_SET_CURRENT_FRAME(ts, NULL);
@@ -990,9 +997,12 @@ test_outside(PyObject *self)
990997
break;
991998
}
992999
}
1000+
ts->st.cstack_base = cstack_base;
1001+
ts->st.cstack_root = cstack_root;
1002+
initial_stub->startaddr = cstack_base;
9931003
ts->st.main = stmain;
9941004
Py_CLEAR(ts->st.initial_stub);
995-
ts->st.initial_stub = cst;
1005+
ts->st.initial_stub = initial_stub;
9961006
SLP_SET_CURRENT_FRAME(ts, f);
9971007
slp_current_insert(stmain);
9981008
ts->recursion_depth = recursion_depth;

Stackless/unittests/_testembed_slp.c

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <stackless_api.h>
2+
3+
4+
static int slp_test_schedule(void)
5+
{
6+
_testembed_Py_Initialize();
7+
PyRun_SimpleString(
8+
"import stackless\n"
9+
"import sysconfig\n"
10+
"stackless.tasklet(print)('Hello, World!')\n"
11+
);
12+
if (!PyStackless_Schedule(Py_None, 0))
13+
PyErr_Print();
14+
Py_Finalize();
15+
return 0;
16+
}
17+
18+
19+
static struct TestCase SlpTestCases[] = {
20+
{ "slp_schedule", slp_test_schedule },
21+
{ NULL, NULL }
22+
};
23+
24+
int main(int argc, char *argv[])
25+
{
26+
int wrapped_main(int, char **);
27+
28+
if (argc > 1) {
29+
for (struct TestCase *tc = SlpTestCases; tc && tc->name; tc++) {
30+
if (strcmp(argv[1], tc->name) == 0)
31+
return (*tc->func)();
32+
}
33+
return wrapped_main(argc, argv);
34+
}
35+
36+
/* No match found, or no test name provided, so display usage */
37+
wrapped_main(argc, argv);
38+
for (struct TestCase *tc = SlpTestCases; tc && tc->name; tc++) {
39+
printf(" %s\n", tc->name);
40+
}
41+
42+
/* Non-zero exit code will cause test_embed.py tests to fail.
43+
This is intentional. */
44+
return -1;
45+
}
46+
47+
48+
#define main wrapped_main

Stackless/unittests/test_outside.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def sink():
6969
def createSource():
7070
tasklet(source)()
7171
tasklet(createSource)() # create source from a different cstate
72-
test_outside()
72+
test_outside() # create the source tasklet and run it until it blocks
7373

7474
# now create the sink tasklet
7575
tasklet(sink)()

Stackless/unittests/test_slp_embed.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Run the tests in Stackless/unittests/_testembed_slp.c
2+
# (tests for the Stackless Python embedding APIs)
3+
"""Test the (Stackless)-Python C-API
4+
5+
Tests not relevant for pure Python code.
6+
"""
7+
8+
from __future__ import print_function, absolute_import, division
9+
10+
import unittest
11+
import os
12+
import sys
13+
14+
from support import test_main # @UnusedImport
15+
16+
from test.test_embed import EmbeddingTestsMixin
17+
from test.support import verbose
18+
19+
20+
@unittest.skip("Stackless issue 218")
21+
class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
22+
def test_schedule(self):
23+
env = dict(os.environ)
24+
out, err = self.run_embedded_interpreter("slp_schedule", env=env)
25+
if verbose > 1:
26+
print()
27+
print(out)
28+
print(err)
29+
expected_output = '\n'.join([
30+
"Hello, World!"])
31+
# This is useful if we ever trip over odd platform behaviour
32+
self.maxDiff = None
33+
self.assertEqual(out.strip(), expected_output)
34+
35+
36+
if __name__ == "__main__":
37+
if not sys.argv[1:]:
38+
sys.argv.append('-v')
39+
unittest.main()

0 commit comments

Comments
 (0)