singrdk/base/Services/ServiceManager/ResilientService.sg

204 lines
7.7 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Services\ServiceManager\ResilientService.sg
//
// Note:
//
using System;
using System.Threading;
using Microsoft.SingSharp;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.ServiceManager;
namespace Microsoft.Singularity.Services.ServiceManager
{
internal class ResilientService : Service
{
protected JournalService journalService;
protected Object! recoveryLock;
protected TRef<ServiceProxyContract.Imp:Start> proxyRef;
internal ResilientService(string! serviceName,
string! binaryName,
[Claims]DirectoryServiceContract.Imp:Ready! ds,
[Claims]ServiceProxyContract.Imp:Start! sp,
JournalService journal)
{
base(serviceName, binaryName, ServiceType.Resilient, ds);
this.journalService = journal;
this.recoveryLock = new Object();
this.proxyRef = new TRef<ServiceProxyContract.Imp:Start>(sp);
}
internal override ServiceError StartServiceProcess()
{
ServiceError report;
ManagedServiceContract.Imp! msImp;
ManagedServiceContract.Exp! msExp;
DebugStub.Print("RS: Create process '{0}'\n",
__arglist(binaryName));
process = new Process(new String[1]{binaryName}, null, 3);
// Create a channel to the service
ManagedServiceContract.NewChannel(out msImp, out msExp);
if (!process.SetStartupEndpoint(0, (Endpoint * in ExHeap)msExp)) {
DebugStub.Print("Endpoint cannot be set. (ManagedService)\n");
delete msImp;
return ServiceError.TryAgain;
}
if (!process.SetStartupEndpoint(1, (Endpoint * in ExHeap)directory.Acquire())) {
DebugStub.Print("Endpoint cannot be set. " +
"(DirectoryService)\n");
delete msImp;
return ServiceError.TryAgain;
}
if (!process.SetStartupEndpoint(2, (Endpoint * in ExHeap)proxyRef.Acquire())) {
DebugStub.Print("Endpoint cannot be set. (ServiceProxy)\n");
delete msImp;
return ServiceError.TryAgain;
}
DebugStub.Print("RS: start process\n");
process.Start();
// Make sure the process has been started
switch receive {
case msImp.RecvSuccess():
managementEndpoint = new TRef<ManagedServiceContract.Imp:Ready>(msImp);
report = ServiceError.None;
break;
case msImp.ChannelClosed():
DebugStub.Print("Service process's channel is closed.\n");
delete msImp;
report = ServiceError.ChannelClosed;
break;
}
return report;
}
internal override ServiceError RestartServiceProcess()
{
ServiceError report = ServiceError.Unknown;
ManagedServiceContract.Imp! msImp;
ManagedServiceContract.Exp! msExp;
DirectoryServiceContract.Imp! substituteImp;
DirectoryServiceContract.Exp! substituteExp;
ServiceProxyContract.Imp! proxyImp;
ServiceProxyContract.Exp! proxyExp;
DebugStub.Print("ResilientService: ENTER RestartServiceProcess\n");
if (!Monitor.TryEnter(recoveryLock)) {
return ServiceError.TryAgain;
}
DebugStub.Print("RS: Stopping the process ...\n");
process.Stop();
DirectoryServiceContract.NewChannel(out substituteImp,
out substituteExp);
ServiceProxyContract.NewChannel(out proxyImp, out proxyExp);
// Set substituteExp to JournalProducer and check the connection
journalService.TransferDirectoryService(substituteExp, proxyExp);
switch receive {
case substituteImp.RecvSuccess():
report = ServiceError.None;
break;
case substituteImp.ChannelClosed():
report = ServiceError.ChannelClosed;
break;
}
if (report != ServiceError.None) {
delete substituteImp;
delete proxyImp;
goto exit;
}
DebugStub.Print("sub received\n");
DebugStub.Print("RS: creating a new process ... ");
process = new Process(new String[1]{binaryName}, null, 3);
DebugStub.Print("done.\n");
//
// Create a channel to the service
//
ManagedServiceContract.NewChannel(out msImp, out msExp);
if (!process.SetStartupEndpoint(0, (Endpoint * in ExHeap)msExp)) {
DebugStub.Print("Endpoint cannot be set. (ManagedService)\n");
delete msImp;
delete substituteImp;
delete proxyImp;
report = ServiceError.TryAgain;
goto exit;
}
if (!process.SetStartupEndpoint(1, (Endpoint * in ExHeap)substituteImp)) {
DebugStub.Print("Endpoint cannot be set. " +
"(DirectoryService)\n");
delete msImp;
delete proxyImp;
report = ServiceError.TryAgain;
goto exit;
}
if (!process.SetStartupEndpoint(2, (Endpoint * in ExHeap)proxyImp)) {
DebugStub.Print("Endpoint cannot be set. " +
"(ServiceProxy)\n");
delete msImp;
report = ServiceError.TryAgain;
goto exit;
}
DebugStub.Print("RS: Restarting service process ... ");
process.Start();
DebugStub.Print("done.\n");
// Make sure the process has been started
switch receive {
case msImp.RecvSuccess():
// Replace the existing endpoint
managementEndpoint = new TRef<ManagedServiceContract.Imp:Ready>(msImp);
report = ServiceError.None;
break;
case msImp.ChannelClosed():
DebugStub.Print("Service process's channel is closed.\n");
delete msImp;
report = ServiceError.ChannelClosed;
break;
}
exit:
Monitor.Exit(recoveryLock);
DebugStub.Print("RS: Exit RestartServiceProcess\n");
return report;
}
internal override ServiceError RestartService()
{
ServiceError report;
//this.StopService();
// Currently, we don't know what condition the service
// process is, so just kill the process and restart it.
report = RestartServiceProcess();
if (report == ServiceError.None) {
report = StartService();
}
return report;
}
}
}