public void SaveState(string assembly) { // If we're currently in an event, just tell it to save upon return // if (m_InEvent) { m_SaveState = true; return; } PluginData = AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID); string xml = ScriptSerializer.Serialize(this); if (m_CurrentState != xml) { try { FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state")); System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); Byte[] buf = enc.GetBytes(xml); fs.Write(buf, 0, buf.Length); fs.Close(); } catch (Exception e) { m_log.Error("Unable to save xml\n" + e.ToString()); } //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"))) //{ // throw new Exception("Completed persistence save, but no file was created"); //} m_CurrentState = xml; } }
public string GetXMLState() { bool run = Running; Stop(100); Running = run; // We should not be doing this, but since we are about to // dispose this, it really doesn't make a difference // This is meant to work around a Windows only race // m_InEvent = false; // Force an update of the in-memory plugin data // PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); return(ScriptSerializer.Serialize(this)); }
public void SaveState(string assembly) { // If we're currently in an event, just tell it to save upon return // if (m_InEvent) { m_SaveState = true; return; } PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); string xml = ScriptSerializer.Serialize(this); // Compare hash of the state we just just created with the state last written to disk // If the state is different, update the disk file. UUID hash = UUID.Parse(Utils.MD5String(xml)); if (hash != m_CurrentStateHash) { try { FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")); System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); Byte[] buf = enc.GetBytes(xml); fs.Write(buf, 0, buf.Length); fs.Close(); } catch (Exception) { // m_log.Error("Unable to save xml\n"+e.ToString()); } //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) //{ // throw new Exception("Completed persistence save, but no file was created"); //} m_CurrentStateHash = hash; } }
/********************************************************************************\ * The only method of interest to outside this module is GetExecutionState() * * which captures the current state of the script into an XML document. * * * * The rest of this module contains support routines for GetExecutionState(). * \********************************************************************************/ /** * @brief Create an XML element that gives the current state of the script. * <ScriptState Engine="YEngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID> * <Snapshot>globalsandstackdump</Snapshot> * <Running>m_Running</Running> * <DetectArray ... * <EventQueue ... * <Permissions ... * <Plugins /> * </ScriptState> * Updates the .state file while we're at it. */ public XmlElement GetExecutionState(XmlDocument doc) { // When we're detaching an attachment, we need to wait here. // Change this to a 5 second timeout. If things do mess up, // we don't want to be stuck forever. // m_DetachReady.WaitOne(5000, false); XmlElement scriptStateN = doc.CreateElement("", "ScriptState", ""); scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName); scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString()); scriptStateN.SetAttribute("SourceHash", m_ObjCode.sourceHash); // Make sure we aren't executing part of the script so it stays // stable. Setting suspendOnCheckRun tells CheckRun() to suspend // and return out so RunOne() will release the lock asap. suspendOnCheckRunHold = true; lock (m_RunLock) { m_RunOnePhase = "GetExecutionState enter"; CheckRunLockInvariants(true); // Get copy of script globals and stack in relocateable form. Byte[] snapshotBytes; using (MemoryStream snapshotStream = new MemoryStream()) { MigrateOutEventHandler(snapshotStream); snapshotBytes = snapshotStream.ToArray(); } string snapshotString = Convert.ToBase64String(snapshotBytes); XmlElement snapshotN = doc.CreateElement("", "Snapshot", ""); snapshotN.AppendChild(doc.CreateTextNode(snapshotString)); scriptStateN.AppendChild(snapshotN); m_RunOnePhase = "GetExecutionState B"; CheckRunLockInvariants(true); // "Running" says whether or not we are accepting new events. XmlElement runningN = doc.CreateElement("", "Running", ""); runningN.AppendChild(doc.CreateTextNode(m_Running.ToString())); scriptStateN.AppendChild(runningN); m_RunOnePhase = "GetExecutionState C"; CheckRunLockInvariants(true); // "DoGblInit" says whether or not default:state_entry() will init global vars. XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", ""); doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString())); scriptStateN.AppendChild(doGblInitN); m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true); if (m_XMRLSLApi != null) { double scriptTime = Util.GetTimeStampMS() - m_XMRLSLApi.getLSLTimer(); XmlElement scriptTimeN = doc.CreateElement("", "scrpTime", ""); scriptTimeN.AppendChild(doc.CreateTextNode(scriptTime.ToString())); scriptStateN.AppendChild(scriptTimeN); } if (m_minEventDelay != 0.0) { XmlElement minEventDelayN = doc.CreateElement("", "mEvtDly", ""); minEventDelayN.AppendChild(doc.CreateTextNode(m_minEventDelay.ToString())); scriptStateN.AppendChild(minEventDelayN); m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true); } // More misc data. XmlNode permissionsN = doc.CreateElement("", "Permissions", ""); scriptStateN.AppendChild(permissionsN); XmlAttribute granterA = doc.CreateAttribute("", "granter", ""); granterA.Value = m_Item.PermsGranter.ToString(); permissionsN.Attributes.Append(granterA); XmlAttribute maskA = doc.CreateAttribute("", "mask", ""); maskA.Value = m_Item.PermsMask.ToString(); permissionsN.Attributes.Append(maskA); m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true); // "DetectParams" are returned by llDetected...() script functions // for the currently active event, if any. if (m_DetectParams != null) { XmlElement detParArrayN = doc.CreateElement("", "DetectArray", ""); AppendXMLDetectArray(doc, detParArrayN, m_DetectParams); scriptStateN.AppendChild(detParArrayN); } m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true); // Save any events we have in the queue. // <EventQueue> // <Event Name="..."> // <param>...</param> ... // <DetectParams>...</DetectParams> ... // </Event> // ... // </EventQueue> XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", ""); lock (m_QueueLock) { foreach (EventParams evt in m_EventQueue) { XmlElement singleEventN = doc.CreateElement("", "Event", ""); singleEventN.SetAttribute("Name", evt.EventName); AppendXMLObjectArray(doc, singleEventN, evt.Params, "param"); AppendXMLDetectArray(doc, singleEventN, evt.DetectParams); queuedEventsN.AppendChild(singleEventN); } } scriptStateN.AppendChild(queuedEventsN); m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true); // "Plugins" indicate enabled timers and listens, etc. Object[] pluginData = AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID); XmlNode plugins = doc.CreateElement("", "Plugins", ""); AppendXMLObjectArray(doc, plugins, pluginData, "plugin"); scriptStateN.AppendChild(plugins); m_RunOnePhase = "GetExecutionState H"; CheckRunLockInvariants(true); // Let script run again. suspendOnCheckRunHold = false; m_RunOnePhase = "GetExecutionState leave"; CheckRunLockInvariants(true); } // scriptStateN represents the contents of the .state file so // write the .state file while we are here. using (FileStream fs = File.Create(m_StateFileName)) { using (StreamWriter sw = new StreamWriter(fs)) sw.Write(scriptStateN.OuterXml); } return(scriptStateN); }
public void SaveState() { if (!Running) { return; } // We cannot call this inside the EventQueue lock since it will currently take AsyncCommandManager.staticLock. // This may already be held by AsyncCommandManager.DoOneCmdHandlerPass() which in turn can take EventQueue // lock via ScriptInstance.PostEvent(). PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); // We need to lock here to avoid any race with a thread that is removing this script. lock (EventQueue) { // Check again to avoid a race with a thread in Stop() if (!Running) { return; } // If we're currently in an event, just tell it to save upon return // if (m_InEvent) { m_SaveState = true; return; } // m_log.DebugFormat( // "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}", // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name); string xml = ScriptSerializer.Serialize(this); // Compare hash of the state we just just created with the state last written to disk // If the state is different, update the disk file. UUID hash = UUID.Parse(Utils.MD5String(xml)); if (hash != m_CurrentStateHash) { try { using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state"))) { Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); fs.Write(buf, 0, buf.Length); } } catch (Exception) { // m_log.Error("Unable to save xml\n"+e.ToString()); } //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) //{ // throw new Exception("Completed persistence save, but no file was created"); //} m_CurrentStateHash = hash; } } }