diff options
author | UbitUmarov | 2018-02-02 12:49:40 +0000 |
---|---|---|
committer | UbitUmarov | 2018-02-02 12:49:40 +0000 |
commit | 83e2fee71be695b78438e0c9dc50b649a539d0e3 (patch) | |
tree | af213fea5ebfa4e773af6942c753e7f3bba0d83f /OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs | |
parent | Merge branch 'master' into httptests (diff) | |
download | opensim-SC-83e2fee71be695b78438e0c9dc50b649a539d0e3.zip opensim-SC-83e2fee71be695b78438e0c9dc50b649a539d0e3.tar.gz opensim-SC-83e2fee71be695b78438e0c9dc50b649a539d0e3.tar.bz2 opensim-SC-83e2fee71be695b78438e0c9dc50b649a539d0e3.tar.xz |
add experimental script engine XMRengine donated by mrieker (DreamNation) And our Melanie. ***DANGER*** ***TESTONLY*** ***disable HG*** dont leave running when not looking... tp/crossing to Xengine will reset scripts. i do see a few issues but should be testable, so we can decide if we should invest more on it.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs | 436 |
1 files changed, 436 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..8950d63 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs | |||
@@ -0,0 +1,436 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Threading; | ||
30 | using System.Reflection; | ||
31 | using System.Collections; | ||
32 | using System.Collections.Generic; | ||
33 | using System.Runtime.Remoting.Lifetime; | ||
34 | using System.Security.Policy; | ||
35 | using System.IO; | ||
36 | using System.Xml; | ||
37 | using System.Text; | ||
38 | using OpenMetaverse; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
41 | using OpenSim.Region.ScriptEngine.Shared; | ||
42 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
43 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
44 | using OpenSim.Region.ScriptEngine.XMREngine; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using log4net; | ||
47 | |||
48 | using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; | ||
49 | using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; | ||
50 | using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
51 | using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; | ||
52 | using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; | ||
53 | using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
54 | using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | ||
55 | |||
56 | namespace OpenSim.Region.ScriptEngine.XMREngine | ||
57 | { | ||
58 | public partial class XMRInstance | ||
59 | { | ||
60 | /********************************************************************************\ | ||
61 | * The only method of interest to outside this module is GetExecutionState() * | ||
62 | * which captures the current state of the script into an XML document. * | ||
63 | * * | ||
64 | * The rest of this module contains support routines for GetExecutionState(). * | ||
65 | \********************************************************************************/ | ||
66 | |||
67 | /** | ||
68 | * @brief Create an XML element that gives the current state of the script. | ||
69 | * <ScriptState Engine="XMREngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID> | ||
70 | * <Snapshot>globalsandstackdump</Snapshot> | ||
71 | * <Running>m_Running</Running> | ||
72 | * <DetectArray ... | ||
73 | * <EventQueue ... | ||
74 | * <Permissions ... | ||
75 | * <Plugins /> | ||
76 | * </ScriptState> | ||
77 | * Updates the .state file while we're at it. | ||
78 | */ | ||
79 | public XmlElement GetExecutionState(XmlDocument doc) | ||
80 | { | ||
81 | /* | ||
82 | * When we're detaching an attachment, we need to wait here. | ||
83 | */ | ||
84 | |||
85 | // Change this to a 5 second timeout. If things do mess up, | ||
86 | // we don't want to be stuck forever. | ||
87 | // | ||
88 | m_DetachReady.WaitOne (5000, false); | ||
89 | |||
90 | XmlElement scriptStateN = doc.CreateElement("", "ScriptState", ""); | ||
91 | scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName); | ||
92 | scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString()); | ||
93 | scriptStateN.SetAttribute ("SourceHash", m_ObjCode.sourceHash); | ||
94 | |||
95 | /* | ||
96 | * Make sure we aren't executing part of the script so it stays | ||
97 | * stable. Setting suspendOnCheckRun tells CheckRun() to suspend | ||
98 | * and return out so RunOne() will release the lock asap. | ||
99 | */ | ||
100 | suspendOnCheckRunHold = true; | ||
101 | lock (m_RunLock) | ||
102 | { | ||
103 | m_RunOnePhase = "GetExecutionState enter"; | ||
104 | CheckRunLockInvariants(true); | ||
105 | |||
106 | /* | ||
107 | * Get copy of script globals and stack in relocateable form. | ||
108 | */ | ||
109 | MemoryStream snapshotStream = new MemoryStream(); | ||
110 | MigrateOutEventHandler(snapshotStream); | ||
111 | Byte[] snapshotBytes = snapshotStream.ToArray(); | ||
112 | snapshotStream.Close(); | ||
113 | string snapshotString = Convert.ToBase64String(snapshotBytes); | ||
114 | XmlElement snapshotN = doc.CreateElement("", "Snapshot", ""); | ||
115 | snapshotN.AppendChild(doc.CreateTextNode(snapshotString)); | ||
116 | scriptStateN.AppendChild(snapshotN); | ||
117 | m_RunOnePhase = "GetExecutionState B"; CheckRunLockInvariants(true); | ||
118 | |||
119 | /* | ||
120 | * "Running" says whether or not we are accepting new events. | ||
121 | */ | ||
122 | XmlElement runningN = doc.CreateElement("", "Running", ""); | ||
123 | runningN.AppendChild(doc.CreateTextNode(m_Running.ToString())); | ||
124 | scriptStateN.AppendChild(runningN); | ||
125 | m_RunOnePhase = "GetExecutionState C"; CheckRunLockInvariants(true); | ||
126 | |||
127 | /* | ||
128 | * "DoGblInit" says whether or not default:state_entry() will init global vars. | ||
129 | */ | ||
130 | XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", ""); | ||
131 | doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString())); | ||
132 | scriptStateN.AppendChild(doGblInitN); | ||
133 | m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true); | ||
134 | |||
135 | /* | ||
136 | * More misc data. | ||
137 | */ | ||
138 | XmlNode permissionsN = doc.CreateElement("", "Permissions", ""); | ||
139 | scriptStateN.AppendChild(permissionsN); | ||
140 | |||
141 | XmlAttribute granterA = doc.CreateAttribute("", "granter", ""); | ||
142 | granterA.Value = m_Item.PermsGranter.ToString(); | ||
143 | permissionsN.Attributes.Append(granterA); | ||
144 | |||
145 | XmlAttribute maskA = doc.CreateAttribute("", "mask", ""); | ||
146 | maskA.Value = m_Item.PermsMask.ToString(); | ||
147 | permissionsN.Attributes.Append(maskA); | ||
148 | m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true); | ||
149 | |||
150 | /* | ||
151 | * "DetectParams" are returned by llDetected...() script functions | ||
152 | * for the currently active event, if any. | ||
153 | */ | ||
154 | if (m_DetectParams != null) | ||
155 | { | ||
156 | XmlElement detParArrayN = doc.CreateElement("", "DetectArray", ""); | ||
157 | AppendXMLDetectArray(doc, detParArrayN, m_DetectParams); | ||
158 | scriptStateN.AppendChild(detParArrayN); | ||
159 | } | ||
160 | m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true); | ||
161 | |||
162 | /* | ||
163 | * Save any events we have in the queue. | ||
164 | * <EventQueue> | ||
165 | * <Event Name="..."> | ||
166 | * <param>...</param> ... | ||
167 | * <DetectParams>...</DetectParams> ... | ||
168 | * </Event> | ||
169 | * ... | ||
170 | * </EventQueue> | ||
171 | */ | ||
172 | XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", ""); | ||
173 | lock (m_QueueLock) | ||
174 | { | ||
175 | foreach (EventParams evt in m_EventQueue) | ||
176 | { | ||
177 | XmlElement singleEventN = doc.CreateElement("", "Event", ""); | ||
178 | singleEventN.SetAttribute("Name", evt.EventName); | ||
179 | AppendXMLObjectArray(doc, singleEventN, evt.Params, "param"); | ||
180 | AppendXMLDetectArray(doc, singleEventN, evt.DetectParams); | ||
181 | queuedEventsN.AppendChild(singleEventN); | ||
182 | } | ||
183 | } | ||
184 | scriptStateN.AppendChild(queuedEventsN); | ||
185 | m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true); | ||
186 | |||
187 | /* | ||
188 | * "Plugins" indicate enabled timers and listens, etc. | ||
189 | */ | ||
190 | Object[] pluginData = | ||
191 | AsyncCommandManager.GetSerializationData(m_Engine, | ||
192 | m_ItemID); | ||
193 | |||
194 | XmlNode plugins = doc.CreateElement("", "Plugins", ""); | ||
195 | AppendXMLObjectArray(doc, plugins, pluginData, "plugin"); | ||
196 | scriptStateN.AppendChild(plugins); | ||
197 | m_RunOnePhase = "GetExecutionState H"; CheckRunLockInvariants(true); | ||
198 | |||
199 | /* | ||
200 | * Let script run again. | ||
201 | */ | ||
202 | suspendOnCheckRunHold = false; | ||
203 | |||
204 | m_RunOnePhase = "GetExecutionState leave"; | ||
205 | CheckRunLockInvariants(true); | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * scriptStateN represents the contents of the .state file so | ||
210 | * write the .state file while we are here. | ||
211 | */ | ||
212 | FileStream fs = File.Create(m_StateFileName); | ||
213 | StreamWriter sw = new StreamWriter(fs); | ||
214 | sw.Write(scriptStateN.OuterXml); | ||
215 | sw.Close(); | ||
216 | fs.Close(); | ||
217 | |||
218 | return scriptStateN; | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * @brief Write script state to output stream. | ||
223 | * The script microthread is at same state on return, | ||
224 | * ie, either inactive or suspended inside CheckRun(). | ||
225 | * | ||
226 | * Input: | ||
227 | * stream = stream to write event handler state information to | ||
228 | */ | ||
229 | private void MigrateOutEventHandler (Stream stream) | ||
230 | { | ||
231 | moehexcep = null; | ||
232 | |||
233 | // do all the work in the MigrateOutEventHandlerThread() method below | ||
234 | moehstream = stream; | ||
235 | |||
236 | XMRScriptThread cst = XMRScriptThread.CurrentScriptThread (); | ||
237 | if (cst != null) { | ||
238 | |||
239 | // we might be getting called inside some LSL Api function | ||
240 | // so we are already in script thread and thus must do | ||
241 | // migration directly | ||
242 | MigrateOutEventHandlerThread (); | ||
243 | } else { | ||
244 | |||
245 | // some other thread, do migration via a script thread | ||
246 | lock (XMRScriptThread.m_WakeUpLock) { | ||
247 | m_Engine.m_ThunkQueue.Enqueue (this.MigrateOutEventHandlerThread); | ||
248 | } | ||
249 | XMRScriptThread.WakeUpOne (); | ||
250 | |||
251 | // wait for it to complete | ||
252 | lock (moehdone) { | ||
253 | while (moehstream != null) { | ||
254 | Monitor.Wait (moehdone); | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | // maybe it threw up | ||
260 | if (moehexcep != null) throw moehexcep; | ||
261 | } | ||
262 | private Exception moehexcep; | ||
263 | private object moehdone = new object (); | ||
264 | private Stream moehstream; | ||
265 | private void MigrateOutEventHandlerThread () | ||
266 | { | ||
267 | Exception except; | ||
268 | |||
269 | try { | ||
270 | |||
271 | /* | ||
272 | * Resume the microthread and it will throw a StackCaptureException() | ||
273 | * with the stack frames saved to this.stackFrames. | ||
274 | * Then write the saved stack frames to the output stream. | ||
275 | * | ||
276 | * There is a stack only if the event code is not None. | ||
277 | */ | ||
278 | if (this.eventCode != ScriptEventCode.None) { | ||
279 | |||
280 | // tell microthread to continue | ||
281 | // it should see captureStackFrames and throw StackCaptureException() | ||
282 | // ...generating XMRStackFrames as it unwinds | ||
283 | this.captureStackFrames = true; | ||
284 | except = this.microthread.ResumeEx (); | ||
285 | this.captureStackFrames = false; | ||
286 | if (except == null) { | ||
287 | throw new Exception ("stack save did not complete"); | ||
288 | } | ||
289 | if (!(except is StackCaptureException)) { | ||
290 | throw except; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Write script state out, frames and all, to the stream. | ||
296 | * Does not change script state. | ||
297 | */ | ||
298 | moehstream.WriteByte (migrationVersion); | ||
299 | moehstream.WriteByte ((byte)16); | ||
300 | this.MigrateOut (new BinaryWriter (moehstream)); | ||
301 | |||
302 | /* | ||
303 | * Now restore script stack. | ||
304 | * Microthread will suspend inside CheckRun() when restore is complete. | ||
305 | */ | ||
306 | if (this.eventCode != ScriptEventCode.None) { | ||
307 | this.stackFramesRestored = false; | ||
308 | except = this.microthread.StartEx (); | ||
309 | if (except != null) { | ||
310 | throw except; | ||
311 | } | ||
312 | if (!this.stackFramesRestored) { | ||
313 | throw new Exception ("restore after save did not complete"); | ||
314 | } | ||
315 | } | ||
316 | } catch (Exception e) { | ||
317 | moehexcep = e; | ||
318 | } finally { | ||
319 | |||
320 | // make sure CheckRunLockInvariants() won't puque | ||
321 | if (this.microthread.Active () == 0) { | ||
322 | this.eventCode = ScriptEventCode.None; | ||
323 | } | ||
324 | |||
325 | // wake the MigrateOutEventHandler() method above | ||
326 | lock (moehdone) { | ||
327 | moehstream = null; | ||
328 | Monitor.Pulse (moehdone); | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * @brief Convert an DetectParams[] to corresponding XML. | ||
335 | * DetectParams[] holds the values retrievable by llDetected...() for | ||
336 | * a given event. | ||
337 | */ | ||
338 | private static void AppendXMLDetectArray(XmlDocument doc, XmlElement parent, DetectParams[] detect) | ||
339 | { | ||
340 | foreach (DetectParams d in detect) | ||
341 | { | ||
342 | XmlElement detectParamsN = GetXMLDetect(doc, d); | ||
343 | parent.AppendChild(detectParamsN); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | private static XmlElement GetXMLDetect(XmlDocument doc, DetectParams d) | ||
348 | { | ||
349 | XmlElement detectParamsN = doc.CreateElement("", "DetectParams", ""); | ||
350 | |||
351 | XmlAttribute d_key = doc.CreateAttribute("", "key", ""); | ||
352 | d_key.Value = d.Key.ToString(); | ||
353 | detectParamsN.Attributes.Append(d_key); | ||
354 | |||
355 | XmlAttribute pos = doc.CreateAttribute("", "pos", ""); | ||
356 | pos.Value = d.OffsetPos.ToString(); | ||
357 | detectParamsN.Attributes.Append(pos); | ||
358 | |||
359 | XmlAttribute d_linkNum = doc.CreateAttribute("", "linkNum", ""); | ||
360 | d_linkNum.Value = d.LinkNum.ToString(); | ||
361 | detectParamsN.Attributes.Append(d_linkNum); | ||
362 | |||
363 | XmlAttribute d_group = doc.CreateAttribute("", "group", ""); | ||
364 | d_group.Value = d.Group.ToString(); | ||
365 | detectParamsN.Attributes.Append(d_group); | ||
366 | |||
367 | XmlAttribute d_name = doc.CreateAttribute("", "name", ""); | ||
368 | d_name.Value = d.Name.ToString(); | ||
369 | detectParamsN.Attributes.Append(d_name); | ||
370 | |||
371 | XmlAttribute d_owner = doc.CreateAttribute("", "owner", ""); | ||
372 | d_owner.Value = d.Owner.ToString(); | ||
373 | detectParamsN.Attributes.Append(d_owner); | ||
374 | |||
375 | XmlAttribute d_position = doc.CreateAttribute("", "position", ""); | ||
376 | d_position.Value = d.Position.ToString(); | ||
377 | detectParamsN.Attributes.Append(d_position); | ||
378 | |||
379 | XmlAttribute d_rotation = doc.CreateAttribute("", "rotation", ""); | ||
380 | d_rotation.Value = d.Rotation.ToString(); | ||
381 | detectParamsN.Attributes.Append(d_rotation); | ||
382 | |||
383 | XmlAttribute d_type = doc.CreateAttribute("", "type", ""); | ||
384 | d_type.Value = d.Type.ToString(); | ||
385 | detectParamsN.Attributes.Append(d_type); | ||
386 | |||
387 | XmlAttribute d_velocity = doc.CreateAttribute("", "velocity", ""); | ||
388 | d_velocity.Value = d.Velocity.ToString(); | ||
389 | detectParamsN.Attributes.Append(d_velocity); | ||
390 | |||
391 | return detectParamsN; | ||
392 | } | ||
393 | |||
394 | /** | ||
395 | * @brief Append elements of an array of objects to an XML parent. | ||
396 | * @param doc = document the parent is part of | ||
397 | * @param parent = parent to append the items to | ||
398 | * @param array = array of objects | ||
399 | * @param tag = <tag ..>...</tag> for each element | ||
400 | */ | ||
401 | private static void AppendXMLObjectArray(XmlDocument doc, XmlNode parent, object[] array, string tag) | ||
402 | { | ||
403 | foreach (object o in array) | ||
404 | { | ||
405 | XmlElement element = GetXMLObject(doc, o, tag); | ||
406 | parent.AppendChild(element); | ||
407 | } | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * @brief Get and XML representation of an object. | ||
412 | * @param doc = document the tag will be put in | ||
413 | * @param o = object to be represented | ||
414 | * @param tag = <tag ...>...</tag> | ||
415 | */ | ||
416 | private static XmlElement GetXMLObject(XmlDocument doc, object o, string tag) | ||
417 | { | ||
418 | XmlAttribute typ = doc.CreateAttribute("", "type", ""); | ||
419 | XmlElement n = doc.CreateElement("", tag, ""); | ||
420 | |||
421 | if (o is LSL_List) | ||
422 | { | ||
423 | typ.Value = "list"; | ||
424 | n.Attributes.Append(typ); | ||
425 | AppendXMLObjectArray(doc, n, ((LSL_List)o).Data, "item"); | ||
426 | } | ||
427 | else | ||
428 | { | ||
429 | typ.Value = o.GetType().ToString(); | ||
430 | n.Attributes.Append(typ); | ||
431 | n.AppendChild(doc.CreateTextNode(o.ToString())); | ||
432 | } | ||
433 | return n; | ||
434 | } | ||
435 | } | ||
436 | } | ||