[NUI] TCSACR-226 code change (#1032)
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.Common / Tizen.Applications / TizenSynchronizationContext.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 using System;
18 using System.Collections.Concurrent;
19 using System.Threading;
20
21 namespace Tizen.Applications
22 {
23     /// <summary>
24     /// Provides a synchronization context for the Tizen application model.
25     /// </summary>
26     /// <since_tizen> 3 </since_tizen>
27     public class TizenSynchronizationContext : SynchronizationContext
28     {
29         /// <summary>
30         /// Initilizes a new TizenSynchronizationContext and install into the current thread.
31         /// </summary>
32         /// <remarks>
33         /// It is equivalent.
34         /// <code>
35         /// SetSynchronizationContext(new TizenSynchronizationContext());
36         /// </code>
37         /// </remarks>
38         /// <since_tizen> 3 </since_tizen>
39         public static void Initialize()
40         {
41             SetSynchronizationContext(new TizenSynchronizationContext());
42         }
43
44         /// <summary>
45         /// Dispatches an asynchronous message to a Tizen main loop.
46         /// </summary>
47         /// <param name="d"><see cref="System.Threading.SendOrPostCallback"/>The SendOrPostCallback delegate to call.</param>
48         /// <param name="state"><see cref="System.Object"/>The object passed to the delegate.</param>
49         /// <remarks>
50         /// The post method starts an asynchronous request to post a message.</remarks>
51         /// <since_tizen> 3 </since_tizen>
52         public override void Post(SendOrPostCallback d, object state)
53         {
54             GSourceManager.Post(() =>
55             {
56                 d(state);
57             });
58         }
59
60         /// <summary>
61         /// Dispatches a synchronous message to a Tizen main loop.
62         /// </summary>
63         /// <param name="d"><see cref="System.Threading.SendOrPostCallback"/>The SendOrPostCallback delegate to call.</param>
64         /// <param name="state"><see cref="System.Object"/>The object passed to the delegate.</param>
65         /// <remarks>
66         /// The send method starts a synchronous request to send a message.</remarks>
67         /// <since_tizen> 3 </since_tizen>
68         public override void Send(SendOrPostCallback d, object state)
69         {
70             var mre = new ManualResetEvent(false);
71             Exception err = null;
72             GSourceManager.Post(() =>
73             {
74                 try
75                 {
76                     d(state);
77                 }
78                 catch (Exception ex)
79                 {
80                     err = ex;
81                 }
82                 finally
83                 {
84                     mre.Set();
85                 }
86             });
87             mre.WaitOne();
88             if (err != null)
89             {
90                 throw err;
91             }
92         }
93
94         private static class GSourceManager
95         {
96             private static Interop.Glib.GSourceFunc _wrapperHandler;
97             private static Object _transactionLock;
98             private static ConcurrentDictionary<int, Action> _handlerMap;
99             private static int _transactionId;
100
101             static GSourceManager()
102             {
103                 _wrapperHandler = new Interop.Glib.GSourceFunc(Handler);
104                 _transactionLock = new Object();
105                 _handlerMap = new ConcurrentDictionary<int, Action>();
106                 _transactionId = 0;
107             }
108
109             public static void Post(Action action)
110             {
111                 int id = 0;
112                 lock (_transactionLock)
113                 {
114                     id = _transactionId++;
115                 }
116                 _handlerMap.TryAdd(id, action);
117                 Interop.Glib.IdleAdd(_wrapperHandler, (IntPtr)id);
118             }
119
120             private static bool Handler(IntPtr userData)
121             {
122                 int key = (int)userData;
123                 if (_handlerMap.ContainsKey(key))
124                 {
125                     Action action;
126                     _handlerMap.TryRemove(key, out action);
127                     action?.Invoke();
128                 }
129                 return false;
130             }
131         }
132     }
133 }