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

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