/////////////////////////////////////////////////////////////////////////////// // // 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; } } } }