aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs
blob: def06b27c577157039b0474e7525b2e7b733af9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
 * Copyright (c) Contributors, http://opensimulator.org/
 * See CONTRIBUTORS.TXT for a full list of copyright holders.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSimulator Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Remoting.Lifetime;
using System.Security.Policy;
using System.IO;
using System.Xml;
using System.Text;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.Yengine;
using OpenSim.Region.Framework.Scenes;
using log4net;

using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;

// This class exists in the main app domain
//
namespace OpenSim.Region.ScriptEngine.Yengine
{
    /**
     * @brief Which queue it is in as far as running is concerned,
     *        ie, m_StartQueue, m_YieldQueue, m_SleepQueue, etc.
     * Allowed transitions:
     *   Starts in CONSTRUCT when constructed
     *   CONSTRUCT->ONSTARTQ              : only by thread that constructed and compiled it
     *   IDLE->ONSTARTQ,RESETTING         : by any thread but must have m_QueueLock when transitioning
     *   ONSTARTQ->RUNNING,RESETTING      : only by thread that removed it from m_StartQueue
     *   ONYIELDQ->RUNNING,RESETTING      : only by thread that removed it from m_YieldQueue
     *   ONSLEEPQ->REMDFROMSLPQ           : by any thread but must have m_SleepQueue when transitioning
     *   REMDFROMSLPQ->ONYIELDQ,RESETTING : only by thread that removed it from m_SleepQueue
     *   RUNNING->whatever1               : only by thread that transitioned it to RUNNING
     *                                      whatever1 = IDLE,ONSLEEPQ,ONYIELDQ,ONSTARTQ,SUSPENDED,FINISHED
     *   FINSHED->whatever2               : only by thread that transitioned it to FINISHED
     *                                      whatever2 = IDLE,ONSTARTQ,DISPOSED
     *   SUSPENDED->ONSTARTQ              : by any thread (NOT YET IMPLEMENTED, should be under some kind of lock?)
     *   RESETTING->ONSTARTQ              : only by the thread that transitioned it to RESETTING
     */
    public enum XMRInstState
    {
        CONSTRUCT,     // it is being constructed
        IDLE,          // nothing happening (finished last event and m_EventQueue is empty)
        ONSTARTQ,      // inserted on m_Engine.m_StartQueue
        RUNNING,       // currently being executed by RunOne()
        ONSLEEPQ,      // inserted on m_Engine.m_SleepQueue
        REMDFROMSLPQ,  // removed from m_SleepQueue but not yet on m_YieldQueue
        ONYIELDQ,      // inserted on m_Engine.m_YieldQueue
        FINISHED,      // just finished handling an event
        SUSPENDED,     // m_SuspendCount > 0
        RESETTING,     // being reset via external call
        DISPOSED       // has been disposed
    }

    public partial class XMRInstance: XMRInstAbstract, IDisposable
    {
        /******************************************************************\
         *  This module contains the instance variables for XMRInstance.  *
        \******************************************************************/

        public const int MAXEVENTQUEUE = 64;

        public static readonly DetectParams[] zeroDetectParams = new DetectParams[0];
        public static readonly object[] zeroObjectArray = new object[0];

        public static readonly ILog m_log =
            LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public XMRInstance m_NextInst;  // used by XMRInstQueue
        public XMRInstance m_PrevInst;

        // For a given m_Item.AssetID, do we have the compiled object code and where
        // is it?
        public static object m_CompileLock = new object();
        private static Dictionary<string, ScriptObjCode> m_CompiledScriptObjCode = new Dictionary<string, ScriptObjCode>();

        public XMRInstState m_IState;

        public bool m_ForceRecomp = false;
        public SceneObjectPart m_Part = null;
        public uint m_LocalID = 0;
        public TaskInventoryItem m_Item = null;
        public UUID m_ItemID;
        public UUID m_PartUUID;
        private string m_CameFrom;
        private string m_ScriptObjCodeKey;

