Python libmm problems
Dan Williams
dcbw at redhat.com
Thu Sep 14 16:11:08 UTC 2017
On Thu, 2017-09-14 at 15:35 +0100, Colin Helliwell wrote:
> > On 13 September 2017 at 19:39 Dan Williams <dcbw at redhat.com> wrote:
> >
>
> ...
> >
> > The two major patterns for doing all of this are (a) threads and
> > (b)
> > event-driven programming. GLib is an example of (b), and it really
> > does remove the error-prone issues of lock management, concurrent
> > data
> > access, and deadlocks from the equation. In return, you get to make
> > sure you clean up your event handlers when you're not using them :)
> >
> > You can add as many timeout_add_seconds() as you like, or you can
> > put
> > most of your logic into the one. Globals will work precisely
> > because
> > you aren't doing multiple threads and thus you are sure that there
> > is
> > only one thing accessing the global data at a given time. But
> > globals
> > have their downsides too (mainly from a readability and refactor-
> > ability perspective).
> >
> > There's always the signals option too, if you want to go fully
> > event-
> > driven. They have nothing to do with the mainloop BTW. But they
> > also
> > break up the program flow and if you have long chains of them, it
> > can
> > become a bit more confusing.
> >
> > But back to your original question, here's an example of getting NM
> > state too:
> >
> > #!/usr/bin/env python
> > import gi
> > gi.require_version('ModemManager', '1.0')
> > gi.require_version('NM', '1.0')
> > from gi.repository import GLib, GObject, Gio, ModemManager, NM
> > import sys, signal
> >
> > main_loop = None
> >
> > def signal_handler(data):
> > main_loop.quit()
> >
> > def get_modem_state(data):
> > (obj, nm) = data
> > modem = obj.get_modem()
> > print "Modem State: %s" %
> > ModemManager.ModemState.get_string(modem.get_state())
> >
> > print "NM state: %s" % nm.get_nm_running()
> >
> > # Do whatever other work you need to do, as long as it doesn't take
> > many seconds
> >
> > # True = continue running this timeout
> > return True
> >
> > main_loop = GLib.MainLoop()
> > GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP,
> > signal_handler, None)
> > GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM,
> > signal_handler, None)
> >
> > connection = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
> > manager = ModemManager.Manager.new_sync(connection,
> > Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START,
> > None)
> > modems = manager.get_objects()
> > if len(modems) == 0:
> > print "no modems found"
> > sys.exit(1)
> >
> > nm = NM.Client.new(None)
> > GLib.timeout_add_seconds(5, get_modem_state, (modems[0], nm))
> > try:
> > main_loop.run()
> > except KeyboardInterrupt:
> > pass
>
> Thanks Dan. I've persevered with GLib, and made a bit of progress.
> On top of your suggestion - instead of the start-up "modems =
> manager.get_objects()" etc, I've hooked in [a derivation of] the
> ModemWatcher example, and pass an instance in the
> timeout_add_seconds() instead of 'modems[0]'.
> Getting somewhere under normal circumstances, but I've found that if
> MM is restarted whilst the script is running, then get_modem_state()
> no longer gets called at all. The ModemWatcher instance *is* still
> spotting the presence of the modem, even if I unload its driver after
> stopping MM and reload it after MM is restarted.
> Something, I guess, has got unhooked in the event driving...?
When MM gets restarted, that object is no longer valid because it went
away when MM quit. So you need to find the new modem. Also, if you're
using modem paths, you cannot be sure that the modem path from before
MM restart will be the same modem after MM restart.
In any case, one thing you could do is to pass the modem reference to
the timeout function rather than an actual modem object, and re-look-up
the modem using that reference every time. A bit inefficient, but if
you don't want to use signals to listen for MM restarts, that's one
simple option.
Dan
More information about the ModemManager-devel
mailing list