private WaitHandle GetExitEvent() { if (OperatingSystemHelper.IsWindowsOS) { return(IpcUtilities.GetShutdownWaitHandle(_scenario)); } else { // Not supported on non-windows OS. Return no-op wait handle. return(CancellationToken.None.WaitHandle); } }
public void SetAndCloseAnOpenHandle() { var identifier = $"{nameof(IpcUtilitiesTests)}.{nameof(SetAndCloseAnOpenHandle)}"; using (var shutdownHandle = IpcUtilities.GetShutdownWaitHandle(identifier)) { // Open the handle, set it, and close it. This should not close the outer handle. IpcUtilities.SetShutdown(identifier).Should().BeTrue(); // Validate the outer handle is set but not closed. shutdownHandle.WaitOne(100).Should().BeTrue(); } }
public void ClosedHandleCannotBeReopened() { var identifier = $"{nameof(IpcUtilitiesTests)}.{nameof(ClosedHandleCannotBeReopened)}"; // Set the shutdown handle and immediately close it IpcUtilities.SetShutdown(identifier).Should().BeTrue(); using (var dupShutdownHandle = IpcUtilities.GetShutdownWaitHandle(identifier)) { // The handle should NOT be set dupShutdownHandle.WaitOne(100).Should().BeFalse(); } }
private static EventWaitHandle CreateShutdownEvent(ILogger logger, string scenario) { var currentUser = UserUtilities.CurrentUserName(); logger.Debug($"Creating shutdown event name=[{scenario}] for user=[{currentUser}]"); var shutdownEvent = IpcUtilities.GetShutdownWaitHandle(scenario); if (shutdownEvent.WaitOne(0)) { shutdownEvent.Dispose(); throw new CacheException($"Shutdown event name=[{scenario}] already exists"); } return(shutdownEvent); }
public void TwoHandlesWithSameNameAreIdentical() { var identifier = $"{nameof(IpcUtilitiesTests)}.{nameof(TwoHandlesWithSameNameAreIdentical)}"; using (var shutdownHandle = IpcUtilities.GetShutdownWaitHandle(identifier)) { // Open the handle for one thread shutdownHandle.Set().Should().BeTrue(); using (var dupShutdownHandle = IpcUtilities.GetShutdownWaitHandle(identifier)) { // Use handle's signal and reset dupShutdownHandle.WaitOne(100).Should().BeTrue(); } } }
internal void Service ( [Description("Cache names")] string[] names, [Description("Cache root paths")] string[] paths, [DefaultValue(DefaultMaxConnections), Description(MaxConnectionsDescription)] uint maxConnections, [DefaultValue(DefaultGracefulShutdownSeconds), Description(GracefulShutdownSecondsDescription)] uint gracefulShutdownSeconds, [DefaultValue(ServiceConfiguration.GrpcDisabledPort), Description(GrpcPortDescription)] int grpcPort, [Description("Name of the memory mapped file used to share GRPC port. 'CASaaS GRPC port' if not specified.")] string grpcPortFileName, [DefaultValue(null), Description("Writable directory for service operations (use CWD if null)")] string dataRootPath, [DefaultValue(null), Description("Duration of inactivity after which a session will be timed out.")] double?unusedSessionTimeoutSeconds, [DefaultValue(null), Description("Duration of inactivity after which a session with a heartbeat will be timed out.")] double?unusedSessionHeartbeatTimeoutSeconds, [DefaultValue(false), Description("Stop running service")] bool stop, [DefaultValue(Constants.OneMB), Description("Max size quota in MB")] int maxSizeQuotaMB ) { Initialize(); if (stop) { IpcUtilities.SetShutdown(_scenario); return; } if (names == null || paths == null) { throw new CacheException("At least one cache name/path is required."); } if (names.Length != paths.Length) { throw new CacheException("Mismatching lengths of names/paths arguments."); } var caches = new Dictionary <string, string>(); for (var i = 0; i < names.Length; i++) { caches.Add(names[i], paths[i]); } var serverDataRootPath = !string.IsNullOrWhiteSpace(dataRootPath) ? new AbsolutePath(dataRootPath) : new AbsolutePath(Environment.CurrentDirectory); var cancellationTokenSource = new CancellationTokenSource(); #if !FEATURE_CORECLR var configuration = new ServiceConfiguration(caches, serverDataRootPath, maxConnections, gracefulShutdownSeconds, grpcPort, grpcPortFileName); if (!configuration.IsValid) { throw new CacheException($"Invalid service configuration, error=[{configuration.Error}]"); } var localContentServerConfiguration = new LocalServerConfiguration(configuration); if (unusedSessionTimeoutSeconds != null) { localContentServerConfiguration.UnusedSessionTimeout = TimeSpan.FromSeconds(unusedSessionTimeoutSeconds.Value); } if (unusedSessionHeartbeatTimeoutSeconds != null) { localContentServerConfiguration.UnusedSessionHeartbeatTimeout = TimeSpan.FromSeconds(unusedSessionHeartbeatTimeoutSeconds.Value); } if (_scenario != null) { _logger.Debug($"scenario=[{_scenario}]"); } var exitSignal = new ManualResetEvent(false); Console.CancelKeyPress += (sender, args) => { exitSignal.Set(); args.Cancel = true; }; using (var exitEvent = IpcUtilities.GetShutdownWaitHandle(_scenario)) { var server = new LocalContentServer( _fileSystem, _logger, _scenario, path => new FileSystemContentStore( _fileSystem, SystemClock.Instance, path, new ConfigurationModel(inProcessConfiguration: ContentStoreConfiguration.CreateWithMaxSizeQuotaMB((uint)maxSizeQuotaMB))), localContentServerConfiguration); using (server) { var context = new Context(_logger); try { var result = server.StartupAsync(context).Result; if (!result.Succeeded) { throw new CacheException(result.ErrorMessage); } int completedIndex = WaitHandle.WaitAny(new WaitHandle[] { exitSignal, exitEvent }); var source = completedIndex == 0 ? "control-C" : "exit event"; _tracer.Always(context, $"Shutdown by {source}."); } finally { var result = server.ShutdownAsync(context).Result; if (!result.Succeeded) { _tracer.Warning(context, $"Failed to shutdown store: {result.ErrorMessage}"); } } } } #else Console.CancelKeyPress += (sender, args) => { cancellationTokenSource.Cancel(); args.Cancel = true; }; var localCasSettings = LocalCasSettings.Default(maxSizeQuotaMB, serverDataRootPath.Path, names[0], (uint)grpcPort); var distributedContentSettings = DistributedContentSettings.CreateDisabled(); var distributedCacheServiceConfiguration = new DistributedCacheServiceConfiguration(localCasSettings, distributedContentSettings); // Ensure the computed keyspace is computed based on the hostInfo's StampId distributedCacheServiceConfiguration.UseStampBasedIsolation = false; var distributedCacheServiceArguments = new DistributedCacheServiceArguments( logger: _logger, copier: null, pathTransformer: null, host: new EnvironmentVariableHost(), hostInfo: new HostInfo(null, null, new List <string>()), cancellation: cancellationTokenSource.Token, dataRootPath: serverDataRootPath.Path, configuration: distributedCacheServiceConfiguration, keyspace: null); DistributedCacheServiceFacade.RunAsync(distributedCacheServiceArguments).GetAwaiter().GetResult(); // Because the facade completes immediately and named wait handles don't exist in CORECLR, // completion here is gated on Control+C. In the future, this can be redone with another option, // such as a MemoryMappedFile or GRPC heartbeat. This is just intended to be functional. cancellationTokenSource.Token.WaitHandle.WaitOne(); #endif }