///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Services\ServiceManager\Acceptor.sg
//
// Note: Service Manager Front-End
//
using System;
using System.Collections;
using System.Collections.Specialized;
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
{
///
/// Acceptor is a Service Manager front end. It receives a client's
/// connection request, accepts and then binds it to a worker thread
/// called ServiceController.
///
internal class Acceptor
{
private Thread serviceThread;
private string servicePath;
private IList controllers;
private Object controllersLock;
private TRef leaderTRef;
private TRef terminalTRef;
private TRef providerTRef;
internal Acceptor(string! path)
{
this.servicePath = path;
this.controllers = new ArrayList();
this.controllersLock = new Object();
}
~Acceptor()
{
// Unless Stop is invoked in advance.
if (serviceThread != null) {
Stop();
}
delete providerTRef.Acquire();
}
internal void Start()
{
if (servicePath == null || servicePath == String.Empty) {
throw new Exception("Service is not specified.");
}
RegisterToNameService();
// Initialize the inter-thread channel
ThreadTerminationContract.Imp! leader;
ThreadTerminationContract.Exp! terminal;
ThreadTerminationContract.NewChannel(out leader, out terminal);
leaderTRef = new TRef(leader);
terminalTRef = new TRef(terminal);
if (serviceThread == null) {
serviceThread = new Thread(new ThreadStart(Run));
serviceThread.Start();
DebugStub.Print("Acceptor: {0}\n",
__arglist(serviceThread.ToString()));
}
}
internal void Stop()
{
ThreadTerminationContract.Imp:Start! leader;
leader = leaderTRef.Acquire();
leader.SendStop();
delete leader;
serviceThread.Join();
serviceThread = null;
}
///
/// Service main loop. Deals with client connection requests.
///
private void Run()
{
ServiceProviderContract.Exp:Start! provider;
ThreadTerminationContract.Exp:Start! terminal;
provider = providerTRef.Acquire();
terminal = terminalTRef.Acquire();
for (;;) {
ServiceManagementContract.Exp:Start user;
switch receive {
case provider.RecvConnect(serverEp):
if (serverEp == null) {
continue;
}
user = serverEp as ServiceManagementContract.Exp:Start;
if (user == null) {
provider.SendNackConnect(serverEp);
continue;
}
else {
Thread th = new Thread(new ThreadStart(NewController(user).Run));
th.Start();
provider.SendAckConnect();
}
DebugStub.Print("Acceptor: Client connected.\n");
break;
case provider.ChannelClosed():
Clear();
goto exit;
break;
case terminal.Stop():
Clear();
goto exit;
break;
case terminal.ChannelClosed():
Clear();
goto exit;
break;
}
}
exit:
delete terminal;
DeregisterFromNameService();
delete provider;
}
///
/// Register ServiceControlContract to the name service.
///
protected void RegisterToNameService()
{
bool success;
DirectoryServiceContract.Imp rootNS;
ServiceProviderContract.Imp! providerClient;
ServiceProviderContract.Exp! providerServer;
ServiceProviderContract.NewChannel(out providerClient,
out providerServer);
// SMS is a client of NS.
rootNS = DirectoryService.NewClientEndpoint();
rootNS.SendRegister(Bitter.FromString2(servicePath),
providerClient);
switch receive {
case rootNS.RecvAckRegister():
success = true;
break;
case rootNS.RecvNakRegister(rejected, error):
delete rejected;
success = false;
break;
case rootNS.ChannelClosed():
success = false;
break;
}
delete rootNS;
if (success == false) {
delete providerServer;
DebugStub.Break();
throw new Exception("Name registration failed.");
}
providerTRef = new TRef(providerServer);
DebugStub.WriteLine("SMS: NS Registered.");
}
protected void DeregisterFromNameService()
{
DirectoryServiceContract.Imp rootNS;
rootNS = DirectoryService.NewClientEndpoint();
rootNS.SendDeregister(Bitter.FromString2(servicePath));
switch receive {
case rootNS.AckDeregister(providerClient):
delete providerClient;
break;
case rootNS.NakDeregister(error):
DebugStub.Print("SMS: Deregister failed.\n");
break;
case rootNS.ChannelClosed():
break;
}
delete rootNS;
}
///
/// Create a new ServiceController object.
///
private ServiceController! NewController([Claims]ServiceManagementContract.Exp:Start! ep)
{
ServiceController worker;
worker = new ServiceController(this, ep);
lock (controllersLock) {
controllers.Add(worker);
}
return worker;
}
///
/// Removes the worker from the list when Reception is terminated.
///
internal void ReleaseController(ServiceController worker)
{
lock (controllersLock) {
controllers.Remove(worker);
}
}
private void Clear()
{
lock (controllersLock) {
// Stops all the workers
foreach (ServiceController worker in controllers) {
if (worker == null) {
continue;
}
worker.Stop();
}
controllers.Clear();
controllers = null;
}
}
}
}