Blame SOURCES/0001-IntrospectionModule-handle-two-threads-loading-type-.patch

d613a8
From eb791e7cca0998bc75e0b3f7e8ecf2672c96d7f8 Mon Sep 17 00:00:00 2001
d613a8
From: Ray Strode <rstrode@redhat.com>
d613a8
Date: Wed, 10 Jun 2020 18:04:07 -0400
d613a8
Subject: [PATCH] IntrospectionModule: handle two threads loading type at same
d613a8
 time
d613a8
d613a8
If two threads are trying to load a type at exactly the same time,
d613a8
it's possible for two wrappers to get generated for the type.
d613a8
One thread will end up with the wrapper that's not blessed as the
d613a8
"real" one and future calls will fail.  The blessed wrapper will
d613a8
be incomplete, and so future calls from it will fail as well.
d613a8
d613a8
This commit adds a lock to ensure the two threads don't stomp
d613a8
on each others toes.
d613a8
---
d613a8
 gi/module.py | 110 +++++++++++++++++++++++++++------------------------
d613a8
 1 file changed, 58 insertions(+), 52 deletions(-)
d613a8
d613a8
--- a/gi/module.py	2020-06-10 18:09:19.292409072 -0400
d613a8
+++ b/gi/module.py	2020-06-10 18:11:24.727045466 -0400
d613a8
@@ -24,6 +24,7 @@ from __future__ import absolute_import
d613a8
 
d613a8
 import sys
d613a8
 import importlib
d613a8
+from threading import Lock
d613a8
 
d613a8
 _have_py3 = (sys.version_info[0] >= 3)
d613a8
 
d613a8
@@ -131,6 +132,8 @@ class IntrospectionModule(object):
d613a8
         if self._version is None:
d613a8
             self._version = repository.get_version(self._namespace)
d613a8
 
d613a8
+        self._lock = Lock()
d613a8
+
d613a8
     def __getattr__(self, name):
d613a8
         info = repository.find_by_name(self._namespace, name)
d613a8
         if not info:
d613a8
@@ -139,39 +142,40 @@ class IntrospectionModule(object):
d613a8
 
d613a8
         if isinstance(info, EnumInfo):
d613a8
             g_type = info.get_g_type()
d613a8
-            wrapper = g_type.pytype
d613a8
+            with self._lock:
d613a8
+                wrapper = g_type.pytype
d613a8
 
d613a8
-            if wrapper is None:
d613a8
-                if info.is_flags():
d613a8
-                    if g_type.is_a(TYPE_FLAGS):
d613a8
-                        wrapper = flags_add(g_type)
d613a8
-                    else:
d613a8
-                        assert g_type == TYPE_NONE
d613a8
-                        wrapper = flags_register_new_gtype_and_add(info)
d613a8
-                else:
d613a8
-                    if g_type.is_a(TYPE_ENUM):
d613a8
-                        wrapper = enum_add(g_type)
d613a8
+                if wrapper is None:
d613a8
+                    if info.is_flags():
d613a8
+                        if g_type.is_a(TYPE_FLAGS):
d613a8
+                            wrapper = flags_add(g_type)
d613a8
+                        else:
d613a8
+                            assert g_type == TYPE_NONE
d613a8
+                            wrapper = flags_register_new_gtype_and_add(info)
d613a8
                     else:
