Skip to content

Commit

Permalink
[mono][debugger] Concurrency on execution context dictionary (#87870)
Browse files Browse the repository at this point in the history
* fix concurrency

* fix typo and get last executioncontext

* use getoradd as suggested by @radical

* using @radical refactor
  • Loading branch information
thaystg authored Jun 21, 2023
1 parent 499bdd9 commit 927ef08
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 98 deletions.
69 changes: 69 additions & 0 deletions src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -404,6 +405,7 @@ public ExecutionContext(MonoSDBHelper sdbAgent, int id, object auxData, PauseOnE
AuxData = auxData;
SdbAgent = sdbAgent;
PauseOnExceptions = pauseOnExceptions;
Destroyed = false;
}
public ExecutionContext CreateChildAsyncExecutionContext(SessionId sessionId)
=> new ExecutionContext(null, Id, AuxData, PauseOnExceptions)
Expand Down Expand Up @@ -456,6 +458,8 @@ public bool CopyDataFromParentContext()
internal int TempBreakpointForSetNextIP { get; set; }
internal bool FirstBreakpoint { get; set; }

internal bool Destroyed { get; set; }

public DebugStore Store
{
get
Expand Down Expand Up @@ -502,4 +506,69 @@ public PerScopeCache()
{
}
}

internal sealed class ConcurrentExecutionContextDictionary
{
private ConcurrentDictionary<SessionId, ConcurrentBag<ExecutionContext>> contexts = new ();
public ExecutionContext GetCurrentContext(SessionId sessionId)
=> TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context)
? context
: throw new KeyNotFoundException($"No execution context found for session {sessionId}");

public bool TryGetCurrentExecutionContextValue(SessionId id, out ExecutionContext executionContext)
{
executionContext = null;
if (!contexts.TryGetValue(id, out ConcurrentBag<ExecutionContext> contextBag))
return false;
if (contextBag.IsEmpty)
return false;
executionContext = contextBag.Where(context => context.Id == contextBag.Where(context => context.Destroyed == false).Max(context => context.Id)).FirstOrDefault();
return executionContext != null;
}

public void OnDefaultContextUpdate(SessionId sessionId, ExecutionContext newContext)
{
if (TryGetAndAddContext(sessionId, newContext, out ExecutionContext previousContext))
{
foreach (KeyValuePair<string, BreakpointRequest> kvp in previousContext.BreakpointRequests)
{
newContext.BreakpointRequests[kvp.Key] = kvp.Value.Clone();
}
newContext.PauseOnExceptions = previousContext.PauseOnExceptions;
}
}

public bool TryGetAndAddContext(SessionId sessionId, ExecutionContext newExecutionContext, out ExecutionContext previousExecutionContext)
{
bool hasExisting = TryGetCurrentExecutionContextValue(sessionId, out previousExecutionContext);
ConcurrentBag<ExecutionContext> bag = contexts.GetOrAdd(sessionId, _ => new ConcurrentBag<ExecutionContext>());
bag.Add(newExecutionContext);
return hasExisting;
}

public void CreateWorkerExecutionContext(SessionId workerSessionId, SessionId originSessionId, ILogger logger)
{
if (!TryGetCurrentExecutionContextValue(originSessionId, out ExecutionContext context))
{
logger.LogDebug($"Origin sessionId does not exist - {originSessionId}");
return;
}
if (contexts.ContainsKey(workerSessionId))
{
logger.LogDebug($"Worker sessionId already exists - {originSessionId}");
return;
}
contexts[workerSessionId] = new();
contexts[workerSessionId].Add(context.CreateChildAsyncExecutionContext(workerSessionId));
}

public void DestroyContext(SessionId sessionId, int id)
{
if (!contexts.TryGetValue(sessionId, out ConcurrentBag<ExecutionContext> contextBag))
return;
foreach (ExecutionContext context in contextBag.Where(x => x.Id == id).ToList())
context.Destroyed = true;
}
public bool ContainsKey(SessionId sessionId) => contexts.ContainsKey(sessionId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public FirefoxMonoProxy(ILogger logger, string loggerId = null, ProxyOptions opt

public FirefoxExecutionContext GetContextFixefox(SessionId sessionId)
{
if (TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
if (Contexts.TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
return context as FirefoxExecutionContext;
throw new ArgumentException($"Invalid Session: \"{sessionId}\"", nameof(sessionId));
}
Expand Down Expand Up @@ -236,7 +236,7 @@ protected override async Task<bool> AcceptEvent(SessionId sessionId, JObject arg
{
if (args["frame"] != null && args["type"] == null)
{
OnDefaultContextUpdate(sessionId, new FirefoxExecutionContext(new MonoSDBHelper (this, logger, sessionId), 0, args["frame"]["consoleActor"].Value<string>()));
Contexts.OnDefaultContextUpdate(sessionId, new FirefoxExecutionContext(new MonoSDBHelper (this, logger, sessionId), 0, args["frame"]["consoleActor"].Value<string>()));
return false;
}

Expand Down Expand Up @@ -289,7 +289,7 @@ protected override async Task<bool> AcceptEvent(SessionId sessionId, JObject arg
}
case "target-available-form":
{
OnDefaultContextUpdate(sessionId, new FirefoxExecutionContext(new MonoSDBHelper (this, logger, sessionId), 0, args["target"]["consoleActor"].Value<string>()));
Contexts.OnDefaultContextUpdate(sessionId, new FirefoxExecutionContext(new MonoSDBHelper (this, logger, sessionId), 0, args["target"]["consoleActor"].Value<string>()));
var ctx = GetContextFixefox(sessionId);
ctx.GlobalName = args["target"]["actor"].Value<string>();
ctx.ThreadName = args["target"]["threadActor"].Value<string>();
Expand All @@ -316,7 +316,7 @@ protected override async Task<bool> AcceptCommand(MessageId sessionId, JObject a
{
case "resume":
{
if (!TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
if (!Contexts.TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
return false;
context.PausedOnWasm = false;
if (context.CallStack == null)
Expand Down Expand Up @@ -380,7 +380,7 @@ protected override async Task<bool> AcceptCommand(MessageId sessionId, JObject a
}
case "setBreakpoint":
{
if (!TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
if (!Contexts.TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
return false;
var req = JObject.FromObject(new
{
Expand Down Expand Up @@ -420,7 +420,7 @@ protected override async Task<bool> AcceptCommand(MessageId sessionId, JObject a
}
case "removeBreakpoint":
{
if (!TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
if (!Contexts.TryGetCurrentExecutionContextValue(sessionId, out ExecutionContext context))
return false;
Result resp = await SendCommand(sessionId, "", args, token);

Expand Down
Loading

0 comments on commit 927ef08

Please # to comment.