singrdk/base/Services/ServiceManager/ServiceManager.sg

337 lines
12 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////
//
// 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
{
/// <summary>
/// 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.
/// </summary>
internal class Dir
{
private static TRef<DirectoryServiceContract.Imp:Ready> m_epNS = null;
internal static void SetDirectoryServiceContract([Claims] DirectoryServiceContract.Imp:Ready! imp)
{
assert m_epNS == null;
m_epNS = new TRef<DirectoryServiceContract.Imp:Ready>(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();
}
}
/// <summary>
/// Creates a new service counter part. Creates a process, but doen't
/// start it.
/// </summary>
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);
}
/// <summary>
/// Terminates the specified service process. The corresponding
/// Service object is deleted.
/// </summary>
internal static void ReleaseService(Service s)
{
if (s != null) {
s.StopServiceProcess();
}
}
/// <summary>
/// Terminates all the services. Deletes all the Service objects.
/// </summary>
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();
}
}
}
/// <summary>
/// Returns a Service object if exists, otherwise null.
/// </summary>
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);
}
/// <summary>
/// <b>Deprecated.</b> Creates and start a new <u>unmanaged</u> SIP.
/// </summary>
//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();
}
/// <summary>
/// Start the initial servers that are specified in the manifest file.
/// </summary>
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;
}
}
}