d613a8
-                        assert g_type == TYPE_NONE
d613a8
-                        wrapper = enum_register_new_gtype_and_add(info)
d613a8
-
d613a8
-                wrapper.__info__ = info
d613a8
-                wrapper.__module__ = 'gi.repository.' + info.get_namespace()
d613a8
-
d613a8
-                # Don't use upper() here to avoid locale specific
d613a8
-                # identifier conversion (e. g. in Turkish 'i'.upper() == 'i')
d613a8
-                # see https://bugzilla.gnome.org/show_bug.cgi?id=649165
d613a8
-                ascii_upper_trans = maketrans(
d613a8
-                    'abcdefgjhijklmnopqrstuvwxyz',
d613a8
-                    'ABCDEFGJHIJKLMNOPQRSTUVWXYZ')
d613a8
-                for value_info in info.get_values():
d613a8
-                    value_name = value_info.get_name_unescaped().translate(ascii_upper_trans)
d613a8
-                    setattr(wrapper, value_name, wrapper(value_info.get_value()))
d613a8
-                for method_info in info.get_methods():
d613a8
-                    setattr(wrapper, method_info.__name__, method_info)
d613a8
+                        if g_type.is_a(TYPE_ENUM):
d613a8
+                            wrapper = enum_add(g_type)
d613a8
+                        else:
d613a8
+                            assert g_type == TYPE_NONE
d613a8
+                            wrapper = enum_register_new_gtype_and_add(info)
d613a8
+
d613a8
+                    wrapper.__info__ = info
d613a8
+                    wrapper.__module__ = 'gi.repository.' + info.get_namespace()
d613a8
+
d613a8
+                    # Don't use upper() here to avoid locale specific
d613a8
+                    # identifier conversion (e. g. in Turkish 'i'.upper() == 'i')
d613a8
+                    # see https://bugzilla.gnome.org/show_bug.cgi?id=649165
d613a8
+                    ascii_upper_trans = maketrans(
d613a8
+                        'abcdefgjhijklmnopqrstuvwxyz',
d613a8
+                        'ABCDEFGJHIJKLMNOPQRSTUVWXYZ')
d613a8
+                    for value_info in info.get_values():
d613a8
+                        value_name = value_info.get_name_unescaped().translate(ascii_upper_trans)
d613a8
+                        setattr(wrapper, value_name, wrapper(value_info.get_value()))
d613a8
+                    for method_info in info.get_methods():
d613a8
+                        setattr(wrapper, method_info.__name__, method_info)
d613a8
 
d613a8
-            if g_type != TYPE_NONE:
d613a8
-                g_type.pytype = wrapper
d613a8
+                if g_type != TYPE_NONE:
d613a8
+                    g_type.pytype = wrapper
d613a8
 
d613a8
         elif isinstance(info, RegisteredTypeInfo):
d613a8
             g_type = info.get_g_type()
d613a8
@@ -202,27 +206,28 @@ class IntrospectionModule(object):
d613a8
             else:
d613a8
                 raise NotImplementedError(info)
d613a8
 
d613a8
-            # Check if there is already a Python wrapper that is not a parent class
d613a8
-            # of the wrapper being created. If it is a parent, it is ok to clobber
d613a8
-            # g_type.pytype with a new child class wrapper of the existing parent.
d613a8
-            # Note that the return here never occurs under normal circumstances due
d613a8
-            # to caching on the __dict__ itself.
d613a8
-            if g_type != TYPE_NONE:
d613a8
-                type_ = g_type.pytype
d613a8
-                if type_ is not None and type_ not in bases:
d613a8
-                    self.__dict__[name] = type_
d613a8
-                    return type_
d613a8
-
d613a8
-            dict_ = {
d613a8
-                '__info__': info,
d613a8
-                '__module__': 'gi.repository.' + self._namespace,
d613a8
-                '__gtype__': g_type
d613a8
-            }
d613a8
-            wrapper = metaclass(name, bases, dict_)
d613a8
-
d613a8
-            # Register the new Python wrapper.
d613a8
-            if g_type != TYPE_NONE:
d613a8
-                g_type.pytype = wrapper
d613a8
+            with self._lock:
d613a8
+                # Check if there is already a Python wrapper that is not a parent class
d613a8
+                # of the wrapper being created. If it is a parent, it is ok to clobber
d613a8
+                # g_type.pytype with a new child class wrapper of the existing parent.
d613a8
+                # Note that the return here never occurs under normal circumstances due
d613a8
+                # to caching on the __dict__ itself.
d613a8
+                if g_type != TYPE_NONE:
d613a8
+                    type_ = g_type.pytype
d613a8
+                    if type_ is not None and type_ not in bases:
d613a8
+                        self.__dict__[name] = type_
d613a8
+                        return type_
d613a8
+
d613a8
+                dict_ = {
d613a8
+                    '__info__': info,
d613a8
+                    '__module__': 'gi.repository.' + self._namespace,
d613a8
+                    '__gtype__': g_type
d613a8
+                }
d613a8
+                wrapper = metaclass(name, bases, dict_)
d613a8
+
d613a8
+                # Register the new Python wrapper.
d613a8
+                if g_type != TYPE_NONE:
d613a8
+                    g_type.pytype = wrapper
d613a8
 
d613a8
         elif isinstance(info, FunctionInfo):
d613a8
             wrapper = info