Fix dbus with tizen patch
authorRonan Le Martret <ronan@fridu.net>
Wed, 28 May 2014 13:05:20 +0000 (15:05 +0200)
committerRonan Le Martret <ronan@fridu.net>
Wed, 28 May 2014 13:05:20 +0000 (15:05 +0200)
Change-Id: I08e3d166b9da316e49e48c265ab2912888d0903d
Signed-off-by: Ronan Le Martret <ronan@fridu.net>
14 files changed:
recipes-core/dbus/dbus_1.6.18.bbappend
recipes-core/dbus/files/0001-Set-correct-address-when-using-address-systemd.patch [new file with mode: 0644]
recipes-core/dbus/files/0002-Add-_DBUS_GNUC_WARN_UNUSED_RESULT-similar-to-GLib-s.patch [new file with mode: 0644]
recipes-core/dbus/files/0003-DBusAtomic-on-Unix-use-pthreads-mutexes-for-fallback.patch [new file with mode: 0644]
recipes-core/dbus/files/0004-dbus_threads_init-call-_dbus_threads_init_platform_s.patch [new file with mode: 0644]
recipes-core/dbus/files/0005-dbus_threads_init_default-dbus_threads_init-be-safe-.patch [new file with mode: 0644]
recipes-core/dbus/files/0006-Remove-unused-global-mutexes-for-win_fds-sid_atom_ca.patch [new file with mode: 0644]
recipes-core/dbus/files/0007-Turn-a-runtime-assertion-into-a-compile-time-asserti.patch [new file with mode: 0644]
recipes-core/dbus/files/0008-Replace-individual-global-lock-variables-with-an-arr.patch [new file with mode: 0644]
recipes-core/dbus/files/0009-Make-taking-a-global-lock-automatically-initialize-l.patch [new file with mode: 0644]
recipes-core/dbus/files/0010-Always-initialize-threading-before-allocating-a-dyna.patch [new file with mode: 0644]
recipes-core/dbus/files/0011-Add-a-statically-initialized-implementation-of-_dbus.patch [new file with mode: 0644]
recipes-core/dbus/files/0012-Enable-checking-of-smack-context-from-DBus-interface.patch [new file with mode: 0644]
recipes-core/dbus/files/0013-Enforce-smack-policy-from-conf-file.patch [new file with mode: 0644]

index edff7f6..abc3328 100644 (file)
@@ -4,6 +4,22 @@ SRC_URI += " file://dbus-user.service \
              file://dbus-user.socket \
            "
 
