diff options
author | Thomas Haller <thaller@redhat.com> | 2018-01-05 17:46:49 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-04-10 15:11:23 +0200 |
commit | d8a31794c8b9db243076ba0c24dfe6e496b78697 (patch) | |
tree | bdc2426e90fa820cd777120cb3a86614904c3e20 /src/nm-connectivity.h | |
parent | 4417b8bf3eef8ca7cf45dc973ab107249bd10d67 (diff) | |
download | NetworkManager-d8a31794c8b9db243076ba0c24dfe6e496b78697.tar.gz |
connectivity: rework async connectivity check requests
An asynchronous request should either be cancellable or not keep
the target object alive. Preferably both.
Otherwise, it is impossible to do a controlled shutdown when terminating
NetworkManager. Currently, when NetworkManager is about to terminate,
it just quits the mainloop and essentially leaks everything. That is a
bug. If we ever want to fix that, every asynchronous request must be
cancellable in a controlled way (or it must not prevent objects from
getting disposed, where disposing the object automatically cancels the
callback).
Rework the asynchronous request for connectivity check to
- return a handle that can be used to cancel the operation.
Cancelling is optional. The caller may choose to ignore the handle
because the asynchronous operation does not keep the target object
alive. That means, it is still possible to shutdown, by everybody
giving up their reference to the target object. In which case the
callback will be invoked during dispose() of the target object.
- also, the callback will always be invoked exactly once, and never
synchronously from within the asynchronous start call. But during
cancel(), the callback is invoked synchronously from within cancel().
Note that it's only allowed to cancel an action at most once, and
never after the callback is invoked (also not from within the callback
itself).
- also, NMConnectivity already supports a fake handler, in case
connectivity check is disabled via configuration. Hence, reuse
the same code paths also when compiling without --enable-concheck.
That means, instead of having #if WITH_CONCHECK at various callers,
move them into NMConnectivity. The downside is, that if you build
without concheck, there is a small overhead compared to before. The
upside is, we reuse the same code paths when compiling with or without
concheck.
- also, the patch synchronizes the connecitivty states. For example,
previously `nmcli networking connectivity check` would schedule
requests in parallel, and return the accumulated result of the individual
requests.
However, the global connectivity state of the manager might have have
been the same as the answer to the explicit connecitivity check,
because while the answer for the manual check is waiting for all
pending checks to complete, the global connectivity state could
already change. That is just wrong. There are not multiple global
connectivity states at the same time, there is just one. A manual
connectivity check should have the meaning of ensure that the global
state is up to date, but it still should return the global
connectivity state -- not the answers for several connectivity checks
issued in parallel.
This is related to commit b799de281bc01073c31dd2c86171b29c8132441c
(libnm: update property in the manager after connectivity check),
which tries to address a similar problem client side.
Similarly, each device has a connectivity state. While there might
be several connectivity checks per device pending, whenever a check
completes, it can update the per-device state (and return that device
state as result), but the immediate answer of the individual check
might not matter. This is especially the case, when a later request
returns earlier and obsoletes all earlier requests. In that case,
earlier requests return with the result of the currend devices
connectivity state.
This patch cleans up the internal API and gives a better defined behavior
to the user (thus, the simple API which simplifies implementation for the
caller). However, the implementation of getting this API right and properly
handle cancel and destruction of the target object is more complicated and
complex. But this but is not just for the sake of a nicer API. This fixes
actual issues explained above.
Also, get rid of GAsyncResult to track information about the pending request.
Instead, allocate our own handle structure, which ends up to be nicer
because it's strongly typed and has exactly the properties that are
useful to track the request. Also, it gets rid of the awkward
_finish() API by passing the relevant arguments to the callback
directly.
Diffstat (limited to 'src/nm-connectivity.h')
-rw-r--r-- | src/nm-connectivity.h | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h index d9a9f2338b..6c16982307 100644 --- a/src/nm-connectivity.h +++ b/src/nm-connectivity.h @@ -24,6 +24,9 @@ #include "nm-dbus-interface.h" +#define NM_CONNECTIVITY_ERROR ((NMConnectivityState) -1) +#define NM_CONNECTIVITY_FAKE ((NMConnectivityState) -2) + #define NM_TYPE_CONNECTIVITY (nm_connectivity_get_type ()) #define NM_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTIVITY, NMConnectivity)) #define NM_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONNECTIVITY, NMConnectivityClass)) @@ -41,13 +44,21 @@ NMConnectivity *nm_connectivity_get (void); const char *nm_connectivity_state_to_string (NMConnectivityState state); -void nm_connectivity_check_async (NMConnectivity *self, - const char *iface, - GAsyncReadyCallback callback, - gpointer user_data); -NMConnectivityState nm_connectivity_check_finish (NMConnectivity *self, - GAsyncResult *result, - GError **error); gboolean nm_connectivity_check_enabled (NMConnectivity *self); +typedef struct _NMConnectivityCheckHandle NMConnectivityCheckHandle; + +typedef void (*NMConnectivityCheckCallback) (NMConnectivity *self, + NMConnectivityCheckHandle *handle, + NMConnectivityState state, + GError *error, + gpointer user_data); + +NMConnectivityCheckHandle *nm_connectivity_check_start (NMConnectivity *self, + const char *iface, + NMConnectivityCheckCallback callback, + gpointer user_data); + +void nm_connectivity_check_cancel (NMConnectivityCheckHandle *handle); + #endif /* __NETWORKMANAGER_CONNECTIVITY_H__ */ |