Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Util / CloseableThreadLocal.cs
1 /* 
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  * http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.Threading;
21
22 namespace Mono.Lucene.Net.Util
23 {
24
25     /// <summary>Java's builtin ThreadLocal has a serious flaw:
26     /// it can take an arbitrarily long amount of time to
27     /// dereference the things you had stored in it, even once the
28     /// ThreadLocal instance itself is no longer referenced.
29     /// This is because there is single, master map stored for
30     /// each thread, which all ThreadLocals share, and that
31     /// master map only periodically purges "stale" entries.
32     /// 
33     /// While not technically a memory leak, because eventually
34     /// the memory will be reclaimed, it can take a long time
35     /// and you can easily hit OutOfMemoryError because from the
36     /// GC's standpoint the stale entries are not reclaimaible.
37     /// 
38     /// This class works around that, by only enrolling
39     /// WeakReference values into the ThreadLocal, and
40     /// separately holding a hard reference to each stored
41     /// value.  When you call {@link #close}, these hard
42     /// references are cleared and then GC is freely able to
43     /// reclaim space by objects stored in it. 
44     /// </summary>
45     /// 
46
47     public class CloseableThreadLocal
48     {
49         private ThreadLocal<WeakReference> t = new ThreadLocal<WeakReference>();
50
51         private Dictionary<Thread, object> hardRefs = new Dictionary<Thread, object>();
52
53
54         public virtual object InitialValue()
55         {
56             return null;
57         }
58
59         public virtual object Get()
60         {
61             WeakReference weakRef = t.Get();
62             if (weakRef == null)
63             {
64                 object iv = InitialValue();
65                 if (iv != null)
66                 {
67                     Set(iv);
68                     return iv;
69                 }
70                 else
71                     return null;
72             }
73             else
74             {
75                 return weakRef.Get();
76             }
77         }
78
79         public virtual void Set(object @object)
80         {
81             //+-- For Debuging
82             if (SupportClass.CloseableThreadLocalProfiler.EnableCloseableThreadLocalProfiler == true)
83             {
84                 lock (SupportClass.CloseableThreadLocalProfiler.Instances)
85                 {
86                     SupportClass.CloseableThreadLocalProfiler.Instances.Add(new WeakReference(@object));
87                 }
88             }
89             //+--
90
91             t.Set(new WeakReference(@object));
92
93             lock (hardRefs)
94             {
95                 //hardRefs[Thread.CurrentThread] = @object;
96                 hardRefs.Add(Thread.CurrentThread, @object);
97
98                 // Purge dead threads
99                 foreach (var thread in new List<Thread>(hardRefs.Keys))
100                 {
101                     if (!thread.IsAlive)
102                         hardRefs.Remove(thread);
103                 }
104
105             }
106         }
107
108         public virtual void Close()
109         {
110             // Clear the hard refs; then, the only remaining refs to
111             // all values we were storing are weak (unless somewhere
112             // else is still using them) and so GC may reclaim them:
113             hardRefs = null;
114             // Take care of the current thread right now; others will be
115             // taken care of via the WeakReferences.
116             if (t != null)
117             {
118                 t.Remove();
119             }
120             t = null;
121         }
122     }
123
124     internal static class CloseableThreadLocalExtensions
125     {
126         public static void Set<T>(this ThreadLocal<T> t, T val)
127         {
128             t.Value = val;
129         }
130
131         public static T Get<T>(this ThreadLocal<T> t)
132         {
133             return t.Value;
134         }
135
136         public static void Remove<T>(this ThreadLocal<T> t)
137         {
138             t.Dispose();
139         }
140
141         public static object Get(this WeakReference w)
142         {
143             return w.Target;
144         }
145     }
146
147     //// {{DIGY}}
148     //// To compile against Framework 2.0
149     //// Uncomment below class
150 #if NET_2_0
151     public class ThreadLocal<T> : IDisposable
152     {
153        [ThreadStatic]
154        static SupportClass.WeakHashTable slots;
155
156        void Init()
157        {
158            if (slots == null) slots = new SupportClass.WeakHashTable();
159        }
160
161        public T Value
162        {
163            set
164            {
165                Init();
166                slots.Add(this, value);
167            }
168            get
169            {
170                Init();
171                return (T)slots[this];
172            }
173        }
174
175        public void Dispose()
176        {
177            slots.Remove(this);
178        }
179     }
180 #endif
181 }