[NUI] Unregister disposed / disposequeued BaseHandle and register again if need
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 31 May 2024 01:44:27 +0000 (10:44 +0900)
committerEunki Hong <h.pichulia@gmail.com>
Tue, 11 Jun 2024 10:37:05 +0000 (19:37 +0900)
It is possible that dispose queued basehandle try to get / register again
due to some reason. Like, Native side object is alived but C# side has no reference.

We already to to detect that cases. But if BaseHandle added at DisposeQueue,
we cannot avoid to call the Dispose(); after some event loops later, and then
Unregister the handle.

To avoid some error cases, let we Unregister the basehandle synchronously
and then re-register base on the new BaseHandle.

Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
src/Tizen.NUI/src/internal/Common/Registry.cs

index 031ea14a85ec7c3fff943edf379db53760d064d6..cc872b65e1efeb81233fbe921200b0da84be2da2 100755 (executable)
@@ -82,13 +82,13 @@ namespace Tizen.NUI
                     var target = weakReference.Target;
 
                     BaseHandle ret = target as BaseHandle;
-                    if ((ret == null) || ret.Disposed || ret.IsDisposeQueued)
+                    // Note : Do not use ret == null because BaseHandle override operator ==.
+                    if ((ret?.Disposed ?? true) || (ret?.IsDisposeQueued ?? true))
                     {
-                        // Special case. If WeakReference.Target is null or it might be disposed by GC, just remove previous item forcibly.
-                        if (Instance._controlMap.TryRemove(refCptr, out weakReference) != true)
-                        {
-                            Tizen.Log.Error("NUI", $"Something Wrong when we try to remove null target! input type:{baseHandle.GetType()}, registed type:{target?.GetType()}\n");
-                        }
+                        // Special case. If WeakReference.Target is null or disposed by GC,
+                        // Unregister forcibly first. and then try to add again.
+                        ret?.UnregisterFromRegistry();
+
                         if (Instance._controlMap.TryAdd(refCptr, new WeakReference(baseHandle, true)) != true)
                         {
                             Tizen.Log.Error("NUI", $"Something Wrong when we try to replace null target! input type:{baseHandle.GetType()}, registed type:{target?.GetType()}\n");
@@ -120,7 +120,7 @@ namespace Tizen.NUI
                 }
             }
 
-            NUILog.Debug($"[Registry] Register! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} copyNativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
+            NUILog.Debug($"[Registry] Register! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} refCptr=0x{refCptr.ToInt64():X} NativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
             return true;
         }
 
@@ -139,7 +139,7 @@ namespace Tizen.NUI
                 Tizen.Log.Error("NUI", $"something wrong when removing refCptr!\n");
             }
 
-            NUILog.Debug($"[Registry] Unregister! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} copyNativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
+            NUILog.Debug($"[Registry] Unregister! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} refCptr=0x{refCptr.ToInt64():X} NativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
             return;
         }
 
@@ -164,7 +164,7 @@ namespace Tizen.NUI
             if (refObjectPtr == global::System.IntPtr.Zero)
             {
                 NUILog.Debug("Registry refObjectPtr is NULL! This means bind native object is NULL!");
-                //return null;
+                return null;
             }
             else
             {
@@ -184,9 +184,12 @@ namespace Tizen.NUI
                 }
 
                 BaseHandle ret = weakReference.Target as BaseHandle;
-                if ((ret == null) || ret.Disposed || ret.IsDisposeQueued)
+                // Note : Do not use ret == null because BaseHandle override operator ==.
+                if ((ret?.Disposed ?? true) || (ret?.IsDisposeQueued ?? true))
                 {
-                    // Special case. If WeakReference.Target is null or disposed by GC, just return null.
+                    // Special case. If WeakReference.Target is null or disposed by GC,
+                    // Unregister first. and then return null.
+                    ret?.UnregisterFromRegistry();
                     return null;
                 }
                 return ret;