aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Instance
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs560
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs4
3 files changed, 376 insertions, 190 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs
index 815d11b..3eaaed0 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.8.0.*")] 32[assembly: AssemblyVersion("0.8.2.*")]
33 33
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 275b608..49df5e7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -52,6 +52,7 @@ using OpenSim.Region.ScriptEngine.Shared.Api.Runtime;
52using OpenSim.Region.ScriptEngine.Shared.ScriptBase; 52using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
53using OpenSim.Region.ScriptEngine.Shared.CodeTools; 53using OpenSim.Region.ScriptEngine.Shared.CodeTools;
54using OpenSim.Region.ScriptEngine.Interfaces; 54using OpenSim.Region.ScriptEngine.Interfaces;
55using System.Diagnostics;
55 56
56namespace OpenSim.Region.ScriptEngine.Shared.Instance 57namespace OpenSim.Region.ScriptEngine.Shared.Instance
57{ 58{
@@ -59,6 +60,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
59 { 60 {
60 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61 62
63 public bool StatePersistedHere { get { return m_AttachedAvatar == UUID.Zero; } }
64
62 /// <summary> 65 /// <summary>
63 /// The current work item if an event for this script is running or waiting to run, 66 /// The current work item if an event for this script is running or waiting to run,
64 /// </summary> 67 /// </summary>
@@ -72,14 +75,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
72 private bool m_TimerQueued; 75 private bool m_TimerQueued;
73 private DateTime m_EventStart; 76 private DateTime m_EventStart;
74 private bool m_InEvent; 77 private bool m_InEvent;
75 private string m_Assembly; 78 private string m_assemblyPath;
79 private string m_dataPath;
76 private string m_CurrentEvent = String.Empty; 80 private string m_CurrentEvent = String.Empty;
77 private bool m_InSelfDelete; 81 private bool m_InSelfDelete;
78 private int m_MaxScriptQueue; 82 private int m_MaxScriptQueue;
79 private bool m_SaveState = true; 83 private bool m_SaveState;
80 private int m_ControlEventsInQueue; 84 private int m_ControlEventsInQueue;
81 private int m_LastControlLevel; 85 private int m_LastControlLevel;
82 private bool m_CollisionInQueue; 86 private bool m_CollisionInQueue;
87 private bool m_StateChangeInProgress;
83 88
84 // The following is for setting a minimum delay between events 89 // The following is for setting a minimum delay between events
85 private double m_minEventDelay; 90 private double m_minEventDelay;
@@ -96,6 +101,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
96 101
97 public int DebugLevel { get; set; } 102 public int DebugLevel { get; set; }
98 103
104 public WaitHandle CoopWaitHandle { get; private set; }
105 public Stopwatch ExecutionTimer { get; private set; }
106
99 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } 107 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; }
100 108
101 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); 109 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>();
@@ -122,7 +130,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
122 } 130 }
123 } 131 }
124 132
125 public bool Running { get; set; } 133 public bool Running
134 {
135 get { return m_running; }
136
137 set
138 {
139 m_running = value;
140 if (m_running)
141 StayStopped = false;
142 }
143 }
144 private bool m_running;
126 145
127 public bool Suspended 146 public bool Suspended
128 { 147 {
@@ -154,6 +173,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
154 173
155 public string State { get; set; } 174 public string State { get; set; }
156 175
176 public bool StayStopped { get; set; }
177
157 public IScriptEngine Engine { get; private set; } 178 public IScriptEngine Engine { get; private set; }
158 179
159 public UUID AppDomain { get; set; } 180 public UUID AppDomain { get; set; }
@@ -195,11 +216,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
195 216
196 public DateTime TimeStarted { get; private set; } 217 public DateTime TimeStarted { get; private set; }
197 218
198 public long MeasurementPeriodTickStart { get; private set; } 219 public MetricsCollectorTime ExecutionTime { get; private set; }
199
200 public long MeasurementPeriodExecutionTime { get; private set; }
201 220
202 public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; 221 private static readonly int MeasurementWindow = 30 * 1000; // show the *recent* time used by the script, to find currently active scripts
203 222
204 private bool m_coopTermination; 223 private bool m_coopTermination;
205 224
@@ -208,6 +227,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
208 public void ClearQueue() 227 public void ClearQueue()
209 { 228 {
210 m_TimerQueued = false; 229 m_TimerQueued = false;
230 m_StateChangeInProgress = false;
211 EventQueue.Clear(); 231 EventQueue.Clear();
212 } 232 }
213 233
@@ -218,6 +238,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
218 { 238 {
219 State = "default"; 239 State = "default";
220 EventQueue = new Queue(32); 240 EventQueue = new Queue(32);
241 ExecutionTimer = new Stopwatch();
221 242
222 Engine = engine; 243 Engine = engine;
223 Part = part; 244 Part = part;
@@ -240,11 +261,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
240 m_AttachedAvatar = part.ParentGroup.AttachedAvatar; 261 m_AttachedAvatar = part.ParentGroup.AttachedAvatar;
241 m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; 262 m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID;
242 263
243 if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") 264 m_SaveState = StatePersistedHere;
244 { 265
245 m_coopTermination = true; 266 ExecutionTime = new MetricsCollectorTime(MeasurementWindow, 10);
246 m_coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); 267
247 } 268// m_log.DebugFormat(
269// "[SCRIPT INSTANCE]: Instantiated script instance {0} (id {1}) in part {2} (id {3}) in object {4} attached avatar {5} in {6}",
270// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, m_AttachedAvatar, Engine.World.Name);
248 } 271 }
249 272
250 /// <summary> 273 /// <summary>
@@ -252,86 +275,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
252 /// </summary> 275 /// </summary>
253 /// <param name='dom'></param> 276 /// <param name='dom'></param>
254 /// <param name='assembly'></param> 277 /// <param name='assembly'></param>
278 /// <param name='dataPath'>
279 /// Path for all script associated data (state, etc.). In a multi-region set up
280 /// with all scripts loading into the same AppDomain this may not be the same place as the DLL itself.
281 /// </param>
255 /// <param name='stateSource'></param> 282 /// <param name='stateSource'></param>
256 /// <returns>false if load failed, true if suceeded</returns> 283 /// <returns>false if load failed, true if suceeded</returns>
257 public bool Load(AppDomain dom, string assembly, StateSource stateSource) 284 public bool Load(
285 IScript script, EventWaitHandle coopSleepHandle, string assemblyPath,
286 string dataPath, StateSource stateSource, bool coopTermination)
258 { 287 {
259 m_Assembly = assembly; 288 m_Script = script;
289 m_coopSleepHandle = coopSleepHandle;
290 m_assemblyPath = assemblyPath;
291 m_dataPath = dataPath;
260 m_stateSource = stateSource; 292 m_stateSource = stateSource;
293 m_coopTermination = coopTermination;
294
295 if (m_coopTermination)
296 CoopWaitHandle = coopSleepHandle;
297 else
298 CoopWaitHandle = null;
261 299
262 ApiManager am = new ApiManager(); 300 ApiManager am = new ApiManager();
263 301
264 foreach (string api in am.GetApis()) 302 foreach (string api in am.GetApis())
265 { 303 {
266 m_Apis[api] = am.CreateApi(api); 304 m_Apis[api] = am.CreateApi(api);
267 m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); 305 m_Apis[api].Initialize(Engine, Part, ScriptTask);
268 }
269
270 try
271 {
272 object[] constructorParams;
273
274 Assembly scriptAssembly = dom.Load(Path.GetFileNameWithoutExtension(assembly));
275 Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript");
276
277 if (scriptType != null)
278 {
279 constructorParams = new object[] { m_coopSleepHandle };
280 }
281 else if (!m_coopTermination)
282 {
283 scriptType = scriptAssembly.GetType("SecondLife.Script");
284 constructorParams = null;
285 }
286 else
287 {
288 m_log.ErrorFormat(
289 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. You must remove all existing {6}* script DLL files before using enabling co-op termination"
290 + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run"
291 + " or by deleting these files manually.",
292 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly);
293
294 return false;
295 }
296
297// m_log.DebugFormat(
298// "[SCRIPT INSTANCE]: Looking to load {0} from assembly {1} in {2}",
299// scriptType.FullName, Path.GetFileNameWithoutExtension(assembly), Engine.World.Name);
300
301 if (dom != System.AppDomain.CurrentDomain)
302 m_Script
303 = (IScript)dom.CreateInstanceAndUnwrap(
304 Path.GetFileNameWithoutExtension(assembly),
305 scriptType.FullName,
306 false,
307 BindingFlags.Default,
308 null,
309 constructorParams,
310 null,
311 null,
312 null);
313 else
314 m_Script
315 = (IScript)scriptAssembly.CreateInstance(
316 scriptType.FullName,
317 false,
318 BindingFlags.Default,
319 null,
320 constructorParams,
321 null,
322 null);
323
324 //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
325 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
326// lease.Register(this);
327 }
328 catch (Exception e)
329 {
330 m_log.ErrorFormat(
331 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}",
332 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly, e.Message, e.StackTrace);
333
334 return false;
335 } 306 }
336 307
337 try 308 try
@@ -341,10 +312,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
341 m_Script.InitApi(kv.Key, kv.Value); 312 m_Script.InitApi(kv.Key, kv.Value);
342 } 313 }
343 314
344// // m_log.Debug("[Script] Script instance created"); 315 // // m_log.Debug("[Script] Script instance created");
345 316
346 Part.SetScriptEvents(ItemID, 317 Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State));
347 (int)m_Script.GetStateEventFlags(State));
348 } 318 }
349 catch (Exception e) 319 catch (Exception e)
350 { 320 {
@@ -355,12 +325,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
355 return false; 325 return false;
356 } 326 }
357 327
358 m_SaveState = true; 328 // For attachments, XEngine saves the state into a .state file when XEngine.SetXMLState() is called.
329 string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
359 330
360 string savedState = Path.Combine(Path.GetDirectoryName(assembly),
361 ItemID.ToString() + ".state");
362 if (File.Exists(savedState)) 331 if (File.Exists(savedState))
363 { 332 {
333 // m_log.DebugFormat(
334 // "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}",
335 // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
336
364 string xml = String.Empty; 337 string xml = String.Empty;
365 338
366 try 339 try
@@ -380,13 +353,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
380 ScriptSerializer.Deserialize(xml, this); 353 ScriptSerializer.Deserialize(xml, this);
381 354
382 AsyncCommandManager.CreateFromData(Engine, 355 AsyncCommandManager.CreateFromData(Engine,
383 LocalID, ItemID, ObjectID, 356 LocalID, ItemID, ObjectID,
384 PluginData); 357 PluginData);
385 358
386// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); 359 // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName);
387 360
388 Part.SetScriptEvents(ItemID, 361 Part.SetScriptEvents(ItemID,
389 (int)m_Script.GetStateEventFlags(State)); 362 (int)m_Script.GetStateEventFlags(State));
390 363
391 if (!Running) 364 if (!Running)
392 m_startOnInit = false; 365 m_startOnInit = false;
@@ -401,29 +374,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
401 m_SaveState = false; 374 m_SaveState = false;
402 m_startedFromSavedState = true; 375 m_startedFromSavedState = true;
403 } 376 }
377
378 // If this script is in an attachment then we no longer need the state file.
379 if (!StatePersistedHere)
380 RemoveState();
404 } 381 }
405 else 382 // else
406 { 383 // {
407 m_log.WarnFormat( 384 // m_log.WarnFormat(
408 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", 385 // "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.",
409 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); 386 // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState);
410 } 387 // }
411 } 388 }
412 catch (Exception e) 389 catch (Exception e)
413 { 390 {
414 m_log.ErrorFormat( 391 m_log.ErrorFormat(
415 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", 392 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}",
416 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); 393 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace);
417 } 394 }
418 } 395 }
419// else 396 // else
420// { 397 // {
421// ScenePresence presence = Engine.World.GetScenePresence(part.OwnerID); 398 // m_log.DebugFormat(
422 399 // "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}",
423// if (presence != null && (!postOnRez)) 400 // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
424// presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); 401 // }
425
426// }
427 402
428 return true; 403 return true;
429 } 404 }
@@ -522,8 +497,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
522 497
523 public void RemoveState() 498 public void RemoveState()
524 { 499 {
525 string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), 500 string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
526 ItemID.ToString() + ".state"); 501
502// m_log.DebugFormat(
503// "[SCRIPT INSTANCE]: Deleting state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}.",
504// savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
527 505
528 try 506 try
529 { 507 {
@@ -558,8 +536,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
558 Running = true; 536 Running = true;
559 537
560 TimeStarted = DateTime.Now; 538 TimeStarted = DateTime.Now;
561 MeasurementPeriodTickStart = Util.EnvironmentTickCount(); 539
562 MeasurementPeriodExecutionTime = 0; 540 // Note: we don't reset ExecutionTime. The reason is that runaway scripts are stopped and restarted
541 // automatically, and we *do* want to show that they had high CPU in that case. If we had reset
542 // ExecutionTime here then runaway scripts, paradoxically, would never show up in the "Top Scripts" dialog.
563 543
564 if (EventQueue.Count > 0) 544 if (EventQueue.Count > 0)
565 { 545 {
@@ -571,7 +551,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
571 } 551 }
572 } 552 }
573 553
574 public bool Stop(int timeout) 554 public bool Stop(int timeout, bool clearEventQueue = false)
575 { 555 {
576 if (DebugLevel >= 1) 556 if (DebugLevel >= 1)
577 m_log.DebugFormat( 557 m_log.DebugFormat(
@@ -582,6 +562,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
582 562
583 lock (EventQueue) 563 lock (EventQueue)
584 { 564 {
565 if (clearEventQueue)
566 ClearQueue();
567
585 if (!Running) 568 if (!Running)
586 return true; 569 return true;
587 570
@@ -671,6 +654,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
671 if (state == State) 654 if (state == State)
672 return; 655 return;
673 656
657<<<<<<< HEAD
658 EventParams lastTimerEv = null;
659
660 lock (EventQueue)
661 {
662 // Remove all queued events, remembering the last timer event
663 while (EventQueue.Count > 0)
664 {
665 EventParams tempv = (EventParams)EventQueue.Dequeue();
666 if (tempv.EventName == "timer") lastTimerEv = tempv;
667 }
668
669 // Post events
670 PostEvent(new EventParams("state_exit", new Object[0],
671 new DetectParams[0]));
672 PostEvent(new EventParams("state", new Object[] { state },
673 new DetectParams[0]));
674 PostEvent(new EventParams("state_entry", new Object[0],
675 new DetectParams[0]));
676
677 // Requeue the timer event after the state changing events
678 if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv);
679
680 // This will stop events from being queued and processed
681 // until the new state is started
682 m_StateChangeInProgress = true;
683 }
684
685=======
674 PostEvent(new EventParams("state_exit", new Object[0], 686 PostEvent(new EventParams("state_exit", new Object[0],
675 new DetectParams[0])); 687 new DetectParams[0]));
676 PostEvent(new EventParams("state", new Object[] { state }, 688 PostEvent(new EventParams("state", new Object[] { state },
@@ -678,6 +690,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
678 PostEvent(new EventParams("state_entry", new Object[0], 690 PostEvent(new EventParams("state_entry", new Object[0],
679 new DetectParams[0])); 691 new DetectParams[0]));
680 692
693>>>>>>> avn/ubitvar
681 throw new EventAbortException(); 694 throw new EventAbortException();
682 } 695 }
683 696
@@ -708,6 +721,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
708 721
709 lock (EventQueue) 722 lock (EventQueue)
710 { 723 {
724 // The only events that persist across state changes are timers
725 if (m_StateChangeInProgress && data.EventName != "timer")
726 return;
727
711 if (EventQueue.Count >= m_MaxScriptQueue) 728 if (EventQueue.Count >= m_MaxScriptQueue)
712 return; 729 return;
713 730
@@ -774,12 +791,40 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
774 791
775// m_log.DebugFormat("[XEngine]: EventProcessor() invoked for {0}.{1}", PrimName, ScriptName); 792// m_log.DebugFormat("[XEngine]: EventProcessor() invoked for {0}.{1}", PrimName, ScriptName);
776 793
794<<<<<<< HEAD
795 if (Suspended)
796 return 0;
797
798 ExecutionTimer.Restart();
799
800 try
801 {
802 return EventProcessorInt();
803 }
804 finally
805 {
806 ExecutionTimer.Stop();
807 ExecutionTime.AddSample(ExecutionTimer);
808 Part.ParentGroup.Scene.AddScriptExecutionTime(ExecutionTimer.ElapsedTicks);
809 }
810 }
811 }
812
813 private object EventProcessorInt()
814 {
815 EventParams data = null;
816
817 lock (EventQueue)
818 {
819 data = (EventParams)EventQueue.Dequeue();
820=======
777 if (Suspended) 821 if (Suspended)
778 return 0; 822 return 0;
779 823
780 lock (EventQueue) 824 lock (EventQueue)
781 { 825 {
782 data = (EventParams) EventQueue.Dequeue(); 826 data = (EventParams) EventQueue.Dequeue();
827>>>>>>> avn/ubitvar
783 if (data == null) // Shouldn't happen 828 if (data == null) // Shouldn't happen
784 { 829 {
785 if (EventQueue.Count > 0 && Running && !ShuttingDown) 830 if (EventQueue.Count > 0 && Running && !ShuttingDown)
@@ -804,6 +849,37 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
804 m_CollisionInQueue = false; 849 m_CollisionInQueue = false;
805 } 850 }
806 851
852<<<<<<< HEAD
853 if (DebugLevel >= 2)
854 m_log.DebugFormat(
855 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
856 data.EventName,
857 ScriptName,
858 Part.Name,
859 Part.LocalId,
860 Part.ParentGroup.Name,
861 Part.ParentGroup.UUID,
862 Part.AbsolutePosition,
863 Part.ParentGroup.Scene.Name);
864
865 m_DetectParams = data.DetectParams;
866
867 if (data.EventName == "state") // Hardcoded state change
868 {
869 State = data.Params[0].ToString();
870
871 if (DebugLevel >= 1)
872 m_log.DebugFormat(
873 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
874 State,
875 ScriptName,
876 Part.Name,
877 Part.LocalId,
878 Part.ParentGroup.Name,
879 Part.ParentGroup.UUID,
880 Part.AbsolutePosition,
881 Part.ParentGroup.Scene.Name);
882=======
807 lock(m_Script) 883 lock(m_Script)
808 { 884 {
809 885
@@ -821,13 +897,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
821 part.ParentGroup.UUID, 897 part.ParentGroup.UUID,
822 part.AbsolutePosition, 898 part.AbsolutePosition,
823 part.ParentGroup.Scene.Name); 899 part.ParentGroup.Scene.Name);
900>>>>>>> avn/ubitvar
824 901
825 m_DetectParams = data.DetectParams; 902 AsyncCommandManager.StateChange(Engine,
903 LocalID, ItemID);
904 // we are effectively in the new state now, so we can resume queueing
905 // and processing other non-timer events
906 m_StateChangeInProgress = false;
826 907
827 if (data.EventName == "state") // Hardcoded state change 908 Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State));
909 }
910 else
911 {
912 if (Engine.World.PipeEventsForScript(LocalID) ||
913 data.EventName == "control") // Don't freeze avies!
828 { 914 {
829 State = data.Params[0].ToString(); 915 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
916 // PrimName, ScriptName, data.EventName, State);
830 917
918<<<<<<< HEAD
919 try
920=======
831 if (DebugLevel >= 1) 921 if (DebugLevel >= 1)
832 m_log.DebugFormat( 922 m_log.DebugFormat(
833 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", 923 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
@@ -853,41 +943,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
853 { 943 {
854 if (Engine.World.PipeEventsForScript(LocalID) || 944 if (Engine.World.PipeEventsForScript(LocalID) ||
855 data.EventName == "control") // Don't freeze avies! 945 data.EventName == "control") // Don't freeze avies!
946>>>>>>> avn/ubitvar
856 { 947 {
857 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", 948 m_CurrentEvent = data.EventName;
858 // PrimName, ScriptName, data.EventName, State); 949 m_EventStart = DateTime.Now;
950 m_InEvent = true;
859 951
860 try 952 try
861 { 953 {
862 m_CurrentEvent = data.EventName;
863 m_EventStart = DateTime.Now;
864 m_InEvent = true;
865
866 int start = Util.EnvironmentTickCount();
867
868 // Reset the measurement period when we reach the end of the current one.
869 if (start - MeasurementPeriodTickStart > MaxMeasurementPeriod)
870 MeasurementPeriodTickStart = start;
871
872 m_Script.ExecuteEvent(State, data.EventName, data.Params); 954 m_Script.ExecuteEvent(State, data.EventName, data.Params);
873 955 }
874 MeasurementPeriodExecutionTime += Util.EnvironmentTickCount() - start; 956 finally
875 957 {
876 m_InEvent = false; 958 m_InEvent = false;
877 m_CurrentEvent = String.Empty; 959 m_CurrentEvent = String.Empty;
960 }
878 961
879 if (m_SaveState) 962 if (m_SaveState)
880 { 963 {
881 // This will be the very first event we deliver 964 // This will be the very first event we deliver
882 // (state_entry) in default state 965 // (state_entry) in default state
883 // 966 //
884 SaveState(m_Assembly); 967 SaveState();
885 968
886 m_SaveState = false; 969 m_SaveState = false;
887 }
888 } 970 }
889 catch (Exception e) 971 }
972 catch (Exception e)
973 {
974 // m_log.DebugFormat(
975 // "[SCRIPT] Exception in script {0} {1}: {2}{3}",
976 // ScriptName, ItemID, e.Message, e.StackTrace);
977
978 if ((!(e is TargetInvocationException)
979 || (!(e.InnerException is SelfDeleteException)
980 && !(e.InnerException is ScriptDeleteException)
981 && !(e.InnerException is ScriptCoopStopException)))
982 && !(e is ThreadAbortException))
890 { 983 {
984<<<<<<< HEAD
985 try
986 {
987 // DISPLAY ERROR INWORLD
988 string text = FormatException(e);
989
990 if (text.Length > 1000)
991 text = text.Substring(0, 1000);
992 Engine.World.SimChat(Utils.StringToBytes(text),
993 ChatTypeEnum.DebugChannel, 2147483647,
994 Part.AbsolutePosition,
995 Part.Name, Part.UUID, false);
996
997
998 m_log.Debug(string.Format(
999 "[SCRIPT INSTANCE]: Runtime error in script {0} (event {1}), part {2} {3} at {4} in {5} ",
1000 ScriptName,
1001 data.EventName,
1002 PrimName,
1003 Part.UUID,
1004 Part.AbsolutePosition,
1005 Part.ParentGroup.Scene.Name),
1006 e);
1007=======
891// m_log.DebugFormat( 1008// m_log.DebugFormat(
892// "[SCRIPT] Exception in script {0} {1}: {2}{3}", 1009// "[SCRIPT] Exception in script {0} {1}: {2}{3}",
893// ScriptName, ItemID, e.Message, e.StackTrace); 1010// ScriptName, ItemID, e.Message, e.StackTrace);
@@ -942,9 +1059,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
942 m_InSelfDelete = true; 1059 m_InSelfDelete = true;
943 if (part != null) 1060 if (part != null)
944 Engine.World.DeleteSceneObject(part.ParentGroup, false); 1061 Engine.World.DeleteSceneObject(part.ParentGroup, false);
1062>>>>>>> avn/ubitvar
945 } 1063 }
946 else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException)) 1064 catch (Exception)
947 { 1065 {
1066<<<<<<< HEAD
1067=======
948 m_InSelfDelete = true; 1068 m_InSelfDelete = true;
949 if (part != null) 1069 if (part != null)
950 part.Inventory.RemoveInventoryItem(ItemID); 1070 part.Inventory.RemoveInventoryItem(ItemID);
@@ -955,31 +1075,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
955 m_log.DebugFormat( 1075 m_log.DebugFormat(
956 "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", 1076 "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.",
957 PrimName, ScriptName, data.EventName, State); 1077 PrimName, ScriptName, data.EventName, State);
1078>>>>>>> avn/ubitvar
958 } 1079 }
1080 // catch (Exception e2) // LEGIT: User Scripting
1081 // {
1082 // m_log.Error("[SCRIPT]: "+
1083 // "Error displaying error in-world: " +
1084 // e2.ToString());
1085 // m_log.Error("[SCRIPT]: " +
1086 // "Errormessage: Error compiling script:\r\n" +
1087 // e.ToString());
1088 // }
1089 }
1090 else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException))
1091 {
1092 m_InSelfDelete = true;
1093 Engine.World.DeleteSceneObject(Part.ParentGroup, false);
1094 }
1095 else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException))
1096 {
1097 m_InSelfDelete = true;
1098 Part.Inventory.RemoveInventoryItem(ItemID);
1099 }
1100 else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException))
1101 {
1102 if (DebugLevel >= 1)
1103 m_log.DebugFormat(
1104 "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.",
1105 PrimName, ScriptName, data.EventName, State);
959 } 1106 }
960 } 1107 }
961 } 1108 }
1109 }
962 1110
963 // If there are more events and we are currently running and not shutting down, then ask the 1111 // If there are more events and we are currently running and not shutting down, then ask the
964 // script engine to run the next event. 1112 // script engine to run the next event.
965 lock (EventQueue) 1113 lock (EventQueue)
1114 {
1115 // Increase processed events counter and prevent wrap;
1116 if (++EventsProcessed == 1000000)
1117 EventsProcessed = 100000;
1118
1119 if ((EventsProcessed % 100000) == 0 && DebugLevel > 0)
966 { 1120 {
967 EventsProcessed++; 1121 m_log.DebugFormat("[SCRIPT INSTANCE]: Script \"{0}\" (Object \"{1}\" {2} @ {3}.{4}, Item ID {5}, Asset {6}) in event {7}: processed {8:n0} script events",
1122 ScriptTask.Name,
1123 Part.ParentGroup.Name, Part.ParentGroup.UUID, Part.ParentGroup.AbsolutePosition, Part.ParentGroup.Scene.Name,
1124 ScriptTask.ItemID, ScriptTask.AssetID, data.EventName, EventsProcessed);
1125 }
968 1126
969 if (EventQueue.Count > 0 && Running && !ShuttingDown) 1127 if (EventQueue.Count > 0 && Running && !ShuttingDown)
970 { 1128 {
971 m_CurrentWorkItem = Engine.QueueEventHandler(this); 1129 m_CurrentWorkItem = Engine.QueueEventHandler(this);
972 } 1130 }
973 else 1131 else
974 { 1132 {
975 m_CurrentWorkItem = null; 1133 m_CurrentWorkItem = null;
976 }
977 } 1134 }
1135 }
978 1136
979 m_DetectParams = null; 1137 m_DetectParams = null;
980 1138
981 return 0; 1139 return 0;
982 }
983 } 1140 }
984 1141
985 public int EventTime() 1142 public int EventTime()
@@ -1008,13 +1165,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1008 AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID); 1165 AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID);
1009 EventQueue.Clear(); 1166 EventQueue.Clear();
1010 m_Script.ResetVars(); 1167 m_Script.ResetVars();
1168 StartParam = 0;
1011 State = "default"; 1169 State = "default";
1012 1170
1013 part.SetScriptEvents(ItemID, 1171 part.SetScriptEvents(ItemID,
1014 (int)m_Script.GetStateEventFlags(State)); 1172 (int)m_Script.GetStateEventFlags(State));
1015 if (running) 1173 if (running)
1016 Start(); 1174 Start();
1017 m_SaveState = true; 1175
1176 m_SaveState = StatePersistedHere;
1177
1018 PostEvent(new EventParams("state_entry", 1178 PostEvent(new EventParams("state_entry",
1019 new Object[0], new DetectParams[0])); 1179 new Object[0], new DetectParams[0]));
1020 } 1180 }
@@ -1036,14 +1196,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1036 1196
1037 EventQueue.Clear(); 1197 EventQueue.Clear();
1038 m_Script.ResetVars(); 1198 m_Script.ResetVars();
1199 string oldState = State;
1200 StartParam = 0;
1039 State = "default"; 1201 State = "default";
1040 1202
1041 part.SetScriptEvents(ItemID, 1203 part.SetScriptEvents(ItemID,
1042 (int)m_Script.GetStateEventFlags(State)); 1204 (int)m_Script.GetStateEventFlags(State));
1043 1205
1044 if (m_CurrentEvent != "state_entry") 1206 if (m_CurrentEvent != "state_entry" || oldState != "default")
1045 { 1207 {
1046 m_SaveState = true; 1208 m_SaveState = StatePersistedHere;
1047 PostEvent(new EventParams("state_entry", 1209 PostEvent(new EventParams("state_entry",
1048 new Object[0], new DetectParams[0])); 1210 new Object[0], new DetectParams[0]));
1049 throw new EventAbortException(); 1211 throw new EventAbortException();
@@ -1057,6 +1219,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1057 1219
1058 public void SetVars(Dictionary<string, object> vars) 1220 public void SetVars(Dictionary<string, object> vars)
1059 { 1221 {
1222// foreach (KeyValuePair<string, object> kvp in vars)
1223// m_log.DebugFormat("[SCRIPT INSTANCE]: Setting var {0}={1}", kvp.Key, kvp.Value);
1224
1060 m_Script.SetVars(vars); 1225 m_Script.SetVars(vars);
1061 } 1226 }
1062 1227
@@ -1080,42 +1245,63 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1080 return m_DetectParams[idx].Key; 1245 return m_DetectParams[idx].Key;
1081 } 1246 }
1082 1247
1083 public void SaveState(string assembly) 1248 public void SaveState()
1084 { 1249 {
1085 // If we're currently in an event, just tell it to save upon return 1250 if (!Running && !StayStopped)
1086 //
1087 if (m_InEvent)
1088 {
1089 m_SaveState = true;
1090 return; 1251 return;
1091 }
1092 1252
1253 // We cannot call this inside the EventQueue lock since it will currently take AsyncCommandManager.staticLock.
1254 // This may already be held by AsyncCommandManager.DoOneCmdHandlerPass() which in turn can take EventQueue
1255 // lock via ScriptInstance.PostEvent().
1093 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); 1256 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
1094 1257
1095 string xml = ScriptSerializer.Serialize(this); 1258 // We need to lock here to avoid any race with a thread that is removing this script.
1096 1259 lock (EventQueue)
1097 // Compare hash of the state we just just created with the state last written to disk
1098 // If the state is different, update the disk file.
1099 UUID hash = UUID.Parse(Utils.MD5String(xml));
1100
1101 if (hash != m_CurrentStateHash)
1102 { 1260 {
1103 try 1261 // Check again to avoid a race with a thread in Stop()
1262 if (!Running && !StayStopped)
1263 return;
1264
1265 // If we're currently in an event, just tell it to save upon return
1266 //
1267 if (m_InEvent)
1104 { 1268 {
1105 FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")); 1269 m_SaveState = true;
1106 Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); 1270 return;
1107 fs.Write(buf, 0, buf.Length);
1108 fs.Close();
1109 } 1271 }
1110 catch(Exception) 1272
1273 // m_log.DebugFormat(
1274 // "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
1275 // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
1276
1277 string xml = ScriptSerializer.Serialize(this);
1278
1279 // Compare hash of the state we just just created with the state last written to disk
1280 // If the state is different, update the disk file.
1281 UUID hash = UUID.Parse(Utils.MD5String(xml));
1282
1283 if (hash != m_CurrentStateHash)
1111 { 1284 {
1112 // m_log.Error("Unable to save xml\n"+e.ToString()); 1285 try
1286 {
1287 using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state")))
1288 {
1289 Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
1290 fs.Write(buf, 0, buf.Length);
1291 }
1292 }
1293 catch(Exception)
1294 {
1295 // m_log.Error("Unable to save xml\n"+e.ToString());
1296 }
1297 //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")))
1298 //{
1299 // throw new Exception("Completed persistence save, but no file was created");
1300 //}
1301 m_CurrentStateHash = hash;
1113 } 1302 }
1114 //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) 1303
1115 //{ 1304 StayStopped = false;
1116 // throw new Exception("Completed persistence save, but no file was created");
1117 //}
1118 m_CurrentStateHash = hash;
1119 } 1305 }
1120 } 1306 }
1121 1307
@@ -1185,7 +1371,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1185 1371
1186 public string GetAssemblyName() 1372 public string GetAssemblyName()
1187 { 1373 {
1188 return m_Assembly; 1374 return m_assemblyPath;
1189 } 1375 }
1190 1376
1191 public string GetXMLState() 1377 public string GetXMLState()
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs
index ac822c6..5b9794b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs
@@ -37,7 +37,6 @@ using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.ScriptEngine.XEngine; 38using OpenSim.Region.ScriptEngine.XEngine;
39using OpenSim.Tests.Common; 39using OpenSim.Tests.Common;
40using OpenSim.Tests.Common.Mock;
41 40
42namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests 41namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests
43{ 42{
@@ -77,6 +76,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests
77 //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); 76 //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin");
78// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); 77// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
79 m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); 78 m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine();
79 m_xEngine.DebugLevel = 1;
80 80
81 IniConfigSource configSource = new IniConfigSource(); 81 IniConfigSource configSource = new IniConfigSource();
82 82
@@ -337,7 +337,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests
337 public void TestStopOnInfiniteJumpLoop() 337 public void TestStopOnInfiniteJumpLoop()
338 { 338 {
339 TestHelpers.InMethod(); 339 TestHelpers.InMethod();
340// TestHelpers.EnableLogging(); 340 TestHelpers.EnableLogging();
341 341
342 string script = 342 string script =
343@"default 343@"default