aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs240
1 files changed, 240 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs
new file mode 100644
index 0000000..08c7e80
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs
@@ -0,0 +1,240 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Framework.Monitoring;
29using System;
30using System.Collections.Generic;
31using System.Threading;
32
33namespace OpenSim.Region.ScriptEngine.Yengine
34{
35
36 public partial class Yengine
37 {
38 private int m_WakeUpOne = 0;
39 public object m_WakeUpLock = new object();
40
41 private Dictionary<int, XMRInstance> m_RunningInstances = new Dictionary<int, XMRInstance>();
42
43 private bool m_SuspendScriptThreadFlag = false;
44 private bool m_WakeUpThis = false;
45 public DateTime m_LastRanAt = DateTime.MinValue;
46 public long m_ScriptExecTime = 0;
47
48 [ThreadStatic]
49 private static int m_ScriptThreadTID;
50
51 public static bool IsScriptThread
52 {
53 get
54 {
55 return m_ScriptThreadTID != 0;
56 }
57 }
58
59 public void StartThreadWorker(int i)
60 {
61 Thread thd;
62 if(i >= 0)
63 thd = Yengine.StartMyThread(RunScriptThread, "YScript" + i.ToString(), ThreadPriority.BelowNormal);
64 else
65 thd = Yengine.StartMyThread(RunScriptThread, "YScript", ThreadPriority.BelowNormal);
66 lock(m_WakeUpLock)
67 m_RunningInstances.Add(thd.ManagedThreadId, null);
68 }
69
70 public void StopThreadWorkers()
71 {
72 lock(m_WakeUpLock)
73 {
74 while(m_RunningInstances.Count != 0)
75 {
76 Monitor.PulseAll(m_WakeUpLock);
77 Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
78 }
79 }
80 }
81
82 /**
83 * @brief Something was just added to the Start or Yield queue so
84 * wake one of the RunScriptThread() instances to run it.
85 */
86 public void WakeUpOne()
87 {
88 lock(m_WakeUpLock)
89 {
90 m_WakeUpOne++;
91 Monitor.Pulse(m_WakeUpLock);
92 }
93 }
94
95 public void SuspendThreads()
96 {
97 lock(m_WakeUpLock)
98 {
99 m_SuspendScriptThreadFlag = true;
100 Monitor.PulseAll(m_WakeUpLock);
101 }
102 }
103
104 public void ResumeThreads()
105 {
106 lock(m_WakeUpLock)
107 {
108 m_SuspendScriptThreadFlag = false;
109 Monitor.PulseAll(m_WakeUpLock);
110 }
111 }
112
113 /**
114 * @brief Thread that runs the scripts.
115 *
116 * There are NUMSCRIPTHREADWKRS of these.
117 * Each sits in a loop checking the Start and Yield queues for
118 * a script to run and calls the script as a microthread.
119 */
120 private void RunScriptThread()
121 {
122 int tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
123 ThreadStart thunk;
124 XMRInstance inst;
125 bool didevent;
126 m_ScriptThreadTID = tid;
127
128 while(!m_Exiting)
129 {
130 Yengine.UpdateMyThread();
131
132 lock(m_WakeUpLock)
133 {
134 // Maybe there are some scripts waiting to be migrated in or out.
135 thunk = null;
136 if(m_ThunkQueue.Count > 0)
137 thunk = m_ThunkQueue.Dequeue();
138
139 // Handle 'xmr resume/suspend' commands.
140 else if(m_SuspendScriptThreadFlag && !m_Exiting)
141 {
142 Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
143 Yengine.UpdateMyThread();
144 continue;
145 }
146 }
147
148 if(thunk != null)
149 {
150 thunk();
151 continue;
152 }
153
154 if(m_StartProcessing)
155 {
156 // If event just queued to any idle scripts
157 // start them right away. But only start so
158 // many so we can make some progress on yield
159 // queue.
160 int numStarts;
161 didevent = false;
162 for(numStarts = 5; numStarts >= 0; --numStarts)
163 {
164 lock(m_StartQueue)
165 inst = m_StartQueue.RemoveHead();
166
167 if(inst == null)
168 break;
169 if(inst.m_IState != XMRInstState.ONSTARTQ)
170 throw new Exception("bad state");
171 RunInstance(inst, tid);
172 if(m_SuspendScriptThreadFlag || m_Exiting)
173 continue;
174 didevent = true;
175 }
176
177 // If there is something to run, run it
178 // then rescan from the beginning in case
179 // a lot of things have changed meanwhile.
180 //
181 // These are considered lower priority than
182 // m_StartQueue as they have been taking at
183 // least one quantum of CPU time and event
184 // handlers are supposed to be quick.
185 lock(m_YieldQueue)
186 inst = m_YieldQueue.RemoveHead();
187
188 if(inst != null)
189 {
190 if(inst.m_IState != XMRInstState.ONYIELDQ)
191 throw new Exception("bad state");
192 RunInstance(inst, tid);
193 continue;
194 }
195
196 // If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it.
197 if(didevent)
198 continue;
199 }
200
201 // Nothing to do, sleep.
202 lock(m_WakeUpLock)
203 {
204 if(!m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting)
205 Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
206
207 m_WakeUpThis = false;
208 if((m_WakeUpOne > 0) && (--m_WakeUpOne > 0))
209 Monitor.Pulse(m_WakeUpLock);
210 }
211 }
212 lock(m_WakeUpLock)
213 m_RunningInstances.Remove(tid);
214
215 Yengine.MyThreadExiting();
216 }
217
218 /**
219 * @brief A script instance was just removed from the Start or Yield Queue.
220 * So run it for a little bit then stick in whatever queue it should go in.
221 */
222 private void RunInstance(XMRInstance inst, int tid)
223 {
224 m_LastRanAt = DateTime.UtcNow;
225 m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds;
226 inst.m_IState = XMRInstState.RUNNING;
227
228 lock(m_WakeUpLock)
229 m_RunningInstances[tid] = inst;
230
231 XMRInstState newIState = inst.RunOne();
232
233 lock(m_WakeUpLock)
234 m_RunningInstances[tid] = null;
235
236 HandleNewIState(inst, newIState);
237 m_ScriptExecTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
238 }
239 }
240}