Skip to content

Commit ce5e107

Browse files
committed
Race condition on FbConnectionPoolManager.Dispose and FbConnectionPoolManager.CleanupCallback (DNET-867).
1 parent 469bbac commit ce5e107

File tree

1 file changed

+21
-18
lines changed

1 file changed

+21
-18
lines changed

Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionPoolManager.cs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ public void Dispose()
4848
if (_disposed)
4949
return;
5050
_disposed = true;
51-
Created = default;
5251
Connection.Dispose();
53-
Connection = null;
5452
}
5553
}
5654

@@ -75,10 +73,7 @@ public void Dispose()
7573
if (_disposed)
7674
return;
7775
_disposed = true;
78-
_connectionString = null;
7976
CleanConnectionsImpl();
80-
_available = null;
81-
_busy = null;
8277
}
8378
}
8479

@@ -177,9 +172,10 @@ FbConnectionInternal CreateNewConnectionIfPossibleImpl(FbConnectionString connec
177172
}
178173
}
179174

180-
int _disposed;
175+
bool _disposed;
181176
ConcurrentDictionary<string, Pool> _pools;
182177
Timer _cleanupTimer;
178+
object _syncRootDisposeTimerCallback;
183179

184180
static FbConnectionPoolManager()
185181
{
@@ -189,9 +185,10 @@ static FbConnectionPoolManager()
189185

190186
FbConnectionPoolManager()
191187
{
192-
_disposed = 0;
188+
_disposed = false;
193189
_pools = new ConcurrentDictionary<string, Pool>();
194190
_cleanupTimer = new Timer(CleanupCallback, null, TimeSpan.FromSeconds(2), Timeout.InfiniteTimeSpan);
191+
_syncRootDisposeTimerCallback = new object();
195192
}
196193

197194
internal FbConnectionInternal Get(FbConnectionString connectionString, FbConnection owner)
@@ -227,25 +224,31 @@ internal void ClearPool(FbConnectionString connectionString)
227224

228225
public void Dispose()
229226
{
230-
if (Interlocked.Exchange(ref _disposed, 1) == 1)
231-
return;
232-
_cleanupTimer.Dispose();
233-
_cleanupTimer = null;
234-
_pools.Values.AsParallel().ForAll(x => x.Dispose());
235-
_pools = null;
227+
lock (_syncRootDisposeTimerCallback)
228+
{
229+
if (_disposed)
230+
return;
231+
_disposed = true;
232+
// when NS1.6 is dropped it can be switched to Dispose(WaitHandle) and Volatile/Interlocked
233+
_cleanupTimer.Dispose();
234+
_pools.Values.AsParallel().ForAll(x => x.Dispose());
235+
}
236236
}
237237

238238
void CleanupCallback(object o)
239239
{
240-
if (Volatile.Read(ref _disposed) == 1)
241-
return;
242-
_pools.Values.AsParallel().ForAll(x => x.CleanupPool());
243-
_cleanupTimer.Change(TimeSpan.FromSeconds(2), Timeout.InfiniteTimeSpan);
240+
lock (_syncRootDisposeTimerCallback)
241+
{
242+
if (_disposed)
243+
return;
244+
_pools.Values.AsParallel().ForAll(x => x.CleanupPool());
245+
_cleanupTimer.Change(TimeSpan.FromSeconds(2), Timeout.InfiniteTimeSpan);
246+
}
244247
}
245248

246249
void CheckDisposed()
247250
{
248-
if (Volatile.Read(ref _disposed) == 1)
251+
if (Volatile.Read(ref _disposed))
249252
throw new ObjectDisposedException(nameof(FbConnectionPoolManager));
250253
}
251254
}

0 commit comments

Comments
 (0)