[NUI][API10] Create Context/CookieManager when WebView is created.
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia / MediaTool / MediaPacket.Lock.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.Diagnostics;
19 using System.Runtime.InteropServices;
20 using System.Threading;
21 using Tizen.Internals.Errors;
22 using Native = Tizen.Multimedia.Interop.MediaPacket;
23
24 namespace Tizen.Multimedia
25 {
26     /// <summary>
27     /// Represents a packet for multimedia.
28     /// </summary>
29     /// <since_tizen> 3 </since_tizen>
30     public abstract partial class MediaPacket : IDisposable
31     {
32         private readonly LockState _lock = new LockState();
33
34         /// <summary>
35         /// Validates the current object is not locked.
36         /// </summary>
37         /// <exception cref="ObjectDisposedException">The MediaPacket has already been disposed of.</exception>
38         /// <exception cref="InvalidOperationException">The MediaPacket is in use by another module.</exception>
39         private void ValidateNotLocked()
40         {
41             ValidateNotDisposed();
42
43             if (_lock.IsLocked)
44             {
45                 throw new InvalidOperationException("Can't perform any writing operation." +
46                     "The packet is in use, internally.");
47             }
48         }
49
50         /// <summary>
51         /// Provides a thread-safe lock state controller.
52         /// </summary>
53         private sealed class LockState
54         {
55             const int LOCKED = 1;
56             const int UNLOCKED = 0;
57
58             private int _locked = UNLOCKED;
59
60             internal void SetLock()
61             {
62                 if (Interlocked.CompareExchange(ref _locked, LOCKED, UNLOCKED) == LOCKED)
63                 {
64                     throw new InvalidOperationException("The packet is already locked.");
65                 }
66             }
67
68             internal void SetUnlock()
69             {
70                 if (Interlocked.CompareExchange(ref _locked, UNLOCKED, LOCKED) == UNLOCKED)
71                 {
72                     Debug.Fail("The packet to unlock is not locked. " +
73                         "There must be an error somewhere that a lock isn't disposed correctly.");
74                 }
75             }
76
77             internal bool IsLocked => Interlocked.CompareExchange(ref _locked, 0, 0) == LOCKED;
78         }
79
80         /// <summary>
81         /// Provides a thread-safe lock controller.
82         /// </summary>
83         /// <example>
84         /// using (var lock = BaseMediaPacket.Lock(mediaPacket))
85         /// {
86         ///     ....
87         /// }
88         /// </example>
89         internal sealed class Lock : IDisposable
90         {
91             private readonly MediaPacket _packet;
92             private readonly GCHandle _gcHandle;
93             private int _lockCount;
94
95             internal static Lock Get(MediaPacket packet)
96             {
97                 Debug.Assert(packet != null);
98
99                 lock (packet._lock)
100                 {
101                     Lock lck = FromHandle(packet._handle) ?? new Lock(packet);
102
103                     lck._lockCount++;
104
105                     return lck;
106                 }
107             }
108
109             private Lock(MediaPacket packet)
110             {
111                 Debug.Assert(packet != null, "The packet is null!");
112
113                 packet.ValidateNotDisposed();
114
115                 _packet = packet;
116
117                 _packet._lock.SetLock();
118
119                 _gcHandle = GCHandle.Alloc(this);
120
121                 SetExtra(GCHandle.ToIntPtr(_gcHandle));
122             }
123
124             internal static Lock FromHandle(IntPtr handle)
125             {
126                 Debug.Assert(handle != IntPtr.Zero);
127
128                 IntPtr extra = GetExtra(handle);
129
130                 if (extra == IntPtr.Zero)
131                 {
132                     return null;
133                 }
134
135                 return (Lock)GCHandle.FromIntPtr(extra).Target;
136             }
137
138             private void SetExtra(IntPtr ptr)
139             {
140                 int ret = Native.SetExtra(_packet._handle, ptr);
141
142                 MultimediaDebug.AssertNoError(ret);
143             }
144
145             private static IntPtr GetExtra(IntPtr handle)
146             {
147                 int ret = Native.GetExtra(handle, out var value);
148
149                 MultimediaDebug.AssertNoError(ret);
150
151                 return value;
152             }
153
154             internal IntPtr GetHandle() => _packet.GetHandle();
155
156             internal MediaPacket MediaPacket => _packet;
157
158             private bool _isDisposed = false;
159
160             public void Dispose()
161             {
162                 if (!_isDisposed)
163                 {
164                     lock (_packet._lock)
165                     {
166                         _lockCount--;
167
168                         if (_lockCount == 0)
169                         {
170                             SetExtra(IntPtr.Zero);
171
172                             if (_gcHandle.IsAllocated)
173                             {
174                                 _gcHandle.Free();
175                             }
176
177                             // We can assure that at this point '_packet' is always locked by this lock.
178                             _packet._lock.SetUnlock();
179                         }
180                     }
181
182                     _isDisposed = true;
183                 }
184             }
185         }
186     }
187 }