///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Services\Tests\Calculator\ServiceExec.sg
//
// Note: A generic worker-style server implementation
//
using System;
using System.Collections;
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
{
// To inherit this class, what you need to do is:
// 1) To call the base constructor in your constructor.
// 2) To implement Accept and NewWorker methods. This class
// automatically creates and assigns threads to Run method of your
// worker object.
public abstract class WorkerServiceExec : ServiceExec
{
protected IList serviceSignalList;
public WorkerServiceExec([Claims]DirectoryServiceContract.Imp:Ready! ep,
string! path)
{
base(ep, path);
serviceSignalList = new ArrayList();
}
///
/// Checks if the request channel type is acceptable.
///
protected abstract bool Accept(ServiceContract.Exp:Start! ep);
///
/// Create a new worker object for the specified channel. The worker
/// created by this method is assigned to a thread by this class.
///
protected abstract IRunnable NewWorker([Claims]ServiceContract.Exp:Start! ep);
protected override bool Listen(ServiceProviderContract.Exp:Start! provider,
ThreadTerminationContract.Exp:Start! signal)
{
bool result = true;
Thread worker;
switch receive {
case provider.Connect(serviceEp):
{
if (Accept(serviceEp)) {
worker = CreateWorker(serviceEp);
if (worker == null) {
provider.SendNackConnect(null);
}
else {
provider.SendAckConnect();
worker.Start();
}
}
else {
provider.SendNackConnect(serviceEp);
}
break;
}
case provider.ChannelClosed():
{
TerminateWorkers();
result = false;
break;
}
case signal.Stop():
{
TerminateWorkers();
signal.SendAckStop();
result = false;
break;
}
case signal.ChannelClosed():
{
TerminateWorkers();
result = false;
break;
}
}
return result;
}
protected Thread CreateWorker([Claims]ServiceContract.Exp:Start! ep)
{
IRunnable worker;
CPTestContract.Exp:Start! server;
ThreadTerminationContract.Imp! imp;
ThreadTerminationContract.Exp! exp;
worker = NewWorker(ep);
if (worker == null) {
return null;
}
ThreadTerminationContract.NewChannel(out imp, out exp);
worker.Signal(exp);
lock (this) {
serviceSignalList.Add(new TRef(imp));
}
return new Thread(new ThreadStart(worker.Run));
}
private void TerminateWorkers()
{
TRef signalRef;
ThreadTerminationContract.Imp:Start signal;
lock (this) {
foreach (Object obj in serviceSignalList)
{
if (obj != null) {
signalRef = obj
as TRef;
if (signalRef != null) {
signal = signalRef.Acquire();
signal.SendStop();
switch receive {
case signal.AckStop():
break;
case signal.ChannelClosed():
break;
}
signalRef.Release(signal);
}
}
}
serviceSignalList.Clear();
}
}
}
}