aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs403
1 files changed, 403 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs
new file mode 100644
index 0000000..ed33108
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs
@@ -0,0 +1,403 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30using System.IO;
31using System.Xml;
32using OpenSim.Region.ScriptEngine.Shared;
33using OpenSim.Region.ScriptEngine.Shared.Api;
34using log4net;
35
36using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
37using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
38using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
39using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
40using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
41using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
42using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
43
44namespace OpenSim.Region.ScriptEngine.XMREngine
45{
46 public partial class XMRInstance
47 {
48 /********************************************************************************\
49 * The only method of interest to outside this module is GetExecutionState() *
50 * which captures the current state of the script into an XML document. *
51 * *
52 * The rest of this module contains support routines for GetExecutionState(). *
53 \********************************************************************************/
54
55 /**
56 * @brief Create an XML element that gives the current state of the script.
57 * <ScriptState Engine="XMREngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID>
58 * <Snapshot>globalsandstackdump</Snapshot>
59 * <Running>m_Running</Running>
60 * <DetectArray ...
61 * <EventQueue ...
62 * <Permissions ...
63 * <Plugins />
64 * </ScriptState>
65 * Updates the .state file while we're at it.
66 */
67 public XmlElement GetExecutionState(XmlDocument doc)
68 {
69 // When we're detaching an attachment, we need to wait here.
70
71 // Change this to a 5 second timeout. If things do mess up,
72 // we don't want to be stuck forever.
73 //
74 m_DetachReady.WaitOne (5000, false);
75
76 XmlElement scriptStateN = doc.CreateElement("", "ScriptState", "");
77 scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName);
78 scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString());
79 scriptStateN.SetAttribute ("SourceHash", m_ObjCode.sourceHash);
80
81 // Make sure we aren't executing part of the script so it stays
82 // stable. Setting suspendOnCheckRun tells CheckRun() to suspend
83 // and return out so RunOne() will release the lock asap.
84 suspendOnCheckRunHold = true;
85 lock (m_RunLock)
86 {
87 m_RunOnePhase = "GetExecutionState enter";
88 CheckRunLockInvariants(true);
89
90 // Get copy of script globals and stack in relocateable form.
91 MemoryStream snapshotStream = new MemoryStream();
92 MigrateOutEventHandler(snapshotStream);
93 Byte[] snapshotBytes = snapshotStream.ToArray();
94 snapshotStream.Close();
95 string snapshotString = Convert.ToBase64String(snapshotBytes);
96 XmlElement snapshotN = doc.CreateElement("", "Snapshot", "");
97 snapshotN.AppendChild(doc.CreateTextNode(snapshotString));
98 scriptStateN.AppendChild(snapshotN);
99 m_RunOnePhase = "GetExecutionState B"; CheckRunLockInvariants(true);
100
101 // "Running" says whether or not we are accepting new events.
102 XmlElement runningN = doc.CreateElement("", "Running", "");
103 runningN.AppendChild(doc.CreateTextNode(m_Running.ToString()));
104 scriptStateN.AppendChild(runningN);
105 m_RunOnePhase = "GetExecutionState C"; CheckRunLockInvariants(true);
106
107 // "DoGblInit" says whether or not default:state_entry() will init global vars.
108 XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", "");
109 doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString()));
110 scriptStateN.AppendChild(doGblInitN);
111 m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true);
112
113 // More misc data.
114 XmlNode permissionsN = doc.CreateElement("", "Permissions", "");
115 scriptStateN.AppendChild(permissionsN);
116
117 XmlAttribute granterA = doc.CreateAttribute("", "granter", "");
118 granterA.Value = m_Item.PermsGranter.ToString();
119 permissionsN.Attributes.Append(granterA);
120
121 XmlAttribute maskA = doc.CreateAttribute("", "mask", "");
122 maskA.Value = m_Item.PermsMask.ToString();
123 permissionsN.Attributes.Append(maskA);
124 m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true);
125
126 // "DetectParams" are returned by llDetected...() script functions
127 // for the currently active event, if any.
128 if (m_DetectParams != null)
129 {
130 XmlElement detParArrayN = doc.CreateElement("", "DetectArray", "");
131 AppendXMLDetectArray(doc, detParArrayN, m_DetectParams);
132 scriptStateN.AppendChild(detParArrayN);
133 }
134 m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true);
135
136 // Save any events we have in the queue.
137 // <EventQueue>
138 // <Event Name="...">
139 // <param>...</param> ...
140 // <DetectParams>...</DetectParams> ...
141 // </Event>
142 // ...
143 // </EventQueue>
144 XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", "");
145 lock (m_QueueLock)
146 {
147 foreach (EventParams evt in m_EventQueue)
148 {
149 XmlElement singleEventN = doc.CreateElement("", "Event", "");
150 singleEventN.SetAttribute("Name", evt.EventName);
151 AppendXMLObjectArray(doc, singleEventN, evt.Params, "param");
152 AppendXMLDetectArray(doc, singleEventN, evt.DetectParams);
153 queuedEventsN.AppendChild(singleEventN);
154 }
155 }
156 scriptStateN.AppendChild(queuedEventsN);
157 m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true);
158
159 // "Plugins" indicate enabled timers and listens, etc.
160 Object[] pluginData =
161 AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID);
162
163 XmlNode plugins = doc.CreateElement("", "Plugins", "");
164 AppendXMLObjectArray(doc, plugins, pluginData, "plugin");
165 scriptStateN.AppendChild(plugins);
166 m_RunOnePhase = "GetExecutionState H"; CheckRunLockInvariants(true);
167
168 // Let script run again.
169 suspendOnCheckRunHold = false;
170
171 m_RunOnePhase = "GetExecutionState leave";
172 CheckRunLockInvariants(true);
173 }
174
175 // scriptStateN represents the contents of the .state file so
176 // write the .state file while we are here.
177 FileStream fs = File.Create(m_StateFileName);
178 StreamWriter sw = new StreamWriter(fs);
179 sw.Write(scriptStateN.OuterXml);
180 sw.Close();
181 fs.Close();
182
183 return scriptStateN;
184 }
185
186 /**
187 * @brief Write script state to output stream.
188 * The script microthread is at same state on return,
189 * ie, either inactive or suspended inside CheckRun().
190 *
191 * Input:
192 * stream = stream to write event handler state information to
193 */
194 private void MigrateOutEventHandler (Stream stream)
195 {
196 moehexcep = null;
197
198 // do all the work in the MigrateOutEventHandlerThread() method below
199 moehstream = stream;
200
201 XMRScriptThread cst = m_Engine.CurrentScriptThread ();
202 if (cst != null)
203 {
204
205 // we might be getting called inside some LSL Api function
206 // so we are already in script thread and thus must do
207 // migration directly
208 MigrateOutEventHandlerThread ();
209 }
210 else
211 {
212 // some other thread, do migration via a script thread
213 m_Engine.QueueToTrunk(this.MigrateOutEventHandlerThread);
214
215 // wait for it to complete
216 lock (moehdone)
217 {
218 while (moehstream != null)
219 Monitor.Wait (moehdone);
220 }
221 }
222
223 // maybe it threw up
224 if (moehexcep != null)
225 throw moehexcep;
226 }
227
228 private Exception moehexcep;
229 private object moehdone = new object ();
230 private Stream moehstream;
231 private void MigrateOutEventHandlerThread ()
232 {
233 Exception except;
234
235 try
236 {
237 // Resume the microthread and it will throw a StackCaptureException()
238 // with the stack frames saved to this.stackFrames.
239 // Then write the saved stack frames to the output stream.
240 //
241 // There is a stack only if the event code is not None.
242 if (this.eventCode != ScriptEventCode.None)
243 {
244 // tell microthread to continue
245 // it should see captureStackFrames and throw StackCaptureException()
246 // ...generating XMRStackFrames as it unwinds
247 this.captureStackFrames = true;
248// this.suspendOnCheckRunTemp = true;
249 except = this.microthread.ResumeEx ();
250 this.captureStackFrames = false;
251
252 if (except == null)
253 throw new Exception ("stack save did not complete");
254
255 if (!(except is StackCaptureException))
256 throw except;
257 }
258
259 // Write script state out, frames and all, to the stream.
260 // Does not change script state.
261
262 moehstream.WriteByte (migrationVersion);
263 moehstream.WriteByte ((byte)16);
264 this.MigrateOut (new BinaryWriter (moehstream));
265
266 // Now restore script stack.
267 // Microthread will suspend inside CheckRun() when restore is complete.
268 if (this.eventCode != ScriptEventCode.None)
269 {
270 this.stackFramesRestored = false;
271 except = this.microthread.StartEx ();
272
273 if (except != null)
274 throw except;
275
276 if (!this.stackFramesRestored)
277 throw new Exception ("restore after save did not complete");
278
279 }
280 }
281 catch (Exception e)
282 {
283 moehexcep = e;
284 }
285 finally
286 {
287 // make sure CheckRunLockInvariants() won't puque
288 if (this.microthread.Active () == 0)
289 this.eventCode = ScriptEventCode.None;
290
291 // wake the MigrateOutEventHandler() method above
292 lock (moehdone)
293 {
294 moehstream = null;
295 Monitor.Pulse (moehdone);
296 }
297 }
298 }
299
300 /**
301 * @brief Convert an DetectParams[] to corresponding XML.
302 * DetectParams[] holds the values retrievable by llDetected...() for
303 * a given event.
304 */
305 private static void AppendXMLDetectArray(XmlDocument doc, XmlElement parent, DetectParams[] detect)
306 {
307 foreach (DetectParams d in detect)
308 {
309 XmlElement detectParamsN = GetXMLDetect(doc, d);
310 parent.AppendChild(detectParamsN);
311 }
312 }
313
314 private static XmlElement GetXMLDetect(XmlDocument doc, DetectParams d)
315 {
316 XmlElement detectParamsN = doc.CreateElement("", "DetectParams", "");
317
318 XmlAttribute d_key = doc.CreateAttribute("", "key", "");
319 d_key.Value = d.Key.ToString();
320 detectParamsN.Attributes.Append(d_key);
321
322 XmlAttribute pos = doc.CreateAttribute("", "pos", "");
323 pos.Value = d.OffsetPos.ToString();
324 detectParamsN.Attributes.Append(pos);
325
326 XmlAttribute d_linkNum = doc.CreateAttribute("", "linkNum", "");
327 d_linkNum.Value = d.LinkNum.ToString();
328 detectParamsN.Attributes.Append(d_linkNum);
329
330 XmlAttribute d_group = doc.CreateAttribute("", "group", "");
331 d_group.Value = d.Group.ToString();
332 detectParamsN.Attributes.Append(d_group);
333
334 XmlAttribute d_name = doc.CreateAttribute("", "name", "");
335 d_name.Value = d.Name.ToString();
336 detectParamsN.Attributes.Append(d_name);
337
338 XmlAttribute d_owner = doc.CreateAttribute("", "owner", "");
339 d_owner.Value = d.Owner.ToString();
340 detectParamsN.Attributes.Append(d_owner);
341
342 XmlAttribute d_position = doc.CreateAttribute("", "position", "");
343 d_position.Value = d.Position.ToString();
344 detectParamsN.Attributes.Append(d_position);
345
346 XmlAttribute d_rotation = doc.CreateAttribute("", "rotation", "");
347 d_rotation.Value = d.Rotation.ToString();
348 detectParamsN.Attributes.Append(d_rotation);
349
350 XmlAttribute d_type = doc.CreateAttribute("", "type", "");
351 d_type.Value = d.Type.ToString();
352 detectParamsN.Attributes.Append(d_type);
353
354 XmlAttribute d_velocity = doc.CreateAttribute("", "velocity", "");
355 d_velocity.Value = d.Velocity.ToString();
356 detectParamsN.Attributes.Append(d_velocity);
357
358 return detectParamsN;
359 }
360
361 /**
362 * @brief Append elements of an array of objects to an XML parent.
363 * @param doc = document the parent is part of
364 * @param parent = parent to append the items to
365 * @param array = array of objects
366 * @param tag = <tag ..>...</tag> for each element
367 */
368 private static void AppendXMLObjectArray(XmlDocument doc, XmlNode parent, object[] array, string tag)
369 {
370 foreach (object o in array)
371 {
372 XmlElement element = GetXMLObject(doc, o, tag);
373 parent.AppendChild(element);
374 }
375 }
376
377 /**
378 * @brief Get and XML representation of an object.
379 * @param doc = document the tag will be put in
380 * @param o = object to be represented
381 * @param tag = <tag ...>...</tag>
382 */
383 private static XmlElement GetXMLObject(XmlDocument doc, object o, string tag)
384 {
385 XmlAttribute typ = doc.CreateAttribute("", "type", "");
386 XmlElement n = doc.CreateElement("", tag, "");
387
388 if (o is LSL_List)
389 {
390 typ.Value = "list";
391 n.Attributes.Append(typ);
392 AppendXMLObjectArray(doc, n, ((LSL_List)o).Data, "item");
393 }
394 else
395 {
396 typ.Value = o.GetType().ToString();
397 n.Attributes.Append(typ);
398 n.AppendChild(doc.CreateTextNode(o.ToString()));
399 }
400 return n;
401 }
402 }
403}