diff options
author | Teemu Ikonen <tpikonen@mailbox.org> | 2021-09-30 14:08:57 +0300 |
---|---|---|
committer | Teemu Ikonen <tpikonen@mailbox.org> | 2021-10-05 15:02:02 +0300 |
commit | 2d1968f84fa81426b1276efaa720956810915f81 (patch) | |
tree | e20cc53b494604588900adfd43841ecb431d4cc4 /src/gclue-modem-gps.c | |
parent | d381d0ee71361eec4717ae6f739430880c1c25ec (diff) | |
download | geoclue-2d1968f84fa81426b1276efaa720956810915f81.tar.gz |
location-source: Fix subclass resource leaks on start
The start_source() and stop_source() functions in GClueLocationSource
are chained up by all the start() and stop() method implementations in
GClueLocationSource subclasses to determine when to really start and
stop the source and allocate / free the needed resources.
Commit 0661107fe0 made start_source() return TRUE when the source was
already active, which caused the resources already reserved for the
physical source to be reserved again. The source class implementations
are typically designed to hold just one set of resources, so the
references to previously reserved resources are lost, that is they leak.
An example of this is the GSocketClient reference (priv->client) held by
GClueNMEASource.
Another visible (in the debug log) example of the extra resources are
callbacks connected to the "fix-*" signals of the physical sources (see
gclue_modem_gps_start() for example). With more than one client using
the same source, all clients receive the same location update N times,
where N is the number of clients using the source.
Make GClueLocationSource.start() and .stop() methods return enums
GClueLocationSourceStartResult and GClueLocationSourceStopResult which
gives subclasses more information on when to allocate resources on
starting and stopping.
The start_source() function now returns the value
GCLUE_LOCATION_SOURCE_START_RESULT_ALREADY_STARTED when the source is
already active. The subclass start() method implementations are changed
to return immediately when they get this value from the base class.
This effectively reverts the first diff in commit 0661107fe0
"location-source: Return source state from start_source and
stop_source".
The behaviour of stop() method subclass implementations remains the
same. Freeing of resources is always attempted, except when the value
GCLUE_LOCATION_SOURCE_STOP_RESULT_STILL_USED is returned from the base
class.
Diffstat (limited to 'src/gclue-modem-gps.c')
-rw-r--r-- | src/gclue-modem-gps.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/src/gclue-modem-gps.c b/src/gclue-modem-gps.c index 501c56e..53ea1b4 100644 --- a/src/gclue-modem-gps.c +++ b/src/gclue-modem-gps.c @@ -48,9 +48,9 @@ G_DEFINE_TYPE_WITH_CODE (GClueModemGPS, GCLUE_TYPE_LOCATION_SOURCE, G_ADD_PRIVATE (GClueModemGPS)) -static gboolean +static GClueLocationSourceStartResult gclue_modem_gps_start (GClueLocationSource *source); -static gboolean +static GClueLocationSourceStopResult gclue_modem_gps_stop (GClueLocationSource *source); static void @@ -233,18 +233,20 @@ on_fix_gps (GClueModem *modem, location); } -static gboolean +static GClueLocationSourceStartResult gclue_modem_gps_start (GClueLocationSource *source) { GClueLocationSourceClass *base_class; GClueModemGPSPrivate *priv; + GClueLocationSourceStartResult base_result; g_return_val_if_fail (GCLUE_IS_LOCATION_SOURCE (source), FALSE); priv = GCLUE_MODEM_GPS (source)->priv; base_class = GCLUE_LOCATION_SOURCE_CLASS (gclue_modem_gps_parent_class); - if (!base_class->start (source)) - return FALSE; + base_result = base_class->start (source); + if (base_result != GCLUE_LOCATION_SOURCE_START_RESULT_OK) + return base_result; g_signal_connect (priv->modem, "fix-gps", @@ -257,21 +259,23 @@ gclue_modem_gps_start (GClueLocationSource *source) on_gps_enabled, source); - return TRUE; + return base_result; } -static gboolean +static GClueLocationSourceStopResult gclue_modem_gps_stop (GClueLocationSource *source) { GClueModemGPSPrivate *priv = GCLUE_MODEM_GPS (source)->priv; GClueLocationSourceClass *base_class; GError *error = NULL; + GClueLocationSourceStopResult base_result; g_return_val_if_fail (GCLUE_IS_LOCATION_SOURCE (source), FALSE); base_class = GCLUE_LOCATION_SOURCE_CLASS (gclue_modem_gps_parent_class); - if (!base_class->stop (source)) - return FALSE; + base_result = base_class->stop (source); + if (base_result == GCLUE_LOCATION_SOURCE_STOP_RESULT_STILL_USED) + return base_result; g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modem), G_CALLBACK (on_fix_gps), @@ -286,5 +290,5 @@ gclue_modem_gps_stop (GClueLocationSource *source) g_error_free (error); } - return TRUE; + return base_result; } |