aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2015-01-16 23:55:00 +0000
committerJustin Clark-Casey (justincc)2015-01-16 23:55:11 +0000
commitfaaf47a86f34f24dec0d7d51eda638d0df3db305 (patch)
tree999a9351ae53e4ecc0b465e8e1bea744cb335837
parentFor scripts in attachments, don't save .state files apart from the initial on... (diff)
downloadopensim-SC-faaf47a86f34f24dec0d7d51eda638d0df3db305.zip
opensim-SC-faaf47a86f34f24dec0d7d51eda638d0df3db305.tar.gz
opensim-SC-faaf47a86f34f24dec0d7d51eda638d0df3db305.tar.bz2
opensim-SC-faaf47a86f34f24dec0d7d51eda638d0df3db305.tar.xz
Prevent a race condition between the script engine backup thread and script removal by locking on the script's EventQueue and only proceeding if it's flagged as still running.
Relates to http://opensimulator.org/mantis/view.php?id=7407
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs3
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs70
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs6
3 files changed, 44 insertions, 35 deletions
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 35e5f18..fa2ceef 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -178,8 +178,9 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
178 /// <param name="timeout"></param> 178 /// <param name="timeout"></param>
179 /// How many milliseconds we will wait for an existing script event to finish before 179 /// How many milliseconds we will wait for an existing script event to finish before
180 /// forcibly aborting that event. 180 /// forcibly aborting that event.
181 /// <param name="clearEventQueue">If true then the event queue is also cleared</param>
181 /// <returns>true if the script was successfully stopped, false otherwise</returns> 182 /// <returns>true if the script was successfully stopped, false otherwise</returns>
182 bool Stop(int timeout); 183 bool Stop(int timeout, bool clearEventQueue = false);
183 184
184 void SetState(string state); 185 void SetState(string state);
185 186
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 9498aa8..e202a24 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -564,7 +564,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
564 } 564 }
565 } 565 }
566 566
567 public bool Stop(int timeout) 567 public bool Stop(int timeout, bool clearEventQueue = false)
568 { 568 {
569 if (DebugLevel >= 1) 569 if (DebugLevel >= 1)
570 m_log.DebugFormat( 570 m_log.DebugFormat(
@@ -575,6 +575,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
575 575
576 lock (EventQueue) 576 lock (EventQueue)
577 { 577 {
578 if (clearEventQueue)
579 ClearQueue();
580
578 if (!Running) 581 if (!Running)
579 return true; 582 return true;
580 583
@@ -1065,45 +1068,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1065 1068
1066 public void SaveState() 1069 public void SaveState()
1067 { 1070 {
1068 // If we're currently in an event, just tell it to save upon return 1071 // We need to lock here to avoid any race with a thread that is removing this script.
1069 // 1072 lock (EventQueue)
1070 if (m_InEvent)
1071 { 1073 {
1072 m_SaveState = true; 1074 if (!Running)
1073 return; 1075 return;
1074 }
1075 1076
1076// m_log.DebugFormat( 1077 // If we're currently in an event, just tell it to save upon return
1077// "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}", 1078 //
1078// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name); 1079 if (m_InEvent)
1080 {
1081 m_SaveState = true;
1082 return;
1083 }
1079 1084
1080 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); 1085 // m_log.DebugFormat(
1086 // "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
1087 // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
1081 1088
1082 string xml = ScriptSerializer.Serialize(this); 1089 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
1083 1090
1084 // Compare hash of the state we just just created with the state last written to disk 1091 string xml = ScriptSerializer.Serialize(this);
1085 // If the state is different, update the disk file.
1086 UUID hash = UUID.Parse(Utils.MD5String(xml));
1087 1092
1088 if (hash != m_CurrentStateHash) 1093 // Compare hash of the state we just just created with the state last written to disk
1089 { 1094 // If the state is different, update the disk file.
1090 try 1095 UUID hash = UUID.Parse(Utils.MD5String(xml));
1096
1097 if (hash != m_CurrentStateHash)
1091 { 1098 {
1092 using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state"))) 1099 try
1100 {
1101 using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state")))
1102 {
1103 Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
1104 fs.Write(buf, 0, buf.Length);
1105 }
1106 }
1107 catch(Exception)
1093 { 1108 {
1094 Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); 1109 // m_log.Error("Unable to save xml\n"+e.ToString());
1095 fs.Write(buf, 0, buf.Length);
1096 } 1110 }
1111 //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")))
1112 //{
1113 // throw new Exception("Completed persistence save, but no file was created");
1114 //}
1115 m_CurrentStateHash = hash;
1097 } 1116 }
1098 catch(Exception)
1099 {
1100 // m_log.Error("Unable to save xml\n"+e.ToString());
1101 }
1102 //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")))
1103 //{
1104 // throw new Exception("Completed persistence save, but no file was created");
1105 //}
1106 m_CurrentStateHash = hash;
1107 } 1117 }
1108 } 1118 }
1109 1119
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 03fafed..1a64595 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -732,8 +732,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
732 732
733 // Clear the event queue and abort the instance thread 733 // Clear the event queue and abort the instance thread
734 // 734 //
735 instance.ClearQueue(); 735 instance.Stop(0, true);
736 instance.Stop(0);
737 736
738 // Release events, timer, etc 737 // Release events, timer, etc
739 // 738 //
@@ -859,8 +858,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
859 } 858 }
860 } 859 }
861 860
862 instances.Clear();
863
864 if (saveTime > 0) 861 if (saveTime > 0)
865 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), 862 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
866 new Object[] { saveTime }); 863 new Object[] { saveTime });
@@ -1443,6 +1440,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1443 m_Scripts.Remove(itemID); 1440 m_Scripts.Remove(itemID);
1444 } 1441 }
1445 1442
1443
1446 instance.ClearQueue(); 1444 instance.ClearQueue();
1447 1445
1448 instance.Stop(m_WaitForEventCompletionOnScriptStop); 1446 instance.Stop(m_WaitForEventCompletionOnScriptStop);