+#SRC_URI += " file://0001-Set-correct-address-when-using-address-systemd.patch "
+
+SRC_URI += " file://0002-Add-_DBUS_GNUC_WARN_UNUSED_RESULT-similar-to-GLib-s.patch \
+             file://0003-DBusAtomic-on-Unix-use-pthreads-mutexes-for-fallback.patch \
+             file://0004-dbus_threads_init-call-_dbus_threads_init_platform_s.patch \
+             file://0005-dbus_threads_init_default-dbus_threads_init-be-safe-.patch \
+             file://0006-Remove-unused-global-mutexes-for-win_fds-sid_atom_ca.patch \
+             file://0007-Turn-a-runtime-assertion-into-a-compile-time-asserti.patch \
+             file://0008-Replace-individual-global-lock-variables-with-an-arr.patch \
+             file://0009-Make-taking-a-global-lock-automatically-initialize-l.patch \
+             file://0010-Always-initialize-threading-before-allocating-a-dyna.patch \
+             file://0011-Add-a-statically-initialized-implementation-of-_dbus.patch \
+             file://0012-Enable-checking-of-smack-context-from-DBus-interface.patch \
+             file://0013-Enforce-smack-policy-from-conf-file.patch \
+           "
+
 do_install_append() {
        mkdir -p ${D}${systemd_unitdir}/user
        install -m 0644 ${WORKDIR}/dbus-user.service ${D}${systemd_unitdir}/user/dbus.service
diff --git a/recipes-core/dbus/files/0001-Set-correct-address-when-using-address-systemd.patch b/recipes-core/dbus/files/0001-Set-correct-address-when-using-address-systemd.patch
new file mode 100644 (file)
index 0000000..0f4689c
--- /dev/null
@@ -0,0 +1,186 @@
+From: Simon Peeters <peeters.simon@gmail.com>
+Date: Sun, 7 Oct 2012 16:59:30 +0200
+Subject: Set correct address when using --address=systemd:
+
+When dbus gets launched through systemd, we need to create an address
+string based on the sockets passed.
+
+The _dbus_append_addres_from_socket() function is responsible for
+extracting the address information from the file-descriptor and
+formatting it in a dbus friendly way.
+
+This fixes bus activation when running dbus under a systemd session.
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=50962
+Signed-off-by: Simon Peeters <peeters.simon@gmail.com>
+Applied-upstream: 1.7.0, commit:d728fdc655f17031da3bb129ab2fd17dadf0fe3a
+---
+ dbus/dbus-server-unix.c  | 38 ++++++++++++++++++---------
+ dbus/dbus-sysdeps-unix.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++
+ dbus/dbus-sysdeps-unix.h |  4 +++
+ 3 files changed, 97 insertions(+), 13 deletions(-)
+
+diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c
+index 130f66e..d995240 100644
+--- a/dbus/dbus-server-unix.c
++++ b/dbus/dbus-server-unix.c
+@@ -149,7 +149,7 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
+     }
+   else if (strcmp (method, "systemd") == 0)
+     {
+-      int n, *fds;
++      int i, n, *fds;
+       DBusString address;
+       n = _dbus_listen_systemd_sockets (&fds, error);
+@@ -159,27 +159,39 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
+           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+         }
+-      _dbus_string_init_const (&address, "systemd:");
++      if (!_dbus_string_init (&address))
++          goto systemd_oom;
+-      *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL);
+-      if (*server_p == NULL)
++      for (i = 0; i < n; i++)
+         {
+-          int i;
+-
+-          for (i = 0; i < n; i++)
++          if (i > 0)
+             {
+-              _dbus_close_socket (fds[i], NULL);
++              if (!_dbus_string_append (&address, ";"))
++                goto systemd_oom;
+             }
+-          dbus_free (fds);
+-
+-          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+-          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
++          if (!_dbus_append_address_from_socket (fds[i], &address, error))
++            goto systemd_err;
+         }
++      *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL);
++      if (*server_p == NULL)
++        goto systemd_oom;
++
+       dbus_free (fds);
+       return DBUS_SERVER_LISTEN_OK;
+-      }
++  systemd_oom:
++      _DBUS_SET_OOM (error);
++  systemd_err:
++      for (i = 0; i < n; i++)
++        {
++          _dbus_close_socket (fds[i], NULL);
++        }
++      dbus_free (fds);
++      _dbus_string_free (&address);
++
++      return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
++    }
+ #ifdef DBUS_ENABLE_LAUNCHD
+   else if (strcmp (method, "launchd") == 0)
+     {
+diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
+index e31c735..7c9fb09 100644
+--- a/dbus/dbus-sysdeps-unix.c
++++ b/dbus/dbus-sysdeps-unix.c
+@@ -55,6 +55,7 @@
+ #include <netinet/in.h>
+ #include <netdb.h>
+ #include <grp.h>
++#include <arpa/inet.h>
+ #ifdef HAVE_ERRNO_H
+ #include <errno.h>
+@@ -4173,4 +4174,71 @@ _dbus_check_setuid (void)
+ #endif
+ }
++/**
++ * Read the address from the socket and append it to the string
++ *
++ * @param fd the socket
++ * @param address
++ * @param error return location for error code
++ */
++dbus_bool_t
++_dbus_append_address_from_socket (int         fd,
++                                  DBusString *address,
++                                  DBusError  *error)
++{
++  union {
++      struct sockaddr sa;
++      struct sockaddr_storage storage;
++      struct sockaddr_un un;
++      struct sockaddr_in ipv4;
++      struct sockaddr_in6 ipv6;
++  } socket;
++  char hostip[INET6_ADDRSTRLEN];
++  int size = sizeof (socket);
++
++  if (getsockname (fd, &socket.sa, &size))
++    goto err;
++
++  switch (socket.sa.sa_family)
++    {
++    case AF_UNIX:
++      if (socket.un.sun_path[0]=='\0')
++        {
++          if (_dbus_string_append_printf (address, "unix:abstract=%s", &(socket.un.sun_path[1])))
++            return TRUE;
++        }
++      else
++        {
++          if (_dbus_string_append_printf (address, "unix:path=%s", socket.un.sun_path))
++            return TRUE;
++        }
++      break;
++    case AF_INET:
++      if (inet_ntop (AF_INET, &socket.ipv4.sin_addr, hostip, sizeof (hostip)))
++        if (_dbus_string_append_printf (address, "tcp:family=ipv4,host=%s,port=%u",
++                   hostip, ntohs (socket.ipv4.sin_port)))
++          return TRUE;
++      break;
++#ifdef AF_INET6
++    case AF_INET6:
++      if (inet_ntop (AF_INET6, &socket.ipv6.sin6_addr, hostip, sizeof (hostip)))
++        if (_dbus_string_append_printf (address, "tcp:family=ipv6,host=%s,port=%u",
++                   hostip, ntohs (socket.ipv6.sin6_port)))
++          return TRUE;
++      break;
++#endif
++    default:
++      dbus_set_error (error,
++                      _dbus_error_from_errno (EINVAL),
++                      "Failed to read address from socket: Unknown socket type.");
++      return FALSE;
++    }
++ err:
++  dbus_set_error (error,
++                  _dbus_error_from_errno (errno),
++                  "Failed to open socket: %s",
++                  _dbus_strerror (errno));
++  return FALSE;
++}
++
+ /* tests in dbus-sysdeps-util.c */
+diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h
+index 9b70896..a265b33 100644
+--- a/dbus/dbus-sysdeps-unix.h
++++ b/dbus/dbus-sysdeps-unix.h
+@@ -138,6 +138,10 @@ dbus_bool_t _dbus_parse_uid (const DBusString  *uid_str,
+ void _dbus_close_all (void);
++dbus_bool_t _dbus_append_address_from_socket (int         fd,
++                                              DBusString *address,
++                                              DBusError  *error);
++
+ /** @} */
+ DBUS_END_DECLS
diff --git a/recipes-core/dbus/files/0002-Add-_DBUS_GNUC_WARN_UNUSED_RESULT-similar-to-GLib-s.patch b/recipes-core/dbus/files/0002-Add-_DBUS_GNUC_WARN_UNUSED_RESULT-similar-to-GLib-s.patch
new file mode 100644 (file)
index 0000000..62763d8
--- /dev/null
@@ -0,0 +1,42 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Mon, 15 Apr 2013 20:40:21 +0100
+Subject: Add _DBUS_GNUC_WARN_UNUSED_RESULT, similar to GLib's
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Applied-upstream: 1.7.4, commit:7ac9b68220a2f48bc2942aaa909d6ba1f4605f73
+Bug-Tizen: TZPC-1971
+Change-Id: I9944ae3a1e9901728bbc3bedbcc6474022db586f
+---
+ dbus/dbus-macros.h | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/dbus/dbus-macros.h b/dbus/dbus-macros.h
+index dcd3eeb..cae4100 100644
+--- a/dbus/dbus-macros.h
++++ b/dbus/dbus-macros.h
+@@ -88,13 +88,21 @@
+ #define DBUS_ALLOC_SIZE2(x,y)
+ #endif
++#if    (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
++#define _DBUS_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
++#else
++#define _DBUS_GNUC_WARN_UNUSED_RESULT
++#endif
++
+ /** @def _DBUS_GNUC_PRINTF
+  * used to tell gcc about printf format strings
+  */
+ /** @def _DBUS_GNUC_NORETURN
+  * used to tell gcc about functions that never return, such as _dbus_abort()
+  */
+-
++/** @def _DBUS_GNUC_WARN_UNUSED_RESULT
++ * used to tell gcc about functions whose result must be used
++ */
+ /* Normally docs are in .c files, but there isn't a .c file for this. */
+ /**
diff --git a/recipes-core/dbus/files/0003-DBusAtomic-on-Unix-use-pthreads-mutexes-for-fallback.patch b/recipes-core/dbus/files/0003-DBusAtomic-on-Unix-use-pthreads-mutexes-for-fallback.patch
new file mode 100644 (file)
index 0000000..bf7ffff
--- /dev/null
@@ -0,0 +1,147 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Mon, 15 Apr 2013 13:51:19 +0100
+Subject: DBusAtomic: on Unix, use pthreads mutexes for fallback
+
+On pthreads platforms, POSIX guarantees that we can "allocate" mutexes
+as library-global variables, without involving malloc. This means we
+don't need to error-check their allocation - if the dynamic linker
+succeeds, then we have enough memory for all our globals - which is an
+important step towards being thread-safe by default. In particular,
+making atomic operations never rely on DBusMutex means that we are free
+to implement parts of DBusMutex in terms of DBusAtomic, if it would help.
+
+We do not currently support any non-Windows platform that does not have
+pthreads. This is unlikely to change.
+
+On Windows, we already used real atomic operations; we can just
+delete the unused global variable.
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
+Applied-upstream: 1.7.4, commit:c36f21a2e91730e9ae52e8945305aa3072f0e508
+Bug-Tizen: TZPC-1971
+Change-Id: I91d99a86f25d49d63d79eebfe85767bb8cc66170
+---
+ dbus/dbus-internals.h    |  5 -----
+ dbus/dbus-sysdeps-unix.c | 27 ++++++++++++++++++++-------
+ dbus/dbus-sysdeps-win.c  |  2 --
+ dbus/dbus-threads.c      |  3 ---
+ 4 files changed, 20 insertions(+), 17 deletions(-)
+
+diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
+index 8036a2b..eaf9603 100644
+--- a/dbus/dbus-internals.h
++++ b/dbus/dbus-internals.h
+@@ -327,12 +327,7 @@ _DBUS_DECLARE_GLOBAL_LOCK (win_fds);
+ _DBUS_DECLARE_GLOBAL_LOCK (sid_atom_cache);
+ _DBUS_DECLARE_GLOBAL_LOCK (machine_uuid);
+-#if !DBUS_USE_SYNC
+-_DBUS_DECLARE_GLOBAL_LOCK (atomic);
+-#define _DBUS_N_GLOBAL_LOCKS (15)
+-#else
+ #define _DBUS_N_GLOBAL_LOCKS (14)
+-#endif
+ dbus_bool_t _dbus_threads_init_debug (void);
+diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
+index 7c9fb09..a67f5d3 100644
+--- a/dbus/dbus-sysdeps-unix.c
++++ b/dbus/dbus-sysdeps-unix.c
+@@ -82,6 +82,10 @@
+ #include "sd-daemon.h"
++#if !DBUS_USE_SYNC
++#include <pthread.h>
++#endif
++
+ #ifndef O_BINARY
+ #define O_BINARY 0
+ #endif
+@@ -2428,7 +2432,12 @@ _dbus_parse_uid (const DBusString      *uid_str,
+ }
+ #if !DBUS_USE_SYNC
+-_DBUS_DEFINE_GLOBAL_LOCK (atomic);
++/* To be thread-safe by default on platforms that don't necessarily have
++ * atomic operations (notably Debian armel, which is armv4t), we must
++ * use a mutex that can be initialized statically, like this.
++ * GLib >= 2.32 uses a similar system.
++ */
++static pthread_mutex_t atomic_mutex = PTHREAD_MUTEX_INITIALIZER;
+ #endif
+ /**
+@@ -2444,10 +2453,12 @@ _dbus_atomic_inc (DBusAtomic *atomic)
+   return __sync_add_and_fetch(&atomic->value, 1)-1;
+ #else
+   dbus_int32_t res;
+-  _DBUS_LOCK (atomic);
++
++  pthread_mutex_lock (&atomic_mutex);
+   res = atomic->value;
+   atomic->value += 1;
+-  _DBUS_UNLOCK (atomic);
++  pthread_mutex_unlock (&atomic_mutex);
++
+   return res;
+ #endif
+ }
+@@ -2466,10 +2477,11 @@ _dbus_atomic_dec (DBusAtomic *atomic)
+ #else
+   dbus_int32_t res;
+-  _DBUS_LOCK (atomic);
++  pthread_mutex_lock (&atomic_mutex);
+   res = atomic->value;
+   atomic->value -= 1;
+-  _DBUS_UNLOCK (atomic);
++  pthread_mutex_unlock (&atomic_mutex);
++
+   return res;
+ #endif
+ }
+@@ -2490,9 +2502,10 @@ _dbus_atomic_get (DBusAtomic *atomic)
+ #else
+   dbus_int32_t res;
+-  _DBUS_LOCK (atomic);
++  pthread_mutex_lock (&atomic_mutex);
+   res = atomic->value;
+-  _DBUS_UNLOCK (atomic);
++  pthread_mutex_unlock (&atomic_mutex);
++
+   return res;
+ #endif
+ }
+diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
+index c42316f..a17b210 100644
+--- a/dbus/dbus-sysdeps-win.c
++++ b/dbus/dbus-sysdeps-win.c
+@@ -3084,8 +3084,6 @@ _dbus_get_standard_system_servicedirs (DBusList **dirs)
+   return TRUE;
+ }
+-_DBUS_DEFINE_GLOBAL_LOCK (atomic);
+-
+ /**
+  * Atomically increments an integer
+  *
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index bb1169d..b464629 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -496,9 +496,6 @@ init_locks (void)
+     LOCK_ADDR (pending_call_slots),
+     LOCK_ADDR (server_slots),
+     LOCK_ADDR (message_slots),
+-#if !DBUS_USE_SYNC
+-    LOCK_ADDR (atomic),
+-#endif
+     LOCK_ADDR (bus),
+     LOCK_ADDR (bus_datas),
+     LOCK_ADDR (shutdown_funcs),
diff --git a/recipes-core/dbus/files/0004-dbus_threads_init-call-_dbus_threads_init_platform_s.patch b/recipes-core/dbus/files/0004-dbus_threads_init-call-_dbus_threads_init_platform_s.patch
new file mode 100644 (file)
index 0000000..faf6f57
--- /dev/null
@@ -0,0 +1,78 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Mon, 15 Apr 2013 13:54:39 +0100
+Subject: dbus_threads_init: call _dbus_threads_init_platform_specific()
+
+This reverses the relationship between these two functions.
+Previously, dbus_threads_init() wouldn't allocate dbus_cond_event_tls
+on Windows, call check_monotonic_clock on Unix, or call
+_dbus_check_setuid on Unix.
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
+Applied-upstream: 1.7.4, commit:eabf6c42a1b779f57f2c08d35772035788657579
+Bug-Tizen: TZPC-1971
+Change-Id: Ice70cf1f3e2202b72016daf619c89206b96aac47
+---
+ dbus/dbus-sysdeps-pthread.c    | 3 ++-
+ dbus/dbus-sysdeps-thread-win.c | 2 +-
+ dbus/dbus-threads.c            | 7 ++++---
+ 3 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/dbus/dbus-sysdeps-pthread.c b/dbus/dbus-sysdeps-pthread.c
+index c60457b..36a1e4b 100644
+--- a/dbus/dbus-sysdeps-pthread.c
++++ b/dbus/dbus-sysdeps-pthread.c
+@@ -281,5 +281,6 @@ _dbus_threads_init_platform_specific (void)
+    */
+   check_monotonic_clock ();
+   (void) _dbus_check_setuid ();
+-  return dbus_threads_init (NULL);
++
++  return TRUE;
+ }
+diff --git a/dbus/dbus-sysdeps-thread-win.c b/dbus/dbus-sysdeps-thread-win.c
+index e30e7b8..4c4442a 100644
+--- a/dbus/dbus-sysdeps-thread-win.c
++++ b/dbus/dbus-sysdeps-thread-win.c
+@@ -269,6 +269,6 @@ _dbus_threads_init_platform_specific (void)
+       return FALSE;
+     }
+-  return dbus_threads_init (NULL);
++  return TRUE;
+ }
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index b464629..e7f2eb7 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -584,7 +584,8 @@ dbus_threads_init (const DBusThreadFunctions *functions)
+   if (thread_init_generation == _dbus_current_generation)
+     return TRUE;
+-  if (!init_locks ())
++  if (!_dbus_threads_init_platform_specific() ||
++      !init_locks ())
+     return FALSE;
+   thread_init_generation = _dbus_current_generation;
+@@ -613,7 +614,7 @@ dbus_threads_init (const DBusThreadFunctions *functions)
+ dbus_bool_t
+ dbus_threads_init_default (void)
+ {
+-  return _dbus_threads_init_platform_specific ();
++  return dbus_threads_init (NULL);
+ }
+@@ -624,7 +625,7 @@ dbus_threads_init_default (void)
+ dbus_bool_t
+ _dbus_threads_init_debug (void)
+ {
+-  return _dbus_threads_init_platform_specific();
++  return dbus_threads_init (NULL);
+ }
+ #endif /* DBUS_BUILD_TESTS */
diff --git a/recipes-core/dbus/files/0005-dbus_threads_init_default-dbus_threads_init-be-safe-.patch b/recipes-core/dbus/files/0005-dbus_threads_init_default-dbus_threads_init-be-safe-.patch
new file mode 100644 (file)
index 0000000..41519a4
--- /dev/null
@@ -0,0 +1,296 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Tue, 16 Apr 2013 12:07:23 +0100
+Subject: dbus_threads_init_default,
+ dbus_threads_init: be safe to call at any time
+
+On Unix, we use a pthreads mutex, which can be allocated and
+initialized in global memory.
+
+On Windows, we use a CRITICAL_SECTION, together with a call to
+InitializeCriticalSection() from the constructor of a global static
+C++ object (thanks to Ralf Habacker for suggesting this approach).
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
+Applied-upstream: 1.7.4, commit:17a23d08b51cf21a2110047649a86445e99e2b3f
+Bug-Tizen: TZPC-1971
+Reviewed-by: Anas Nashif <anas.nashif@intel.com>
+Change-Id: Id6aa81b7d553965c4c6f511e2410673c2f222a66
+---
+ cmake/dbus/CMakeLists.txt      |  1 +
+ dbus/Makefile.am               |  1 +
+ dbus/dbus-init-win.cpp         | 52 ++++++++++++++++++++++++++++++++++++++++++
+ dbus/dbus-memory.c             |  7 ++++++
+ dbus/dbus-sysdeps-pthread.c    | 14 ++++++++++++
+ dbus/dbus-sysdeps-thread-win.c | 28 +++++++++++++++++++++++
+ dbus/dbus-sysdeps-win.h        |  3 +++
+ dbus/dbus-sysdeps.h            | 12 ++++++++++
+ dbus/dbus-threads.c            | 28 +++++++++++++++++------
+ 9 files changed, 139 insertions(+), 7 deletions(-)
+ create mode 100644 dbus/dbus-init-win.cpp
+
+diff --git a/cmake/dbus/CMakeLists.txt b/cmake/dbus/CMakeLists.txt
+index d09e63d..9fcbb80 100644
+--- a/cmake/dbus/CMakeLists.txt
++++ b/cmake/dbus/CMakeLists.txt
+@@ -186,6 +186,7 @@ set (DBUS_UTIL_HEADERS
+ if (WIN32)
+       set (DBUS_SHARED_SOURCES ${DBUS_SHARED_SOURCES} 
+               ${DBUS_DIR}/dbus-file-win.c
++              ${DBUS_DIR}/dbus-init-win.cpp
+               ${DBUS_DIR}/dbus-sysdeps-win.c
+               ${DBUS_DIR}/dbus-pipe-win.c
+               ${DBUS_DIR}/dbus-sysdeps-thread-win.c
+diff --git a/dbus/Makefile.am b/dbus/Makefile.am
+index bb5ccca..0e54c9f 100644
+--- a/dbus/Makefile.am
++++ b/dbus/Makefile.am
+@@ -68,6 +68,7 @@ endif
+ DBUS_SHARED_arch_sources =                    \
+       $(wince_source)                         \
+       dbus-file-win.c                         \
++      dbus-init-win.cpp                       \
+       dbus-pipe-win.c                         \
+       dbus-sockets-win.h                      \
+       dbus-sysdeps-win.c                      \
+diff --git a/dbus/dbus-init-win.cpp b/dbus/dbus-init-win.cpp
+new file mode 100644
+index 0000000..687f248
+--- /dev/null
++++ b/dbus/dbus-init-win.cpp
+@@ -0,0 +1,52 @@
++/*
++ * dbus-init-win.cpp - once-per-process initialization
++ *
++ * Copyright Â© 2013 Intel Corporation
++ *
++ * Licensed under the Academic Free License version 2.1
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ *
++ */
++
++#include <config.h>
++
++extern "C"
++{
++#include "dbus-sysdeps-win.h"
++}
++
++class DBusInternalInit
++  {
++    public:
++      DBusInternalInit ()
++        {
++          _dbus_threads_windows_init_global ();
++        }
++
++      void must_not_be_omitted ()
++        {
++        }
++  };
++
++static DBusInternalInit init;
++
++extern "C" void
++_dbus_threads_windows_ensure_ctor_linked ()
++{
++  /* Do nothing significant, just ensure that the global initializer gets
++   * linked in. */
++  init.must_not_be_omitted ();
++}
+diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c
+index a033b54..317e37e 100644
+--- a/dbus/dbus-memory.c
++++ b/dbus/dbus-memory.c
+@@ -26,6 +26,7 @@
+ #include "dbus-internals.h"
+ #include "dbus-sysdeps.h"
+ #include "dbus-list.h"
++#include "dbus-threads.h"
+ #include <stdlib.h>
+ /**
+@@ -890,7 +891,13 @@ dbus_shutdown (void)
+       dbus_free (c);
+     }
++  /* We wrap this in the thread-initialization lock because
++   * dbus_threads_init() uses the current generation to tell whether
++   * we're initialized, so we need to make sure that un-initializing
++   * propagates into all threads. */
++  _dbus_threads_lock_platform_specific ();
+   _dbus_current_generation += 1;
++  _dbus_threads_unlock_platform_specific ();
+ }
+ /** @} */ /** End of public API docs block */
+diff --git a/dbus/dbus-sysdeps-pthread.c b/dbus/dbus-sysdeps-pthread.c
+index 36a1e4b..1b5d0ba 100644
+--- a/dbus/dbus-sysdeps-pthread.c
++++ b/dbus/dbus-sysdeps-pthread.c
+@@ -284,3 +284,17 @@ _dbus_threads_init_platform_specific (void)
+   return TRUE;
+ }
++
++static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
++
++void
++_dbus_threads_lock_platform_specific (void)
++{
++  pthread_mutex_lock (&init_mutex);
++}
++
++void
++_dbus_threads_unlock_platform_specific (void)
++{
++  pthread_mutex_unlock (&init_mutex);
++}
+diff --git a/dbus/dbus-sysdeps-thread-win.c b/dbus/dbus-sysdeps-thread-win.c
+index 4c4442a..0887a54 100644
+--- a/dbus/dbus-sysdeps-thread-win.c
++++ b/dbus/dbus-sysdeps-thread-win.c
+@@ -30,6 +30,21 @@
+ #include <windows.h>
++static dbus_bool_t global_init_done = FALSE;
++static CRITICAL_SECTION init_lock;
++
++/* Called from C++ code in dbus-init-win.cpp. */
++void
++_dbus_threads_windows_init_global (void)
++{
++  /* this ensures that the object that acts as our global constructor
++   * actually gets linked in when we're linked statically */
++  _dbus_threads_windows_ensure_ctor_linked ();
++
++  InitializeCriticalSection (&init_lock);
++  global_init_done = TRUE;
++}
++
+ struct DBusCondVar {
+   DBusList *list;        /**< list thread-local-stored events waiting on the cond variable */
+   CRITICAL_SECTION lock; /**< lock protecting the list */
+@@ -272,3 +287,16 @@ _dbus_threads_init_platform_specific (void)
+   return TRUE;
+ }
++void
++_dbus_threads_lock_platform_specific (void)
++{
++  _dbus_assert (global_init_done);
++  EnterCriticalSection (&init_lock);
++}
++
++void
++_dbus_threads_unlock_platform_specific (void)
++{
++  _dbus_assert (global_init_done);
++  LeaveCriticalSection (&init_lock);
++}
+diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h
+index 74624b7..5e7f1e4 100644
+--- a/dbus/dbus-sysdeps-win.h
++++ b/dbus/dbus-sysdeps-win.h
+@@ -85,6 +85,9 @@ dbus_bool_t _dbus_get_config_file_name(DBusString *config_file,
+ dbus_bool_t _dbus_get_install_root(char *prefix, int len);
++void        _dbus_threads_windows_init_global (void);
++void        _dbus_threads_windows_ensure_ctor_linked (void);
++
+ #endif
+ /** @} end of sysdeps-win.h */
+diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
+index eee9160..c48d50f 100644
+--- a/dbus/dbus-sysdeps.h
++++ b/dbus/dbus-sysdeps.h
+@@ -507,6 +507,18 @@ dbus_bool_t _dbus_read_local_machine_uuid   (DBusGUID         *machine_id,
+  */
+ dbus_bool_t _dbus_threads_init_platform_specific (void);
++/**
++ * Lock a static mutex used to protect _dbus_threads_init_platform_specific().
++ *
++ * On Windows, this is currently unimplemented and does nothing.
++ */
++void _dbus_threads_lock_platform_specific (void);
++
++/**
++ * Undo _dbus_threads_lock_platform_specific().
++ */
++void _dbus_threads_unlock_platform_specific (void);
++
+ dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs, 
+                                           const char *suffix, 
+                                           DBusList **dir_list);
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index e7f2eb7..9a505de 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -581,15 +581,24 @@ init_locks (void)
+ dbus_bool_t
+ dbus_threads_init (const DBusThreadFunctions *functions)
+ {
++  _dbus_threads_lock_platform_specific ();
++
+   if (thread_init_generation == _dbus_current_generation)
+-    return TRUE;
++    {
++      _dbus_threads_unlock_platform_specific ();
++      return TRUE;
++    }
+   if (!_dbus_threads_init_platform_specific() ||
+       !init_locks ())
+-    return FALSE;
++    {
++      _dbus_threads_unlock_platform_specific ();
++      return FALSE;
++    }
+   thread_init_generation = _dbus_current_generation;
+-  
++
++  _dbus_threads_unlock_platform_specific ();
+   return TRUE;
+ }
+@@ -600,11 +609,16 @@ dbus_threads_init (const DBusThreadFunctions *functions)
+ /**
+  * Initializes threads. If this function is not called, the D-Bus
+  * library will not lock any data structures.  If it is called, D-Bus
+- * will do locking, at some cost in efficiency. Note that this
+- * function must be called BEFORE the second thread is started.
++ * will do locking, at some cost in efficiency.
++ *
++ * Since D-Bus 1.7 it is safe to call this function from any thread,
++ * any number of times (but it must be called before any other
++ * libdbus API is used).
+  *
+- * It's safe to call dbus_threads_init_default() as many times as you
+- * want, but only the first time will have an effect.
++ * In D-Bus 1.6 or older, this function must be called in the main thread
++ * before any other thread starts. As a result, it is not sufficient to
++ * call this function in a library or plugin, unless the library or plugin
++ * imposes a similar requirement on its callers.
+  *
+  * dbus_shutdown() reverses the effects of this function when it
+  * resets all global state in libdbus.
diff --git a/recipes-core/dbus/files/0006-Remove-unused-global-mutexes-for-win_fds-sid_atom_ca.patch b/recipes-core/dbus/files/0006-Remove-unused-global-mutexes-for-win_fds-sid_atom_ca.patch
new file mode 100644 (file)
index 0000000..6901fd5
--- /dev/null
@@ -0,0 +1,78 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Tue, 16 Apr 2013 12:14:02 +0100
+Subject: Remove unused global mutexes for win_fds, sid_atom_cache
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
+Applied-upstream: 1.7.4, commit:d35f64339e401a7a47c1b088ef26e3dcb202cb9d
+Bug-Tizen: TZPC-1971
+Reviewed-by: Anas Nashif <anas.nashif@intel.com>
+Change-Id: I9619eaf477eaf1763133772b95e3845dd7c2b62e
+---
+ dbus/dbus-internals.h | 10 ++++------
+ dbus/dbus-sysdeps.c   |  2 --
+ dbus/dbus-threads.c   |  2 --
+ 3 files changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
+index eaf9603..336d22e 100644
+--- a/dbus/dbus-internals.h
++++ b/dbus/dbus-internals.h
+@@ -309,25 +309,23 @@ extern int _dbus_current_generation;
+ #define _DBUS_LOCK(name)                _dbus_rmutex_lock   (_dbus_lock_##name)
+ #define _DBUS_UNLOCK(name)              _dbus_rmutex_unlock (_dbus_lock_##name)
+-/* 1-5 */
++/* index 0-4 */
+ _DBUS_DECLARE_GLOBAL_LOCK (list);
+ _DBUS_DECLARE_GLOBAL_LOCK (connection_slots);
+ _DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots);
+ _DBUS_DECLARE_GLOBAL_LOCK (server_slots);
+ _DBUS_DECLARE_GLOBAL_LOCK (message_slots);
+-/* 5-10 */
++/* index 5-9 */
+ _DBUS_DECLARE_GLOBAL_LOCK (bus);
+ _DBUS_DECLARE_GLOBAL_LOCK (bus_datas);
+ _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
+ _DBUS_DECLARE_GLOBAL_LOCK (system_users);
+ _DBUS_DECLARE_GLOBAL_LOCK (message_cache);
+-/* 10-14 */
++/* index 10-11 */
+ _DBUS_DECLARE_GLOBAL_LOCK (shared_connections);
+-_DBUS_DECLARE_GLOBAL_LOCK (win_fds);
+-_DBUS_DECLARE_GLOBAL_LOCK (sid_atom_cache);
+ _DBUS_DECLARE_GLOBAL_LOCK (machine_uuid);
+-#define _DBUS_N_GLOBAL_LOCKS (14)
++#define _DBUS_N_GLOBAL_LOCKS (12)
+ dbus_bool_t _dbus_threads_init_debug (void);
+diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
+index 04fb8d7..4e14ac3 100644
+--- a/dbus/dbus-sysdeps.c
++++ b/dbus/dbus-sysdeps.c
+@@ -46,8 +46,6 @@
+ #include <errno.h>
+ #endif
+-_DBUS_DEFINE_GLOBAL_LOCK (win_fds);
+-_DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache);
+ _DBUS_DEFINE_GLOBAL_LOCK (system_users);
+ #ifdef DBUS_WIN
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index 9a505de..9fbbae5 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -489,8 +489,6 @@ init_locks (void)
+   DBusRMutex ***dynamic_global_locks;
+   DBusRMutex **global_locks[] = {
+ #define LOCK_ADDR(name) (& _dbus_lock_##name)
+-    LOCK_ADDR (win_fds),
+-    LOCK_ADDR (sid_atom_cache),
+     LOCK_ADDR (list),
+     LOCK_ADDR (connection_slots),
+     LOCK_ADDR (pending_call_slots),
diff --git a/recipes-core/dbus/files/0007-Turn-a-runtime-assertion-into-a-compile-time-asserti.patch b/recipes-core/dbus/files/0007-Turn-a-runtime-assertion-into-a-compile-time-asserti.patch
new file mode 100644 (file)
index 0000000..396ca3f
--- /dev/null
@@ -0,0 +1,30 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Tue, 16 Apr 2013 12:14:14 +0100
+Subject: Turn a runtime assertion into a compile-time assertion
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
+Applied-upstream: 1.7.4, commit:24a9b93021908b6f2b20eaacc1b36fa8fb24edb4
+Bug-Tizen: TZPC-1971
+Reviewed-by: Anas Nashif <anas.nashif@intel.com>
+Change-Id: I2784b0aa9046fba5a83065d32305c127a2a2dc78
+---
+ dbus/dbus-threads.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index 9fbbae5..43676bc 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -504,8 +504,7 @@ init_locks (void)
+ #undef LOCK_ADDR
+   };
+-  _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
+-                _DBUS_N_GLOBAL_LOCKS);
++  _DBUS_STATIC_ASSERT (_DBUS_N_ELEMENTS (global_locks) == _DBUS_N_GLOBAL_LOCKS);
+   i = 0;
+   
diff --git a/recipes-core/dbus/files/0008-Replace-individual-global-lock-variables-with-an-arr.patch b/recipes-core/dbus/files/0008-Replace-individual-global-lock-variables-with-an-arr.patch
new file mode 100644 (file)
index 0000000..e87c4f3
--- /dev/null
@@ -0,0 +1,734 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Tue, 16 Apr 2013 15:39:54 +0100
+Subject: Replace individual global-lock variables with an array of DBusRMutex
+ *
+
+This means we can use a much simpler code structure in data-slot
+allocators: instead of giving them a DBusRMutex ** at first-allocation,
+we can just give them an index into the array, which can be done
+statically.
+
+It doesn't make us any more thread-safe-by-default - the mutexes will
+only actually be used if threads were already initialized - but it's
+substantially better than nothing.
+
+These locks really do have to be recursive: for instance,
+internal_bus_get() calls dbus_bus_register() under the bus lock,
+and dbus_bus_register() can call _dbus_connection_close_possibly_shared(),
+which takes the bus lock.
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
+Reviewed-by: Anas Nashif <anas.nashif@intel.com>
+Applied-upstream: 1.7.6, commit:c80c20af46c5f43dcbe672f2c6d8aec0e7f2bbd6
+Bug-Tizen: TZPC-1971
+Change-Id: I22a31a9278b5f9c88557c54723f86827a91de818
+---
+ Doxyfile.in              |   1 -
+ cmake/Doxyfile.cmake     |   1 -
+ dbus/dbus-bus.c          |  13 ------
+ dbus/dbus-connection.c   |   7 ++--
+ dbus/dbus-dataslot.c     |  62 +++++++++--------------------
+ dbus/dbus-dataslot.h     |   8 ++--
+ dbus/dbus-internals.c    |  19 +--------
+ dbus/dbus-internals.h    |  59 ++++++++++++++++------------
+ dbus/dbus-list.c         |   2 +-
+ dbus/dbus-memory.c       |  18 ++++++---
+ dbus/dbus-message.c      |   7 ++--
+ dbus/dbus-pending-call.c |   5 +--
+ dbus/dbus-server.c       |   6 +--
+ dbus/dbus-sysdeps.c      |   2 -
+ dbus/dbus-threads.c      | 100 +++++++++++++++++++++--------------------------
+ 15 files changed, 126 insertions(+), 184 deletions(-)
+
+diff --git a/Doxyfile.in b/Doxyfile.in
+index afac639..f0a37ed 100644
+--- a/Doxyfile.in
++++ b/Doxyfile.in
+@@ -147,7 +147,6 @@ PREDEFINED             = "DBUS_BEGIN_DECLS="                       \
+                        "DBUS_END_DECLS="                      \
+                        "DOXYGEN_SHOULD_SKIP_THIS"             \
+                          "DBUS_GNUC_DEPRECATED="                \
+-                       "_DBUS_DEFINE_GLOBAL_LOCK(name)="      \
+                        "_DBUS_GNUC_PRINTF(from,to)="
+ SKIP_FUNCTION_MACROS   = YES
+ #---------------------------------------------------------------------------
+diff --git a/cmake/Doxyfile.cmake b/cmake/Doxyfile.cmake
+index e00984e..3c63d95 100644
+--- a/cmake/Doxyfile.cmake
++++ b/cmake/Doxyfile.cmake
+@@ -147,7 +147,6 @@ PREDEFINED             = "DBUS_BEGIN_DECLS="                       \
+                        "DBUS_END_DECLS="                      \
+                        "DOXYGEN_SHOULD_SKIP_THIS"             \
+                          "DBUS_GNUC_DEPRECATED="                \
+-                       "_DBUS_DEFINE_GLOBAL_LOCK(name)="      \
+                        "_DBUS_GNUC_PRINTF(from,to)=" \
+                        "DBUS_EXPORT="
+ SKIP_FUNCTION_MACROS   = YES
+diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c
+index fadc3a8..7a31cbd 100644
+--- a/dbus/dbus-bus.c
++++ b/dbus/dbus-bus.c
+@@ -95,19 +95,6 @@ static DBusBusType activation_bus_type = DBUS_BUS_STARTER;
+ static dbus_bool_t initialized = FALSE;
+-/**
+- * Lock for globals in this file
+- */
+-_DBUS_DEFINE_GLOBAL_LOCK (bus);
+-
+-/**
+- * Global lock covering all BusData on any connection. The bet is
+- * that some lock contention is better than more memory
+- * for a per-connection lock, but it's tough to imagine it mattering
+- * either way.
+- */
+-_DBUS_DEFINE_GLOBAL_LOCK (bus_datas);
+-
+ static void
+ addresses_shutdown_func (void *data)
+ {
+diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
+index 66315b3..03ee066 100644
+--- a/dbus/dbus-connection.c
++++ b/dbus/dbus-connection.c
+@@ -1531,7 +1531,7 @@ _dbus_connection_handle_watch (DBusWatch                   *watch,
+   return retval;
+ }
+-_DBUS_DEFINE_GLOBAL_LOCK (shared_connections);
++/* Protected by _DBUS_LOCK (shared_connections) */
+ static DBusHashTable *shared_connections = NULL;
+ static DBusList *shared_connections_no_guid = NULL;
+@@ -5852,8 +5852,8 @@ dbus_connection_list_registered (DBusConnection              *connection,
+   return retval;
+ }
+-static DBusDataSlotAllocator slot_allocator;
+-_DBUS_DEFINE_GLOBAL_LOCK (connection_slots);
++static DBusDataSlotAllocator slot_allocator =
++  _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (connection_slots));
+ /**
+  * Allocates an integer ID to be used for storing application-specific
+@@ -5873,7 +5873,6 @@ dbus_bool_t
+ dbus_connection_allocate_data_slot (dbus_int32_t *slot_p)
+ {
+   return _dbus_data_slot_allocator_alloc (&slot_allocator,
+-                                          &_DBUS_LOCK_NAME (connection_slots),
+                                           slot_p);
+ }
+diff --git a/dbus/dbus-dataslot.c b/dbus/dbus-dataslot.c
+index 0369612..b3c8090 100644
+--- a/dbus/dbus-dataslot.c
++++ b/dbus/dbus-dataslot.c
+@@ -43,13 +43,14 @@
+  * @param allocator the allocator to initialize
+  */
+ dbus_bool_t
+-_dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator)
++_dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator,
++                                DBusGlobalLock         lock)
+ {
+   allocator->allocated_slots = NULL;
+   allocator->n_allocated_slots = 0;
+   allocator->n_used_slots = 0;
+-  allocator->lock_loc = NULL;
+-  
++  allocator->lock = lock;
++
+   return TRUE;
+ }
+@@ -61,29 +62,16 @@ _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator)
+  * is allocated and stored at *slot_id_p.
+  * 
+  * @param allocator the allocator
+- * @param mutex_loc the location lock for this allocator
+  * @param slot_id_p address to fill with the slot ID
+  * @returns #TRUE on success
+  */
+ dbus_bool_t
+ _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
+-                                 DBusRMutex            **mutex_loc,
+                                  dbus_int32_t          *slot_id_p)
+ {
+   dbus_int32_t slot;
+-  _dbus_rmutex_lock (*mutex_loc);
+-
+-  if (allocator->n_allocated_slots == 0)
+-    {
+-      _dbus_assert (allocator->lock_loc == NULL);
+-      allocator->lock_loc = mutex_loc;
+-    }
+-  else if (allocator->lock_loc != mutex_loc)
+-    {
+-      _dbus_warn_check_failed ("D-Bus threads were initialized after first using the D-Bus library. If your application does not directly initialize threads or use D-Bus, keep in mind that some library or plugin may have used D-Bus or initialized threads behind your back. You can often fix this problem by calling dbus_init_threads() or dbus_g_threads_init() early in your main() method, before D-Bus is used.\n");
+-      _dbus_assert_not_reached ("exiting");
+-    }
++  _dbus_lock (allocator->lock);
+   if (*slot_id_p >= 0)
+     {
+@@ -146,7 +134,7 @@ _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
+                  slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
+   
+  out:
+-  _dbus_rmutex_unlock (*(allocator->lock_loc));
++  _dbus_unlock (allocator->lock);
+   return slot >= 0;
+ }
+@@ -165,7 +153,7 @@ void
+ _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
+                                 dbus_int32_t          *slot_id_p)
+ {
+-  _dbus_rmutex_lock (*(allocator->lock_loc));
++  _dbus_lock (allocator->lock);
+   
+   _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
+   _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
+@@ -175,7 +163,7 @@ _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
+   if (allocator->allocated_slots[*slot_id_p].refcount > 0)
+     {
+-      _dbus_rmutex_unlock (*(allocator->lock_loc));
++      _dbus_unlock (allocator->lock);
+       return;
+     }
+@@ -190,19 +178,12 @@ _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
+   
+   if (allocator->n_used_slots == 0)
+     {
+-      DBusRMutex **mutex_loc = allocator->lock_loc;
+-      
+       dbus_free (allocator->allocated_slots);
+       allocator->allocated_slots = NULL;
+       allocator->n_allocated_slots = 0;
+-      allocator->lock_loc = NULL;
+-
+-      _dbus_rmutex_unlock (*mutex_loc);
+-    }
+-  else
+-    {
+-      _dbus_rmutex_unlock (*(allocator->lock_loc));
+     }
++
++  _dbus_unlock (allocator->lock);
+ }
+ /**
+@@ -247,10 +228,10 @@ _dbus_data_slot_list_set  (DBusDataSlotAllocator *allocator,
+    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
+    * are disabled, since then the asserts are empty.
+    */
+-  _dbus_rmutex_lock (*(allocator->lock_loc));
++  _dbus_lock (allocator->lock);
+   _dbus_assert (slot < allocator->n_allocated_slots);
+   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+-  _dbus_rmutex_unlock (*(allocator->lock_loc));
++  _dbus_unlock (allocator->lock);
+ #endif
+   
+   if (slot >= list->n_slots)
+@@ -304,11 +285,11 @@ _dbus_data_slot_list_get  (DBusDataSlotAllocator *allocator,
+    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
+    * are disabled, since then the asserts are empty.
+    */
+-  _dbus_rmutex_lock (*(allocator->lock_loc));
++  _dbus_lock (allocator->lock);
+   _dbus_assert (slot >= 0);
+   _dbus_assert (slot < allocator->n_allocated_slots);
+   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+-  _dbus_rmutex_unlock (*(allocator->lock_loc));
++  _dbus_unlock (allocator->lock);
+ #endif
+   if (slot >= list->n_slots)
+@@ -384,17 +365,12 @@ _dbus_data_slot_test (void)
+   int i;
+   DBusFreeFunction old_free_func;
+   void *old_data;
+-  DBusRMutex *mutex;
+-  
+-  if (!_dbus_data_slot_allocator_init (&allocator))
++
++  if (!_dbus_data_slot_allocator_init (&allocator, _DBUS_LOCK_server_slots))
+     _dbus_assert_not_reached ("no memory for allocator");
+   _dbus_data_slot_list_init (&list);
+-  _dbus_rmutex_new_at_location (&mutex);
+-  if (mutex == NULL)
+-    _dbus_assert_not_reached ("failed to alloc mutex");
+-  
+ #define N_SLOTS 100
+   i = 0;
+@@ -405,8 +381,8 @@ _dbus_data_slot_test (void)
+        * here.
+        */
+       dbus_int32_t tmp = -1;
+-      
+-      _dbus_data_slot_allocator_alloc (&allocator, &mutex, &tmp);
++
++      _dbus_data_slot_allocator_alloc (&allocator, &tmp);
+       if (tmp != i)
+         _dbus_assert_not_reached ("did not allocate slots in numeric order\n");
+@@ -471,8 +447,6 @@ _dbus_data_slot_test (void)
+       ++i;
+     }
+-  _dbus_rmutex_free_at_location (&mutex);
+-  
+   return TRUE;
+ }
+diff --git a/dbus/dbus-dataslot.h b/dbus/dbus-dataslot.h
+index 3d9d5ed..1e04fcb 100644
+--- a/dbus/dbus-dataslot.h
++++ b/dbus/dbus-dataslot.h
+@@ -57,9 +57,11 @@ struct DBusDataSlotAllocator
+   DBusAllocatedSlot *allocated_slots; /**< Allocated slots */
+   int  n_allocated_slots; /**< number of slots malloc'd */
+   int  n_used_slots;      /**< number of slots used */
+-  DBusRMutex **lock_loc;  /**< location of thread lock */
++  DBusGlobalLock lock;    /**< index of thread lock */
+ };
++#define _DBUS_DATA_SLOT_ALLOCATOR_INIT(x) { NULL, 0, 0, x }
++
+ /**
+  * Data structure that stores the actual user data set at a given
+  * slot.
+@@ -70,9 +72,9 @@ struct DBusDataSlotList
+   int           n_slots; /**< Slots we have storage for in data_slots */
+ };
+-dbus_bool_t _dbus_data_slot_allocator_init  (DBusDataSlotAllocator  *allocator);
++dbus_bool_t _dbus_data_slot_allocator_init  (DBusDataSlotAllocator  *allocator,
++                                             DBusGlobalLock          lock);
+ dbus_bool_t _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator  *allocator,
+-                                             DBusRMutex             **mutex_loc,
+                                              int                    *slot_id_p);
+ void        _dbus_data_slot_allocator_free  (DBusDataSlotAllocator  *allocator,
+                                              int                    *slot_id_p);
+diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
+index 0e5d807..1a36734 100644
+--- a/dbus/dbus-internals.c
++++ b/dbus/dbus-internals.c
+@@ -163,23 +163,6 @@
+  */
+ /**
+- * @def _DBUS_DEFINE_GLOBAL_LOCK
+- *
+- * Defines a global lock variable with the given name.
+- * The lock must be added to the list to initialize
+- * in dbus_threads_init().
+- */
+-
+-/**
+- * @def _DBUS_DECLARE_GLOBAL_LOCK
+- *
+- * Expands to declaration of a global lock defined
+- * with _DBUS_DEFINE_GLOBAL_LOCK.
+- * The lock must be added to the list to initialize
+- * in dbus_threads_init().
+- */
+-
+-/**
+  * @def _DBUS_LOCK
+  *
+  * Locks a global lock
+@@ -847,7 +830,7 @@ _dbus_read_uuid_file (const DBusString *filename,
+     }
+ }
+-_DBUS_DEFINE_GLOBAL_LOCK (machine_uuid);
++/* Protected by _DBUS_LOCK (machine_uuid) */
+ static int machine_uuid_initialized_generation = 0;
+ static DBusGUID machine_uuid;
+diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
+index 336d22e..22ad297 100644
+--- a/dbus/dbus-internals.h
++++ b/dbus/dbus-internals.h
+@@ -297,35 +297,42 @@ dbus_bool_t _dbus_test_oom_handling (const char             *description,
+ #endif /* !DBUS_BUILD_TESTS */
+ typedef void (* DBusShutdownFunction) (void *data);
+-dbus_bool_t _dbus_register_shutdown_func (DBusShutdownFunction  function,
+-                                          void                 *data);
++dbus_bool_t _dbus_register_shutdown_func          (DBusShutdownFunction  function,
++                                                   void                 *data);
++dbus_bool_t _dbus_register_shutdown_func_unlocked (DBusShutdownFunction  function,
++                                                   void                 *data);
+ extern int _dbus_current_generation;
+-/* Thread initializers */
+-#define _DBUS_LOCK_NAME(name)           _dbus_lock_##name
+-#define _DBUS_DECLARE_GLOBAL_LOCK(name) extern DBusRMutex *_dbus_lock_##name
+-#define _DBUS_DEFINE_GLOBAL_LOCK(name)  DBusRMutex        *_dbus_lock_##name
+-#define _DBUS_LOCK(name)                _dbus_rmutex_lock   (_dbus_lock_##name)
+-#define _DBUS_UNLOCK(name)              _dbus_rmutex_unlock (_dbus_lock_##name)
+-
+-/* index 0-4 */
+-_DBUS_DECLARE_GLOBAL_LOCK (list);
+-_DBUS_DECLARE_GLOBAL_LOCK (connection_slots);
+-_DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots);
+-_DBUS_DECLARE_GLOBAL_LOCK (server_slots);
+-_DBUS_DECLARE_GLOBAL_LOCK (message_slots);
+-/* index 5-9 */
+-_DBUS_DECLARE_GLOBAL_LOCK (bus);
+-_DBUS_DECLARE_GLOBAL_LOCK (bus_datas);
+-_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
+-_DBUS_DECLARE_GLOBAL_LOCK (system_users);
+-_DBUS_DECLARE_GLOBAL_LOCK (message_cache);
+-/* index 10-11 */
+-_DBUS_DECLARE_GLOBAL_LOCK (shared_connections);
+-_DBUS_DECLARE_GLOBAL_LOCK (machine_uuid);
+-
+-#define _DBUS_N_GLOBAL_LOCKS (12)
++/* The weird case convention is to avoid having to change all the callers,
++ * which would be quite a mega-patch. */
++typedef enum
++{
++  /* index 0-4 */
++  _DBUS_LOCK_list,
++  _DBUS_LOCK_connection_slots,
++  _DBUS_LOCK_pending_call_slots,
++  _DBUS_LOCK_server_slots,
++  _DBUS_LOCK_message_slots,
++  /* index 5-9 */
++  _DBUS_LOCK_bus,
++  _DBUS_LOCK_bus_datas,
++  _DBUS_LOCK_shutdown_funcs,
++  _DBUS_LOCK_system_users,
++  _DBUS_LOCK_message_cache,
++  /* index 10-11 */
++  _DBUS_LOCK_shared_connections,
++  _DBUS_LOCK_machine_uuid,
++
++  _DBUS_N_GLOBAL_LOCKS
++} DBusGlobalLock;
++
++void _dbus_lock   (DBusGlobalLock lock);
++void _dbus_unlock (DBusGlobalLock lock);
++
++#define _DBUS_LOCK_NAME(name)           _DBUS_LOCK_##name
++#define _DBUS_LOCK(name)                _dbus_lock   (_DBUS_LOCK_##name)
++#define _DBUS_UNLOCK(name)              _dbus_unlock (_DBUS_LOCK_##name)
+ dbus_bool_t _dbus_threads_init_debug (void);
+diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c
+index 7e11cc8..e5a4940 100644
+--- a/dbus/dbus-list.c
++++ b/dbus/dbus-list.c
+@@ -35,8 +35,8 @@
+  * Types and functions related to DBusList.
+  */
++/* Protected by _DBUS_LOCK (list) */
+ static DBusMemPool *list_pool;
+-_DBUS_DEFINE_GLOBAL_LOCK (list);
+ /**
+  * @defgroup DBusListInternals Linked list implementation details
+diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c
+index 317e37e..a13b951 100644
+--- a/dbus/dbus-memory.c
++++ b/dbus/dbus-memory.c
+@@ -795,7 +795,7 @@ struct ShutdownClosure
+   void *data;                /**< Data for function */
+ };
+-_DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
++/* Protected by _DBUS_LOCK (shutdown_funcs) */
+ static ShutdownClosure *registered_globals = NULL;
+ /**
+@@ -810,6 +810,18 @@ dbus_bool_t
+ _dbus_register_shutdown_func (DBusShutdownFunction  func,
+                               void                 *data)
+ {
++  dbus_bool_t ok;
++
++  _DBUS_LOCK (shutdown_funcs);
++  ok = _dbus_register_shutdown_func_unlocked (func, data);
++  _DBUS_UNLOCK (shutdown_funcs);
++  return ok;
++}
++
++dbus_bool_t
++_dbus_register_shutdown_func_unlocked (DBusShutdownFunction  func,
++                                       void                 *data)
++{
+   ShutdownClosure *c;
+   c = dbus_new (ShutdownClosure, 1);
+@@ -820,13 +832,9 @@ _dbus_register_shutdown_func (DBusShutdownFunction  func,
+   c->func = func;
+   c->data = data;
+-  _DBUS_LOCK (shutdown_funcs);
+-  
+   c->next = registered_globals;
+   registered_globals = c;
+-  _DBUS_UNLOCK (shutdown_funcs);
+-  
+   return TRUE;
+ }
+diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
+index 71bcee6..2814569 100644
+--- a/dbus/dbus-message.c
++++ b/dbus/dbus-message.c
+@@ -506,7 +506,7 @@ _dbus_message_set_signature (DBusMessage *message,
+ /** Avoid caching too many messages */
+ #define MAX_MESSAGE_CACHE_SIZE    5
+-_DBUS_DEFINE_GLOBAL_LOCK (message_cache);
++/* Protected by _DBUS_LOCK (message_cache) */
+ static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE];
+ static int message_cache_count = 0;
+ static dbus_bool_t message_cache_shutdown_registered = FALSE;
+@@ -4423,8 +4423,8 @@ _dbus_message_loader_get_max_message_unix_fds (DBusMessageLoader  *loader)
+   return loader->max_message_unix_fds;
+ }
+-static DBusDataSlotAllocator slot_allocator;
+-_DBUS_DEFINE_GLOBAL_LOCK (message_slots);
++static DBusDataSlotAllocator slot_allocator =
++  _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (message_slots));
+ /**
+  * Allocates an integer ID to be used for storing application-specific
+@@ -4444,7 +4444,6 @@ dbus_bool_t
+ dbus_message_allocate_data_slot (dbus_int32_t *slot_p)
+ {
+   return _dbus_data_slot_allocator_alloc (&slot_allocator,
+-                                          &_DBUS_LOCK_NAME (message_slots),
+                                           slot_p);
+ }
+diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c
+index 62c6c74..1604408 100644
+--- a/dbus/dbus-pending-call.c
++++ b/dbus/dbus-pending-call.c
+@@ -489,8 +489,8 @@ _dbus_pending_call_get_completed_unlocked (DBusPendingCall    *pending)
+   return pending->completed;
+ }
+-static DBusDataSlotAllocator slot_allocator;
+-_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
++static DBusDataSlotAllocator slot_allocator =
++  _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (pending_call_slots));
+ /**
+  * Stores a pointer on a #DBusPendingCall, along
+@@ -768,7 +768,6 @@ dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
+   _dbus_return_val_if_fail (slot_p != NULL, FALSE);
+   return _dbus_data_slot_allocator_alloc (&slot_allocator,
+-                                          &_DBUS_LOCK_NAME (pending_call_slots),
+                                           slot_p);
+ }
+diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
+index b62c2b4..e021266 100644
+--- a/dbus/dbus-server.c
++++ b/dbus/dbus-server.c
+@@ -1071,9 +1071,8 @@ dbus_server_set_auth_mechanisms (DBusServer  *server,
+   return TRUE;
+ }
+-
+-static DBusDataSlotAllocator slot_allocator;
+-_DBUS_DEFINE_GLOBAL_LOCK (server_slots);
++static DBusDataSlotAllocator slot_allocator =
++  _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (server_slots));
+ /**
+  * Allocates an integer ID to be used for storing application-specific
+@@ -1093,7 +1092,6 @@ dbus_bool_t
+ dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
+ {
+   return _dbus_data_slot_allocator_alloc (&slot_allocator,
+-                                          (DBusRMutex **)&_DBUS_LOCK_NAME (server_slots),
+                                           slot_p);
+ }
+diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
+index 4e14ac3..0fbf9e7 100644
+--- a/dbus/dbus-sysdeps.c
++++ b/dbus/dbus-sysdeps.c
+@@ -46,8 +46,6 @@
+ #include <errno.h>
+ #endif
+-_DBUS_DEFINE_GLOBAL_LOCK (system_users);
+-
+ #ifdef DBUS_WIN
+   #include <stdlib.h>
+ #elif (defined __APPLE__)
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index 43676bc..297a7e4 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -343,23 +343,19 @@ _dbus_condvar_wake_one (DBusCondVar *cond)
+     _dbus_platform_condvar_wake_one (cond);
+ }
++static DBusRMutex *global_locks[_DBUS_N_GLOBAL_LOCKS] = { NULL };
++
+ static void
+-shutdown_global_locks (void *data)
++shutdown_global_locks (void *nil)
+ {
+-  DBusRMutex ***locks = data;
+   int i;
+-  i = 0;
+-  while (i < _DBUS_N_GLOBAL_LOCKS)
++  for (i = 0; i < _DBUS_N_GLOBAL_LOCKS; i++)
+     {
+-      if (*(locks[i]) != NULL)
+-        _dbus_platform_rmutex_free (*(locks[i]));
+-
+-      *(locks[i]) = NULL;
+-      ++i;
++      _dbus_assert (global_locks[i] != NULL);
++      _dbus_platform_rmutex_free (global_locks[i]);
++      global_locks[i] = NULL;
+     }
+-  
+-  dbus_free (locks);
+ }
+ static void
+@@ -483,67 +479,60 @@ init_uninitialized_locks (void)
+ }
+ static dbus_bool_t
+-init_locks (void)
++init_global_locks (void)
+ {
+   int i;
+-  DBusRMutex ***dynamic_global_locks;
+-  DBusRMutex **global_locks[] = {
+-#define LOCK_ADDR(name) (& _dbus_lock_##name)
+-    LOCK_ADDR (list),
+-    LOCK_ADDR (connection_slots),
+-    LOCK_ADDR (pending_call_slots),
+-    LOCK_ADDR (server_slots),
+-    LOCK_ADDR (message_slots),
+-    LOCK_ADDR (bus),
+-    LOCK_ADDR (bus_datas),
+-    LOCK_ADDR (shutdown_funcs),
+-    LOCK_ADDR (system_users),
+-    LOCK_ADDR (message_cache),
+-    LOCK_ADDR (shared_connections),
+-    LOCK_ADDR (machine_uuid)
+-#undef LOCK_ADDR
+-  };
+-
+-  _DBUS_STATIC_ASSERT (_DBUS_N_ELEMENTS (global_locks) == _DBUS_N_GLOBAL_LOCKS);
+-
+-  i = 0;
+-  
+-  dynamic_global_locks = dbus_new (DBusRMutex**, _DBUS_N_GLOBAL_LOCKS);
+-  if (dynamic_global_locks == NULL)
+-    goto failed;
+-  
+-  while (i < _DBUS_N_ELEMENTS (global_locks))
++  dbus_bool_t ok;
++
++  for (i = 0; i < _DBUS_N_GLOBAL_LOCKS; i++)
+     {
+-      *global_locks[i] = _dbus_platform_rmutex_new ();
++      _dbus_assert (global_locks[i] == NULL);
++
++      global_locks[i] = _dbus_platform_rmutex_new ();
+-      if (*global_locks[i] == NULL)
++      if (global_locks[i] == NULL)
+         goto failed;
++    }
+-      dynamic_global_locks[i] = global_locks[i];
++  _dbus_lock (_DBUS_LOCK_NAME (shutdown_funcs));
++  ok = _dbus_register_shutdown_func_unlocked (shutdown_global_locks, NULL);
++  _dbus_unlock (_DBUS_LOCK_NAME (shutdown_funcs));
+-      ++i;
+-    }
+-  
+-  if (!_dbus_register_shutdown_func (shutdown_global_locks,
+-                                     dynamic_global_locks))
++  if (!ok)
+     goto failed;
+-  if (!init_uninitialized_locks ())
+-    goto failed;
+-  
+   return TRUE;
+  failed:
+-  dbus_free (dynamic_global_locks);
+-                                     
+   for (i = i - 1; i >= 0; i--)
+     {
+-      _dbus_platform_rmutex_free (*global_locks[i]);
+-      *global_locks[i] = NULL;
++      _dbus_platform_rmutex_free (global_locks[i]);
++      global_locks[i] = NULL;
+     }
++
+   return FALSE;
+ }
++void
++_dbus_lock (DBusGlobalLock lock)
++{
++  _dbus_assert (lock >= 0);
++  _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS);
++
++  if (thread_init_generation == _dbus_current_generation)
++    _dbus_platform_rmutex_lock (global_locks[lock]);
++}
++
++void
++_dbus_unlock (DBusGlobalLock lock)
++{
++  _dbus_assert (lock >= 0);
++  _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS);
++
++  if (thread_init_generation == _dbus_current_generation)
++    _dbus_platform_rmutex_unlock (global_locks[lock]);
++}
++
+ /** @} */ /* end of internals */
+ /**
+@@ -587,7 +576,8 @@ dbus_threads_init (const DBusThreadFunctions *functions)
+     }
+   if (!_dbus_threads_init_platform_specific() ||
+-      !init_locks ())
++      !init_global_locks () ||
++      !init_uninitialized_locks ())
+     {
+       _dbus_threads_unlock_platform_specific ();
+       return FALSE;
diff --git a/recipes-core/dbus/files/0009-Make-taking-a-global-lock-automatically-initialize-l.patch b/recipes-core/dbus/files/0009-Make-taking-a-global-lock-automatically-initialize-l.patch
new file mode 100644 (file)
index 0000000..d104bc4
--- /dev/null
@@ -0,0 +1,719 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Tue, 16 Apr 2013 16:28:44 +0100
+Subject: Make taking a global lock automatically initialize locking if needed
+
+This lets them be thread-safe by default, at the cost that they can
+now fail.
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Anas Nashif <anas.nashif@intel.com>
+Applied-upstream: 1.7.6, commit:2b3272c75ae48c93911bd6f656965cf77d6de3e8
+Bug-Tizen: TZPC-1971
+Change-Id: I7e547e5776d37051ec8b6eccc2c8bd34b8d1996b
+---
+ bus/stats.c                        |  4 +--
+ dbus/dbus-bus.c                    | 52 ++++++++++++++++++++++++++++++--------
+ dbus/dbus-connection.c             | 50 ++++++++++++++++++++++++++----------
+ dbus/dbus-dataslot.c               | 19 ++++++++++----
+ dbus/dbus-internals.c              |  8 ++++--
+ dbus/dbus-internals.h              |  4 +--
+ dbus/dbus-list.c                   | 17 ++++++++++---
+ dbus/dbus-memory.c                 |  4 ++-
+ dbus/dbus-message.c                | 19 +++++++++++---
+ dbus/dbus-threads.c                | 28 +++++++++++++-------
+ dbus/dbus-userdb-util.c            | 20 ++++++++++++---
+ dbus/dbus-userdb.c                 | 43 +++++++++++++++++++++++--------
+ dbus/dbus-userdb.h                 |  2 +-
+ test/name-test/test-threads-init.c | 14 ++++++----
+ 14 files changed, 213 insertions(+), 71 deletions(-)
+
+diff --git a/bus/stats.c b/bus/stats.c
+index 28fd49b..4553191 100644
+--- a/bus/stats.c
++++ b/bus/stats.c
+@@ -203,8 +203,8 @@ bus_stats_handle_get_stats (DBusConnection *connection,
+   if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++))
+     goto oom;
+-  _dbus_list_get_stats (&in_use, &in_free_list, &allocated);
+-  if (!asv_add_uint32 (&iter, &arr_iter, "ListMemPoolUsedBytes", in_use) ||
++  if (!_dbus_list_get_stats (&in_use, &in_free_list, &allocated) ||
++      !asv_add_uint32 (&iter, &arr_iter, "ListMemPoolUsedBytes", in_use) ||
+       !asv_add_uint32 (&iter, &arr_iter, "ListMemPoolCachedBytes",
+                        in_free_list) ||
+       !asv_add_uint32 (&iter, &arr_iter, "ListMemPoolAllocatedBytes",
+diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c
+index 7a31cbd..3aa5c09 100644
+--- a/dbus/dbus-bus.c
++++ b/dbus/dbus-bus.c
+@@ -317,7 +317,11 @@ bus_data_free (void *data)
+   if (bd->is_well_known)
+     {
+       int i;
+-      _DBUS_LOCK (bus);
++
++      if (!_DBUS_LOCK (bus))
++        _dbus_assert_not_reached ("global locks should have been initialized "
++            "when we attached bus data");
++
+       /* We may be stored in more than one slot */
+       /* This should now be impossible - these slots are supposed to
+        * be cleared on disconnect, so should not need to be cleared on
+@@ -388,8 +392,13 @@ void
+ _dbus_bus_notify_shared_connection_disconnected_unlocked (DBusConnection *connection)
+ {
+   int i;
+-  
+-  _DBUS_LOCK (bus);
++
++  if (!_DBUS_LOCK (bus))
++    {
++      /* If it was in bus_connections, we would have initialized global locks
++       * when we added it. So, it can't be. */
++      return;
++    }
+   /* We are expecting to have the connection saved in only one of these
+    * slots, but someone could in a pathological case set system and session
+@@ -423,7 +432,12 @@ internal_bus_get (DBusBusType  type,
+   connection = NULL;
+-  _DBUS_LOCK (bus);
++  if (!_DBUS_LOCK (bus))
++    {
++      _DBUS_SET_OOM (error);
++      /* do not "goto out", that would try to unlock */
++      return NULL;
++    }
+   if (!init_connections_unlocked ())
+     {
+@@ -493,8 +507,10 @@ internal_bus_get (DBusBusType  type,
+    */
+   dbus_connection_set_exit_on_disconnect (connection,
+                                           TRUE);
+- 
+-  _DBUS_LOCK (bus_datas);
++
++  if (!_DBUS_LOCK (bus_datas))
++    _dbus_assert_not_reached ("global locks were initialized already");
++
+   bd = ensure_bus_data (connection);
+   _dbus_assert (bd != NULL); /* it should have been created on
+                                 register, so OOM not possible */
+@@ -647,7 +663,12 @@ dbus_bus_register (DBusConnection *connection,
+   message = NULL;
+   reply = NULL;
+-  _DBUS_LOCK (bus_datas);
++  if (!_DBUS_LOCK (bus_datas))
++    {
++      _DBUS_SET_OOM (error);
++      /* do not "goto out", that would try to unlock */
++      return FALSE;
++    }
+   bd = ensure_bus_data (connection);
+   if (bd == NULL)
+@@ -756,8 +777,12 @@ dbus_bus_set_unique_name (DBusConnection *connection,
+   _dbus_return_val_if_fail (connection != NULL, FALSE);
+   _dbus_return_val_if_fail (unique_name != NULL, FALSE);
+-  _DBUS_LOCK (bus_datas);
+-  
++  if (!_DBUS_LOCK (bus_datas))
++    {
++      /* do not "goto out", that would try to unlock */
++      return FALSE;
++    }
++
+   bd = ensure_bus_data (connection);
+   if (bd == NULL)
+     goto out;
+@@ -799,8 +824,13 @@ dbus_bus_get_unique_name (DBusConnection *connection)
+   _dbus_return_val_if_fail (connection != NULL, NULL);
+-  _DBUS_LOCK (bus_datas);
+-  
++  if (!_DBUS_LOCK (bus_datas))
++    {
++      /* We'd have initialized locks when we gave it its unique name, if it
++       * had one. Don't "goto out", that would try to unlock. */
++      return NULL;
++    }
++
+   bd = ensure_bus_data (connection);
+   if (bd == NULL)
+     goto out;
+diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
+index 03ee066..87cfeb0 100644
+--- a/dbus/dbus-connection.c
++++ b/dbus/dbus-connection.c
+@@ -1555,9 +1555,14 @@ static void
+ shared_connections_shutdown (void *data)
+ {
+   int n_entries;
+-  
+-  _DBUS_LOCK (shared_connections);
+-  
++
++  if (!_DBUS_LOCK (shared_connections))
++    {
++      /* We'd have initialized locks before adding anything, so there
++       * can't be anything there. */
++      return;
++    }
++
+   /* This is a little bit unpleasant... better ideas? */
+   while ((n_entries = _dbus_hash_table_get_n_entries (shared_connections)) > 0)
+     {
+@@ -1571,7 +1576,8 @@ shared_connections_shutdown (void *data)
+       _DBUS_UNLOCK (shared_connections);
+       close_connection_on_shutdown (connection);
+-      _DBUS_LOCK (shared_connections);
++      if (!_DBUS_LOCK (shared_connections))
++        _dbus_assert_not_reached ("global locks were already initialized");
+       /* The connection should now be dead and not in our hash ... */
+       _dbus_assert (_dbus_hash_table_get_n_entries (shared_connections) < n_entries);
+@@ -1590,7 +1596,8 @@ shared_connections_shutdown (void *data)
+         {
+           _DBUS_UNLOCK (shared_connections);
+           close_connection_on_shutdown (connection);
+-          _DBUS_LOCK (shared_connections);
++          if (!_DBUS_LOCK (shared_connections))
++            _dbus_assert_not_reached ("global locks were already initialized");
+           connection = _dbus_list_pop_first (&shared_connections_no_guid);
+         }
+     }
+@@ -1607,8 +1614,13 @@ connection_lookup_shared (DBusAddressEntry  *entry,
+   _dbus_verbose ("checking for existing connection\n");
+   
+   *result = NULL;
+-  
+-  _DBUS_LOCK (shared_connections);
++
++  if (!_DBUS_LOCK (shared_connections))
++    {
++      /* If it was shared, we'd have initialized global locks when we put
++       * it in shared_connections. */
++      return FALSE;
++    }
+   if (shared_connections == NULL)
+     {
+@@ -1706,7 +1718,8 @@ connection_record_shared_unlocked (DBusConnection *connection,
+   if (guid == NULL)
+     {
+-      _DBUS_LOCK (shared_connections);
++      if (!_DBUS_LOCK (shared_connections))
++        return FALSE;
+       if (!_dbus_list_prepend (&shared_connections_no_guid, connection))
+         {
+@@ -1733,8 +1746,14 @@ connection_record_shared_unlocked (DBusConnection *connection,
+       dbus_free (guid_key);
+       return FALSE;
+     }
+-  
+-  _DBUS_LOCK (shared_connections);
++
++  if (!_DBUS_LOCK (shared_connections))
++    {
++      dbus_free (guid_in_connection);
++      dbus_free (guid_key);
++      return FALSE;
++    }
++
+   _dbus_assert (shared_connections != NULL);
+   
+   if (!_dbus_hash_table_insert_string (shared_connections,
+@@ -1765,9 +1784,14 @@ connection_forget_shared_unlocked (DBusConnection *connection)
+   if (!connection->shareable)
+     return;
+-  
+-  _DBUS_LOCK (shared_connections);
+-      
++
++  if (!_DBUS_LOCK (shared_connections))
++    {
++      /* If it was shared, we'd have initialized global locks when we put
++       * it in the table; so it can't be there. */
++      return;
++    }
++
+   if (connection->server_guid != NULL)
+     {
+       _dbus_verbose ("dropping connection to %s out of the shared table\n",
+diff --git a/dbus/dbus-dataslot.c b/dbus/dbus-dataslot.c
+index b3c8090..412e7f4 100644
+--- a/dbus/dbus-dataslot.c
++++ b/dbus/dbus-dataslot.c
+@@ -71,7 +71,8 @@ _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
+ {
+   dbus_int32_t slot;
+-  _dbus_lock (allocator->lock);
++  if (!_dbus_lock (allocator->lock))
++    return FALSE;
+   if (*slot_id_p >= 0)
+     {
+@@ -153,8 +154,10 @@ void
+ _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
+                                 dbus_int32_t          *slot_id_p)
+ {
+-  _dbus_lock (allocator->lock);
+-  
++  if (!_dbus_lock (allocator->lock))
++    _dbus_assert_not_reached ("we should have initialized global locks "
++        "before we allocated this slot");
++
+   _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
+   _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
+   _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0);
+@@ -228,7 +231,10 @@ _dbus_data_slot_list_set  (DBusDataSlotAllocator *allocator,
+    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
+    * are disabled, since then the asserts are empty.
+    */
+-  _dbus_lock (allocator->lock);
++  if (!_dbus_lock (allocator->lock))
++    _dbus_assert_not_reached ("we should have initialized global locks "
++        "before we allocated this slot");
++
+   _dbus_assert (slot < allocator->n_allocated_slots);
+   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+   _dbus_unlock (allocator->lock);
+@@ -285,7 +291,10 @@ _dbus_data_slot_list_get  (DBusDataSlotAllocator *allocator,
+    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
+    * are disabled, since then the asserts are empty.
+    */
+-  _dbus_lock (allocator->lock);
++  if (!_dbus_lock (allocator->lock))
++    _dbus_assert_not_reached ("we should have initialized global locks "
++        "before we allocated this slot");
++
+   _dbus_assert (slot >= 0);
+   _dbus_assert (slot < allocator->n_allocated_slots);
+   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
+index 1a36734..63559be 100644
+--- a/dbus/dbus-internals.c
++++ b/dbus/dbus-internals.c
+@@ -165,7 +165,9 @@
+ /**
+  * @def _DBUS_LOCK
+  *
+- * Locks a global lock
++ * Locks a global lock, initializing it first if necessary.
++ *
++ * @returns #FALSE if not enough memory
+  */
+ /**
+@@ -849,7 +851,9 @@ _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
+ {
+   dbus_bool_t ok;
+   
+-  _DBUS_LOCK (machine_uuid);
++  if (!_DBUS_LOCK (machine_uuid))
++    return FALSE;
++
+   if (machine_uuid_initialized_generation != _dbus_current_generation)
+     {
+       DBusError error = DBUS_ERROR_INIT;
+diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
+index 22ad297..edde80b 100644
+--- a/dbus/dbus-internals.h
++++ b/dbus/dbus-internals.h
+@@ -327,8 +327,8 @@ typedef enum
+   _DBUS_N_GLOBAL_LOCKS
+ } DBusGlobalLock;
+-void _dbus_lock   (DBusGlobalLock lock);
+-void _dbus_unlock (DBusGlobalLock lock);
++dbus_bool_t _dbus_lock   (DBusGlobalLock lock) _DBUS_GNUC_WARN_UNUSED_RESULT;
++void        _dbus_unlock (DBusGlobalLock lock);
+ #define _DBUS_LOCK_NAME(name)           _DBUS_LOCK_##name
+ #define _DBUS_LOCK(name)                _dbus_lock   (_DBUS_LOCK_##name)
+diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c
+index e5a4940..525e067 100644
+--- a/dbus/dbus-list.c
++++ b/dbus/dbus-list.c
+@@ -56,7 +56,8 @@ alloc_link (void *data)
+ {
+   DBusList *link;
+-  _DBUS_LOCK (list);
++  if (!_DBUS_LOCK (list))
++    return FALSE;
+   if (list_pool == NULL)
+     {      
+@@ -93,7 +94,10 @@ alloc_link (void *data)
+ static void
+ free_link (DBusList *link)
+ {  
+-  _DBUS_LOCK (list);
++  if (!_DBUS_LOCK (list))
++    _dbus_assert_not_reached ("we should have initialized global locks "
++        "before we allocated a linked-list link");
++
+   if (_dbus_mem_pool_dealloc (list_pool, link))
+     {
+       _dbus_mem_pool_free (list_pool);
+@@ -152,7 +156,14 @@ _dbus_list_get_stats     (dbus_uint32_t *in_use_p,
+                           dbus_uint32_t *in_free_list_p,
+                           dbus_uint32_t *allocated_p)
+ {
+-  _DBUS_LOCK (list);
++  if (!_DBUS_LOCK (list))
++    {
++      *in_use_p = 0;
++      *in_free_list_p = 0;
++      *allocated_p = 0;
++      return;
++    }
++
+   _dbus_mem_pool_get_stats (list_pool, in_use_p, in_free_list_p, allocated_p);
+   _DBUS_UNLOCK (list);
+ }
+diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c
+index a13b951..6cf0449 100644
+--- a/dbus/dbus-memory.c
++++ b/dbus/dbus-memory.c
+@@ -812,7 +812,9 @@ _dbus_register_shutdown_func (DBusShutdownFunction  func,
+ {
+   dbus_bool_t ok;
+-  _DBUS_LOCK (shutdown_funcs);
++  if (!_DBUS_LOCK (shutdown_funcs))
++    return FALSE;
++
+   ok = _dbus_register_shutdown_func_unlocked (func, data);
+   _DBUS_UNLOCK (shutdown_funcs);
+   return ok;
+diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
+index 2814569..275c425 100644
+--- a/dbus/dbus-message.c
++++ b/dbus/dbus-message.c
+@@ -516,7 +516,9 @@ dbus_message_cache_shutdown (void *data)
+ {
+   int i;
+-  _DBUS_LOCK (message_cache);
++  if (!_DBUS_LOCK (message_cache))
++    _dbus_assert_not_reached ("we would have initialized global locks "
++        "before registering a shutdown function");
+   i = 0;
+   while (i < MAX_MESSAGE_CACHE_SIZE)
+@@ -548,7 +550,12 @@ dbus_message_get_cached (void)
+   message = NULL;
+-  _DBUS_LOCK (message_cache);
++  if (!_DBUS_LOCK (message_cache))
++    {
++      /* we'd have initialized global locks before caching anything,
++       * so there can't be anything in the cache */
++      return NULL;
++    }
+   _dbus_assert (message_cache_count >= 0);
+@@ -660,7 +667,13 @@ dbus_message_cache_or_finalize (DBusMessage *message)
+   was_cached = FALSE;
+-  _DBUS_LOCK (message_cache);
++  if (!_DBUS_LOCK (message_cache))
++    {
++      /* The only way to get a non-null message goes through
++       * dbus_message_get_cached() which takes the lock. */
++      _dbus_assert_not_reached ("we would have initialized global locks "
++          "the first time we constructed a message");
++    }
+   if (!message_cache_shutdown_registered)
+     {
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index 297a7e4..2c2a816 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -366,10 +366,12 @@ shutdown_uninitialized_locks (void *data)
+   _dbus_list_clear (&uninitialized_condvar_list);
+ }
++/* init_global_locks() must be called first. */
+ static dbus_bool_t
+ init_uninitialized_locks (void)
+ {
+   DBusList *link;
++  dbus_bool_t ok;
+   _dbus_assert (thread_init_generation != _dbus_current_generation);
+@@ -422,8 +424,12 @@ init_uninitialized_locks (void)
+   _dbus_list_clear (&uninitialized_cmutex_list);
+   _dbus_list_clear (&uninitialized_condvar_list);
+-  if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
+-                                     NULL))
++  /* This assumes that init_global_locks() has already been called. */
++  _dbus_platform_rmutex_lock (global_locks[_DBUS_LOCK_shutdown_funcs]);
++  ok = _dbus_register_shutdown_func_unlocked (shutdown_uninitialized_locks, NULL);
++  _dbus_platform_rmutex_unlock (global_locks[_DBUS_LOCK_shutdown_funcs]);
++
++  if (!ok)
+     goto fail_condvar;
+   return TRUE;
+@@ -494,9 +500,9 @@ init_global_locks (void)
+         goto failed;
+     }
+-  _dbus_lock (_DBUS_LOCK_NAME (shutdown_funcs));
++  _dbus_platform_rmutex_lock (global_locks[_DBUS_LOCK_shutdown_funcs]);
+   ok = _dbus_register_shutdown_func_unlocked (shutdown_global_locks, NULL);
+-  _dbus_unlock (_DBUS_LOCK_NAME (shutdown_funcs));
++  _dbus_platform_rmutex_unlock (global_locks[_DBUS_LOCK_shutdown_funcs]);
+   if (!ok)
+     goto failed;
+@@ -513,14 +519,18 @@ init_global_locks (void)
+   return FALSE;
+ }
+-void
++dbus_bool_t
+ _dbus_lock (DBusGlobalLock lock)
+ {
+   _dbus_assert (lock >= 0);
+   _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS);
+-  if (thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_rmutex_lock (global_locks[lock]);
++  if (thread_init_generation != _dbus_current_generation &&
++      !dbus_threads_init_default ())
++    return FALSE;
++
++  _dbus_platform_rmutex_lock (global_locks[lock]);
++  return TRUE;
+ }
+ void
+@@ -529,8 +539,7 @@ _dbus_unlock (DBusGlobalLock lock)
+   _dbus_assert (lock >= 0);
+   _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS);
+-  if (thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_rmutex_unlock (global_locks[lock]);
++  _dbus_platform_rmutex_unlock (global_locks[lock]);
+ }
+ /** @} */ /* end of internals */
+@@ -576,6 +585,7 @@ dbus_threads_init (const DBusThreadFunctions *functions)
+     }
+   if (!_dbus_threads_init_platform_specific() ||
++      /* init_global_locks() must be called before init_uninitialized_locks. */
+       !init_global_locks () ||
+       !init_uninitialized_locks ())
+     {
+diff --git a/dbus/dbus-userdb-util.c b/dbus/dbus-userdb-util.c
+index 16bf229..a8cc3d1 100644
+--- a/dbus/dbus-userdb-util.c
++++ b/dbus/dbus-userdb-util.c
+@@ -103,7 +103,11 @@ _dbus_is_console_user (dbus_uid_t uid,
+ #endif /* HAVE_CONSOLE_OWNER_FILE */
+-  _dbus_user_database_lock_system ();
++  if (!_dbus_user_database_lock_system ())
++    {
++      _DBUS_SET_OOM (error);
++      return FALSE;
++    }
+   db = _dbus_user_database_get_system ();
+   if (db == NULL)
+@@ -157,7 +161,10 @@ _dbus_get_group_id (const DBusString  *groupname,
+ {
+   DBusUserDatabase *db;
+   const DBusGroupInfo *info;
+-  _dbus_user_database_lock_system ();
++
++  /* FIXME: this can't distinguish ENOMEM from other errors */
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
+   db = _dbus_user_database_get_system ();
+   if (db == NULL)
+@@ -194,7 +201,10 @@ _dbus_get_user_id_and_primary_group (const DBusString  *username,
+ {
+   DBusUserDatabase *db;
+   const DBusUserInfo *info;
+-  _dbus_user_database_lock_system ();
++
++  /* FIXME: this can't distinguish ENOMEM from other errors */
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
+   db = _dbus_user_database_get_system ();
+   if (db == NULL)
+@@ -387,7 +397,9 @@ _dbus_groups_from_uid (dbus_uid_t         uid,
+   *group_ids = NULL;
+   *n_group_ids = 0;
+-  _dbus_user_database_lock_system ();
++  /* FIXME: this can't distinguish ENOMEM from other errors */
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
+   db = _dbus_user_database_get_system ();
+   if (db == NULL)
+diff --git a/dbus/dbus-userdb.c b/dbus/dbus-userdb.c
+index 4e8b39a..73f8fce 100644
+--- a/dbus/dbus-userdb.c
++++ b/dbus/dbus-userdb.c
+@@ -306,11 +306,18 @@ init_system_db (void)
+ /**
+  * Locks global system user database.
+  */
+-void
++dbus_bool_t
+ _dbus_user_database_lock_system (void)
+ {
+-  _DBUS_LOCK (system_users);
+-  database_locked = TRUE;
++  if (_DBUS_LOCK (system_users))
++    {
++      database_locked = TRUE;
++      return TRUE;
++    }
++  else
++    {
++      return FALSE;
++    }
+ }
+ /**
+@@ -345,8 +352,12 @@ _dbus_user_database_get_system (void)
+ void
+ _dbus_user_database_flush_system (void)
+ {
+-  _dbus_user_database_lock_system ();
+-   
++  if (!_dbus_user_database_lock_system ())
++    {
++      /* nothing to flush */
++      return;
++    }
++
+    if (system_db != NULL)
+     _dbus_user_database_flush (system_db);
+@@ -363,7 +374,9 @@ _dbus_user_database_flush_system (void)
+ dbus_bool_t
+ _dbus_username_from_current_process (const DBusString **username)
+ {
+-  _dbus_user_database_lock_system ();
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
++
+   if (!init_system_db ())
+     {
+       _dbus_user_database_unlock_system ();
+@@ -385,7 +398,9 @@ _dbus_username_from_current_process (const DBusString **username)
+ dbus_bool_t
+ _dbus_homedir_from_current_process (const DBusString  **homedir)
+ {
+-  _dbus_user_database_lock_system ();
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
++
+   if (!init_system_db ())
+     {
+       _dbus_user_database_unlock_system ();
+@@ -410,7 +425,10 @@ _dbus_homedir_from_username (const DBusString *username,
+ {
+   DBusUserDatabase *db;
+   const DBusUserInfo *info;
+-  _dbus_user_database_lock_system ();
++
++  /* FIXME: this can't distinguish ENOMEM from other errors */
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
+   db = _dbus_user_database_get_system ();
+   if (db == NULL)
+@@ -449,7 +467,10 @@ _dbus_homedir_from_uid (dbus_uid_t         uid,
+ {
+   DBusUserDatabase *db;
+   const DBusUserInfo *info;
+-  _dbus_user_database_lock_system ();
++
++  /* FIXME: this can't distinguish ENOMEM from other errors */
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
+   db = _dbus_user_database_get_system ();
+   if (db == NULL)
+@@ -496,7 +517,9 @@ _dbus_credentials_add_from_user (DBusCredentials  *credentials,
+   DBusUserDatabase *db;
+   const DBusUserInfo *info;
+-  _dbus_user_database_lock_system ();
++  /* FIXME: this can't distinguish ENOMEM from other errors */
++  if (!_dbus_user_database_lock_system ())
++    return FALSE;
+   db = _dbus_user_database_get_system ();
+   if (db == NULL)
+diff --git a/dbus/dbus-userdb.h b/dbus/dbus-userdb.h
+index cb49d9e..d6b72d8 100644
+--- a/dbus/dbus-userdb.h
++++ b/dbus/dbus-userdb.h
+@@ -86,7 +86,7 @@ void           _dbus_group_info_free_allocated  (DBusGroupInfo    *info);
+ #endif /* DBUS_USERDB_INCLUDES_PRIVATE */
+ DBusUserDatabase* _dbus_user_database_get_system    (void);
+-void              _dbus_user_database_lock_system   (void);
++dbus_bool_t       _dbus_user_database_lock_system   (void) _DBUS_GNUC_WARN_UNUSED_RESULT;
+ void              _dbus_user_database_unlock_system (void);
+ void              _dbus_user_database_flush_system  (void);
+diff --git a/test/name-test/test-threads-init.c b/test/name-test/test-threads-init.c
+index 5e22852..580ffe1 100644
+--- a/test/name-test/test-threads-init.c
++++ b/test/name-test/test-threads-init.c
+@@ -149,11 +149,15 @@ main (int argc, char *argv[])
+                                          &dispatch_cond1,
+                                          &io_path_cond1);
+-  check_mutex_lock (mutex1, mutex2, FALSE);
+-  check_mutex_lock (dispatch_mutex1, dispatch_mutex2, FALSE);
+-  check_mutex_lock (io_path_mutex1, io_path_mutex2, FALSE);
+-  check_condvar_lock (dispatch_cond1, dispatch_cond2, FALSE);
+-  check_condvar_lock (io_path_cond1, io_path_cond2, FALSE);
++  /* Since 1.7 it is no longer the case that mutex1 != mutex2, because
++   * initializing global locks automatically initializes locks
++   * in general. However, it is true that the mutex is not the dummy
++   * implementation, which is what we really wanted to check here. */
++  _dbus_assert (mutex1 != (DBusMutex *) 0xABCDEF);
++  _dbus_assert (dispatch_mutex1 != (DBusMutex *) 0xABCDEF);
++  _dbus_assert (dispatch_cond1 != (DBusCondVar *) 0xABCDEF2);
++  _dbus_assert (io_path_mutex1 != (DBusMutex *) 0xABCDEF);
++  _dbus_assert (io_path_cond1 != (DBusCondVar *) 0xABCDEF2);
+   _run_iteration (conn);
+   _dbus_connection_test_get_locks (conn, &mutex2,
diff --git a/recipes-core/dbus/files/0010-Always-initialize-threading-before-allocating-a-dyna.patch b/recipes-core/dbus/files/0010-Always-initialize-threading-before-allocating-a-dyna.patch
new file mode 100644 (file)
index 0000000..e9abe9c
--- /dev/null
@@ -0,0 +1,491 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Tue, 16 Apr 2013 16:37:51 +0100
+Subject: Always initialize threading before allocating a dynamic mutex
+
+Dynamic allocation of mutexes can fail anyway, so this is easy.
+
+Justification for not keeping the dummy mutex code-paths, even as an
+opt-in thing for processes known to be high-performance and
+single-threaded: real mutexes only cut the throughput of
+test/dbus-daemon.c by a couple of percent on my laptop (from around
+6700 to around 6600 messages per second), and libdbus crashes caused
+by not calling dbus_threads_init_default() are sufficiently widespread
+that they're wasting a lot of everyone's time.
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Anas Nashif <anas.nashif@intel.com>
+Bug-Tizen: TZPC-1971
+Applied-upstream: 1.7.6, commit:08391b14616c248458e838691d068aa48dc70d18
+Change-Id: I62e4fc541f6868ef44dc0654337b895e5392c16e
+---
+ dbus/dbus-threads.c | 300 ++++++++++------------------------------------------
+ 1 file changed, 56 insertions(+), 244 deletions(-)
+
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index 2c2a816..29462eb 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -27,18 +27,6 @@
+ #include "dbus-list.h"
+ static int thread_init_generation = 0;
+- 
+-static DBusList *uninitialized_rmutex_list = NULL;
+-static DBusList *uninitialized_cmutex_list = NULL;
+-static DBusList *uninitialized_condvar_list = NULL;
+-
+-/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
+-#define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
+-#define _DBUS_DUMMY_RMUTEX ((DBusRMutex *) _DBUS_DUMMY_MUTEX)
+-#define _DBUS_DUMMY_CMUTEX ((DBusCMutex *) _DBUS_DUMMY_MUTEX)
+-
+-/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
+-#define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
+ /**
+  * @defgroup DBusThreadsInternals Thread functions
+@@ -59,11 +47,6 @@ static DBusList *uninitialized_condvar_list = NULL;
+  * If possible, the mutex returned by this function is recursive, to
+  * avoid deadlocks. However, that cannot be relied on.
+  *
+- * The extra level of indirection given by allocating a pointer
+- * to point to the mutex location allows the threading
+- * module to swap out dummy mutexes for a real mutex so libraries
+- * can initialize threads even after the D-Bus API has been used.
+- *
+  * @param location_p the location of the new mutex, can return #NULL on OOM
+  */
+ void
+@@ -71,17 +54,13 @@ _dbus_rmutex_new_at_location (DBusRMutex **location_p)
+ {
+   _dbus_assert (location_p != NULL);
+-  if (thread_init_generation == _dbus_current_generation)
++  if (!dbus_threads_init_default ())
+     {
+-      *location_p = _dbus_platform_rmutex_new ();
++      *location_p = NULL;
++      return;
+     }
+-  else
+-    {
+-      *location_p = _DBUS_DUMMY_RMUTEX;
+-      if (!_dbus_list_append (&uninitialized_rmutex_list, location_p))
+-        *location_p = NULL;
+-    }
++  *location_p = _dbus_platform_rmutex_new ();
+ }
+ /**
+@@ -92,11 +71,6 @@ _dbus_rmutex_new_at_location (DBusRMutex **location_p)
+  *
+  * The returned mutex is suitable for use with condition variables.
+  *
+- * The extra level of indirection given by allocating a pointer
+- * to point to the mutex location allows the threading
+- * module to swap out dummy mutexes for a real mutex so libraries
+- * can initialize threads even after the D-Bus API has been used.
+- *
+  * @param location_p the location of the new mutex, can return #NULL on OOM
+  */
+ void
+@@ -104,22 +78,17 @@ _dbus_cmutex_new_at_location (DBusCMutex **location_p)
+ {
+   _dbus_assert (location_p != NULL);
+-  if (thread_init_generation == _dbus_current_generation)
++  if (!dbus_threads_init_default ())
+     {
+-      *location_p = _dbus_platform_cmutex_new ();
++      *location_p = NULL;
++      return;
+     }
+-  else
+-    {
+-      *location_p = _DBUS_DUMMY_CMUTEX;
+-      if (!_dbus_list_append (&uninitialized_cmutex_list, location_p))
+-        *location_p = NULL;
+-    }
++  *location_p = _dbus_platform_cmutex_new ();
+ }
+ /**
+- * Frees a DBusRMutex or removes it from the uninitialized mutex list;
+- * does nothing if passed a #NULL pointer.
++ * Frees a DBusRMutex; does nothing if passed a #NULL pointer.
+  */
+ void
+ _dbus_rmutex_free_at_location (DBusRMutex **location_p)
+@@ -127,23 +96,12 @@ _dbus_rmutex_free_at_location (DBusRMutex **location_p)
+   if (location_p == NULL)
+     return;
+-  if (thread_init_generation == _dbus_current_generation)
+-    {
+-      if (*location_p != NULL)
+-        _dbus_platform_rmutex_free (*location_p);
+-    }
+-  else
+-    {
+-      _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_RMUTEX);
+-
+-      _dbus_list_remove (&uninitialized_rmutex_list, location_p);
+-    }
++  if (*location_p != NULL)
++    _dbus_platform_rmutex_free (*location_p);
+ }
+ /**
+- * Frees a DBusCMutex and removes it from the
+- * uninitialized mutex list;
+- * does nothing if passed a #NULL pointer.
++ * Frees a DBusCMutex; does nothing if passed a #NULL pointer.
+  */
+ void
+ _dbus_cmutex_free_at_location (DBusCMutex **location_p)
+@@ -151,17 +109,8 @@ _dbus_cmutex_free_at_location (DBusCMutex **location_p)
+   if (location_p == NULL)
+     return;
+-  if (thread_init_generation == _dbus_current_generation)
+-    {
+-      if (*location_p != NULL)
+-        _dbus_platform_cmutex_free (*location_p);
+-    }
+-  else
+-    {
+-      _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CMUTEX);
+-
+-      _dbus_list_remove (&uninitialized_cmutex_list, location_p);
+-    }
++  if (*location_p != NULL)
++    _dbus_platform_cmutex_free (*location_p);
+ }
+ /**
+@@ -172,8 +121,10 @@ _dbus_cmutex_free_at_location (DBusCMutex **location_p)
+ void
+ _dbus_rmutex_lock (DBusRMutex *mutex)
+ {
+-  if (mutex && thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_rmutex_lock (mutex);
++  if (mutex == NULL)
++    return;
++
++  _dbus_platform_rmutex_lock (mutex);
+ }
+ /**
+@@ -184,8 +135,10 @@ _dbus_rmutex_lock (DBusRMutex *mutex)
+ void
+ _dbus_cmutex_lock (DBusCMutex *mutex)
+ {
+-  if (mutex && thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_cmutex_lock (mutex);
++  if (mutex == NULL)
++    return;
++
++  _dbus_platform_cmutex_lock (mutex);
+ }
+ /**
+@@ -196,8 +149,10 @@ _dbus_cmutex_lock (DBusCMutex *mutex)
+ void
+ _dbus_rmutex_unlock (DBusRMutex *mutex)
+ {
+-  if (mutex && thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_rmutex_unlock (mutex);
++  if (mutex == NULL)
++    return;
++
++  _dbus_platform_rmutex_unlock (mutex);
+ }
+ /**
+@@ -208,8 +163,10 @@ _dbus_rmutex_unlock (DBusRMutex *mutex)
+ void
+ _dbus_cmutex_unlock (DBusCMutex *mutex)
+ {
+-  if (mutex && thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_cmutex_unlock (mutex);
++  if (mutex == NULL)
++    return;
++
++  _dbus_platform_cmutex_unlock (mutex);
+ }
+ /**
+@@ -223,19 +180,17 @@ _dbus_cmutex_unlock (DBusCMutex *mutex)
+ DBusCondVar *
+ _dbus_condvar_new (void)
+ {
+-  if (thread_init_generation == _dbus_current_generation)
+-    return _dbus_platform_condvar_new ();
+-  else
+-    return _DBUS_DUMMY_CONDVAR;
++  if (!dbus_threads_init_default ())
++    return NULL;
++
++  return _dbus_platform_condvar_new ();
+ }
+ /**
+  * This does the same thing as _dbus_condvar_new.  It however
+  * gives another level of indirection by allocating a pointer
+- * to point to the condvar location.  This allows the threading
+- * module to swap out dummy condvars for a real condvar so libraries
+- * can initialize threads even after the D-Bus API has been used.
++ * to point to the condvar location; this used to be useful.
+  *
+  * @returns the location of a new condvar or #NULL on OOM
+  */
+@@ -245,17 +200,7 @@ _dbus_condvar_new_at_location (DBusCondVar **location_p)
+ {
+   _dbus_assert (location_p != NULL);
+-  if (thread_init_generation == _dbus_current_generation)
+-    {
+-      *location_p = _dbus_condvar_new();
+-    }
+-  else
+-    {
+-      *location_p = _DBUS_DUMMY_CONDVAR;
+-
+-      if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
+-        *location_p = NULL;
+-    }
++  *location_p = _dbus_condvar_new();
+ }
+@@ -266,14 +211,14 @@ _dbus_condvar_new_at_location (DBusCondVar **location_p)
+ void
+ _dbus_condvar_free (DBusCondVar *cond)
+ {
+-  if (cond && thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_condvar_free (cond);
++  if (cond == NULL)
++    return;
++
++  _dbus_platform_condvar_free (cond);
+ }
+ /**
+- * Frees a conditional variable and removes it from the 
+- * uninitialized_condvar_list; 
+- * does nothing if passed a #NULL pointer.
++ * Frees a condition variable; does nothing if passed a #NULL pointer.
+  */
+ void
+ _dbus_condvar_free_at_location (DBusCondVar **location_p)
+@@ -281,17 +226,8 @@ _dbus_condvar_free_at_location (DBusCondVar **location_p)
+   if (location_p == NULL)
+     return;
+-  if (thread_init_generation == _dbus_current_generation)
+-    {
+-      if (*location_p != NULL)
+-        _dbus_platform_condvar_free (*location_p);
+-    }
+-  else
+-    {
+-      _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CONDVAR);
+-
+-      _dbus_list_remove (&uninitialized_condvar_list, location_p);
+-    }
++  if (*location_p != NULL)
++    _dbus_platform_condvar_free (*location_p);
+ }
+ /**
+@@ -304,8 +240,10 @@ void
+ _dbus_condvar_wait (DBusCondVar *cond,
+                     DBusCMutex  *mutex)
+ {
+-  if (cond && mutex && thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_condvar_wait (cond, mutex);
++  if (cond == NULL || mutex == NULL)
++    return;
++
++  _dbus_platform_condvar_wait (cond, mutex);
+ }
+ /**
+@@ -324,11 +262,11 @@ _dbus_condvar_wait_timeout (DBusCondVar               *cond,
+                             DBusCMutex                *mutex,
+                             int                        timeout_milliseconds)
+ {
+-  if (cond && mutex && thread_init_generation == _dbus_current_generation)
+-    return _dbus_platform_condvar_wait_timeout (cond, mutex,
+-                                                timeout_milliseconds);
+-  else
++  if (cond == NULL || mutex == NULL)
+     return TRUE;
++
++  return _dbus_platform_condvar_wait_timeout (cond, mutex,
++      timeout_milliseconds);
+ }
+ /**
+@@ -339,8 +277,10 @@ _dbus_condvar_wait_timeout (DBusCondVar               *cond,
+ void
+ _dbus_condvar_wake_one (DBusCondVar *cond)
+ {
+-  if (cond && thread_init_generation == _dbus_current_generation)
+-    _dbus_platform_condvar_wake_one (cond);
++  if (cond == NULL)
++    return;
++
++  _dbus_platform_condvar_wake_one (cond);
+ }
+ static DBusRMutex *global_locks[_DBUS_N_GLOBAL_LOCKS] = { NULL };
+@@ -358,132 +298,6 @@ shutdown_global_locks (void *nil)
+     }
+ }
+-static void
+-shutdown_uninitialized_locks (void *data)
+-{
+-  _dbus_list_clear (&uninitialized_rmutex_list);
+-  _dbus_list_clear (&uninitialized_cmutex_list);
+-  _dbus_list_clear (&uninitialized_condvar_list);
+-}
+-
+-/* init_global_locks() must be called first. */
+-static dbus_bool_t
+-init_uninitialized_locks (void)
+-{
+-  DBusList *link;
+-  dbus_bool_t ok;
+-
+-  _dbus_assert (thread_init_generation != _dbus_current_generation);
+-
+-  link = uninitialized_rmutex_list;
+-  while (link != NULL)
+-    {
+-      DBusRMutex **mp;
+-
+-      mp = link->data;
+-      _dbus_assert (*mp == _DBUS_DUMMY_RMUTEX);
+-
+-      *mp = _dbus_platform_rmutex_new ();
+-      if (*mp == NULL)
+-        goto fail_mutex;
+-
+-      link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
+-    }
+-
+-  link = uninitialized_cmutex_list;
+-  while (link != NULL)
+-    {
+-      DBusCMutex **mp;
+-
+-      mp = link->data;
+-      _dbus_assert (*mp == _DBUS_DUMMY_CMUTEX);
+-
+-      *mp = _dbus_platform_cmutex_new ();
+-      if (*mp == NULL)
+-        goto fail_mutex;
+-
+-      link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
+-    }
+-
+-  link = uninitialized_condvar_list;
+-  while (link != NULL)
+-    {
+-      DBusCondVar **cp;
+-
+-      cp = (DBusCondVar **)link->data;
+-      _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
+-
+-      *cp = _dbus_platform_condvar_new ();
+-      if (*cp == NULL)
+-        goto fail_condvar;
+-
+-      link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
+-    }
+-
+-  _dbus_list_clear (&uninitialized_rmutex_list);
+-  _dbus_list_clear (&uninitialized_cmutex_list);
+-  _dbus_list_clear (&uninitialized_condvar_list);
+-
+-  /* This assumes that init_global_locks() has already been called. */
+-  _dbus_platform_rmutex_lock (global_locks[_DBUS_LOCK_shutdown_funcs]);
+-  ok = _dbus_register_shutdown_func_unlocked (shutdown_uninitialized_locks, NULL);
+-  _dbus_platform_rmutex_unlock (global_locks[_DBUS_LOCK_shutdown_funcs]);
+-
+-  if (!ok)
+-    goto fail_condvar;
+-
+-  return TRUE;
+-
+- fail_condvar:
+-  link = uninitialized_condvar_list;
+-  while (link != NULL)
+-    {
+-      DBusCondVar **cp;
+-
+-      cp = link->data;
+-
+-      if (*cp != _DBUS_DUMMY_CONDVAR && *cp != NULL)
+-        _dbus_platform_condvar_free (*cp);
+-
+-      *cp = _DBUS_DUMMY_CONDVAR;
+-
+-      link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
+-    }
+-
+- fail_mutex:
+-  link = uninitialized_rmutex_list;
+-  while (link != NULL)
+-    {
+-      DBusRMutex **mp;
+-
+-      mp = link->data;
+-
+-      if (*mp != _DBUS_DUMMY_RMUTEX && *mp != NULL)
+-        _dbus_platform_rmutex_free (*mp);
+-
+-      *mp = _DBUS_DUMMY_RMUTEX;
+-
+-      link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
+-    }
+-
+-  link = uninitialized_cmutex_list;
+-  while (link != NULL)
+-    {
+-      DBusCMutex **mp;
+-
+-      mp = link->data;
+-
+-      if (*mp != _DBUS_DUMMY_CMUTEX && *mp != NULL)
+-        _dbus_platform_cmutex_free (*mp);
+-
+-      *mp = _DBUS_DUMMY_CMUTEX;
+-
+-      link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
+-    }
+-
+-  return FALSE;
+-}
+-
+ static dbus_bool_t
+ init_global_locks (void)
+ {
+@@ -585,9 +399,7 @@ dbus_threads_init (const DBusThreadFunctions *functions)
+     }
+   if (!_dbus_threads_init_platform_specific() ||
+-      /* init_global_locks() must be called before init_uninitialized_locks. */
+-      !init_global_locks () ||
+-      !init_uninitialized_locks ())
++      !init_global_locks ())
+     {
+       _dbus_threads_unlock_platform_specific ();
+       return FALSE;
diff --git a/recipes-core/dbus/files/0011-Add-a-statically-initialized-implementation-of-_dbus.patch b/recipes-core/dbus/files/0011-Add-a-statically-initialized-implementation-of-_dbus.patch
new file mode 100644 (file)
index 0000000..5f380a9
--- /dev/null
@@ -0,0 +1,122 @@
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Tue, 16 Apr 2013 16:48:11 +0100
+Subject: Add a statically-initialized implementation of _dbus_lock() on glibc
+ systems
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
+Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
+Reviewed-by: Anas Nashif <anas.nashif@intel.com>
+Bug-Tizen: TZPC-1971
+Applied-upstream: 1.7.6, commit:83aaa9f359e90d3b8cae5d17f6d9ba4600cff68b
+Change-Id: Iee8ec5e2138ad8398efbe1cd16b46e61cee08670
+---
+ dbus/dbus-sysdeps-pthread.c  | 47 ++++++++++++++++++++++++++++++++++++++++++++
+ dbus/dbus-threads-internal.h |  6 ++++++
+ dbus/dbus-threads.c          | 14 +++++++++++++
+ 3 files changed, 67 insertions(+)
+
+diff --git a/dbus/dbus-sysdeps-pthread.c b/dbus/dbus-sysdeps-pthread.c
+index 1b5d0ba..da7d937 100644
+--- a/dbus/dbus-sysdeps-pthread.c
++++ b/dbus/dbus-sysdeps-pthread.c
+@@ -298,3 +298,50 @@ _dbus_threads_unlock_platform_specific (void)
+ {
+   pthread_mutex_unlock (&init_mutex);
+ }
++
++#ifdef DBUS_HAVE_STATIC_RECURSIVE_MUTEXES
++
++static pthread_mutex_t global_locks[] = {
++    /* 0-4 */
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    /* 5-9 */
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    /* 10-11 */
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
++    PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
++};
++
++_DBUS_STATIC_ASSERT (_DBUS_N_ELEMENTS (global_locks) == _DBUS_N_GLOBAL_LOCKS);
++
++dbus_bool_t
++_dbus_lock (DBusGlobalLock lock)
++{
++  /* No initialization is needed. */
++  _dbus_assert (lock >= 0);
++  _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS);
++
++  PTHREAD_CHECK ("pthread_mutex_lock",
++      pthread_mutex_lock (&(global_locks[lock])));
++  return TRUE;
++}
++
++void
++_dbus_unlock (DBusGlobalLock lock)
++{
++  /* No initialization is needed. */
++  _dbus_assert (lock >= 0);
++  _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS);
++
++  PTHREAD_CHECK ("pthread_mutex_unlock",
++      pthread_mutex_unlock (&(global_locks[lock])));
++}
++
++#endif
+diff --git a/dbus/dbus-threads-internal.h b/dbus/dbus-threads-internal.h
+index 64e8bac..228a8c0 100644
+--- a/dbus/dbus-threads-internal.h
++++ b/dbus/dbus-threads-internal.h
+@@ -32,6 +32,12 @@
+  * @{
+  */
++/* glibc can implement global locks without needing an initialization step,
++ * which improves our thread-safety-by-default further. */
++#if defined(__GLIBC__) && defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
++#   define DBUS_HAVE_STATIC_RECURSIVE_MUTEXES 1
++#endif
++
+ /**
+  * A mutex which is recursive if possible, else non-recursive.
+  * This is typically recursive, but that cannot be relied upon.
+diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
+index 29462eb..1781bda 100644
+--- a/dbus/dbus-threads.c
++++ b/dbus/dbus-threads.c
+@@ -283,6 +283,18 @@ _dbus_condvar_wake_one (DBusCondVar *cond)
+   _dbus_platform_condvar_wake_one (cond);
+ }
++#ifdef DBUS_HAVE_STATIC_RECURSIVE_MUTEXES
++
++static dbus_bool_t
++init_global_locks (void)
++{
++  return TRUE;
++}
++
++/* implementations in dbus-sysdeps-pthread.c */
++
++#else /* !defined(DBUS_HAVE_STATIC_RECURSIVE_MUTEXES) */
++
+ static DBusRMutex *global_locks[_DBUS_N_GLOBAL_LOCKS] = { NULL };
+ static void
+@@ -356,6 +368,8 @@ _dbus_unlock (DBusGlobalLock lock)
+   _dbus_platform_rmutex_unlock (global_locks[lock]);
+ }
++#endif /* !defined(DBUS_HAVE_STATIC_RECURSIVE_MUTEXES) */
++
+ /** @} */ /* end of internals */
+ /**
diff --git a/recipes-core/dbus/files/0012-Enable-checking-of-smack-context-from-DBus-interface.patch b/recipes-core/dbus/files/0012-Enable-checking-of-smack-context-from-DBus-interface.patch
new file mode 100644 (file)
index 0000000..5393bb9
--- /dev/null
@@ -0,0 +1,341 @@
+From: Brian McGillion <brian.mcgillion@intel.com>
+Date: Mon, 6 Feb 2012 18:46:05 +0200
+Subject: Enable checking of smack context from DBus interface
+
+---
+ bus/Makefile.am          |   4 ++
+ bus/driver.c             |   6 +++
+ bus/smack.c              | 132 +++++++++++++++++++++++++++++++++++++++++++++++
+ bus/smack.h              |  36 +++++++++++++
+ cmake/CMakeLists.txt     |   3 ++
+ cmake/bus/CMakeLists.txt |   4 +-
+ configure.ac             |  17 +++++-
+ 7 files changed, 199 insertions(+), 3 deletions(-)
+ create mode 100644 bus/smack.c
+ create mode 100644 bus/smack.h
+
+diff --git a/bus/Makefile.am b/bus/Makefile.am
+index 6cbc09a..7f63d86 100644
+--- a/bus/Makefile.am
++++ b/bus/Makefile.am
+@@ -7,6 +7,7 @@ DBUS_BUS_LIBS = \
+       $(THREAD_LIBS) \
+       $(ADT_LIBS) \
+       $(NETWORK_libs) \
++      $(LIBSMACK_LIBS) \
+       $(NULL)
+ DBUS_LAUNCHER_LIBS = \
+@@ -21,6 +22,7 @@ AM_CPPFLAGS = \
+       -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \
+       -DDBUS_COMPILATION \
+       -DDBUS_STATIC_BUILD \
++      $(LIBSMACK_CFLAGS) \
+       $(NULL)
+ # if assertions are enabled, improve backtraces
+@@ -93,6 +95,8 @@ BUS_SOURCES=                                 \
+       services.h                              \
+       signals.c                               \
+       signals.h                               \
++      smack.c                                 \
++      smack.h                                 \
+       stats.c                                 \
+       stats.h                                 \
+       test.c                                  \
+diff --git a/bus/driver.c b/bus/driver.c
+index 574e0f3..c6298d7 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -30,6 +30,7 @@
+ #include "services.h"
+ #include "selinux.h"
+ #include "signals.h"
++#include "smack.h"
+ #include "stats.h"
+ #include "utils.h"
+ #include <dbus/dbus-string.h>
+@@ -38,6 +39,7 @@
+ #include <dbus/dbus-marshal-recursive.h>
+ #include <string.h>
++
+ static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
+                                                     DBusMessage    *hello_message,
+                                                     BusTransaction *transaction,
+@@ -1736,6 +1738,10 @@ static const MessageHandler dbus_message_handlers[] = {
+     "",
+     DBUS_TYPE_STRING_AS_STRING,
+     bus_driver_handle_get_id },
++  { "GetConnectionSmackContext",
++    DBUS_TYPE_STRING_AS_STRING,
++    DBUS_TYPE_STRING_AS_STRING,
++    bus_smack_handle_get_connection_context },
+   { NULL, NULL, NULL, NULL }
+ };
+diff --git a/bus/smack.c b/bus/smack.c
+new file mode 100644
+index 0000000..b8542c2
+--- /dev/null
++++ b/bus/smack.c
+@@ -0,0 +1,132 @@
++/* smack.c - Provide interface to query smack context
++ *
++ * Author: Brian McGillion <brian.mcgillion@intel.com>
++ * Copyright Â© 2011 Intel Corporation
++ *
++ * Licensed under the Academic Free License version 2.1
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <config.h>
++#include "smack.h"
++
++#include <dbus/dbus-internals.h>
++
++#include "connection.h"
++#include "services.h"
++#include "utils.h"
++
++#ifdef DBUS_ENABLE_SMACK
++#include <sys/smack.h>
++#endif
++
++#ifdef DBUS_ENABLE_SMACK
++static char *
++bus_smack_get_label (DBusConnection *connection)
++{
++  char *label;
++  int sock_fd;
++
++  if (!dbus_connection_get_socket(connection, &sock_fd))
++    return NULL;
++
++  if (smack_new_label_from_socket(sock_fd, &label) < 0)
++    return NULL;
++  return label;
++}
++#endif
++
++dbus_bool_t
++bus_smack_handle_get_connection_context (DBusConnection *connection,
++                                         BusTransaction *transaction,
++                                         DBusMessage    *message,
++                                         DBusError      *error)
++{
++#ifdef DBUS_ENABLE_SMACK
++  const char *remote_end = NULL;
++  BusRegistry *registry;
++  DBusString remote_end_str;
++  BusService *service;
++  DBusConnection *remote_connection;
++  DBusMessage *reply = NULL;
++  char *label;
++
++  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
++
++  registry = bus_connection_get_registry (connection);
++
++  if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &remote_end,
++                              DBUS_TYPE_INVALID))
++    return FALSE;
++
++  _dbus_verbose ("asked for label of connection %s\n", remote_end);
++
++  _dbus_string_init_const (&remote_end_str, remote_end);
++
++  service = bus_registry_lookup (registry, &remote_end_str);
++  if (service == NULL)
++    {
++      dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
++                      "Bus name '%s' has no owner", remote_end);
++      return FALSE;
++    }
++
++  remote_connection = bus_service_get_primary_owners_connection (service);
++  if (remote_connection == NULL)
++    goto oom;
++
++  reply = dbus_message_new_method_return (message);
++  if (reply == NULL)
++    goto oom;
++
++  label = bus_smack_get_label (remote_connection);
++  if (label == NULL)
++    {
++      dbus_set_error (error, DBUS_ERROR_FAILED,
++                      "Failed to get the socket fd of the connection",
++                      remote_end);
++      goto err;
++    }
++
++  if (!dbus_message_append_args (reply, DBUS_TYPE_STRING,
++                                 &label, DBUS_TYPE_INVALID))
++    goto oom;
++
++  if (!bus_transaction_send_from_driver (transaction, connection, reply))
++    goto oom;
++
++  dbus_message_unref (reply);
++  dbus_free(label);
++
++  return TRUE;
++
++oom:
++  BUS_SET_OOM (error);
++
++err:
++  if (reply != NULL)
++    dbus_message_unref (reply);
++
++  dbus_free(label);
++
++  return FALSE;
++#else
++  dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
++                  "SMACK support is not enabled");
++  return FALSE;
++#endif
++}
+diff --git a/bus/smack.h b/bus/smack.h
+new file mode 100644
+index 0000000..04a4a2a
+--- /dev/null
++++ b/bus/smack.h
+@@ -0,0 +1,36 @@
++/* smack.h - Provide interface to query smack context
++ *
++ * Author: Brian McGillion <brian.mcgillion@intel.com>
++ * Copyright Â© 2011 Intel Corporation
++ *
++ * Based on example from Stats interface
++ *
++ * Licensed under the Academic Free License version 2.1
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef SMACK_H
++#define SMACK_H
++
++#include "bus.h"
++
++dbus_bool_t bus_smack_handle_get_connection_context (DBusConnection *connection,
++                                                     BusTransaction *transaction,
++                                                     DBusMessage    *message,
++                                                     DBusError      *error);
++
++#endif // SMACK_H
+diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
+index 000acda..68b7a9e 100644
+--- a/cmake/CMakeLists.txt
++++ b/cmake/CMakeLists.txt
+@@ -94,6 +94,8 @@ option (DBUS_ENABLE_STATS "enable bus daemon usage statistics" OFF)
+ option (DBUS_ENABLE_STATS "enable bus daemon usage statistics" OFF)
++option (DBUS_ENABLE_SMACK "enable smack checks in the daemon" OFF)
++
+ if (DBUS_USE_EXPAT)
+     find_package(LibExpat)
+ else ()
+@@ -555,6 +557,7 @@ message("        Building bus stats API:   ${DBUS_ENABLE_STATS}                "
+ message("        installing system libs:   ${DBUS_INSTALL_SYSTEM_LIBS}         ")
+ #message("        Building SELinux support: ${have_selinux}                     ")
+ #message("        Building dnotify support: ${have_dnotify}                     ")
++message("        Building Smack support:   ${DBUS_ENABLE_SMACK}                ")
+ message("        Building Doxygen docs:    ${DBUS_ENABLE_DOXYGEN_DOCS}         ")
+ message("        Building XML docs:        ${DBUS_ENABLE_XML_DOCS}             ")
+ #message("        Gettext libs (empty OK):  ${INTLLIBS}                         ")
+diff --git a/cmake/bus/CMakeLists.txt b/cmake/bus/CMakeLists.txt
+index 2657605..13fb34c 100644
+--- a/cmake/bus/CMakeLists.txt
++++ b/cmake/bus/CMakeLists.txt
+@@ -72,7 +72,9 @@ set (BUS_SOURCES
+       ${BUS_DIR}/test.c                                       
+       ${BUS_DIR}/test.h                                       
+       ${BUS_DIR}/utils.c                                      
+-      ${BUS_DIR}/utils.h                                      
++      ${BUS_DIR}/utils.h
++      ${BUS_DIR}/smack.c
++      ${BUS_DIR}/smack.h
+       ${XML_SOURCES}
+       ${DIR_WATCH_SOURCE}
+ )
+diff --git a/configure.ac b/configure.ac
+index a963d4d..95216c5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -207,6 +207,9 @@ if test "x$enable_embedded_tests" = xyes; then
+       [Define to build test code into the library and binaries])
+ fi
++# call early to ensure availability
++PKG_PROG_PKG_CONFIG
++
+ # DBUS_ENABLE_MODULAR_TESTS controls tests that work based on public API.
+ # These use GTest, from GLib, because life's too short. They're enabled by
+ # default (unless you don't have GLib), because they don't bloat the library
+@@ -907,8 +910,6 @@ fi
+ # unix:path=/foo or unix:abstract=/foo
+ AC_SUBST(DBUS_PATH_OR_ABSTRACT)
+-PKG_PROG_PKG_CONFIG
+-
+ #### Sort out XML library
+ # see what we have
+@@ -1703,6 +1704,17 @@ if test "x$enable_stats" = xyes; then
+     [Define to enable bus daemon usage statistics])
+ fi
++#enable smack label support
++AC_ARG_ENABLE([smack], [AS_HELP_STRING([--enable-smack], [enable SMACK security checks])], [], [enable_smack=no])
++if test "x$enable_smack" = xyes; then
++  PKG_CHECK_MODULES([LIBSMACK], [libsmack >= 1.0],
++     [AC_DEFINE([DBUS_ENABLE_SMACK], [1], [Define to enable SMACK security features])],
++     [AC_MSG_ERROR([libsmack is required to enable smack support])])
++fi
++
++AC_SUBST([LIBSMACK_CFLAGS])
++AC_SUBST([LIBSMACK_LIBS])
++
+ AC_CONFIG_FILES([
+ Doxyfile
+ dbus/versioninfo.rc
+@@ -1781,6 +1793,7 @@ echo "
+         Building checks:          ${enable_checks}
+         Building bus stats API:   ${enable_stats}
+         Building SELinux support: ${have_selinux}
++      Building SMACK support:   ${enable_smack}
+         Building inotify support: ${have_inotify}
+         Building dnotify support: ${have_dnotify}
+         Building kqueue support:  ${have_kqueue}
diff --git a/recipes-core/dbus/files/0013-Enforce-smack-policy-from-conf-file.patch b/recipes-core/dbus/files/0013-Enforce-smack-policy-from-conf-file.patch
new file mode 100644 (file)
index 0000000..c54f5af
--- /dev/null
@@ -0,0 +1,481 @@
+From: Brian McGillion <brian.mcgillion@intel.com>
+Date: Mon, 6 Feb 2012 18:48:30 +0200
+Subject: Enforce smack policy from conf file
+
+---
+ bus/config-parser.c |  38 ++++++++++----
+ bus/policy.c        | 141 +++++++++++++++++++++++++++++++++++++++++++++++++---
+ bus/policy.h        |   3 ++
+ bus/smack.c         | 111 +++++++++++++++++++++++++++++++++++++++++
+ bus/smack.h         |   4 ++
+ 5 files changed, 278 insertions(+), 19 deletions(-)
+
+diff --git a/bus/config-parser.c b/bus/config-parser.c
+index 07e8fbb..d7ba549 100644
+--- a/bus/config-parser.c
++++ b/bus/config-parser.c
+@@ -43,6 +43,7 @@ typedef enum
+   POLICY_MANDATORY,
+   POLICY_USER,
+   POLICY_GROUP,
++  POLICY_SMACK,
+   POLICY_CONSOLE
+ } PolicyType;
+@@ -64,7 +65,11 @@ typedef struct
+     struct
+     {
+       PolicyType type;
+-      unsigned long gid_uid_or_at_console;      
++      union
++      {
++        unsigned long gid_uid_or_at_console;
++        char *smack_label;
++      };
+     } policy;
+     struct
+@@ -150,6 +155,8 @@ element_free (Element *e)
+ {
+   if (e->type == ELEMENT_LIMIT)
+     dbus_free (e->d.limit.name);
++  else if (e->type == ELEMENT_POLICY && e->d.policy.type == POLICY_SMACK)
++      dbus_free (e->d.policy.smack_label);
+   
+   dbus_free (e);
+ }
+@@ -972,6 +979,7 @@ start_busconfig_child (BusConfigParser   *parser,
+       const char *user;
+       const char *group;
+       const char *at_console;
++      const char *smack;
+       if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
+         {
+@@ -988,20 +996,16 @@ start_busconfig_child (BusConfigParser   *parser,
+                               "context", &context,
+                               "user", &user,
+                               "group", &group,
++                              "smack", &smack,
+                               "at_console", &at_console,
+                               NULL))
+         return FALSE;
+-      if (((context && user) ||
+-           (context && group) ||
+-           (context && at_console)) ||
+-           ((user && group) ||
+-           (user && at_console)) ||
+-           (group && at_console) ||
+-          !(context || user || group || at_console))
++      if (((context != NULL) + (user != NULL) + (group != NULL) +
++          (smack != NULL) + (at_console != NULL)) != 1)
+         {
+           dbus_set_error (error, DBUS_ERROR_FAILED,
+-                          "<policy> element must have exactly one of (context|user|group|at_console) attributes");
++                          "<policy> element must have exactly one of (context|user|group|smack|at_console) attributes");
+           return FALSE;
+         }
+@@ -1047,6 +1051,16 @@ start_busconfig_child (BusConfigParser   *parser,
+             _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
+                         group);          
+         }
++      else if (smack != NULL)
++        {
++          e->d.policy.type = POLICY_SMACK;
++          e->d.policy.smack_label = _dbus_strdup (smack);
++          if (e->d.policy.smack_label == NULL)
++            {
++              BUS_SET_OOM (error);
++              return FALSE;
++            }
++        }
+       else if (at_console != NULL)
+         {
+            dbus_bool_t t;
+@@ -1631,8 +1645,10 @@ append_rule_from_element (BusConfigParser   *parser,
+                                              rule))
+             goto nomem;
+           break;
+-        
+-
++        case POLICY_SMACK:
++          if (!bus_policy_append_smack_rule (parser->policy, pe->d.policy.smack_label, rule))
++            goto nomem;
++          break;
+         case POLICY_CONSOLE:
+           if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
+                                                rule))
+diff --git a/bus/policy.c b/bus/policy.c
+index 379cea9..836354a 100644
+--- a/bus/policy.c
++++ b/bus/policy.c
+@@ -26,6 +26,7 @@
+ #include "services.h"
+ #include "test.h"
+ #include "utils.h"
++#include "smack.h"
+ #include <dbus/dbus-list.h>
+ #include <dbus/dbus-hash.h>
+ #include <dbus/dbus-internals.h>
+@@ -126,12 +127,13 @@ struct BusPolicy
+ {
+   int refcount;
+-  DBusList *default_rules;         /**< Default policy rules */
+-  DBusList *mandatory_rules;       /**< Mandatory policy rules */
+-  DBusHashTable *rules_by_uid;     /**< per-UID policy rules */
+-  DBusHashTable *rules_by_gid;     /**< per-GID policy rules */
+-  DBusList *at_console_true_rules; /**< console user policy rules where at_console="true"*/
+-  DBusList *at_console_false_rules; /**< console user policy rules where at_console="false"*/
++  DBusList *default_rules;             /**< Default policy rules */
++  DBusList *mandatory_rules;           /**< Mandatory policy rules */
++  DBusHashTable *rules_by_uid;         /**< per-UID policy rules */
++  DBusHashTable *rules_by_gid;         /**< per-GID policy rules */
++  DBusHashTable *rules_by_smack_label; /**< per-SMACK label policy rules */
++  DBusList *at_console_true_rules;     /**< console user policy rules where at_console="true"*/
++  DBusList *at_console_false_rules;    /**< console user policy rules where at_console="false"*/
+ };
+ static void
+@@ -181,6 +183,14 @@ bus_policy_new (void)
+   if (policy->rules_by_gid == NULL)
+     goto failed;
++#ifdef DBUS_ENABLE_SMACK
++  policy->rules_by_smack_label = _dbus_hash_table_new (DBUS_HASH_STRING,
++                                                       (DBusFreeFunction) dbus_free,
++                                                       free_rule_list_func);
++  if (policy->rules_by_smack_label == NULL)
++    goto failed;
++#endif
++
+   return policy;
+   
+  failed:
+@@ -230,7 +240,13 @@ bus_policy_unref (BusPolicy *policy)
+           _dbus_hash_table_unref (policy->rules_by_gid);
+           policy->rules_by_gid = NULL;
+         }
+-      
++
++      if (policy->rules_by_smack_label)
++        {
++          _dbus_hash_table_unref (policy->rules_by_smack_label);
++          policy->rules_by_smack_label = NULL;
++        }
++
+       dbus_free (policy);
+     }
+ }
+@@ -356,6 +372,24 @@ bus_policy_create_client_policy (BusPolicy      *policy,
+         }
+     }
++  if (policy->rules_by_smack_label &&
++      _dbus_hash_table_get_n_entries (policy->rules_by_smack_label) > 0)
++    {
++      DBusList **list;
++      dbus_bool_t nomem_err = FALSE;
++
++      list = bus_smack_generate_allowed_list(connection, policy->rules_by_smack_label, &nomem_err);
++
++      if (list != NULL)
++        {
++          nomem_err = !add_list_to_client (list, client);
++          _dbus_list_clear (list);
++        }
++
++      if (nomem_err)
++        goto nomem;
++    }
++
+   if (!add_list_to_client (&policy->mandatory_rules,
+                            client))
+     goto nomem;
+@@ -576,6 +610,66 @@ bus_policy_append_group_rule (BusPolicy      *policy,
+   return TRUE;
+ }
++#ifdef DBUS_ENABLE_SMACK
++static DBusList **
++get_list_string (DBusHashTable *table,
++                 const char *key)
++{
++  DBusList **list;
++
++  if (key == NULL)
++      return NULL;
++
++  list = _dbus_hash_table_lookup_string (table, key);
++
++  if (list == NULL)
++    {
++      char *new_key;
++
++      list = dbus_new0 (DBusList*, 1);
++      if (list == NULL)
++        return NULL;
++
++      new_key = _dbus_strdup (key);
++      if (new_key == NULL)
++        {
++          dbus_free (list);
++          return NULL;
++        }
++
++      if (!_dbus_hash_table_insert_string (table, new_key, list))
++        {
++          dbus_free (list);
++          dbus_free (new_key);
++          return NULL;
++        }
++    }
++
++  return list;
++}
++#endif
++
++dbus_bool_t
++bus_policy_append_smack_rule (BusPolicy      *policy,
++                              const char     *label,
++                              BusPolicyRule  *rule)
++{
++#ifdef DBUS_ENABLE_SMACK
++  DBusList **list;
++
++  list = get_list_string (policy->rules_by_smack_label, label);
++  if (list == NULL)
++    return FALSE;
++
++  if (!_dbus_list_append (list, rule))
++    return FALSE;
++
++  bus_policy_rule_ref (rule);
++#endif
++
++  return TRUE;
++}
++
+ dbus_bool_t
+ bus_policy_append_console_rule (BusPolicy      *policy,
+                                 dbus_bool_t     at_console,
+@@ -653,6 +747,31 @@ merge_id_hash (DBusHashTable *dest,
+   return TRUE;
+ }
++#ifdef DBUS_ENABLE_SMACK
++static dbus_bool_t
++merge_string_hash (DBusHashTable *dest,
++                   DBusHashTable *to_absorb)
++{
++  DBusHashIter iter;
++
++  _dbus_hash_iter_init (to_absorb, &iter);
++  while (_dbus_hash_iter_next (&iter))
++    {
++      const char *absorb_label = _dbus_hash_iter_get_string_key(&iter);
++      DBusList **list = _dbus_hash_iter_get_value (&iter);
++      DBusList **target = get_list_string (dest, absorb_label);
++
++      if (target == NULL)
++        return FALSE;
++
++      if (!append_copy_of_policy_list (target, list))
++        return FALSE;
++    }
++
++  return TRUE;
++}
++#endif
++
+ dbus_bool_t
+ bus_policy_merge (BusPolicy *policy,
+                   BusPolicy *to_absorb)
+@@ -685,6 +804,12 @@ bus_policy_merge (BusPolicy *policy,
+                       to_absorb->rules_by_gid))
+     return FALSE;
++#ifdef DBUS_ENABLE_SMACK
++  if (!merge_string_hash (policy->rules_by_smack_label,
++                          to_absorb->rules_by_smack_label))
++    return FALSE;
++#endif
++
+   return TRUE;
+ }
+@@ -873,7 +998,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
+ {
+   DBusList *link;
+   dbus_bool_t allowed;
+-  
++
+   /* policy->rules is in the order the rules appeared
+    * in the config file, i.e. last rule that applies wins
+    */
+diff --git a/bus/policy.h b/bus/policy.h
+index 3ff6f48..20d0a39 100644
+--- a/bus/policy.h
++++ b/bus/policy.h
+@@ -130,6 +130,9 @@ dbus_bool_t      bus_policy_append_user_rule      (BusPolicy        *policy,
+ dbus_bool_t      bus_policy_append_group_rule     (BusPolicy        *policy,
+                                                    dbus_gid_t        gid,
+                                                    BusPolicyRule    *rule);
++dbus_bool_t      bus_policy_append_smack_rule     (BusPolicy        *policy,
++                                                   const char       *label,
++                                                   BusPolicyRule    *rule);
+ dbus_bool_t      bus_policy_append_console_rule   (BusPolicy        *policy,
+                                                    dbus_bool_t        at_console,
+                                                    BusPolicyRule    *rule);
+diff --git a/bus/smack.c b/bus/smack.c
+index b8542c2..d4546a3 100644
+--- a/bus/smack.c
++++ b/bus/smack.c
+@@ -29,11 +29,17 @@
+ #include "connection.h"
+ #include "services.h"
+ #include "utils.h"
++#include "policy.h"
+ #ifdef DBUS_ENABLE_SMACK
+ #include <sys/smack.h>
+ #endif
++#define SMACK_WRITE "W"
++#define SMACK_READ "R"
++#define SMACK_READ_WRITE "RW"
++
++
+ #ifdef DBUS_ENABLE_SMACK
+ static char *
+ bus_smack_get_label (DBusConnection *connection)
+@@ -130,3 +136,108 @@ err:
+   return FALSE;
+ #endif
+ }
++
++#ifdef DBUS_ENABLE_SMACK
++static dbus_bool_t
++bus_smack_has_access (const char *subject, const char *object,
++                      const char *access)
++{
++  return (smack_have_access (subject, object, access) == 1 ? TRUE : FALSE);
++}
++#endif
++
++
++/**
++ * Calculate the list of rules that apply to a connection.
++ *
++ * @param connection The inbound conenction
++ * @param rules_by_smack_label The table of object labels -> rules mapping
++ * @param nomem_err (out) If a nomem situation is encountered this value is set to TRUE.
++ * @returns the list of permitted rules if it exists and no errors were encountered otherwise NULL.
++ */
++DBusList**
++bus_smack_generate_allowed_list (DBusConnection *connection,
++                                 DBusHashTable  *rules_by_smack_label,
++                                 dbus_bool_t *nomem_err)
++{
++#ifdef DBUS_ENABLE_SMACK
++  char *subject_label;
++  DBusHashIter iter;
++  dbus_bool_t is_allowed;
++  DBusList **allowed_list;
++
++  /* the label of the subject, is the label on the new connection,
++     either the service itself or one of its clients */
++  subject_label = bus_smack_get_label (connection);
++  if (subject_label == NULL)
++    return NULL;
++
++  allowed_list = dbus_new0 (DBusList*, 1);
++  if (allowed_list == NULL)
++    goto nomem;
++
++  /* Iterate over all the smack labels we have parsed from the .conf files */
++  _dbus_hash_iter_init (rules_by_smack_label, &iter);
++  while (_dbus_hash_iter_next (&iter))
++    {
++      DBusList *link;
++      const char *object_label = _dbus_hash_iter_get_string_key (&iter);
++      /* the list here is all the rules that are 'protected'
++         by the SMACK label named $object_label */
++      DBusList **list = _dbus_hash_iter_get_value (&iter);
++
++      link = _dbus_list_get_first_link (list);
++      while (link != NULL)
++        {
++          BusPolicyRule *rule = link->data;
++          link = _dbus_list_get_next_link (list, link);
++          is_allowed = FALSE;
++
++          switch (rule->type)
++            {
++            case BUS_POLICY_RULE_OWN:
++              is_allowed = bus_smack_has_access (subject_label,
++                                                 object_label,
++                                                 SMACK_READ_WRITE);
++              break;
++            case BUS_POLICY_RULE_SEND:
++              is_allowed = bus_smack_has_access (subject_label,
++                                                 object_label,
++                                                 SMACK_WRITE);
++              break;
++            case BUS_POLICY_RULE_RECEIVE:
++              is_allowed = bus_smack_has_access (subject_label,
++                                                 object_label,
++                                                 SMACK_READ);
++              break;
++            default:
++              continue;
++            }
++
++          if (is_allowed)
++            {
++              if (!_dbus_list_append (allowed_list, rule))
++                goto nomem;
++
++              bus_policy_rule_ref (rule);
++            }
++
++          _dbus_verbose ("permission request subject (%s) -> object (%s) : %s", subject_label, object_label, (is_allowed ? "GRANTED" : "REJECTED"));
++        }
++    }
++
++  dbus_free(subject_label);
++  return allowed_list;
++
++nomem:
++  if (allowed_list != NULL)
++    _dbus_list_clear (allowed_list);
++
++  dbus_free(subject_label);
++  *nomem_err = TRUE;
++  return NULL;
++
++#else
++  return NULL;
++#endif
++}
+diff --git a/bus/smack.h b/bus/smack.h
+index 04a4a2a..6b1dfad 100644
+--- a/bus/smack.h
++++ b/bus/smack.h
+@@ -27,10 +27,14 @@
+ #define SMACK_H
+ #include "bus.h"
++#include <dbus/dbus-hash.h>
+ dbus_bool_t bus_smack_handle_get_connection_context (DBusConnection *connection,
+                                                      BusTransaction *transaction,
+                                                      DBusMessage    *message,
+                                                      DBusError      *error);
++DBusList **bus_smack_generate_allowed_list (DBusConnection *connection,
++                                            DBusHashTable *label_rules,
++                                            dbus_bool_t *error);
+ #endif // SMACK_H