How to invoke own method from C?

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Post Reply
jamesbowman
Posts: 2
Joined: Mon Jan 27, 2020 5:49 pm

How to invoke own method from C?

Post by jamesbowman » Mon Jan 27, 2020 6:13 pm

I am porting some code that is structured like this:

Code: Select all


class stem:
    def flush(self):
        self.write(self, <blah>)
        
class Dumper(stem):
    def write(self, bb):
        print("---> WRITE called", bb)

That is Dumper inherits from stem, while stem.flush() calls method write.

What I am trying to do is implement class stem as a MicroPython native module, for speed.

My question is, how does the C implementation of flush() find the method named write? I have so far failed to find an example of this in the existing code base. My attempts to implement it from scratch also didn't work.

What I have done as a hacky workaround is to implement a register method in stem which stores the write function as a callable. So the Python side looks like this:

Code: Select all

f = Dumper()
f.register(f.write)
And the C side looks like this:

https://github.com/jamesbowman/py-bteve ... mpy/stem.c

This works fine, but it would be much better to do this properly.

Any pointers much appreciated, thanks.

User avatar
jimmo
Posts: 1676
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: How to invoke own method from C?

Post by jimmo » Tue Jan 28, 2020 1:27 am

You're right that this isn't done very much in the core firmware (which is partially why deriving from built-in types doesn't work very well in Python). Mostly this is done for efficiency.

However, what you need to do is look up the write method by name, then invoke it using one of the mp_call_method variants.

If you search the codebase for mp_call_method you'll be able to find some examples. One such example is extmod/machine_pinbase.c where the ioctl method calls the type's value() method.

jamesbowman
Posts: 2
Joined: Mon Jan 27, 2020 5:49 pm

Re: How to invoke own method from C?

Post by jamesbowman » Wed Jan 29, 2020 4:30 am

Thanks, I have adjusted that code a little because it's in an external C module:

Code: Select all

      mp_obj_t dest[3];
      mp_fun_table.load_method(self, MP_QSTR_write, dest);
      dest[2] = b;
      mp_fun_table.call_method_n_kw(1, 0, dest);
At run time though it does not find the write method that is in the subclass Dumper:

Code: Select all

AttributeError: 'stem' object has no attribute 'write'
I'm not sure how to dig deeper on this. Do you think it could be related to running in a external module?

User avatar
jimmo
Posts: 1676
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: How to invoke own method from C?

Post by jimmo » Mon Feb 03, 2020 1:25 am

Ahh looks like I gave you a bit of bad advice there. Sorry!

This is exactly the limitation with deriving from built-in types (which includes types defined in dynamic native modules). When dumper.flush is called, the "self" is actually a pointer to the stem. I'm not aware of a way to go backwards to the dumper instance.

However, there might be a workaround which you may be able to use (which is actually what's happening in machine_pinbase.c that I referenced earlier), which is that there's a special case for "protocols". See objtype.c line 1144, where it copies the protocol from the base into the derived.

So you might be able to use this if you only ever invoke flush from C code? (Or you could write a helper method in the same module as the stem class).

tannewt
Posts: 41
Joined: Thu Aug 25, 2016 2:43 am

Re: How to invoke own method from C?

Post by tannewt » Tue Feb 18, 2020 4:42 am

We recently ran this down in CircuitPython because we wanted native code to have access to the instance rather than just the native struct. (Our PixelBuf class calls `_transmit` on the subclass.)

Here is the PR: https://github.com/adafruit/circuitpython/pull/2550 There was definitely work to make the existing native functions correctly get the native struct as they needed it.

Damien
Site Admin
Posts: 634
Joined: Mon Dec 09, 2013 5:02 pm

Re: How to invoke own method from C?

Post by Damien » Tue Feb 18, 2020 11:23 am

I posted a possible solution to this in https://github.com/micropython/micropython/pull/5660. This allows the "stem" example to work as originally intended.

Post Reply