/* * 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; using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; namespace Tizen.NUI { /// /// This is used to store a mapping between C++ base handle objects and it's C# instances. /// /// internal sealed class Registry { private static readonly Registry registry = new Registry(); /// /// static initialization singleton /// internal static Registry Instance { get { return registry; } } /// /// 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. /// private ConcurrentDictionary _controlMap; private Registry() { _controlMap = new ConcurrentDictionary(); } /// /// Stores the mapping between this instance of BaseHandle (C# base class) and native part. /// /// The instance of BaseHandle (C# base class). internal static void Register(BaseHandle baseHandle) { // We store a pointer to the RefObject for the control RefObject refObj = baseHandle.GetObjectPtr(); IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj); RegistryCurrentThreadCheck(); if (Instance._controlMap.TryAdd(refCptr, new WeakReference(baseHandle, false)) != true) { NUILog.Debug("refCptr is already exist! OR something wrong!"); } return; } /// /// Removes this instance of BaseHandle (C# base class) and native part from the mapping table. /// /// The instance of BaseHandle (C# base class) internal static void Unregister(BaseHandle baseHandle) { RefObject refObj = baseHandle.GetObjectPtr(); IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj); RegistryCurrentThreadCheck(); WeakReference refe; if (Instance._controlMap.TryRemove(refCptr, out refe) != true) { NUILog.Debug("something wrong when removing refCptr!"); } return; } internal static BaseHandle GetManagedBaseHandleFromNativePtr(BaseHandle baseHandle) { RefObject refObj = baseHandle.GetObjectPtr(); IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj); // we store a dictionary of ref-obects (C++ land) to managed obects (C# land) return GetManagedBaseHandleFromRefObject(refObjectPtr); } internal static BaseHandle GetManagedBaseHandleFromNativePtr(IntPtr cPtr) { IntPtr refObjectPtr = Interop.RefObject.GetRefObjectPtr(cPtr); // we store a dictionary of ref-obects (C++ land) to managed obects (C# land) return GetManagedBaseHandleFromRefObject(refObjectPtr); } 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; } else { return null; } } 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\n"); 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!"); } } } }