about summary refs log tree commit diff
path: root/docs/libnm/libnm-docs.xml
diff options
context:
space:
mode:
Diffstat (limited to 'docs/libnm/libnm-docs.xml')
-rw-r--r--docs/libnm/libnm-docs.xml159
1 files changed, 158 insertions, 1 deletions
diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml
index c6471348..357cfe16 100644
--- a/docs/libnm/libnm-docs.xml
+++ b/docs/libnm/libnm-docs.xml
@@ -172,6 +172,125 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
           <ulink url="https://gitlab.freedesktop.org/NetworkManager/NetworkManager/tree/master/examples">some examples</ulink>.
         </para>
       </simplesect>
+
+      <simplesect id="sync-api">
+        <title>Synchronous API in libnm</title>
+        <para>
+          Libnm contains some synchronous API. This API basically makes a blocking
+          D-Bus call (g_dbus_connection_call_sync()) and is now deprecated.
+        </para>
+        <para>
+          Note that D-Bus is fundamentally asynchronous. Doing blocking calls
+          on top of D-Bus is odd, especially for libnm's NMClient. That is because
+          NMClient essentially is a client-side cache of the objects of the D-Bus
+          interface. This cache should be filled exclusively by (asynchronous) D-Bus
+          events. So, making a blocking D-Bus call means to wait for a response and
+          return it, while queuing everything that happens in between. Basically,
+          there are three options how a synchronous API on NMClient could behave:
+          <orderedlist>
+            <listitem>
+              <para>
+                The call basically calls g_dbus_connection_call_sync(). This means
+                that libnm sends a D-Bus request via GDBusConnection, and blockingly
+                waits for the response. All D-Bus messages that get received in the
+                meantime are queued in the GMainContext that belongs to NMClient.
+                That means, none of these D-Bus events are processed until we
+                iterate the GMainContext after the call returns. The effect is,
+                that NMClient (and all cached objects in there) are unaffected by
+                the D-Bus request.
+                Most of the synchronous API calls in libnm are of this kind.
+                The problem is that the strict ordering of D-Bus events gets
+                violated.
+                For some API this is not an immediate problem. Take for example
+                nm_device_wifi_request_scan(). The call merely blockingly tells
+                NetworkManager to start scanning, but since NetworkManager's D-Bus
+                API does not directly expose any state that tells whether we are
+                currently scanning, this out of order processing of the D-Bus
+                request is a small issue.
+                The problem is more obvious for nm_client_networking_set_enabled().
+                After calling it, NM_CLIENT_NETWORKING_ENABLED is still unaffected
+                and unchanged, because the PropertiesChanged signal from D-Bus
+                is not yet processed.
+                This means, while you make such a blocking call, NMClient's state
+                does not change. But usually you perform the synchronous call
+                to change some state. In this form, the blocking call is not useful,
+                because NMClient only changes the state after iterating the GMainContext,
+                and not after the blocking call returns.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                Like 1), but after making the blocking g_dbus_connection_call_sync(),
+                update the NMClient cache artificially. This is what
+                nm_manager_check_connectivity() does, to "fix" bgo#784629.
+                This also has the problem of out-of-order events, but it kinda
+                solves the problem of not changing the state during the blocking
+                call. But it does so by hacking the state of the cache. I think
+                this is really wrong because the state should only be updated from
+                the ordered stream of D-Bus messages. When libnm decides to modify
+                the state, there are already D-Bus messages queued that affect this
+                very state.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                Instead of calling g_dbus_connection_call_sync(), use the
+                asynchronous g_dbus_connection_call(). If we would use a sepaate
+                GMainContext for all D-Bus related calls, we could ensure that
+                while we block for the response, we iterate the internal main context.
+                This might be nice, because all events are processed in order and
+                after the blocking call returns, the NMClient state is up to date.
+                The are problems however: current blocking API does not do this,
+                so it's a significant change in behavior. Also, it might be
+                unexpected to the user that during the blocking call the entire
+                content of NMClient's cache might change and all pointers to the
+                cache might be invalidated. Also, of course NMClient would invoke
+                signals for all the changes that happen.
+                Another problem is that this would be more effort to implement
+                and it involves a small performance overhead for all D-Bus related
+                calls (because we have to serialize all events in an internal
+                GMainContext first and then invoke them on the caller's context).
+                Also, if the users wants this, they could implement it themself
+                using their own extra GMainContext and the asynchronous API.
+              </para>
+            </listitem>
+          </orderedlist>
+
+          See also <ulink url="https://smcv.pseudorandom.co.uk/2008/11/nonblocking/">this blog</ulink>
+          for why blocking calls are wrong.
+        </para>
+        <para>
+          All possible behaviors for synchronous API have severe behavioural
+          issues and thus such API is deprecated. Note that "deprecated" here does not
+          mean that the API is going to be removed. Libnm does not break API. The
+          user may:
+
+          <itemizedlist>
+            <listitem>
+              <para>
+                Continue to use this API. It's deprecated, awkward and discouraged,
+                but if it works for you, that's fine.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                Use asynchronous API. That's the only sensible way to use D-Bus.
+                If libnm lacks a certain asynchronous counterpart, it should be
+                added.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                Use GDBusConnection directly. There really isn't anything wrong
+                with D-Bus or GDBusConnection. This deprecated API is just a wrapper
+                around g_dbus_connection_call_sync(). You may call it directly
+                without feeling dirty.
+              </para>
+            </listitem>
+          </itemizedlist>
+        </para>
+      </simplesect>
+
     </section>
   </chapter>
 
@@ -309,5 +428,43 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
   </index>
 
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
-</book>
 
+  <appendix id="license">
+    <title>License</title>
+
+    <para>
+      This library is free software; you can redistribute
+      it and/or modify it under the terms of the <citetitle>GNU
+      Lesser General Public License</citetitle> as published by
+      the Free Software Foundation; either version 2 of the
+      License, or (at your option) any later version.
+    </para>
+
+    <para>
+      This library is distributed in the hope that it will
+      be useful, but WITHOUT ANY WARRANTY; without even the
+      implied warranty of MERCHANTABILITY or FITNESS FOR A
+      PARTICULAR PURPOSE. See the GNU Lesser General Public
+      License for more details.
+    </para>
+
+    <para>
+      You should have received a copy of the <citetitle>GNU
+      Lesser General Public License</citetitle> along with this
+      library; if not, write to the
+      <address>
+        Free Software Foundation, Inc.,
+        <street>51 Franklin Street</street> - Fifth Floor,
+        <city>Boston</city>, <state>MA</state> <postcode>02110-1301</postcode>,
+        <country>USA</country>
+      </address>
+    </para>
+
+    <para>
+      A copy of the <citetitle>GNU Lesser General Public License</citetitle>
+      can also be obtained from the <ulink url="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html">
+      GNU web site</ulink>.
+    </para>
+  </appendix>
+
+</book>