This GetScriptErrors() change allows initial XEngine to run in background

thread.  It should block only for the case of being called by
CapsUpdateTaskInventoryScriptAsset().
avinationmerge
Mike Rieker 2010-04-18 19:19:16 -04:00
parent 1636f535ba
commit 68a4f897b4
1 changed files with 65 additions and 6 deletions

View File

@ -290,7 +290,7 @@ namespace OpenSim.Region.Framework.Scenes
m_items.LockItemsForWrite(false); m_items.LockItemsForWrite(false);
m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
StoreScriptErrors(item.ItemID, GetScriptErrors(item.ItemID)); StoreScriptErrors(item.ItemID, null);
m_part.ParentGroup.AddActiveScriptCount(1); m_part.ParentGroup.AddActiveScriptCount(1);
m_part.ScheduleFullUpdate(); m_part.ScheduleFullUpdate();
return; return;
@ -319,7 +319,7 @@ namespace OpenSim.Region.Framework.Scenes
string script = Utils.BytesToString(asset.Data); string script = Utils.BytesToString(asset.Data);
m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
StoreScriptErrors(item.ItemID, GetScriptErrors(item.ItemID)); StoreScriptErrors(item.ItemID, null);
m_part.ParentGroup.AddActiveScriptCount(1); m_part.ParentGroup.AddActiveScriptCount(1);
m_part.ScheduleFullUpdate(); m_part.ScheduleFullUpdate();
} }
@ -388,11 +388,22 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Start a script which is in this prim's inventory. /// Start a script which is in this prim's inventory.
/// Some processing may occur in the background, but this routine returns asap.
/// </summary> /// </summary>
/// <param name="itemId"> /// <param name="itemId">
/// A <see cref="UUID"/> /// A <see cref="UUID"/>
/// </param> /// </param>
public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
{
lock (m_scriptErrors)
{
// Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion
m_scriptErrors.Remove(itemId);
}
CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
}
private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
{ {
m_items.LockItemsForRead(true); m_items.LockItemsForRead(true);
if (m_items.ContainsKey(itemId)) if (m_items.ContainsKey(itemId))
@ -425,25 +436,38 @@ namespace OpenSim.Region.Framework.Scenes
} }
/// <summary>
/// Start a script which is in this prim's inventory and return any compilation error messages.
/// </summary>
/// <param name="itemId">
/// A <see cref="UUID"/>
/// </param>
public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
{ {
ArrayList errors; ArrayList errors;
// Indicate to CreateScriptInstanceInternal() we want it to
// post any compilation/loading error messages
lock (m_scriptErrors) lock (m_scriptErrors)
{ {
m_scriptErrors.Remove(itemId); m_scriptErrors[itemId] = null;
} }
CreateScriptInstance(itemId, startParam, postOnRez, engine, stateSource);
// Perform compilation/loading
CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
// Wait for and retrieve any errors
lock (m_scriptErrors) lock (m_scriptErrors)
{ {
while (!m_scriptErrors.TryGetValue(itemId, out errors)) while ((errors = m_scriptErrors[itemId]) == null)
{ {
if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000)) if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000))
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[PRIM INVENTORY]: " + "[PRIM INVENTORY]: " +
"timedout waiting for script {0} errors", itemId); "timedout waiting for script {0} errors", itemId);
if (!m_scriptErrors.TryGetValue(itemId, out errors)) errors = m_scriptErrors[itemId];
if (errors == null)
{ {
errors = new ArrayList(1); errors = new ArrayList(1);
errors.Add("timedout waiting for errors"); errors.Add("timedout waiting for errors");
@ -455,14 +479,49 @@ namespace OpenSim.Region.Framework.Scenes
} }
return errors; return errors;
} }
// Signal to CreateScriptInstanceEr() that compilation/loading is complete
private void StoreScriptErrors(UUID itemId, ArrayList errors) private void StoreScriptErrors(UUID itemId, ArrayList errors)
{ {
lock (m_scriptErrors)
{
// If compilation/loading initiated via CreateScriptInstance(),
// it does not want the errors, so just get out
if (!m_scriptErrors.ContainsKey(itemId))
{
return;
}
// Initiated via CreateScriptInstanceEr(), if we know what the
// errors are, save them and wake CreateScriptInstanceEr().
if (errors != null)
{
m_scriptErrors[itemId] = errors;
System.Threading.Monitor.PulseAll(m_scriptErrors);
return;
}
}
// Initiated via CreateScriptInstanceEr() but we don't know what
// the errors are yet, so retrieve them from the script engine.
// This may involve some waiting internal to GetScriptErrors().
errors = GetScriptErrors(itemId);
// Get a default non-null value to indicate success.
if (errors == null)
{
errors = new ArrayList();
}
// Post to CreateScriptInstanceEr() and wake it up
lock (m_scriptErrors) lock (m_scriptErrors)
{ {
m_scriptErrors[itemId] = errors; m_scriptErrors[itemId] = errors;
System.Threading.Monitor.PulseAll(m_scriptErrors); System.Threading.Monitor.PulseAll(m_scriptErrors);
} }
} }
// Like StoreScriptErrors(), but just posts a single string message
private void StoreScriptError(UUID itemId, string message) private void StoreScriptError(UUID itemId, string message)
{ {
ArrayList errors = new ArrayList(1); ArrayList errors = new ArrayList(1);