//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Iso9660ControlWorker.sg // // Note: Handles control messages for Iso9660 // using System; using System.IO; using System.Threading; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Io; using Microsoft.Singularity.Directory; namespace Microsoft.Singularity.FileSystem { public enum Iso9660ControlState {Uninitialized, Initialized, Mounted} public class Iso9660ControlWorker { public static bool debug = true; private static bool started = false; private static bool running = true; private static bool success = false; private static bool checkedOut = false; private static Iso9660ControlState controlState = Iso9660ControlState.Uninitialized; private static object startToken = new Object(); private static object lockToken = new Object(); private static string controlPath; private static string mountPath = null; // pivot point for the iso9660 control endpoint private static TRef controlT; public static bool Start(string! controlPath) { Iso9660ControlWorker.controlPath = controlPath; Thread t = new Thread(new ThreadStart(ControlServiceWorker)); t.Start(); lock (startToken) { while (!started) Monitor.Wait(startToken); } return success; } // handles namespace connect requests // makes sure only one client ever has access to the // control channel endpoint // client killing the endpoint returns it to this module private static void ControlServiceWorker() { ServiceProviderContract.Imp! providerClient; ServiceProviderContract.Exp! providerServer; ServiceProviderContract.NewChannel( out providerClient, out providerServer); // start the thread that actually handles control requests Thread t = new Thread(new ThreadStart(ControlWorker)); t.Start(); // register the control channel DirectoryServiceContract.Imp rootNS = DirectoryService.NewClientEndpoint(); if (debug) { DebugStub.Print("FS: Sending control register for "+ controlPath+"\r\n"); } rootNS.SendRegister(Bitter.FromString(controlPath), providerClient); switch receive { case rootNS.AckRegister(): if (debug) { DebugStub.Print("FS: Successfully registered\r\n"); } success = true; break; case rootNS.NakRegister(rejected, error): if (debug) { DebugStub.Print("FS: Failed register\r\n"); } delete rejected; success = false; break; } delete rootNS; lock (startToken) { started = true; Monitor.Pulse(startToken); } if (!success) { delete providerServer; return; } if (debug) { DebugStub.Print("FS: Starting control service "+ "worker loop\r\n"); } while (running) { ServiceContract.Exp:Start! epServer; Iso9660ServiceControlContract.Exp controlServer; // wait for connection message providerServer.RecvConnect(out epServer); controlServer = epServer as Iso9660ServiceControlContract.Exp; // hack to get the thing to stop running lock (lockToken) { if (!running) { providerServer.SendNackConnect(epServer); break; } } if (debug) { DebugStub.Print("FS: received control connect\r\n"); } if (controlServer == null) { // Inappropriate channel type DebugStub.Print("Received improper channel type"); providerServer.SendNackConnect(epServer); } else { lock (lockToken) { if (checkedOut) { if (debug) { DebugStub.Print("FS: control checked out;"+ " sending nack...\r\n"); } providerServer.SendNackConnect(epServer); } else { try { if (debug) { DebugStub.Print( "FS: processing connect\r\n"); } checkedOut = true; controlServer.SendSuccess(); // hand the control channel to the worker thread controlT = new TRef (controlServer); Monitor.Pulse(lockToken); providerServer.SendAckConnect(); } catch (Exception e) { if (debug) { DebugStub.Print( "FS: Caught exception: "+e+"\r\n"); } throw; } } } } } // deregister the control channel rootNS = DirectoryService.NewClientEndpoint(); if (debug) { DebugStub.Print("FS: Sending control deregister for "+ controlPath+"\r\n"); } rootNS.SendDeregister(Bitter.FromString(controlPath)); switch receive { case rootNS.AckDeregister(providerClient2): if (debug) { DebugStub.Print("FS: Successfully deregistered\r\n"); } success = true; delete providerClient2; break; case rootNS.NakDeregister(error): success = false; if (debug) { DebugStub.Print("FS: Failed deregister!!!\r\n"); } break; } delete rootNS; delete providerServer; lock (lockToken) { started = true; Monitor.Pulse(lockToken); } } private static void ControlWorker() { Iso9660ServiceControlContract.Exp control = null; while (running) { lock (lockToken) { while(!checkedOut) {Monitor.Wait(lockToken);} } if (debug) { DebugStub.Print("FS: controlworker triggered\r\n"); } // grab from the pivot point control = controlT.Acquire(); bool inner = true; // while the channel is still active, process while (running && inner) { switch receive { case control.Initialize(char* opt(ExHeap[]) deviceTemp): string device = Bitter.ToString(deviceTemp); delete deviceTemp; if (debug) { DebugStub.Print("FS: Got initialize on "+ device+"\r\n"); } if (controlState != Iso9660ControlState.Uninitialized && controlState != Iso9660ControlState.Initialized) { if (debug) { DebugStub.Print( "FS: Failed to initialize "+ device+" (already initialized)\r\n"); } control.SendNackInitialize(); } else if (controlState == Iso9660ControlState.Initialized) { control.SendAckInitialize(); } else if (Iso9660Init(device)) { if (debug) { DebugStub.Print( "FS: Successfully initialized on "+ device+"\r\n"); } controlState = Iso9660ControlState.Initialized; control.SendAckInitialize(); } else { if (debug) { DebugStub.Print( "FS: Failed to initialize "+ device+"\r\n"); } control.SendNackInitialize(); } break; case control.Mount(char* opt(ExHeap[]) locationTemp): string location = Bitter.ToString(locationTemp); delete locationTemp; if (debug) { DebugStub.Print("FS: Got mount to "+ location+"\r\n"); } if (controlState != Iso9660ControlState.Initialized) { if (debug) { DebugStub.Print( "FS: Failed mount on "+location+ " (not initialized or "+ "already mounted)\r\n"); } control.SendNackMount(); } else if (Mount(location)) { if (debug) { DebugStub.Print( "FS: Successfully mounted "+location+ "\r\n"); } controlState = Iso9660ControlState.Mounted; control.SendAckMount(); } else { if (debug) { DebugStub.Print( "FS: Failed mount on "+location+ "\r\n"); } control.SendNackMount(); } break; case control.Unmount(): if (controlState != Iso9660ControlState.Mounted) { control.SendNackUnmount(); } else { Shutdown(); //controlState = Iso9660ControlState.Initialized; lock (lockToken) { started = false; running = false; } Iso9660ServiceControlContract.Imp! providerClient; Iso9660ServiceControlContract.Exp! providerServer; Iso9660ServiceControlContract.NewChannel( out providerClient, out providerServer); DirectoryServiceContract.Imp rootNS = DirectoryService.NewClientEndpoint(); if (debug) { DebugStub.Print("FS: Triggering control loop to stop\n"); } rootNS.SendBind(Bitter.FromString(controlPath), providerServer); switch receive { case rootNS.NakBind(dummy, code): delete dummy; break; } delete providerClient; delete rootNS; lock (lockToken) { while (!started) { Monitor.Wait(lockToken); } } if (success) { control.SendAckUnmount(); } else { control.SendNackUnmount(); } delete control; return; } break; case control.ChannelClosed(): inner = false; lock (lockToken) { checkedOut = false; } break; case unsatisfiable: // channel killed; fall out inner = false; lock (lockToken) { checkedOut = false; // XXX // delete controlT; } break; } } controlT.Release(control); } } public static bool Iso9660Init(string! device) { long unit = Iso9660.Stdio.RawDevice.LoadDisk(device); if (unit < 0) { Console.WriteLine("LoadDisk " + device + " failed with " + unit ); return false; } return true; } public static bool Mount(string! location) { byte[] superBlock; superBlock = new byte[2048]; DebugStub.Write("Reading root..."); Iso9660.Stdio.RawDevice.ReadBlock(superBlock,16); // 0x01 + "CD001" if (superBlock[0] != (byte)0x01 || superBlock[1] != (byte)0x43 || superBlock[2] != (byte)0x44 || superBlock[3] != (byte)0x30 || superBlock[4] != (byte)0x30 || superBlock[5] != (byte)0x31) { return false; } if (!Iso9660.SuperBlock.Unmarshall(superBlock)) return false; DebugStub.WriteLine("done."); mountPath = location; DebugStub.Write("Starting file instance worker..."); FSFileInstanceWorker.Start(); DebugStub.WriteLine("done."); DebugStub.Write("Starting directory instance worker..."); bool result = FSDirectoryInstanceWorker.Start(location); DebugStub.WriteLine("done."); return result; } public static bool Shutdown() { DebugStub.Write("Terminating directory instance worker..."); FSDirectoryInstanceWorker.Terminate(); DebugStub.WriteLine("done."); DebugStub.Write("Terminating file instance worker..."); FSFileInstanceWorker.Terminate(); DebugStub.WriteLine("done."); return true; } } }