337 lines
12 KiB
Plaintext
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;
|
||
|
}
|
||
|
}
|
||
|
}
|