//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: NotifcationManager.sg // // Note: // using System; using System.Text; using System.Collections; using System.Threading; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Directory; #if !SINGULARITY_PROCESS namespace Microsoft.Singularity.Directory #else using Microsoft.Singularity; using Microsoft.Singularity.V1.Services; namespace Microsoft.Application.DSP #endif { public static class NotificationManager { private static object! monitor; private static Queue! requests; private static TRef! notificationExpTRef; private static TRef! notificationImpTRef; private static StringBuilder! sb; private static bool notificationThreadStarted; internal contract NotificationQueueContract { in message WaitForData(); out message AckWaitForData(); state RUNNING : one { WaitForData? -> AckWaitForData! -> RUNNING; } } internal class RequestEntry{ internal DirNode! dir; internal string! name; internal NotifyType type; internal DictionaryEntry trefLoc; public RequestEntry(DirNode! n, string! name, NotifyType type) { this.dir = n; this.name = name; this.type = type; } } public static void Initialize() { requests = new Queue(); monitor = new object(); sb = new StringBuilder(512); notificationThreadStarted = false; // Create an internal contract to communicate with worker thread. // We use a message rather than a monitor so that the worker may // create a set to wait on all its acks and for potential new work. // This is needed because we cannot wait on both events and messages. NotificationQueueContract.Imp! notificationImp; NotificationQueueContract.Exp! notificationExp; NotificationQueueContract.NewChannel(out notificationImp, out notificationExp); notificationImpTRef = new TRef! x = (TRef ) request.trefLoc.Value; x.Release(ep); } } private static void Notify(RequestEntry! request, EMap! notifyEpMap) { if (request.dir.notificationList == null) { return; } foreach (DictionaryEntry n in request.dir.notificationList) { string pattern = (string!) n.Key; bool match = isMatch(request.name,pattern); if (match) { NotifyContract.Imp! notifyEP = ((TRef !) n.Value).Acquire(); assert notifyEP.InState(NotifyContract.Notify.Value); notifyEP.SendChangeNotification(Bitter.FromString2(request.name),request.type); // add ep,request to map request.trefLoc = n; notifyEpMap.Add(notifyEP,request); Tracing.Log(Tracing.Debug,"notifying: pattern="+pattern+" path="+request.name+" type="+request.type); } } //foreach } private static void DequeueWork(EMap! notifyEpMap) { lock (monitor) { int count = requests.Count; for(int i = 0; i < count; i++) { object o = requests.Dequeue(); Notify( (RequestEntry!) o, notifyEpMap); } } } private static void NotificationWorkerMain() { // map to hold tuples EMap notifyEpMap = new EMap(); bool shutdown = false; NotificationQueueContract.Exp internalChannel; internalChannel = notificationExpTRef.Acquire(); // handle initial requests. Entries were added before the // scheduler was started. As a result it was not possible to // send a message. // DequeueWork((!)notifyEpMap); while (shutdown == false) { switch receive { case internalChannel.WaitForData(): DequeueWork(notifyEpMap); internalChannel.SendAckWaitForData(); break; case ep.AckChangeNotification() in notifyEpMap ~> request: // return the tref ReturnTRef(ep, request); break; } } delete internalChannel; notifyEpMap.Dispose(); } } }