File: ObjectCache.cs

package info (click to toggle)
mono-debugger 0.60%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 9,556 kB
  • ctags: 22,787
  • sloc: ansic: 99,407; cs: 42,429; sh: 9,192; makefile: 376
file content (209 lines) | stat: -rw-r--r-- 4,307 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
using System;
using System.Threading;
using System.Collections;
using System.Runtime.InteropServices;

using Mono.Debugger.Backend;

namespace Mono.Debugger
{
	public delegate object ObjectCacheFunc (object user_data);

	internal class ObjectCache : IDisposable
	{
		WeakReference weak_reference;
		ObjectCacheFunc func;
		object user_data;
		object cached_object;
		int initial_ttl, ttl;
		int id;

		static ArrayList objects;
		static Timer timer;
		static DebuggerMutex mutex;
		static int next_id = 0;

		public ObjectCache (ObjectCacheFunc func, object user_data, int ttl)
		{
			this.func = func;
			this.user_data = user_data;
			this.initial_ttl = this.ttl = ttl;
			this.id = ++next_id;

			mutex.Lock ();
			objects.Add (this);
			mutex.Unlock ();
		}

		public static void Initialize ()
		{
			mutex = new DebuggerMutex ("object_cache");
			objects = new ArrayList ();
			timer = new Timer (new TimerCallback (cleanup_process), null, 0, 60000);
		}

		public static void Shutdown ()
		{
			if (timer != null) {
				timer.Dispose ();
				timer = null;
			}
		}

		static void cleanup_process (object dummy)
		{
			mutex.Lock ();
			foreach (ObjectCache obj in objects)
				obj.timeout_func ();
			mutex.Unlock ();
		}

		void timeout_func ()
		{
			if (ttl > 0)
				--ttl;
			if (ttl > 0)
				return;

			cached_object = null;
		}

		public object PeekData {
			get {
				check_disposed ();

				// We must avoid a race condition here: when restarting the
				// timeout, this may wipe out the cached_object immediately.
				object data = cached_object;

				// If we still have a hard reference to the data.
				if (data != null)
					return data;

				// Maybe we still have a weak reference to it.
				if (weak_reference != null) {
					try {
						data = weak_reference.Target;
					} catch {
						weak_reference = null;
					}
				}

				return data;
			}
		}

		public object Data {
			get {
				check_disposed ();

				// We must avoid a race condition here: when restarting the
				// timeout, this may wipe out the cached_object immediately.
				object data = cached_object;

				// If we still have a hard reference to the data.
				if (data != null) {
					// Reset timeout since the data has been accessed.
					ttl = initial_ttl;
					return data;
				}

				// Maybe we still have a weak reference to it.
				if (weak_reference != null) {
					try {
						data = weak_reference.Target;
					} catch {
						weak_reference = null;
					}
				}
				if (data != null) {
					// Data is still there and has just been accessed, so
					// add a hard reference to it again and restart the timeout.
					cached_object = data;
					ttl = initial_ttl;
					return data;
				}

				data = func (user_data);
				try {
					weak_reference = new WeakReference (data);
				} catch (Exception e) {
					Console.WriteLine ("EX: {0}", e);
					// Silently ignore.
				}

				// Just created a new object, add a hard reference to it and restart
				// the timeout.
				cached_object = data;
				ttl = initial_ttl;

				return data;
			}
		}

		public void Flush ()
		{
			ttl = 0;
			cached_object = null;
			weak_reference = null;
		}

		//
		// IDisposable
		//

		private void check_disposed ()
		{
			if (disposed)
				throw new ObjectDisposedException ("Inferior");
		}

		private bool disposed = false;

		protected virtual void Dispose (bool disposing)
		{
			// Check to see if Dispose has already been called.
			if (!this.disposed) {
				// If this is a call to Dispose,
				// dispose all managed resources.
				if (disposing) {
					ttl = -1;
					mutex.Lock ();
					objects.Remove (this);
					mutex.Unlock ();
					IDisposable data_dispose = cached_object as IDisposable;
					if (data_dispose != null)
						data_dispose.Dispose ();
					cached_object = null;
					weak_reference = null;
					user_data = null;
					// Do stuff here
				}
				
				this.disposed = true;

				lock (this) {
					// Release unmanaged resources
				}
			}
		}

		public void Dispose ()
		{
			Dispose (true);
			// Take yourself off the Finalization queue
			GC.SuppressFinalize (this);
		}

		~ObjectCache ()
		{
			Dispose (false);
		}

		public override string ToString ()
		{
			return String.Format ("ObjectCache ({0}:{1}:{2}:{3})", id,
					      initial_ttl, ttl, cached_object != null);
		}
	}
}