aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs806
1 files changed, 488 insertions, 318 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 01a5e34..fa6e6fc 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -51,6 +51,7 @@ using OpenSim.Region.ScriptEngine.Shared.Api.Runtime;
51using OpenSim.Region.ScriptEngine.Shared.ScriptBase; 51using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
52using OpenSim.Region.ScriptEngine.Shared.CodeTools; 52using OpenSim.Region.ScriptEngine.Shared.CodeTools;
53using OpenSim.Region.ScriptEngine.Interfaces; 53using OpenSim.Region.ScriptEngine.Interfaces;
54using System.Diagnostics;
54 55
55namespace OpenSim.Region.ScriptEngine.Shared.Instance 56namespace OpenSim.Region.ScriptEngine.Shared.Instance
56{ 57{
@@ -58,6 +59,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
58 { 59 {
59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 60 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 61
62 public bool StatePersistedHere { get { return m_AttachedAvatar == UUID.Zero; } }
63
61 /// <summary> 64 /// <summary>
62 /// The current work item if an event for this script is running or waiting to run, 65 /// The current work item if an event for this script is running or waiting to run,
63 /// </summary> 66 /// </summary>
@@ -71,14 +74,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
71 private bool m_TimerQueued; 74 private bool m_TimerQueued;
72 private DateTime m_EventStart; 75 private DateTime m_EventStart;
73 private bool m_InEvent; 76 private bool m_InEvent;
74 private string m_Assembly; 77 private string m_assemblyPath;
78 private string m_dataPath;
75 private string m_CurrentEvent = String.Empty; 79 private string m_CurrentEvent = String.Empty;
76 private bool m_InSelfDelete; 80 private bool m_InSelfDelete;
77 private int m_MaxScriptQueue; 81 private int m_MaxScriptQueue;
78 private bool m_SaveState = true; 82 private bool m_SaveState;
79 private int m_ControlEventsInQueue; 83 private int m_ControlEventsInQueue;
80 private int m_LastControlLevel; 84 private int m_LastControlLevel;
81 private bool m_CollisionInQueue; 85 private bool m_CollisionInQueue;
86 private bool m_StateChangeInProgress;
82 87
83 // The following is for setting a minimum delay between events 88 // The following is for setting a minimum delay between events
84 private double m_minEventDelay; 89 private double m_minEventDelay;
@@ -95,6 +100,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
95 100
96 public int DebugLevel { get; set; } 101 public int DebugLevel { get; set; }
97 102
103 public WaitHandle CoopWaitHandle { get; private set; }
104 public Stopwatch ExecutionTimer { get; private set; }
105
98 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } 106 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; }
99 107
100 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); 108 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>();
@@ -121,7 +129,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
121 } 129 }
122 } 130 }
123 131
124 public bool Running { get; set; } 132 public bool Running
133 {
134 get { return m_running; }
135
136 set
137 {
138 m_running = value;
139 if (m_running)
140 StayStopped = false;
141 }
142 }
143 private bool m_running;
125 144
126 public bool Suspended 145 public bool Suspended
127 { 146 {
@@ -153,23 +172,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
153 172
154 public string State { get; set; } 173 public string State { get; set; }
155 174
175 public bool StayStopped { get; set; }
176
156 public IScriptEngine Engine { get; private set; } 177 public IScriptEngine Engine { get; private set; }
157 178
158 public UUID AppDomain { get; set; } 179 public UUID AppDomain { get; set; }
159 180
181 public SceneObjectPart Part { get; private set; }
182
160 public string PrimName { get; private set; } 183 public string PrimName { get; private set; }
161 184
162 public string ScriptName { get; private set; } 185 public string ScriptName { get; private set; }
163 186
164 public UUID ItemID { get; private set; } 187 public UUID ItemID { get; private set; }
165 188
166 public UUID ObjectID { get; private set; } 189 public UUID ObjectID { get { return Part.UUID; } }
167 190
168 public uint LocalID { get; private set; } 191 public uint LocalID { get { return Part.LocalId; } }
169 192
170 public UUID RootObjectID { get; private set; } 193 public UUID RootObjectID { get { return Part.ParentGroup.UUID; } }
171 194
172 public uint RootLocalID { get; private set; } 195 public uint RootLocalID { get { return Part.ParentGroup.LocalId; } }
173 196
174 public UUID AssetID { get; private set; } 197 public UUID AssetID { get; private set; }
175 198
@@ -192,83 +215,92 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
192 215
193 public DateTime TimeStarted { get; private set; } 216 public DateTime TimeStarted { get; private set; }
194 217
195 public long MeasurementPeriodTickStart { get; private set; } 218 public MetricsCollectorTime ExecutionTime { get; private set; }
196 219
197 public long MeasurementPeriodExecutionTime { get; private set; } 220 private static readonly int MeasurementWindow = 30 * 1000; // show the *recent* time used by the script, to find currently active scripts
198 221
199 public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; 222 private bool m_coopTermination;
223
224 private EventWaitHandle m_coopSleepHandle;
200 225
201 public void ClearQueue() 226 public void ClearQueue()
202 { 227 {
203 m_TimerQueued = false; 228 m_TimerQueued = false;
229 m_StateChangeInProgress = false;
204 EventQueue.Clear(); 230 EventQueue.Clear();
205 } 231 }
206 232
207 public ScriptInstance(IScriptEngine engine, SceneObjectPart part, 233 public ScriptInstance(
208 UUID itemID, UUID assetID, string assembly, 234 IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item,
209 AppDomain dom, string primName, string scriptName, 235 int startParam, bool postOnRez,
210 int startParam, bool postOnRez, StateSource stateSource, 236 int maxScriptQueue)
211 int maxScriptQueue)
212 { 237 {
213 State = "default"; 238 State = "default";
214 EventQueue = new Queue(32); 239 EventQueue = new Queue(32);
240 ExecutionTimer = new Stopwatch();
215 241
216 Engine = engine; 242 Engine = engine;
217 LocalID = part.LocalId; 243 Part = part;
218 ObjectID = part.UUID; 244 ScriptTask = item;
219 RootLocalID = part.ParentGroup.LocalId; 245
220 RootObjectID = part.ParentGroup.UUID; 246 // This is currently only here to allow regression tests to get away without specifying any inventory
221 ItemID = itemID; 247 // item when they are testing script logic that doesn't require an item.
222 AssetID = assetID; 248 if (ScriptTask != null)
223 PrimName = primName; 249 {
224 ScriptName = scriptName; 250 ScriptName = ScriptTask.Name;
225 m_Assembly = assembly; 251 ItemID = ScriptTask.ItemID;
252 AssetID = ScriptTask.AssetID;
253 }
254
255 PrimName = part.ParentGroup.Name;
226 StartParam = startParam; 256 StartParam = startParam;
227 m_MaxScriptQueue = maxScriptQueue; 257 m_MaxScriptQueue = maxScriptQueue;
228 m_stateSource = stateSource;
229 m_postOnRez = postOnRez; 258 m_postOnRez = postOnRez;
230 m_AttachedAvatar = part.ParentGroup.AttachedAvatar; 259 m_AttachedAvatar = Part.ParentGroup.AttachedAvatar;
231 m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; 260 m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID;
232 261
233 if (part != null) 262 m_SaveState = StatePersistedHere;
234 { 263
235 lock (part.TaskInventory) 264 ExecutionTime = new MetricsCollectorTime(MeasurementWindow, 10);
236 { 265
237 if (part.TaskInventory.ContainsKey(ItemID)) 266// m_log.DebugFormat(
238 { 267// "[SCRIPT INSTANCE]: Instantiated script instance {0} (id {1}) in part {2} (id {3}) in object {4} attached avatar {5} in {6}",
239 ScriptTask = part.TaskInventory[ItemID]; 268// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, m_AttachedAvatar, Engine.World.Name);
240 } 269 }
241 } 270
242 } 271 /// <summary>
272 /// Load the script from an assembly into an AppDomain.
273 /// </summary>
274 /// <param name='dom'></param>
275 /// <param name='assembly'></param>
276 /// <param name='dataPath'>
277 /// Path for all script associated data (state, etc.). In a multi-region set up
278 /// with all scripts loading into the same AppDomain this may not be the same place as the DLL itself.
279 /// </param>
280 /// <param name='stateSource'></param>
281 /// <returns>false if load failed, true if suceeded</returns>
282 public bool Load(
283 IScript script, EventWaitHandle coopSleepHandle, string assemblyPath,
284 string dataPath, StateSource stateSource, bool coopTermination)
285 {
286 m_Script = script;
287 m_coopSleepHandle = coopSleepHandle;
288 m_assemblyPath = assemblyPath;
289 m_dataPath = dataPath;
290 m_stateSource = stateSource;
291 m_coopTermination = coopTermination;
292
293 if (m_coopTermination)
294 CoopWaitHandle = coopSleepHandle;
295 else
296 CoopWaitHandle = null;
243 297
244 ApiManager am = new ApiManager(); 298 ApiManager am = new ApiManager();
245 299
246 foreach (string api in am.GetApis()) 300 foreach (string api in am.GetApis())
247 { 301 {
248 m_Apis[api] = am.CreateApi(api); 302 m_Apis[api] = am.CreateApi(api);
249 m_Apis[api].Initialize(engine, part, ScriptTask); 303 m_Apis[api].Initialize(Engine, Part, ScriptTask);
250 }
251
252 try
253 {
254 if (dom != System.AppDomain.CurrentDomain)
255 m_Script = (IScript)dom.CreateInstanceAndUnwrap(
256 Path.GetFileNameWithoutExtension(assembly),
257 "SecondLife.Script");
258 else
259 m_Script = (IScript)Assembly.Load(
260 Path.GetFileNameWithoutExtension(assembly)).CreateInstance(
261 "SecondLife.Script");
262
263 //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
264 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
265// lease.Register(this);
266 }
267 catch (Exception e)
268 {
269 m_log.ErrorFormat(
270 "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}",
271 assembly, e.Message, e.StackTrace);
272 } 304 }
273 305
274 try 306 try
@@ -278,26 +310,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
278 m_Script.InitApi(kv.Key, kv.Value); 310 m_Script.InitApi(kv.Key, kv.Value);
279 } 311 }
280 312
281// // m_log.Debug("[Script] Script instance created"); 313 // // m_log.Debug("[Script] Script instance created");
282 314
283 part.SetScriptEvents(ItemID, 315 Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State));
284 (int)m_Script.GetStateEventFlags(State));
285 } 316 }
286 catch (Exception e) 317 catch (Exception e)
287 { 318 {
288 m_log.ErrorFormat( 319 m_log.ErrorFormat(
289 "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", 320 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}",
290 assembly, e.Message, e.StackTrace); 321 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace);
291 322
292 return; 323 return false;
293 } 324 }
294 325
295 m_SaveState = true; 326 // For attachments, XEngine saves the state into a .state file when XEngine.SetXMLState() is called.
327 string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
296 328
297 string savedState = Path.Combine(Path.GetDirectoryName(assembly),
298 ItemID.ToString() + ".state");
299 if (File.Exists(savedState)) 329 if (File.Exists(savedState))
300 { 330 {
331 // m_log.DebugFormat(
332 // "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}",
333 // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
334
301 string xml = String.Empty; 335 string xml = String.Empty;
302 336
303 try 337 try
@@ -317,13 +351,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
317 ScriptSerializer.Deserialize(xml, this); 351 ScriptSerializer.Deserialize(xml, this);
318 352
319 AsyncCommandManager.CreateFromData(Engine, 353 AsyncCommandManager.CreateFromData(Engine,
320 LocalID, ItemID, ObjectID, 354 LocalID, ItemID, ObjectID,
321 PluginData); 355 PluginData);
322 356
323// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); 357 // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName);
324 358
325 part.SetScriptEvents(ItemID, 359 Part.SetScriptEvents(ItemID,
326 (int)m_Script.GetStateEventFlags(State)); 360 (int)m_Script.GetStateEventFlags(State));
327 361
328 if (!Running) 362 if (!Running)
329 m_startOnInit = false; 363 m_startOnInit = false;
@@ -338,29 +372,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
338 m_SaveState = false; 372 m_SaveState = false;
339 m_startedFromSavedState = true; 373 m_startedFromSavedState = true;
340 } 374 }
375
376 // If this script is in an attachment then we no longer need the state file.
377 if (!StatePersistedHere)
378 RemoveState();
341 } 379 }
342 else 380 // else
343 { 381 // {
344 m_log.WarnFormat( 382 // m_log.WarnFormat(
345 "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). Memory limit exceeded", 383 // "[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.",
346 savedState, ScriptName, ItemID, PrimName, ObjectID, assembly); 384 // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState);
347 } 385 // }
348 } 386 }
349 catch (Exception e) 387 catch (Exception e)
350 { 388 {
351 m_log.ErrorFormat( 389 m_log.ErrorFormat(
352 "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). XML is {6}. Exception {7}{8}", 390 "[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}",
353 savedState, ScriptName, ItemID, PrimName, ObjectID, assembly, xml, e.Message, e.StackTrace); 391 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace);
354 } 392 }
355 } 393 }
356// else 394 // else
357// { 395 // {
358// ScenePresence presence = Engine.World.GetScenePresence(part.OwnerID); 396 // m_log.DebugFormat(
397 // "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}",
398 // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
399 // }
359 400
360// if (presence != null && (!postOnRez)) 401 return true;
361// presence.ControllingClient.SendAgentAlertMessage("Compile successful", false);
362
363// }
364 } 402 }
365 403
366 public void Init() 404 public void Init()
@@ -418,33 +456,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
418 PostEvent(new EventParams("attach", 456 PostEvent(new EventParams("attach",
419 new object[] { new LSL_Types.LSLString(m_AttachedAvatar.ToString()) }, new DetectParams[0])); 457 new object[] { new LSL_Types.LSLString(m_AttachedAvatar.ToString()) }, new DetectParams[0]));
420 } 458 }
421
422 } 459 }
423 } 460 }
424 461
425 private void ReleaseControls() 462 private void ReleaseControls()
426 { 463 {
427 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); 464 int permsMask;
428 465 UUID permsGranter;
429 if (part != null) 466 lock (Part.TaskInventory)
430 { 467 {
431 int permsMask; 468 if (!Part.TaskInventory.ContainsKey(ItemID))
432 UUID permsGranter; 469 return;
433 lock (part.TaskInventory)
434 {
435 if (!part.TaskInventory.ContainsKey(ItemID))
436 return;
437 470
438 permsGranter = part.TaskInventory[ItemID].PermsGranter; 471 permsGranter = Part.TaskInventory[ItemID].PermsGranter;
439 permsMask = part.TaskInventory[ItemID].PermsMask; 472 permsMask = Part.TaskInventory[ItemID].PermsMask;
440 } 473 }
441 474
442 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) 475 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
443 { 476 {
444 ScenePresence presence = Engine.World.GetScenePresence(permsGranter); 477 ScenePresence presence = Engine.World.GetScenePresence(permsGranter);
445 if (presence != null) 478 if (presence != null)
446 presence.UnRegisterControlEventsToScript(LocalID, ItemID); 479 presence.UnRegisterControlEventsToScript(LocalID, ItemID);
447 }
448 } 480 }
449 } 481 }
450 482
@@ -456,15 +488,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
456 488
457 public void RemoveState() 489 public void RemoveState()
458 { 490 {
459 string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), 491 string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
460 ItemID.ToString() + ".state"); 492
493// m_log.DebugFormat(
494// "[SCRIPT INSTANCE]: Deleting state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}.",
495// savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
461 496
462 try 497 try
463 { 498 {
464 File.Delete(savedState); 499 File.Delete(savedState);
465 } 500 }
466 catch(Exception) 501 catch (Exception e)
467 { 502 {
503 m_log.Warn(
504 string.Format(
505 "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ",
506 savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name),
507 e);
468 } 508 }
469 } 509 }
470 510
@@ -487,8 +527,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
487 Running = true; 527 Running = true;
488 528
489 TimeStarted = DateTime.Now; 529 TimeStarted = DateTime.Now;
490 MeasurementPeriodTickStart = Util.EnvironmentTickCount(); 530
491 MeasurementPeriodExecutionTime = 0; 531 // Note: we don't reset ExecutionTime. The reason is that runaway scripts are stopped and restarted
532 // automatically, and we *do* want to show that they had high CPU in that case. If we had reset
533 // ExecutionTime here then runaway scripts, paradoxically, would never show up in the "Top Scripts" dialog.
492 534
493 if (EventQueue.Count > 0) 535 if (EventQueue.Count > 0)
494 { 536 {
@@ -500,16 +542,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
500 } 542 }
501 } 543 }
502 544
503 public bool Stop(int timeout) 545 public bool Stop(int timeout, bool clearEventQueue = false)
504 { 546 {
505// m_log.DebugFormat( 547 if (DebugLevel >= 1)
506// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", 548 m_log.DebugFormat(
507// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); 549 "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
550 ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
508 551
509 IScriptWorkItem workItem; 552 IScriptWorkItem workItem;
510 553
511 lock (EventQueue) 554 lock (EventQueue)
512 { 555 {
556 if (clearEventQueue)
557 ClearQueue();
558
513 if (!Running) 559 if (!Running)
514 return true; 560 return true;
515 561
@@ -533,9 +579,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
533 } 579 }
534 580
535 // Wait for the current event to complete. 581 // Wait for the current event to complete.
536 if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) 582 if (!m_InSelfDelete)
537 { 583 {
538 return true; 584 if (!m_coopTermination)
585 {
586 // If we're not co-operative terminating then try and wait for the event to complete before stopping
587 if (workItem.Wait(timeout))
588 return true;
589 }
590 else
591 {
592 if (DebugLevel >= 1)
593 m_log.DebugFormat(
594 "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}",
595 ScriptName, ItemID, PrimName, ObjectID);
596
597 // This will terminate the event on next handle check by the script.
598 m_coopSleepHandle.Set();
599
600 // For now, we will wait forever since the event should always cleanly terminate once LSL loop
601 // checking is implemented. May want to allow a shorter timeout option later.
602 if (workItem.Wait(Timeout.Infinite))
603 {
604 if (DebugLevel >= 1)
605 m_log.DebugFormat(
606 "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}",
607 ScriptName, ItemID, PrimName, ObjectID);
608
609 return true;
610 }
611 }
539 } 612 }
540 613
541 lock (EventQueue) 614 lock (EventQueue)
@@ -548,6 +621,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
548 621
549 // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then 622 // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then
550 // forcibly abort the work item (this aborts the underlying thread). 623 // forcibly abort the work item (this aborts the underlying thread).
624 // Co-operative termination should never reach this point.
551 if (!m_InSelfDelete) 625 if (!m_InSelfDelete)
552 { 626 {
553 m_log.DebugFormat( 627 m_log.DebugFormat(
@@ -570,12 +644,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
570 if (state == State) 644 if (state == State)
571 return; 645 return;
572 646
573 PostEvent(new EventParams("state_exit", new Object[0], 647 EventParams lastTimerEv = null;
574 new DetectParams[0])); 648
575 PostEvent(new EventParams("state", new Object[] { state }, 649 lock (EventQueue)
576 new DetectParams[0])); 650 {
577 PostEvent(new EventParams("state_entry", new Object[0], 651 // Remove all queued events, remembering the last timer event
578 new DetectParams[0])); 652 while (EventQueue.Count > 0)
653 {
654 EventParams tempv = (EventParams)EventQueue.Dequeue();
655 if (tempv.EventName == "timer") lastTimerEv = tempv;
656 }
657
658 // Post events
659 PostEvent(new EventParams("state_exit", new Object[0],
660 new DetectParams[0]));
661 PostEvent(new EventParams("state", new Object[] { state },
662 new DetectParams[0]));
663 PostEvent(new EventParams("state_entry", new Object[0],
664 new DetectParams[0]));
665
666 // Requeue the timer event after the state changing events
667 if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv);
668
669 // This will stop events from being queued and processed
670 // until the new state is started
671 m_StateChangeInProgress = true;
672 }
579 673
580 throw new EventAbortException(); 674 throw new EventAbortException();
581 } 675 }
@@ -607,6 +701,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
607 701
608 lock (EventQueue) 702 lock (EventQueue)
609 { 703 {
704 // The only events that persist across state changes are timers
705 if (m_StateChangeInProgress && data.EventName != "timer")
706 return;
707
610 if (EventQueue.Count >= m_MaxScriptQueue) 708 if (EventQueue.Count >= m_MaxScriptQueue)
611 return; 709 return;
612 710
@@ -677,196 +775,222 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
677 if (Suspended) 775 if (Suspended)
678 return 0; 776 return 0;
679 777
680 EventParams data = null; 778 ExecutionTimer.Restart();
779
780 try
781 {
782 return EventProcessorInt();
783 }
784 finally
785 {
786 ExecutionTimer.Stop();
787 ExecutionTime.AddSample(ExecutionTimer);
788 Part.ParentGroup.Scene.AddScriptExecutionTime(ExecutionTimer.ElapsedTicks);
789 }
790 }
791 }
792
793 private object EventProcessorInt()
794 {
795 EventParams data = null;
681 796
682 lock (EventQueue) 797 lock (EventQueue)
798 {
799 data = (EventParams)EventQueue.Dequeue();
800 if (data == null) // Shouldn't happen
683 { 801 {
684 data = (EventParams)EventQueue.Dequeue(); 802 if (EventQueue.Count > 0 && Running && !ShuttingDown)
685 if (data == null) // Shouldn't happen
686 { 803 {
687 if (EventQueue.Count > 0 && Running && !ShuttingDown) 804 m_CurrentWorkItem = Engine.QueueEventHandler(this);
688 {
689 m_CurrentWorkItem = Engine.QueueEventHandler(this);
690 }
691 else
692 {
693 m_CurrentWorkItem = null;
694 }
695 return 0;
696 } 805 }
697 806 else
698 if (data.EventName == "timer")
699 m_TimerQueued = false;
700 if (data.EventName == "control")
701 { 807 {
702 if (m_ControlEventsInQueue > 0) 808 m_CurrentWorkItem = null;
703 m_ControlEventsInQueue--;
704 } 809 }
705 if (data.EventName == "collision") 810 return 0;
706 m_CollisionInQueue = false;
707 } 811 }
708 812
709 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); 813 if (data.EventName == "timer")
814 m_TimerQueued = false;
815 if (data.EventName == "control")
816 {
817 if (m_ControlEventsInQueue > 0)
818 m_ControlEventsInQueue--;
819 }
820 if (data.EventName == "collision")
821 m_CollisionInQueue = false;
822 }
710 823
711 if (DebugLevel >= 2) 824 if (DebugLevel >= 2)
825 m_log.DebugFormat(
826 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
827 data.EventName,
828 ScriptName,
829 Part.Name,
830 Part.LocalId,
831 Part.ParentGroup.Name,
832 Part.ParentGroup.UUID,
833 Part.AbsolutePosition,
834 Part.ParentGroup.Scene.Name);
835
836 m_DetectParams = data.DetectParams;
837
838 if (data.EventName == "state") // Hardcoded state change
839 {
840 State = data.Params[0].ToString();
841
842 if (DebugLevel >= 1)
712 m_log.DebugFormat( 843 m_log.DebugFormat(
713 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", 844 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
714 data.EventName, 845 State,
715 ScriptName, 846 ScriptName,
716 part.Name, 847 Part.Name,
717 part.LocalId, 848 Part.LocalId,
718 part.ParentGroup.Name, 849 Part.ParentGroup.Name,
719 part.ParentGroup.UUID, 850 Part.ParentGroup.UUID,
720 part.AbsolutePosition, 851 Part.AbsolutePosition,
721 part.ParentGroup.Scene.Name); 852 Part.ParentGroup.Scene.Name);
722 853
723 m_DetectParams = data.DetectParams; 854 AsyncCommandManager.StateChange(Engine,
724 855 LocalID, ItemID);
725 if (data.EventName == "state") // Hardcoded state change 856 // we are effectively in the new state now, so we can resume queueing
857 // and processing other non-timer events
858 m_StateChangeInProgress = false;
859
860 Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State));
861 }
862 else
863 {
864 if (Engine.World.PipeEventsForScript(LocalID) ||
865 data.EventName == "control") // Don't freeze avies!
726 { 866 {
727 State = data.Params[0].ToString(); 867 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
868 // PrimName, ScriptName, data.EventName, State);
728 869
729 if (DebugLevel >= 1) 870 try
730 m_log.DebugFormat(
731 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
732 State,
733 ScriptName,
734 part.Name,
735 part.LocalId,
736 part.ParentGroup.Name,
737 part.ParentGroup.UUID,
738 part.AbsolutePosition,
739 part.ParentGroup.Scene.Name);
740
741 AsyncCommandManager.RemoveScript(Engine,
742 LocalID, ItemID);
743
744 if (part != null)
745 { 871 {
746 part.SetScriptEvents(ItemID, 872 m_CurrentEvent = data.EventName;
747 (int)m_Script.GetStateEventFlags(State)); 873 m_EventStart = DateTime.Now;
748 } 874 m_InEvent = true;
749 }
750 else
751 {
752 if (Engine.World.PipeEventsForScript(LocalID) ||
753 data.EventName == "control") // Don't freeze avies!
754 {
755 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
756 // PrimName, ScriptName, data.EventName, State);
757 875
758 try 876 try
759 { 877 {
760 m_CurrentEvent = data.EventName;
761 m_EventStart = DateTime.Now;
762 m_InEvent = true;
763
764 int start = Util.EnvironmentTickCount();
765
766 // Reset the measurement period when we reach the end of the current one.
767 if (start - MeasurementPeriodTickStart > MaxMeasurementPeriod)
768 MeasurementPeriodTickStart = start;
769
770 m_Script.ExecuteEvent(State, data.EventName, data.Params); 878 m_Script.ExecuteEvent(State, data.EventName, data.Params);
771 879 }
772 MeasurementPeriodExecutionTime += Util.EnvironmentTickCount() - start; 880 finally
773 881 {
774 m_InEvent = false; 882 m_InEvent = false;
775 m_CurrentEvent = String.Empty; 883 m_CurrentEvent = String.Empty;
884 }
776 885
777 if (m_SaveState) 886 if (m_SaveState)
778 { 887 {
779 // This will be the very first event we deliver 888 // This will be the very first event we deliver
780 // (state_entry) in default state 889 // (state_entry) in default state
781 // 890 //
782 SaveState(m_Assembly); 891 SaveState();
783 892
784 m_SaveState = false; 893 m_SaveState = false;
785 }
786 } 894 }
787 catch (Exception e) 895 }
896 catch (Exception e)
897 {
898 // m_log.DebugFormat(
899 // "[SCRIPT] Exception in script {0} {1}: {2}{3}",
900 // ScriptName, ItemID, e.Message, e.StackTrace);
901
902 if ((!(e is TargetInvocationException)
903 || (!(e.InnerException is SelfDeleteException)
904 && !(e.InnerException is ScriptDeleteException)
905 && !(e.InnerException is ScriptCoopStopException)))
906 && !(e is ThreadAbortException))
788 { 907 {
789// m_log.DebugFormat( 908 try
790// "[SCRIPT] Exception in script {0} {1}: {2}{3}",
791// ScriptName, ItemID, e.Message, e.StackTrace);
792
793 m_InEvent = false;
794 m_CurrentEvent = String.Empty;
795
796 if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException))
797 { 909 {
798 try 910 // DISPLAY ERROR INWORLD
799 { 911 string text = FormatException(e);
800 // DISPLAY ERROR INWORLD 912
801 string text = FormatException(e); 913 if (text.Length > 1000)
802 914 text = text.Substring(0, 1000);
803 if (text.Length > 1000) 915 Engine.World.SimChat(Utils.StringToBytes(text),
804 text = text.Substring(0, 1000); 916 ChatTypeEnum.DebugChannel, 2147483647,
805 Engine.World.SimChat(Utils.StringToBytes(text), 917 Part.AbsolutePosition,
806 ChatTypeEnum.DebugChannel, 2147483647, 918 Part.Name, Part.UUID, false);
807 part.AbsolutePosition, 919
808 part.Name, part.UUID, false); 920
809 921 m_log.Debug(string.Format(
810 922 "[SCRIPT INSTANCE]: Runtime error in script {0} (event {1}), part {2} {3} at {4} in {5} ",
811 m_log.DebugFormat( 923 ScriptName,
812 "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}", 924 data.EventName,
813 ScriptName, 925 PrimName,
814 PrimName, 926 Part.UUID,
815 part.UUID, 927 Part.AbsolutePosition,
816 part.AbsolutePosition, 928 Part.ParentGroup.Scene.Name),
817 part.ParentGroup.Scene.Name, 929 e);
818 text.Replace("\n", "\\n"),
819 e.InnerException);
820 }
821 catch (Exception)
822 {
823 }
824 // catch (Exception e2) // LEGIT: User Scripting
825 // {
826 // m_log.Error("[SCRIPT]: "+
827 // "Error displaying error in-world: " +
828 // e2.ToString());
829 // m_log.Error("[SCRIPT]: " +
830 // "Errormessage: Error compiling script:\r\n" +
831 // e.ToString());
832 // }
833 } 930 }
834 else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) 931 catch (Exception)
835 { 932 {
836 m_InSelfDelete = true;
837 if (part != null)
838 Engine.World.DeleteSceneObject(part.ParentGroup, false);
839 }
840 else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException))
841 {
842 m_InSelfDelete = true;
843 if (part != null)
844 part.Inventory.RemoveInventoryItem(ItemID);
845 } 933 }
934 // catch (Exception e2) // LEGIT: User Scripting
935 // {
936 // m_log.Error("[SCRIPT]: "+
937 // "Error displaying error in-world: " +
938 // e2.ToString());
939 // m_log.Error("[SCRIPT]: " +
940 // "Errormessage: Error compiling script:\r\n" +
941 // e.ToString());
942 // }
943 }
944 else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException))
945 {
946 m_InSelfDelete = true;
947 Engine.World.DeleteSceneObject(Part.ParentGroup, false);
948 }
949 else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException))
950 {
951 m_InSelfDelete = true;
952 Part.Inventory.RemoveInventoryItem(ItemID);
953 }
954 else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException))
955 {
956 if (DebugLevel >= 1)
957 m_log.DebugFormat(
958 "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.",
959 PrimName, ScriptName, data.EventName, State);
846 } 960 }
847 } 961 }
848 } 962 }
963 }
849 964
850 // If there are more events and we are currently running and not shutting down, then ask the 965 // If there are more events and we are currently running and not shutting down, then ask the
851 // script engine to run the next event. 966 // script engine to run the next event.
852 lock (EventQueue) 967 lock (EventQueue)
968 {
969 // Increase processed events counter and prevent wrap;
970 if (++EventsProcessed == 1000000)
971 EventsProcessed = 100000;
972
973 if ((EventsProcessed % 100000) == 0 && DebugLevel > 0)
853 { 974 {
854 EventsProcessed++; 975 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",
976 ScriptTask.Name,
977 Part.ParentGroup.Name, Part.ParentGroup.UUID, Part.ParentGroup.AbsolutePosition, Part.ParentGroup.Scene.Name,
978 ScriptTask.ItemID, ScriptTask.AssetID, data.EventName, EventsProcessed);
979 }
855 980
856 if (EventQueue.Count > 0 && Running && !ShuttingDown) 981 if (EventQueue.Count > 0 && Running && !ShuttingDown)
857 { 982 {
858 m_CurrentWorkItem = Engine.QueueEventHandler(this); 983 m_CurrentWorkItem = Engine.QueueEventHandler(this);
859 }
860 else
861 {
862 m_CurrentWorkItem = null;
863 }
864 } 984 }
985 else
986 {
987 m_CurrentWorkItem = null;
988 }
989 }
865 990
866 m_DetectParams = null; 991 m_DetectParams = null;
867 992
868 return 0; 993 return 0;
869 }
870 } 994 }
871 995
872 public int EventTime() 996 public int EventTime()
@@ -888,19 +1012,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
888 ReleaseControls(); 1012 ReleaseControls();
889 1013
890 Stop(timeout); 1014 Stop(timeout);
891 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); 1015 Part.Inventory.GetInventoryItem(ItemID).PermsMask = 0;
892 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; 1016 Part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero;
893 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero;
894 AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID); 1017 AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID);
895 EventQueue.Clear(); 1018 EventQueue.Clear();
896 m_Script.ResetVars(); 1019 m_Script.ResetVars();
1020 StartParam = 0;
897 State = "default"; 1021 State = "default";
898 1022
899 part.SetScriptEvents(ItemID, 1023 Part.SetScriptEvents(ItemID,
900 (int)m_Script.GetStateEventFlags(State)); 1024 (int)m_Script.GetStateEventFlags(State));
901 if (running) 1025 if (running)
902 Start(); 1026 Start();
903 m_SaveState = true; 1027
1028 m_SaveState = StatePersistedHere;
1029
904 PostEvent(new EventParams("state_entry", 1030 PostEvent(new EventParams("state_entry",
905 new Object[0], new DetectParams[0])); 1031 new Object[0], new DetectParams[0]));
906 } 1032 }
@@ -913,21 +1039,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
913 ReleaseControls(); 1039 ReleaseControls();
914 1040
915 m_Script.ResetVars(); 1041 m_Script.ResetVars();
916 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); 1042 Part.Inventory.GetInventoryItem(ItemID).PermsMask = 0;
917 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; 1043 Part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero;
918 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero;
919 AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID); 1044 AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID);
920 1045
921 EventQueue.Clear(); 1046 EventQueue.Clear();
922 m_Script.ResetVars(); 1047 m_Script.ResetVars();
1048 string oldState = State;
1049 StartParam = 0;
923 State = "default"; 1050 State = "default";
924 1051
925 part.SetScriptEvents(ItemID, 1052 Part.SetScriptEvents(ItemID,
926 (int)m_Script.GetStateEventFlags(State)); 1053 (int)m_Script.GetStateEventFlags(State));
927 1054
928 if (m_CurrentEvent != "state_entry") 1055 if (m_CurrentEvent != "state_entry" || oldState != "default")
929 { 1056 {
930 m_SaveState = true; 1057 m_SaveState = StatePersistedHere;
931 PostEvent(new EventParams("state_entry", 1058 PostEvent(new EventParams("state_entry",
932 new Object[0], new DetectParams[0])); 1059 new Object[0], new DetectParams[0]));
933 throw new EventAbortException(); 1060 throw new EventAbortException();
@@ -944,6 +1071,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
944 1071
945 public void SetVars(Dictionary<string, object> vars) 1072 public void SetVars(Dictionary<string, object> vars)
946 { 1073 {
1074// foreach (KeyValuePair<string, object> kvp in vars)
1075// m_log.DebugFormat("[SCRIPT INSTANCE]: Setting var {0}={1}", kvp.Key, kvp.Value);
1076
947 m_Script.SetVars(vars); 1077 m_Script.SetVars(vars);
948 } 1078 }
949 1079
@@ -967,42 +1097,63 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
967 return m_DetectParams[idx].Key; 1097 return m_DetectParams[idx].Key;
968 } 1098 }
969 1099
970 public void SaveState(string assembly) 1100 public void SaveState()
971 { 1101 {
972 // If we're currently in an event, just tell it to save upon return 1102 if (!Running && !StayStopped)
973 //
974 if (m_InEvent)
975 {
976 m_SaveState = true;
977 return; 1103 return;
978 }
979 1104
1105 // We cannot call this inside the EventQueue lock since it will currently take AsyncCommandManager.staticLock.
1106 // This may already be held by AsyncCommandManager.DoOneCmdHandlerPass() which in turn can take EventQueue
1107 // lock via ScriptInstance.PostEvent().
980 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); 1108 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
981 1109
982 string xml = ScriptSerializer.Serialize(this); 1110 // We need to lock here to avoid any race with a thread that is removing this script.
983 1111 lock (EventQueue)
984 // Compare hash of the state we just just created with the state last written to disk
985 // If the state is different, update the disk file.
986 UUID hash = UUID.Parse(Utils.MD5String(xml));
987
988 if (hash != m_CurrentStateHash)
989 { 1112 {
990 try 1113 // Check again to avoid a race with a thread in Stop()
1114 if (!Running && !StayStopped)
1115 return;
1116
1117 // If we're currently in an event, just tell it to save upon return
1118 //
1119 if (m_InEvent)
991 { 1120 {
992 FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")); 1121 m_SaveState = true;
993 Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); 1122 return;
994 fs.Write(buf, 0, buf.Length);
995 fs.Close();
996 } 1123 }
997 catch(Exception) 1124
1125 // m_log.DebugFormat(
1126 // "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
1127 // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
1128
1129 string xml = ScriptSerializer.Serialize(this);
1130
1131 // Compare hash of the state we just just created with the state last written to disk
1132 // If the state is different, update the disk file.
1133 UUID hash = UUID.Parse(Utils.MD5String(xml));
1134
1135 if (hash != m_CurrentStateHash)
998 { 1136 {
999 // m_log.Error("Unable to save xml\n"+e.ToString()); 1137 try
1138 {
1139 using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state")))
1140 {
1141 Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
1142 fs.Write(buf, 0, buf.Length);
1143 }
1144 }
1145 catch(Exception)
1146 {
1147 // m_log.Error("Unable to save xml\n"+e.ToString());
1148 }
1149 //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")))
1150 //{
1151 // throw new Exception("Completed persistence save, but no file was created");
1152 //}
1153 m_CurrentStateHash = hash;
1000 } 1154 }
1001 //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) 1155
1002 //{ 1156 StayStopped = false;
1003 // throw new Exception("Completed persistence save, but no file was created");
1004 //}
1005 m_CurrentStateHash = hash;
1006 } 1157 }
1007 } 1158 }
1008 1159
@@ -1072,7 +1223,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1072 1223
1073 public string GetAssemblyName() 1224 public string GetAssemblyName()
1074 { 1225 {
1075 return m_Assembly; 1226 return m_assemblyPath;
1076 } 1227 }
1077 1228
1078 public string GetXMLState() 1229 public string GetXMLState()
@@ -1109,4 +1260,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1109 Suspended = false; 1260 Suspended = false;
1110 } 1261 }
1111 } 1262 }
1263
1264 /// <summary>
1265 /// Xengine event wait handle.
1266 /// </summary>
1267 /// <remarks>
1268 /// This class exists becase XEngineScriptBase gets a reference to this wait handle. We need to make sure that
1269 /// when scripts are running in different AppDomains the lease does not expire.
1270 /// FIXME: Like LSL_Api, etc., this effectively leaks memory since the GC will never collect it. To avoid this,
1271 /// proper remoting sponsorship needs to be implemented across the board.
1272 /// </remarks>
1273 public class XEngineEventWaitHandle : EventWaitHandle
1274 {
1275 public XEngineEventWaitHandle(bool initialState, EventResetMode mode) : base(initialState, mode) {}
1276
1277 public override Object InitializeLifetimeService()
1278 {
1279 return null;
1280 }
1281 }
1112} 1282}