Skip to content

Commit

Permalink
docs/isr_rules docs/micropython Add note on alloc caused by bound met…
Browse files Browse the repository at this point in the history
…hod refs.
  • Loading branch information
peterhinch committed Nov 14, 2017
1 parent 79ed58f commit 2167ef5
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
11 changes: 10 additions & 1 deletion docs/library/micropython.rst
Expand Up @@ -112,5 +112,14 @@ Functions
the heap may be locked) and scheduling a function to call later will lift
those restrictions.

There is a finite stack to hold the scheduled functions and `schedule`
Note: If `schedule()` is called from a preempting IRQ, when memory
allocation is not allowed and the callback to be passed to `schedule()` is
a bound method, passing this directly will fail. This is because creating a
reference to a bound method causes memory allocation. A solution is to
create a reference to the method in the class constructor and to pass that
reference to `schedule()`. This is discussed in detail here
:ref:`reference documentation <isr_rules>` under "Creation of Python
objects".

There is a finite stack to hold the scheduled functions and `schedule()`
will raise a `RuntimeError` if the stack is full.
29 changes: 29 additions & 0 deletions docs/reference/isr_rules.rst
Expand Up @@ -124,6 +124,32 @@ A means of creating an object without employing a class or globals is as follows
The compiler instantiates the default ``buf`` argument when the function is
loaded for the first time (usually when the module it's in is imported).

An instance of object creation occurs when a reference to a bound method is
created. This means that an ISR cannot pass a bound method to a function. One
solution is to create a reference to the bound method in the class constructor
and to pass that reference in the ISR. For example:

.. code:: python
class Foo():
def __init__(self):
self.bar_ref = self.bar # Allocation occurs here
self.x = 0.1
tim = pyb.Timer(4)
tim.init(freq=2)
tim.callback(self.cb)
def bar(self, _):
self.x *= 1.2
print(self.x)
def cb(self, t):
# Passing self.bar would cause allocation.
micropython.schedule(self.bar_ref, 0)
Other techniques are to define and instantiate the method in the constructor
or to pass :meth:`Foo.bar` with the argument *self*.

Use of Python objects
~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -179,6 +205,9 @@ interrupt occurs while the previous callback is executing, a further instance of
for execution; this will run after the current instance has completed. A sustained high interrupt repetition
rate therefore carries a risk of unconstrained queue growth and eventual failure with a ``RuntimeError``.

If the callback to be passed to `schedule()` is a bound method, consider the
note in "Creation of Python objects".

Exceptions
----------

Expand Down

0 comments on commit 2167ef5

Please sign in to comment.