diff options
author | Tedd Hansen | 2007-08-19 11:09:54 +0000 |
---|---|---|
committer | Tedd Hansen | 2007-08-19 11:09:54 +0000 |
commit | 7770c65a7e888739dfb0c8a9ccf2dc521e99a33a (patch) | |
tree | e5542e0b0427b16a70d5dc98194330cd042fd1c4 | |
parent | Added event method invoke cache to Executor. "Bind once, Invoke multiple time... (diff) | |
download | opensim-SC_OLD-7770c65a7e888739dfb0c8a9ccf2dc521e99a33a.zip opensim-SC_OLD-7770c65a7e888739dfb0c8a9ccf2dc521e99a33a.tar.gz opensim-SC_OLD-7770c65a7e888739dfb0c8a9ccf2dc521e99a33a.tar.bz2 opensim-SC_OLD-7770c65a7e888739dfb0c8a9ccf2dc521e99a33a.tar.xz |
Sped up EventQueueManager response time (scripts now respond quickly). Added support for multiple threads executing events on objects, but only one thread on one script at the time (to utilize MultiCore/hyperthreading CPU's).
-rw-r--r-- | OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs | 156 |
1 files changed, 117 insertions, 39 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs index 311d32b..ec34bb0 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs | |||
@@ -42,8 +42,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
42 | [Serializable] | 42 | [Serializable] |
43 | class EventQueueManager | 43 | class EventQueueManager |
44 | { | 44 | { |
45 | private Thread EventQueueThread; | 45 | private List<Thread> EventQueueThreads = new List<Thread>(); |
46 | private int NothingToDoSleepms = 200; | 46 | private object QueueLock = new object(); |
47 | private int NothingToDoSleepms = 50; | ||
48 | private int NumberOfThreads = 2; | ||
47 | private Queue<QueueItemStruct> EventQueue = new Queue<QueueItemStruct>(); | 49 | private Queue<QueueItemStruct> EventQueue = new Queue<QueueItemStruct>(); |
48 | private struct QueueItemStruct | 50 | private struct QueueItemStruct |
49 | { | 51 | { |
@@ -59,26 +61,36 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
59 | myScriptEngine = _ScriptEngine; | 61 | myScriptEngine = _ScriptEngine; |
60 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Start"); | 62 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Start"); |
61 | // Start worker thread | 63 | // Start worker thread |
62 | EventQueueThread = new Thread(EventQueueThreadLoop); | 64 | |
63 | EventQueueThread.IsBackground = true; | 65 | for (int ThreadCount = 0; ThreadCount <= NumberOfThreads; ThreadCount++) |
64 | EventQueueThread.Name = "EventQueueManagerThread"; | 66 | { |
65 | EventQueueThread.Start(); | 67 | Thread EventQueueThread = new Thread(EventQueueThreadLoop); |
68 | EventQueueThreads.Add(EventQueueThread); | ||
69 | EventQueueThread.IsBackground = true; | ||
70 | EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; | ||
71 | EventQueueThread.Start(); | ||
72 | } | ||
66 | } | 73 | } |
67 | ~EventQueueManager() | 74 | ~EventQueueManager() |
68 | { | 75 | { |
69 | // Kill worker thread | 76 | |
70 | if (EventQueueThread != null && EventQueueThread.IsAlive == true) | 77 | // Kill worker threads |
78 | foreach (Thread EventQueueThread in new System.Collections.ArrayList(EventQueueThreads)) | ||
71 | { | 79 | { |
72 | try | 80 | if (EventQueueThread != null && EventQueueThread.IsAlive == true) |
73 | { | ||
74 | EventQueueThread.Abort(); | ||
75 | EventQueueThread.Join(); | ||
76 | } | ||
77 | catch (Exception e) | ||
78 | { | 81 | { |
79 | myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); | 82 | try |
83 | { | ||
84 | EventQueueThread.Abort(); | ||
85 | EventQueueThread.Join(); | ||
86 | } | ||
87 | catch (Exception e) | ||
88 | { | ||
89 | myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); | ||
90 | } | ||
80 | } | 91 | } |
81 | } | 92 | } |
93 | EventQueueThreads.Clear(); | ||
82 | // Todo: Clean up our queues | 94 | // Todo: Clean up our queues |
83 | 95 | ||
84 | } | 96 | } |
@@ -88,8 +100,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
88 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); | 100 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); |
89 | try | 101 | try |
90 | { | 102 | { |
103 | QueueItemStruct BlankQIS = new QueueItemStruct(); | ||
91 | while (true) | 104 | while (true) |
92 | { | 105 | { |
106 | QueueItemStruct QIS = BlankQIS; | ||
107 | bool GotItem = false; | ||
108 | |||
93 | if (EventQueue.Count == 0) | 109 | if (EventQueue.Count == 0) |
94 | { | 110 | { |
95 | // Nothing to do? Sleep a bit waiting for something to do | 111 | // Nothing to do? Sleep a bit waiting for something to do |
@@ -98,45 +114,107 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine | |||
98 | else | 114 | else |
99 | { | 115 | { |
100 | // Something in queue, process | 116 | // Something in queue, process |
101 | QueueItemStruct QIS = EventQueue.Dequeue(); | ||
102 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for ObjectID: " + QIS.ObjectID + ", ScriptID: " + QIS.ScriptID + ", FunctionName: " + QIS.FunctionName); | 117 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for ObjectID: " + QIS.ObjectID + ", ScriptID: " + QIS.ScriptID + ", FunctionName: " + QIS.FunctionName); |
103 | // TODO: Execute function | 118 | |
104 | myScriptEngine.myScriptManager.ExecuteEvent(QIS.ObjectID, QIS.ScriptID, QIS.FunctionName, QIS.param); | 119 | // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD |
105 | } | 120 | lock (QueueLock) |
106 | } | 121 | { |
107 | } | 122 | GotItem = false; |
123 | for (int qc = 0; qc < EventQueue.Count; qc++) | ||
124 | { | ||
125 | // Get queue item | ||
126 | QIS = EventQueue.Dequeue(); | ||
127 | |||
128 | // Check if object is being processed by someone else | ||
129 | if (TryLock(QIS.ObjectID) == false) | ||
130 | { | ||
131 | // Object is already being processed, requeue it | ||
132 | EventQueue.Enqueue(QIS); | ||
133 | } | ||
134 | else | ||
135 | { | ||
136 | // We have lock on an object and can process it | ||
137 | GotItem = true; | ||
138 | break; | ||
139 | } | ||
140 | } // go through queue | ||
141 | } // lock | ||
142 | |||
143 | if (GotItem == true) | ||
144 | { | ||
145 | // Execute function | ||
146 | myScriptEngine.myScriptManager.ExecuteEvent(QIS.ObjectID, QIS.ScriptID, QIS.FunctionName, QIS.param); | ||
147 | ReleaseLock(QIS.ObjectID); | ||
148 | } | ||
149 | |||
150 | } // Something in queue | ||
151 | } // while | ||
152 | } // try | ||
108 | catch (ThreadAbortException tae) | 153 | catch (ThreadAbortException tae) |
109 | { | 154 | { |
110 | myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); | 155 | myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); |
111 | } | 156 | } |
112 | } | 157 | } |
113 | 158 | ||
159 | private List<IScriptHost> ObjectLocks = new List<IScriptHost>(); | ||
160 | private object TryLockLock = new object(); | ||
161 | private bool TryLock(IScriptHost ObjectID) | ||
162 | { | ||
163 | lock (TryLockLock) | ||
164 | { | ||
165 | if (ObjectLocks.Contains(ObjectID) == true) | ||
166 | { | ||
167 | return false; | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | ObjectLocks.Add(ObjectID); | ||
172 | return true; | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | private void ReleaseLock(IScriptHost ObjectID) | ||
178 | { | ||
179 | lock (TryLockLock) | ||
180 | { | ||
181 | if (ObjectLocks.Contains(ObjectID) == true) | ||
182 | { | ||
183 | ObjectLocks.Remove(ObjectID); | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
114 | public void AddToObjectQueue(IScriptHost ObjectID, string FunctionName, object[] param) | 188 | public void AddToObjectQueue(IScriptHost ObjectID, string FunctionName, object[] param) |
115 | { | 189 | { |
116 | // Determine all scripts in Object and add to their queue | 190 | // Determine all scripts in Object and add to their queue |
117 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding ObjectID: " + ObjectID + ", FunctionName: " + FunctionName); | 191 | //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding ObjectID: " + ObjectID + ", FunctionName: " + FunctionName); |
118 | 192 | ||
119 | foreach (string ScriptID in myScriptEngine.myScriptManager.GetScriptKeys(ObjectID)) | 193 | lock (QueueLock) |
120 | { | 194 | { |
121 | // Add to each script in that object | 195 | |
122 | // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? | 196 | foreach (string ScriptID in myScriptEngine.myScriptManager.GetScriptKeys(ObjectID)) |
123 | 197 | { | |
124 | // Create a structure and add data | 198 | // Add to each script in that object |
125 | QueueItemStruct QIS = new QueueItemStruct(); | 199 | // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? |
126 | QIS.ObjectID = ObjectID; | 200 | |
127 | QIS.ScriptID = ScriptID; | 201 | // Create a structure and add data |
128 | QIS.FunctionName = FunctionName; | 202 | QueueItemStruct QIS = new QueueItemStruct(); |
129 | QIS.param = param; | 203 | QIS.ObjectID = ObjectID; |
130 | 204 | QIS.ScriptID = ScriptID; | |
131 | // Add it to queue | 205 | QIS.FunctionName = FunctionName; |
132 | EventQueue.Enqueue(QIS); | 206 | QIS.param = param; |
133 | 207 | ||
208 | // Add it to queue | ||
209 | EventQueue.Enqueue(QIS); | ||
210 | |||
211 | } | ||
134 | } | 212 | } |
213 | //public void AddToScriptQueue(string ObjectID, string FunctionName, object[] param) | ||
214 | //{ | ||
215 | // // Add to script queue | ||
216 | //} | ||
135 | } | 217 | } |
136 | //public void AddToScriptQueue(string ObjectID, string FunctionName, object[] param) | ||
137 | //{ | ||
138 | // // Add to script queue | ||
139 | //} | ||
140 | 218 | ||
141 | } | 219 | } |
142 | } | 220 | } |