1f951a2d2d7d75404517475f1a06c12db14aa310
[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.Collections.Generic;
21 using System.Runtime.InteropServices;
22 using System.Threading;
23
24 namespace Tizen.NUI
25 {
26     /// <summary>
27     /// This is used to store a mapping between C++ base handle objects and it's C# instances.
28     ///
29     /// </summary>
30     internal sealed class Registry
31     {
32         private static readonly Registry registry = new Registry();
33
34         /// <summary>
35         /// static initialization singleton
36         /// </summary>
37         internal static Registry Instance
38         {
39             get { return registry; }
40         }
41
42         /// <summary>
43         /// Given a C++ object, the dictionary allows us to find which C# object it belongs to.
44         /// By keeping the weak reference only, it will allow the object to be garbage collected.
45         /// </summary>
46         private ConcurrentDictionary<IntPtr, WeakReference> _controlMap;
47
48         private Registry()
49         {
50             _controlMap = new ConcurrentDictionary<IntPtr, WeakReference>();
51         }
52
53
54         /// <summary>
55         /// Stores the mapping between this instance of BaseHandle (C# base class) and native part.
56         /// </summary>
57         /// <param name="baseHandle">The instance of BaseHandle (C# base class).</param>
58         internal static void Register(BaseHandle baseHandle)
59         {
60             // We store a pointer to the RefObject for the control
61             RefObject refObj = baseHandle.GetObjectPtr();
62             IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
63
64             RegistryCurrentThreadCheck();
65
66             if (Instance._controlMap.TryAdd(refCptr, new WeakReference(baseHandle, false)) != true)
67             {
68                 NUILog.Debug("refCptr is already exist! OR something wrong!");
69             }
70
71             return;
72         }
73
74         /// <summary>
75         /// Removes this instance of BaseHandle (C# base class) and native part from the mapping table.
76         /// </summary>
77         /// <param name="baseHandle"> The instance of BaseHandle (C# base class)</param>
78         internal static void Unregister(BaseHandle baseHandle)
79         {
80             RefObject refObj = baseHandle.GetObjectPtr();
81             IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
82
83             RegistryCurrentThreadCheck();
84             WeakReference refe;
85             if (Instance._controlMap.TryRemove(refCptr, out refe) != true)
86             {
87                 NUILog.Debug("something wrong when removing refCptr!");
88             }
89
90             return;
91         }
92
93         internal static BaseHandle GetManagedBaseHandleFromNativePtr(BaseHandle baseHandle)
94         {
95             RefObject refObj = baseHandle.GetObjectPtr();
96             IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
97
98             // we store a dictionary of ref-obects (C++ land) to managed obects (C# land)
99             return GetManagedBaseHandleFromRefObject(refObjectPtr);
100         }
101
102         internal static BaseHandle GetManagedBaseHandleFromNativePtr(IntPtr cPtr)
103         {
104             IntPtr refObjectPtr = Interop.RefObject.GetRefObjectPtr(cPtr);
105
106             // we store a dictionary of ref-obects (C++ land) to managed obects (C# land)
107             return GetManagedBaseHandleFromRefObject(refObjectPtr);
108         }
109
110         internal static BaseHandle GetManagedBaseHandleFromRefObject(IntPtr refObjectPtr)
111         {
112             if (refObjectPtr == global::System.IntPtr.Zero)
113             {
114                 NUILog.Debug("Registry refObjectPtr is NULL! This means bind native object is NULL!");
115                 //return null;
116             }
117             else
118             {
119                 NUILog.Debug($"refObjectPtr=0x{refObjectPtr.ToInt64():X}");
120             }
121
122             RegistryCurrentThreadCheck();
123
124             // we store a dictionary of ref-obects (C++ land) to managed obects (C# land)
125             WeakReference weakReference;
126
127             if (Instance._controlMap.TryGetValue(refObjectPtr, out weakReference))
128             {
129                 if (weakReference == null)
130                 {
131                     throw new System.InvalidOperationException("Error! NUI Registry weakReference should not be NULL!");
132                 }
133
134                 BaseHandle ret = weakReference.Target as BaseHandle;
135                 return ret;
136             }
137             else
138             {
139                 return null;
140             }
141         }
142
143         private static Thread savedApplicationThread;
144         internal Thread SavedApplicationThread
145         {
146             get
147             {
148                 return savedApplicationThread;
149             }
150             set
151             {
152                 savedApplicationThread = value;
153             }
154         }
155
156         private static void RegistryCurrentThreadCheck()
157         {
158             
159             if (savedApplicationThread == null)
160             {
161                 Tizen.Log.Fatal("NUI", $"Error! maybe main thread is created by other process\n");
162                 return;
163             }
164             int currentId = Thread.CurrentThread.ManagedThreadId;
165             int mainThreadId = savedApplicationThread.ManagedThreadId;
166
167             if (currentId != mainThreadId)
168             {
169                 Tizen.Log.Fatal("NUI", $"Error! current thread({currentId}) which is NOT main thread({mainThreadId}) utilizes NUI object!");
170             }
171         }
172
173
174     }
175 }