/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // using System; using System.Collections; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Directory; using Microsoft.Singularity.V1.Processes; using Microsoft.Singularity.ServiceManager; // //using Microsoft.Singularity.Applications; //using Microsoft.Singularity.Xml; // namespace Microsoft.Singularity.Services.ServiceManager { /// // // This class tracks all of the state relevant to one specific service process // that the Service Manager has created. The Service Manager may create more than // one process for each service, depending on the configuration, load, sanity, etc. // of the service. // // internal sealed class ServiceProcess { public ServiceProcess(Service! service) { this.Service = service; this.State = (ServiceProcessState)(-1); this.controlEndpointState = ControlEndpointState.Disconnected; this.eventChannelState = EventChannelState.Disconnected; this.eventEndpointRef = null; this.Health = ServiceHealth.Unknown; this.Load = ServiceLoad.Unknown; this.dbgprefix = service.dbgprefix; } public string! dbgprefix; private Process process; public Process Process { get { return process; } } public void SetProcess(Process! process) { if (this.Process != null) throw new InvalidOperationException("This ServiceProcess instance already has a system process."); this.process = process; this.dbgprefix = ServiceManager.MakeDbgPrefix(this.Service.ServiceName + "/" + process.Id); } public void ReleaseProcess() { if (this.process != null) { this.process.Dispose(true); this.process = null; } this.dbgprefix = this.Service.dbgprefix; } public readonly Service! Service; public ServiceProcessState State; // public bool IsTerminated; public bool IsDefective; public ServiceHealth Health; public ServiceLoad Load; /// /// This variable only has meaning when _state == ServiceProcessState.Stopping /// public bool NeedSendStopControl; private ControlEndpointState controlEndpointState; private TRef controlEndpointRef; private EventChannelState eventChannelState; private TRef eventEndpointRef; public EventChannelState EventChannelState { get { return eventChannelState; } } private bool currentConnectDirIsSet; private TRef currentConnectDirRef; private string currentConnectSubPath; private DirectoryClientInfo currentConnectDirInfo; private SchedulerTime currentConnectTimeStarted; private SchedulerTime currentConnectTimeRoutedToService; public bool HasCurrentConnectDir { get { return currentConnectDirIsSet; } } public void SetCurrentConnectDir( [Claims]DirectoryServiceContract.Exp:Ready! dir, DirectoryClientInfo! dirinfo, string! subpath, SchedulerTime timeStarted) { if (currentConnectDirIsSet) throw new Exception("The current connect dir client is already set."); currentConnectDirIsSet = true; if (currentConnectDirRef != null) { currentConnectDirRef.Release(dir); } else { currentConnectDirRef = new TRef(dir); } currentConnectSubPath = subpath; currentConnectDirInfo = dirinfo; currentConnectTimeStarted = timeStarted; currentConnectTimeRoutedToService = SchedulerTime.Now; } public void GetCurrentConnectDir( out DirectoryServiceContract.Exp:Ready! dir, out DirectoryClientInfo! dirinfo) { string! subpath; SchedulerTime timeStarted; SchedulerTime timeRoutedToService; GetCurrentConnectDir(out dir, out dirinfo, out subpath, out timeStarted, out timeRoutedToService); } public void GetCurrentConnectDir( out DirectoryServiceContract.Exp:Ready! dir, out DirectoryClientInfo! dirinfo, out string! subpath, out SchedulerTime timeStarted, out SchedulerTime timeRoutedToService) { if (!currentConnectDirIsSet) throw new Exception("The current connect dir client is not set."); assert currentConnectDirRef != null; assert currentConnectSubPath != null; assert currentConnectDirInfo != null; currentConnectDirIsSet = false; dir = currentConnectDirRef.Acquire(); subpath = currentConnectSubPath; dirinfo = currentConnectDirInfo; timeStarted = currentConnectTimeStarted; timeRoutedToService = currentConnectTimeRoutedToService; } public void SetControlEndpoint([Claims]ServiceProcessContract.Imp:Running! svcontrol) { if (controlEndpointState == ControlEndpointState.Ready) { delete svcontrol; throw new InvalidOperationException("Cannot set control endpoint; this service instance already has one."); } controlEndpointState = ControlEndpointState.Ready; if (controlEndpointRef != null) controlEndpointRef.Release(svcontrol); else controlEndpointRef = new TRef(svcontrol); } public void CloseControlEndpoint() { if (controlEndpointState == ControlEndpointState.Ready) { assert controlEndpointRef != null; ServiceProcessContract.Imp! svcontrol = controlEndpointRef.Acquire(); delete svcontrol; } controlEndpointState = ControlEndpointState.Disconnected; } public bool ControlEndpointIsReady { get { return controlEndpointState == ControlEndpointState.Ready; } } public ServiceProcessContract.Imp:Running! GetControlEndpoint(ControlEndpointState nextState) { if (nextState == ControlEndpointState.Ready) throw new ArgumentException("'Ready' is not a valid next state for AcquireControlEndpoint."); if (controlEndpointState != ControlEndpointState.Ready) throw new InvalidOperationException("Cannot acquire control endpoint; none has been set."); assert controlEndpointRef != null; controlEndpointState = nextState; return controlEndpointRef.Acquire(); } public bool EventEndpointIsReady { get { return eventChannelState == EventChannelState.Ready; } } public void SetEventEndpoint([Claims]ServiceEventContract.Exp! notify) { switch (eventChannelState) { case EventChannelState.Ready: // This should not happen! We already have one?! delete notify; throw new InvalidOperationException("Cannot set event endpoint; this service instance already has one."); case EventChannelState.Disconnected: case EventChannelState.WaitingEvent: break; default: throw new InvalidStateException(); } if (eventEndpointRef != null) eventEndpointRef.Release(notify); else eventEndpointRef = new TRef(notify); eventChannelState = EventChannelState.Ready; } public ServiceEventContract.Exp! GetEventEndpoint(EventChannelState nextState) { if (nextState == EventChannelState.Ready) throw new Exception("State 'Ready' is not a valid next state for GetEventEndpoint."); if (eventChannelState != EventChannelState.Ready) throw new InvalidOperationException("Cannot acquire event endpoint; none has been set."); assert eventEndpointRef != null; eventChannelState = nextState; ServiceEventContract.Exp! svevent = eventEndpointRef.Acquire(); return svevent; } public void CloseEventEndpoint() { switch (eventChannelState) { case EventChannelState.Disconnected: break; case EventChannelState.Ready: { assert eventEndpointRef != null; ServiceEventContract.Exp! svevent = eventEndpointRef.Acquire(); delete svevent; eventChannelState = EventChannelState.Disconnected; break; } case EventChannelState.WaitingEvent: eventChannelState = EventChannelState.Disconnected; break; default: throw new InvalidStateException(); } } public void SetEventChannelState(EventChannelState newState) { if (newState == EventChannelState.Ready) throw new ArgumentException("Cannot move event channel state to 'Ready' using this method."); eventChannelState = newState; } public override string! ToString() { if (this.process != null) return String.Format("[pid {0}]", this.process.Id.ToString()); else return "[pid ??]"; } public void Dispose() { if (this.process != null) { this.process.Dispose(true); this.process = null; } CloseEventEndpoint(); } } // The state of the control endpoint. enum ControlEndpointState { Disconnected = 1, Ready, Connecting, Stopping, } enum EventChannelState { /// /// No event channel exists. Either the service is not running, or the service does not /// support an event channel. /// Disconnected = 1, /// /// An event channel exists, and our side of it is parked in Service.eventEndpointRef. /// The GetEventEndpoint method can be used to acquire the endpoint. /// Ready, /// /// The event channel is created, and is in the ServiceManager.svevents endpoint map. /// WaitingEvent, } }