Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions Source/Core/Runtime/CoyoteRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ internal sealed class CoyoteRuntime : ICoyoteRuntime, IDisposable
/// <summary>
/// Map from unique controlled thread names to their corresponding operations.
/// </summary>
private readonly ConcurrentDictionary<string, ControlledOperation> ControlledThreads;
private readonly ConcurrentDictionary<int, ControlledOperation> ControlledThreads;

/// <summary>
/// Map from controlled tasks to their corresponding operations.
Expand Down Expand Up @@ -321,7 +321,7 @@ private CoyoteRuntime(Configuration configuration, OperationScheduler scheduler,
this.ThreadPool = new ConcurrentDictionary<ulong, Thread>();
this.OperationMap = new Dictionary<ulong, ControlledOperation>();
this.PendingStartOperationMap = new Dictionary<ControlledOperation, ManualResetEventSlim>();
this.ControlledThreads = new ConcurrentDictionary<string, ControlledOperation>();
this.ControlledThreads = new ConcurrentDictionary<int, ControlledOperation>();
this.ControlledTasks = new ConcurrentDictionary<Task, ControlledOperation>();
this.UncontrolledTasks = new ConcurrentDictionary<Task, string>();
this.UncontrolledInvocations = new HashSet<string>();
Expand Down Expand Up @@ -584,7 +584,7 @@ internal Thread CreateControlledThread(ControlledOperation op, Delegate logic, A

// TODO: optimize by reusing threads instead of creating a new thread each time?
this.ThreadPool.AddOrUpdate(op.Id, thread, (id, oldThread) => thread);
this.ControlledThreads.AddOrUpdate(thread.Name, op, (threadName, oldOp) => op);
this.ControlledThreads.AddOrUpdate(thread.ManagedThreadId, op, (threadName, oldOp) => op);
return thread;
}
}
Expand Down Expand Up @@ -1529,13 +1529,7 @@ internal ControlledOperation GetOperationExecutingOnThread(Thread thread)
{
using (SynchronizedSection.Enter(this.RuntimeLock))
{
ControlledOperation op = null;
string name = thread?.Name;
if (!string.IsNullOrEmpty(name))
{
this.ControlledThreads.TryGetValue(name, out op);
}

this.ControlledThreads.TryGetValue(thread.ManagedThreadId, out var op);
return op;
}
}
Expand Down Expand Up @@ -1833,8 +1827,7 @@ private void StartMonitoringDeadlocks() => Task.Factory.StartNew(this.CheckIfExe
/// </summary>
private bool IsThreadControlled(Thread thread)
{
string name = thread?.Name;
return name != null && this.ControlledThreads.ContainsKey(name);
return this.ControlledThreads.ContainsKey(thread.ManagedThreadId);
}

/// <summary>
Expand Down
18 changes: 18 additions & 0 deletions Tests/Tests.BugFinding/Threads/ThreadRunTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,23 @@ public void TestThreadStartAndJoinStress()
},
configuration: this.GetConfiguration().WithTestingIterations(10));
}

[Fact(Timeout = 5000)]
public void TestThreadRenamed()
{
this.Test(() =>
{
bool isDone = false;
Thread t = new Thread(() => { isDone = true; });
t.Name = "CustomName";
t.Start();
t.Join();

Specification.Assert(isDone, "The expected condition was not satisfied.");
Specification.Assert(t.ThreadState is ThreadState.Stopped, "State of thread '{0}' is {1} instead of Stopped.",
t.ManagedThreadId, t.ThreadState);
},
configuration: this.GetConfiguration().WithTestingIterations(10));
}
}
}