singrdk/base/Services/ServiceManager/ServiceController.sg

217 lines
8.8 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Services\ServiceManager\ServiceController.sg
//
// Note: Client counterpart
//
using System;
using System.Collections;
using System.Threading;
using Microsoft.SingSharp;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.ServiceManager;
namespace Microsoft.Singularity.Services.ServiceManager
{
// ServiceController is created per client and provides generic services,
// such as starting a service and enumerating current running services.
// ServiceController is created by ServiceManager when ServiceManager
// accepts a client connection.
internal class ServiceController
{
protected Acceptor acceptor;
protected TRef<ServiceManagementContract.Exp:Ready> endpoint;
protected TRef<ThreadTerminationContract.Imp:Start> sender;
protected TRef<ThreadTerminationContract.Exp:Start> signal;
internal ServiceController(Acceptor acceptor,
[Claims]ServiceManagementContract.Exp:Start! ep)
{
this.acceptor = acceptor;
ep.SendSuccess();
this.endpoint = new TRef<ServiceManagementContract.Exp:Ready>(ep);
ThreadTerminationContract.Imp! imp;
ThreadTerminationContract.Exp! exp;
ThreadTerminationContract.NewChannel(out imp, out exp);
this.sender = new TRef<ThreadTerminationContract.Imp:Start>(imp);
this.signal = new TRef<ThreadTerminationContract.Exp:Start>(exp);
}
internal void Stop()
{
ThreadTerminationContract.Imp! imp;
imp = sender.Acquire();
imp.SendStop();
delete imp;
}
/// <summary>
/// Service main loop.
/// </summary>
internal void Run()
{
ServiceManagementContract.Exp:Ready! ep;
ThreadTerminationContract.Exp:Start! sig;
ep = endpoint.Acquire();
sig = signal.Acquire();
for (;;) {
switch receive {
case ep.Bind(info, control):
{
try {
string name = info->Name;
string binary = info->Binary;
Service service;
DebugStub.Print("Binding '{0}({1})' ... ",
__arglist(name, binary));
// Create a new process
service = ServiceManager.NewService(name,
binary,
info->Type);
if (service != null) {
// Bind the given control to the service
// counterpart. This doesn't start the
// service itself.
service.Start(control);
ep.SendAckBind();
DebugStub.Print(" done.\n");
}
else {
ep.SendNotFound(control);
}
}
catch (ProcessCreateException) {
ep.SendNotFound(control);
}
catch (AccessControlException) {
ep.SendPermissionDenied(control);
}
delete info;
break;
}
case ep.GetControl(id, control):
{
Service service = ServiceManager.GetService(id);
if (service != null) {
if (!service.IsBound()) {
service.Start(control);
ep.SendAckGetControl();
}
else {
ep.SendTryAgain(control);
}
}
else {
ep.SendNotFound(control);
}
break;
}
case ep.Unbind(id):
{
try {
Service service = ServiceManager.GetService(id);
if (service != null) {
if (service.IsBound()) {
ServiceControlContract.Exp:Ready! control;
service.Stop(out control);
// HI: It doesn't check the ownership of
// the control.
ep.SendAckUnbind(control);
}
else {
ep.SendControlNotFound();
}
}
else {
ep.SendServiceNotFound();
}
}
catch (AccessControlException) {
ep.SendControlPermissionDenied();
}
break;
}
case ep.BeginEnumeration():
{
IDictionaryEnumerator controls;
controls = ServiceManager.GetEnumerator();
if (controls == null) {
ep.SendEnumerationTerminated();
}
else {
Service entry = null;
bool next = false;
do {
if (controls.MoveNext() == false) {
ep.SendEnumerationTerminated();
break;
}
entry = (Service)controls.Value;
if (entry == null) {
ep.SendEnumerationTerminated();
break;
}
ServiceInfo* in ExHeap info;
info = new[ExHeap] ServiceInfo(entry.Id,
entry.Name,
entry.Binary,
entry.Type);
ep.SendCurrent(info);
switch receive {
case ep.RecvMoveNext():
next = true;
break;
case ep.RecvEndEnumeration():
next = false;
break;
case ep.ChannelClosed():
next = false;
break;
}
} while (next);
}
break;
}
case ep.ChannelClosed():
{
DebugStub.Print("Controller: Client Channel closed\n");
goto exit;
break;
}
case sig.Stop():
{
sig.SendAckStop();
goto exit;
break;
}
case sig.ChannelClosed():
{
DebugStub.Print("Controller: Signal ch closed\n");
goto exit;
break;
}
}
}
exit:
delete ep;
delete sig;
acceptor.ReleaseController(this);
//DebugStub.Print("Exit Service Controller\n");
}
}
}