        private Yengine m_Engine = null;
        private string m_ScriptBasePath;
        private string m_StateFileName;
        public string m_SourceCode;
        public bool m_PostOnRez;
        private DetectParams[] m_DetectParams = null;
        public int m_StartParam = 0;
        public StateSource m_StateSource;
        public string m_DescName;
        private bool[] m_HaveEventHandlers;
        public int m_StackSize;
        public int m_HeapSize;
        private ArrayList m_CompilerErrors;
        private DateTime m_LastRanAt = DateTime.MinValue;
        private string m_RunOnePhase = "hasn't run";
        private string m_CheckRunPhase = "hasn't checked";
        public int m_InstEHEvent = 0;  // number of events dequeued (StartEventHandler called)
        public int m_InstEHSlice = 0;  // number of times handler timesliced (ResumeEx called)
        public double m_CPUTime = 0;  // accumulated CPU time (milliseconds)
        public double m_SliceStart = 0;  // when did current exec start

        // If code needs to have both m_QueueLock and m_RunLock,
        // be sure to lock m_RunLock first then m_QueueLock, as
        // that is the order used in RunOne().
        // These locks are currently separated to allow the script
        // to call API routines that queue events back to the script.
        // If we just had one lock, then the queuing would deadlock.

        // guards m_DetachQuantum, m_EventQueue, m_EventCounts, m_Running, m_Suspended
        public Object m_QueueLock = new Object();

        // true iff allowed to accept new events
        public bool m_Running = true;

        // queue of events that haven't been acted upon yet
        public LinkedList<EventParams> m_EventQueue = new LinkedList<EventParams>();

        // number of events of each code currently in m_EventQueue.
        private int[] m_EventCounts = new int[(int)ScriptEventCode.Size];

        // locked whilst running on the microthread stack (or about to run on it or just ran on it)
        private Object m_RunLock = new Object();

        // script won't step while > 0.  bus-atomic updates only.
        private int m_SuspendCount = 0;

        // don't run any of script until this time
        // or until one of these events are queued
        public DateTime m_SleepUntil = DateTime.MinValue;
        public int m_SleepEventMask1 = 0;
        public int m_SleepEventMask2 = 0;

        private XMRLSL_Api m_XMRLSLApi;

        /*
         * Makes sure migration data version is same on both ends.
         */
        public static byte migrationVersion = 11;

        // Incremented each time script gets reset.
        public int m_ResetCount = 0;

        // Scripts start suspended now. This means that event queues will
        // accept events, but will not actually run them until the core
        // tells it it's OK. This is needed to prevent loss of link messages
        // in complex objects, where no event can be allowed to run until
        // all possible link message receivers' queues are established.
        // Guarded by m_QueueLock.
        public bool m_Suspended = true;

        // We really don't want to save state for a script that hasn't had
        // a chance to run, because it's state will be blank. That would
        // cause attachment state loss.
        public bool m_HasRun = false;

        // When llDie is executed within the attach(NULL_KEY) event of
        // a script being detached to inventory, the DeleteSceneObject call
        // it causes will delete the script instances before their state can
        // be saved. Therefore, the instance needs to know that it's being
        // detached to inventory, rather than to ground.
        // Also, the attach(NULL_KEY) event needs to run with priority, and
        // it also needs to have a limited quantum.
        // If this is nonzero, we're detaching to inventory.
        // Guarded by m_QueueLock.
        private int m_DetachQuantum = 0;

        // Finally, we need to wait until the quantum is done, or the script
        // suspends itself. This should be efficient, so we use an event
        // for it instead of spinning busy.
        // It's born ready, but will be reset when the detach is posted.
        // It will then be set again on suspend/completion
        private ManualResetEvent m_DetachReady = new ManualResetEvent(true);

        // llmineventdelay support
        double m_minEventDelay = 0.0;
        double m_nextEventTime = 0.0;
    }
}