d51aca4427e29370d91f9b8108162130f7271d74
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Registry.cs
1 /*
2  * Copyright(c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Collections.Concurrent;
20 using System.Threading;
21
22 namespace Tizen.NUI
23 {
24     /// <summary>
25     /// This is used to store a mapping between C++ base handle objects and it's C# instances.
26     ///
27     /// </summary>
28     internal sealed class Registry
29     {
30         private static readonly Registry registry = new Registry();
31
32         /// <summary>
33         /// static initialization singleton
34         /// </summary>
35         internal static Registry Instance
36         {
37             get { return registry; }
38         }
39
40         /// <summary>
41         /// Given a C++ object, the dictionary allows us to find which C# object it belongs to.
42         /// By keeping the weak reference only, it will allow the object to be garbage collected.
43         /// </summary>
44         private ConcurrentDictionary<IntPtr, WeakReference> _controlMap;
45
46         private Registry()
47         {
48             _controlMap = new ConcurrentDictionary<IntPtr, WeakReference>();
49         }
50
51
52         /// <summary>
53         /// Stores the mapping between this instance of BaseHandle (C# base class) and native part.
54         /// </summary>
55         /// <param name="baseHandle">The instance of BaseHandle (C# base class).</param>
56         internal static void Register(BaseHandle baseHandle)
57         {
58             // We store a pointer to the RefObject for the control
59             RefObject refObj = baseHandle.GetObjectPtr();
60             IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
61
62             RegistryCurrentThreadCheck();
63
64             if(Instance._controlMap.TryAdd(refCptr, new WeakReference(baseHandle, false)) != true)
65             {
66                 NUILog.Debug("refCptr is already exist! OR something wrong!");
67             }
68
69             return;
70         }
71
72         /// <summary>
73         /// Removes this instance of BaseHandle (C# base class) and native part from the mapping table.
74         /// </summary>
75         /// <param name="baseHandle"> The instance of BaseHandle (C# base class)</param>
76         internal static void Unregister(BaseHandle baseHandle)
77         {
78             RefObject refObj = baseHandle.GetObjectPtr();
79             IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
80
81             RegistryCurrentThreadCheck();
82
83             WeakReference removeTarget;
84             if(Instance._controlMap.TryRemove(refCptr, out removeTarget) != true)
85             {
86                 NUILog.Debug("something wrong when removing refCptr!");
87             }
88
89             return;
90         }
91
92         internal static BaseHandle GetManagedBaseHandleFromNativePtr(BaseHandle baseHandle)
93         {
94             RefObject refObj = baseHandle.GetObjectPtr();
95             IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
96
97             // we store a dictionary of ref-obects (C++ land) to managed obects (C# land)
98             return GetManagedBaseHandleFromRefObject(refObjectPtr);
99         }
100
101         internal static BaseHandle GetManagedBaseHandleFromNativePtr(IntPtr cPtr)
102         {
103             IntPtr refObjectPtr = NDalicPINVOKE.GetRefObjectPtr(cPtr);
104
105             // we store a dictionary of ref-obects (C++ land) to managed obects (C# land)
106             return GetManagedBaseHandleFromRefObject(refObjectPtr);
107         }
108
109         internal static BaseHandle GetManagedBaseHandleFromRefObject(IntPtr refObjectPtr)
110         {
111             if (refObjectPtr == global::System.IntPtr.Zero)
112             {
113                 NUILog.Debug("Registry refObjectPtr is NULL! This means bind native object is NULL!");
114                 return null;
115             }
116             else
117             {
118                 NUILog.Debug($"refObjectPtr=0x{refObjectPtr.ToInt64():X}");
119             }
120
121             RegistryCurrentThreadCheck();
122
123             // we store a dictionary of ref-obects (C++ land) to managed obects (C# land)
124             WeakReference weakReference;
125
126             if (Instance._controlMap.TryGetValue(refObjectPtr, out weakReference))
127             {
128                 if(weakReference == null)
129                 {
130                     throw new System.InvalidOperationException("Error! NUI Registry weakReference should not be NULL!");
131                 }
132
133                 BaseHandle ret = weakReference.Target as BaseHandle;
134                 return ret;
135             }
136             else
137             {
138                 return null;
139             }
140         }
141
142         private static Thread savedApplicationThread;
143         internal Thread SavedApplicationThread
144         {
145             get
146             {
147                 return savedApplicationThread;
148             }
149             set
150             {
151                 savedApplicationThread = value;
152             }
153         }
154
155         private static void RegistryCurrentThreadCheck()
156         {
157             if(savedApplicationThread == null)
158             {
159                 Tizen.Log.Fatal("NUI", $"Error! maybe main thread is created by other process ");
160                 return;
161             }
162             int currentId = Thread.CurrentThread.ManagedThreadId;
163             int mainThreadId = savedApplicationThread.ManagedThreadId;
164
165             if(currentId != mainThreadId)
166             {
167                 Tizen.Log.Fatal("NUI", $"Error! current thread({currentId}) which is NOT main thread({mainThreadId}) utilizes NUI object!");
168             }
169         }
170
171
172     }
173 }