docs: Add notes on heap allocation caused by bound method refs.

This commit is contained in:
Peter Hinch 2017-11-12 06:13:45 +00:00 committed by Damien George
parent df078e8213
commit ec1e9a10a7
2 changed files with 39 additions and 1 deletions

View File

@ -112,5 +112,14 @@ Functions
the heap may be locked) and scheduling a function to call later will lift the heap may be locked) and scheduling a function to call later will lift
those restrictions. 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. will raise a `RuntimeError` if the stack is full.

View File

@ -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 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). 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 Use of Python objects
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
@ -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 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``. 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 Exceptions
---------- ----------