393 lines
15 KiB
Plaintext
393 lines
15 KiB
Plaintext
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: FSDirectoryInstanceWorker.sg
|
||
|
//
|
||
|
// Note: Handles servicing directory requests for all active directories
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using System.Threading;
|
||
|
using Microsoft.SingSharp;
|
||
|
using Microsoft.Singularity.Channels;
|
||
|
using Microsoft.Singularity.Directory;
|
||
|
using Microsoft.Singularity.Security;
|
||
|
using Microsoft.Singularity;
|
||
|
|
||
|
|
||
|
using Iso9660;
|
||
|
|
||
|
namespace Microsoft.Singularity.FileSystem
|
||
|
{
|
||
|
public class FSDirectoryInstanceWorker
|
||
|
{
|
||
|
private static string location;
|
||
|
private static bool started = false;
|
||
|
private static bool terminating = false;
|
||
|
private static bool success = false;
|
||
|
private static bool endpointCaptured = false;
|
||
|
private static bool endpointAvailable = true;
|
||
|
private static object lockToken = new Object();
|
||
|
private static Iso9660DirectoryInfo pendingDir;
|
||
|
private static TRef<DirectoryServiceContract.Exp:Ready>
|
||
|
pendingEPT = null;
|
||
|
private static TRef<ThreadPoolControlContract.Imp:Start> signalEPT;
|
||
|
public static FSThreadPool threadPool;
|
||
|
|
||
|
public static bool Start(string mountLocation)
|
||
|
{
|
||
|
started = false;
|
||
|
terminating = false;
|
||
|
location = mountLocation;
|
||
|
threadPool =
|
||
|
new FSThreadPool(1, new FSThreadPoolCallback(ProcessRequest));
|
||
|
Thread t = new Thread(new ThreadStart(Run));
|
||
|
t.Start();
|
||
|
lock (lockToken) {
|
||
|
while (!started) Monitor.Wait(lockToken);
|
||
|
}
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
public static bool TrackEndpoint(
|
||
|
[Claims] DirectoryServiceContract.Exp:Ready s,
|
||
|
Iso9660DirectoryInfo dir) {
|
||
|
|
||
|
Monitoring.Log(Monitoring.Provider.Iso9660,
|
||
|
(ushort)FileSystemEvent.StartTrackEndpoint);
|
||
|
|
||
|
lock (lockToken) {
|
||
|
while (!endpointAvailable && !terminating) {
|
||
|
Monitor.Wait(lockToken);
|
||
|
}
|
||
|
if (terminating) {
|
||
|
delete s;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
endpointAvailable = false;
|
||
|
endpointCaptured = false;
|
||
|
pendingDir = dir;
|
||
|
pendingEPT = new TRef<DirectoryServiceContract.Exp:Ready>(s);
|
||
|
ThreadPoolControlContract.Imp signalEP = signalEPT.Acquire();
|
||
|
signalEP.SendTrackEndpoint();
|
||
|
//signalEP.RecvAckTrackEndpoint();
|
||
|
while (!endpointCaptured && !terminating) {
|
||
|
Monitor.Wait(lockToken);
|
||
|
}
|
||
|
|
||
|
endpointAvailable = true;
|
||
|
Monitor.PulseAll(lockToken);
|
||
|
if (pendingEPT != null) {
|
||
|
signalEPT.Release(signalEP);
|
||
|
delete pendingEPT.Acquire();
|
||
|
return false;
|
||
|
} else {
|
||
|
signalEP.RecvAckTrackEndpoint();
|
||
|
signalEPT.Release(signalEP);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
Monitoring.Log(Monitoring.Provider.Iso9660,
|
||
|
(ushort)FileSystemEvent.StopTrackEndpoint);
|
||
|
|
||
|
}
|
||
|
|
||
|
public static void Terminate() {
|
||
|
lock (lockToken) {
|
||
|
ThreadPoolControlContract.Imp signalEP = signalEPT.Acquire();
|
||
|
signalEP.SendTerminate();
|
||
|
while (!terminating) {
|
||
|
Monitor.Wait(lockToken);
|
||
|
}
|
||
|
signalEP.RecvAckTerminate();
|
||
|
started = false;
|
||
|
delete signalEP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// worker thread that actually services requests
|
||
|
protected static void Run()
|
||
|
{
|
||
|
ServiceProviderContract.Imp! spClient;
|
||
|
ServiceProviderContract.Exp! spServer;
|
||
|
ServiceProviderContract.NewChannel(out spClient, out spServer);
|
||
|
|
||
|
DirectoryServiceContract.Imp systemNS = DirectoryService.NewClientEndpoint();
|
||
|
systemNS.SendRegister(Bitter.FromString2(location), spClient);
|
||
|
|
||
|
switch receive {
|
||
|
case systemNS.AckRegister():
|
||
|
success = true;
|
||
|
break;
|
||
|
|
||
|
case systemNS.NakRegister(rejected, error):
|
||
|
delete rejected;
|
||
|
success = false;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
delete systemNS;
|
||
|
|
||
|
lock (lockToken) {
|
||
|
started = true;
|
||
|
Monitor.Pulse(lockToken);
|
||
|
}
|
||
|
|
||
|
if (!success) {
|
||
|
delete spServer;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
EMap<DirectoryServiceContract.Exp:Ready,
|
||
|
Iso9660DirectoryInfo> dirSet =
|
||
|
new EMap<DirectoryServiceContract.Exp:Ready,
|
||
|
Iso9660DirectoryInfo>();
|
||
|
ThreadPoolControlContract.Imp! imp;
|
||
|
ThreadPoolControlContract.Exp! exp;
|
||
|
ThreadPoolControlContract.NewChannel(out imp, out exp);
|
||
|
signalEPT = new TRef<ThreadPoolControlContract.Imp:Start>(imp);
|
||
|
//EMap<FileContract.Exp:Ready, Iso9660DirectoryInfo> dirSet;
|
||
|
|
||
|
lock (lockToken) {
|
||
|
endpointAvailable = true;
|
||
|
started = true;
|
||
|
Monitor.Pulse(lockToken);
|
||
|
}
|
||
|
|
||
|
for (bool run = true; run;)
|
||
|
{
|
||
|
//dirSet = dirSetT.Acquire();
|
||
|
byte[] buf;
|
||
|
switch receive
|
||
|
{
|
||
|
case spServer.Connect(candidate) :
|
||
|
// the directory server is trying to connect
|
||
|
// with a DirectoryServiceContract endpoint
|
||
|
DirectoryServiceContract.Exp dsClient = candidate as DirectoryServiceContract.Exp;
|
||
|
if (null == dsClient){
|
||
|
spServer.SendNackConnect(candidate);
|
||
|
break;
|
||
|
}
|
||
|
spServer.SendAckConnect();
|
||
|
dsClient.SendSuccess();
|
||
|
dirSet.Add(dsClient, SuperBlock.Root);
|
||
|
break;
|
||
|
|
||
|
case exp.TrackEndpoint():
|
||
|
lock (lockToken) {
|
||
|
|
||
|
endpointCaptured = true;
|
||
|
if (!terminating) {
|
||
|
DirectoryServiceContract.Exp newEP = pendingEPT.Acquire();
|
||
|
dirSet.Add(newEP, pendingDir);
|
||
|
pendingEPT = null;
|
||
|
}
|
||
|
exp.SendAckTrackEndpoint();
|
||
|
Monitor.PulseAll(lockToken);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case exp.Terminate():
|
||
|
lock (lockToken) {
|
||
|
terminating = true;
|
||
|
threadPool.KillPool();
|
||
|
Monitor.PulseAll(lockToken);
|
||
|
}
|
||
|
exp.SendAckTerminate();
|
||
|
run = false;
|
||
|
break;
|
||
|
|
||
|
case ep.Bind(char[]! in ExHeap pathTemp,
|
||
|
ServiceContract.Exp:Start! serviceServer) in dirSet~>dir :
|
||
|
|
||
|
string path = Bitter.ToString(pathTemp);
|
||
|
delete pathTemp;
|
||
|
|
||
|
if (path == null) {
|
||
|
path = "";
|
||
|
}
|
||
|
|
||
|
threadPool.EnqueueItem(
|
||
|
new FSBindRequestInfo(
|
||
|
FSRequestAction.Bind,
|
||
|
new TRef<DirectoryServiceContract.Exp:Ready>(ep),
|
||
|
new TRef<ServiceContract.Exp:Start>(serviceServer),
|
||
|
dir,
|
||
|
path));
|
||
|
break;
|
||
|
|
||
|
case ep.BeginEnumeration()
|
||
|
in dirSet~>dir:
|
||
|
|
||
|
threadPool.EnqueueItem(
|
||
|
new FSDirectoryRequestInfo(
|
||
|
FSRequestAction.BeginEnumeration,
|
||
|
new TRef<
|
||
|
DirectoryServiceContract.Exp:Ready>(ep),
|
||
|
dir,
|
||
|
null));
|
||
|
break;
|
||
|
|
||
|
case ep.GetAttributes(char []! in ExHeap fileNameTemp)
|
||
|
in dirSet~>dir:
|
||
|
Iso9660FileSystemInfo info;
|
||
|
string fileName = Bitter.ToString(fileNameTemp);
|
||
|
delete fileNameTemp;
|
||
|
|
||
|
threadPool.EnqueueItem(
|
||
|
new FSDirectoryRequestInfo(
|
||
|
FSRequestAction.GetAttributes,
|
||
|
new TRef<DirectoryServiceContract.Exp:Ready>(ep),
|
||
|
dir,
|
||
|
fileName));
|
||
|
break;
|
||
|
|
||
|
case ep.ChannelClosed() in dirSet~>dir:
|
||
|
delete ep;
|
||
|
break;
|
||
|
|
||
|
case unsatisfiable:
|
||
|
//DebugStub.Print("FSFileWorker shutting down\n");
|
||
|
run = false;
|
||
|
break;
|
||
|
//return;
|
||
|
}//switch
|
||
|
//dirSetT.Release(dirSet);
|
||
|
} //for
|
||
|
|
||
|
dirSet.Dispose();
|
||
|
delete exp;
|
||
|
delete spServer;
|
||
|
} //run
|
||
|
|
||
|
protected static void ProcessRequest(FSRequestInfo request) {
|
||
|
FSDirectoryRequestInfo info;
|
||
|
DirectoryServiceContract.Exp ep;
|
||
|
Iso9660FileSystemInfo child;
|
||
|
|
||
|
switch (request.action) {
|
||
|
case FSRequestAction.Bind:
|
||
|
|
||
|
Monitoring.Log(Monitoring.Provider.Iso9660,
|
||
|
(ushort)FileSystemEvent.StartBind);
|
||
|
FSBindRequestInfo bindInfo = (FSBindRequestInfo)request;
|
||
|
ep = bindInfo.endpointT.Acquire();
|
||
|
Iso9660FileSystemInfo fsInfo = Iso9660FileSystemInfo.InstantiatePath
|
||
|
(bindInfo.path, bindInfo.startingDir);
|
||
|
|
||
|
// This var serves to track whether we have given away the
|
||
|
// endpoint or not.
|
||
|
ServiceContract.Exp localServiceServer =
|
||
|
bindInfo.bindEndpointT.Acquire();
|
||
|
|
||
|
if (fsInfo is Iso9660FileInfo) {
|
||
|
FileContract.Exp fileServer =
|
||
|
localServiceServer as FileContract.Exp;
|
||
|
|
||
|
if (fileServer != null) {
|
||
|
Iso9660FileStream fileStream =
|
||
|
((Iso9660FileInfo)fsInfo).Open(
|
||
|
System.IO.FileMode.Open,
|
||
|
System.IO.FileAccess.Read);
|
||
|
|
||
|
fileServer.SendSuccess();
|
||
|
FSFileInstanceWorker.TrackEndpoint(
|
||
|
fileServer, fileStream);
|
||
|
localServiceServer = null; // Gave it away
|
||
|
}
|
||
|
} else if (fsInfo is Iso9660DirectoryInfo) {
|
||
|
DirectoryServiceContract.Exp dirServer =
|
||
|
localServiceServer as DirectoryServiceContract.Exp;
|
||
|
|
||
|
if (dirServer != null) {
|
||
|
dirServer.SendSuccess();
|
||
|
//FSDirectoryInstanceWorker.TrackEndpoint(
|
||
|
// dirServer, (Iso9660DirectoryInfo)fsInfo);
|
||
|
TrackEndpoint(dirServer, (Iso9660DirectoryInfo)fsInfo);
|
||
|
localServiceServer = null; // Gave it away
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (localServiceServer == null) { // Did we give it away?
|
||
|
// If so, success
|
||
|
ep.SendAckBind();
|
||
|
} else {
|
||
|
// We didn't give it away, so give it back.
|
||
|
ep.SendNakBind(localServiceServer, ErrorCode.NotFound);
|
||
|
}
|
||
|
TrackEndpoint(ep, bindInfo.startingDir);
|
||
|
Monitoring.Log(Monitoring.Provider.Iso9660,
|
||
|
(ushort)FileSystemEvent.StopBind);
|
||
|
break;
|
||
|
|
||
|
case FSRequestAction.BeginEnumeration :
|
||
|
info = (FSDirectoryRequestInfo)request;
|
||
|
ep = info.endpointT.Acquire();
|
||
|
EnumerationRecords[] in ExHeap responses = null;
|
||
|
|
||
|
// use the root
|
||
|
ErrorCode errorOut;
|
||
|
responses = info.dir.Enumerate(out errorOut);
|
||
|
if (null == responses) {
|
||
|
ep.SendEnumerationTerminated(errorOut);
|
||
|
delete responses;
|
||
|
} else {
|
||
|
ep.SendEnumerationEntries(responses,false);
|
||
|
}
|
||
|
TrackEndpoint(ep, info.dir);
|
||
|
break;
|
||
|
|
||
|
case FSRequestAction.GetAttributes:
|
||
|
info = (FSDirectoryRequestInfo)request;
|
||
|
ep = info.endpointT.Acquire();
|
||
|
Iso9660FileSystemInfo file = Iso9660FileSystemInfo.InstantiatePath(info.name, info.dir);
|
||
|
if (file == null) {
|
||
|
//if (!info.dir.FindChild(info.name, true, out file)) {
|
||
|
ep.SendNakGetAttributes(ErrorCode.Unknown);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
long len = 0;
|
||
|
if (file is Iso9660FileInfo)
|
||
|
{
|
||
|
#if WHAT_FOR?
|
||
|
Iso9660FileStream fileStream =
|
||
|
((Iso9660FileInfo)file).Open(
|
||
|
System.IO.FileMode.Open,
|
||
|
System.IO.FileAccess.Read);
|
||
|
len = fileStream.Length;
|
||
|
#else
|
||
|
len = (long)((Iso9660FileInfo)file).size;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
NodeType nodeType = NodeType.File;
|
||
|
|
||
|
// Translate flags
|
||
|
if ((file.flags & (byte)Iso9660FileFlags.Directory) != 0) {
|
||
|
nodeType = NodeType.Directory;
|
||
|
}
|
||
|
|
||
|
// Unprocessed: System, Archive
|
||
|
|
||
|
ep.SendAckGetAttributes(nodeType, len);
|
||
|
}
|
||
|
|
||
|
TrackEndpoint(ep, info.dir);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// Should be impossible
|
||
|
System.Diagnostics.Debug.Assert(false);
|
||
|
break;
|
||
|
} // switch
|
||
|
} // ProcessRequest
|
||
|
} //FSFileWorker class
|
||
|
} //namespace
|
||
|
|