[NUI] Fix widget application crash issue (#175)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Registry.cs
index d9e0ee0..d51aca4 100755 (executable)
@@ -1,9 +1,23 @@
+/*
+ * Copyright(c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
 
-using System.Reflection;
 using System;
-using System.Runtime.InteropServices;
-using System.Collections.Generic;
-using Tizen.NUI.BaseComponents;
+using System.Collections.Concurrent;
+using System.Threading;
 
 namespace Tizen.NUI
 {
@@ -13,20 +27,25 @@ namespace Tizen.NUI
     /// </summary>
     internal sealed class Registry
     {
+        private static readonly Registry registry = new Registry();
+
         /// <summary>
-        /// The registry is a singleton.
+        /// static initialization singleton
         /// </summary>
-        private static Registry instance = null;
+        internal static Registry Instance
+        {
+            get { return registry; }
+        }
 
         /// <summary>
         /// Given a C++ object, the dictionary allows us to find which C# object it belongs to.
         /// By keeping the weak reference only, it will allow the object to be garbage collected.
         /// </summary>
-        private Dictionary<IntPtr, WeakReference> _controlMap;
+        private ConcurrentDictionary<IntPtr, WeakReference> _controlMap;
 
         private Registry()
         {
-            _controlMap = new Dictionary<IntPtr, WeakReference>();
+            _controlMap = new ConcurrentDictionary<IntPtr, WeakReference>();
         }
 
 
@@ -40,11 +59,11 @@ namespace Tizen.NUI
             RefObject refObj = baseHandle.GetObjectPtr();
             IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
 
-            NUILog.Debug("________Storing ref object cptr in control map Hex: {0:X}" + refCptr);
+            RegistryCurrentThreadCheck();
 
-            if (!Instance._controlMap.ContainsKey(refCptr))
+            if(Instance._controlMap.TryAdd(refCptr, new WeakReference(baseHandle, false)) != true)
             {
-                Instance._controlMap.Add(refCptr, new WeakReference(baseHandle, false));
+                NUILog.Debug("refCptr is already exist! OR something wrong!");
             }
 
             return;
@@ -59,26 +78,17 @@ namespace Tizen.NUI
             RefObject refObj = baseHandle.GetObjectPtr();
             IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
 
-            if (Instance._controlMap.ContainsKey(refCptr))
+            RegistryCurrentThreadCheck();
+
+            WeakReference removeTarget;
+            if(Instance._controlMap.TryRemove(refCptr, out removeTarget) != true)
             {
-                Instance._controlMap.Remove(refCptr);
+                NUILog.Debug("something wrong when removing refCptr!");
             }
 
             return;
         }
 
-        private static Registry Instance
-        {
-            get
-            {
-                if (instance == null)
-                {
-                    instance = new Registry();
-                }
-                return instance;
-            }
-        }
-
         internal static BaseHandle GetManagedBaseHandleFromNativePtr(BaseHandle baseHandle)
         {
             RefObject refObj = baseHandle.GetObjectPtr();
@@ -98,11 +108,28 @@ namespace Tizen.NUI
 
         internal static BaseHandle GetManagedBaseHandleFromRefObject(IntPtr refObjectPtr)
         {
+            if (refObjectPtr == global::System.IntPtr.Zero)
+            {
+                NUILog.Debug("Registry refObjectPtr is NULL! This means bind native object is NULL!");
+                return null;
+            }
+            else
+            {
+                NUILog.Debug($"refObjectPtr=0x{refObjectPtr.ToInt64():X}");
+            }
+
+            RegistryCurrentThreadCheck();
+
             // we store a dictionary of ref-obects (C++ land) to managed obects (C# land)
             WeakReference weakReference;
 
             if (Instance._controlMap.TryGetValue(refObjectPtr, out weakReference))
             {
+                if(weakReference == null)
+                {
+                    throw new System.InvalidOperationException("Error! NUI Registry weakReference should not be NULL!");
+                }
+
                 BaseHandle ret = weakReference.Target as BaseHandle;
                 return ret;
             }
@@ -112,5 +139,35 @@ namespace Tizen.NUI
             }
         }
 
+        private static Thread savedApplicationThread;
+        internal Thread SavedApplicationThread
+        {
+            get
+            {
+                return savedApplicationThread;
+            }
+            set
+            {
+                savedApplicationThread = value;
+            }
+        }
+
+        private static void RegistryCurrentThreadCheck()
+        {
+            if(savedApplicationThread == null)
+            {
+                Tizen.Log.Fatal("NUI", $"Error! maybe main thread is created by other process ");
+                return;
+            }
+            int currentId = Thread.CurrentThread.ManagedThreadId;
+            int mainThreadId = savedApplicationThread.ManagedThreadId;
+
+            if(currentId != mainThreadId)
+            {
+                Tizen.Log.Fatal("NUI", $"Error! current thread({currentId}) which is NOT main thread({mainThreadId}) utilizes NUI object!");
+            }
+        }
+
+
     }
 }