public void Clear() { try { ScriptRunInfo = new ConcurrentDictionary <string, ScriptInfo>(ScriptRunInfo.Where(S => S.Value.RunningInstances > 0).ToArray()); } catch (Exception error) { ScriptRunInfo.Clear(); Log($"EmpyrionScripting Mod: Clear => {error}", LogLevel.Error); } WaitForExec.Clear(); ExecQueue = new ConcurrentQueue <IScriptRootData>(); }
public void Add(IScriptRootData data) { if (WaitForExec.TryAdd(data.ScriptId, data)) { ExecQueue.Enqueue(data); } else { lock (ExecQueue) WaitForExec.AddOrUpdate(data.ScriptId, data, (i, d) => data); } }
private void ExecScript(object state) { if (!(state is IScriptRootData data)) { return; } try { if (data.E.EntityType == EntityType.Proxy) { WaitForExec.TryRemove(data.ScriptId, out _); return; } if (!ScriptRunInfo.TryGetValue(data.ScriptId, out var info)) { info = new ScriptInfo(); } info.LastStart = DateTime.Now; info.Count++; Interlocked.Increment(ref info.RunningInstances); processScript(data); Interlocked.Decrement(ref info.RunningInstances); lock (ExecQueue) WaitForExec.TryRemove(data.ScriptId, out _); info.ExecTime += DateTime.Now - info.LastStart; ScriptRunInfo.AddOrUpdate(data.ScriptId, info, (id, i) => info); Interlocked.Increment(ref _MainCount); if (MainCount > ScriptsCount) { if (Interlocked.Exchange(ref _MainCount, 0) > 0 && (DateTime.Now - LastIterationUpdate).TotalSeconds >= 1) { LastIterationUpdate = DateTime.Now; Interlocked.Increment(ref _Iteration); } } } catch (Exception error) { Log($"EmpyrionScripting Mod: ExecNext {data.ScriptId} => {error}", LogLevel.Debug); } }
public void CheckForEmergencyRestart(PlayfieldScriptData playfield) { lock (ExecQueue) { if (ExecQueue.IsEmpty && WaitForExec.Count > 0 && BackgroundWorkerToDo.Count == 0) { Log($"ExecQueue.IsEmpty restart [{playfield.PlayfieldName}]... #{WaitForExec.Count} => {WaitForExec.Aggregate("Pendingscripts:", (E, L) => E + "\n" + L.Key)}", LogLevel.Message); ThreadPool.GetAvailableThreads(out var availableWorkerThreads, out var availableCompletionPortThreads); Log($"ThreadPool available: WorkerThreads:{availableWorkerThreads} CompletionPortThreads:{availableCompletionPortThreads}", LogLevel.Message); ThreadPool.GetMaxThreads(out var maxWorkerThreads, out var maxCompletionPortThreads); Log($"ThreadPool max: WorkerThreads:{maxWorkerThreads} CompletionPortThreads:{maxCompletionPortThreads}", LogLevel.Message); ThreadPool.GetMinThreads(out var minWorkerThreads, out var minCompletionPortThreads); Log($"ThreadPool min: WorkerThreads:{minWorkerThreads} CompletionPortThreads:{minCompletionPortThreads}", LogLevel.Message); WaitForExec.Clear(); // robust error restart with fresh data } } }
public void Add(IScriptRootData data) { if (ScriptNeedsMainThread.TryGetValue(data.ScriptId, out var needMainThread)) { data.ScriptNeedsMainThread = needMainThread; } else { ScriptNeedsMainThread.TryAdd(data.ScriptId, false); } if (WaitForExec.TryAdd(data.ScriptId, data)) { ExecQueue.Enqueue(data.ScriptId); } else { WaitForExec.AddOrUpdate(data.ScriptId, data, (scriptId, oldData) => data); } }
public void ExecNext(int maxCount, int scriptsSyncExecution, ref int syncExecCount, Stopwatch scriptLoopTimeLimiter) { if (BackgroundWorkerToDo.Count > maxCount / 2) { return; } var scriptLoopTimeLimiterStopwatch = scriptLoopTimeLimiter; var timeLimitBackgroundReached = new Func <bool>(() => scriptLoopTimeLimiterStopwatch.ElapsedMilliseconds > EmpyrionScripting.Configuration.Current.ScriptLoopBackgroundTimeLimiterMS); TimeLimitSyncReached = new Func <bool>(() => scriptLoopTimeLimiterStopwatch.ElapsedMilliseconds > EmpyrionScripting.Configuration.Current.ScriptLoopSyncTimeLimiterMS); Log($"ExecNext: {WaitForExec.Count} -> {ExecQueue.Count}", LogLevel.Debug); for (int i = maxCount - 1; i >= 0; i--) { if (ExecQueue.TryDequeue(out var scriptId) && WaitForExec.TryGetValue(scriptId, out var data)) { if (data.ScriptNeedsMainThread) { Interlocked.Increment(ref syncExecCount); if (syncExecCount > scriptsSyncExecution) { ExecQueue.Enqueue(scriptId); } else { ((ScriptRootData)data).ScriptLoopTimeLimitReached = TimeLimitSyncReached; ExecNext(data); } } else { ((ScriptRootData)data).ScriptLoopTimeLimitReached = timeLimitBackgroundReached; ExecNext(data); } }