/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Services\ServiceManager\ServiceManager.sg // // Note: Service Manager main program // using System; using System.Collections; using System.Collections.Specialized; using System.Threading; using Microsoft.Contracts; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Applications; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Configuration; using Microsoft.Singularity.Directory; using Microsoft.Singularity.Security; using Microsoft.Singularity.ServiceManager; using Microsoft.Singularity.Xml; [assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] [assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] namespace Microsoft.Singularity.Services.ServiceManager { /// /// The following class caches the directory service endpoint passed in /// at startup in slot 0. SetDirectoryServiceContract is called by /// Main() to initialize the cache. This is used repeatedly to read the /// manifests of the service to be started. /// internal class Dir { private static TRef m_epNS = null; internal static void SetDirectoryServiceContract([Claims] DirectoryServiceContract.Imp:Ready! imp) { assert m_epNS == null; m_epNS = new TRef(imp); } internal static DirectoryServiceContract.Imp:Ready! GetDirectoryServiceContract() { if (m_epNS == null) { DebugStub.Break(); } return m_epNS.Acquire(); } internal static void ReleaseDirectoryServiceContract([Claims] DirectoryServiceContract.Imp:Ready! imp) { m_epNS.Release(imp); } } internal sealed class ServiceManager { private static IDictionary serviceList; private static Object serviceListLock; internal static void Initialize() { if (serviceList == null) { serviceList = new ListDictionary(); serviceListLock = new Object(); } } /// /// Creates a new service counter part. Creates a process, but doen't /// start it. /// internal static Service NewService(string! serviceName, string! binaryName, ServiceType creatorType) { DirectoryServiceContract.Imp ds; Service service; IServiceProduceable creator; // look at the manifest and see if the entity to be started is // indeed a service. ds = Dir.GetDirectoryServiceContract(); Manifest manifest = Binder.LoadManifest(ds, binaryName); Dir.ReleaseDirectoryServiceContract(ds); if (manifest == null) { DebugStub.WriteLine("No manifest present for {0}", __arglist(binaryName)); return null; } XmlNode category = manifest.GetCategoryNodeByName("Service"); if (category == null) { DebugStub.WriteLine("Service Category node not present " + "in manifest for {0}", __arglist(binaryName)); return null; } switch (creatorType) { case ServiceType.Default: DebugStub.Print("Create Default service\n"); creator = new DefaultServiceCreator(); break; case ServiceType.Resilient: DebugStub.Print("Create Resilient service\n"); creator = new ResilientServiceCreator(); break; default: DebugStub.Break(); return null; break; } return creator.NewService(serviceName, binaryName); } /// /// Terminates the specified service process. The corresponding /// Service object is deleted. /// internal static void ReleaseService(Service s) { if (s != null) { s.StopServiceProcess(); } } /// /// Terminates all the services. Deletes all the Service objects. /// internal static void Clear() { if (serviceListLock != null) { lock (serviceListLock) { foreach (DictionaryEntry entry in serviceList) { Service service = (Service)entry.Value; if (service != null) { ServiceControlContract.Exp:Ready! dummy; service.Stop(out dummy); delete dummy; } } serviceList.Clear(); } } } /// /// Returns a Service object if exists, otherwise null. /// internal static Service GetService(int id) { if (serviceListLock != null) { lock (serviceListLock) { return (Service)serviceList[id]; } } return null; } internal static IDictionaryEnumerator GetEnumerator() { if (serviceList != null) { return serviceList.GetEnumerator(); } else { return null; } } internal static bool Register(Service! s) { bool result; if (serviceListLock != null) { lock (serviceListLock) { try { serviceList.Add(s.Id, s); result = true; } catch (ArgumentNullException) { result = false; } catch (ArgumentException e) { DebugStub.WriteLine("ServiceManager.sg: " + e.ToString() + " " + s.Id); result = false; } } DebugStub.Print("SMS: Register {0}\n", __arglist(s.Id)); } else { DebugStub.Print("ServiceManager.sg: lock is uninitialized.\n"); result = false; } return result; } internal static void Deregister(int id) { if (serviceListLock != null) { lock (serviceListLock) { DebugStub.Print("SMS: Deregister {0}\n", __arglist(id)); serviceList.Remove(id); } } else { DebugStub.Print("ServiceManager.sg: lock is uninitialized.\n"); } } internal static void Deregister(Service! s) { Deregister(s.Id); } /// /// Deprecated. Creates and start a new unmanaged SIP. /// //TODO: Deprecated. Merge this to StartService. internal static void StartServiceSimple(string! name) { Process process = null; string[] arg = { name }; try { process = new Process(arg, null, 0); } catch (ProcessCreateException) { DebugStub.Print("SMS: Process creation failed\n"); throw; } process.Start(); } /// /// Start the initial servers that are specified in the manifest file. /// internal static void StartInitialServices(string[]! list) { try { for (int i = 1; i < list.Length - 1; i += 3) { string serviceName = list[i]; string binaryName = list[i + 1]; string mode = list[i + 2]; ServiceType type = ServiceType.Default; //TODO: if (serviceName == null || binaryName == null || mode == null) { DebugStub.Print("SMS init: service is null\n"); continue; } DebugStub.Print("SMS: Start " + serviceName + "(" + mode + ")\n"); Tracing.Log(Tracing.Audit, "SMS: Initializing " + serviceName); if (mode == "managed") { Service service = NewService(serviceName, binaryName, type); if (service == null) { DebugStub.Print("SMS: failed.\n"); DebugStub.Break(); } else { service.StartServiceProcess(); } } else if (mode == "unmanaged") { //TODO: This is going to be merged above. StartServiceSimple(binaryName); } else { DebugStub.Print("Unknown mode: " + serviceName + "(" + mode + ") is not launched.\n"); } } } catch (ProcessCreateException) { DebugStub.Print("SMS: Service initialization failed."); } } public static int Main(string[]! args) { int res = 1; Endpoint * in ExHeap initialEp; DirectoryServiceContract.Imp ep; initialEp = Process.GetStartupEndpoint(0); if (initialEp == null) { DebugStub.WriteLine("Unable to get directory service contract!"); DebugStub.Break(); return -1; } ep = initialEp as DirectoryServiceContract.Imp; if (ep == null) { DebugStub.WriteLine("Startup endpoint is not a directory service contract!"); DebugStub.Break(); delete initialEp; return -1; } Dir.SetDirectoryServiceContract(ep); try { ServiceManager.Initialize(); if (args.Length > 1) { ServiceManager.StartInitialServices(args); } Acceptor acceptor = new Acceptor(ServiceManagementContract.ModuleName); acceptor.Start(); res = 0; } catch (Exception e) { DebugStub.Print("SMS: Exception caught at the top level\n"); Console.WriteLine(e); } return res; } } }