diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 71201c50a1..87873422eb 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -237,7 +237,7 @@ namespace Tgstation.Server.Host.Components.Chat if (!enumerable.Any()) { ulong newId; - lock (this) + lock (synchronizationLock) newId = channelIdCounter++; logger.LogTrace( "Mapping private channel {0}:{1} as {2}", @@ -268,7 +268,7 @@ namespace Tgstation.Server.Host.Components.Chat var splits = new List(message.Content.Trim().Split(' ')); var address = splits[0]; - if (address.Length > 1 && (address[address.Length - 1] == ':' || address[address.Length - 1] == ',')) + if (address.Length > 1 && (address.Last() == ':' || address.Last() == ',')) address = address[0..^1]; address = address.ToUpperInvariant(); diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 77fddea724..7efa1c7756 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -231,7 +231,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers var enumerator = channels.Select(x => GetModelChannelFromDBChannel(x)).Where(x => x != null).ToList(); - lock (this) + lock (client) { mappedChannels.Clear(); mappedChannels.AddRange(enumerator.Select(x => x.RealId)); diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index e4dc424f34..5eb58003f8 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -203,7 +203,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers } ulong userId, channelId; - lock (this) + lock (client) { userId = MapAndGetChannelId(queryChannelIdMap); channelId = isPrivate ? userId : MapAndGetChannelId(channelIdMap); @@ -250,7 +250,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers public override Task Connect(CancellationToken cancellationToken) => Task.Factory.StartNew(() => { disconnecting = false; - lock (this) + lock (client) try { client.Connect(address, port); @@ -384,7 +384,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers { if (channels.Any(x => x.IrcChannel == null)) throw new InvalidOperationException("ChatChannel missing IrcChannel!"); - lock (this) + lock (client) { var channelsWithKeys = new Dictionary(); var hs = new HashSet(); // for unique inserts diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index 22068e0bab..952fabf24b 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -22,7 +22,7 @@ namespace Tgstation.Server.Host.Components.Deployment { get { - lock (this) + lock (jobLockCounts) return newerDmbTcs.Task; } } @@ -114,7 +114,7 @@ namespace Tgstation.Server.Host.Components.Deployment await Task.WhenAll(otherTask, deleteJob).ConfigureAwait(false); } - lock (this) + lock (jobLockCounts) if (!jobLockCounts.TryGetValue(job.Id, out var currentVal) || currentVal == 1) { jobLockCounts.Remove(job.Id); @@ -137,7 +137,7 @@ namespace Tgstation.Server.Host.Components.Deployment var newProvider = await FromCompileJob(job, cancellationToken).ConfigureAwait(false); if (newProvider == null) return; - lock (this) + lock (jobLockCounts) { nextDmbProvider?.Dispose(); nextDmbProvider = newProvider; @@ -153,7 +153,7 @@ namespace Tgstation.Server.Host.Components.Deployment throw new InvalidOperationException("No .dmb available!"); if (lockCount < 0) throw new ArgumentOutOfRangeException(nameof(lockCount), lockCount, "lockCount must be greater than or equal to 0!"); - lock (this) + lock (jobLockCounts) { var jobId = nextDmbProvider.CompileJob.Id; var incremented = jobLockCounts[jobId] += lockCount; @@ -221,7 +221,7 @@ namespace Tgstation.Server.Host.Components.Deployment return null; // omae wa mou shinderu } - lock (this) + lock (jobLockCounts) { if (!jobLockCounts.TryGetValue(compileJob.Id, out int value)) { @@ -252,7 +252,7 @@ namespace Tgstation.Server.Host.Components.Deployment List jobIdsToSkip; // don't clean locked directories - lock (this) + lock (jobLockCounts) jobIdsToSkip = jobLockCounts.Select(x => x.Key).ToList(); List jobUidsToNotErase = null; diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index bbe2f4323e..e8fd1446b0 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -86,6 +86,11 @@ namespace Tgstation.Server.Host.Components.Deployment /// readonly ILogger logger; + /// + /// for . + /// + readonly object compilingLock; + /// /// If a compile job is running /// @@ -123,6 +128,8 @@ namespace Tgstation.Server.Host.Components.Deployment this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + + compilingLock = new object(); } /// @@ -175,50 +182,48 @@ namespace Tgstation.Server.Host.Components.Deployment job.MinimumSecurityLevel = securityLevel; // needed for the TempDmbProvider var timeoutAt = DateTimeOffset.Now.AddSeconds(timeout); - using (var provider = new TemporaryDmbProvider(ioManager.ResolvePath(dirA), String.Concat(job.DmeName, DmbExtension), job)) - using (var controller = await sessionControllerFactory.LaunchNew(provider, byondLock, launchParameters, true, true, true, cancellationToken).ConfigureAwait(false)) + using var provider = new TemporaryDmbProvider(ioManager.ResolvePath(dirA), String.Concat(job.DmeName, DmbExtension), job); + using var controller = await sessionControllerFactory.LaunchNew(provider, byondLock, launchParameters, true, true, true, cancellationToken).ConfigureAwait(false); + var launchResult = await controller.LaunchResult.ConfigureAwait(false); + + var now = DateTimeOffset.Now; + if (now < timeoutAt && launchResult.StartupTime.HasValue) { - var launchResult = await controller.LaunchResult.ConfigureAwait(false); + var timeoutTask = Task.Delay(timeoutAt - now, cancellationToken); - var now = DateTimeOffset.Now; - if (now < timeoutAt && launchResult.StartupTime.HasValue) - { - var timeoutTask = Task.Delay(timeoutAt - now, cancellationToken); - - await Task.WhenAny(controller.Lifetime, timeoutTask).ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); - } - - if (controller.Lifetime.IsCompleted) - { - var validationStatus = controller.ApiValidationStatus; - logger.LogTrace("API validation status: {0}", validationStatus); - - job.DMApiVersion = controller.DMApiVersion; - switch (validationStatus) - { - case ApiValidationStatus.RequiresUltrasafe: - job.MinimumSecurityLevel = DreamDaemonSecurity.Ultrasafe; - return; - case ApiValidationStatus.RequiresSafe: - job.MinimumSecurityLevel = DreamDaemonSecurity.Safe; - return; - case ApiValidationStatus.RequiresTrusted: - job.MinimumSecurityLevel = DreamDaemonSecurity.Trusted; - return; - case ApiValidationStatus.NeverValidated: - throw new JobException(ErrorCode.DreamMakerNeverValidated); - case ApiValidationStatus.BadValidationRequest: - throw new JobException(ErrorCode.DreamMakerInvalidValidation); - case ApiValidationStatus.UnaskedValidationRequest: - default: - throw new InvalidOperationException( - $"Session controller returned unexpected ApiValidationStatus: {validationStatus}"); - } - } - - throw new JobException(ErrorCode.DreamMakerValidationTimeout); + await Task.WhenAny(controller.Lifetime, timeoutTask).ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); } + + if (controller.Lifetime.IsCompleted) + { + var validationStatus = controller.ApiValidationStatus; + logger.LogTrace("API validation status: {0}", validationStatus); + + job.DMApiVersion = controller.DMApiVersion; + switch (validationStatus) + { + case ApiValidationStatus.RequiresUltrasafe: + job.MinimumSecurityLevel = DreamDaemonSecurity.Ultrasafe; + return; + case ApiValidationStatus.RequiresSafe: + job.MinimumSecurityLevel = DreamDaemonSecurity.Safe; + return; + case ApiValidationStatus.RequiresTrusted: + job.MinimumSecurityLevel = DreamDaemonSecurity.Trusted; + return; + case ApiValidationStatus.NeverValidated: + throw new JobException(ErrorCode.DreamMakerNeverValidated); + case ApiValidationStatus.BadValidationRequest: + throw new JobException(ErrorCode.DreamMakerInvalidValidation); + case ApiValidationStatus.UnaskedValidationRequest: + default: + throw new InvalidOperationException( + $"Session controller returned unexpected ApiValidationStatus: {validationStatus}"); + } + } + + throw new JobException(ErrorCode.DreamMakerValidationTimeout); } /// @@ -230,7 +235,7 @@ namespace Tgstation.Server.Host.Components.Deployment /// A representing the running operation async Task RunDreamMaker(string dreamMakerPath, Models.CompileJob job, CancellationToken cancellationToken) { - using (var dm = processExecutor.LaunchProcess( + using var dm = processExecutor.LaunchProcess( dreamMakerPath, ioManager.ResolvePath( ioManager.ConcatPath( @@ -238,18 +243,16 @@ namespace Tgstation.Server.Host.Components.Deployment ADirectoryName)), $"-clean {job.DmeName}.{DmeExtension}", true, - true)) - { - int exitCode; - using (cancellationToken.Register(() => dm.Terminate())) - exitCode = await dm.Lifetime.ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); + true); + int exitCode; + using (cancellationToken.Register(() => dm.Terminate())) + exitCode = await dm.Lifetime.ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); - logger.LogDebug("DreamMaker exit code: {0}", exitCode); - job.Output = dm.GetCombinedOutput(); - logger.LogDebug("DreamMaker output: {0}{1}", Environment.NewLine, job.Output); - return exitCode; - } + logger.LogDebug("DreamMaker exit code: {0}", exitCode); + job.Output = dm.GetCombinedOutput(); + logger.LogDebug("DreamMaker output: {0}{1}", Environment.NewLine, job.Output); + return exitCode; } /// @@ -480,46 +483,42 @@ namespace Tgstation.Server.Host.Components.Deployment logger.LogTrace("Begin Compile"); - lock (this) + lock (compilingLock) { if (compiling) throw new JobException(ErrorCode.DreamMakerCompileJobInProgress); compiling = true; } - using (var progressCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) + using var progressCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var progressTask = estimatedDuration.HasValue ? ProgressTask(progressReporter, estimatedDuration.Value, cancellationToken) : Task.CompletedTask; + try { - var progressTask = estimatedDuration.HasValue ? ProgressTask(progressReporter, estimatedDuration.Value, cancellationToken) : Task.CompletedTask; - try - { - using (var byondLock = await byond.UseExecutables(null, cancellationToken).ConfigureAwait(false)) - { - await SendDeploymentMessage(revisionInformation, byondLock, cancellationToken).ConfigureAwait(false); + using var byondLock = await byond.UseExecutables(null, cancellationToken).ConfigureAwait(false); + await SendDeploymentMessage(revisionInformation, byondLock, cancellationToken).ConfigureAwait(false); - var job = new Models.CompileJob - { - DirectoryName = Guid.NewGuid(), - DmeName = dreamMakerSettings.ProjectName, - RevisionInformation = revisionInformation, - ByondVersion = byondLock.Version.ToString() - }; - - await RunCompileJob(job, dreamMakerSettings, byondLock, repository, apiValidateTimeout, cancellationToken).ConfigureAwait(false); - - return job; - } - } - catch (OperationCanceledException) + var job = new Models.CompileJob { - await eventConsumer.HandleEvent(EventType.CompileCancelled, null, default).ConfigureAwait(false); - throw; - } - finally - { - compiling = false; - progressCts.Cancel(); - await progressTask.ConfigureAwait(false); - } + DirectoryName = Guid.NewGuid(), + DmeName = dreamMakerSettings.ProjectName, + RevisionInformation = revisionInformation, + ByondVersion = byondLock.Version.ToString() + }; + + await RunCompileJob(job, dreamMakerSettings, byondLock, repository, apiValidateTimeout, cancellationToken).ConfigureAwait(false); + + return job; + } + catch (OperationCanceledException) + { + await eventConsumer.HandleEvent(EventType.CompileCancelled, null, default).ConfigureAwait(false); + throw; + } + finally + { + compiling = false; + progressCts.Cancel(); + await progressTask.ConfigureAwait(false); } } } diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index cd266a6110..b431681550 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -85,6 +85,11 @@ namespace Tgstation.Server.Host.Components /// readonly Api.Models.Instance metadata; + /// + /// for and . + /// + readonly object timerLock; + /// /// The auto update /// @@ -143,6 +148,8 @@ namespace Tgstation.Server.Host.Components this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + + timerLock = new object(); } /// @@ -605,7 +612,7 @@ namespace Tgstation.Server.Host.Components public async Task SetAutoUpdateInterval(uint newInterval) { Task toWait; - lock (this) + lock (timerLock) { if (timerTask != null) { @@ -619,7 +626,7 @@ namespace Tgstation.Server.Host.Components await toWait.ConfigureAwait(false); if (newInterval == 0) return; - lock (this) + lock (timerLock) { // race condition, just quit if (timerTask != null) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 8575d732b4..204aa29587 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -66,7 +66,7 @@ namespace Tgstation.Server.Host.Components readonly ILogger logger; /// - /// Map of s to respective s + /// Map of s to respective s. Also used as a . /// readonly IDictionary instances; @@ -127,7 +127,7 @@ namespace Tgstation.Server.Host.Components /// public void Dispose() { - lock (this) + lock (instances) { if (disposed) return; @@ -143,7 +143,7 @@ namespace Tgstation.Server.Host.Components { if (metadata == null) throw new ArgumentNullException(nameof(metadata)); - lock (this) + lock (instances) { if (!instances.TryGetValue(metadata.Id, out IInstance instance)) throw new InvalidOperationException("Instance not online!"); @@ -180,7 +180,7 @@ namespace Tgstation.Server.Host.Components throw new ArgumentNullException(nameof(metadata)); logger.LogInformation("Offlining instance ID {0}", metadata.Id); IInstance instance; - lock (this) + lock (instances) { if (!instances.TryGetValue(metadata.Id, out instance)) throw new InvalidOperationException("Instance not online!"); @@ -223,7 +223,7 @@ namespace Tgstation.Server.Host.Components var instance = instanceFactory.CreateInstance(this, metadata); try { - lock (this) + lock (instances) { if (instances.ContainsKey(metadata.Id)) throw new InvalidOperationException("Instance already online!"); @@ -309,9 +309,9 @@ namespace Tgstation.Server.Host.Components /// private void CheckSystemCompatibility() { - using (var systemIdentity = systemIdentityFactory.GetCurrent()) - if (!systemIdentity.CanCreateSymlinks) - throw new InvalidOperationException("The user running tgstation-server cannot create symlinks! Please try running as an administrative user!"); + using var systemIdentity = systemIdentityFactory.GetCurrent(); + if (!systemIdentity.CanCreateSymlinks) + throw new InvalidOperationException("The user running tgstation-server cannot create symlinks! Please try running as an administrative user!"); } /// diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index 5da7b9507f..c2ce055042 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -74,7 +74,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles readonly ILogger logger; /// - /// The for + /// The for . Also used as a . /// readonly SemaphoreSlim semaphore; @@ -159,7 +159,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles if (!headFileExistsTask.Result && !tailFileExistsTask.Result) return null; - string IncludeLine(string filePath) => String.Format(CultureInfo.InvariantCulture, "#include \"{0}\"", filePath); + static string IncludeLine(string filePath) => String.Format(CultureInfo.InvariantCulture, "#include \"{0}\"", filePath); return new ServerSideModifications(headFileExistsTask.Result ? IncludeLine(CodeModificationsHeadFile) : null, tailFileExistsTask.Result ? IncludeLine(CodeModificationsTailFile) : null, false); } @@ -235,7 +235,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles void ReadImpl() { - lock (this) + lock (semaphore) try { var content = synchronousIOManager.ReadFile(path); @@ -366,7 +366,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles void WriteImpl() { - lock (this) + lock (semaphore) try { var fileHash = previousHash; diff --git a/src/Tgstation.Server.Host/Components/Watchdog/DeadSessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/DeadSessionController.cs index 2cc9cbfc8a..8b680b567c 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/DeadSessionController.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/DeadSessionController.cs @@ -48,6 +48,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// public Version DMApiVersion => throw new NotSupportedException(); + /// + /// for . + /// + readonly object disposeLock; + /// /// If the was d /// @@ -66,12 +71,13 @@ namespace Tgstation.Server.Host.Components.Watchdog }); Lifetime = Task.FromResult(-1); OnReboot = new TaskCompletionSource().Task; + disposeLock = new object(); } /// public void Dispose() { - lock (this) + lock (disposeLock) { if (disposed) return; diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs index d46052b450..fb630201a3 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs @@ -136,6 +136,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// readonly ILogger logger; + /// + /// for port updates and . + /// + readonly object synchronizationLock; + /// /// The waits on when DreamDaemon currently has it's ports closed /// @@ -214,6 +219,8 @@ namespace Tgstation.Server.Host.Components.Watchdog rebootTcs = new TaskCompletionSource(); + synchronizationLock = new object(); + CancellationTokenSource cts = null; Task lifetimeContinuation = null; lifetimeContinuation = process.Lifetime.ContinueWith( @@ -287,7 +294,7 @@ namespace Tgstation.Server.Host.Components.Watchdog /// If this function was NOT called by the finalizer void Dispose(bool disposing) { - lock (this) + lock (synchronizationLock) { if (disposed) return; @@ -366,7 +373,7 @@ namespace Tgstation.Server.Host.Components.Watchdog process.Terminate(); break; case BridgeCommandType.PortUpdate: - lock (this) + lock (synchronizationLock) { if (!parameters.CurrentPort.HasValue) { @@ -569,7 +576,7 @@ namespace Tgstation.Server.Host.Components.Watchdog return true; } - lock (this) + lock (synchronizationLock) if (portClosedForReboot) { if (portAssignmentTcs != null) diff --git a/src/Tgstation.Server.Host/Core/SemaphoreSlimContext.cs b/src/Tgstation.Server.Host/Core/SemaphoreSlimContext.cs index 8c78b4570f..2fd1896e8d 100644 --- a/src/Tgstation.Server.Host/Core/SemaphoreSlimContext.cs +++ b/src/Tgstation.Server.Host/Core/SemaphoreSlimContext.cs @@ -29,6 +29,11 @@ namespace Tgstation.Server.Host.Core /// readonly SemaphoreSlim lockedSemaphore; + /// + /// for . + /// + readonly object disposeLock; + /// /// If has been called /// @@ -41,6 +46,7 @@ namespace Tgstation.Server.Host.Core SemaphoreSlimContext(SemaphoreSlim lockedSemaphore) { this.lockedSemaphore = lockedSemaphore; + disposeLock = new object(); } /// @@ -55,7 +61,7 @@ namespace Tgstation.Server.Host.Core /// public void Dispose() { - lock (this) + lock (disposeLock) { if (disposed) return; diff --git a/src/Tgstation.Server.Host/Jobs/JobManager.cs b/src/Tgstation.Server.Host/Jobs/JobManager.cs index 06a987b251..a3919c8dd2 100644 --- a/src/Tgstation.Server.Host/Jobs/JobManager.cs +++ b/src/Tgstation.Server.Host/Jobs/JobManager.cs @@ -28,6 +28,11 @@ namespace Tgstation.Server.Host.Jobs /// readonly Dictionary jobs; + /// + /// for various operations. + /// + readonly object synchronizationLock; + /// /// Construct a /// @@ -38,6 +43,7 @@ namespace Tgstation.Server.Host.Jobs this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); jobs = new Dictionary(); + synchronizationLock = new object(); } /// @@ -54,7 +60,7 @@ namespace Tgstation.Server.Host.Jobs /// The JobHandler CheckGetJob(Job job) { - lock (this) + lock (synchronizationLock) { if (!jobs.TryGetValue(job.Id, out JobHandler jobHandler)) throw new InvalidOperationException("Job not running!"); @@ -139,7 +145,7 @@ namespace Tgstation.Server.Host.Jobs } finally { - lock (this) + lock (synchronizationLock) { var handler = jobs[job.Id]; jobs.Remove(job.Id); @@ -178,12 +184,12 @@ namespace Tgstation.Server.Host.Jobs var jobHandler = new JobHandler(x => RunJob(job, (jobParam, serviceProvider, ct) => operation(jobParam, serviceProvider, y => { - lock (this) + lock (synchronizationLock) if (jobs.TryGetValue(job.Id, out var handler)) handler.Progress = y; }, ct), x)); - lock (this) + lock (synchronizationLock) jobs.Add(job.Id, jobHandler); }); @@ -264,7 +270,7 @@ namespace Tgstation.Server.Host.Jobs { if (job == null) throw new ArgumentNullException(nameof(job)); - lock (this) + lock (synchronizationLock) { if (!jobs.TryGetValue(job.Id, out var handler)) return null; @@ -280,7 +286,7 @@ namespace Tgstation.Server.Host.Jobs if (canceller == null) throw new ArgumentNullException(nameof(canceller)); JobHandler handler; - lock (this) + lock (synchronizationLock) { if (!jobs.TryGetValue(job.Id, out handler)) return; diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index 675803d370..35af32a33d 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -28,11 +28,6 @@ namespace Tgstation.Server.Host /// readonly IHostBuilder hostBuilder; - /// - /// The for the . - /// - readonly IIOManager ioManager; - /// /// The s to run when the restarts /// @@ -43,6 +38,11 @@ namespace Tgstation.Server.Host /// readonly string updatePath; + /// + /// for certain restart related operations. + /// + readonly object restartLock; + /// /// The for the /// @@ -72,17 +72,16 @@ namespace Tgstation.Server.Host /// Construct a /// /// The value of - /// The value of . /// The value of - public Server(IHostBuilder hostBuilder, IIOManager ioManager, string updatePath) + public Server(IHostBuilder hostBuilder, string updatePath) { this.hostBuilder = hostBuilder ?? throw new ArgumentNullException(nameof(hostBuilder)); - this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.updatePath = updatePath; hostBuilder.ConfigureServices(serviceCollection => serviceCollection.AddSingleton(this)); restartHandlers = new List(); + restartLock = new object(); } /// @@ -133,22 +132,22 @@ namespace Tgstation.Server.Host fsWatcher.EnableRaisingEvents = true; } - using (var host = hostBuilder.Build()) - try + using var host = hostBuilder.Build(); + try + { + logger = host.Services.GetRequiredService>(); + using (cancellationToken.Register(() => logger.LogInformation("Process termination requested!"))) { - logger = host.Services.GetRequiredService>(); - using (cancellationToken.Register(() => logger.LogInformation("Process termination requested!"))) - { - var generalConfigurationOptions = host.Services.GetRequiredService>(); - generalConfiguration = generalConfigurationOptions.Value; - await host.RunAsync(cancellationTokenSource.Token).ConfigureAwait(false); - } - } - catch (Exception ex) - { - CheckExceptionPropagation(ex); - throw; + var generalConfigurationOptions = host.Services.GetRequiredService>(); + generalConfiguration = generalConfigurationOptions.Value; + await host.RunAsync(cancellationTokenSource.Token).ConfigureAwait(false); } + } + catch (Exception ex) + { + CheckExceptionPropagation(ex); + throw; + } } CheckExceptionPropagation(null); @@ -168,7 +167,7 @@ namespace Tgstation.Server.Host logger.LogTrace("Begin ApplyUpdate..."); - lock (this) + lock (restartLock) { if (updating || RestartRequested) { @@ -241,14 +240,14 @@ namespace Tgstation.Server.Host CheckSanity(false); - lock (this) + lock (restartLock) if (!RestartRequested) { logger.LogTrace("Registering restart handler {0}...", handler); restartHandlers.Add(handler); return new RestartRegistration(() => { - lock (this) + lock (restartLock) if (!RestartRequested) restartHandlers.Remove(handler); }); @@ -273,7 +272,7 @@ namespace Tgstation.Server.Host logger.LogTrace("Begin Restart..."); - lock (this) + lock (restartLock) { if ((updating && newVersion == null) || RestartRequested) { diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 5075e72412..0368e13633 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -70,7 +70,7 @@ namespace Tgstation.Server.Host IOManager.ResolvePath( IOManager.GetDirectoryName(assemblyInformationProvider.Path))); - return new Server(hostBuilder, IOManager, updatePath); + return new Server(hostBuilder, updatePath); } } }