/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: ChannelIo.sg // using Microsoft.SingSharp; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Directory; using Microsoft.Singularity.Services.Fat.Contracts; using System; using System.Collections; using System.Threading; namespace Microsoft.Singularity.Services.Fat.Fs { using ThreadPool = FatThreadPool; using DirectoryContract = DirectoryServiceContract; /// /// The ChannelIoFeedbackContract provides a means of /// interrupting the main request dispatcher thread to /// either do useful work or instruct it to stop. /// internal contract ChannelIoFeedBackContract { in message PollWaitingTuples(); out message AckPollWaitingTuples(); state RUNNING : one { PollWaitingTuples? -> AckPollWaitingTuples! -> RUNNING; } } /// /// Tuple for File endpoint and object instance. /// /// Used to store directory endpoint and object when an /// asynchronous command has finished using them. /// internal class DirectoryTuple { TRef dirExpHolder; Directory directory; internal DirectoryTuple([Claims] DirectoryContract.Exp:Ready! dirExp, Directory! directory) { this.dirExpHolder = new TRef(dirExp); this.directory = directory; } internal DirectoryContract.Exp:Ready! AcquireDirectoryEndpoint() { return dirExpHolder.Acquire(); } internal Directory! AcquireDirectory() { assert this.directory != null; Directory! ret = this.directory; this.directory = null; return ret; } } /// /// Tuple for File endpoint and object instance. /// /// Used to store file endpoint and object when an /// asynchronous command has finished using them. /// internal class FileTuple { TRef fileExpHolder; File file; internal FileTuple([Claims] FileContract.Exp:Ready! fileExp, File! file) { this.fileExpHolder = new TRef(fileExp); this.file = file; } internal FileContract.Exp:Ready! AcquireFileEndpoint() { return fileExpHolder.Acquire(); } internal File! AcquireFile() { assert this.file != null; File! ret = this.file; this.file = null; return ret; } } internal sealed class ChannelIo { /////////////////////////////////////////////////////////////////////// // Constants private const int WorkerThreads = 8; private const int MaxWorkItems = 32 * WorkerThreads; /////////////////////////////////////////////////////////////////////// // Member variables TRef mgrExpTRef; TRef spExpTRef; TRef feedbackExpTRef; TRef feedbackImpTRef; Queue fileTupleQueue = new Queue(); Queue dirTupleQueue = new Queue(); ThreadPool threadPool; /////////////////////////////////////////////////////////////////////// // Methods [ Microsoft.Contracts.NotDelayed ] internal ChannelIo( [Claims] FatClientContract.Exp:Running! managerExp, [Claims] ServiceProviderContract.Exp:Start! spExp ) { spExpTRef = new TRef(spExp); mgrExpTRef = new TRef(managerExp); ChannelIoFeedBackContract.Imp! feedbackImp; ChannelIoFeedBackContract.Exp! feedbackExp; ChannelIoFeedBackContract.NewChannel(out feedbackImp, out feedbackExp); feedbackImpTRef = new TRef! fileMap) { lock (fileTupleQueue) { int remain = fileTupleQueue.Count; while (remain-- > 0) { FileTuple! t = (!)(FileTuple)fileTupleQueue.Dequeue(); fileMap.Add(t.AcquireFileEndpoint(), t.AcquireFile()); } } } internal void PollAvailableDirectoryTuples( EMap! directoryMap ) { lock (dirTupleQueue) { int remain = dirTupleQueue.Count; while (remain-- > 0) { DirectoryTuple! t = (!)(DirectoryTuple)dirTupleQueue.Dequeue(); directoryMap.Add(t.AcquireDirectoryEndpoint(), t.AcquireDirectory()); } } } private void EnqueueCommand([Claims] AsyncCommand! command) { threadPool.QueueUserWorkItem(command); } internal void Run() { ChannelIoFeedBackContract.Exp! feedbackExp = feedbackExpTRef.Acquire(); FatClientContract.Exp! managerExp = mgrExpTRef.Acquire(); ServiceProviderContract.Exp! spExp = spExpTRef.Acquire(); EMap dirMap = new EMap(); EMap fileMap = new EMap(); bool shutdown = false; try { while (shutdown == false) { switch receive { // // Process-local feedback messages // case feedbackExp.PollWaitingTuples(): feedbackExp.SendAckPollWaitingTuples(); PollAvailableDirectoryTuples(dirMap); PollAvailableFileTuples(fileMap); break; case feedbackExp.ChannelClosed(): // This should never happen DebugStub.Break(); shutdown = true; break; // // Directory contract endpoint messages // case dirExp.Bind(path, serviceExp) in dirMap ~> dir: EnqueueCommand( new BindCommand(this, dirExp, dir, path, serviceExp) ); break; case dirExp.Notify(path, pattern, announce, notifyImp) in dirMap ~> dir: delete path; delete pattern; dirExp.SendNakNotify( notifyImp, ErrorCode.ContractNotSupported ); dirMap.Add(dirExp, dir); break; case dirExp.BeginEnumeration() in dirMap ~> dir: EnqueueCommand( new EnumerateCommand(this, dirExp, dir) ); break; case dirExp.GetAttributes(path) in dirMap ~> dir: EnqueueCommand( new GetAttributesCommand(this, dirExp, dir, path) ); break; case dirExp.QueryACL(path, effective) in dirMap ~> dir: delete path; dirExp.SendNakQueryACL(ErrorCode.NotSupported); dirMap.Add(dirExp, dir); break; case dirExp.Register(path, childImp) in dirMap ~> dir: delete path; dirExp.SendNakRegister(childImp, ErrorCode.NotSupported); dirMap.Add(dirExp, dir); break; case dirExp.Deregister(path) in dirMap ~> dir: delete path; dirExp.SendNakDeregister(ErrorCode.NotSupported); dirMap.Add(dirExp, dir); break; case dirExp.CreateDirectory(path) in dirMap ~> dir: EnqueueCommand( new CreateDirectoryCommand(this, dirExp, dir, path) ); break; case dirExp.DeleteDirectory(path) in dirMap ~> dir: EnqueueCommand( new DeleteDirectoryCommand(this, dirExp, dir, path) ); break; case dirExp.CreateFile(path) in dirMap ~> dir: EnqueueCommand( new CreateFileCommand(this, dirExp, dir, path) ); break; case dirExp.CreateAndBindFile(path, fileImp) in dirMap ~> dir: EnqueueCommand( new CreateAndBindFileCommand(this, dirExp, dir, path, fileImp) ); break; case dirExp.DeleteFile(path) in dirMap ~> dir: EnqueueCommand( new DeleteFileCommand(this, dirExp, dir, path) ); break; case dirExp.StoreACL(path, aclThis, aclInherited) in dirMap ~> dir: delete path; delete aclThis; delete aclInherited; dirExp.SendNakStoreACL(ErrorCode.NotSupported); dirMap.Add(dirExp, dir); break; case dirExp.CreateLink(linkPath, linkValue) in dirMap ~> dir: delete linkPath; delete linkValue; dirExp.SendNakCreateLink(ErrorCode.NotSupported); dirMap.Add(dirExp, dir); break; case dirExp.DeleteLink(linkPath) in dirMap ~> dir: delete linkPath; dirExp.SendNakDeleteLink(ErrorCode.NotSupported); dirMap.Add(dirExp, dir); break; case dirExp.GetLinkValue(linkPath) in dirMap ~> dir: delete linkPath; dirExp.SendNakGetLinkValue(ErrorCode.NotSupported); dirMap.Add(dirExp, dir); break; case dirExp.ChannelClosed() in dirMap ~> dir: dir.Close(); delete dirExp; break; // // File contract messages // case fileExp.Read(buffer, bufferOffset, fileOffset, maxLength) in fileMap ~> file: EnqueueCommand( new FileReadCommand(this, fileExp, file, buffer, bufferOffset, fileOffset, maxLength) ); break; case fileExp.Write(buffer, bufferOffset, fileOffset, maxLength) in fileMap ~> file: EnqueueCommand( new FileWriteCommand(this, fileExp, file, buffer, bufferOffset, fileOffset, maxLength) ); break; case fileExp.Close() in fileMap ~> file: file.Close(); delete fileExp; break; case fileExp.ChannelClosed() in fileMap ~> file: file.Close(); delete fileExp; break; // // ServiceProvider messages // case spExp.Connect(serviceExp): DirectoryServiceContract.Exp dsExp = serviceExp as DirectoryServiceContract.Exp; if (dsExp == null) { spExp.SendNackConnect(serviceExp); } else { spExp.SendAckConnect(); dsExp.SendSuccess(); dirMap.Add(dsExp, Directory.OpenRootDirectory()); } break; case spExp.ChannelClosed(): DebugStub.Print("ServiceProvider closed.\n"); DebugStub.Break(); break; // // FatClientContract messages // case managerExp.Unmount(force): // We should check whether anyone is using // filesystem before unmounting. shutdown = true; managerExp.SendSuccess(); break; case managerExp.ChannelClosed(): shutdown = true; break; } } this.threadPool.Shutdown(); } finally { delete managerExp; delete spExp; delete feedbackExp; dirMap.Dispose(); fileMap.Dispose(); } } } }