martinpitt / umockdev

Mock hardware devices for creating unit tests and bug reporting
https://launchpad.net/umockdev
GNU Lesser General Public License v2.1
308 stars 55 forks source link

ioctl: Make data object usable from python #191

Closed benzea closed 1 year ago

benzea commented 2 years ago

So, things are not usable from python. Thing still broken:

So, kinda works, but you can't actually read the memory. And, not sure if maybe a ctypes.memmove shouldn't be workable instead.

The bindings cannot deal with a struct object, as it is not a boxed type and it'll try to ref/unref using g_object_ref. Probably this is fixable in another way, but this works.

Also, the python bindings cannot modify the byte data directly, so add an update method that is essentially a glorified memcpy.

martinpitt commented 2 years ago

Marking as draft until this works. Thanks!

benzea commented 2 years ago

This works now, I believe. Adding the update/retrieve methods isn't really elegant, but I couldn't convince vala to put the array lenght information into the GIR information correctly (no idea if that is even possible). And even if, we still need something like the update method anyway.

benzea commented 2 years ago

OK, also verified that the libusb tests still work fine after the ABI change (without recompile).

benzea commented 2 years ago

Do you have some example how to use this? I'm happy to help with turning that into a test in test-umockdev.py. Is that parallel to t_ioctl_custom() in test-umockdev-vala.vala? Otherwise I'm afraid this will just bitrot and get broken.

Yeah, a short test would be good, and something parallel to t_ioctl_custom is the right thing, yes. I think we can do something really minimal that just uses the new retrieve/update functions.

Yeah, it is pretty simple. My "existing user" was looking again a bit into the thermald test setup that I was hacking on at one point. Where I have the following code:

...
        self.acpi_thermal_rel_handler = UMockdev.IoctlBase()
        self.acpi_thermal_rel_handler.connect("handle-ioctl", self.acpi_thermal_rel_ioctl)

        self.testbed.attach_ioctl('/dev/acpi_thermal_rel', self.acpi_thermal_rel_handler)
...

    def acpi_thermal_rel_ioctl(self, handler, client):
        request = client.get_request()

        if request in (ioctls.ACPI_THERMAL_GET_ART_COUNT, ioctls.ACPI_THERMAL_GET_ART_LEN, ioctls.ACPI_THERMAL_GET_ART):
            print('ART')
            if self.acpi_art[0] < 0:
                client.complete(-1, -self.acpi_art[0])
                return True

            arg = client.get_arg()

            if request == ioctls.ACPI_THERMAL_GET_ART_COUNT:
                i = struct.pack('l', self.acpi_art[0])
                data = arg.resolve(0, len(i));
                data.update(0, i)
            elif request == ioctls.ACPI_THERMAL_GET_ART_LEN:
                i = struct.pack('l', len(self.acpi_art[1]))
                data = arg.resolve(0, len(i));
                data.update(0, i)
            elif request == ioctls.ACPI_THERMAL_GET_ART:
                data = arg.resolve(0, len(self.acpi_art[1]))
                data.update(0, self.acpi_art[1])

            client.complete(0, 0)
            return True

        elif request in (ioctls.ACPI_THERMAL_GET_TRT_COUNT, ioctls.ACPI_THERMAL_GET_TRT_LEN, ioctls.ACPI_THERMAL_GET_TRT):
            if self.acpi_trt[0] < 0:
                client.complete(-1, -self.acpi_trt[0])
                return True

            arg = client.get_arg()

            if request == ioctls.ACPI_THERMAL_GET_TRT_COUNT:
                i = struct.pack('l', self.acpi_trt[0])
                data = arg.resolve(0, len(i));
                print('TRT COUNT user side is:', data.retrieve(0))
                data.update(0, i)
            elif request == ioctls.ACPI_THERMAL_GET_TRT_LEN:
                i = struct.pack('l', len(self.acpi_trt[1]))
                data = arg.resolve(0, len(i));
                data.update(0, i)
            elif request == ioctls.ACPI_THERMAL_GET_TRT:
                data = arg.resolve(0, len(self.acpi_trt[1]))
                data.update(0, self.acpi_trt[1])

            client.complete(0, 0)
            return True

        return False

Let me see if I can hack up something quickly

benzea commented 2 years ago

Very cool, thank you!

I am a bit disappointed at myself for not checking the python (or GIR) output properly before the ioctl stuff got merged ... :-)

benzea commented 1 year ago

Hmm, should i merge this, or do you want to do so before the next time you make a release?

martinpitt commented 1 year ago

Ah sorry -- I wasnt' sure if you are done with this. Sure!

benzea commented 1 year ago

Nah, I think it is ready, and simply had forgotten about it again :-)