Skip to content

Commit

Permalink
merge 3.3-slp (Stackless python#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
Anselm Kruis committed Dec 13, 2016
2 parents b0789ae + 70f5f79 commit 0692497
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 7 deletions.
21 changes: 14 additions & 7 deletions Doc/library/stackless/tasklets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ The ``tasklet`` class
>>> t = stackless.tasklet()
>>> t.bind(func)
>>> t.setup(1, 2, 3, name="test")


and

>>> t = stackless.tasklet()
>>> t.bind(func, (1, 2, 3), {"name":"test"})
>>> t.insert()
Expand Down Expand Up @@ -147,12 +149,17 @@ The ``tasklet`` class
provided with arguments to pass to it, they are implicitly
scheduled and will be run in turn when the scheduler is next run.

The above code is equivalent to::
>>> t = stackless.tasklet()
>>> t.bind(func, (1, 2), {"name":"test"})
>>> t.insert()

The method :meth:`setup` is equivalent to::

>>> def setup(self, *args, **kwargs):
>>> assert isinstance(self, stackless.tasklet)
>>> with stackless.atomic():
>>> if self.alive:
>>> raise(RuntimeError("tasklet is alive")
>>> self.bind(None, args, kwargs)
>>> self.insert()
>>> return self

.. method:: tasklet.insert()

Insert a tasklet at the end of the scheduler runnables queue, given that it isn't blocked.
Expand Down
4 changes: 4 additions & 0 deletions Stackless/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ What's New in Stackless 3.X.X?

*Release date: 20XX-XX-XX*

- https://bitbucket.org/stackless-dev/stackless/issues/106
Raise RuntimeError, if you call tasklet.setup() on a tasklet, that is
already alive.

- https://bitbucket.org/stackless-dev/stackless/issues/105
Fix an occasional NULL-pointer access during interpreter shutdown.

Expand Down
22 changes: 22 additions & 0 deletions Stackless/module/taskletobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ tasklet_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (t == NULL)
return NULL;
*(int*)&t->flags = 0;
t->recursion_depth = 0;
t->next = NULL;
t->prev = NULL;
t->f.frame = NULL;
Expand Down Expand Up @@ -1048,6 +1049,27 @@ tasklet_setup(PyObject *self, PyObject *args, PyObject *kwds)
{
PyTaskletObject *task = (PyTaskletObject *) self;

if (PyTasklet_Alive(task)) {
RUNTIME_ERROR("tasklet is alive", NULL);
}

/* The implementation of PyTasklet_Alive does not imply,
* that the current tasklet is always alive. But I can't figure out,
* how to create a current tasklet, that is dead.
*/
assert(task->cstate->tstate == NULL || task->cstate->tstate->st.current != task);

/* guaranted by !alive && !current.
* Equivalent to the call of tasklet_clear_frames(task) in PyTasklet_BindEx().
*/
assert(task->f.frame == NULL);

/* the following assertions are equivalent to the remaining argument checks
* in PyTasklet_BindEx().
*/
assert(!PyTasklet_Scheduled(task));
assert(PyTasklet_GetNestingLevel(task) == 0);

if (impl_tasklet_setup(task, args, kwds, 1))
return NULL;
Py_INCREF(task);
Expand Down
14 changes: 14 additions & 0 deletions Stackless/unittests/test_miscell.py
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,20 @@ def other_thread_main():
self.assertGreater(tlet.nesting_level, 0)
self.assertRaisesRegex(RuntimeError, "tasklet has C state on its stack", tlet.bind, None)

def test_setup_fail_alive(self):
# make sure, that you can't bind a tasklet, which is alive
# https://bitbucket.org/stackless-dev/stackless/issues/106

def task():
t = stackless.current
t.tempval = lambda: None
self.assertTrue(t.alive)
self.assertRaisesRegex(RuntimeError, "tasklet is alive", t.setup)

t = stackless.tasklet(task, ())
t.run()
self.assertFalse(t.alive)


class TestSwitch(StacklessTestCase):
"""Test the new tasklet.switch() method, which allows
Expand Down

0 comments on commit 0692497

Please sign in to comment.