146 lines
5.0 KiB
Plaintext
146 lines
5.0 KiB
Plaintext
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the request channel type is acceptable.
|
|
/// </summary>
|
|
protected abstract bool Accept(ServiceContract.Exp:Start! ep);
|
|
|
|
/// <summary>
|
|
/// Create a new worker object for the specified channel. The worker
|
|
/// created by this method is assigned to a thread by this class.
|
|
/// </summary>
|
|
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<ThreadTerminationContract.Imp:Start>(imp));
|
|
}
|
|
return new Thread(new ThreadStart(worker.Run));
|
|
}
|
|
|
|
private void TerminateWorkers()
|
|
{
|
|
TRef<ThreadTerminationContract.Imp:Start> signalRef;
|
|
ThreadTerminationContract.Imp:Start signal;
|
|
|
|
lock (this) {
|
|
foreach (Object obj in serviceSignalList)
|
|
{
|
|
if (obj != null) {
|
|
signalRef = obj
|
|
as TRef<ThreadTerminationContract.Imp:Start>;
|
|
if (signalRef != null) {
|
|
signal = signalRef.Acquire();
|
|
signal.SendStop();
|
|
switch receive {
|
|
case signal.AckStop():
|
|
break;
|
|
case signal.ChannelClosed():
|
|
break;
|
|
}
|
|
signalRef.Release(signal);
|
|
}
|
|
}
|
|
}
|
|
serviceSignalList.Clear();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|