aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDiva Canto2013-05-06 09:18:17 -0700
committerDiva Canto2013-05-06 09:18:17 -0700
commita81ddf3d7097a2e0959080ae7291357435b0bd5b (patch)
tree688ceb63aa41d8eb9d3af27bd57d39cbd38ca250
parentMinor reordering of operations on NewUserConnection. The agent circuit needs ... (diff)
parentMerge branch 'master' into bulletsim4 (diff)
downloadopensim-SC_OLD-a81ddf3d7097a2e0959080ae7291357435b0bd5b.zip
opensim-SC_OLD-a81ddf3d7097a2e0959080ae7291357435b0bd5b.tar.gz
opensim-SC_OLD-a81ddf3d7097a2e0959080ae7291357435b0bd5b.tar.bz2
opensim-SC_OLD-a81ddf3d7097a2e0959080ae7291357435b0bd5b.tar.xz
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
-rw-r--r--OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs23
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs1
-rw-r--r--OpenSim/Capabilities/CapsHandlers.cs7
-rw-r--r--OpenSim/Framework/IScene.cs7
-rw-r--r--OpenSim/Framework/Util.cs20
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs13
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs101
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs449
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs11
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs43
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs111
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs12
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs142
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs6
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs6
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActors.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs127
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs2
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs41
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs21
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs272
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs20
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs12
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs11
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs77
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs220
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs22
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs21
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs3
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs1019
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs712
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs30
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs60
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs56
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs48
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt18
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs7
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs6
-rw-r--r--OpenSim/Server/Base/ServicesServerBase.cs5
-rw-r--r--OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs41
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs16
-rw-r--r--OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs28
-rw-r--r--ThirdParty/SmartThreadPool/AssemblyInfo.cs61
-rw-r--r--ThirdParty/SmartThreadPool/CallerThreadContext.cs309
-rw-r--r--ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs14
-rw-r--r--ThirdParty/SmartThreadPool/EventWaitHandle.cs104
-rw-r--r--ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs82
-rw-r--r--ThirdParty/SmartThreadPool/Exceptions.cs82
-rw-r--r--ThirdParty/SmartThreadPool/Interfaces.cs703
-rw-r--r--ThirdParty/SmartThreadPool/InternalInterfaces.cs27
-rw-r--r--ThirdParty/SmartThreadPool/PriorityQueue.cs465
-rw-r--r--ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs23
-rw-r--r--ThirdParty/SmartThreadPool/SLExt.cs16
-rw-r--r--ThirdParty/SmartThreadPool/STPEventWaitHandle.cs62
-rw-r--r--ThirdParty/SmartThreadPool/STPPerformanceCounter.cs648
-rw-r--r--ThirdParty/SmartThreadPool/STPStartInfo.cs269
-rw-r--r--ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs60
-rw-r--r--ThirdParty/SmartThreadPool/SmartThreadPool.cs2562
-rw-r--r--ThirdParty/SmartThreadPool/SynchronizedDictionary.cs89
-rw-r--r--ThirdParty/SmartThreadPool/WIGStartInfo.cs218
-rw-r--r--ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs190
-rw-r--r--ThirdParty/SmartThreadPool/WorkItem.cs659
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemFactory.cs628
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemInfo.cs145
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs128
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemsGroup.cs759
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs471
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemsQueue.cs973
-rw-r--r--bin/Robust.HG.ini.example27
-rw-r--r--bin/Robust.ini.example28
-rw-r--r--prebuild.xml1
82 files changed, 7953 insertions, 5745 deletions
diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs
index fcb6991..1d63d26 100644
--- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs
+++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs
@@ -115,6 +115,8 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
115 Environment.Exit(1); 115 Environment.Exit(1);
116 } 116 }
117 117
118 List<IScene> createdScenes = new List<IScene>();
119
118 for (int i = 0; i < regionsToLoad.Length; i++) 120 for (int i = 0; i < regionsToLoad.Length; i++)
119 { 121 {
120 IScene scene; 122 IScene scene;
@@ -123,17 +125,22 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
123 ")"); 125 ")");
124 126
125 bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); 127 bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]);
128
126 m_openSim.CreateRegion(regionsToLoad[i], true, out scene); 129 m_openSim.CreateRegion(regionsToLoad[i], true, out scene);
130 createdScenes.Add(scene);
131
127 if (changed) 132 if (changed)
128 regionsToLoad[i].EstateSettings.Save(); 133 regionsToLoad[i].EstateSettings.Save();
129 134 }
130 if (scene != null) 135
136 foreach (IScene scene in createdScenes)
137 {
138 scene.Start();
139
140 m_newRegionCreatedHandler = OnNewRegionCreated;
141 if (m_newRegionCreatedHandler != null)
131 { 142 {
132 m_newRegionCreatedHandler = OnNewRegionCreated; 143 m_newRegionCreatedHandler(scene);
133 if (m_newRegionCreatedHandler != null)
134 {
135 m_newRegionCreatedHandler(scene);
136 }
137 } 144 }
138 } 145 }
139 } 146 }
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index d19b8b6..355f7b3 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -700,6 +700,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
700 700
701 IScene newScene; 701 IScene newScene;
702 m_application.CreateRegion(region, out newScene); 702 m_application.CreateRegion(region, out newScene);
703 newScene.Start();
703 704
704 // If an access specification was provided, use it. 705 // If an access specification was provided, use it.
705 // Otherwise accept the default. 706 // Otherwise accept the default.
diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs
index 1709f46..458272d 100644
--- a/OpenSim/Capabilities/CapsHandlers.cs
+++ b/OpenSim/Capabilities/CapsHandlers.cs
@@ -158,7 +158,7 @@ namespace OpenSim.Framework.Capabilities
158 /// capabilities and their handler details. 158 /// capabilities and their handler details.
159 /// </summary> 159 /// </summary>
160 /// <param name="excludeSeed">If true, then exclude the seed cap.</param> 160 /// <param name="excludeSeed">If true, then exclude the seed cap.</param>
161 public Hashtable GetCapsDetails(bool excludeSeed) 161 public Hashtable GetCapsDetails(bool excludeSeed, List<string> requestedCaps)
162 { 162 {
163 Hashtable caps = new Hashtable(); 163 Hashtable caps = new Hashtable();
164 string protocol = "http://"; 164 string protocol = "http://";
@@ -175,6 +175,9 @@ namespace OpenSim.Framework.Capabilities
175 if (excludeSeed && "SEED" == capsName) 175 if (excludeSeed && "SEED" == capsName)
176 continue; 176 continue;
177 177
178 if (requestedCaps != null && !requestedCaps.Contains(capsName))
179 continue;
180
178 caps[capsName] = baseUrl + m_capsHandlers[capsName].Path; 181 caps[capsName] = baseUrl + m_capsHandlers[capsName].Path;
179 } 182 }
180 } 183 }
@@ -182,4 +185,4 @@ namespace OpenSim.Framework.Capabilities
182 return caps; 185 return caps;
183 } 186 }
184 } 187 }
185} \ No newline at end of file 188}
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index 87ec99e..8164f41 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -136,5 +136,10 @@ namespace OpenSim.Framework
136 ISceneObject DeserializeObject(string representation); 136 ISceneObject DeserializeObject(string representation);
137 137
138 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); 138 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep);
139
140 /// <summary>
141 /// Start the scene and associated scripts within it.
142 /// </summary>
143 void Start();
139 } 144 }
140} 145} \ No newline at end of file
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index bde4673..a3602e9 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1840,7 +1840,7 @@ namespace OpenSim.Framework
1840 case FireAndForgetMethod.SmartThreadPool: 1840 case FireAndForgetMethod.SmartThreadPool:
1841 if (m_ThreadPool == null) 1841 if (m_ThreadPool == null)
1842 InitThreadPool(15); 1842 InitThreadPool(15);
1843 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1843 m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
1844 break; 1844 break;
1845 case FireAndForgetMethod.Thread: 1845 case FireAndForgetMethod.Thread:
1846 Thread thread = new Thread(delegate(object o) { realCallback(o); }); 1846 Thread thread = new Thread(delegate(object o) { realCallback(o); });
@@ -1910,15 +1910,15 @@ namespace OpenSim.Framework
1910 return sb.ToString(); 1910 return sb.ToString();
1911 } 1911 }
1912 1912
1913 private static object SmartThreadPoolCallback(object o) 1913// private static object SmartThreadPoolCallback(object o)
1914 { 1914// {
1915 object[] array = (object[])o; 1915// object[] array = (object[])o;
1916 WaitCallback callback = (WaitCallback)array[0]; 1916// WaitCallback callback = (WaitCallback)array[0];
1917 object obj = array[1]; 1917// object obj = array[1];
1918 1918//
1919 callback(obj); 1919// callback(obj);
1920 return null; 1920// return null;
1921 } 1921// }
1922 1922
1923 #endregion FireAndForget Threading Pattern 1923 #endregion FireAndForget Threading Pattern
1924 1924
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index d86eefe..f9e0cf1 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -425,9 +425,6 @@ namespace OpenSim
425 425
426 mscene = scene; 426 mscene = scene;
427 427
428 scene.Start();
429 scene.StartScripts();
430
431 return clientServers; 428 return clientServers;
432 } 429 }
433 430
@@ -751,6 +748,7 @@ namespace OpenSim
751 ShutdownClientServer(whichRegion); 748 ShutdownClientServer(whichRegion);
752 IScene scene; 749 IScene scene;
753 CreateRegion(whichRegion, true, out scene); 750 CreateRegion(whichRegion, true, out scene);
751 scene.Start();
754 } 752 }
755 753
756 # region Setup methods 754 # region Setup methods
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 8752404..a46c24a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -273,11 +273,22 @@ namespace OpenSim.Region.ClientStack.Linden
273 return string.Empty; 273 return string.Empty;
274 } 274 }
275 275
276 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true); 276 OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request);
277 List<string> validCaps = new List<string>();
278
279 foreach (OSD c in capsRequested)
280 validCaps.Add(c.AsString());
281
282 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps);
277 283
278 // Add the external too 284 // Add the external too
279 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers) 285 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
286 {
287 if (!validCaps.Contains(kvp.Key))
288 continue;
289
280 caps[kvp.Key] = kvp.Value; 290 caps[kvp.Key] = kvp.Value;
291 }
281 292
282 string result = LLSDHelpers.SerialiseLLSDReply(caps); 293 string result = LLSDHelpers.SerialiseLLSDReply(caps);
283 294
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..a0e0078 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -75,6 +75,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
75 [SetUp] 75 [SetUp]
76 public void SetUp() 76 public void SetUp()
77 { 77 {
78 base.SetUp();
79
78 UUID userId = TestHelpers.ParseTail(0x3); 80 UUID userId = TestHelpers.ParseTail(0x3);
79 81
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 82 J2KDecoderModule j2kdm = new J2KDecoderModule();
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index bcb7f42..1417a19 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -47,10 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
47 47
48 /// <summary> 48 /// <summary>
49 private List<Scene> m_Scenelist = new List<Scene>(); 49 private List<Scene> m_Scenelist = new List<Scene>();
50// private Dictionary<UUID, Scene> m_AgentRegions =
51// new Dictionary<UUID, Scene>();
52 50
53 private IMessageTransferModule m_TransferModule = null; 51 private IMessageTransferModule m_TransferModule;
54 private bool m_Enabled = true; 52 private bool m_Enabled = true;
55 53
56 #region Region Module interface 54 #region Region Module interface
@@ -81,9 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
81// scene.RegisterModuleInterface<IInventoryTransferModule>(this); 79// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
82 80
83 scene.EventManager.OnNewClient += OnNewClient; 81 scene.EventManager.OnNewClient += OnNewClient;
84// scene.EventManager.OnClientClosed += ClientLoggedOut;
85 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; 82 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
86// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
87 } 83 }
88 84
89 public void RegionLoaded(Scene scene) 85 public void RegionLoaded(Scene scene)
@@ -96,11 +92,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
96 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only"); 92 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
97 m_Enabled = false; 93 m_Enabled = false;
98 94
99 m_Scenelist.Clear(); 95// m_Scenelist.Clear();
100 scene.EventManager.OnNewClient -= OnNewClient; 96// scene.EventManager.OnNewClient -= OnNewClient;
101// scene.EventManager.OnClientClosed -= ClientLoggedOut;
102 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 97 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
103// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
104 } 98 }
105 } 99 }
106 } 100 }
@@ -108,9 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
108 public void RemoveRegion(Scene scene) 102 public void RemoveRegion(Scene scene)
109 { 103 {
110 scene.EventManager.OnNewClient -= OnNewClient; 104 scene.EventManager.OnNewClient -= OnNewClient;
111// scene.EventManager.OnClientClosed -= ClientLoggedOut;
112 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 105 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
113// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
114 m_Scenelist.Remove(scene); 106 m_Scenelist.Remove(scene);
115 } 107 }
116 108
@@ -139,11 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
139 // Inventory giving is conducted via instant message 131 // Inventory giving is conducted via instant message
140 client.OnInstantMessage += OnInstantMessage; 132 client.OnInstantMessage += OnInstantMessage;
141 } 133 }
142
143// protected void OnSetRootAgentScene(UUID id, Scene scene)
144// {
145// m_AgentRegions[id] = scene;
146// }
147 134
148 private Scene FindClientScene(UUID agentId) 135 private Scene FindClientScene(UUID agentId)
149 { 136 {
@@ -188,9 +175,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
188 { 175 {
189 UUID folderID = new UUID(im.binaryBucket, 1); 176 UUID folderID = new UUID(im.binaryBucket, 1);
190 177
191 m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+ 178 m_log.DebugFormat(
192 "into agent {1}'s inventory", 179 "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory",
193 folderID, new UUID(im.toAgentID)); 180 folderID, new UUID(im.toAgentID));
194 181
195 InventoryFolderBase folderCopy 182 InventoryFolderBase folderCopy
196 = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero); 183 = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero);
@@ -213,7 +200,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
213 user.ControllingClient.SendBulkUpdateInventory(folderCopy); 200 user.ControllingClient.SendBulkUpdateInventory(folderCopy);
214 201
215 // HACK!! 202 // HACK!!
216 im.imSessionID = folderID.Guid; 203 // Insert the ID of the copied folder into the IM so that we know which item to move to trash if it
204 // is rejected.
205 // XXX: This is probably a misuse of the session ID slot.
206 im.imSessionID = copyID.Guid;
217 } 207 }
218 else 208 else
219 { 209 {
@@ -243,7 +233,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
243 user.ControllingClient.SendBulkUpdateInventory(itemCopy); 233 user.ControllingClient.SendBulkUpdateInventory(itemCopy);
244 234
245 // HACK!! 235 // HACK!!
246 im.imSessionID = itemID.Guid; 236 // Insert the ID of the copied item into the IM so that we know which item to move to trash if it
237 // is rejected.
238 // XXX: This is probably a misuse of the session ID slot.
239 im.imSessionID = copyID.Guid;
247 } 240 }
248 241
249 // Send the IM to the recipient. The item is already 242 // Send the IM to the recipient. The item is already
@@ -403,7 +396,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
403 { 396 {
404 folder = new InventoryFolderBase(inventoryID, client.AgentId); 397 folder = new InventoryFolderBase(inventoryID, client.AgentId);
405 folder = invService.GetFolder(folder); 398 folder = invService.GetFolder(folder);
406 399
407 if (folder != null & trashFolder != null) 400 if (folder != null & trashFolder != null)
408 { 401 {
409 previousParentFolderID = folder.ParentID; 402 previousParentFolderID = folder.ParentID;
@@ -454,70 +447,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
454 } 447 }
455 } 448 }
456 449
457// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
458// {
459// if (!m_AgentRegions.ContainsKey(agentID))
460// {
461// // Since we can get here two ways, we need to scan
462// // the scenes here. This is somewhat more expensive
463// // but helps avoid a nasty bug
464// //
465//
466// foreach (Scene s in m_Scenelist)
467// {
468// ScenePresence presence;
469//
470// if (s.TryGetScenePresence(agentID, out presence))
471// {
472// // If the agent is in this scene, then we
473// // are being called twice in a single
474// // teleport. This is wasteful of cycles
475// // but harmless due to this 2nd level check
476// //
477// // If the agent is found in another scene
478// // then the list wasn't current
479// //
480// // If the agent is totally unknown, then what
481// // are we even doing here??
482// //
483// if (s == scene)
484// {
485// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
486// return true;
487// }
488// else
489// {
490// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
491// return false;
492// }
493// }
494// }
495// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
496// return true;
497// }
498//
499// // The agent is left in current Scene, so we must be
500// // going to another instance
501// //
502// if (m_AgentRegions[agentID] == scene)
503// {
504// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
505// m_AgentRegions.Remove(agentID);
506// return true;
507// }
508//
509// // Another region has claimed the agent
510// //
511// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
512// return false;
513// }
514//
515// public void ClientLoggedOut(UUID agentID, Scene scene)
516// {
517// if (m_AgentRegions.ContainsKey(agentID))
518// m_AgentRegions.Remove(agentID);
519// }
520
521 /// <summary> 450 /// <summary>
522 /// 451 ///
523 /// </summary> 452 /// </summary>
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
new file mode 100644
index 0000000..162a0c3
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
@@ -0,0 +1,449 @@
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 System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net.Config;
32using Nini.Config;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenMetaverse.Assets;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43
44namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests
45{
46 [TestFixture]
47 public class InventoryTransferModuleTests : OpenSimTestCase
48 {
49 protected TestScene m_scene;
50
51 [SetUp]
52 public override void SetUp()
53 {
54 base.SetUp();
55
56 IConfigSource config = new IniConfigSource();
57 config.AddConfig("Messaging");
58 config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule");
59
60 m_scene = new SceneHelpers().SetupScene();
61 SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule());
62 }
63
64 [Test]
65 public void TestAcceptGivenItem()
66 {
67// TestHelpers.EnableLogging();
68
69 UUID initialSessionId = TestHelpers.ParseTail(0x10);
70 UUID itemId = TestHelpers.ParseTail(0x100);
71 UUID assetId = TestHelpers.ParseTail(0x200);
72
73 UserAccount ua1
74 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
75 UserAccount ua2
76 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
77
78 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
79 TestClient giverClient = (TestClient)giverSp.ControllingClient;
80
81 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
82 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
83
84 // Create the object to test give
85 InventoryItemBase originalItem
86 = UserInventoryHelpers.CreateInventoryItem(
87 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
88
89 byte[] giveImBinaryBucket = new byte[17];
90 byte[] itemIdBytes = itemId.GetBytes();
91 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
92
93 GridInstantMessage giveIm
94 = new GridInstantMessage(
95 m_scene,
96 giverSp.UUID,
97 giverSp.Name,
98 receiverSp.UUID,
99 (byte)InstantMessageDialog.InventoryOffered,
100 false,
101 "inventory offered msg",
102 initialSessionId,
103 false,
104 Vector3.Zero,
105 giveImBinaryBucket,
106 true);
107
108 giverClient.HandleImprovedInstantMessage(giveIm);
109
110 // These details might not all be correct.
111 GridInstantMessage acceptIm
112 = new GridInstantMessage(
113 m_scene,
114 receiverSp.UUID,
115 receiverSp.Name,
116 giverSp.UUID,
117 (byte)InstantMessageDialog.InventoryAccepted,
118 false,
119 "inventory accepted msg",
120 initialSessionId,
121 false,
122 Vector3.Zero,
123 null,
124 true);
125
126 receiverClient.HandleImprovedInstantMessage(acceptIm);
127
128 // Test for item remaining in the giver's inventory (here we assume a copy item)
129 // TODO: Test no-copy items.
130 InventoryItemBase originalItemAfterGive
131 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
132
133 Assert.That(originalItemAfterGive, Is.Not.Null);
134 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
135
136 // Test for item successfully making it into the receiver's inventory
137 InventoryItemBase receivedItem
138 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj");
139
140 Assert.That(receivedItem, Is.Not.Null);
141 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
142
143 // Test that on a delete, item still exists and is accessible for the giver.
144 m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List<UUID>() { receivedItem.ID });
145
146 InventoryItemBase originalItemAfterDelete
147 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
148
149 Assert.That(originalItemAfterDelete, Is.Not.Null);
150
151 // TODO: Test scenario where giver deletes their item first.
152 }
153
154 /// <summary>
155 /// Test user rejection of a given item.
156 /// </summary>
157 /// <remarks>
158 /// A rejected item still ends up in the user's trash folder.
159 /// </remarks>
160 [Test]
161 public void TestRejectGivenItem()
162 {
163// TestHelpers.EnableLogging();
164
165 UUID initialSessionId = TestHelpers.ParseTail(0x10);
166 UUID itemId = TestHelpers.ParseTail(0x100);
167 UUID assetId = TestHelpers.ParseTail(0x200);
168
169 UserAccount ua1
170 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
171 UserAccount ua2
172 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
173
174 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
175 TestClient giverClient = (TestClient)giverSp.ControllingClient;
176
177 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
178 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
179
180 // Create the object to test give
181 InventoryItemBase originalItem
182 = UserInventoryHelpers.CreateInventoryItem(
183 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
184
185 GridInstantMessage receivedIm = null;
186 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
187
188 byte[] giveImBinaryBucket = new byte[17];
189 byte[] itemIdBytes = itemId.GetBytes();
190 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
191
192 GridInstantMessage giveIm
193 = new GridInstantMessage(
194 m_scene,
195 giverSp.UUID,
196 giverSp.Name,
197 receiverSp.UUID,
198 (byte)InstantMessageDialog.InventoryOffered,
199 false,
200 "inventory offered msg",
201 initialSessionId,
202 false,
203 Vector3.Zero,
204 giveImBinaryBucket,
205 true);
206
207 giverClient.HandleImprovedInstantMessage(giveIm);
208
209 // These details might not all be correct.
210 // Session ID is now the created item ID (!)
211 GridInstantMessage rejectIm
212 = new GridInstantMessage(
213 m_scene,
214 receiverSp.UUID,
215 receiverSp.Name,
216 giverSp.UUID,
217 (byte)InstantMessageDialog.InventoryDeclined,
218 false,
219 "inventory declined msg",
220 new UUID(receivedIm.imSessionID),
221 false,
222 Vector3.Zero,
223 null,
224 true);
225
226 receiverClient.HandleImprovedInstantMessage(rejectIm);
227
228 // Test for item remaining in the giver's inventory (here we assume a copy item)
229 // TODO: Test no-copy items.
230 InventoryItemBase originalItemAfterGive
231 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
232
233 Assert.That(originalItemAfterGive, Is.Not.Null);
234 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
235
236 // Test for item successfully making it into the receiver's inventory
237 InventoryItemBase receivedItem
238 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj");
239
240 InventoryFolderBase trashFolder
241 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder);
242
243 Assert.That(receivedItem, Is.Not.Null);
244 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
245 Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID));
246
247 // Test that on a delete, item still exists and is accessible for the giver.
248 m_scene.InventoryService.PurgeFolder(trashFolder);
249
250 InventoryItemBase originalItemAfterDelete
251 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
252
253 Assert.That(originalItemAfterDelete, Is.Not.Null);
254 }
255
256 [Test]
257 public void TestAcceptGivenFolder()
258 {
259 TestHelpers.InMethod();
260// TestHelpers.EnableLogging();
261
262 UUID initialSessionId = TestHelpers.ParseTail(0x10);
263 UUID folderId = TestHelpers.ParseTail(0x100);
264
265 UserAccount ua1
266 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
267 UserAccount ua2
268 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
269
270 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
271 TestClient giverClient = (TestClient)giverSp.ControllingClient;
272
273 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
274 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
275
276 InventoryFolderBase originalFolder
277 = UserInventoryHelpers.CreateInventoryFolder(
278 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
279
280 byte[] giveImBinaryBucket = new byte[17];
281 giveImBinaryBucket[0] = (byte)AssetType.Folder;
282 byte[] itemIdBytes = folderId.GetBytes();
283 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
284
285 GridInstantMessage giveIm
286 = new GridInstantMessage(
287 m_scene,
288 giverSp.UUID,
289 giverSp.Name,
290 receiverSp.UUID,
291 (byte)InstantMessageDialog.InventoryOffered,
292 false,
293 "inventory offered msg",
294 initialSessionId,
295 false,
296 Vector3.Zero,
297 giveImBinaryBucket,
298 true);
299
300 giverClient.HandleImprovedInstantMessage(giveIm);
301
302 // These details might not all be correct.
303 GridInstantMessage acceptIm
304 = new GridInstantMessage(
305 m_scene,
306 receiverSp.UUID,
307 receiverSp.Name,
308 giverSp.UUID,
309 (byte)InstantMessageDialog.InventoryAccepted,
310 false,
311 "inventory accepted msg",
312 initialSessionId,
313 false,
314 Vector3.Zero,
315 null,
316 true);
317
318 receiverClient.HandleImprovedInstantMessage(acceptIm);
319
320 // Test for item remaining in the giver's inventory (here we assume a copy item)
321 // TODO: Test no-copy items.
322 InventoryFolderBase originalFolderAfterGive
323 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
324
325 Assert.That(originalFolderAfterGive, Is.Not.Null);
326 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
327
328 // Test for item successfully making it into the receiver's inventory
329 InventoryFolderBase receivedFolder
330 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1");
331
332 Assert.That(receivedFolder, Is.Not.Null);
333 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
334
335 // Test that on a delete, item still exists and is accessible for the giver.
336 m_scene.InventoryService.DeleteFolders(receiverSp.UUID, new List<UUID>() { receivedFolder.ID });
337
338 InventoryFolderBase originalFolderAfterDelete
339 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
340
341 Assert.That(originalFolderAfterDelete, Is.Not.Null);
342
343 // TODO: Test scenario where giver deletes their item first.
344 }
345
346 /// <summary>
347 /// Test user rejection of a given item.
348 /// </summary>
349 /// <remarks>
350 /// A rejected item still ends up in the user's trash folder.
351 /// </remarks>
352 [Test]
353 public void TestRejectGivenFolder()
354 {
355 TestHelpers.InMethod();
356// TestHelpers.EnableLogging();
357
358 UUID initialSessionId = TestHelpers.ParseTail(0x10);
359 UUID folderId = TestHelpers.ParseTail(0x100);
360
361 UserAccount ua1
362 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
363 UserAccount ua2
364 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
365
366 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
367 TestClient giverClient = (TestClient)giverSp.ControllingClient;
368
369 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
370 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
371
372 // Create the folder to test give
373 InventoryFolderBase originalFolder
374 = UserInventoryHelpers.CreateInventoryFolder(
375 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
376
377 GridInstantMessage receivedIm = null;
378 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
379
380 byte[] giveImBinaryBucket = new byte[17];
381 giveImBinaryBucket[0] = (byte)AssetType.Folder;
382 byte[] itemIdBytes = folderId.GetBytes();
383 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
384
385 GridInstantMessage giveIm
386 = new GridInstantMessage(
387 m_scene,
388 giverSp.UUID,
389 giverSp.Name,
390 receiverSp.UUID,
391 (byte)InstantMessageDialog.InventoryOffered,
392 false,
393 "inventory offered msg",
394 initialSessionId,
395 false,
396 Vector3.Zero,
397 giveImBinaryBucket,
398 true);
399
400 giverClient.HandleImprovedInstantMessage(giveIm);
401
402 // These details might not all be correct.
403 // Session ID is now the created item ID (!)
404 GridInstantMessage rejectIm
405 = new GridInstantMessage(
406 m_scene,
407 receiverSp.UUID,
408 receiverSp.Name,
409 giverSp.UUID,
410 (byte)InstantMessageDialog.InventoryDeclined,
411 false,
412 "inventory declined msg",
413 new UUID(receivedIm.imSessionID),
414 false,
415 Vector3.Zero,
416 null,
417 true);
418
419 receiverClient.HandleImprovedInstantMessage(rejectIm);
420
421 // Test for item remaining in the giver's inventory (here we assume a copy item)
422 // TODO: Test no-copy items.
423 InventoryFolderBase originalFolderAfterGive
424 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
425
426 Assert.That(originalFolderAfterGive, Is.Not.Null);
427 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
428
429 // Test for folder successfully making it into the receiver's inventory
430 InventoryFolderBase receivedFolder
431 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1");
432
433 InventoryFolderBase trashFolder
434 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder);
435
436 Assert.That(receivedFolder, Is.Not.Null);
437 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
438 Assert.That(receivedFolder.ParentID, Is.EqualTo(trashFolder.ID));
439
440 // Test that on a delete, item still exists and is accessible for the giver.
441 m_scene.InventoryService.PurgeFolder(trashFolder);
442
443 InventoryFolderBase originalFolderAfterDelete
444 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
445
446 Assert.That(originalFolderAfterDelete, Is.Not.Null);
447 }
448 }
449} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 8329af0..6ae9448 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -240,7 +240,7 @@ namespace OpenSim.Region.CoreModules.Framework
240 { 240 {
241 caps.AppendFormat("** User {0}:\n", kvp.Key); 241 caps.AppendFormat("** User {0}:\n", kvp.Key);
242 242
243 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) 243 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); )
244 { 244 {
245 Uri uri = new Uri(kvp2.Value.ToString()); 245 Uri uri = new Uri(kvp2.Value.ToString());
246 caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); 246 caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index e0009bb..e6d6cbf 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -646,11 +646,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
646 } 646 }
647 else 647 else
648 { 648 {
649 if (remoteClient == null || so.OwnerID != remoteClient.AgentId) 649 if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
650 { 650 {
651 // Taking copy of another person's item. Take to 651 // Taking copy of another person's item. Take to
652 // Objects folder. 652 // Objects folder.
653 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); 653 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
654 so.FromFolderID = UUID.Zero;
654 } 655 }
655 else 656 else
656 { 657 {
@@ -666,10 +667,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
666 // 667 //
667 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) 668 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
668 { 669 {
669 if (so.FromFolderID != UUID.Zero && userID == remoteClient.AgentId) 670 if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
670 { 671 {
671 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); 672 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
672 folder = m_Scene.InventoryService.GetFolder(f); 673 folder = m_Scene.InventoryService.GetFolder(f);
674
675 if(folder.Type == 14 || folder.Type == 16)
676 {
677 // folder.Type = 6;
678 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
679 }
673 } 680 }
674 } 681 }
675 682
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
index c0c2ca7..c32820e 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
@@ -142,10 +142,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
142 142
143 scene.RegisterModuleInterface<IGridService>(this); 143 scene.RegisterModuleInterface<IGridService>(this);
144 144
145 if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) 145 lock (m_LocalCache)
146 m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); 146 {
147 else 147 if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID))
148 m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); 148 m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!");
149 else
150 m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene));
151 }
149 } 152 }
150 153
151 public void RemoveRegion(Scene scene) 154 public void RemoveRegion(Scene scene)
@@ -153,8 +156,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
153 if (!m_Enabled) 156 if (!m_Enabled)
154 return; 157 return;
155 158
156 m_LocalCache[scene.RegionInfo.RegionID].Clear(); 159 lock (m_LocalCache)
157 m_LocalCache.Remove(scene.RegionInfo.RegionID); 160 {
161 m_LocalCache[scene.RegionInfo.RegionID].Clear();
162 m_LocalCache.Remove(scene.RegionInfo.RegionID);
163 }
158 } 164 }
159 165
160 public void RegionLoaded(Scene scene) 166 public void RegionLoaded(Scene scene)
@@ -191,12 +197,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
191 197
192 // First see if it's a neighbour, even if it isn't on this sim. 198 // First see if it's a neighbour, even if it isn't on this sim.
193 // Neighbour data is cached in memory, so this is fast 199 // Neighbour data is cached in memory, so this is fast
194 foreach (RegionCache rcache in m_LocalCache.Values) 200
201 lock (m_LocalCache)
195 { 202 {
196 region = rcache.GetRegionByPosition(x, y); 203 foreach (RegionCache rcache in m_LocalCache.Values)
197 if (region != null)
198 { 204 {
199 return region; 205 region = rcache.GetRegionByPosition(x, y);
206 if (region != null)
207 {
208 return region;
209 }
200 } 210 }
201 } 211 }
202 212
@@ -245,12 +255,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
245 { 255 {
246 System.Text.StringBuilder caps = new System.Text.StringBuilder(); 256 System.Text.StringBuilder caps = new System.Text.StringBuilder();
247 257
248 foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache) 258 lock (m_LocalCache)
249 { 259 {
250 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); 260 foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache)
251 List<GridRegion> regions = kvp.Value.GetNeighbours(); 261 {
252 foreach (GridRegion r in regions) 262 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key);
253 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); 263 List<GridRegion> regions = kvp.Value.GetNeighbours();
264 foreach (GridRegion r in regions)
265 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize);
266 }
254 } 267 }
255 268
256 MainConsole.Instance.Output(caps.ToString()); 269 MainConsole.Instance.Output(caps.ToString());
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index ff7e5ed..8fe2d72 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -389,10 +389,12 @@ namespace OpenSim.Region.Framework.Scenes
389 if (value) 389 if (value)
390 { 390 {
391 if (!m_active) 391 if (!m_active)
392 Start(); 392 Start(false);
393 } 393 }
394 else 394 else
395 { 395 {
396 // This appears assymetric with Start() above but is not - setting m_active = false stops the loops
397 // XXX: Possibly this should be in an explicit Stop() method for symmetry.
396 m_active = false; 398 m_active = false;
397 } 399 }
398 } 400 }
@@ -1331,10 +1333,18 @@ namespace OpenSim.Region.Framework.Scenes
1331 } 1333 }
1332 } 1334 }
1333 1335
1336 public override void Start()
1337 {
1338 Start(true);
1339 }
1340
1334 /// <summary> 1341 /// <summary>
1335 /// Start the scene 1342 /// Start the scene
1336 /// </summary> 1343 /// </summary>
1337 public void Start() 1344 /// <param name='startScripts'>
1345 /// Start the scripts within the scene.
1346 /// </param>
1347 public void Start(bool startScripts)
1338 { 1348 {
1339 m_active = true; 1349 m_active = true;
1340 1350
@@ -1353,6 +1363,8 @@ namespace OpenSim.Region.Framework.Scenes
1353 m_heartbeatThread 1363 m_heartbeatThread
1354 = Watchdog.StartThread( 1364 = Watchdog.StartThread(
1355 Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false); 1365 Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false);
1366
1367 StartScripts();
1356 } 1368 }
1357 1369
1358 /// <summary> 1370 /// <summary>
@@ -3699,7 +3711,7 @@ namespace OpenSim.Region.Framework.Scenes
3699 // On login test land permisions 3711 // On login test land permisions
3700 if (vialogin) 3712 if (vialogin)
3701 { 3713 {
3702 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3714 if (land != null && !TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3703 { 3715 {
3704 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3716 m_authenticateHandler.RemoveCircuit(agent.circuitcode);
3705 return false; 3717 return false;
@@ -3880,20 +3892,37 @@ namespace OpenSim.Region.Framework.Scenes
3880 return true; 3892 return true;
3881 } 3893 }
3882 3894
3883 private bool TestLandRestrictions(AgentCircuitData agent, ILandObject land, out string reason) 3895 public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
3884 { 3896 {
3885 bool banned = land.IsBannedFromLand(agent.AgentID); 3897 if (posX < 0)
3886 bool restricted = land.IsRestrictedFromLand(agent.AgentID); 3898 posX = 0;
3899 else if (posX >= 256)
3900 posX = 255.999f;
3901 if (posY < 0)
3902 posY = 0;
3903 else if (posY >= 256)
3904 posY = 255.999f;
3905
3906 reason = String.Empty;
3907 if (Permissions.IsGod(agentID))
3908 return true;
3909
3910 ILandObject land = LandChannel.GetLandObject(posX, posY);
3911 if (land == null)
3912 return false;
3913
3914 bool banned = land.IsBannedFromLand(agentID);
3915 bool restricted = land.IsRestrictedFromLand(agentID);
3887 3916
3888 if (banned || restricted) 3917 if (banned || restricted)
3889 { 3918 {
3890 ILandObject nearestParcel = GetNearestAllowedParcel(agent.AgentID, agent.startpos.X, agent.startpos.Y); 3919 ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY);
3891 if (nearestParcel != null) 3920 if (nearestParcel != null)
3892 { 3921 {
3893 //Move agent to nearest allowed 3922 //Move agent to nearest allowed
3894 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel); 3923 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
3895 agent.startpos.X = newPosition.X; 3924 posX = newPosition.X;
3896 agent.startpos.Y = newPosition.Y; 3925 posY = newPosition.Y;
3897 } 3926 }
3898 else 3927 else
3899 { 3928 {
@@ -5478,6 +5507,8 @@ namespace OpenSim.Region.Framework.Scenes
5478 /// <returns></returns> 5507 /// <returns></returns>
5479 public bool QueryAccess(UUID agentID, Vector3 position, out string reason) 5508 public bool QueryAccess(UUID agentID, Vector3 position, out string reason)
5480 { 5509 {
5510 reason = "You are banned from the region";
5511
5481 if (EntityTransferModule.IsInTransit(agentID)) 5512 if (EntityTransferModule.IsInTransit(agentID))
5482 { 5513 {
5483 reason = "Agent is still in transit from this region"; 5514 reason = "Agent is still in transit from this region";
@@ -5489,6 +5520,12 @@ namespace OpenSim.Region.Framework.Scenes
5489 return false; 5520 return false;
5490 } 5521 }
5491 5522
5523 if (Permissions.IsGod(agentID))
5524 {
5525 reason = String.Empty;
5526 return true;
5527 }
5528
5492 // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check. 5529 // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check.
5493 // However, the long term fix is to make sure root agent count is always accurate. 5530 // However, the long term fix is to make sure root agent count is always accurate.
5494 m_sceneGraph.RecalculateStats(); 5531 m_sceneGraph.RecalculateStats();
@@ -5509,6 +5546,41 @@ namespace OpenSim.Region.Framework.Scenes
5509 } 5546 }
5510 } 5547 }
5511 5548
5549 ScenePresence presence = GetScenePresence(agentID);
5550 IClientAPI client = null;
5551 AgentCircuitData aCircuit = null;
5552
5553 if (presence != null)
5554 {
5555 client = presence.ControllingClient;
5556 if (client != null)
5557 aCircuit = client.RequestClientInfo();
5558 }
5559
5560 // We may be called before there is a presence or a client.
5561 // Fake AgentCircuitData to keep IAuthorizationModule smiling
5562 if (client == null)
5563 {
5564 aCircuit = new AgentCircuitData();
5565 aCircuit.AgentID = agentID;
5566 aCircuit.firstname = String.Empty;
5567 aCircuit.lastname = String.Empty;
5568 }
5569
5570 try
5571 {
5572 if (!AuthorizeUser(aCircuit, out reason))
5573 {
5574 // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
5575 return false;
5576 }
5577 }
5578 catch (Exception e)
5579 {
5580 m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} "+ e.StackTrace, e.Message);
5581 return false;
5582 }
5583
5512 if (position == Vector3.Zero) // Teleport 5584 if (position == Vector3.Zero) // Teleport
5513 { 5585 {
5514 if (!RegionInfo.EstateSettings.AllowDirectTeleport) 5586 if (!RegionInfo.EstateSettings.AllowDirectTeleport)
@@ -5542,6 +5614,27 @@ namespace OpenSim.Region.Framework.Scenes
5542 } 5614 }
5543 } 5615 }
5544 } 5616 }
5617
5618 float posX = 128.0f;
5619 float posY = 128.0f;
5620
5621 if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
5622 {
5623 // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
5624 return false;
5625 }
5626 }
5627 else // Walking
5628 {
5629 ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
5630 if (land == null)
5631 return false;
5632
5633 bool banned = land.IsBannedFromLand(agentID);
5634 bool restricted = land.IsRestrictedFromLand(agentID);
5635
5636 if (banned || restricted)
5637 return false;
5545 } 5638 }
5546 5639
5547 reason = String.Empty; 5640 reason = String.Empty;
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index d3e968e..d2097ea 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -561,6 +561,10 @@ namespace OpenSim.Region.Framework.Scenes
561 get { return false; } 561 get { return false; }
562 } 562 }
563 563
564 public virtual void Start()
565 {
566 }
567
564 public void Restart() 568 public void Restart()
565 { 569 {
566 // This has to be here to fire the event 570 // This has to be here to fire the event
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
index fdf2cb9..231f0f8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -75,11 +75,11 @@ private sealed class BulletBodyUnman : BulletBody
75private sealed class BulletShapeUnman : BulletShape 75private sealed class BulletShapeUnman : BulletShape
76{ 76{
77 public IntPtr ptr; 77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) 78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base() 79 : base()
80 { 80 {
81 ptr = xx; 81 ptr = xx;
82 type = typ; 82 shapeType = typ;
83 } 83 }
84 public override bool HasPhysicalShape 84 public override bool HasPhysicalShape
85 { 85 {
@@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape
91 } 91 }
92 public override BulletShape Clone() 92 public override BulletShape Clone()
93 { 93 {
94 return new BulletShapeUnman(ptr, type); 94 return new BulletShapeUnman(ptr, shapeType);
95 } 95 }
96 public override bool ReferenceSame(BulletShape other) 96 public override bool ReferenceSame(BulletShape other)
97 { 97 {
@@ -255,7 +255,7 @@ public override BulletShape CreateHullShape(BulletWorld world, int hullCount, fl
255{ 255{
256 BulletWorldUnman worldu = world as BulletWorldUnman; 256 BulletWorldUnman worldu = world as BulletWorldUnman;
257 return new BulletShapeUnman( 257 return new BulletShapeUnman(
258 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), 258 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
259 BSPhysicsShapeType.SHAPE_HULL); 259 BSPhysicsShapeType.SHAPE_HULL);
260} 260}
261 261
@@ -375,7 +375,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha
375{ 375{
376 BulletWorldUnman worldu = world as BulletWorldUnman; 376 BulletWorldUnman worldu = world as BulletWorldUnman;
377 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; 377 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
378 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); 378 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
379} 379}
380 380
381public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) 381public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
@@ -1503,7 +1503,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1503public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); 1503public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1504 1504
1505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1506public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, 1506public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1507 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, 1507 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1508 float scaleFactor, float collisionMargin); 1508 float scaleFactor, float collisionMargin);
1509 1509
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
index b37265a..59780ae 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -81,11 +81,11 @@ private sealed class BulletBodyXNA : BulletBody
81private sealed class BulletShapeXNA : BulletShape 81private sealed class BulletShapeXNA : BulletShape
82{ 82{
83 public CollisionShape shape; 83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) 84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base() 85 : base()
86 { 86 {
87 shape = xx; 87 shape = xx;
88 type = typ; 88 shapeType = typ;
89 } 89 }
90 public override bool HasPhysicalShape 90 public override bool HasPhysicalShape
91 { 91 {
@@ -97,7 +97,7 @@ private sealed class BulletShapeXNA : BulletShape
97 } 97 }
98 public override BulletShape Clone() 98 public override BulletShape Clone()
99 { 99 {
100 return new BulletShapeXNA(shape, type); 100 return new BulletShapeXNA(shape, shapeType);
101 } 101 }
102 public override bool ReferenceSame(BulletShape other) 102 public override bool ReferenceSame(BulletShape other)
103 { 103 {
@@ -137,8 +137,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
137 internal int LastEntityProperty = 0; 137 internal int LastEntityProperty = 0;
138 138
139 internal EntityProperties[] UpdatedObjects; 139 internal EntityProperties[] UpdatedObjects;
140 internal Dictionary<uint, GhostObject> specialCollisionObjects; 140 internal Dictionary<uint, GhostObject> specialCollisionObjects;
141 141
142 private static int m_collisionsThisFrame; 142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; } 143 private BSScene PhysicsScene { get; set; }
144 144
@@ -151,7 +151,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
151 } 151 }
152 152
153 /// <summary> 153 /// <summary>
154 /// 154 ///
155 /// </summary> 155 /// </summary>
156 /// <param name="p"></param> 156 /// <param name="p"></param>
157 /// <param name="p_2"></param> 157 /// <param name="p_2"></param>
@@ -174,7 +174,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; 175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
176 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); 176 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
177 177
178 return true; 178 return true;
179 179
180 } 180 }
@@ -300,7 +300,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
300 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { 300 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
301 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 301 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
302 return world.GetForceUpdateAllAabbs(); 302 return world.GetForceUpdateAllAabbs();
303 303
304 } 304 }
305 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) 305 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
306 { 306 {
@@ -404,7 +404,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
404 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); 404 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
405 mat._origin = vposition; 405 mat._origin = vposition;
406 collisionObject.SetWorldTransform(mat); 406 collisionObject.SetWorldTransform(mat);
407 407
408 } 408 }
409 409
410 public override Vector3 GetPosition(BulletBody pCollisionObject) 410 public override Vector3 GetPosition(BulletBody pCollisionObject)
@@ -457,7 +457,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
457 { 457 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
459 collisionObject.Activate(pforceactivation); 459 collisionObject.Activate(pforceactivation);
460 460
461 } 461 }
462 462
463 public override Quaternion GetOrientation(BulletBody pCollisionObject) 463 public override Quaternion GetOrientation(BulletBody pCollisionObject)
@@ -486,7 +486,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
486 { 486 {
487 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 487 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
488 return collisionObject.GetCcdSweptSphereRadius(); 488 return collisionObject.GetCcdSweptSphereRadius();
489 489
490 } 490 }
491 491
492 public override IntPtr GetUserPointer(BulletBody pCollisionObject) 492 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
@@ -559,8 +559,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
559 } 559 }
560 560
561 561
562 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, 562 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
563 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, 563 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
564 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 564 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
565 565
566 { 566 {
@@ -604,7 +604,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
604 } 604 }
605 605
606 /// <summary> 606 /// <summary>
607 /// 607 ///
608 /// </summary> 608 /// </summary>
609 /// <param name="pWorld"></param> 609 /// <param name="pWorld"></param>
610 /// <param name="pBody1"></param> 610 /// <param name="pBody1"></param>
@@ -824,7 +824,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
824 { 824 {
825 RigidBody body = (pBody as BulletBodyXNA).rigidBody; 825 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
826 float angularDamping = body.GetAngularDamping(); 826 float angularDamping = body.GetAngularDamping();
827 body.SetDamping(lin_damping, angularDamping); 827 body.SetDamping(lin_damping, angularDamping);
828 } 828 }
829 829
830 public override float GetLinearDamping(BulletBody pBody) 830 public override float GetLinearDamping(BulletBody pBody)
@@ -907,7 +907,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
907 RigidBody bo = co as RigidBody; 907 RigidBody bo = co as RigidBody;
908 if (bo == null) 908 if (bo == null)
909 { 909 {
910 910
911 if (world.IsInWorld(co)) 911 if (world.IsInWorld(co))
912 { 912 {
913 world.RemoveCollisionObject(co); 913 world.RemoveCollisionObject(co);
@@ -915,7 +915,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
915 } 915 }
916 else 916 else
917 { 917 {
918 918
919 if (world.IsInWorld(bo)) 919 if (world.IsInWorld(bo))
920 { 920 {
921 world.RemoveRigidBody(bo); 921 world.RemoveRigidBody(bo);
@@ -947,7 +947,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
947 947
948 // TODO: Turn this from a reference copy to a Value Copy. 948 // TODO: Turn this from a reference copy to a Value Copy.
949 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); 949 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
950 950
951 return shape2; 951 return shape2;
952 } 952 }
953 953
@@ -957,7 +957,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
957 return false; 957 return false;
958 } 958 }
959 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); 959 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
960 960
961 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 961 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
962 { 962 {
963 CollisionWorld world = (pWorld as BulletWorldXNA).world; 963 CollisionWorld world = (pWorld as BulletWorldXNA).world;
@@ -993,11 +993,11 @@ private sealed class BulletConstraintXNA : BulletConstraint
993 m_startWorldTransform = IndexedMatrix.Identity; 993 m_startWorldTransform = IndexedMatrix.Identity;
994 */ 994 */
995 body.SetUserPointer(pLocalID); 995 body.SetUserPointer(pLocalID);
996 996
997 return new BulletBodyXNA(pLocalID, body); 997 return new BulletBodyXNA(pLocalID, body);
998 } 998 }
999 999
1000 1000
1001 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 1001 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1002 { 1002 {
1003 1003
@@ -1025,7 +1025,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1025 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) 1025 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1026 { 1026 {
1027 1027
1028 /* TODO */ 1028 /* TODO */
1029 return Vector3.Zero; 1029 return Vector3.Zero;
1030 } 1030 }
1031 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } 1031 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
@@ -1035,7 +1035,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1035 { 1035 {
1036 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 1036 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1037 return collisionObject.IsStaticObject(); 1037 return collisionObject.IsStaticObject();
1038 1038
1039 } 1039 }
1040 public override bool IsKinematicObject(BulletBody pCollisionObject) 1040 public override bool IsKinematicObject(BulletBody pCollisionObject)
1041 { 1041 {
@@ -1098,10 +1098,10 @@ private sealed class BulletConstraintXNA : BulletConstraint
1098 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); 1098 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1099 } 1099 }
1100 1100
1101 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, 1101 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1102 ConfigurationParameters[] o, 1102 ConfigurationParameters[] o,
1103 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, 1103 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1104 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, 1104 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1105 object mDebugLogCallbackHandle) 1105 object mDebugLogCallbackHandle)
1106 { 1106 {
1107 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); 1107 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
@@ -1138,9 +1138,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
1138 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; 1138 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1139 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; 1139 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1140 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; 1140 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1141 1141
1142 p.vehicleAngularDamping = BSParam.VehicleAngularDamping; 1142 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1143 1143
1144 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; 1144 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1145 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; 1145 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1146 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; 1146 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
@@ -1160,7 +1160,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1160 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; 1160 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1161 p.physicsLoggingFrames = o[0].physicsLoggingFrames; 1161 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1162 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); 1162 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1163 1163
1164 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); 1164 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1165 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); 1165 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1166 1166
@@ -1263,7 +1263,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1263 } 1263 }
1264 } 1264 }
1265 return ret; 1265 return ret;
1266 1266
1267 } 1267 }
1268 1268
1269 public override float GetAngularMotionDisc(BulletShape pShape) 1269 public override float GetAngularMotionDisc(BulletShape pShape)
@@ -1353,10 +1353,10 @@ private sealed class BulletConstraintXNA : BulletConstraint
1353 CollisionShape shape = (pShape as BulletShapeXNA).shape; 1353 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1354 gObj.SetCollisionShape(shape); 1354 gObj.SetCollisionShape(shape);
1355 gObj.SetUserPointer(pLocalID); 1355 gObj.SetUserPointer(pLocalID);
1356 1356
1357 if (specialCollisionObjects.ContainsKey(pLocalID)) 1357 if (specialCollisionObjects.ContainsKey(pLocalID))
1358 specialCollisionObjects[pLocalID] = gObj; 1358 specialCollisionObjects[pLocalID] = gObj;
1359 else 1359 else
1360 specialCollisionObjects.Add(pLocalID, gObj); 1360 specialCollisionObjects.Add(pLocalID, gObj);
1361 1361
1362 // TODO: Add to Special CollisionObjects! 1362 // TODO: Add to Special CollisionObjects!
@@ -1447,8 +1447,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
1447 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); 1447 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1448 } 1448 }
1449 1449
1450 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { 1450 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1451 1451
1452 if (cShape == null) 1452 if (cShape == null)
1453 return null; 1453 return null;
1454 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; 1454 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
@@ -1456,7 +1456,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1456 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); 1456 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1457 1457
1458 1458
1459 return retShape; 1459 return retShape;
1460 } 1460 }
1461 1461
1462 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) 1462 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
@@ -1598,8 +1598,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
1598 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); 1598 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1599 } 1599 }
1600 1600
1601 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, 1601 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1602 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, 1602 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1603 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 1603 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1604 1604
1605 { 1605 {
@@ -1745,7 +1745,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1745 { 1745 {
1746 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 1746 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1747 CompoundShape compoundshape = new CompoundShape(false); 1747 CompoundShape compoundshape = new CompoundShape(false);
1748 1748
1749 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); 1749 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1750 int ii = 1; 1750 int ii = 1;
1751 1751
@@ -1761,7 +1761,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1761 int ender = ((ii + 4) + (vertexCount*3)); 1761 int ender = ((ii + 4) + (vertexCount*3));
1762 for (int iii = ii + 4; iii < ender; iii+=3) 1762 for (int iii = ii + 4; iii < ender; iii+=3)
1763 { 1763 {
1764 1764
1765 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); 1765 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1766 } 1766 }
1767 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); 1767 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
@@ -1769,7 +1769,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1769 compoundshape.AddChildShape(ref childTrans, convexShape); 1769 compoundshape.AddChildShape(ref childTrans, convexShape);
1770 ii += (vertexCount*3 + 4); 1770 ii += (vertexCount*3 + 4);
1771 } 1771 }
1772 1772
1773 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); 1773 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1774 } 1774 }
1775 1775
@@ -1791,13 +1791,13 @@ private sealed class BulletConstraintXNA : BulletConstraint
1791 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) 1791 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1792 { 1792 {
1793 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); 1793 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1794 1794
1795 for (int iter = 0; iter < pVerticesCount; iter++) 1795 for (int iter = 0; iter < pVerticesCount; iter++)
1796 { 1796 {
1797 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; 1797 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1798 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; 1798 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1799 } 1799 }
1800 1800
1801 ObjectArray<int> indicesarr = new ObjectArray<int>(indices); 1801 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1802 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); 1802 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1803 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); 1803 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
@@ -1811,7 +1811,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1811 mesh.m_vertexStride = 3; 1811 mesh.m_vertexStride = 3;
1812 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; 1812 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1813 mesh.m_triangleIndexStride = 3; 1813 mesh.m_triangleIndexStride = 3;
1814 1814
1815 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); 1815 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1816 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); 1816 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1817 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); 1817 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
@@ -1822,7 +1822,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1822 } 1822 }
1823 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) 1823 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1824 { 1824 {
1825 1825
1826 String fileName = "objTest3.raw"; 1826 String fileName = "objTest3.raw";
1827 String completePath = System.IO.Path.Combine(Util.configDir(), fileName); 1827 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1828 StreamWriter sw = new StreamWriter(completePath); 1828 StreamWriter sw = new StreamWriter(completePath);
@@ -1848,7 +1848,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1848 string s = vertices[indices[i * 3]].ToString("0.0000"); 1848 string s = vertices[indices[i * 3]].ToString("0.0000");
1849 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); 1849 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1850 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); 1850 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1851 1851
1852 sw.Write(s + "\n"); 1852 sw.Write(s + "\n");
1853 } 1853 }
1854 1854
@@ -1870,7 +1870,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1870 mesh.m_vertexStride = 3; 1870 mesh.m_vertexStride = 3;
1871 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; 1871 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1872 mesh.m_triangleIndexStride = 3; 1872 mesh.m_triangleIndexStride = 3;
1873 1873
1874 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); 1874 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1875 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); 1875 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1876 1876
@@ -1901,7 +1901,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1901 sw.Close(); 1901 sw.Close();
1902 } 1902 }
1903 1903
1904 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 1904 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1905 float scaleFactor, float collisionMargin) 1905 float scaleFactor, float collisionMargin)
1906 { 1906 {
1907 const int upAxis = 2; 1907 const int upAxis = 2;
@@ -1943,14 +1943,14 @@ private sealed class BulletConstraintXNA : BulletConstraint
1943 /* TODO */ 1943 /* TODO */
1944 updatedEntityCount = 0; 1944 updatedEntityCount = 0;
1945 collidersCount = 0; 1945 collidersCount = 0;
1946 1946
1947 1947
1948 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); 1948 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
1949 1949
1950 return ret; 1950 return ret;
1951 } 1951 }
1952 1952
1953 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, 1953 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1954 out int updatedEntityCount, out EntityProperties[] updatedEntities, 1954 out int updatedEntityCount, out EntityProperties[] updatedEntities,
1955 out int collidersCount, out CollisionDesc[] colliders) 1955 out int collidersCount, out CollisionDesc[] colliders)
1956 { 1956 {
@@ -1959,24 +1959,24 @@ private sealed class BulletConstraintXNA : BulletConstraint
1959 return epic; 1959 return epic;
1960 } 1960 }
1961 1961
1962 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, 1962 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
1963 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) 1963 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
1964 { 1964 {
1965 int numSimSteps = 0; 1965 int numSimSteps = 0;
1966 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); 1966 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
1967 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); 1967 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
1968 LastEntityProperty=0; 1968 LastEntityProperty=0;
1969 1969
1970 1970
1971 1971
1972 1972
1973 1973
1974 1974
1975 LastCollisionDesc=0; 1975 LastCollisionDesc=0;
1976 1976
1977 updatedEntityCount = 0; 1977 updatedEntityCount = 0;
1978 collidersCount = 0; 1978 collidersCount = 0;
1979 1979
1980 1980
1981 if (pWorld is BulletWorldXNA) 1981 if (pWorld is BulletWorldXNA)
1982 { 1982 {
@@ -2033,7 +2033,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2033 2033
2034 collidersCount = LastCollisionDesc; 2034 collidersCount = LastCollisionDesc;
2035 colliders = UpdatedCollisions; 2035 colliders = UpdatedCollisions;
2036 2036
2037 2037
2038 } 2038 }
2039 else 2039 else
@@ -2041,15 +2041,15 @@ private sealed class BulletConstraintXNA : BulletConstraint
2041 //if (updatedEntities is null) 2041 //if (updatedEntities is null)
2042 //updatedEntities = new List<BulletXNA.EntityProperties>(); 2042 //updatedEntities = new List<BulletXNA.EntityProperties>();
2043 //updatedEntityCount = 0; 2043 //updatedEntityCount = 0;
2044 2044
2045 2045
2046 //collidersCount = 0; 2046 //collidersCount = 0;
2047 2047
2048 updatedEntities = new EntityProperties[0]; 2048 updatedEntities = new EntityProperties[0];
2049 2049
2050 2050
2051 colliders = new CollisionDesc[0]; 2051 colliders = new CollisionDesc[0];
2052 2052
2053 } 2053 }
2054 return numSimSteps; 2054 return numSimSteps;
2055 } 2055 }
@@ -2057,7 +2057,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2057 { 2057 {
2058 IOverlappingPairCache cache = obj.GetOverlappingPairCache(); 2058 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2059 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); 2059 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2060 2060
2061 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; 2061 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2062 PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); 2062 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2063 BroadphasePair collisionPair; 2063 BroadphasePair collisionPair;
@@ -2069,7 +2069,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2069 ManifoldPoint pt; 2069 ManifoldPoint pt;
2070 2070
2071 int numPairs = pairs.Count; 2071 int numPairs = pairs.Count;
2072 2072
2073 for (int i = 0; i < numPairs; i++) 2073 for (int i = 0; i < numPairs; i++)
2074 { 2074 {
2075 manifoldArray.Clear(); 2075 manifoldArray.Clear();
@@ -2078,7 +2078,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2078 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); 2078 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2079 if (collisionPair == null) 2079 if (collisionPair == null)
2080 continue; 2080 continue;
2081 2081
2082 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); 2082 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2083 for (int j = 0; j < manifoldArray.Count; j++) 2083 for (int j = 0; j < manifoldArray.Count; j++)
2084 { 2084 {
@@ -2101,7 +2101,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2101 } 2101 }
2102 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) 2102 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2103 { 2103 {
2104 2104
2105 IndexedVector3 contactNormal = norm; 2105 IndexedVector3 contactNormal = norm;
2106 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && 2106 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2107 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) 2107 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
@@ -2171,11 +2171,11 @@ private sealed class BulletConstraintXNA : BulletConstraint
2171 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) 2171 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2172 { 2172 {
2173 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; 2173 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2174 2174
2175 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); 2175 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2176 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); 2176 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2177 using ( 2177 using (
2178 ClosestNotMeRayResultCallback rayCallback = 2178 ClosestNotMeRayResultCallback rayCallback =
2179 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) 2179 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2180 ) 2180 )
2181 { 2181 {
@@ -2191,9 +2191,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
2191 return false; 2191 return false;
2192 } 2192 }
2193} 2193}
2194
2195 2194
2196 2195
2196
2197 2197
2198 public class SimMotionState : DefaultMotionState 2198 public class SimMotionState : DefaultMotionState
2199 { 2199 {
@@ -2286,12 +2286,12 @@ private sealed class BulletConstraintXNA : BulletConstraint
2286 m_lastProperties = m_properties; 2286 m_lastProperties = m_properties;
2287 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) 2287 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2288 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); 2288 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2289 2289
2290 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; 2290 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2291 } 2291 }
2292 2292
2293 2293
2294 2294
2295 2295
2296 } 2296 }
2297 public override void SetRigidBody(RigidBody body) 2297 public override void SetRigidBody(RigidBody body)
@@ -2314,7 +2314,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2314 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && 2314 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2315 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); 2315 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2316 } 2316 }
2317 2317
2318 } 2318 }
2319} 2319}
2320 2320
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
index bd5ee0b1..4e067b5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
@@ -87,8 +87,8 @@ public class BSActorAvatarMove : BSActor
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step. 88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time. 89 // Called at taint-time.
90 // BSActor.RemoveBodyDependencies() 90 // BSActor.RemoveDependencies()
91 public override void RemoveBodyDependencies() 91 public override void RemoveDependencies()
92 { 92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time. 93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 } 94 }
@@ -115,7 +115,7 @@ public class BSActorAvatarMove : BSActor
115 if (m_velocityMotor == null) 115 if (m_velocityMotor == null)
116 { 116 {
117 // Infinite decay and timescale values so motor only changes current to target values. 117 // Infinite decay and timescale values so motor only changes current to target values.
118 m_velocityMotor = new BSVMotor("BSCharacter.Velocity", 118 m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
119 0.2f, // time scale 119 0.2f, // time scale
120 BSMotor.Infinite, // decay time scale 120 BSMotor.Infinite, // decay time scale
121 BSMotor.InfiniteVector, // friction timescale 121 BSMotor.InfiniteVector, // friction timescale
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
index 92ace66..3630ca8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
@@ -87,8 +87,8 @@ public class BSActorHover : BSActor
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step. 88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time. 89 // Called at taint-time.
90 // BSActor.RemoveBodyDependencies() 90 // BSActor.RemoveDependencies()
91 public override void RemoveBodyDependencies() 91 public override void RemoveDependencies()
92 { 92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time. 93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 } 94 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
index 09ee32b..7801d8e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
@@ -63,7 +63,7 @@ public class BSActorLockAxis : BSActor
63 // BSActor.Refresh() 63 // BSActor.Refresh()
64 public override void Refresh() 64 public override void Refresh()
65 { 65 {
66 m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", 66 m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}",
67 m_controllingPrim.LocalID, m_controllingPrim.LockedAxis, Enabled, m_controllingPrim.IsPhysicallyActive); 67 m_controllingPrim.LocalID, m_controllingPrim.LockedAxis, Enabled, m_controllingPrim.IsPhysicallyActive);
68 // If all the axis are free, we don't need to exist 68 // If all the axis are free, we don't need to exist
69 if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) 69 if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree)
@@ -85,8 +85,8 @@ public class BSActorLockAxis : BSActor
85 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 85 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
86 // Register a prestep action to restore physical requirements before the next simulation step. 86 // Register a prestep action to restore physical requirements before the next simulation step.
87 // Called at taint-time. 87 // Called at taint-time.
88 // BSActor.RemoveBodyDependencies() 88 // BSActor.RemoveDependencies()
89 public override void RemoveBodyDependencies() 89 public override void RemoveDependencies()
90 { 90 {
91 if (LockAxisConstraint != null) 91 if (LockAxisConstraint != null)
92 { 92 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
index 56aacc5..1b598fd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
@@ -88,8 +88,8 @@ public class BSActorMoveToTarget : BSActor
88 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 88 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
89 // Register a prestep action to restore physical requirements before the next simulation step. 89 // Register a prestep action to restore physical requirements before the next simulation step.
90 // Called at taint-time. 90 // Called at taint-time.
91 // BSActor.RemoveBodyDependencies() 91 // BSActor.RemoveDependencies()
92 public override void RemoveBodyDependencies() 92 public override void RemoveDependencies()
93 { 93 {
94 // Nothing to do for the moveToTarget since it is all software at pre-step action time. 94 // Nothing to do for the moveToTarget since it is all software at pre-step action time.
95 } 95 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
index 3ad138d..c0f40fd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
@@ -89,8 +89,8 @@ public class BSActorSetForce : BSActor
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step. 90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time. 91 // Called at taint-time.
92 // BSActor.RemoveBodyDependencies() 92 // BSActor.RemoveDependencies()
93 public override void RemoveBodyDependencies() 93 public override void RemoveDependencies()
94 { 94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time. 95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 } 96 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
index 7a791ec..b3806e1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
@@ -89,8 +89,8 @@ public class BSActorSetTorque : BSActor
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step. 90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time. 91 // Called at taint-time.
92 // BSActor.RemoveBodyDependencies() 92 // BSActor.RemoveDependencies()
93 public override void RemoveBodyDependencies() 93 public override void RemoveDependencies()
94 { 94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time. 95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 } 96 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
index 12a8817..fff63e4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
@@ -106,9 +106,9 @@ public class BSActorCollection
106 { 106 {
107 ForEachActor(a => a.Refresh()); 107 ForEachActor(a => a.Refresh());
108 } 108 }
109 public void RemoveBodyDependencies() 109 public void RemoveDependencies()
110 { 110 {
111 ForEachActor(a => a.RemoveBodyDependencies()); 111 ForEachActor(a => a.RemoveDependencies());
112 } 112 }
113} 113}
114 114
@@ -117,7 +117,7 @@ public class BSActorCollection
117/// Each physical object can have 'actors' who are pushing the object around. 117/// Each physical object can have 'actors' who are pushing the object around.
118/// This can be used for hover, locking axis, making vehicles, etc. 118/// This can be used for hover, locking axis, making vehicles, etc.
119/// Each physical object can have multiple actors acting on it. 119/// Each physical object can have multiple actors acting on it.
120/// 120///
121/// An actor usually registers itself with physics scene events (pre-step action) 121/// An actor usually registers itself with physics scene events (pre-step action)
122/// and modifies the parameters on the host physical object. 122/// and modifies the parameters on the host physical object.
123/// </summary> 123/// </summary>
@@ -154,7 +154,7 @@ public abstract class BSActor
154 public abstract void Refresh(); 154 public abstract void Refresh();
155 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 155 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
156 // Register a prestep action to restore physical requirements before the next simulation step. 156 // Register a prestep action to restore physical requirements before the next simulation step.
157 public abstract void RemoveBodyDependencies(); 157 public abstract void RemoveDependencies();
158 158
159} 159}
160} 160}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
index bfeec24..3378c93 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -298,7 +298,7 @@ public abstract class BSAPITemplate
298{ 298{
299// Returns the name of the underlying Bullet engine 299// Returns the name of the underlying Bullet engine
300public abstract string BulletEngineName { get; } 300public abstract string BulletEngineName { get; }
301public abstract string BulletEngineVersion { get; protected set;} 301public abstract string BulletEngineVersion { get; protected set;}
302 302
303// Initialization and simulation 303// Initialization and simulation
304public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, 304public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
@@ -373,7 +373,7 @@ public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
373// ===================================================================================== 373// =====================================================================================
374public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); 374public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
375 375
376public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 376public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
377 float scaleFactor, float collisionMargin); 377 float scaleFactor, float collisionMargin);
378 378
379// ===================================================================================== 379// =====================================================================================
@@ -388,7 +388,7 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
388 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 388 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
389 389
390public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, 390public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
391 Vector3 frameInBloc, Quaternion frameInBrot, 391 Vector3 frameInBloc, Quaternion frameInBrot,
392 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); 392 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
393 393
394public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 394public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index a0d58d3..542f732 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -95,18 +95,18 @@ public sealed class BSCharacter : BSPhysObject
95 // the avatar seeking to reach the motor's target speed. 95 // the avatar seeking to reach the motor's target speed.
96 // This motor runs as a prestep action for the avatar so it will keep the avatar 96 // This motor runs as a prestep action for the avatar so it will keep the avatar
97 // standing as well as moving. Destruction of the avatar will destroy the pre-step action. 97 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
98 m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName); 98 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
99 PhysicalActors.Add(AvatarMoveActorName, m_moveActor); 99 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
100 100
101 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 101 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
102 LocalID, _size, Scale, Density, _avatarVolume, RawMass); 102 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
103 103
104 // do actual creation in taint time 104 // do actual creation in taint time
105 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 105 PhysScene.TaintedObject("BSCharacter.create", delegate()
106 { 106 {
107 DetailLog("{0},BSCharacter.create,taint", LocalID); 107 DetailLog("{0},BSCharacter.create,taint", LocalID);
108 // New body and shape into PhysBody and PhysShape 108 // New body and shape into PhysBody and PhysShape
109 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); 109 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
110 110
111 SetPhysicalProperties(); 111 SetPhysicalProperties();
112 }); 112 });
@@ -119,18 +119,18 @@ public sealed class BSCharacter : BSPhysObject
119 base.Destroy(); 119 base.Destroy();
120 120
121 DetailLog("{0},BSCharacter.Destroy", LocalID); 121 DetailLog("{0},BSCharacter.Destroy", LocalID);
122 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 122 PhysScene.TaintedObject("BSCharacter.destroy", delegate()
123 { 123 {
124 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); 124 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
125 PhysBody.Clear(); 125 PhysBody.Clear();
126 PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); 126 PhysShape.Dereference(PhysScene);
127 PhysShape.Clear(); 127 PhysShape = new BSShapeNull();
128 }); 128 });
129 } 129 }
130 130
131 private void SetPhysicalProperties() 131 private void SetPhysicalProperties()
132 { 132 {
133 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 133 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
134 134
135 ZeroMotion(true); 135 ZeroMotion(true);
136 ForcePosition = _position; 136 ForcePosition = _position;
@@ -145,35 +145,35 @@ public sealed class BSCharacter : BSPhysObject
145 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 145 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
146 Flying = _flying; 146 Flying = _flying;
147 147
148 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 148 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
149 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 149 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
150 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 150 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
151 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 151 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
152 if (BSParam.CcdMotionThreshold > 0f) 152 if (BSParam.CcdMotionThreshold > 0f)
153 { 153 {
154 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 154 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
155 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 155 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
156 } 156 }
157 157
158 UpdatePhysicalMassProperties(RawMass, false); 158 UpdatePhysicalMassProperties(RawMass, false);
159 159
160 // Make so capsule does not fall over 160 // Make so capsule does not fall over
161 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); 161 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
162 162
163 // The avatar mover sets some parameters. 163 // The avatar mover sets some parameters.
164 PhysicalActors.Refresh(); 164 PhysicalActors.Refresh();
165 165
166 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); 166 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
167 167
168 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 168 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
169 169
170 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 170 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
171 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); 171 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
172 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 172 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
173 173
174 // Do this after the object has been added to the world 174 // Do this after the object has been added to the world
175 PhysBody.collisionType = CollisionType.Avatar; 175 PhysBody.collisionType = CollisionType.Avatar;
176 PhysBody.ApplyCollisionMask(PhysicsScene); 176 PhysBody.ApplyCollisionMask(PhysScene);
177 } 177 }
178 178
179 179
@@ -203,14 +203,14 @@ public sealed class BSCharacter : BSPhysObject
203 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 203 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
204 LocalID, _size, Scale, Density, _avatarVolume, RawMass); 204 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
205 205
206 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 206 PhysScene.TaintedObject("BSCharacter.setSize", delegate()
207 { 207 {
208 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 208 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
209 { 209 {
210 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 210 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
211 UpdatePhysicalMassProperties(RawMass, true); 211 UpdatePhysicalMassProperties(RawMass, true);
212 // Make sure this change appears as a property update event 212 // Make sure this change appears as a property update event
213 PhysicsScene.PE.PushUpdate(PhysBody); 213 PhysScene.PE.PushUpdate(PhysBody);
214 } 214 }
215 }); 215 });
216 216
@@ -221,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject
221 { 221 {
222 set { BaseShape = value; } 222 set { BaseShape = value; }
223 } 223 }
224 // I want the physics engine to make an avatar capsule
225 public override BSPhysicsShapeType PreferredPhysicalShape
226 {
227 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
228 }
229 224
230 public override bool Grabbed { 225 public override bool Grabbed {
231 set { _grabbed = value; } 226 set { _grabbed = value; }
@@ -252,24 +247,24 @@ public sealed class BSCharacter : BSPhysObject
252 _rotationalVelocity = OMV.Vector3.Zero; 247 _rotationalVelocity = OMV.Vector3.Zero;
253 248
254 // Zero some other properties directly into the physics engine 249 // Zero some other properties directly into the physics engine
255 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 250 PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
256 { 251 {
257 if (PhysBody.HasPhysicalBody) 252 if (PhysBody.HasPhysicalBody)
258 PhysicsScene.PE.ClearAllForces(PhysBody); 253 PhysScene.PE.ClearAllForces(PhysBody);
259 }); 254 });
260 } 255 }
261 public override void ZeroAngularMotion(bool inTaintTime) 256 public override void ZeroAngularMotion(bool inTaintTime)
262 { 257 {
263 _rotationalVelocity = OMV.Vector3.Zero; 258 _rotationalVelocity = OMV.Vector3.Zero;
264 259
265 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 260 PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
266 { 261 {
267 if (PhysBody.HasPhysicalBody) 262 if (PhysBody.HasPhysicalBody)
268 { 263 {
269 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); 264 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
270 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); 265 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
271 // The next also get rid of applied linear force but the linear velocity is untouched. 266 // The next also get rid of applied linear force but the linear velocity is untouched.
272 PhysicsScene.PE.ClearForces(PhysBody); 267 PhysScene.PE.ClearForces(PhysBody);
273 } 268 }
274 }); 269 });
275 } 270 }
@@ -291,7 +286,7 @@ public sealed class BSCharacter : BSPhysObject
291 set { 286 set {
292 _position = value; 287 _position = value;
293 288
294 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 289 PhysScene.TaintedObject("BSCharacter.setPosition", delegate()
295 { 290 {
296 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 291 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
297 PositionSanityCheck(); 292 PositionSanityCheck();
@@ -301,14 +296,14 @@ public sealed class BSCharacter : BSPhysObject
301 } 296 }
302 public override OMV.Vector3 ForcePosition { 297 public override OMV.Vector3 ForcePosition {
303 get { 298 get {
304 _position = PhysicsScene.PE.GetPosition(PhysBody); 299 _position = PhysScene.PE.GetPosition(PhysBody);
305 return _position; 300 return _position;
306 } 301 }
307 set { 302 set {
308 _position = value; 303 _position = value;
309 if (PhysBody.HasPhysicalBody) 304 if (PhysBody.HasPhysicalBody)
310 { 305 {
311 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 306 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
312 } 307 }
313 } 308 }
314 } 309 }
@@ -322,18 +317,18 @@ public sealed class BSCharacter : BSPhysObject
322 bool ret = false; 317 bool ret = false;
323 318
324 // TODO: check for out of bounds 319 // TODO: check for out of bounds
325 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 320 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
326 { 321 {
327 // The character is out of the known/simulated area. 322 // The character is out of the known/simulated area.
328 // Force the avatar position to be within known. ScenePresence will use the position 323 // Force the avatar position to be within known. ScenePresence will use the position
329 // plus the velocity to decide if the avatar is moving out of the region. 324 // plus the velocity to decide if the avatar is moving out of the region.
330 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); 325 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
331 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); 326 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
332 return true; 327 return true;
333 } 328 }
334 329
335 // If below the ground, move the avatar up 330 // If below the ground, move the avatar up
336 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 331 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
337 if (Position.Z < terrainHeight) 332 if (Position.Z < terrainHeight)
338 { 333 {
339 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); 334 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
@@ -342,7 +337,7 @@ public sealed class BSCharacter : BSPhysObject
342 } 337 }
343 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 338 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
344 { 339 {
345 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 340 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position);
346 if (Position.Z < waterHeight) 341 if (Position.Z < waterHeight)
347 { 342 {
348 _position.Z = waterHeight; 343 _position.Z = waterHeight;
@@ -363,7 +358,7 @@ public sealed class BSCharacter : BSPhysObject
363 { 358 {
364 // The new position value must be pushed into the physics engine but we can't 359 // The new position value must be pushed into the physics engine but we can't
365 // just assign to "Position" because of potential call loops. 360 // just assign to "Position" because of potential call loops.
366 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 361 PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
367 { 362 {
368 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 363 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
369 ForcePosition = _position; 364 ForcePosition = _position;
@@ -376,13 +371,13 @@ public sealed class BSCharacter : BSPhysObject
376 public override float Mass { get { return _mass; } } 371 public override float Mass { get { return _mass; } }
377 372
378 // used when we only want this prim's mass and not the linkset thing 373 // used when we only want this prim's mass and not the linkset thing
379 public override float RawMass { 374 public override float RawMass {
380 get {return _mass; } 375 get {return _mass; }
381 } 376 }
382 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 377 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
383 { 378 {
384 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 379 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
385 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 380 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
386 } 381 }
387 382
388 public override OMV.Vector3 Force { 383 public override OMV.Vector3 Force {
@@ -390,11 +385,11 @@ public sealed class BSCharacter : BSPhysObject
390 set { 385 set {
391 RawForce = value; 386 RawForce = value;
392 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 387 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
393 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 388 PhysScene.TaintedObject("BSCharacter.SetForce", delegate()
394 { 389 {
395 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); 390 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
396 if (PhysBody.HasPhysicalBody) 391 if (PhysBody.HasPhysicalBody)
397 PhysicsScene.PE.SetObjectForce(PhysBody, RawForce); 392 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
398 }); 393 });
399 } 394 }
400 } 395 }
@@ -437,7 +432,7 @@ public sealed class BSCharacter : BSPhysObject
437 set { 432 set {
438 RawVelocity = value; 433 RawVelocity = value;
439 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); 434 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
440 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 435 PhysScene.TaintedObject("BSCharacter.setVelocity", delegate()
441 { 436 {
442 if (m_moveActor != null) 437 if (m_moveActor != null)
443 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); 438 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
@@ -450,11 +445,11 @@ public sealed class BSCharacter : BSPhysObject
450 public override OMV.Vector3 ForceVelocity { 445 public override OMV.Vector3 ForceVelocity {
451 get { return RawVelocity; } 446 get { return RawVelocity; }
452 set { 447 set {
453 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 448 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
454 449
455 RawVelocity = value; 450 RawVelocity = value;
456 PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); 451 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
457 PhysicsScene.PE.Activate(PhysBody, true); 452 PhysScene.PE.Activate(PhysBody, true);
458 } 453 }
459 } 454 }
460 public override OMV.Vector3 Torque { 455 public override OMV.Vector3 Torque {
@@ -484,7 +479,7 @@ public sealed class BSCharacter : BSPhysObject
484 if (_orientation != value) 479 if (_orientation != value)
485 { 480 {
486 _orientation = value; 481 _orientation = value;
487 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 482 PhysScene.TaintedObject("BSCharacter.setOrientation", delegate()
488 { 483 {
489 ForceOrientation = _orientation; 484 ForceOrientation = _orientation;
490 }); 485 });
@@ -496,7 +491,7 @@ public sealed class BSCharacter : BSPhysObject
496 { 491 {
497 get 492 get
498 { 493 {
499 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 494 _orientation = PhysScene.PE.GetOrientation(PhysBody);
500 return _orientation; 495 return _orientation;
501 } 496 }
502 set 497 set
@@ -505,7 +500,7 @@ public sealed class BSCharacter : BSPhysObject
505 if (PhysBody.HasPhysicalBody) 500 if (PhysBody.HasPhysicalBody)
506 { 501 {
507 // _position = PhysicsScene.PE.GetPosition(BSBody); 502 // _position = PhysicsScene.PE.GetPosition(BSBody);
508 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 503 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
509 } 504 }
510 } 505 }
511 } 506 }
@@ -554,14 +549,14 @@ public sealed class BSCharacter : BSPhysObject
554 public override bool FloatOnWater { 549 public override bool FloatOnWater {
555 set { 550 set {
556 _floatOnWater = value; 551 _floatOnWater = value;
557 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 552 PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
558 { 553 {
559 if (PhysBody.HasPhysicalBody) 554 if (PhysBody.HasPhysicalBody)
560 { 555 {
561 if (_floatOnWater) 556 if (_floatOnWater)
562 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 557 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
563 else 558 else
564 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 559 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
565 } 560 }
566 }); 561 });
567 } 562 }
@@ -582,7 +577,7 @@ public sealed class BSCharacter : BSPhysObject
582 public override float Buoyancy { 577 public override float Buoyancy {
583 get { return _buoyancy; } 578 get { return _buoyancy; }
584 set { _buoyancy = value; 579 set { _buoyancy = value;
585 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 580 PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
586 { 581 {
587 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 582 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
588 ForceBuoyancy = _buoyancy; 583 ForceBuoyancy = _buoyancy;
@@ -591,8 +586,8 @@ public sealed class BSCharacter : BSPhysObject
591 } 586 }
592 public override float ForceBuoyancy { 587 public override float ForceBuoyancy {
593 get { return _buoyancy; } 588 get { return _buoyancy; }
594 set { 589 set {
595 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); 590 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
596 591
597 _buoyancy = value; 592 _buoyancy = value;
598 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 593 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
@@ -600,7 +595,7 @@ public sealed class BSCharacter : BSPhysObject
600 float grav = BSParam.Gravity * (1f - _buoyancy); 595 float grav = BSParam.Gravity * (1f - _buoyancy);
601 Gravity = new OMV.Vector3(0f, 0f, grav); 596 Gravity = new OMV.Vector3(0f, 0f, grav);
602 if (PhysBody.HasPhysicalBody) 597 if (PhysBody.HasPhysicalBody)
603 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 598 PhysScene.PE.SetGravity(PhysBody, Gravity);
604 } 599 }
605 } 600 }
606 601
@@ -618,7 +613,7 @@ public sealed class BSCharacter : BSPhysObject
618 public override void AddForce(OMV.Vector3 force, bool pushforce) 613 public override void AddForce(OMV.Vector3 force, bool pushforce)
619 { 614 {
620 // Since this force is being applied in only one step, make this a force per second. 615 // Since this force is being applied in only one step, make this a force per second.
621 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 616 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
622 AddForce(addForce, pushforce, false); 617 AddForce(addForce, pushforce, false);
623 } 618 }
624 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 619 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
@@ -627,13 +622,13 @@ public sealed class BSCharacter : BSPhysObject
627 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 622 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
628 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); 623 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
629 624
630 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() 625 PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
631 { 626 {
632 // Bullet adds this central force to the total force for this tick 627 // Bullet adds this central force to the total force for this tick
633 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 628 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
634 if (PhysBody.HasPhysicalBody) 629 if (PhysBody.HasPhysicalBody)
635 { 630 {
636 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 631 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
637 } 632 }
638 }); 633 });
639 } 634 }
@@ -652,7 +647,7 @@ public sealed class BSCharacter : BSPhysObject
652 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) 647 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
653 { 648 {
654 OMV.Vector3 newScale; 649 OMV.Vector3 newScale;
655 650
656 // Bullet's capsule total height is the "passed height + radius * 2"; 651 // Bullet's capsule total height is the "passed height + radius * 2";
657 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) 652 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
658 // The number we pass in for 'scaling' is the multiplier to get that base 653 // The number we pass in for 'scaling' is the multiplier to get that base
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index 7714a03..ed89f63 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -45,7 +45,7 @@ public sealed class BSConstraintHinge : BSConstraint
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, 47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 pivotInA, pivotInB, axisInA, axisInB, 48 pivotInA, pivotInB, axisInA, axisInB,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true; 50 m_enabled = true;
51 } 51 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 612c68b..c5bee6d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -559,9 +559,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
559 break; 559 break;
560 } 560 }
561 561
562 // Update any physical parameters based on this type.
563 Refresh();
564
565 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, 562 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
566 m_linearMotorDecayTimescale, m_linearFrictionTimescale, 563 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
567 1f); 564 1f);
@@ -589,6 +586,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
589 { 586 {
590 RegisterForSceneEvents(); 587 RegisterForSceneEvents();
591 } 588 }
589
590 // Update any physical parameters based on this type.
591 Refresh();
592 } 592 }
593 #endregion // Vehicle parameter setting 593 #endregion // Vehicle parameter setting
594 594
@@ -596,6 +596,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
596 public override void Refresh() 596 public override void Refresh()
597 { 597 {
598 // If asking for a refresh, reset the physical parameters before the next simulation step. 598 // If asking for a refresh, reset the physical parameters before the next simulation step.
599 // Called whether active or not since the active state may be updated before the next step.
599 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() 600 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
600 { 601 {
601 SetPhysicalParameters(); 602 SetPhysicalParameters();
@@ -625,7 +626,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
625 // Vehicles report collision events so we know when it's on the ground 626 // Vehicles report collision events so we know when it's on the ground
626 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 627 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
627 628
628 ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape, m_vehicleMass); 629 ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
629 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); 630 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
630 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); 631 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
631 632
@@ -649,7 +650,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
649 } 650 }
650 651
651 // BSActor.RemoveBodyDependencies 652 // BSActor.RemoveBodyDependencies
652 public override void RemoveBodyDependencies() 653 public override void RemoveDependencies()
653 { 654 {
654 Refresh(); 655 Refresh();
655 } 656 }
@@ -789,7 +790,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
789 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) 790 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
790 { 791 {
791 lastRememberedHeightPos = pos; 792 lastRememberedHeightPos = pos;
792 m_knownTerrainHeight = ControllingPrim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 793 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
793 m_knownHas |= m_knownChangedTerrainHeight; 794 m_knownHas |= m_knownChangedTerrainHeight;
794 } 795 }
795 return m_knownTerrainHeight; 796 return m_knownTerrainHeight;
@@ -801,7 +802,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
801 { 802 {
802 if ((m_knownHas & m_knownChangedWaterLevel) == 0) 803 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
803 { 804 {
804 m_knownWaterLevel = ControllingPrim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); 805 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
805 m_knownHas |= m_knownChangedWaterLevel; 806 m_knownHas |= m_knownChangedWaterLevel;
806 } 807 }
807 return (float)m_knownWaterLevel; 808 return (float)m_knownWaterLevel;
@@ -1019,7 +1020,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1019 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG 1020 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1020 VehicleVelocity /= VehicleVelocity.Length(); 1021 VehicleVelocity /= VehicleVelocity.Length();
1021 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; 1022 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
1022 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", 1023 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
1023 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); 1024 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
1024 } 1025 }
1025 else if (newVelocityLengthSq < 0.001f) 1026 else if (newVelocityLengthSq < 0.001f)
@@ -1094,7 +1095,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1094 if (VehiclePosition.Z > m_VhoverTargetHeight) 1095 if (VehiclePosition.Z > m_VhoverTargetHeight)
1095 m_VhoverTargetHeight = VehiclePosition.Z; 1096 m_VhoverTargetHeight = VehiclePosition.Z;
1096 } 1097 }
1097 1098
1098 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1099 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
1099 { 1100 {
1100 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) 1101 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
@@ -1188,7 +1189,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1188 // used with conjunction with banking: the strength of the banking will decay when the 1189 // used with conjunction with banking: the strength of the banking will decay when the
1189 // vehicle no longer experiences collisions. The decay timescale is the same as 1190 // vehicle no longer experiences collisions. The decay timescale is the same as
1190 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering 1191 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1191 // when they are in mid jump. 1192 // when they are in mid jump.
1192 // TODO: this code is wrong. Also, what should it do for boats (height from water)? 1193 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1193 // This is just using the ground and a general collision check. Should really be using 1194 // This is just using the ground and a general collision check. Should really be using
1194 // a downward raycast to find what is below. 1195 // a downward raycast to find what is below.
@@ -1254,7 +1255,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1254 1255
1255 VehicleAddForce(appliedGravity); 1256 VehicleAddForce(appliedGravity);
1256 1257
1257 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", 1258 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
1258 ControllingPrim.LocalID, m_VehicleGravity, 1259 ControllingPrim.LocalID, m_VehicleGravity,
1259 ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); 1260 ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1260 } 1261 }
@@ -1330,7 +1331,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1330 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : 1331 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1331 // This flag prevents linear deflection parallel to world z-axis. This is useful 1332 // This flag prevents linear deflection parallel to world z-axis. This is useful
1332 // for preventing ground vehicles with large linear deflection, like bumper cars, 1333 // for preventing ground vehicles with large linear deflection, like bumper cars,
1333 // from climbing their linear deflection into the sky. 1334 // from climbing their linear deflection into the sky.
1334 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement 1335 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1335 // TODO: This is here because this is where ODE put it but documentation says it 1336 // TODO: This is here because this is where ODE put it but documentation says it
1336 // is a linear effect. Where should this check go? 1337 // is a linear effect. Where should this check go?
@@ -1463,7 +1464,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1463 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); 1464 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1464 1465
1465 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", 1466 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1466 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, 1467 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1467 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); 1468 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1468 */ 1469 */
1469 } 1470 }
@@ -1530,13 +1531,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1530 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude 1531 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1531 // of the yaw effect will be proportional to the 1532 // of the yaw effect will be proportional to the
1532 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's 1533 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1533 // velocity along its preferred axis of motion. 1534 // velocity along its preferred axis of motion.
1534 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any 1535 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1535 // positive rotation (by the right-hand rule) about the roll-axis will effect a 1536 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1536 // (negative) torque around the yaw-axis, making it turn to the right--that is the 1537 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1537 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. 1538 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1538 // Negating the banking coefficient will make it so that the vehicle leans to the 1539 // Negating the banking coefficient will make it so that the vehicle leans to the
1539 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). 1540 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1540 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making 1541 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1541 // banking vehicles do what you want rather than what the laws of physics allow. 1542 // banking vehicles do what you want rather than what the laws of physics allow.
1542 // For example, consider a real motorcycle...it must be moving forward in order for 1543 // For example, consider a real motorcycle...it must be moving forward in order for
@@ -1548,11 +1549,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1548 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the 1549 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1549 // banking effect depends only on the vehicle's rotation about its roll-axis compared 1550 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1550 // to "dynamic" where the banking is also proportional to its velocity along its 1551 // to "dynamic" where the banking is also proportional to its velocity along its
1551 // roll-axis. Finding the best value of the "mixture" will probably require trial and error. 1552 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1552 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the 1553 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1553 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to 1554 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1554 // bank quickly then give it a banking timescale of about a second or less, otherwise you can 1555 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1555 // make a sluggish vehicle by giving it a timescale of several seconds. 1556 // make a sluggish vehicle by giving it a timescale of several seconds.
1556 public void ComputeAngularBanking() 1557 public void ComputeAngularBanking()
1557 { 1558 {
1558 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1559 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
@@ -1581,7 +1582,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1581 1582
1582 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; 1583 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1583 VehicleRotationalVelocity += bankingContributionV; 1584 VehicleRotationalVelocity += bankingContributionV;
1584 1585
1585 1586
1586 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", 1587 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1587 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); 1588 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
@@ -1637,8 +1638,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1637 // Invoke the detailed logger and output something if it's enabled. 1638 // Invoke the detailed logger and output something if it's enabled.
1638 private void VDetailLog(string msg, params Object[] args) 1639 private void VDetailLog(string msg, params Object[] args)
1639 { 1640 {
1640 if (ControllingPrim.PhysicsScene.VehicleLoggingEnabled) 1641 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1641 ControllingPrim.PhysicsScene.DetailLog(msg, args); 1642 ControllingPrim.PhysScene.DetailLog(msg, args);
1642 } 1643 }
1643 } 1644 }
1644} 1645}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 4ece1eb..76c2187 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -80,7 +80,7 @@ public abstract class BSLinkset
80 80
81 public BSPrimLinkable LinksetRoot { get; protected set; } 81 public BSPrimLinkable LinksetRoot { get; protected set; }
82 82
83 public BSScene PhysicsScene { get; private set; } 83 protected BSScene m_physicsScene { get; private set; }
84 84
85 static int m_nextLinksetID = 1; 85 static int m_nextLinksetID = 1;
86 public int LinksetID { get; private set; } 86 public int LinksetID { get; private set; }
@@ -93,13 +93,6 @@ public abstract class BSLinkset
93 // to the physical representation is done via the tainting mechenism. 93 // to the physical representation is done via the tainting mechenism.
94 protected object m_linksetActivityLock = new Object(); 94 protected object m_linksetActivityLock = new Object();
95 95
96 // Some linksets have a preferred physical shape.
97 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
98 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
99 {
100 return BSPhysicsShapeType.SHAPE_UNKNOWN;
101 }
102
103 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 96 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
104 public float LinksetMass { get; protected set; } 97 public float LinksetMass { get; protected set; }
105 98
@@ -122,7 +115,7 @@ public abstract class BSLinkset
122 // We create LOTS of linksets. 115 // We create LOTS of linksets.
123 if (m_nextLinksetID <= 0) 116 if (m_nextLinksetID <= 0)
124 m_nextLinksetID = 1; 117 m_nextLinksetID = 1;
125 PhysicsScene = scene; 118 m_physicsScene = scene;
126 LinksetRoot = parent; 119 LinksetRoot = parent;
127 m_children = new HashSet<BSPrimLinkable>(); 120 m_children = new HashSet<BSPrimLinkable>();
128 LinksetMass = parent.RawMass; 121 LinksetMass = parent.RawMass;
@@ -165,7 +158,7 @@ public abstract class BSLinkset
165 } 158 }
166 159
167 // The child is down to a linkset of just itself 160 // The child is down to a linkset of just itself
168 return BSLinkset.Factory(PhysicsScene, child); 161 return BSLinkset.Factory(m_physicsScene, child);
169 } 162 }
170 163
171 // Return 'true' if the passed object is the root object of this linkset 164 // Return 'true' if the passed object is the root object of this linkset
@@ -221,7 +214,7 @@ public abstract class BSLinkset
221 // I am the root of a linkset and a new child is being added 214 // I am the root of a linkset and a new child is being added
222 // Called while LinkActivity is locked. 215 // Called while LinkActivity is locked.
223 protected abstract void AddChildToLinkset(BSPrimLinkable child); 216 protected abstract void AddChildToLinkset(BSPrimLinkable child);
224 217
225 // I am the root of a linkset and one of my children is being removed. 218 // I am the root of a linkset and one of my children is being removed.
226 // Safe to call even if the child is not really in my linkset. 219 // Safe to call even if the child is not really in my linkset.
227 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); 220 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
@@ -263,7 +256,7 @@ public abstract class BSLinkset
263 // This is called when the root body is changing. 256 // This is called when the root body is changing.
264 // Returns 'true' of something was actually removed and would need restoring 257 // Returns 'true' of something was actually removed and would need restoring
265 // Called at taint-time!! 258 // Called at taint-time!!
266 public abstract bool RemoveBodyDependencies(BSPrimLinkable child); 259 public abstract bool RemoveDependencies(BSPrimLinkable child);
267 260
268 // ================================================================ 261 // ================================================================
269 protected virtual float ComputeLinksetMass() 262 protected virtual float ComputeLinksetMass()
@@ -323,8 +316,8 @@ public abstract class BSLinkset
323 // Invoke the detailed logger and output something if it's enabled. 316 // Invoke the detailed logger and output something if it's enabled.
324 protected void DetailLog(string msg, params Object[] args) 317 protected void DetailLog(string msg, params Object[] args)
325 { 318 {
326 if (PhysicsScene.PhysicsLogging.Enabled) 319 if (m_physicsScene.PhysicsLogging.Enabled)
327 PhysicsScene.DetailLog(msg, args); 320 m_physicsScene.DetailLog(msg, args);
328 } 321 }
329 322
330} 323}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index e05562a..1f16cc8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -35,6 +35,7 @@ using OMV = OpenMetaverse;
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37 37
38 /*
38// When a child is linked, the relationship position of the child to the parent 39// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is 40// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset. 41// removed from the linkset.
@@ -88,6 +89,7 @@ sealed class BSLinksetCompoundInfo : BSLinksetInfo
88 return buff.ToString(); 89 return buff.ToString();
89 } 90 }
90}; 91};
92 */
91 93
92public sealed class BSLinksetCompound : BSLinkset 94public sealed class BSLinksetCompound : BSLinkset
93{ 95{
@@ -98,19 +100,6 @@ public sealed class BSLinksetCompound : BSLinkset
98 { 100 {
99 } 101 }
100 102
101 // For compound implimented linksets, if there are children, use compound shape for the root.
102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
103 {
104 // Returning 'unknown' means we don't have a preference.
105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
106 if (IsRoot(requestor) && HasAnyChildren)
107 {
108 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
109 }
110 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
111 return ret;
112 }
113
114 // When physical properties are changed the linkset needs to recalculate 103 // When physical properties are changed the linkset needs to recalculate
115 // its internal properties. 104 // its internal properties.
116 public override void Refresh(BSPrimLinkable requestor) 105 public override void Refresh(BSPrimLinkable requestor)
@@ -124,14 +113,14 @@ public sealed class BSLinksetCompound : BSLinkset
124 // Schedule a refresh to happen after all the other taint processing. 113 // Schedule a refresh to happen after all the other taint processing.
125 private void ScheduleRebuild(BSPrimLinkable requestor) 114 private void ScheduleRebuild(BSPrimLinkable requestor)
126 { 115 {
127 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", 116 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
128 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); 117 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
129 // When rebuilding, it is possible to set properties that would normally require a rebuild. 118 // When rebuilding, it is possible to set properties that would normally require a rebuild.
130 // If already rebuilding, don't request another rebuild. 119 // If already rebuilding, don't request another rebuild.
131 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. 120 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
132 if (!Rebuilding && HasAnyChildren) 121 if (!Rebuilding && HasAnyChildren)
133 { 122 {
134 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() 123 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
135 { 124 {
136 if (HasAnyChildren) 125 if (HasAnyChildren)
137 RecomputeLinksetCompound(); 126 RecomputeLinksetCompound();
@@ -153,26 +142,11 @@ public sealed class BSLinksetCompound : BSLinkset
153 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. 142 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
154 ScheduleRebuild(LinksetRoot); 143 ScheduleRebuild(LinksetRoot);
155 } 144 }
156 else
157 {
158 // The origional prims are removed from the world as the shape of the root compound
159 // shape takes over.
160 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
161 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
162 // We don't want collisions from the old linkset children.
163 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
164
165 child.PhysBody.collisionType = CollisionType.LinksetChild;
166
167 ret = true;
168 }
169 return ret; 145 return ret;
170 } 146 }
171 147
172 // The object is going static (non-physical). Do any setup necessary for a static linkset. 148 // The object is going static (non-physical). We do not do anything for static linksets.
173 // Return 'true' if any properties updated on the passed object. 149 // Return 'true' if any properties updated on the passed object.
174 // This doesn't normally happen -- OpenSim removes the objects from the physical
175 // world if it is a static linkset.
176 // Called at taint-time! 150 // Called at taint-time!
177 public override bool MakeStatic(BSPrimLinkable child) 151 public override bool MakeStatic(BSPrimLinkable child)
178 { 152 {
@@ -180,19 +154,9 @@ public sealed class BSLinksetCompound : BSLinkset
180 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
181 if (IsRoot(child)) 155 if (IsRoot(child))
182 { 156 {
157 // Schedule a rebuild to verify that the root shape is set to the real shape.
183 ScheduleRebuild(LinksetRoot); 158 ScheduleRebuild(LinksetRoot);
184 } 159 }
185 else
186 {
187 // The non-physical children can come back to life.
188 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
189
190 child.PhysBody.collisionType = CollisionType.LinksetChild;
191
192 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
193 PhysicsScene.PE.Activate(child.PhysBody, false);
194 ret = true;
195 }
196 return ret; 160 return ret;
197 } 161 }
198 162
@@ -200,13 +164,20 @@ public sealed class BSLinksetCompound : BSLinkset
200 // Called at taint-time. 164 // Called at taint-time.
201 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) 165 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
202 { 166 {
167 if (!LinksetRoot.IsPhysicallyActive)
168 {
169 // No reason to do this physical stuff for static linksets.
170 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
171 return;
172 }
173
203 // The user moving a child around requires the rebuilding of the linkset compound shape 174 // The user moving a child around requires the rebuilding of the linkset compound shape
204 // One problem is this happens when a border is crossed -- the simulator implementation 175 // One problem is this happens when a border is crossed -- the simulator implementation
205 // stores the position into the group which causes the move of the object 176 // stores the position into the group which causes the move of the object
206 // but it also means all the child positions get updated. 177 // but it also means all the child positions get updated.
207 // What would cause an unnecessary rebuild so we make sure the linkset is in a 178 // What would cause an unnecessary rebuild so we make sure the linkset is in a
208 // region before bothering to do a rebuild. 179 // region before bothering to do a rebuild.
209 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) 180 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
210 { 181 {
211 // If a child of the linkset is updating only the position or rotation, that can be done 182 // If a child of the linkset is updating only the position or rotation, that can be done
212 // without rebuilding the linkset. 183 // without rebuilding the linkset.
@@ -218,22 +189,22 @@ public sealed class BSLinksetCompound : BSLinkset
218 // and that is caused by us updating the object. 189 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) 190 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 { 191 {
221 // Find the physical instance of the child 192 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) 193 if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
223 { 194 {
224 // It is possible that the linkset is still under construction and the child is not yet 195 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will 196 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation. 197 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity 198 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed. 199 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); 200 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
230 if (updated.LinksetChildIndex < numLinksetChildren) 201 if (updated.LinksetChildIndex < numLinksetChildren)
231 { 202 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); 203 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape) 204 if (linksetChildShape.HasPhysicalShape)
234 { 205 {
235 // Found the child shape within the compound shape 206 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, 207 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition, 208 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), 209 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */); 210 true /* shouldRecalculateLocalAabb */);
@@ -275,75 +246,22 @@ public sealed class BSLinksetCompound : BSLinkset
275 } 246 }
276 247
277 // Routine called when rebuilding the body of some member of the linkset. 248 // Routine called when rebuilding the body of some member of the linkset.
278 // Since we don't keep in world relationships, do nothing unless it's a child changing. 249 // If one of the bodies is being changed, the linkset needs rebuilding.
250 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
279 // Returns 'true' of something was actually removed and would need restoring 251 // Returns 'true' of something was actually removed and would need restoring
280 // Called at taint-time!! 252 // Called at taint-time!!
281 public override bool RemoveBodyDependencies(BSPrimLinkable child) 253 public override bool RemoveDependencies(BSPrimLinkable child)
282 { 254 {
283 bool ret = false; 255 bool ret = false;
284 256
285 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 257 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
286 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); 258 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
287 259
288 if (!IsRoot(child)) 260 ScheduleRebuild(child);
289 {
290 // Because it is a convenient time, recompute child world position and rotation based on
291 // its position in the linkset.
292 RecomputeChildWorldPosition(child, true /* inTaintTime */);
293 child.LinksetInfo = null;
294 }
295
296 // Cannot schedule a refresh/rebuild here because this routine is called when
297 // the linkset is being rebuilt.
298 // InternalRefresh(LinksetRoot);
299 261
300 return ret; 262 return ret;
301 } 263 }
302 264
303 // When the linkset is built, the child shape is added to the compound shape relative to the
304 // root shape. The linkset then moves around but this does not move the actual child
305 // prim. The child prim's location must be recomputed based on the location of the root shape.
306 private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
307 {
308 // For the moment (20130201), disable this computation (converting the child physical addr back to
309 // a region address) until we have a good handle on center-of-mass offsets and what the physics
310 // engine moving a child actually means.
311 // The simulator keeps track of where children should be as the linkset moves. Setting
312 // the pos/rot here does not effect that knowledge as there is no good way for the
313 // physics engine to send the simulator an update for a child.
314
315 /*
316 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
317 if (lci != null)
318 {
319 if (inTaintTime)
320 {
321 OMV.Vector3 oldPos = child.RawPosition;
322 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
323 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
324 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
325 child.LocalID, oldPos, lci, child.RawPosition);
326 }
327 else
328 {
329 // TaintedObject is not used here so the raw position is set now and not at taint-time.
330 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
331 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
332 }
333 }
334 else
335 {
336 // This happens when children have been added to the linkset but the linkset
337 // has not been constructed yet. So like, at taint time, adding children to a linkset
338 // and then changing properties of the children (makePhysical, for instance)
339 // but the post-print action of actually rebuilding the linkset has not yet happened.
340 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
341 // LogHeader, child.LocalID);
342 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
343 }
344 */
345 }
346
347 // ================================================================ 265 // ================================================================
348 266
349 // Add a new child to the linkset. 267 // Add a new child to the linkset.
@@ -376,7 +294,6 @@ public sealed class BSLinksetCompound : BSLinkset
376 child.LocalID, child.PhysBody.AddrString); 294 child.LocalID, child.PhysBody.AddrString);
377 295
378 // Cause the child's body to be rebuilt and thus restored to normal operation 296 // Cause the child's body to be rebuilt and thus restored to normal operation
379 RecomputeChildWorldPosition(child, false);
380 child.LinksetInfo = null; 297 child.LinksetInfo = null;
381 child.ForceBodyShapeRebuild(false); 298 child.ForceBodyShapeRebuild(false);
382 299
@@ -399,108 +316,105 @@ public sealed class BSLinksetCompound : BSLinkset
399 // Constraint linksets are rebuilt every time. 316 // Constraint linksets are rebuilt every time.
400 // Note that this works for rebuilding just the root after a linkset is taken apart. 317 // Note that this works for rebuilding just the root after a linkset is taken apart.
401 // Called at taint time!! 318 // Called at taint time!!
402 private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged 319 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
320 private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting
403 private void RecomputeLinksetCompound() 321 private void RecomputeLinksetCompound()
404 { 322 {
405 try 323 try
406 { 324 {
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true; 325 Rebuilding = true;
409 326
410 // Cause the root shape to be rebuilt as a compound object with just the root in it 327 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); 328 // to what they should be as if the root was not in a linkset.
329 // Not that bad since we only get into this routine if there are children in the linkset and
330 // something has been updated/changed.
331 LinksetRoot.ForceBodyShapeRebuild(true);
332
333 // There is no reason to build all this physical stuff for a non-physical linkset.
334 if (!LinksetRoot.IsPhysicallyActive)
335 {
336 // Clean up any old linkset shape and make sure the root shape is set to the root object.
337 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
338
339 return; // Note the 'finally' clause at the botton which will get executed.
340 }
341
342 // Get a new compound shape to build the linkset shape in.
343 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
412 344
413 // The center of mass for the linkset is the geometric center of the group. 345 // The center of mass for the linkset is the geometric center of the group.
414 // Compute a displacement for each component so it is relative to the center-of-mass. 346 // Compute a displacement for each component so it is relative to the center-of-mass.
415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass 347 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition; 348 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
417 if (!disableCOM) // DEBUG DEBUG
418 {
419 // Compute a center-of-mass in world coordinates.
420 centerOfMassW = ComputeLinksetCenterOfMass();
421 }
422 349
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 350 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
424 351
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position 352 // 'centerDisplacement' is the value to subtract from children to give physical offset position
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; 353 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); 354 if (UseBulletSimRootOffsetHack || disableCOM)
428 355 {
429 // This causes the physical position of the root prim to be offset to accomodate for the displacements 356 centerDisplacement = OMV.Vector3.Zero;
430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition; 357 LinksetRoot.ClearDisplacement();
431 358 }
432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM 359 else
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, 360 {
434 -centerDisplacement, 361 LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacement);
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, 362 }
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */); 363 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
437 364 LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacement);
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
440
441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
443 365
444 // Add a shape for each of the other children in the linkset 366 // Add the shapes of all the components of the linkset
445 int memberIndex = 1; 367 int memberIndex = 1;
446 ForEachMember(delegate(BSPrimLinkable cPrim) 368 ForEachMember(delegate(BSPrimLinkable cPrim)
447 { 369 {
448 if (IsRoot(cPrim)) 370 // Root shape is always index zero.
371 cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex;
372
373 // Get a reference to the shape of the child and add that shape to the linkset compound shape
374 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
375 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
376 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
377 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
378 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
379 LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot);
380
381 // Since we are borrowing the shape of the child, disable the origional child body
382 if (!IsRoot(cPrim))
449 { 383 {
450 cPrim.LinksetChildIndex = 0; 384 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
385 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
386 // We don't want collisions from the old linkset children.
387 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
388 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
451 } 389 }
452 else
453 {
454 cPrim.LinksetChildIndex = memberIndex;
455 390
456 if (cPrim.PhysShape.isNativeShape) 391 memberIndex++;
457 {
458 // A native shape is turned into a hull collision shape because native
459 // shapes are not shared so we have to hullify it so it will be tracked
460 // and freed at the correct time. This also solves the scaling problem
461 // (native shapes scale but hull/meshes are assumed to not be).
462 // TODO: decide of the native shape can just be used in the compound shape.
463 // Use call to CreateGeomNonSpecial().
464 BulletShape saveShape = cPrim.PhysShape;
465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
467 BulletShape newShape = cPrim.PhysShape;
468 cPrim.PhysShape = saveShape;
469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
475 }
476 else
477 {
478 // For the shared shapes (meshes and hulls), just use the shape in the child.
479 // The reference count added here will be decremented when the compound shape
480 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
481 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
482 {
483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
485 }
486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
491 392
492 }
493 memberIndex++;
494 }
495 return false; // 'false' says to move onto the next child in the list 393 return false; // 'false' says to move onto the next child in the list
496 }); 394 });
497 395
396 // Replace the root shape with the built compound shape.
397 // Object removed and added to world to get collision cache rebuilt for new shape.
398 LinksetRoot.PhysShape.Dereference(m_physicsScene);
399 LinksetRoot.PhysShape = linksetShape;
400 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
401 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
402 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
403 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
404 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
405
498 // With all of the linkset packed into the root prim, it has the mass of everyone. 406 // With all of the linkset packed into the root prim, it has the mass of everyone.
499 LinksetMass = ComputeLinksetMass(); 407 LinksetMass = ComputeLinksetMass();
500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); 408 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
501 409
502 // Enable the physical position updator to return the position and rotation of the root shape 410 if (UseBulletSimRootOffsetHack)
503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); 411 {
412 // Enable the physical position updator to return the position and rotation of the root shape.
413 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
414 // compound shape. This eleviates the need to offset the returned physical position by the
415 // center-of-mass offset.
416 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
417 }
504 } 418 }
505 finally 419 finally
506 { 420 {
@@ -508,7 +422,7 @@ public sealed class BSLinksetCompound : BSLinkset
508 } 422 }
509 423
510 // See that the Aabb surrounds the new shape 424 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); 425 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
512 } 426 }
513} 427}
514} \ No newline at end of file 428} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index 6d252ca..a06a44d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -51,7 +51,7 @@ public sealed class BSLinksetConstraints : BSLinkset
51 if (HasAnyChildren && IsRoot(requestor)) 51 if (HasAnyChildren && IsRoot(requestor))
52 { 52 {
53 // Queue to happen after all the other taint processing 53 // Queue to happen after all the other taint processing
54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() 54 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 { 55 {
56 if (HasAnyChildren && IsRoot(requestor)) 56 if (HasAnyChildren && IsRoot(requestor))
57 RecomputeLinksetConstraints(); 57 RecomputeLinksetConstraints();
@@ -93,11 +93,11 @@ public sealed class BSLinksetConstraints : BSLinkset
93 // up to rebuild the constraints before the next simulation step. 93 // up to rebuild the constraints before the next simulation step.
94 // Returns 'true' of something was actually removed and would need restoring 94 // Returns 'true' of something was actually removed and would need restoring
95 // Called at taint-time!! 95 // Called at taint-time!!
96 public override bool RemoveBodyDependencies(BSPrimLinkable child) 96 public override bool RemoveDependencies(BSPrimLinkable child)
97 { 97 {
98 bool ret = false; 98 bool ret = false;
99 99
100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 100 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); 101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
102 102
103 lock (m_linksetActivityLock) 103 lock (m_linksetActivityLock)
@@ -142,7 +142,7 @@ public sealed class BSLinksetConstraints : BSLinkset
142 rootx.LocalID, rootx.PhysBody.AddrString, 142 rootx.LocalID, rootx.PhysBody.AddrString,
143 childx.LocalID, childx.PhysBody.AddrString); 143 childx.LocalID, childx.PhysBody.AddrString);
144 144
145 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() 145 m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
146 { 146 {
147 PhysicallyUnlinkAChildFromRoot(rootx, childx); 147 PhysicallyUnlinkAChildFromRoot(rootx, childx);
148 }); 148 });
@@ -187,7 +187,7 @@ public sealed class BSLinksetConstraints : BSLinkset
187 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 187 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
188 188
189 BSConstraint6Dof constrain = new BSConstraint6Dof( 189 BSConstraint6Dof constrain = new BSConstraint6Dof(
190 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); 190 m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
191 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); 191 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
192 192
193 /* NOTE: below is an attempt to build constraint with full frame computation, etc. 193 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
@@ -216,7 +216,7 @@ public sealed class BSLinksetConstraints : BSLinkset
216 // ================================================================================== 216 // ==================================================================================
217 */ 217 */
218 218
219 PhysicsScene.Constraints.AddConstraint(constrain); 219 m_physicsScene.Constraints.AddConstraint(constrain);
220 220
221 // zero linear and angular limits makes the objects unable to move in relation to each other 221 // zero linear and angular limits makes the objects unable to move in relation to each other
222 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 222 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@@ -248,10 +248,10 @@ public sealed class BSLinksetConstraints : BSLinkset
248 childPrim.LocalID, childPrim.PhysBody.AddrString); 248 childPrim.LocalID, childPrim.PhysBody.AddrString);
249 249
250 // Find the constraint for this link and get rid of it from the overall collection and from my list 250 // Find the constraint for this link and get rid of it from the overall collection and from my list
251 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) 251 if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
252 { 252 {
253 // Make the child refresh its location 253 // Make the child refresh its location
254 PhysicsScene.PE.PushUpdate(childPrim.PhysBody); 254 m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
255 ret = true; 255 ret = true;
256 } 256 }
257 257
@@ -265,7 +265,7 @@ public sealed class BSLinksetConstraints : BSLinkset
265 { 265 {
266 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 266 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
267 267
268 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); 268 return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
269 } 269 }
270 270
271 // Call each of the constraints that make up this linkset and recompute the 271 // Call each of the constraints that make up this linkset and recompute the
@@ -289,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset
289 child.UpdatePhysicalMassProperties(linksetMass, true); 289 child.UpdatePhysicalMassProperties(linksetMass, true);
290 290
291 BSConstraint constrain; 291 BSConstraint constrain;
292 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 292 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
293 { 293 {
294 // If constraint doesn't exist yet, create it. 294 // If constraint doesn't exist yet, create it.
295 constrain = BuildConstraint(LinksetRoot, child); 295 constrain = BuildConstraint(LinksetRoot, child);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index 9501e2d..0128d8d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -102,7 +102,7 @@ public class BSVMotor : BSMotor
102 return ErrorIsZero(LastError); 102 return ErrorIsZero(LastError);
103 } 103 }
104 public virtual bool ErrorIsZero(Vector3 err) 104 public virtual bool ErrorIsZero(Vector3 err)
105 { 105 {
106 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); 106 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
107 } 107 }
108 108
@@ -115,7 +115,7 @@ public class BSVMotor : BSMotor
115 CurrentValue = TargetValue = Vector3.Zero; 115 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f; 116 ErrorZeroThreshold = 0.001f;
117 } 117 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
119 : this(useName) 119 : this(useName)
120 { 120 {
121 TimeScale = timeScale; 121 TimeScale = timeScale;
@@ -237,7 +237,7 @@ public class BSVMotor : BSMotor
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); 237 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
238 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", 238 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
239 BSScene.DetailLogZero, UseName, 239 BSScene.DetailLogZero, UseName,
240 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, 240 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
241 CurrentValue, TargetValue); 241 CurrentValue, TargetValue);
242 242
243 LastError = BSMotor.InfiniteVector; 243 LastError = BSMotor.InfiniteVector;
@@ -248,7 +248,7 @@ public class BSVMotor : BSMotor
248 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); 248 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
249 } 249 }
250 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); 250 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
251 251
252 252
253 } 253 }
254 254
@@ -279,7 +279,7 @@ public class BSFMotor : BSMotor
279 return ErrorIsZero(LastError); 279 return ErrorIsZero(LastError);
280 } 280 }
281 public virtual bool ErrorIsZero(float err) 281 public virtual bool ErrorIsZero(float err)
282 { 282 {
283 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); 283 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
284 } 284 }
285 285
@@ -410,7 +410,7 @@ public class BSPIDVMotor : BSVMotor
410 // The factors are vectors for the three dimensions. This is the proportional of each 410 // The factors are vectors for the three dimensions. This is the proportional of each
411 // that is applied. This could be multiplied through the actual factors but it 411 // that is applied. This could be multiplied through the actual factors but it
412 // is sometimes easier to manipulate the factors and their mix separately. 412 // is sometimes easier to manipulate the factors and their mix separately.
413 // to 413 // to
414 public Vector3 FactorMix; 414 public Vector3 FactorMix;
415 415
416 // Arbritrary factor range. 416 // Arbritrary factor range.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 980d405..2ac68e3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -37,7 +37,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
37{ 37{
38public static class BSParam 38public static class BSParam
39{ 39{
40 private static string LogHeader = "[BULLETSIM PARAMETERS]"; 40 private static string LogHeader = "[BULLETSIM PARAMETERS]";
41 41
42 // Tuning notes: 42 // Tuning notes:
43 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 43 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
@@ -51,7 +51,7 @@ public static class BSParam
51 // This is separate/independent from the collision margin. The collision margin increases the object a bit 51 // This is separate/independent from the collision margin. The collision margin increases the object a bit
52 // to improve collision detection performance and accuracy. 52 // to improve collision detection performance and accuracy.
53 // =================== 53 // ===================
54 // From: 54 // From:
55 55
56 // Level of Detail values kept as float because that's what the Meshmerizer wants 56 // Level of Detail values kept as float because that's what the Meshmerizer wants
57 public static float MeshLOD { get; private set; } 57 public static float MeshLOD { get; private set; }
@@ -87,6 +87,7 @@ public static class BSParam
87 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects 87 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
88 public static bool ShouldRemoveZeroWidthTriangles { get; private set; } 88 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
89 public static bool ShouldUseBulletHACD { get; set; } 89 public static bool ShouldUseBulletHACD { get; set; }
90 public static bool ShouldUseSingleConvexHullForPrims { get; set; }
90 91
91 public static float TerrainImplementation { get; private set; } 92 public static float TerrainImplementation { get; private set; }
92 public static int TerrainMeshMagnification { get; private set; } 93 public static int TerrainMeshMagnification { get; private set; }
@@ -342,6 +343,10 @@ public static class BSParam
342 false, 343 false,
343 (s) => { return ShouldUseBulletHACD; }, 344 (s) => { return ShouldUseBulletHACD; },
344 (s,v) => { ShouldUseBulletHACD = v; } ), 345 (s,v) => { ShouldUseBulletHACD = v; } ),
346 new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims",
347 true,
348 (s) => { return ShouldUseSingleConvexHullForPrims; },
349 (s,v) => { ShouldUseSingleConvexHullForPrims = v; } ),
345 350
346 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 351 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
347 5, 352 5,
@@ -636,7 +641,7 @@ public static class BSParam
636 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", 641 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
637 false, 642 false,
638 (s) => { return ShouldDisableContactPoolDynamicAllocation; }, 643 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
639 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; 644 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
640 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), 645 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
641 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", 646 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
642 false, 647 false,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 309d004..e796804 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -38,7 +38,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
38 * Class to wrap all objects. 38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims 39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant. 40 * unless the difference is significant.
41 * 41 *
42 * Variables in the physicsl objects are in three forms: 42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc 43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value 44 * RawVariableName: direct reference to the BulletSim storage for the variable value
@@ -52,7 +52,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce 52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse 53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v 54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque 55 * BS.ApplyCentralForce BS.ApplyTorque
56 */ 56 */
57 57
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. 58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
@@ -72,14 +72,14 @@ public abstract class BSPhysObject : PhysicsActor
72 } 72 }
73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) 73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
74 { 74 {
75 PhysicsScene = parentScene; 75 PhysScene = parentScene;
76 LocalID = localID; 76 LocalID = localID;
77 PhysObjectName = name; 77 PhysObjectName = name;
78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate. 78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
79 TypeName = typeName; 79 TypeName = typeName;
80 80
81 // The collection of things that push me around 81 // The collection of things that push me around
82 PhysicalActors = new BSActorCollection(PhysicsScene); 82 PhysicalActors = new BSActorCollection(PhysScene);
83 83
84 // Initialize variables kept in base. 84 // Initialize variables kept in base.
85 GravModifier = 1.0f; 85 GravModifier = 1.0f;
@@ -88,7 +88,7 @@ public abstract class BSPhysObject : PhysicsActor
88 88
89 // We don't have any physical representation yet. 89 // We don't have any physical representation yet.
90 PhysBody = new BulletBody(localID); 90 PhysBody = new BulletBody(localID);
91 PhysShape = new BulletShape(); 91 PhysShape = new BSShapeNull();
92 92
93 PrimAssetState = PrimAssetCondition.Unknown; 93 PrimAssetState = PrimAssetCondition.Unknown;
94 94
@@ -97,6 +97,9 @@ public abstract class BSPhysObject : PhysicsActor
97 97
98 CollisionCollection = new CollisionEventUpdate(); 98 CollisionCollection = new CollisionEventUpdate();
99 CollisionsLastReported = CollisionCollection; 99 CollisionsLastReported = CollisionCollection;
100 CollisionsLastTick = new CollisionEventUpdate();
101 CollisionsLastTickStep = -1;
102
100 SubscribedEventsMs = 0; 103 SubscribedEventsMs = 0;
101 CollidingStep = 0; 104 CollidingStep = 0;
102 CollidingGroundStep = 0; 105 CollidingGroundStep = 0;
@@ -112,13 +115,13 @@ public abstract class BSPhysObject : PhysicsActor
112 public virtual void Destroy() 115 public virtual void Destroy()
113 { 116 {
114 PhysicalActors.Enable(false); 117 PhysicalActors.Enable(false);
115 PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate() 118 PhysScene.TaintedObject("BSPhysObject.Destroy", delegate()
116 { 119 {
117 PhysicalActors.Dispose(); 120 PhysicalActors.Dispose();
118 }); 121 });
119 } 122 }
120 123
121 public BSScene PhysicsScene { get; protected set; } 124 public BSScene PhysScene { get; protected set; }
122 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor 125 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
123 public string PhysObjectName { get; protected set; } 126 public string PhysObjectName { get; protected set; }
124 public string TypeName { get; protected set; } 127 public string TypeName { get; protected set; }
@@ -138,7 +141,7 @@ public abstract class BSPhysObject : PhysicsActor
138 // Reference to the physical body (btCollisionObject) of this object 141 // Reference to the physical body (btCollisionObject) of this object
139 public BulletBody PhysBody; 142 public BulletBody PhysBody;
140 // Reference to the physical shape (btCollisionShape) of this object 143 // Reference to the physical shape (btCollisionShape) of this object
141 public BulletShape PhysShape; 144 public BSShape PhysShape;
142 145
143 // The physical representation of the prim might require an asset fetch. 146 // The physical representation of the prim might require an asset fetch.
144 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. 147 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
@@ -151,13 +154,6 @@ public abstract class BSPhysObject : PhysicsActor
151 // The objects base shape information. Null if not a prim type shape. 154 // The objects base shape information. Null if not a prim type shape.
152 public PrimitiveBaseShape BaseShape { get; protected set; } 155 public PrimitiveBaseShape BaseShape { get; protected set; }
153 156
154 // Some types of objects have preferred physical representations.
155 // Returns SHAPE_UNKNOWN if there is no preference.
156 public virtual BSPhysicsShapeType PreferredPhysicalShape
157 {
158 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
159 }
160
161 // When the physical properties are updated, an EntityProperty holds the update values. 157 // When the physical properties are updated, an EntityProperty holds the update values.
162 // Keep the current and last EntityProperties to enable computation of differences 158 // Keep the current and last EntityProperties to enable computation of differences
163 // between the current update and the previous values. 159 // between the current update and the previous values.
@@ -266,7 +262,8 @@ public abstract class BSPhysObject : PhysicsActor
266 262
267 // The user can optionally set the center of mass. The user's setting will override any 263 // The user can optionally set the center of mass. The user's setting will override any
268 // computed center-of-mass (like in linksets). 264 // computed center-of-mass (like in linksets).
269 public OMV.Vector3? UserSetCenterOfMass { get; set; } 265 // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
266 public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
270 267
271 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. 268 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
272 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free 269 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
@@ -277,7 +274,7 @@ public abstract class BSPhysObject : PhysicsActor
277 public void ActivateIfPhysical(bool forceIt) 274 public void ActivateIfPhysical(bool forceIt)
278 { 275 {
279 if (IsPhysical && PhysBody.HasPhysicalBody) 276 if (IsPhysical && PhysBody.HasPhysicalBody)
280 PhysicsScene.PE.Activate(PhysBody, forceIt); 277 PhysScene.PE.Activate(PhysBody, forceIt);
281 } 278 }
282 279
283 // 'actors' act on the physical object to change or constrain its motion. These can range from 280 // 'actors' act on the physical object to change or constrain its motion. These can range from
@@ -340,29 +337,29 @@ public abstract class BSPhysObject : PhysicsActor
340 protected long CollisionAccumulation { get; set; } 337 protected long CollisionAccumulation { get; set; }
341 338
342 public override bool IsColliding { 339 public override bool IsColliding {
343 get { return (CollidingStep == PhysicsScene.SimulationStep); } 340 get { return (CollidingStep == PhysScene.SimulationStep); }
344 set { 341 set {
345 if (value) 342 if (value)
346 CollidingStep = PhysicsScene.SimulationStep; 343 CollidingStep = PhysScene.SimulationStep;
347 else 344 else
348 CollidingStep = 0; 345 CollidingStep = 0;
349 } 346 }
350 } 347 }
351 public override bool CollidingGround { 348 public override bool CollidingGround {
352 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } 349 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
353 set 350 set
354 { 351 {
355 if (value) 352 if (value)
356 CollidingGroundStep = PhysicsScene.SimulationStep; 353 CollidingGroundStep = PhysScene.SimulationStep;
357 else 354 else
358 CollidingGroundStep = 0; 355 CollidingGroundStep = 0;
359 } 356 }
360 } 357 }
361 public override bool CollidingObj { 358 public override bool CollidingObj {
362 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } 359 get { return (CollidingObjectStep == PhysScene.SimulationStep); }
363 set { 360 set {
364 if (value) 361 if (value)
365 CollidingObjectStep = PhysicsScene.SimulationStep; 362 CollidingObjectStep = PhysScene.SimulationStep;
366 else 363 else
367 CollidingObjectStep = 0; 364 CollidingObjectStep = 0;
368 } 365 }
@@ -387,14 +384,14 @@ public abstract class BSPhysObject : PhysicsActor
387 bool ret = false; 384 bool ret = false;
388 385
389 // The following lines make IsColliding(), CollidingGround() and CollidingObj work 386 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
390 CollidingStep = PhysicsScene.SimulationStep; 387 CollidingStep = PhysScene.SimulationStep;
391 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 388 if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
392 { 389 {
393 CollidingGroundStep = PhysicsScene.SimulationStep; 390 CollidingGroundStep = PhysScene.SimulationStep;
394 } 391 }
395 else 392 else
396 { 393 {
397 CollidingObjectStep = PhysicsScene.SimulationStep; 394 CollidingObjectStep = PhysScene.SimulationStep;
398 } 395 }
399 396
400 CollisionAccumulation++; 397 CollisionAccumulation++;
@@ -404,10 +401,10 @@ public abstract class BSPhysObject : PhysicsActor
404 401
405 // Make a collection of the collisions that happened the last simulation tick. 402 // Make a collection of the collisions that happened the last simulation tick.
406 // This is different than the collection created for sending up to the simulator as it is cleared every tick. 403 // This is different than the collection created for sending up to the simulator as it is cleared every tick.
407 if (CollisionsLastTickStep != PhysicsScene.SimulationStep) 404 if (CollisionsLastTickStep != PhysScene.SimulationStep)
408 { 405 {
409 CollisionsLastTick = new CollisionEventUpdate(); 406 CollisionsLastTick = new CollisionEventUpdate();
410 CollisionsLastTickStep = PhysicsScene.SimulationStep; 407 CollisionsLastTickStep = PhysScene.SimulationStep;
411 } 408 }
412 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 409 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
413 410
@@ -434,9 +431,9 @@ public abstract class BSPhysObject : PhysicsActor
434 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); 431 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
435 432
436 // throttle the collisions to the number of milliseconds specified in the subscription 433 // throttle the collisions to the number of milliseconds specified in the subscription
437 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 434 if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
438 { 435 {
439 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; 436 NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
440 437
441 // We are called if we previously had collisions. If there are no collisions 438 // We are called if we previously had collisions. If there are no collisions
442 // this time, send up one last empty event so OpenSim can sense collision end. 439 // this time, send up one last empty event so OpenSim can sense collision end.
@@ -454,7 +451,7 @@ public abstract class BSPhysObject : PhysicsActor
454 451
455 // The CollisionCollection instance is passed around in the simulator. 452 // The CollisionCollection instance is passed around in the simulator.
456 // Make sure we don't have a handle to that one and that a new one is used for next time. 453 // Make sure we don't have a handle to that one and that a new one is used for next time.
457 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, 454 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
458 // a race condition is created for the other users of this instance. 455 // a race condition is created for the other users of this instance.
459 CollisionCollection = new CollisionEventUpdate(); 456 CollisionCollection = new CollisionEventUpdate();
460 } 457 }
@@ -471,10 +468,10 @@ public abstract class BSPhysObject : PhysicsActor
471 // make sure first collision happens 468 // make sure first collision happens
472 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); 469 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
473 470
474 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 471 PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
475 { 472 {
476 if (PhysBody.HasPhysicalBody) 473 if (PhysBody.HasPhysicalBody)
477 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 474 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
478 }); 475 });
479 } 476 }
480 else 477 else
@@ -486,11 +483,11 @@ public abstract class BSPhysObject : PhysicsActor
486 public override void UnSubscribeEvents() { 483 public override void UnSubscribeEvents() {
487 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); 484 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
488 SubscribedEventsMs = 0; 485 SubscribedEventsMs = 0;
489 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 486 PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
490 { 487 {
491 // Make sure there is a body there because sometimes destruction happens in an un-ideal order. 488 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
492 if (PhysBody.HasPhysicalBody) 489 if (PhysBody.HasPhysicalBody)
493 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 490 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
494 }); 491 });
495 } 492 }
496 // Return 'true' if the simulator wants collision events 493 // Return 'true' if the simulator wants collision events
@@ -504,7 +501,7 @@ public abstract class BSPhysObject : PhysicsActor
504 { 501 {
505 // Scale the collision count by the time since the last collision. 502 // Scale the collision count by the time since the last collision.
506 // The "+1" prevents dividing by zero. 503 // The "+1" prevents dividing by zero.
507 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; 504 long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
508 CollisionScore = CollisionAccumulation / timeAgo; 505 CollisionScore = CollisionAccumulation / timeAgo;
509 } 506 }
510 public override float CollisionScore { get; set; } 507 public override float CollisionScore { get; set; }
@@ -531,8 +528,8 @@ public abstract class BSPhysObject : PhysicsActor
531 // High performance detailed logging routine used by the physical objects. 528 // High performance detailed logging routine used by the physical objects.
532 protected void DetailLog(string msg, params Object[] args) 529 protected void DetailLog(string msg, params Object[] args)
533 { 530 {
534 if (PhysicsScene.PhysicsLogging.Enabled) 531 if (PhysScene.PhysicsLogging.Enabled)
535 PhysicsScene.DetailLog(msg, args); 532 PhysScene.DetailLog(msg, args);
536 } 533 }
537 534
538} 535}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 4bc266b..d3f3475 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -101,21 +101,21 @@ public class BSPrim : BSPhysObject
101 _isVolumeDetect = false; 101 _isVolumeDetect = false;
102 102
103 // We keep a handle to the vehicle actor so we can set vehicle parameters later. 103 // We keep a handle to the vehicle actor so we can set vehicle parameters later.
104 VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); 104 VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName);
105 PhysicalActors.Add(VehicleActorName, VehicleActor); 105 PhysicalActors.Add(VehicleActorName, VehicleActor);
106 106
107 _mass = CalculateMass(); 107 _mass = CalculateMass();
108 108
109 // DetailLog("{0},BSPrim.constructor,call", LocalID); 109 // DetailLog("{0},BSPrim.constructor,call", LocalID);
110 // do the actual object creation at taint time 110 // do the actual object creation at taint time
111 PhysicsScene.TaintedObject("BSPrim.create", delegate() 111 PhysScene.TaintedObject("BSPrim.create", delegate()
112 { 112 {
113 // Make sure the object is being created with some sanity. 113 // Make sure the object is being created with some sanity.
114 ExtremeSanityCheck(true /* inTaintTime */); 114 ExtremeSanityCheck(true /* inTaintTime */);
115 115
116 CreateGeomAndObject(true); 116 CreateGeomAndObject(true);
117 117
118 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); 118 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
119 }); 119 });
120 } 120 }
121 121
@@ -128,14 +128,14 @@ public class BSPrim : BSPhysObject
128 // Undo any vehicle properties 128 // Undo any vehicle properties
129 this.VehicleType = (int)Vehicle.TYPE_NONE; 129 this.VehicleType = (int)Vehicle.TYPE_NONE;
130 130
131 PhysicsScene.TaintedObject("BSPrim.Destroy", delegate() 131 PhysScene.TaintedObject("BSPrim.Destroy", delegate()
132 { 132 {
133 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 133 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
134 // If there are physical body and shape, release my use of same. 134 // If there are physical body and shape, release my use of same.
135 PhysicsScene.Shapes.DereferenceBody(PhysBody, null); 135 PhysScene.Shapes.DereferenceBody(PhysBody, null);
136 PhysBody.Clear(); 136 PhysBody.Clear();
137 PhysicsScene.Shapes.DereferenceShape(PhysShape, null); 137 PhysShape.Dereference(PhysScene);
138 PhysShape.Clear(); 138 PhysShape = new BSShapeNull();
139 }); 139 });
140 } 140 }
141 141
@@ -161,25 +161,13 @@ public class BSPrim : BSPhysObject
161 ForceBodyShapeRebuild(false); 161 ForceBodyShapeRebuild(false);
162 } 162 }
163 } 163 }
164 // 'unknown' says to choose the best type
165 public override BSPhysicsShapeType PreferredPhysicalShape
166 { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
167
168 public override bool ForceBodyShapeRebuild(bool inTaintTime) 164 public override bool ForceBodyShapeRebuild(bool inTaintTime)
169 { 165 {
170 if (inTaintTime) 166 PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
171 { 167 {
172 _mass = CalculateMass(); // changing the shape changes the mass 168 _mass = CalculateMass(); // changing the shape changes the mass
173 CreateGeomAndObject(true); 169 CreateGeomAndObject(true);
174 } 170 });
175 else
176 {
177 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
178 {
179 _mass = CalculateMass(); // changing the shape changes the mass
180 CreateGeomAndObject(true);
181 });
182 }
183 return true; 171 return true;
184 } 172 }
185 public override bool Grabbed { 173 public override bool Grabbed {
@@ -192,7 +180,7 @@ public class BSPrim : BSPhysObject
192 if (value != _isSelected) 180 if (value != _isSelected)
193 { 181 {
194 _isSelected = value; 182 _isSelected = value;
195 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 183 PhysScene.TaintedObject("BSPrim.setSelected", delegate()
196 { 184 {
197 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 185 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
198 SetObjectDynamic(false); 186 SetObjectDynamic(false);
@@ -238,23 +226,23 @@ public class BSPrim : BSPhysObject
238 _rotationalVelocity = OMV.Vector3.Zero; 226 _rotationalVelocity = OMV.Vector3.Zero;
239 227
240 // Zero some other properties in the physics engine 228 // Zero some other properties in the physics engine
241 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 229 PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
242 { 230 {
243 if (PhysBody.HasPhysicalBody) 231 if (PhysBody.HasPhysicalBody)
244 PhysicsScene.PE.ClearAllForces(PhysBody); 232 PhysScene.PE.ClearAllForces(PhysBody);
245 }); 233 });
246 } 234 }
247 public override void ZeroAngularMotion(bool inTaintTime) 235 public override void ZeroAngularMotion(bool inTaintTime)
248 { 236 {
249 _rotationalVelocity = OMV.Vector3.Zero; 237 _rotationalVelocity = OMV.Vector3.Zero;
250 // Zero some other properties in the physics engine 238 // Zero some other properties in the physics engine
251 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 239 PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
252 { 240 {
253 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); 241 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
254 if (PhysBody.HasPhysicalBody) 242 if (PhysBody.HasPhysicalBody)
255 { 243 {
256 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 244 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
257 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 245 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
258 } 246 }
259 }); 247 });
260 } 248 }
@@ -272,11 +260,11 @@ public class BSPrim : BSPhysObject
272 260
273 EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, delegate() 261 EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, delegate()
274 { 262 {
275 return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName); 263 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
276 }); 264 });
277 265
278 // Update parameters so the new actor's Refresh() action is called at the right time. 266 // Update parameters so the new actor's Refresh() action is called at the right time.
279 PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() 267 PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
280 { 268 {
281 UpdatePhysicalParameters(); 269 UpdatePhysicalParameters();
282 }); 270 });
@@ -306,7 +294,7 @@ public class BSPrim : BSPhysObject
306 _position = value; 294 _position = value;
307 PositionSanityCheck(false); 295 PositionSanityCheck(false);
308 296
309 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 297 PhysScene.TaintedObject("BSPrim.setPosition", delegate()
310 { 298 {
311 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 299 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
312 ForcePosition = _position; 300 ForcePosition = _position;
@@ -316,14 +304,14 @@ public class BSPrim : BSPhysObject
316 304
317 public override OMV.Vector3 ForcePosition { 305 public override OMV.Vector3 ForcePosition {
318 get { 306 get {
319 _position = PhysicsScene.PE.GetPosition(PhysBody); 307 _position = PhysScene.PE.GetPosition(PhysBody);
320 return _position; 308 return _position;
321 } 309 }
322 set { 310 set {
323 _position = value; 311 _position = value;
324 if (PhysBody.HasPhysicalBody) 312 if (PhysBody.HasPhysicalBody)
325 { 313 {
326 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 314 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
327 ActivateIfPhysical(false); 315 ActivateIfPhysical(false);
328 } 316 }
329 } 317 }
@@ -340,7 +328,7 @@ public class BSPrim : BSPhysObject
340 if (!IsPhysicallyActive) 328 if (!IsPhysicallyActive)
341 return ret; 329 return ret;
342 330
343 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 331 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
344 { 332 {
345 // The physical object is out of the known/simulated area. 333 // The physical object is out of the known/simulated area.
346 // Upper levels of code will handle the transition to other areas so, for 334 // Upper levels of code will handle the transition to other areas so, for
@@ -348,7 +336,7 @@ public class BSPrim : BSPhysObject
348 return ret; 336 return ret;
349 } 337 }
350 338
351 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 339 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
352 OMV.Vector3 upForce = OMV.Vector3.Zero; 340 OMV.Vector3 upForce = OMV.Vector3.Zero;
353 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); 341 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
354 if ((RawPosition.Z + approxSize / 2f) < terrainHeight) 342 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
@@ -369,7 +357,7 @@ public class BSPrim : BSPhysObject
369 357
370 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 358 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
371 { 359 {
372 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 360 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position);
373 // TODO: a floating motor so object will bob in the water 361 // TODO: a floating motor so object will bob in the water
374 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) 362 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
375 { 363 {
@@ -377,7 +365,7 @@ public class BSPrim : BSPhysObject
377 upForce.Z = (waterHeight - RawPosition.Z) * 1f; 365 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
378 366
379 // Apply upforce and overcome gravity. 367 // Apply upforce and overcome gravity.
380 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; 368 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
381 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); 369 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
382 AddForce(correctionForce, false, inTaintTime); 370 AddForce(correctionForce, false, inTaintTime);
383 ret = true; 371 ret = true;
@@ -432,7 +420,7 @@ public class BSPrim : BSPhysObject
432 get { return _mass; } 420 get { return _mass; }
433 } 421 }
434 // used when we only want this prim's mass and not the linkset thing 422 // used when we only want this prim's mass and not the linkset thing
435 public override float RawMass { 423 public override float RawMass {
436 get { return _mass; } 424 get { return _mass; }
437 } 425 }
438 // Set the physical mass to the passed mass. 426 // Set the physical mass to the passed mass.
@@ -443,10 +431,10 @@ public class BSPrim : BSPhysObject
443 { 431 {
444 if (IsStatic) 432 if (IsStatic)
445 { 433 {
446 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); 434 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
447 Inertia = OMV.Vector3.Zero; 435 Inertia = OMV.Vector3.Zero;
448 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); 436 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
449 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 437 PhysScene.PE.UpdateInertiaTensor(PhysBody);
450 } 438 }
451 else 439 else
452 { 440 {
@@ -455,16 +443,16 @@ public class BSPrim : BSPhysObject
455 // Changing interesting properties doesn't change proxy and collision cache 443 // Changing interesting properties doesn't change proxy and collision cache
456 // information. The Bullet solution is to re-add the object to the world 444 // information. The Bullet solution is to re-add the object to the world
457 // after parameters are changed. 445 // after parameters are changed.
458 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 446 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
459 } 447 }
460 448
461 // The computation of mass props requires gravity to be set on the object. 449 // The computation of mass props requires gravity to be set on the object.
462 Gravity = ComputeGravity(Buoyancy); 450 Gravity = ComputeGravity(Buoyancy);
463 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 451 PhysScene.PE.SetGravity(PhysBody, Gravity);
464 452
465 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 453 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
466 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); 454 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
467 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 455 PhysScene.PE.UpdateInertiaTensor(PhysBody);
468 456
469 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", 457 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
470 LocalID, physMass, Inertia, Gravity, inWorld); 458 LocalID, physMass, Inertia, Gravity, inWorld);
@@ -480,7 +468,7 @@ public class BSPrim : BSPhysObject
480 // Return what gravity should be set to this very moment 468 // Return what gravity should be set to this very moment
481 public OMV.Vector3 ComputeGravity(float buoyancy) 469 public OMV.Vector3 ComputeGravity(float buoyancy)
482 { 470 {
483 OMV.Vector3 ret = PhysicsScene.DefaultGravity; 471 OMV.Vector3 ret = PhysScene.DefaultGravity;
484 472
485 if (!IsStatic) 473 if (!IsStatic)
486 { 474 {
@@ -509,7 +497,7 @@ public class BSPrim : BSPhysObject
509 RawForce = value; 497 RawForce = value;
510 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() 498 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
511 { 499 {
512 return new BSActorSetForce(PhysicsScene, this, SetForceActorName); 500 return new BSActorSetForce(PhysScene, this, SetForceActorName);
513 }); 501 });
514 } 502 }
515 } 503 }
@@ -521,9 +509,9 @@ public class BSPrim : BSPhysObject
521 set { 509 set {
522 Vehicle type = (Vehicle)value; 510 Vehicle type = (Vehicle)value;
523 511
524 PhysicsScene.TaintedObject("setVehicleType", delegate() 512 PhysScene.TaintedObject("setVehicleType", delegate()
525 { 513 {
526 // Vehicle code changes the parameters for this vehicle type. 514 ZeroMotion(true /* inTaintTime */);
527 VehicleActor.ProcessTypeChange(type); 515 VehicleActor.ProcessTypeChange(type);
528 ActivateIfPhysical(false); 516 ActivateIfPhysical(false);
529 }); 517 });
@@ -531,7 +519,7 @@ public class BSPrim : BSPhysObject
531 } 519 }
532 public override void VehicleFloatParam(int param, float value) 520 public override void VehicleFloatParam(int param, float value)
533 { 521 {
534 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 522 PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
535 { 523 {
536 VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); 524 VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
537 ActivateIfPhysical(false); 525 ActivateIfPhysical(false);
@@ -539,7 +527,7 @@ public class BSPrim : BSPhysObject
539 } 527 }
540 public override void VehicleVectorParam(int param, OMV.Vector3 value) 528 public override void VehicleVectorParam(int param, OMV.Vector3 value)
541 { 529 {
542 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 530 PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
543 { 531 {
544 VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); 532 VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
545 ActivateIfPhysical(false); 533 ActivateIfPhysical(false);
@@ -547,7 +535,7 @@ public class BSPrim : BSPhysObject
547 } 535 }
548 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 536 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
549 { 537 {
550 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 538 PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
551 { 539 {
552 VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); 540 VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
553 ActivateIfPhysical(false); 541 ActivateIfPhysical(false);
@@ -555,7 +543,7 @@ public class BSPrim : BSPhysObject
555 } 543 }
556 public override void VehicleFlags(int param, bool remove) 544 public override void VehicleFlags(int param, bool remove)
557 { 545 {
558 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 546 PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate()
559 { 547 {
560 VehicleActor.ProcessVehicleFlags(param, remove); 548 VehicleActor.ProcessVehicleFlags(param, remove);
561 }); 549 });
@@ -567,7 +555,7 @@ public class BSPrim : BSPhysObject
567 if (_isVolumeDetect != newValue) 555 if (_isVolumeDetect != newValue)
568 { 556 {
569 _isVolumeDetect = newValue; 557 _isVolumeDetect = newValue;
570 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() 558 PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
571 { 559 {
572 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); 560 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
573 SetObjectDynamic(true); 561 SetObjectDynamic(true);
@@ -578,7 +566,7 @@ public class BSPrim : BSPhysObject
578 public override void SetMaterial(int material) 566 public override void SetMaterial(int material)
579 { 567 {
580 base.SetMaterial(material); 568 base.SetMaterial(material);
581 PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() 569 PhysScene.TaintedObject("BSPrim.SetMaterial", delegate()
582 { 570 {
583 UpdatePhysicalParameters(); 571 UpdatePhysicalParameters();
584 }); 572 });
@@ -591,7 +579,7 @@ public class BSPrim : BSPhysObject
591 if (base.Friction != value) 579 if (base.Friction != value)
592 { 580 {
593 base.Friction = value; 581 base.Friction = value;
594 PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() 582 PhysScene.TaintedObject("BSPrim.setFriction", delegate()
595 { 583 {
596 UpdatePhysicalParameters(); 584 UpdatePhysicalParameters();
597 }); 585 });
@@ -606,7 +594,7 @@ public class BSPrim : BSPhysObject
606 if (base.Restitution != value) 594 if (base.Restitution != value)
607 { 595 {
608 base.Restitution = value; 596 base.Restitution = value;
609 PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() 597 PhysScene.TaintedObject("BSPrim.setRestitution", delegate()
610 { 598 {
611 UpdatePhysicalParameters(); 599 UpdatePhysicalParameters();
612 }); 600 });
@@ -623,7 +611,7 @@ public class BSPrim : BSPhysObject
623 if (base.Density != value) 611 if (base.Density != value)
624 { 612 {
625 base.Density = value; 613 base.Density = value;
626 PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() 614 PhysScene.TaintedObject("BSPrim.setDensity", delegate()
627 { 615 {
628 UpdatePhysicalParameters(); 616 UpdatePhysicalParameters();
629 }); 617 });
@@ -638,7 +626,7 @@ public class BSPrim : BSPhysObject
638 if (base.GravModifier != value) 626 if (base.GravModifier != value)
639 { 627 {
640 base.GravModifier = value; 628 base.GravModifier = value;
641 PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() 629 PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate()
642 { 630 {
643 UpdatePhysicalParameters(); 631 UpdatePhysicalParameters();
644 }); 632 });
@@ -649,7 +637,7 @@ public class BSPrim : BSPhysObject
649 get { return RawVelocity; } 637 get { return RawVelocity; }
650 set { 638 set {
651 RawVelocity = value; 639 RawVelocity = value;
652 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 640 PhysScene.TaintedObject("BSPrim.setVelocity", delegate()
653 { 641 {
654 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); 642 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
655 ForceVelocity = RawVelocity; 643 ForceVelocity = RawVelocity;
@@ -659,13 +647,13 @@ public class BSPrim : BSPhysObject
659 public override OMV.Vector3 ForceVelocity { 647 public override OMV.Vector3 ForceVelocity {
660 get { return RawVelocity; } 648 get { return RawVelocity; }
661 set { 649 set {
662 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); 650 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
663 651
664 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); 652 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
665 if (PhysBody.HasPhysicalBody) 653 if (PhysBody.HasPhysicalBody)
666 { 654 {
667 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); 655 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
668 PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); 656 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
669 ActivateIfPhysical(false); 657 ActivateIfPhysical(false);
670 } 658 }
671 } 659 }
@@ -676,7 +664,7 @@ public class BSPrim : BSPhysObject
676 RawTorque = value; 664 RawTorque = value;
677 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() 665 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
678 { 666 {
679 return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName); 667 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
680 }); 668 });
681 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); 669 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
682 } 670 }
@@ -699,7 +687,7 @@ public class BSPrim : BSPhysObject
699 return; 687 return;
700 _orientation = value; 688 _orientation = value;
701 689
702 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 690 PhysScene.TaintedObject("BSPrim.setOrientation", delegate()
703 { 691 {
704 ForceOrientation = _orientation; 692 ForceOrientation = _orientation;
705 }); 693 });
@@ -710,14 +698,14 @@ public class BSPrim : BSPhysObject
710 { 698 {
711 get 699 get
712 { 700 {
713 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 701 _orientation = PhysScene.PE.GetOrientation(PhysBody);
714 return _orientation; 702 return _orientation;
715 } 703 }
716 set 704 set
717 { 705 {
718 _orientation = value; 706 _orientation = value;
719 if (PhysBody.HasPhysicalBody) 707 if (PhysBody.HasPhysicalBody)
720 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 708 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
721 } 709 }
722 } 710 }
723 public override int PhysicsActorType { 711 public override int PhysicsActorType {
@@ -730,7 +718,7 @@ public class BSPrim : BSPhysObject
730 if (_isPhysical != value) 718 if (_isPhysical != value)
731 { 719 {
732 _isPhysical = value; 720 _isPhysical = value;
733 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 721 PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate()
734 { 722 {
735 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 723 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
736 SetObjectDynamic(true); 724 SetObjectDynamic(true);
@@ -779,13 +767,13 @@ public class BSPrim : BSPhysObject
779 if (!PhysBody.HasPhysicalBody) 767 if (!PhysBody.HasPhysicalBody)
780 { 768 {
781 // This would only happen if updates are called for during initialization when the body is not set up yet. 769 // This would only happen if updates are called for during initialization when the body is not set up yet.
782 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); 770 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
783 return; 771 return;
784 } 772 }
785 773
786 // Mangling all the physical properties requires the object not be in the physical world. 774 // Mangling all the physical properties requires the object not be in the physical world.
787 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 775 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
788 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 776 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
789 777
790 // Set up the object physicalness (does gravity and collisions move this object) 778 // Set up the object physicalness (does gravity and collisions move this object)
791 MakeDynamic(IsStatic); 779 MakeDynamic(IsStatic);
@@ -802,10 +790,11 @@ public class BSPrim : BSPhysObject
802 AddObjectToPhysicalWorld(); 790 AddObjectToPhysicalWorld();
803 791
804 // Rebuild its shape 792 // Rebuild its shape
805 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 793 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
806 794
807 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", 795 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
808 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); 796 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
797 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
809 } 798 }
810 799
811 // "Making dynamic" means changing to and from static. 800 // "Making dynamic" means changing to and from static.
@@ -818,28 +807,28 @@ public class BSPrim : BSPhysObject
818 if (makeStatic) 807 if (makeStatic)
819 { 808 {
820 // Become a Bullet 'static' object type 809 // Become a Bullet 'static' object type
821 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 810 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
822 // Stop all movement 811 // Stop all movement
823 ZeroMotion(true); 812 ZeroMotion(true);
824 813
825 // Set various physical properties so other object interact properly 814 // Set various physical properties so other object interact properly
826 PhysicsScene.PE.SetFriction(PhysBody, Friction); 815 PhysScene.PE.SetFriction(PhysBody, Friction);
827 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 816 PhysScene.PE.SetRestitution(PhysBody, Restitution);
828 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 817 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
829 818
830 // Mass is zero which disables a bunch of physics stuff in Bullet 819 // Mass is zero which disables a bunch of physics stuff in Bullet
831 UpdatePhysicalMassProperties(0f, false); 820 UpdatePhysicalMassProperties(0f, false);
832 // Set collision detection parameters 821 // Set collision detection parameters
833 if (BSParam.CcdMotionThreshold > 0f) 822 if (BSParam.CcdMotionThreshold > 0f)
834 { 823 {
835 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 824 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
836 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 825 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
837 } 826 }
838 827
839 // The activation state is 'disabled' so Bullet will not try to act on it. 828 // The activation state is 'disabled' so Bullet will not try to act on it.
840 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); 829 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
841 // Start it out sleeping and physical actions could wake it up. 830 // Start it out sleeping and physical actions could wake it up.
842 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); 831 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
843 832
844 // This collides like a static object 833 // This collides like a static object
845 PhysBody.collisionType = CollisionType.Static; 834 PhysBody.collisionType = CollisionType.Static;
@@ -847,11 +836,11 @@ public class BSPrim : BSPhysObject
847 else 836 else
848 { 837 {
849 // Not a Bullet static object 838 // Not a Bullet static object
850 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 839 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
851 840
852 // Set various physical properties so other object interact properly 841 // Set various physical properties so other object interact properly
853 PhysicsScene.PE.SetFriction(PhysBody, Friction); 842 PhysScene.PE.SetFriction(PhysBody, Friction);
854 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 843 PhysScene.PE.SetRestitution(PhysBody, Restitution);
855 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); 844 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
856 845
857 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 846 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
@@ -869,22 +858,22 @@ public class BSPrim : BSPhysObject
869 // Set collision detection parameters 858 // Set collision detection parameters
870 if (BSParam.CcdMotionThreshold > 0f) 859 if (BSParam.CcdMotionThreshold > 0f)
871 { 860 {
872 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 861 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
873 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 862 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
874 } 863 }
875 864
876 // Various values for simulation limits 865 // Various values for simulation limits
877 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); 866 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
878 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); 867 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
879 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); 868 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
880 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 869 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
881 870
882 // This collides like an object. 871 // This collides like an object.
883 PhysBody.collisionType = CollisionType.Dynamic; 872 PhysBody.collisionType = CollisionType.Dynamic;
884 873
885 // Force activation of the object so Bullet will act on it. 874 // Force activation of the object so Bullet will act on it.
886 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 875 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
887 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 876 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
888 } 877 }
889 } 878 }
890 879
@@ -894,7 +883,7 @@ public class BSPrim : BSPhysObject
894 // the functions after this one set up the state of a possibly newly created collision body. 883 // the functions after this one set up the state of a possibly newly created collision body.
895 private void MakeSolid(bool makeSolid) 884 private void MakeSolid(bool makeSolid)
896 { 885 {
897 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); 886 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
898 if (makeSolid) 887 if (makeSolid)
899 { 888 {
900 // Verify the previous code created the correct shape for this type of thing. 889 // Verify the previous code created the correct shape for this type of thing.
@@ -902,7 +891,7 @@ public class BSPrim : BSPhysObject
902 { 891 {
903 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 892 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
904 } 893 }
905 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 894 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
906 } 895 }
907 else 896 else
908 { 897 {
@@ -910,7 +899,7 @@ public class BSPrim : BSPhysObject
910 { 899 {
911 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 900 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
912 } 901 }
913 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 902 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
914 903
915 // Change collision info from a static object to a ghosty collision object 904 // Change collision info from a static object to a ghosty collision object
916 PhysBody.collisionType = CollisionType.VolumeDetect; 905 PhysBody.collisionType = CollisionType.VolumeDetect;
@@ -922,11 +911,11 @@ public class BSPrim : BSPhysObject
922 { 911 {
923 if (wantsCollisionEvents) 912 if (wantsCollisionEvents)
924 { 913 {
925 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 914 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
926 } 915 }
927 else 916 else
928 { 917 {
929 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 918 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
930 } 919 }
931 } 920 }
932 921
@@ -937,7 +926,7 @@ public class BSPrim : BSPhysObject
937 { 926 {
938 if (PhysBody.HasPhysicalBody) 927 if (PhysBody.HasPhysicalBody)
939 { 928 {
940 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 929 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
941 } 930 }
942 else 931 else
943 { 932 {
@@ -972,12 +961,12 @@ public class BSPrim : BSPhysObject
972 public override bool FloatOnWater { 961 public override bool FloatOnWater {
973 set { 962 set {
974 _floatOnWater = value; 963 _floatOnWater = value;
975 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 964 PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
976 { 965 {
977 if (_floatOnWater) 966 if (_floatOnWater)
978 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 967 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
979 else 968 else
980 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 969 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
981 }); 970 });
982 } 971 }
983 } 972 }
@@ -989,7 +978,7 @@ public class BSPrim : BSPhysObject
989 _rotationalVelocity = value; 978 _rotationalVelocity = value;
990 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); 979 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
991 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 980 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
992 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 981 PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
993 { 982 {
994 ForceRotationalVelocity = _rotationalVelocity; 983 ForceRotationalVelocity = _rotationalVelocity;
995 }); 984 });
@@ -1004,7 +993,7 @@ public class BSPrim : BSPhysObject
1004 if (PhysBody.HasPhysicalBody) 993 if (PhysBody.HasPhysicalBody)
1005 { 994 {
1006 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 995 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1007 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 996 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1008 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 997 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1009 ActivateIfPhysical(false); 998 ActivateIfPhysical(false);
1010 } 999 }
@@ -1020,7 +1009,7 @@ public class BSPrim : BSPhysObject
1020 get { return _buoyancy; } 1009 get { return _buoyancy; }
1021 set { 1010 set {
1022 _buoyancy = value; 1011 _buoyancy = value;
1023 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 1012 PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate()
1024 { 1013 {
1025 ForceBuoyancy = _buoyancy; 1014 ForceBuoyancy = _buoyancy;
1026 }); 1015 });
@@ -1043,7 +1032,7 @@ public class BSPrim : BSPhysObject
1043 base.MoveToTargetActive = value; 1032 base.MoveToTargetActive = value;
1044 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() 1033 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1045 { 1034 {
1046 return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName); 1035 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1047 }); 1036 });
1048 } 1037 }
1049 } 1038 }
@@ -1055,7 +1044,7 @@ public class BSPrim : BSPhysObject
1055 base.HoverActive = value; 1044 base.HoverActive = value;
1056 EnableActor(HoverActive, HoverActorName, delegate() 1045 EnableActor(HoverActive, HoverActorName, delegate()
1057 { 1046 {
1058 return new BSActorHover(PhysicsScene, this, HoverActorName); 1047 return new BSActorHover(PhysScene, this, HoverActorName);
1059 }); 1048 });
1060 } 1049 }
1061 } 1050 }
@@ -1065,7 +1054,7 @@ public class BSPrim : BSPhysObject
1065 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 1054 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1066 1055
1067 // Since this force is being applied in only one step, make this a force per second. 1056 // Since this force is being applied in only one step, make this a force per second.
1068 addForce /= PhysicsScene.LastTimeStep; 1057 addForce /= PhysScene.LastTimeStep;
1069 AddForce(addForce, pushforce, false /* inTaintTime */); 1058 AddForce(addForce, pushforce, false /* inTaintTime */);
1070 } 1059 }
1071 1060
@@ -1080,13 +1069,13 @@ public class BSPrim : BSPhysObject
1080 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); 1069 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1081 1070
1082 OMV.Vector3 addForce = force; 1071 OMV.Vector3 addForce = force;
1083 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() 1072 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1084 { 1073 {
1085 // Bullet adds this central force to the total force for this tick 1074 // Bullet adds this central force to the total force for this tick
1086 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); 1075 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1087 if (PhysBody.HasPhysicalBody) 1076 if (PhysBody.HasPhysicalBody)
1088 { 1077 {
1089 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 1078 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1090 ActivateIfPhysical(false); 1079 ActivateIfPhysical(false);
1091 } 1080 }
1092 }); 1081 });
@@ -1108,13 +1097,13 @@ public class BSPrim : BSPhysObject
1108 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); 1097 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1109 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); 1098 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1110 1099
1111 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() 1100 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1112 { 1101 {
1113 // Bullet adds this impulse immediately to the velocity 1102 // Bullet adds this impulse immediately to the velocity
1114 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); 1103 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1115 if (PhysBody.HasPhysicalBody) 1104 if (PhysBody.HasPhysicalBody)
1116 { 1105 {
1117 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); 1106 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1118 ActivateIfPhysical(false); 1107 ActivateIfPhysical(false);
1119 } 1108 }
1120 }); 1109 });
@@ -1133,12 +1122,12 @@ public class BSPrim : BSPhysObject
1133 if (force.IsFinite()) 1122 if (force.IsFinite())
1134 { 1123 {
1135 OMV.Vector3 angForce = force; 1124 OMV.Vector3 angForce = force;
1136 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() 1125 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1137 { 1126 {
1138 if (PhysBody.HasPhysicalBody) 1127 if (PhysBody.HasPhysicalBody)
1139 { 1128 {
1140 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); 1129 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1141 PhysicsScene.PE.ApplyTorque(PhysBody, angForce); 1130 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1142 ActivateIfPhysical(false); 1131 ActivateIfPhysical(false);
1143 } 1132 }
1144 }); 1133 });
@@ -1157,11 +1146,11 @@ public class BSPrim : BSPhysObject
1157 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1146 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1158 { 1147 {
1159 OMV.Vector3 applyImpulse = impulse; 1148 OMV.Vector3 applyImpulse = impulse;
1160 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1149 PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1161 { 1150 {
1162 if (PhysBody.HasPhysicalBody) 1151 if (PhysBody.HasPhysicalBody)
1163 { 1152 {
1164 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); 1153 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1165 ActivateIfPhysical(false); 1154 ActivateIfPhysical(false);
1166 } 1155 }
1167 }); 1156 });
@@ -1463,12 +1452,13 @@ public class BSPrim : BSPhysObject
1463 // Create the correct physical representation for this type of object. 1452 // Create the correct physical representation for this type of object.
1464 // Updates base.PhysBody and base.PhysShape with the new information. 1453 // Updates base.PhysBody and base.PhysShape with the new information.
1465 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. 1454 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1466 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1455 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1467 { 1456 {
1468 // Called if the current prim body is about to be destroyed. 1457 // Called if the current prim body is about to be destroyed.
1469 // Remove all the physical dependencies on the old body. 1458 // Remove all the physical dependencies on the old body.
1470 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) 1459 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1471 RemoveBodyDependencies(); 1460 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1461 RemoveDependencies();
1472 }); 1462 });
1473 1463
1474 // Make sure the properties are set on the new object 1464 // Make sure the properties are set on the new object
@@ -1477,9 +1467,9 @@ public class BSPrim : BSPhysObject
1477 } 1467 }
1478 1468
1479 // Called at taint-time 1469 // Called at taint-time
1480 protected virtual void RemoveBodyDependencies() 1470 protected virtual void RemoveDependencies()
1481 { 1471 {
1482 PhysicalActors.RemoveBodyDependencies(); 1472 PhysicalActors.RemoveDependencies();
1483 } 1473 }
1484 1474
1485 // The physics engine says that properties have updated. Update same and inform 1475 // The physics engine says that properties have updated. Update same and inform
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
index f1c3b5c..f5ee671 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
@@ -78,14 +78,16 @@ public class BSPrimDisplaced : BSPrim
78 // Set this sets and computes the displacement from the passed prim to the center-of-mass. 78 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
79 // A user set value for center-of-mass overrides whatever might be passed in here. 79 // A user set value for center-of-mass overrides whatever might be passed in here.
80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). 80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
81 public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement) 81 public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
82 { 82 {
83 Vector3 comDisp; 83 Vector3 comDisp;
84 if (UserSetCenterOfMass.HasValue) 84 if (UserSetCenterOfMassDisplacement.HasValue)
85 comDisp = (OMV.Vector3)UserSetCenterOfMass; 85 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
86 else 86 else
87 comDisp = centerOfMassDisplacement; 87 comDisp = centerOfMassDisplacement;
88 88
89 DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
90 LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
89 if (comDisp == Vector3.Zero) 91 if (comDisp == Vector3.Zero)
90 { 92 {
91 // If there is no diplacement. Things get reset. 93 // If there is no diplacement. Things get reset.
@@ -107,9 +109,15 @@ public class BSPrimDisplaced : BSPrim
107 set 109 set
108 { 110 {
109 if (PositionDisplacement != OMV.Vector3.Zero) 111 if (PositionDisplacement != OMV.Vector3.Zero)
110 base.ForcePosition = value - (PositionDisplacement * RawOrientation); 112 {
113 OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation);
114 DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos);
115 base.ForcePosition = displacedPos;
116 }
111 else 117 else
118 {
112 base.ForcePosition = value; 119 base.ForcePosition = value;
120 }
113 } 121 }
114 } 122 }
115 123
@@ -118,6 +126,7 @@ public class BSPrimDisplaced : BSPrim
118 get { return base.ForceOrientation; } 126 get { return base.ForceOrientation; }
119 set 127 set
120 { 128 {
129 // TODO:
121 base.ForceOrientation = value; 130 base.ForceOrientation = value;
122 } 131 }
123 } 132 }
@@ -143,7 +152,10 @@ public class BSPrimDisplaced : BSPrim
143 { 152 {
144 // Correct for any rotation around the center-of-mass 153 // Correct for any rotation around the center-of-mass
145 // TODO!!! 154 // TODO!!!
146 entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation); 155
156 OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation);
157 DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos);
158 entprop.Position = displacedPos;
147 // entprop.Rotation = something; 159 // entprop.Rotation = something;
148 } 160 }
149 161
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
index 28242d4..235da78 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -47,9 +47,9 @@ public class BSPrimLinkable : BSPrimDisplaced
47 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 47 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
48 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) 48 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
49 { 49 {
50 Linkset = BSLinkset.Factory(PhysicsScene, this); 50 Linkset = BSLinkset.Factory(PhysScene, this);
51 51
52 PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() 52 PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
53 { 53 {
54 Linkset.Refresh(this); 54 Linkset.Refresh(this);
55 }); 55 });
@@ -61,9 +61,6 @@ public class BSPrimLinkable : BSPrimDisplaced
61 base.Destroy(); 61 base.Destroy();
62 } 62 }
63 63
64 public override BSPhysicsShapeType PreferredPhysicalShape
65 { get { return Linkset.PreferredPhysicalShape(this); } }
66
67 public override void link(Manager.PhysicsActor obj) 64 public override void link(Manager.PhysicsActor obj)
68 { 65 {
69 BSPrimLinkable parent = obj as BSPrimLinkable; 66 BSPrimLinkable parent = obj as BSPrimLinkable;
@@ -102,7 +99,7 @@ public class BSPrimLinkable : BSPrimDisplaced
102 set 99 set
103 { 100 {
104 base.Position = value; 101 base.Position = value;
105 PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate() 102 PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate()
106 { 103 {
107 Linkset.UpdateProperties(UpdatedProperties.Position, this); 104 Linkset.UpdateProperties(UpdatedProperties.Position, this);
108 }); 105 });
@@ -116,7 +113,7 @@ public class BSPrimLinkable : BSPrimDisplaced
116 set 113 set
117 { 114 {
118 base.Orientation = value; 115 base.Orientation = value;
119 PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() 116 PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate()
120 { 117 {
121 Linkset.UpdateProperties(UpdatedProperties.Orientation, this); 118 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
122 }); 119 });
@@ -149,10 +146,10 @@ public class BSPrimLinkable : BSPrimDisplaced
149 } 146 }
150 147
151 // Body is being taken apart. Remove physical dependencies and schedule a rebuild. 148 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
152 protected override void RemoveBodyDependencies() 149 protected override void RemoveDependencies()
153 { 150 {
154 Linkset.RemoveBodyDependencies(this); 151 Linkset.RemoveDependencies(this);
155 base.RemoveBodyDependencies(); 152 base.RemoveDependencies();
156 } 153 }
157 154
158 public override void UpdateProperties(EntityProperties entprop) 155 public override void UpdateProperties(EntityProperties entprop)
@@ -185,6 +182,10 @@ public class BSPrimLinkable : BSPrimDisplaced
185 { 182 {
186 return false; 183 return false;
187 } 184 }
185
186 // TODO: handle collisions of other objects with with children of linkset.
187 // This is a problem for LinksetCompound since the children are packed into the root.
188
188 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); 189 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
189 } 190 }
190} 191}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 8e05b58..a4a8794 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -316,7 +316,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
316 break; 316 break;
317 case "bulletxna": 317 case "bulletxna":
318 ret = new BSAPIXNA(engineName, this); 318 ret = new BSAPIXNA(engineName, this);
319 // Disable some features that are not implemented in BulletXNA
320 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
319 BSParam.ShouldUseBulletHACD = false; 321 BSParam.ShouldUseBulletHACD = false;
322 BSParam.ShouldUseSingleConvexHullForPrims = false;
320 break; 323 break;
321 } 324 }
322 325
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index bc26460..64aaa15 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -38,38 +38,15 @@ public sealed class BSShapeCollection : IDisposable
38{ 38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 private BSScene PhysicsScene { get; set; } 41 private BSScene m_physicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public BulletShape shape;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public BulletShape shape;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false; 45 private bool DDetail = false;
69 46
70 public BSShapeCollection(BSScene physScene) 47 public BSShapeCollection(BSScene physScene)
71 { 48 {
72 PhysicsScene = physScene; 49 m_physicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) 50 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the 51 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging 52 // DetailLog statements. When debugging slows down, this and the protected logging
@@ -86,22 +63,18 @@ public sealed class BSShapeCollection : IDisposable
86 // Mostly used for changing bodies out from under Linksets. 63 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving. 64 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback. 65 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape); 66 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91 67
92 // Called to update/change the body and shape for an object. 68 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes 69 // The object has some shape and body on it. Here we decide if that is the correct shape
94 // sure the body is of the right type. 70 // for the current state of the object (static/dynamic/...).
71 // If bodyCallback is not null, it is called if either the body or the shape are changed
72 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
95 // Return 'true' if either the body or the shape changed. 73 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before 74 // Called at taint-time.
97 // the current shape or body is destroyed. This allows the caller to remove any 75 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 { 76 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 77 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105 78
106 bool ret = false; 79 bool ret = false;
107 80
@@ -111,12 +84,12 @@ public sealed class BSShapeCollection : IDisposable
111 // Do we have the correct geometry for this type of object? 84 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape. 85 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape. 86 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); 87 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
115 // If we had to select a new shape geometry for the object, 88 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it. 89 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body 90 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed. 91 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); 92 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
120 ret = newGeom || newBody; 93 ret = newGeom || newBody;
121 } 94 }
122 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 95 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -127,271 +100,20 @@ public sealed class BSShapeCollection : IDisposable
127 100
128 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
129 { 102 {
130 return GetBodyAndShape(forceRebuild, sim, prim, null, null); 103 return GetBodyAndShape(forceRebuild, sim, prim, null);
131 }
132
133 // Track another user of a body.
134 // We presume the caller has allocated the body.
135 // Bodies only have one user so the body is just put into the world if not already there.
136 private void ReferenceBody(BulletBody body)
137 {
138 lock (m_collectionActivityLock)
139 {
140 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
141 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
142 {
143 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
144 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
145 }
146 }
147 }
148
149 // Release the usage of a body.
150 // Called when releasing use of a BSBody. BSShape is handled separately.
151 // Called in taint time.
152 public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback )
153 {
154 if (!body.HasPhysicalBody)
155 return;
156
157 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
158
159 lock (m_collectionActivityLock)
160 {
161 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
162 // If the caller needs to know the old body is going away, pass the event up.
163 if (bodyCallback != null) bodyCallback(body);
164
165 // Removing an object not in the world is a NOOP
166 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
167
168 // Zero any reference to the shape so it is not freed when the body is deleted.
169 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
170 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
171 }
172 }
173
174 // Track the datastructures and use count for a shape.
175 // When creating a hull, this is called first to reference the mesh
176 // and then again to reference the hull.
177 // Meshes and hulls for the same shape have the same hash key.
178 // NOTE that native shapes are not added to the mesh list or removed.
179 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
180 public bool ReferenceShape(BulletShape shape)
181 {
182 bool ret = false;
183 switch (shape.type)
184 {
185 case BSPhysicsShapeType.SHAPE_MESH:
186 MeshDesc meshDesc;
187 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
188 {
189 // There is an existing instance of this mesh.
190 meshDesc.referenceCount++;
191 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
192 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
193 }
194 else
195 {
196 // This is a new reference to a mesh
197 meshDesc.shape = shape.Clone();
198 meshDesc.shapeKey = shape.shapeKey;
199 // We keep a reference to the underlying IMesh data so a hull can be built
200 meshDesc.referenceCount = 1;
201 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
202 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
203 ret = true;
204 }
205 meshDesc.lastReferenced = System.DateTime.Now;
206 Meshes[shape.shapeKey] = meshDesc;
207 break;
208 case BSPhysicsShapeType.SHAPE_HULL:
209 HullDesc hullDesc;
210 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
211 {
212 // There is an existing instance of this hull.
213 hullDesc.referenceCount++;
214 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
215 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
216 }
217 else
218 {
219 // This is a new reference to a hull
220 hullDesc.shape = shape.Clone();
221 hullDesc.shapeKey = shape.shapeKey;
222 hullDesc.referenceCount = 1;
223 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
224 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
225 ret = true;
226
227 }
228 hullDesc.lastReferenced = System.DateTime.Now;
229 Hulls[shape.shapeKey] = hullDesc;
230 break;
231 case BSPhysicsShapeType.SHAPE_UNKNOWN:
232 break;
233 default:
234 // Native shapes are not tracked and they don't go into any list
235 break;
236 }
237 return ret;
238 }
239
240 // Release the usage of a shape.
241 public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback)
242 {
243 if (!shape.HasPhysicalShape)
244 return;
245
246 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape");
247
248 if (shape.HasPhysicalShape)
249 {
250 if (shape.isNativeShape)
251 {
252 // Native shapes are not tracked and are released immediately
253 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}",
254 BSScene.DetailLogZero, shape.AddrString);
255 if (shapeCallback != null) shapeCallback(shape);
256 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
257 }
258 else
259 {
260 switch (shape.type)
261 {
262 case BSPhysicsShapeType.SHAPE_HULL:
263 DereferenceHull(shape, shapeCallback);
264 break;
265 case BSPhysicsShapeType.SHAPE_MESH:
266 DereferenceMesh(shape, shapeCallback);
267 break;
268 case BSPhysicsShapeType.SHAPE_COMPOUND:
269 DereferenceCompound(shape, shapeCallback);
270 break;
271 case BSPhysicsShapeType.SHAPE_UNKNOWN:
272 break;
273 default:
274 break;
275 }
276 }
277 }
278 }
279
280 // Count down the reference count for a mesh shape
281 // Called at taint-time.
282 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
283 {
284 MeshDesc meshDesc;
285 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
286 {
287 meshDesc.referenceCount--;
288 // TODO: release the Bullet storage
289 if (shapeCallback != null) shapeCallback(shape);
290 meshDesc.lastReferenced = System.DateTime.Now;
291 Meshes[shape.shapeKey] = meshDesc;
292 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
293 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
294
295 }
296 }
297
298 // Count down the reference count for a hull shape
299 // Called at taint-time.
300 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
301 {
302 HullDesc hullDesc;
303 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
304 {
305 hullDesc.referenceCount--;
306 // TODO: release the Bullet storage (aging old entries?)
307
308 // Tell upper layers that, if they have dependencies on this shape, this link is going away
309 if (shapeCallback != null) shapeCallback(shape);
310
311 hullDesc.lastReferenced = System.DateTime.Now;
312 Hulls[shape.shapeKey] = hullDesc;
313 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
314 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
315 }
316 }
317
318 // Remove a reference to a compound shape.
319 // Taking a compound shape apart is a little tricky because if you just delete the
320 // physical shape, it will free all the underlying children. We can't do that because
321 // they could be shared. So, this removes each of the children from the compound and
322 // dereferences them separately before destroying the compound collision object itself.
323 // Called at taint-time.
324 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
325 {
326 if (!PhysicsScene.PE.IsCompound(shape))
327 {
328 // Failed the sanity check!!
329 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
330 LogHeader, shape.type, shape.AddrString);
331 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
332 BSScene.DetailLogZero, shape.type, shape.AddrString);
333 return;
334 }
335
336 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
337 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
338
339 for (int ii = numChildren - 1; ii >= 0; ii--)
340 {
341 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
342 DereferenceAnonCollisionShape(childShape);
343 }
344 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
345 } 104 }
346 105
347 // Sometimes we have a pointer to a collision shape but don't know what type it is. 106 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
348 // Figure out type and call the correct dereference routine. 107 // before replacing it.
349 // Called at taint-time. 108 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
350 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
351 { 109 {
352 MeshDesc meshDesc; 110 if (prim.PhysShape.HasPhysicalShape)
353 HullDesc hullDesc;
354
355 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
356 {
357 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
358 shapeInfo.shapeKey = meshDesc.shapeKey;
359 }
360 else
361 {
362 if (TryGetHullByPtr(shapeInfo, out hullDesc))
363 {
364 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
365 shapeInfo.shapeKey = hullDesc.shapeKey;
366 }
367 else
368 {
369 if (PhysicsScene.PE.IsCompound(shapeInfo))
370 {
371 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
372 }
373 else
374 {
375 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
376 {
377 shapeInfo.isNativeShape = true;
378 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
379 }
380 }
381 }
382 }
383
384 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
385
386 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
387 {
388 DereferenceShape(shapeInfo, null);
389 }
390 else
391 { 111 {
392 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", 112 if (shapeCallback != null)
393 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); 113 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
114 prim.PhysShape.Dereference(m_physicsScene);
394 } 115 }
116 prim.PhysShape = new BSShapeNull();
395 } 117 }
396 118
397 // Create the geometry information in Bullet for later use. 119 // Create the geometry information in Bullet for later use.
@@ -402,60 +124,41 @@ public sealed class BSShapeCollection : IDisposable
402 // Info in prim.BSShape is updated to the new shape. 124 // Info in prim.BSShape is updated to the new shape.
403 // Returns 'true' if the geometry was rebuilt. 125 // Returns 'true' if the geometry was rebuilt.
404 // Called at taint-time! 126 // Called at taint-time!
405 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 127 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
406 { 128 {
407 bool ret = false; 129 bool ret = false;
408 bool haveShape = false; 130 bool haveShape = false;
131 bool nativeShapePossible = true;
132 PrimitiveBaseShape pbs = prim.BaseShape;
409 133
410 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 134 // Kludge to create the capsule for the avatar.
135 // TDOD: Remove/redo this when BSShapeAvatar is working!!
136 BSCharacter theChar = prim as BSCharacter;
137 if (theChar != null)
411 { 138 {
412 // an avatar capsule is close to a native shape (it is not shared) 139 DereferenceExistingShape(prim, shapeCallback);
413 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); 140 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
414 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); 141 BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
415 ret = true; 142 ret = true;
416 haveShape = true; 143 haveShape = true;
417 } 144 }
418 145
419 // Compound shapes are handled special as they are rebuilt from scratch.
420 // This isn't too great a hardship since most of the child shapes will have already been created.
421 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
422 {
423 ret = GetReferenceToCompoundShape(prim, shapeCallback);
424 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
425 haveShape = true;
426 }
427
428 if (!haveShape)
429 {
430 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
431 }
432
433 return ret;
434 }
435
436 // Create a mesh, hull or native shape.
437 // Return 'true' if the prim's shape was changed.
438 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
439 {
440 bool ret = false;
441 bool haveShape = false;
442 bool nativeShapePossible = true;
443 PrimitiveBaseShape pbs = prim.BaseShape;
444
445 // If the prim attributes are simple, this could be a simple Bullet native shape 146 // If the prim attributes are simple, this could be a simple Bullet native shape
147 // Native shapes work whether to object is static or physical.
446 if (!haveShape 148 if (!haveShape
447 && nativeShapePossible 149 && nativeShapePossible
448 && pbs != null 150 && pbs != null
449 && !pbs.SculptEntry 151 && PrimHasNoCuts(pbs)
450 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) ) 152 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
153 )
451 { 154 {
452 // Get the scale of any existing shape so we can see if the new shape is same native type and same size. 155 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
453 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; 156 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
454 if (prim.PhysShape.HasPhysicalShape) 157 if (prim.PhysShape.HasPhysicalShape)
455 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); 158 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
456 159
457 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", 160 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
458 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); 161 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
459 162
460 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal 163 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
461 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 164 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -463,26 +166,30 @@ public sealed class BSShapeCollection : IDisposable
463 { 166 {
464 haveShape = true; 167 haveShape = true;
465 if (forceRebuild 168 if (forceRebuild
466 || prim.Scale != scaleOfExistingShape 169 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
467 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 170 )
468 )
469 { 171 {
470 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 172 DereferenceExistingShape(prim, shapeCallback);
471 FixedShapeKey.KEY_SPHERE, shapeCallback); 173 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
174 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
175 ret = true;
472 } 176 }
473 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", 177 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
474 prim.LocalID, forceRebuild, ret, prim.PhysShape); 178 prim.LocalID, forceRebuild, ret, prim.PhysShape);
475 } 179 }
180 // If we didn't make a sphere, maybe a box will work.
476 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 181 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
477 { 182 {
478 haveShape = true; 183 haveShape = true;
479 if (forceRebuild 184 if (forceRebuild
480 || prim.Scale != scaleOfExistingShape 185 || prim.Scale != scaleOfExistingShape
481 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 186 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
482 ) 187 )
483 { 188 {
484 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 189 DereferenceExistingShape(prim, shapeCallback);
485 FixedShapeKey.KEY_BOX, shapeCallback); 190 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
191 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
192 ret = true;
486 } 193 }
487 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", 194 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
488 prim.LocalID, forceRebuild, ret, prim.PhysShape); 195 prim.LocalID, forceRebuild, ret, prim.PhysShape);
@@ -499,7 +206,7 @@ public sealed class BSShapeCollection : IDisposable
499 } 206 }
500 207
501 // return 'true' if this shape description does not include any cutting or twisting. 208 // return 'true' if this shape description does not include any cutting or twisting.
502 private bool PrimHasNoCuts(PrimitiveBaseShape pbs) 209 public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
503 { 210 {
504 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 211 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
505 && pbs.ProfileHollow == 0 212 && pbs.ProfileHollow == 0
@@ -511,7 +218,7 @@ public sealed class BSShapeCollection : IDisposable
511 } 218 }
512 219
513 // return 'true' if the prim's shape was changed. 220 // return 'true' if the prim's shape was changed.
514 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 221 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
515 { 222 {
516 223
517 bool ret = false; 224 bool ret = false;
@@ -519,538 +226,110 @@ public sealed class BSShapeCollection : IDisposable
519 // made. Native shapes work in either case. 226 // made. Native shapes work in either case.
520 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) 227 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
521 { 228 {
522 // Update prim.BSShape to reference a hull of this shape. 229 // Use a simple, single mesh convex hull shape if the object is simple enough
523 ret = GetReferenceToHull(prim, shapeCallback); 230 BSShape potentialHull = null;
524 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
525 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
526 }
527 else
528 {
529 ret = GetReferenceToMesh(prim, shapeCallback);
530 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
531 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
532 }
533 return ret;
534 }
535
536 // Creates a native shape and assignes it to prim.BSShape.
537 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
538 private bool GetReferenceToNativeShape(BSPhysObject prim,
539 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
540 ShapeDestructionCallback shapeCallback)
541 {
542 // release any previous shape
543 DereferenceShape(prim.PhysShape, shapeCallback);
544
545 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
546
547 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
548 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
549 prim.LocalID, newShape, prim.Scale);
550
551 // native shapes are scaled by Bullet
552 prim.PhysShape = newShape;
553 return true;
554 }
555
556 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
557 FixedShapeKey shapeKey)
558 {
559 BulletShape newShape;
560 // Need to make sure the passed shape information is for the native type.
561 ShapeData nativeShapeData = new ShapeData();
562 nativeShapeData.Type = shapeType;
563 nativeShapeData.ID = prim.LocalID;
564 nativeShapeData.Scale = prim.Scale;
565 nativeShapeData.Size = prim.Scale; // unneeded, I think.
566 nativeShapeData.MeshKey = (ulong)shapeKey;
567 nativeShapeData.HullKey = (ulong)shapeKey;
568
569 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
570 {
571 231
572 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); 232 PrimitiveBaseShape pbs = prim.BaseShape;
573 if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 233 if (BSParam.ShouldUseSingleConvexHullForPrims
574 } 234 && pbs != null
575 else 235 && !pbs.SculptEntry
576 { 236 && PrimHasNoCuts(pbs)
577 // Native shapes are scaled in Bullet so set the scaling to the size 237 )
578 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
579
580 }
581 if (!newShape.HasPhysicalShape)
582 {
583 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
584 LogHeader, prim.LocalID, shapeType);
585 }
586 newShape.shapeKey = (System.UInt64)shapeKey;
587 newShape.isNativeShape = true;
588
589 return newShape;
590 }
591
592 // Builds a mesh shape in the physical world and updates prim.BSShape.
593 // Dereferences previous shape in BSShape and adds a reference for this new shape.
594 // Returns 'true' of a mesh was actually built. Otherwise .
595 // Called at taint-time!
596 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
597 {
598 BulletShape newShape = new BulletShape();
599
600 float lod;
601 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
602
603 // if this new shape is the same as last time, don't recreate the mesh
604 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
605 return false;
606
607 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}",
608 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
609
610 // Since we're recreating new, get rid of the reference to the previous shape
611 DereferenceShape(prim.PhysShape, shapeCallback);
612
613 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
614 // Take evasive action if the mesh was not constructed.
615 newShape = VerifyMeshCreated(PhysicsScene, newShape, prim);
616
617 ReferenceShape(newShape);
618
619 prim.PhysShape = newShape;
620
621 return true; // 'true' means a new shape has been added to this prim
622 }
623
624 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
625 {
626 BulletShape newShape = new BulletShape();
627
628 MeshDesc meshDesc;
629 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
630 {
631 // If the mesh has already been built just use it.
632 newShape = meshDesc.shape.Clone();
633 }
634 else
635 {
636 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
637 false, // say it is not physical so a bounding box is not built
638 false // do not cache the mesh and do not use previously built versions
639 );
640
641 if (meshData != null)
642 { 238 {
643 239 potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
644 int[] indices = meshData.getIndexListAsInt(); 240 }
645 int realIndicesIndex = indices.Length; 241 else
646 float[] verticesAsFloats = meshData.getVertexListAsFloat(); 242 {
647 243 potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
648 if (BSParam.ShouldRemoveZeroWidthTriangles)
649 {
650 // Remove degenerate triangles. These are triangles with two of the vertices
651 // are the same. This is complicated by the problem that vertices are not
652 // made unique in sculpties so we have to compare the values in the vertex.
653 realIndicesIndex = 0;
654 for (int tri = 0; tri < indices.Length; tri += 3)
655 {
656 // Compute displacements into vertex array for each vertex of the triangle
657 int v1 = indices[tri + 0] * 3;
658 int v2 = indices[tri + 1] * 3;
659 int v3 = indices[tri + 2] * 3;
660 // Check to see if any two of the vertices are the same
661 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
662 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
663 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
664 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
665 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
666 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
667 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
668 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
669 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
670 )
671 {
672 // None of the vertices of the triangles are the same. This is a good triangle;
673 indices[realIndicesIndex + 0] = indices[tri + 0];
674 indices[realIndicesIndex + 1] = indices[tri + 1];
675 indices[realIndicesIndex + 2] = indices[tri + 2];
676 realIndicesIndex += 3;
677 }
678 }
679 }
680 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
681 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
682
683 if (realIndicesIndex != 0)
684 {
685 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
686 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
687 }
688 else
689 {
690 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
691 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
692 }
693 } 244 }
694 }
695 newShape.shapeKey = newMeshKey;
696
697 return newShape;
698 }
699
700 // See that hull shape exists in the physical world and update prim.BSShape.
701 // We could be creating the hull because scale changed or whatever.
702 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
703 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
704 {
705 BulletShape newShape;
706
707 float lod;
708 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
709
710 // if the hull hasn't changed, don't rebuild it
711 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
712 return false;
713
714 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
715 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
716
717 // Remove usage of the previous shape.
718 DereferenceShape(prim.PhysShape, shapeCallback);
719
720 newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod);
721 // It might not have been created if we're waiting for an asset.
722 newShape = VerifyMeshCreated(PhysicsScene, newShape, prim);
723
724 ReferenceShape(newShape);
725
726 prim.PhysShape = newShape;
727 return true; // 'true' means a new shape has been added to this prim
728 }
729
730 List<ConvexResult> m_hulls;
731 private BulletShape CreatePhysicalHull(BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
732 {
733
734 BulletShape newShape = new BulletShape();
735 IntPtr hullPtr = IntPtr.Zero;
736 245
737 HullDesc hullDesc; 246 // If the current shape is not what is on the prim at the moment, time to change.
738 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 247 if (!prim.PhysShape.HasPhysicalShape
739 { 248 || potentialHull.ShapeType != prim.PhysShape.ShapeType
740 // If the hull shape already has been created, just use the one shared instance. 249 || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
741 newShape = hullDesc.shape.Clone(); 250 {
251 DereferenceExistingShape(prim, shapeCallback);
252 prim.PhysShape = potentialHull;
253 ret = true;
254 }
255 else
256 {
257 // The current shape on the prim is the correct one. We don't need the potential reference.
258 potentialHull.Dereference(m_physicsScene);
259 }
260 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
742 } 261 }
743 else 262 else
744 { 263 {
745 if (BSParam.ShouldUseBulletHACD) 264 // Update prim.BSShape to reference a mesh of this shape.
265 BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
266 // If the current shape is not what is on the prim at the moment, time to change.
267 if (!prim.PhysShape.HasPhysicalShape
268 || potentialMesh.ShapeType != prim.PhysShape.ShapeType
269 || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
746 { 270 {
747 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); 271 DereferenceExistingShape(prim, shapeCallback);
748 MeshDesc meshDesc; 272 prim.PhysShape = potentialMesh;
749 if (!Meshes.TryGetValue(newHullKey, out meshDesc)) 273 ret = true;
750 {
751 // That's odd because the mesh should have been created before the hull
752 // but, since it doesn't exist, create it.
753 newShape = CreatePhysicalMesh(prim, newHullKey, prim.BaseShape, prim.Size, lod);
754 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,noMeshBuiltNew,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
755
756 if (newShape.HasPhysicalShape)
757 {
758 ReferenceShape(newShape);
759 Meshes.TryGetValue(newHullKey, out meshDesc);
760 }
761 }
762 if (meshDesc.shape.HasPhysicalShape)
763 {
764 HACDParams parms;
765 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
766 parms.minClusters = BSParam.BHullMinClusters;
767 parms.compacityWeight = BSParam.BHullCompacityWeight;
768 parms.volumeWeight = BSParam.BHullVolumeWeight;
769 parms.concavity = BSParam.BHullConcavity;
770 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
771 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
772 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
773 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
774
775 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
776 newShape = PhysicsScene.PE.BuildHullShapeFromMesh(PhysicsScene.World, meshDesc.shape, parms);
777 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
778 }
779 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
780 } 274 }
781 if (!newShape.HasPhysicalShape) 275 else
782 { 276 {
783 // Build a new hull in the physical world. 277 // We don't need this reference to the mesh that is already being using.
784 // Pass true for physicalness as this prevents the creation of bounding box which is not needed 278 potentialMesh.Dereference(m_physicsScene);
785 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
786 if (meshData != null)
787 {
788 int[] indices = meshData.getIndexListAsInt();
789 List<OMV.Vector3> vertices = meshData.getVertexList();
790
791 //format conversion from IMesh format to DecompDesc format
792 List<int> convIndices = new List<int>();
793 List<float3> convVertices = new List<float3>();
794 for (int ii = 0; ii < indices.GetLength(0); ii++)
795 {
796 convIndices.Add(indices[ii]);
797 }
798 foreach (OMV.Vector3 vv in vertices)
799 {
800 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
801 }
802
803 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
804 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
805 {
806 // Simple primitive shapes we know are convex so they are better implemented with
807 // fewer hulls.
808 // Check for simple shape (prim without cuts) and reduce split parameter if so.
809 if (PrimHasNoCuts(pbs))
810 {
811 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
812 }
813 }
814
815 // setup and do convex hull conversion
816 m_hulls = new List<ConvexResult>();
817 DecompDesc dcomp = new DecompDesc();
818 dcomp.mIndices = convIndices;
819 dcomp.mVertices = convVertices;
820 dcomp.mDepth = maxDepthSplit;
821 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
822 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
823 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
824 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
825 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
826 // create the hull into the _hulls variable
827 convexBuilder.process(dcomp);
828
829 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
830 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
831
832 // Convert the vertices and indices for passing to unmanaged.
833 // The hull information is passed as a large floating point array.
834 // The format is:
835 // convHulls[0] = number of hulls
836 // convHulls[1] = number of vertices in first hull
837 // convHulls[2] = hull centroid X coordinate
838 // convHulls[3] = hull centroid Y coordinate
839 // convHulls[4] = hull centroid Z coordinate
840 // convHulls[5] = first hull vertex X
841 // convHulls[6] = first hull vertex Y
842 // convHulls[7] = first hull vertex Z
843 // convHulls[8] = second hull vertex X
844 // ...
845 // convHulls[n] = number of vertices in second hull
846 // convHulls[n+1] = second hull centroid X coordinate
847 // ...
848 //
849 // TODO: is is very inefficient. Someday change the convex hull generator to return
850 // data structures that do not need to be converted in order to pass to Bullet.
851 // And maybe put the values directly into pinned memory rather than marshaling.
852 int hullCount = m_hulls.Count;
853 int totalVertices = 1; // include one for the count of the hulls
854 foreach (ConvexResult cr in m_hulls)
855 {
856 totalVertices += 4; // add four for the vertex count and centroid
857 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
858 }
859 float[] convHulls = new float[totalVertices];
860
861 convHulls[0] = (float)hullCount;
862 int jj = 1;
863 foreach (ConvexResult cr in m_hulls)
864 {
865 // copy vertices for index access
866 float3[] verts = new float3[cr.HullVertices.Count];
867 int kk = 0;
868 foreach (float3 ff in cr.HullVertices)
869 {
870 verts[kk++] = ff;
871 }
872
873 // add to the array one hull's worth of data
874 convHulls[jj++] = cr.HullIndices.Count;
875 convHulls[jj++] = 0f; // centroid x,y,z
876 convHulls[jj++] = 0f;
877 convHulls[jj++] = 0f;
878 foreach (int ind in cr.HullIndices)
879 {
880 convHulls[jj++] = verts[ind].x;
881 convHulls[jj++] = verts[ind].y;
882 convHulls[jj++] = verts[ind].z;
883 }
884 }
885 // create the hull data structure in Bullet
886 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
887 }
888 } 279 }
889 newShape.shapeKey = newHullKey; 280 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
890 } 281 }
891 282 return ret;
892 return newShape;
893 }
894
895 // Callback from convex hull creater with a newly created hull.
896 // Just add it to our collection of hulls for this shape.
897 private void HullReturn(ConvexResult result)
898 {
899 m_hulls.Add(result);
900 return;
901 } 283 }
902 284
903 // Compound shapes are always built from scratch. 285 // Track another user of a body.
904 // This shouldn't be to bad since most of the parts will be meshes that had been built previously. 286 // We presume the caller has allocated the body.
905 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 287 // Bodies only have one user so the body is just put into the world if not already there.
288 private void ReferenceBody(BulletBody body)
906 { 289 {
907 // Remove reference to the old shape 290 lock (m_collectionActivityLock)
908 // Don't need to do this as the shape is freed when the new root shape is created below. 291 {
909 // DereferenceShape(prim.PhysShape, true, shapeCallback); 292 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
910 293 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
911 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); 294 {
912 295 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
913 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 296 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
914 CreateGeomMeshOrHull(prim, shapeCallback); 297 }
915 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); 298 }
916 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
917 prim.LocalID, cShape, prim.PhysShape);
918
919 prim.PhysShape = cShape;
920
921 return true;
922 } 299 }
923 300
924 // Create a hash of all the shape parameters to be used as a key 301 // Release the usage of a body.
925 // for this particular shape. 302 // Called when releasing use of a BSBody. BSShape is handled separately.
926 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 303 // Called in taint time.
927 { 304 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
928 // level of detail based on size and type of the object
929 float lod = BSParam.MeshLOD;
930
931 // prims with curvy internal cuts need higher lod
932 if (pbs.HollowShape == HollowShape.Circle)
933 lod = BSParam.MeshCircularLOD;
934
935 if (pbs.SculptEntry)
936 lod = BSParam.SculptLOD;
937
938 // Mega prims usually get more detail because one can interact with shape approximations at this size.
939 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
940 if (maxAxis > BSParam.MeshMegaPrimThreshold)
941 lod = BSParam.MeshMegaPrimLOD;
942
943 retLod = lod;
944 return pbs.GetMeshKey(size, lod);
945 }
946 // For those who don't want the LOD
947 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
948 { 305 {
949 float lod; 306 if (!body.HasPhysicalBody)
950 return ComputeShapeKey(size, pbs, out lod); 307 return;
951 }
952 308
953 // The creation of a mesh or hull can fail if an underlying asset is not available. 309 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
954 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
955 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
956 // The first case causes the asset to be fetched. The second case requires
957 // us to not loop forever.
958 // Called after creating a physical mesh or hull. If the physical shape was created,
959 // just return.
960 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
961 {
962 // If the shape was successfully created, nothing more to do
963 if (newShape.HasPhysicalShape)
964 return newShape;
965 310
966 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been 311 lock (m_collectionActivityLock)
967 // fetched but we end up here again, the meshing of the asset must have failed.
968 // Prevent trying to keep fetching the mesh by declaring failure.
969 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
970 {
971 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
972 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
973 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
974 }
975 else
976 { 312 {
977 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 313 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
978 if (prim.BaseShape.SculptEntry 314 // If the caller needs to know the old body is going away, pass the event up.
979 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed 315 if (bodyCallback != null)
980 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting 316 bodyCallback(body, null);
981 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
982 )
983 {
984 physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
985 // Multiple requestors will know we're waiting for this asset
986 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
987
988 BSPhysObject xprim = prim;
989 Util.FireAndForget(delegate
990 {
991 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
992 if (assetProvider != null)
993 {
994 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
995 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
996 {
997 bool assetFound = false;
998 string mismatchIDs = String.Empty; // DEBUG DEBUG
999 if (asset != null && yprim.BaseShape.SculptEntry)
1000 {
1001 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
1002 {
1003 yprim.BaseShape.SculptData = asset.Data;
1004 // This will cause the prim to see that the filler shape is not the right
1005 // one and try again to build the object.
1006 // No race condition with the normal shape setting since the rebuild is at taint time.
1007 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
1008 assetFound = true;
1009 }
1010 else
1011 {
1012 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
1013 }
1014 }
1015 if (assetFound)
1016 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
1017 else
1018 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
1019 physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
1020 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
1021 317
1022 }); 318 // Removing an object not in the world is a NOOP
1023 } 319 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
1024 else
1025 {
1026 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
1027 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
1028 LogHeader, physicsScene.Name);
1029 }
1030 });
1031 }
1032 else
1033 {
1034 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1035 {
1036 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1037 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1038 }
1039 }
1040 }
1041 320
1042 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. 321 // Zero any reference to the shape so it is not freed when the body is deleted.
1043 BulletShape fillinShape = physicsScene.Shapes.BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 322 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
1044 physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
1045 323
1046 return fillinShape; 324 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
325 }
1047 } 326 }
1048 327
1049 // Create a body object in Bullet. 328 // Create a body object in Bullet.
1050 // Updates prim.BSBody with the information about the new body if one is created. 329 // Updates prim.BSBody with the information about the new body if one is created.
1051 // Returns 'true' if an object was actually created. 330 // Returns 'true' if an object was actually created.
1052 // Called at taint-time. 331 // Called at taint-time.
1053 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) 332 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
1054 { 333 {
1055 bool ret = false; 334 bool ret = false;
1056 335
@@ -1061,7 +340,7 @@ public sealed class BSShapeCollection : IDisposable
1061 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 340 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
1062 if (!mustRebuild) 341 if (!mustRebuild)
1063 { 342 {
1064 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); 343 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
1065 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 344 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
1066 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 345 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
1067 { 346 {
@@ -1079,12 +358,12 @@ public sealed class BSShapeCollection : IDisposable
1079 BulletBody aBody; 358 BulletBody aBody;
1080 if (prim.IsSolid) 359 if (prim.IsSolid)
1081 { 360 {
1082 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 361 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1083 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); 362 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
1084 } 363 }
1085 else 364 else
1086 { 365 {
1087 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 366 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1088 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); 367 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
1089 } 368 }
1090 369
@@ -1098,46 +377,10 @@ public sealed class BSShapeCollection : IDisposable
1098 return ret; 377 return ret;
1099 } 378 }
1100 379
1101 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
1102 {
1103 bool ret = false;
1104 MeshDesc foundDesc = new MeshDesc();
1105 foreach (MeshDesc md in Meshes.Values)
1106 {
1107 if (md.shape.ReferenceSame(shape))
1108 {
1109 foundDesc = md;
1110 ret = true;
1111 break;
1112 }
1113
1114 }
1115 outDesc = foundDesc;
1116 return ret;
1117 }
1118
1119 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
1120 {
1121 bool ret = false;
1122 HullDesc foundDesc = new HullDesc();
1123 foreach (HullDesc hd in Hulls.Values)
1124 {
1125 if (hd.shape.ReferenceSame(shape))
1126 {
1127 foundDesc = hd;
1128 ret = true;
1129 break;
1130 }
1131
1132 }
1133 outDesc = foundDesc;
1134 return ret;
1135 }
1136
1137 private void DetailLog(string msg, params Object[] args) 380 private void DetailLog(string msg, params Object[] args)
1138 { 381 {
1139 if (PhysicsScene.PhysicsLogging.Enabled) 382 if (m_physicsScene.PhysicsLogging.Enabled)
1140 PhysicsScene.DetailLog(msg, args); 383 m_physicsScene.DetailLog(msg, args);
1141 } 384 }
1142} 385}
1143} 386}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index dd5ae1a..3e4ee5a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -31,6 +31,7 @@ using System.Text;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34 35
35using OMV = OpenMetaverse; 36using OMV = OpenMetaverse;
36 37
@@ -38,74 +39,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
38{ 39{
39public abstract class BSShape 40public abstract class BSShape
40{ 41{
42 private static string LogHeader = "[BULLETSIM SHAPE]";
43
41 public int referenceCount { get; set; } 44 public int referenceCount { get; set; }
42 public DateTime lastReferenced { get; set; } 45 public DateTime lastReferenced { get; set; }
43 public BulletShape physShapeInfo { get; set; } 46 public BulletShape physShapeInfo { get; set; }
44 47
45 public BSShape() 48 public BSShape()
46 { 49 {
47 referenceCount = 0; 50 referenceCount = 1;
48 lastReferenced = DateTime.Now; 51 lastReferenced = DateTime.Now;
49 physShapeInfo = new BulletShape(); 52 physShapeInfo = new BulletShape();
50 } 53 }
51 public BSShape(BulletShape pShape) 54 public BSShape(BulletShape pShape)
52 { 55 {
53 referenceCount = 0; 56 referenceCount = 1;
54 lastReferenced = DateTime.Now; 57 lastReferenced = DateTime.Now;
55 physShapeInfo = pShape; 58 physShapeInfo = pShape;
56 } 59 }
57 60
58 // Get a reference to a physical shape. Create if it doesn't exist 61 // Get another reference to this shape.
59 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 62 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
60 {
61 BSShape ret = null;
62
63 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
64 {
65 // an avatar capsule is close to a native shape (it is not shared)
66 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
67 FixedShapeKey.KEY_CAPSULE);
68 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
69 }
70
71 // Compound shapes are handled special as they are rebuilt from scratch.
72 // This isn't too great a hardship since most of the child shapes will have already been created.
73 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
74 {
75 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
76 ret = BSShapeCompound.GetReference(prim);
77 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
78 }
79
80 // Avatars have their own unique shape
81 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
82 {
83 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
84 ret = BSShapeAvatar.GetReference(prim);
85 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
86 }
87
88 if (ret == null)
89 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
90
91 return ret;
92 }
93 private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
94 {
95 BSShapeMesh.GetReference(physicsScene, forceRebuild, prim);
96 BSShapeHull.GetReference(physicsScene, forceRebuild, prim);
97 return null;
98 }
99 63
100 // Called when this shape is being used again. 64 // Called when this shape is being used again.
101 public virtual void IncrementReference() 65 // Used internally. External callers should call instance.GetReference() to properly copy/reference
66 // the shape.
67 protected virtual void IncrementReference()
102 { 68 {
103 referenceCount++; 69 referenceCount++;
104 lastReferenced = DateTime.Now; 70 lastReferenced = DateTime.Now;
105 } 71 }
106 72
107 // Called when this shape is being used again. 73 // Called when this shape is being used again.
108 public virtual void DecrementReference() 74 protected virtual void DecrementReference()
109 { 75 {
110 referenceCount--; 76 referenceCount--;
111 lastReferenced = DateTime.Now; 77 lastReferenced = DateTime.Now;
@@ -114,22 +80,178 @@ public abstract class BSShape
114 // Release the use of a physical shape. 80 // Release the use of a physical shape.
115 public abstract void Dereference(BSScene physicsScene); 81 public abstract void Dereference(BSScene physicsScene);
116 82
83 // Return 'true' if there is an allocated physics physical shape under this class instance.
84 public virtual bool HasPhysicalShape
85 {
86 get
87 {
88 if (physShapeInfo != null)
89 return physShapeInfo.HasPhysicalShape;
90 return false;
91 }
92 }
93 public virtual BSPhysicsShapeType ShapeType
94 {
95 get
96 {
97 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
98 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
99 ret = physShapeInfo.shapeType;
100 return ret;
101 }
102 }
103
117 // Returns a string for debugging that uniquily identifies the memory used by this instance 104 // Returns a string for debugging that uniquily identifies the memory used by this instance
118 public virtual string AddrString 105 public virtual string AddrString
119 { 106 {
120 get { return "unknown"; } 107 get
108 {
109 if (physShapeInfo != null)
110 return physShapeInfo.AddrString;
111 return "unknown";
112 }
121 } 113 }
122 114
123 public override string ToString() 115 public override string ToString()
124 { 116 {
125 StringBuilder buff = new StringBuilder(); 117 StringBuilder buff = new StringBuilder();
126 buff.Append("<p="); 118 if (physShapeInfo == null)
127 buff.Append(AddrString); 119 {
120 buff.Append(",noPhys");
121 }
122 else
123 {
124 buff.Append(",phy=");
125 buff.Append(physShapeInfo.ToString());
126 }
128 buff.Append(",c="); 127 buff.Append(",c=");
129 buff.Append(referenceCount.ToString()); 128 buff.Append(referenceCount.ToString());
130 buff.Append(">"); 129 buff.Append(">");
131 return buff.ToString(); 130 return buff.ToString();
132 } 131 }
132
133 #region Common shape routines
134 // Create a hash of all the shape parameters to be used as a key for this particular shape.
135 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
136 {
137 // level of detail based on size and type of the object
138 float lod = BSParam.MeshLOD;
139 if (pbs.SculptEntry)
140 lod = BSParam.SculptLOD;
141
142 // Mega prims usually get more detail because one can interact with shape approximations at this size.
143 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
144 if (maxAxis > BSParam.MeshMegaPrimThreshold)
145 lod = BSParam.MeshMegaPrimLOD;
146
147 retLod = lod;
148 return pbs.GetMeshKey(size, lod);
149 }
150
151 // The creation of a mesh or hull can fail if an underlying asset is not available.
152 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
153 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
154 // The first case causes the asset to be fetched. The second case requires
155 // us to not loop forever.
156 // Called after creating a physical mesh or hull. If the physical shape was created,
157 // just return.
158 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
159 {
160 // If the shape was successfully created, nothing more to do
161 if (newShape.HasPhysicalShape)
162 return newShape;
163
164 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
165 // fetched but we end up here again, the meshing of the asset must have failed.
166 // Prevent trying to keep fetching the mesh by declaring failure.
167 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
168 {
169 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
170 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
171 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
172 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}",
173 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
174 }
175 else
176 {
177 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
178 if (prim.BaseShape.SculptEntry
179 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
180 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
181 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
182 )
183 {
184 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
185 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
186 // Multiple requestors will know we're waiting for this asset
187 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
188
189 BSPhysObject xprim = prim;
190 Util.FireAndForget(delegate
191 {
192 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
193 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
194 if (assetProvider != null)
195 {
196 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
197 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
198 {
199 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
200 bool assetFound = false;
201 string mismatchIDs = String.Empty; // DEBUG DEBUG
202 if (asset != null && yprim.BaseShape.SculptEntry)
203 {
204 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
205 {
206 yprim.BaseShape.SculptData = asset.Data;
207 // This will cause the prim to see that the filler shape is not the right
208 // one and try again to build the object.
209 // No race condition with the normal shape setting since the rebuild is at taint time.
210 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
211 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
212 assetFound = true;
213 }
214 else
215 {
216 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
217 }
218 }
219 if (!assetFound)
220 {
221 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
222 }
223 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
224 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
225 });
226 }
227 else
228 {
229 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
230 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
231 LogHeader, physicsScene.Name);
232 }
233 });
234 }
235 else
236 {
237 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
238 {
239 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
240 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
241 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}",
242 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
243 }
244 }
245 }
246
247 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
248 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
249 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
250
251 return fillShape.physShapeInfo;
252 }
253
254 #endregion // Common shape routines
133} 255}
134 256
135// ============================================================================================================ 257// ============================================================================================================
@@ -139,6 +261,7 @@ public class BSShapeNull : BSShape
139 { 261 {
140 } 262 }
141 public static BSShape GetReference() { return new BSShapeNull(); } 263 public static BSShape GetReference() { return new BSShapeNull(); }
264 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
142 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } 265 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
143} 266}
144 267
@@ -150,24 +273,34 @@ public class BSShapeNative : BSShape
150 { 273 {
151 } 274 }
152 275
153 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, 276 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
154 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 277 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
155 { 278 {
156 // Native shapes are not shared and are always built anew. 279 // Native shapes are not shared and are always built anew.
157 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); 280 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
158 } 281 }
159 282
283 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
284 {
285 // Native shapes are not shared so we return a new shape.
286 return new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
287 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey) );
288 }
289
160 // Make this reference to the physical shape go away since native shapes are not shared. 290 // Make this reference to the physical shape go away since native shapes are not shared.
161 public override void Dereference(BSScene physicsScene) 291 public override void Dereference(BSScene physicsScene)
162 { 292 {
163 // Native shapes are not tracked and are released immediately 293 // Native shapes are not tracked and are released immediately
164 if (physShapeInfo.HasPhysicalShape) 294 lock (physShapeInfo)
165 { 295 {
166 physicsScene.DetailLog("{0},BSShapeNative.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); 296 if (physShapeInfo.HasPhysicalShape)
167 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); 297 {
298 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
299 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
300 }
301 physShapeInfo.Clear();
302 // Garbage collection will free up this instance.
168 } 303 }
169 physShapeInfo.Clear();
170 // Garbage collection will free up this instance.
171 } 304 }
172 305
173 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, 306 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
@@ -197,7 +330,7 @@ public class BSShapeNative : BSShape
197 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 330 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
198 LogHeader, prim.LocalID, shapeType); 331 LogHeader, prim.LocalID, shapeType);
199 } 332 }
200 newShape.type = shapeType; 333 newShape.shapeType = shapeType;
201 newShape.isNativeShape = true; 334 newShape.isNativeShape = true;
202 newShape.shapeKey = (UInt64)shapeKey; 335 newShape.shapeKey = (UInt64)shapeKey;
203 return newShape; 336 return newShape;
@@ -209,7 +342,7 @@ public class BSShapeNative : BSShape
209public class BSShapeMesh : BSShape 342public class BSShapeMesh : BSShape
210{ 343{
211 private static string LogHeader = "[BULLETSIM SHAPE MESH]"; 344 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
212 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); 345 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
213 346
214 public BSShapeMesh(BulletShape pShape) : base(pShape) 347 public BSShapeMesh(BulletShape pShape) : base(pShape)
215 { 348 {
@@ -217,12 +350,9 @@ public class BSShapeMesh : BSShape
217 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 350 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
218 { 351 {
219 float lod; 352 float lod;
220 System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 353 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
221 354
222 physicsScene.DetailLog("{0},BSShapeMesh,create,oldKey={1},newKey={2},size={3},lod={4}", 355 BSShapeMesh retMesh = null;
223 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
224
225 BSShapeMesh retMesh;
226 lock (Meshes) 356 lock (Meshes)
227 { 357 {
228 if (Meshes.TryGetValue(newMeshKey, out retMesh)) 358 if (Meshes.TryGetValue(newMeshKey, out retMesh))
@@ -232,39 +362,78 @@ public class BSShapeMesh : BSShape
232 } 362 }
233 else 363 else
234 { 364 {
365 retMesh = new BSShapeMesh(new BulletShape());
235 // An instance of this mesh has not been created. Build and remember same. 366 // An instance of this mesh has not been created. Build and remember same.
236 BulletShape newShape = CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); 367 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
237 // Take evasive action if the mesh was not constructed.
238 newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim);
239 368
240 retMesh = new BSShapeMesh(newShape); 369 // Check to see if mesh was created (might require an asset).
370 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
371 if (!newShape.isNativeShape)
372 {
373 // If a mesh was what was created, remember the built shape for later sharing.
374 Meshes.Add(newMeshKey, retMesh);
375 }
241 376
242 Meshes.Add(newMeshKey, retMesh); 377 retMesh.physShapeInfo = newShape;
243 } 378 }
244 } 379 }
380 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
245 return retMesh; 381 return retMesh;
246 } 382 }
383 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
384 {
385 // Another reference to this shape is just counted.
386 IncrementReference();
387 return this;
388 }
247 public override void Dereference(BSScene physicsScene) 389 public override void Dereference(BSScene physicsScene)
248 { 390 {
249 lock (Meshes) 391 lock (Meshes)
250 { 392 {
251 this.DecrementReference(); 393 this.DecrementReference();
394 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
252 // TODO: schedule aging and destruction of unused meshes. 395 // TODO: schedule aging and destruction of unused meshes.
253 } 396 }
254 } 397 }
398 // Loop through all the known meshes and return the description based on the physical address.
399 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
400 {
401 bool ret = false;
402 BSShapeMesh foundDesc = null;
403 lock (Meshes)
404 {
405 foreach (BSShapeMesh sm in Meshes.Values)
406 {
407 if (sm.physShapeInfo.ReferenceSame(pShape))
408 {
409 foundDesc = sm;
410 ret = true;
411 break;
412 }
255 413
256 private static BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, 414 }
415 }
416 outMesh = foundDesc;
417 return ret;
418 }
419 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
257 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 420 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
258 { 421 {
259 BulletShape newShape = null; 422 BulletShape newShape = new BulletShape();
260 423
261 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, 424 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
262 false, // say it is not physical so a bounding box is not built 425 false, // say it is not physical so a bounding box is not built
263 false // do not cache the mesh and do not use previously built versions 426 false // do not cache the mesh and do not use previously built versions
264 ); 427 );
265 428
266 if (meshData != null) 429 if (meshData != null)
267 { 430 {
431 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
432 {
433 // Release the fetched asset data once it has been used.
434 pbs.SculptData = new byte[0];
435 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
436 }
268 437
269 int[] indices = meshData.getIndexListAsInt(); 438 int[] indices = meshData.getIndexListAsInt();
270 int realIndicesIndex = indices.Length; 439 int realIndicesIndex = indices.Length;
@@ -302,8 +471,8 @@ public class BSShapeMesh : BSShape
302 } 471 }
303 } 472 }
304 } 473 }
305 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", 474 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
306 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); 475 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
307 476
308 if (realIndicesIndex != 0) 477 if (realIndicesIndex != 0)
309 { 478 {
@@ -326,17 +495,239 @@ public class BSShapeMesh : BSShape
326public class BSShapeHull : BSShape 495public class BSShapeHull : BSShape
327{ 496{
328 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 497 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
329 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 498 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
330 499
331 public BSShapeHull(BulletShape pShape) : base(pShape) 500 public BSShapeHull(BulletShape pShape) : base(pShape)
332 { 501 {
333 } 502 }
334 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 503 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
335 { 504 {
336 return new BSShapeNull(); 505 float lod;
506 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
507
508 BSShapeHull retHull = null;
509 lock (Hulls)
510 {
511 if (Hulls.TryGetValue(newHullKey, out retHull))
512 {
513 // The mesh has already been created. Return a new reference to same.
514 retHull.IncrementReference();
515 }
516 else
517 {
518 retHull = new BSShapeHull(new BulletShape());
519 // An instance of this mesh has not been created. Build and remember same.
520 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
521
522 // Check to see if hull was created (might require an asset).
523 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
524 if (!newShape.isNativeShape)
525 {
526 // If a mesh was what was created, remember the built shape for later sharing.
527 Hulls.Add(newHullKey, retHull);
528 }
529 retHull.physShapeInfo = newShape;
530 }
531 }
532 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
533 return retHull;
534 }
535 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
536 {
537 // Another reference to this shape is just counted.
538 IncrementReference();
539 return this;
337 } 540 }
338 public override void Dereference(BSScene physicsScene) 541 public override void Dereference(BSScene physicsScene)
339 { 542 {
543 lock (Hulls)
544 {
545 this.DecrementReference();
546 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
547 // TODO: schedule aging and destruction of unused meshes.
548 }
549 }
550 List<ConvexResult> m_hulls;
551 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
552 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
553 {
554 BulletShape newShape = new BulletShape();
555 IntPtr hullPtr = IntPtr.Zero;
556
557 if (BSParam.ShouldUseBulletHACD)
558 {
559 // Build the hull shape from an existing mesh shape.
560 // The mesh should have already been created in Bullet.
561 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID);
562 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
563
564 if (meshShape.physShapeInfo.HasPhysicalShape)
565 {
566 HACDParams parms;
567 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
568 parms.minClusters = BSParam.BHullMinClusters;
569 parms.compacityWeight = BSParam.BHullCompacityWeight;
570 parms.volumeWeight = BSParam.BHullVolumeWeight;
571 parms.concavity = BSParam.BHullConcavity;
572 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
573 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
574 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
575 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
576
577 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
578 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
579 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
580
581 // Now done with the mesh shape.
582 meshShape.Dereference(physicsScene);
583 }
584 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
585 }
586 if (!newShape.HasPhysicalShape)
587 {
588 // Build a new hull in the physical world using the C# HACD algorigthm.
589 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
590 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
591 if (meshData != null)
592 {
593 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
594 {
595 // Release the fetched asset data once it has been used.
596 pbs.SculptData = new byte[0];
597 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
598 }
599
600 int[] indices = meshData.getIndexListAsInt();
601 List<OMV.Vector3> vertices = meshData.getVertexList();
602
603 //format conversion from IMesh format to DecompDesc format
604 List<int> convIndices = new List<int>();
605 List<float3> convVertices = new List<float3>();
606 for (int ii = 0; ii < indices.GetLength(0); ii++)
607 {
608 convIndices.Add(indices[ii]);
609 }
610 foreach (OMV.Vector3 vv in vertices)
611 {
612 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
613 }
614
615 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
616 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
617 {
618 // Simple primitive shapes we know are convex so they are better implemented with
619 // fewer hulls.
620 // Check for simple shape (prim without cuts) and reduce split parameter if so.
621 if (BSShapeCollection.PrimHasNoCuts(pbs))
622 {
623 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
624 }
625 }
626
627 // setup and do convex hull conversion
628 m_hulls = new List<ConvexResult>();
629 DecompDesc dcomp = new DecompDesc();
630 dcomp.mIndices = convIndices;
631 dcomp.mVertices = convVertices;
632 dcomp.mDepth = maxDepthSplit;
633 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
634 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
635 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
636 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
637 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
638 // create the hull into the _hulls variable
639 convexBuilder.process(dcomp);
640
641 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
642 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
643
644 // Convert the vertices and indices for passing to unmanaged.
645 // The hull information is passed as a large floating point array.
646 // The format is:
647 // convHulls[0] = number of hulls
648 // convHulls[1] = number of vertices in first hull
649 // convHulls[2] = hull centroid X coordinate
650 // convHulls[3] = hull centroid Y coordinate
651 // convHulls[4] = hull centroid Z coordinate
652 // convHulls[5] = first hull vertex X
653 // convHulls[6] = first hull vertex Y
654 // convHulls[7] = first hull vertex Z
655 // convHulls[8] = second hull vertex X
656 // ...
657 // convHulls[n] = number of vertices in second hull
658 // convHulls[n+1] = second hull centroid X coordinate
659 // ...
660 //
661 // TODO: is is very inefficient. Someday change the convex hull generator to return
662 // data structures that do not need to be converted in order to pass to Bullet.
663 // And maybe put the values directly into pinned memory rather than marshaling.
664 int hullCount = m_hulls.Count;
665 int totalVertices = 1; // include one for the count of the hulls
666 foreach (ConvexResult cr in m_hulls)
667 {
668 totalVertices += 4; // add four for the vertex count and centroid
669 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
670 }
671 float[] convHulls = new float[totalVertices];
672
673 convHulls[0] = (float)hullCount;
674 int jj = 1;
675 foreach (ConvexResult cr in m_hulls)
676 {
677 // copy vertices for index access
678 float3[] verts = new float3[cr.HullVertices.Count];
679 int kk = 0;
680 foreach (float3 ff in cr.HullVertices)
681 {
682 verts[kk++] = ff;
683 }
684
685 // add to the array one hull's worth of data
686 convHulls[jj++] = cr.HullIndices.Count;
687 convHulls[jj++] = 0f; // centroid x,y,z
688 convHulls[jj++] = 0f;
689 convHulls[jj++] = 0f;
690 foreach (int ind in cr.HullIndices)
691 {
692 convHulls[jj++] = verts[ind].x;
693 convHulls[jj++] = verts[ind].y;
694 convHulls[jj++] = verts[ind].z;
695 }
696 }
697 // create the hull data structure in Bullet
698 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
699 }
700 newShape.shapeKey = newHullKey;
701 }
702 return newShape;
703 }
704 // Callback from convex hull creater with a newly created hull.
705 // Just add it to our collection of hulls for this shape.
706 private void HullReturn(ConvexResult result)
707 {
708 m_hulls.Add(result);
709 return;
710 }
711 // Loop through all the known hulls and return the description based on the physical address.
712 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
713 {
714 bool ret = false;
715 BSShapeHull foundDesc = null;
716 lock (Hulls)
717 {
718 foreach (BSShapeHull sh in Hulls.Values)
719 {
720 if (sh.physShapeInfo.ReferenceSame(pShape))
721 {
722 foundDesc = sh;
723 ret = true;
724 break;
725 }
726
727 }
728 }
729 outHull = foundDesc;
730 return ret;
340 } 731 }
341} 732}
342 733
@@ -344,14 +735,169 @@ public class BSShapeHull : BSShape
344public class BSShapeCompound : BSShape 735public class BSShapeCompound : BSShape
345{ 736{
346 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 737 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
347 public BSShapeCompound() : base() 738 public BSShapeCompound(BulletShape pShape) : base(pShape)
348 { 739 {
349 } 740 }
350 public static BSShape GetReference(BSPhysObject prim) 741 public static BSShape GetReference(BSScene physicsScene)
351 { 742 {
352 return new BSShapeNull(); 743 // Base compound shapes are not shared so this returns a raw shape.
744 // A built compound shape can be reused in linksets.
745 return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
746 }
747 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
748 {
749 // Calling this reference means we want another handle to an existing compound shape
750 // (usually linksets) so return this copy.
751 IncrementReference();
752 return this;
753 }
754 // Dereferencing a compound shape releases the hold on all the child shapes.
755 public override void Dereference(BSScene physicsScene)
756 {
757 lock (physShapeInfo)
758 {
759 this.DecrementReference();
760 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
761 if (referenceCount <= 0)
762 {
763 if (!physicsScene.PE.IsCompound(physShapeInfo))
764 {
765 // Failed the sanity check!!
766 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
767 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
768 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
769 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
770 return;
771 }
772
773 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
774 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
775 BSScene.DetailLogZero, physShapeInfo, numChildren);
776
777 // Loop through all the children dereferencing each.
778 for (int ii = numChildren - 1; ii >= 0; ii--)
779 {
780 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
781 DereferenceAnonCollisionShape(physicsScene, childShape);
782 }
783 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
784 }
785 }
786 }
787 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
788 {
789 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
790 return cShape;
791 }
792 // Sometimes we have a pointer to a collision shape but don't know what type it is.
793 // Figure out type and call the correct dereference routine.
794 // Called at taint-time.
795 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
796 {
797 BSShapeMesh meshDesc;
798 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
799 {
800 meshDesc.Dereference(physicsScene);
801 }
802 else
803 {
804 BSShapeHull hullDesc;
805 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
806 {
807 hullDesc.Dereference(physicsScene);
808 }
809 else
810 {
811 if (physicsScene.PE.IsCompound(pShape))
812 {
813 BSShapeCompound recursiveCompound = new BSShapeCompound(pShape);
814 recursiveCompound.Dereference(physicsScene);
815 }
816 else
817 {
818 if (physicsScene.PE.IsNativeShape(pShape))
819 {
820 BSShapeNative nativeShape = new BSShapeNative(pShape);
821 nativeShape.Dereference(physicsScene);
822 }
823 }
824 }
825 }
826 }
827}
828
829// ============================================================================================================
830public class BSShapeConvexHull : BSShape
831{
832 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
833 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
834
835 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
836 {
837 }
838 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
839 {
840 float lod;
841 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
842
843 physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}",
844 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
845
846 BSShapeConvexHull retConvexHull = null;
847 lock (ConvexHulls)
848 {
849 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
850 {
851 // The mesh has already been created. Return a new reference to same.
852 retConvexHull.IncrementReference();
853 }
854 else
855 {
856 retConvexHull = new BSShapeConvexHull(new BulletShape());
857 BulletShape convexShape = null;
858
859 // Get a handle to a mesh to build the hull from
860 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
861 if (baseMesh.physShapeInfo.isNativeShape)
862 {
863 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
864 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
865 // get back to this code with a buildable mesh.
866 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
867 convexShape = baseMesh.physShapeInfo;
868 }
869 else
870 {
871 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
872 convexShape.shapeKey = newMeshKey;
873 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
874 }
875
876 // Done with the base mesh
877 baseMesh.Dereference(physicsScene);
878
879 retConvexHull.physShapeInfo = convexShape;
880 }
881 }
882 return retConvexHull;
883 }
884 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
885 {
886 // Calling this reference means we want another handle to an existing shape
887 // (usually linksets) so return this copy.
888 IncrementReference();
889 return this;
890 }
891 // Dereferencing a compound shape releases the hold on all the child shapes.
892 public override void Dereference(BSScene physicsScene)
893 {
894 lock (ConvexHulls)
895 {
896 this.DecrementReference();
897 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
898 // TODO: schedule aging and destruction of unused meshes.
899 }
353 } 900 }
354 public override void Dereference(BSScene physicsScene) { }
355} 901}
356 902
357// ============================================================================================================ 903// ============================================================================================================
@@ -361,8 +907,12 @@ public class BSShapeAvatar : BSShape
361 public BSShapeAvatar() : base() 907 public BSShapeAvatar() : base()
362 { 908 {
363 } 909 }
364 public static BSShape GetReference(BSPhysObject prim) 910 public static BSShape GetReference(BSPhysObject prim)
365 { 911 {
912 return new BSShapeNull();
913 }
914 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
915 {
366 return new BSShapeNull(); 916 return new BSShapeNull();
367 } 917 }
368 public override void Dereference(BSScene physicsScene) { } 918 public override void Dereference(BSScene physicsScene) { }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index e4fecc3..c7deb4e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -68,7 +68,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
68 68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z 69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap). 70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords) 72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id) 73 : base(physicsScene, regionBase, id)
74 { 74 {
@@ -92,7 +92,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
92 private void BuildHeightmapTerrain() 92 private void BuildHeightmapTerrain()
93 { 93 {
94 // Create the terrain shape from the mapInfo 94 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, 95 m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, 96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); 97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98 98
@@ -103,26 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); 103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); 104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105 105
106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, 106 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity); 107 m_mapInfo.ID, centerPos, Quaternion.Identity);
108 108
109 // Set current terrain attributes 109 // Set current terrain attributes
110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); 110 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); 111 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); 112 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); 113 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
114 114
115 // Return the new terrain to the world of physical objects 115 // Return the new terrain to the world of physical objects
116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); 116 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
117 117
118 // redo its bounding box now that it is in the world 118 // redo its bounding box now that it is in the world
119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); 119 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
120 120
121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; 121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); 122 m_mapInfo.terrainBody.ApplyCollisionMask(m_physicsScene);
123 123
124 // Make it so the terrain will not move or be considered for movement. 124 // Make it so the terrain will not move or be considered for movement.
125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); 125 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
126 126
127 return; 127 return;
128 } 128 }
@@ -134,9 +134,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
134 { 134 {
135 if (m_mapInfo.terrainBody.HasPhysicalBody) 135 if (m_mapInfo.terrainBody.HasPhysicalBody)
136 { 136 {
137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); 137 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
138 // Frees both the body and the shape. 138 // Frees both the body and the shape.
139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); 139 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
140 } 140 }
141 } 141 }
142 m_mapInfo = null; 142 m_mapInfo = null;
@@ -155,7 +155,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
155 catch 155 catch
156 { 156 {
157 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 157 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
158 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", 158 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
159 LogHeader, m_mapInfo.terrainRegionBase, pos); 159 LogHeader, m_mapInfo.terrainRegionBase, pos);
160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
161 } 161 }
@@ -165,7 +165,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
165 // The passed position is relative to the base of the region. 165 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos) 166 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 { 167 {
168 return PhysicsScene.SimpleWaterLevel; 168 return m_physicsScene.SimpleWaterLevel;
169 } 169 }
170} 170}
171} 171}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 5240ad8..c4807c4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -50,14 +50,14 @@ public abstract class BSTerrainPhys : IDisposable
50 Mesh = 1 50 Mesh = 1
51 } 51 }
52 52
53 public BSScene PhysicsScene { get; private set; } 53 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this. 54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; } 55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; } 56 public uint ID { get; private set; }
57 57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) 58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 { 59 {
60 PhysicsScene = physicsScene; 60 m_physicsScene = physicsScene;
61 TerrainBase = regionBase; 61 TerrainBase = regionBase;
62 ID = id; 62 ID = id;
63 } 63 }
@@ -86,7 +86,7 @@ public sealed class BSTerrainManager : IDisposable
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
88 // The scene that I am part of 88 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; } 89 private BSScene m_physicsScene { get; set; }
90 90
91 // The ground plane created to keep thing from falling to infinity. 91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane; 92 private BulletBody m_groundPlane;
@@ -113,7 +113,7 @@ public sealed class BSTerrainManager : IDisposable
113 113
114 public BSTerrainManager(BSScene physicsScene) 114 public BSTerrainManager(BSScene physicsScene)
115 { 115 {
116 PhysicsScene = physicsScene; 116 m_physicsScene = physicsScene;
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); 117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118 118
119 // Assume one region of default size 119 // Assume one region of default size
@@ -132,21 +132,21 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
134 { 134 {
135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); 135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
136 // The ground plane is here to catch things that are trying to drop to negative infinity 136 // The ground plane is here to catch things that are trying to drop to negative infinity
137 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); 137 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
138 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 138 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); 139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
140 140
141 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); 141 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
142 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); 142 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
143 // Ground plane does not move 143 // Ground plane does not move
144 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); 144 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
145 // Everything collides with the ground plane. 145 // Everything collides with the ground plane.
146 m_groundPlane.collisionType = CollisionType.Groundplane; 146 m_groundPlane.collisionType = CollisionType.Groundplane;
147 m_groundPlane.ApplyCollisionMask(PhysicsScene); 147 m_groundPlane.ApplyCollisionMask(m_physicsScene);
148 148
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
150 lock (m_terrains) 150 lock (m_terrains)
151 { 151 {
152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
@@ -157,12 +157,12 @@ public sealed class BSTerrainManager : IDisposable
157 // Release all the terrain structures we might have allocated 157 // Release all the terrain structures we might have allocated
158 public void ReleaseGroundPlaneAndTerrain() 158 public void ReleaseGroundPlaneAndTerrain()
159 { 159 {
160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); 160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
161 if (m_groundPlane.HasPhysicalBody) 161 if (m_groundPlane.HasPhysicalBody)
162 { 162 {
163 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 163 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
164 { 164 {
165 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); 165 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
166 } 166 }
167 m_groundPlane.Clear(); 167 m_groundPlane.Clear();
168 } 168 }
@@ -188,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable
188 float[] localHeightMap = heightMap; 188 float[] localHeightMap = heightMap;
189 // If there are multiple requests for changes to the same terrain between ticks, 189 // If there are multiple requests for changes to the same terrain between ticks,
190 // only do that last one. 190 // only do that last one.
191 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() 191 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
192 { 192 {
193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
194 { 194 {
@@ -219,7 +219,7 @@ public sealed class BSTerrainManager : IDisposable
219 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 219 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
220 { 220 {
221 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. 221 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
222 PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() 222 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
223 { 223 {
224 UpdateTerrain(id, heightMap, minCoords, maxCoords); 224 UpdateTerrain(id, heightMap, minCoords, maxCoords);
225 }); 225 });
@@ -318,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable
318 // TODO: redo terrain implementation selection to allow other base types than heightMap. 318 // TODO: redo terrain implementation selection to allow other base types than heightMap.
319 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 319 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
320 { 320 {
321 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 321 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
322 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 322 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
323 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); 323 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
324 BSTerrainPhys newTerrainPhys = null; 324 BSTerrainPhys newTerrainPhys = null;
325 switch ((int)BSParam.TerrainImplementation) 325 switch ((int)BSParam.TerrainImplementation)
326 { 326 {
327 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 327 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
328 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 328 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
329 heightMap, minCoords, maxCoords); 329 heightMap, minCoords, maxCoords);
330 break; 330 break;
331 case (int)BSTerrainPhys.TerrainImplementation.Mesh: 331 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
332 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, 332 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
333 heightMap, minCoords, maxCoords); 333 heightMap, minCoords, maxCoords);
334 break; 334 break;
335 default: 335 default:
336 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 336 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
337 LogHeader, 337 LogHeader,
338 (int)BSParam.TerrainImplementation, 338 (int)BSParam.TerrainImplementation,
339 BSParam.TerrainImplementation, 339 BSParam.TerrainImplementation,
340 PhysicsScene.RegionName, terrainRegionBase); 340 m_physicsScene.RegionName, terrainRegionBase);
341 break; 341 break;
342 } 342 }
343 return newTerrainPhys; 343 return newTerrainPhys;
@@ -429,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable
429 } 429 }
430 else 430 else
431 { 431 {
432 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 432 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
433 LogHeader, PhysicsScene.RegionName, tX, tY); 433 LogHeader, m_physicsScene.RegionName, tX, tY);
434 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", 434 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
435 BSScene.DetailLogZero, pos, terrainBaseXYZ); 435 BSScene.DetailLogZero, pos, terrainBaseXYZ);
436 } 436 }
@@ -451,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable
451 } 451 }
452 else 452 else
453 { 453 {
454 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", 454 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
455 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); 455 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
456 } 456 }
457 return ret; 457 return ret;
458 } 458 }
@@ -564,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable
564 564
565 private void DetailLog(string msg, params Object[] args) 565 private void DetailLog(string msg, params Object[] args)
566 { 566 {
567 PhysicsScene.PhysicsLogging.Write(msg, args); 567 m_physicsScene.PhysicsLogging.Write(msg, args);
568 } 568 }
569} 569}
570} 570}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index 2ce1513..e4ca098 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -51,7 +51,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
51 BulletShape m_terrainShape; 51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody; 52 BulletBody m_terrainBody;
53 53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) 54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id) 55 : base(physicsScene, regionBase, id)
56 { 56 {
57 } 57 }
@@ -62,7 +62,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
62 } 62 }
63 63
64 // Create terrain mesh from a heightmap. 64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords) 66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id) 67 : base(physicsScene, regionBase, id)
68 { 68 {
@@ -80,7 +80,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
80 if (BSParam.TerrainMeshMagnification == 1) 80 if (BSParam.TerrainMeshMagnification == 1)
81 { 81 {
82 // If a magnification of one, use the old routine that is tried and true. 82 // If a magnification of one, use the old routine that is tried and true.
83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, 83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size 84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh 85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices); 86 out indicesCount, out indices, out verticesCount, out vertices);
@@ -88,7 +88,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 else 88 else
89 { 89 {
90 // Other magnifications use the newer routine 90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene, 91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size 92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification, 93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize, 94 physicsScene.TerrainManager.DefaultRegionSize,
@@ -98,21 +98,21 @@ public sealed class BSTerrainMesh : BSTerrainPhys
98 if (!meshCreationSuccess) 98 if (!meshCreationSuccess)
99 { 99 {
100 // DISASTER!! 100 // DISASTER!!
101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); 101 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
102 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); 102 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
103 // Something is very messed up and a crash is in our future. 103 // Something is very messed up and a crash is in our future.
104 return; 104 return;
105 } 105 }
106 106
107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", 107 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); 108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
109 109
110 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); 110 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape) 111 if (!m_terrainShape.HasPhysicalShape)
112 { 112 {
113 // DISASTER!! 113 // DISASTER!!
114 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); 114 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
115 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); 115 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
116 // Something is very messed up and a crash is in our future. 116 // Something is very messed up and a crash is in our future.
117 return; 117 return;
118 } 118 }
@@ -120,52 +120,52 @@ public sealed class BSTerrainMesh : BSTerrainPhys
120 Vector3 pos = regionBase; 120 Vector3 pos = regionBase;
121 Quaternion rot = Quaternion.Identity; 121 Quaternion rot = Quaternion.Identity;
122 122
123 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); 123 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
124 if (!m_terrainBody.HasPhysicalBody) 124 if (!m_terrainBody.HasPhysicalBody)
125 { 125 {
126 // DISASTER!! 126 // DISASTER!!
127 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 127 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
128 // Something is very messed up and a crash is in our future. 128 // Something is very messed up and a crash is in our future.
129 return; 129 return;
130 } 130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); 131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
132 132
133 // Set current terrain attributes 133 // Set current terrain attributes
134 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); 134 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
135 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); 135 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
136 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); 136 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
137 PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); 137 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
138 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); 138 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
139 139
140 // Static objects are not very massive. 140 // Static objects are not very massive.
141 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); 141 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
142 142
143 // Put the new terrain to the world of physical objects 143 // Put the new terrain to the world of physical objects
144 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); 144 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
145 145
146 // Redo its bounding box now that it is in the world 146 // Redo its bounding box now that it is in the world
147 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); 147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
148 148
149 m_terrainBody.collisionType = CollisionType.Terrain; 149 m_terrainBody.collisionType = CollisionType.Terrain;
150 m_terrainBody.ApplyCollisionMask(PhysicsScene); 150 m_terrainBody.ApplyCollisionMask(m_physicsScene);
151 151
152 if (BSParam.UseSingleSidedMeshes) 152 if (BSParam.UseSingleSidedMeshes)
153 { 153 {
154 PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); 154 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); 155 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 } 156 }
157 157
158 // Make it so the terrain will not move or be considered for movement. 158 // Make it so the terrain will not move or be considered for movement.
159 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); 159 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
160 } 160 }
161 161
162 public override void Dispose() 162 public override void Dispose()
163 { 163 {
164 if (m_terrainBody.HasPhysicalBody) 164 if (m_terrainBody.HasPhysicalBody)
165 { 165 {
166 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); 166 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
167 // Frees both the body and the shape. 167 // Frees both the body and the shape.
168 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); 168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
169 m_terrainBody.Clear(); 169 m_terrainBody.Clear();
170 m_terrainShape.Clear(); 170 m_terrainShape.Clear();
171 } 171 }
@@ -185,7 +185,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
185 catch 185 catch
186 { 186 {
187 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 187 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
188 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", 188 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
189 LogHeader, TerrainBase, pos); 189 LogHeader, TerrainBase, pos);
190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
191 } 191 }
@@ -195,7 +195,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
195 // The passed position is relative to the base of the region. 195 // The passed position is relative to the base of the region.
196 public override float GetWaterLevelAtXYZ(Vector3 pos) 196 public override float GetWaterLevelAtXYZ(Vector3 pos)
197 { 197 {
198 return PhysicsScene.SimpleWaterLevel; 198 return m_physicsScene.SimpleWaterLevel;
199 } 199 }
200 200
201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
index 8012d91..d5060e3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -104,11 +104,11 @@ public class BulletShape
104{ 104{
105 public BulletShape() 105 public BulletShape()
106 { 106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN; 107 shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; 108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false; 109 isNativeShape = false;
110 } 110 }
111 public BSPhysicsShapeType type; 111 public BSPhysicsShapeType shapeType;
112 public System.UInt64 shapeKey; 112 public System.UInt64 shapeKey;
113 public bool isNativeShape; 113 public bool isNativeShape;
114 114
@@ -133,7 +133,7 @@ public class BulletShape
133 buff.Append("<p="); 133 buff.Append("<p=");
134 buff.Append(AddrString); 134 buff.Append(AddrString);
135 buff.Append(",s="); 135 buff.Append(",s=");
136 buff.Append(type.ToString()); 136 buff.Append(shapeType.ToString());
137 buff.Append(",k="); 137 buff.Append(",k=");
138 buff.Append(shapeKey.ToString("X")); 138 buff.Append(shapeKey.ToString("X"));
139 buff.Append(",n="); 139 buff.Append(",n=");
@@ -224,42 +224,42 @@ public static class BulletSimData
224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code 224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
225// but, instead, use references to this dictionary. Finding and debugging 225// but, instead, use references to this dictionary. Finding and debugging
226// collision flag problems will be made easier. 226// collision flag problems will be made easier.
227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks 227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>() 228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
229{ 229{
230 { CollisionType.Avatar, 230 { CollisionType.Avatar,
231 new CollisionTypeFilterGroup(CollisionType.Avatar, 231 new CollisionTypeFilterGroup(CollisionType.Avatar,
232 (uint)CollisionFilterGroups.BCharacterGroup, 232 (uint)CollisionFilterGroups.BCharacterGroup,
233 (uint)CollisionFilterGroups.BAllGroup) 233 (uint)CollisionFilterGroups.BAllGroup)
234 }, 234 },
235 { CollisionType.Groundplane, 235 { CollisionType.Groundplane,
236 new CollisionTypeFilterGroup(CollisionType.Groundplane, 236 new CollisionTypeFilterGroup(CollisionType.Groundplane,
237 (uint)CollisionFilterGroups.BGroundPlaneGroup, 237 (uint)CollisionFilterGroups.BGroundPlaneGroup,
238 (uint)CollisionFilterGroups.BAllGroup) 238 (uint)CollisionFilterGroups.BAllGroup)
239 }, 239 },
240 { CollisionType.Terrain, 240 { CollisionType.Terrain,
241 new CollisionTypeFilterGroup(CollisionType.Terrain, 241 new CollisionTypeFilterGroup(CollisionType.Terrain,
242 (uint)CollisionFilterGroups.BTerrainGroup, 242 (uint)CollisionFilterGroups.BTerrainGroup,
243 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) 243 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
244 }, 244 },
245 { CollisionType.Static, 245 { CollisionType.Static,
246 new CollisionTypeFilterGroup(CollisionType.Static, 246 new CollisionTypeFilterGroup(CollisionType.Static,
247 (uint)CollisionFilterGroups.BStaticGroup, 247 (uint)CollisionFilterGroups.BStaticGroup,
248 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 248 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
249 }, 249 },
250 { CollisionType.Dynamic, 250 { CollisionType.Dynamic,
251 new CollisionTypeFilterGroup(CollisionType.Dynamic, 251 new CollisionTypeFilterGroup(CollisionType.Dynamic,
252 (uint)CollisionFilterGroups.BSolidGroup, 252 (uint)CollisionFilterGroups.BSolidGroup,
253 (uint)(CollisionFilterGroups.BAllGroup)) 253 (uint)(CollisionFilterGroups.BAllGroup))
254 }, 254 },
255 { CollisionType.VolumeDetect, 255 { CollisionType.VolumeDetect,
256 new CollisionTypeFilterGroup(CollisionType.VolumeDetect, 256 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
257 (uint)CollisionFilterGroups.BSensorTrigger, 257 (uint)CollisionFilterGroups.BSensorTrigger,
258 (uint)(~CollisionFilterGroups.BSensorTrigger)) 258 (uint)(~CollisionFilterGroups.BSensorTrigger))
259 }, 259 },
260 { CollisionType.LinksetChild, 260 { CollisionType.LinksetChild,
261 new CollisionTypeFilterGroup(CollisionType.LinksetChild, 261 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
262 (uint)CollisionFilterGroups.BLinksetChildGroup, 262 (uint)CollisionFilterGroups.BLinksetChildGroup,
263 (uint)(CollisionFilterGroups.BNoneGroup)) 263 (uint)(CollisionFilterGroups.BNoneGroup))
264 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 264 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
265 }, 265 },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index 1284ae7..5792ae6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -1,3 +1,12 @@
1PROBLEMS TO LOOK INTO
2=================================================
3Nebadon vehicle ride, get up, ride again. Second time vehicle does not act correctly.
4 Have to rez new vehicle and delete the old to fix situation.
5Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd
6 position state where it will not settle onto ground properly, etc
7Two of Nebadon vehicles in a sim max the CPU. This is new.
8A sitting, active vehicle bobs up and down a small amount.
9
1CURRENT PRIORITIES 10CURRENT PRIORITIES
2================================================= 11=================================================
3Use the HACD convex hull routine in Bullet rather than the C# version. 12Use the HACD convex hull routine in Bullet rather than the C# version.
@@ -11,6 +20,8 @@ Deleting a linkset while standing on the root will leave the physical shape of t
11Linkset child rotations. 20Linkset child rotations.
12 Nebadon spiral tube has middle sections which are rotated wrong. 21 Nebadon spiral tube has middle sections which are rotated wrong.
13 Select linked spiral tube. Delink and note where the middle section ends up. 22 Select linked spiral tube. Delink and note where the middle section ends up.
23Refarb compound linkset creation to create a pseudo-root for center-of-mass
24 Let children change their shape to physical indendently and just add shapes to compound
14Vehicle angular vertical attraction 25Vehicle angular vertical attraction
15vehicle angular banking 26vehicle angular banking
16Center-of-gravity 27Center-of-gravity
@@ -27,14 +38,13 @@ llLookAt
27Avatars walking up stairs (HALF DONE) 38Avatars walking up stairs (HALF DONE)
28Avatar movement 39Avatar movement
29 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) 40 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
30 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) 41 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE)
31 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) 42 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
32Vehicle script tuning/debugging 43Vehicle script tuning/debugging
33 Avanti speed script 44 Avanti speed script
34 Weapon shooter script 45 Weapon shooter script
35Move material definitions (friction, ...) into simulator. 46Move material definitions (friction, ...) into simulator.
36Add material densities to the material types. 47Add material densities to the material types.
37Terrain detail: double terrain mesh detail
38One sided meshes? Should terrain be built into a closed shape? 48One sided meshes? Should terrain be built into a closed shape?
39 When meshes get partially wedged into the terrain, they cannot push themselves out. 49 When meshes get partially wedged into the terrain, they cannot push themselves out.
40 It is possible that Bullet processes collisions whether entering or leaving a mesh. 50 It is possible that Bullet processes collisions whether entering or leaving a mesh.
@@ -42,6 +52,9 @@ One sided meshes? Should terrain be built into a closed shape?
42 52
43VEHICLES TODO LIST: 53VEHICLES TODO LIST:
44================================================= 54=================================================
55LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
56 What are the limits in SL?
57 Same for other velocity settings.
45UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: 58UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
46 https://github.com/UbitUmarov/Ubit-opensim 59 https://github.com/UbitUmarov/Ubit-opensim
47Border crossing with linked vehicle causes crash 60Border crossing with linked vehicle causes crash
@@ -347,4 +360,5 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
347 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. 360 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
348Nebadon vehicles turning funny in arena (DONE) 361Nebadon vehicles turning funny in arena (DONE)
349Lock axis (DONE 20130401) 362Lock axis (DONE 20130401)
363Terrain detail: double terrain mesh detail (DONE)
350 364
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 35ae44c..b9a217b 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
51 public interface IScriptWorkItem 51 public interface IScriptWorkItem
52 { 52 {
53 bool Cancel(); 53 bool Cancel();
54 void Abort(); 54 bool Abort();
55 55
56 /// <summary> 56 /// <summary>
57 /// Wait for the work item to complete. 57 /// Wait for the work item to complete.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 1e6db43..887a317 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -564,9 +564,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
564 564
565 public bool Stop(int timeout) 565 public bool Stop(int timeout)
566 { 566 {
567// m_log.DebugFormat( 567 if (DebugLevel >= 1)
568// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", 568 m_log.DebugFormat(
569// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); 569 "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
570 ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
570 571
571 IScriptWorkItem workItem; 572 IScriptWorkItem workItem;
572 573
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 0d9babb..5804aa8 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -483,7 +483,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
483 /// <param name="instance"></param> 483 /// <param name="instance"></param>
484 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> 484 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
485 private void HandleScriptsAction<TKey>( 485 private void HandleScriptsAction<TKey>(
486 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) 486 string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector)
487 { 487 {
488 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 488 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
489 return; 489 return;
@@ -1517,7 +1517,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1517 startInfo.MaxWorkerThreads = maxThreads; 1517 startInfo.MaxWorkerThreads = maxThreads;
1518 startInfo.MinWorkerThreads = minThreads; 1518 startInfo.MinWorkerThreads = minThreads;
1519 startInfo.ThreadPriority = threadPriority;; 1519 startInfo.ThreadPriority = threadPriority;;
1520 startInfo.StackSize = stackSize; 1520 startInfo.MaxStackSize = stackSize;
1521 startInfo.StartSuspended = true; 1521 startInfo.StartSuspended = true;
1522 1522
1523 m_ThreadPool = new SmartThreadPool(startInfo); 1523 m_ThreadPool = new SmartThreadPool(startInfo);
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
index 8dd7677..9d9dee1 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
52 return wr.Cancel(); 52 return wr.Cancel();
53 } 53 }
54 54
55 public void Abort() 55 public bool Abort()
56 { 56 {
57 wr.Abort(); 57 return wr.Cancel(true);
58 } 58 }
59 59
60 public bool Wait(int t) 60 public bool Wait(int t)
61 { 61 {
62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the 62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an 63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
64 // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 64 // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8
65 // (or very likely other versions of Mono at least up until 3.0.3). 65 // (or very likely other versions of Mono at least up until 3.0.3).
66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); 66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
67 } 67 }
diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs
index 7c8e6b7..b13c87d 100644
--- a/OpenSim/Server/Base/ServicesServerBase.cs
+++ b/OpenSim/Server/Base/ServicesServerBase.cs
@@ -171,11 +171,6 @@ namespace OpenSim.Server.Base
171 171
172 m_console = MainConsole.Instance; 172 m_console = MainConsole.Instance;
173 173
174 // Configure the appenders for log4net
175 //
176 OpenSimAppender consoleAppender = null;
177 FileAppender fileAppender = null;
178
179 if (logConfig != null) 174 if (logConfig != null)
180 { 175 {
181 FileInfo cfg = new FileInfo(logConfig); 176 FileInfo cfg = new FileInfo(logConfig);
diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
index a1794c9..b3b75af 100644
--- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
@@ -218,12 +218,37 @@ namespace OpenSim.Tests.Common
218 public static InventoryFolderBase CreateInventoryFolder( 218 public static InventoryFolderBase CreateInventoryFolder(
219 IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders) 219 IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders)
220 { 220 {
221 return CreateInventoryFolder(inventoryService, userId, UUID.Random(), path, useExistingFolders);
222 }
223
224 /// <summary>
225 /// Create inventory folders starting from the user's root folder.
226 /// </summary>
227 /// <param name="inventoryService"></param>
228 /// <param name="userId"></param>
229 /// <param name="folderId"></param>
230 /// <param name="path">
231 /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER
232 /// </param>
233 /// <param name="useExistingFolders">
234 /// If true, then folders in the path which already the same name are
235 /// used. This applies to the terminal folder as well.
236 /// If false, then all folders in the path are created, even if there is already a folder at a particular
237 /// level with the same name.
238 /// </param>
239 /// <returns>
240 /// The folder created. If the path contains multiple folders then the last one created is returned.
241 /// Will return null if the root folder could not be found.
242 /// </returns>
243 public static InventoryFolderBase CreateInventoryFolder(
244 IInventoryService inventoryService, UUID userId, UUID folderId, string path, bool useExistingFolders)
245 {
221 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); 246 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
222 247
223 if (null == rootFolder) 248 if (null == rootFolder)
224 return null; 249 return null;
225 250
226 return CreateInventoryFolder(inventoryService, rootFolder, path, useExistingFolders); 251 return CreateInventoryFolder(inventoryService, folderId, rootFolder, path, useExistingFolders);
227 } 252 }
228 253
229 /// <summary> 254 /// <summary>
@@ -235,6 +260,7 @@ namespace OpenSim.Tests.Common
235 /// TODO: May need to make it an option to create duplicate folders. 260 /// TODO: May need to make it an option to create duplicate folders.
236 /// </remarks> 261 /// </remarks>
237 /// <param name="inventoryService"></param> 262 /// <param name="inventoryService"></param>
263 /// <param name="folderId">ID of the folder to create</param>
238 /// <param name="parentFolder"></param> 264 /// <param name="parentFolder"></param>
239 /// <param name="path"> 265 /// <param name="path">
240 /// The folder to create. 266 /// The folder to create.
@@ -249,7 +275,7 @@ namespace OpenSim.Tests.Common
249 /// The folder created. If the path contains multiple folders then the last one created is returned. 275 /// The folder created. If the path contains multiple folders then the last one created is returned.
250 /// </returns> 276 /// </returns>
251 public static InventoryFolderBase CreateInventoryFolder( 277 public static InventoryFolderBase CreateInventoryFolder(
252 IInventoryService inventoryService, InventoryFolderBase parentFolder, string path, bool useExistingFolders) 278 IInventoryService inventoryService, UUID folderId, InventoryFolderBase parentFolder, string path, bool useExistingFolders)
253 { 279 {
254 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); 280 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None);
255 281
@@ -262,9 +288,16 @@ namespace OpenSim.Tests.Common
262 { 288 {
263// Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name); 289// Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name);
264 290
291 UUID folderIdForCreate;
292
293 if (components.Length > 1)
294 folderIdForCreate = UUID.Random();
295 else
296 folderIdForCreate = folderId;
297
265 folder 298 folder
266 = new InventoryFolderBase( 299 = new InventoryFolderBase(
267 UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); 300 folderIdForCreate, components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0);
268 301
269 inventoryService.AddFolder(folder); 302 inventoryService.AddFolder(folder);
270 } 303 }
@@ -274,7 +307,7 @@ namespace OpenSim.Tests.Common
274// } 307// }
275 308
276 if (components.Length > 1) 309 if (components.Length > 1)
277 return CreateInventoryFolder(inventoryService, folder, components[1], useExistingFolders); 310 return CreateInventoryFolder(inventoryService, folderId, folder, components[1], useExistingFolders);
278 else 311 else
279 return folder; 312 return folder;
280 } 313 }
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index d26e3f7..41402a4 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -61,6 +61,7 @@ namespace OpenSim.Tests.Common.Mock
61 // Test client specific events - for use by tests to implement some IClientAPI behaviour. 61 // Test client specific events - for use by tests to implement some IClientAPI behaviour.
62 public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion; 62 public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion;
63 public event Action<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour; 63 public event Action<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour;
64 public event Action<GridInstantMessage> OnReceivedInstantMessage;
64 65
65// disable warning: public events, part of the public API 66// disable warning: public events, part of the public API
66#pragma warning disable 67 67#pragma warning disable 67
@@ -484,6 +485,18 @@ namespace OpenSim.Tests.Common.Mock
484 OnCompleteMovementToRegion(this, true); 485 OnCompleteMovementToRegion(this, true);
485 } 486 }
486 487
488 /// <summary>
489 /// Emulate sending an IM from the viewer to the simulator.
490 /// </summary>
491 /// <param name='im'></param>
492 public void HandleImprovedInstantMessage(GridInstantMessage im)
493 {
494 ImprovedInstantMessage handlerInstantMessage = OnInstantMessage;
495
496 if (handlerInstantMessage != null)
497 handlerInstantMessage(this, im);
498 }
499
487 public virtual void ActivateGesture(UUID assetId, UUID gestureId) 500 public virtual void ActivateGesture(UUID assetId, UUID gestureId)
488 { 501 {
489 } 502 }
@@ -538,7 +551,8 @@ namespace OpenSim.Tests.Common.Mock
538 551
539 public void SendInstantMessage(GridInstantMessage im) 552 public void SendInstantMessage(GridInstantMessage im)
540 { 553 {
541 554 if (OnReceivedInstantMessage != null)
555 OnReceivedInstantMessage(im);
542 } 556 }
543 557
544 public void SendGenericMessage(string method, UUID invoice, List<string> message) 558 public void SendGenericMessage(string method, UUID invoice, List<string> message)
diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
index ccbdf81..30b1f38 100644
--- a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
+++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
@@ -53,6 +53,9 @@ namespace OpenSim.Tests.Common.Mock
53 53
54 public XInventoryFolder[] GetFolders(string[] fields, string[] vals) 54 public XInventoryFolder[] GetFolders(string[] fields, string[] vals)
55 { 55 {
56// Console.WriteLine(
57// "Requesting folders, fields {0}, vals {1}", string.Join(",", fields), string.Join(",", vals));
58
56 List<XInventoryFolder> origFolders 59 List<XInventoryFolder> origFolders
57 = Get<XInventoryFolder>(fields, vals, m_allFolders.Values.ToList()); 60 = Get<XInventoryFolder>(fields, vals, m_allFolders.Values.ToList());
58 61
@@ -104,7 +107,30 @@ namespace OpenSim.Tests.Common.Mock
104 } 107 }
105 108
106 public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); } 109 public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); }
107 public bool MoveFolder(string id, string newParent) { throw new NotImplementedException(); } 110
111 public bool MoveFolder(string id, string newParent)
112 {
113 // Don't use GetFolders() here - it takes a clone!
114 XInventoryFolder folder = m_allFolders[new UUID(id)];
115
116 if (folder == null)
117 return false;
118
119 folder.parentFolderID = new UUID(newParent);
120
121 XInventoryFolder[] newParentFolders
122 = GetFolders(new string[] { "folderID" }, new string[] { folder.parentFolderID.ToString() });
123
124// Console.WriteLine(
125// "Moved folder {0} {1}, to {2} {3}",
126// folder.folderName, folder.folderID, newParentFolders[0].folderName, folder.parentFolderID);
127
128 // TODO: Really need to implement folder version incrementing, though this should be common code anyway,
129 // not reimplemented in each db plugin.
130
131 return true;
132 }
133
108 public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); } 134 public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); }
109 public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); } 135 public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); }
110 } 136 }
diff --git a/ThirdParty/SmartThreadPool/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/AssemblyInfo.cs
deleted file mode 100644
index e2465b0..0000000
--- a/ThirdParty/SmartThreadPool/AssemblyInfo.cs
+++ /dev/null
@@ -1,61 +0,0 @@
1using System;
2using System.Reflection;
3using System.Runtime.InteropServices;
4
5//
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9//
10[assembly: AssemblyTitle("")]
11[assembly: AssemblyDescription("")]
12[assembly: AssemblyConfiguration("")]
13[assembly: AssemblyCompany("")]
14[assembly: AssemblyProduct("")]
15[assembly: AssemblyCopyright("")]
16[assembly: AssemblyTrademark("")]
17[assembly: AssemblyCulture("")]
18[assembly: ComVisible(false)]
19[assembly: CLSCompliant(true)]
20
21//
22// Version information for an assembly consists of the following four values:
23//
24// Major Version
25// Minor Version
26// Build Number
27// Revision
28//
29// You can specify all the values or you can default the Revision and Build Numbers
30// by using the '*' as shown below:
31
32[assembly: AssemblyVersion("0.7.6.*")]
33
34//
35// In order to sign your assembly you must specify a key to use. Refer to the
36// Microsoft .NET Framework documentation for more information on assembly signing.
37//
38// Use the attributes below to control which key is used for signing.
39//
40// Notes:
41// (*) If no key is specified, the assembly is not signed.
42// (*) KeyName refers to a key that has been installed in the Crypto Service
43// Provider (CSP) on your machine. KeyFile refers to a file which contains
44// a key.
45// (*) If the KeyFile and the KeyName values are both specified, the
46// following processing occurs:
47// (1) If the KeyName can be found in the CSP, that key is used.
48// (2) If the KeyName does not exist and the KeyFile does exist, the key
49// in the KeyFile is installed into the CSP and used.
50// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
51// When specifying the KeyFile, the location of the KeyFile should be
52// relative to the project output directory which is
53// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
54// located in the project directory, you would specify the AssemblyKeyFile
55// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
56// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
57// documentation for more information on this.
58//
59[assembly: AssemblyDelaySign(false)]
60[assembly: AssemblyKeyFile("")]
61[assembly: AssemblyKeyName("")]
diff --git a/ThirdParty/SmartThreadPool/CallerThreadContext.cs b/ThirdParty/SmartThreadPool/CallerThreadContext.cs
index 6ea53f6..e63add5 100644
--- a/ThirdParty/SmartThreadPool/CallerThreadContext.cs
+++ b/ThirdParty/SmartThreadPool/CallerThreadContext.cs
@@ -1,3 +1,6 @@
1
2#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
3
1using System; 4using System;
2using System.Diagnostics; 5using System.Diagnostics;
3using System.Threading; 6using System.Threading;
@@ -6,218 +9,130 @@ using System.Web;
6using System.Runtime.Remoting.Messaging; 9using System.Runtime.Remoting.Messaging;
7 10
8 11
9namespace Amib.Threading 12namespace Amib.Threading.Internal
10{ 13{
11 #region CallerThreadContext class 14#region CallerThreadContext class
12
13 /// <summary>
14 /// This class stores the caller call context in order to restore
15 /// it when the work item is executed in the thread pool environment.
16 /// </summary>
17 internal class CallerThreadContext
18 {
19 #region Prepare reflection information
20
21 // Cached type information.
22 private static MethodInfo getLogicalCallContextMethodInfo =
23 typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
24
25 private static MethodInfo setLogicalCallContextMethodInfo =
26 typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
27 15
28 private static string HttpContextSlotName = GetHttpContextSlotName(); 16 /// <summary>
17 /// This class stores the caller call context in order to restore
18 /// it when the work item is executed in the thread pool environment.
19 /// </summary>
20 internal class CallerThreadContext
21 {
22#region Prepare reflection information
29 23
30 private static string GetHttpContextSlotName() 24 // Cached type information.
31 { 25 private static readonly MethodInfo getLogicalCallContextMethodInfo =
32 FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); 26 typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
33 27
34 if( fi != null ) 28 private static readonly MethodInfo setLogicalCallContextMethodInfo =
35 return (string)fi.GetValue(null); 29 typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
36 else // Use the default "HttpContext" slot name
37 return "HttpContext";
38 }
39 30
40 #endregion 31 private static string HttpContextSlotName = GetHttpContextSlotName();
41
42 #region Private fields
43
44 private HttpContext _httpContext = null;
45 private LogicalCallContext _callContext = null;
46
47 #endregion
48 32
49 /// <summary> 33 private static string GetHttpContextSlotName()
50 /// Constructor 34 {
51 /// </summary> 35 FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
52 private CallerThreadContext()
53 {
54 }
55 36
56 public bool CapturedCallContext 37 if (fi != null)
57 {
58 get
59 { 38 {
60 return (null != _callContext); 39 return (string) fi.GetValue(null);
61 } 40 }
62 }
63 41
64 public bool CapturedHttpContext 42 return "HttpContext";
65 { 43 }
66 get
67 {
68 return (null != _httpContext);
69 }
70 }
71
72 /// <summary>
73 /// Captures the current thread context
74 /// </summary>
75 /// <returns></returns>
76 public static CallerThreadContext Capture(
77 bool captureCallContext,
78 bool captureHttpContext)
79 {
80 Debug.Assert(captureCallContext || captureHttpContext);
81
82 CallerThreadContext callerThreadContext = new CallerThreadContext();
83
84 // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
85 // Capture Call Context
86 if(captureCallContext && (getLogicalCallContextMethodInfo != null))
87 {
88 callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
89 if (callerThreadContext._callContext != null)
90 {
91 callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
92 }
93 }
94
95 // Capture httpContext
96 if (captureHttpContext && (null != HttpContext.Current))
97 {
98 callerThreadContext._httpContext = HttpContext.Current;
99 }
100
101 return callerThreadContext;
102 }
103 44
104 /// <summary> 45 #endregion
105 /// Applies the thread context stored earlier
106 /// </summary>
107 /// <param name="callerThreadContext"></param>
108 public static void Apply(CallerThreadContext callerThreadContext)
109 {
110 if (null == callerThreadContext)
111 {
112 throw new ArgumentNullException("callerThreadContext");
113 }
114
115 // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
116 // Restore call context
117 if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
118 {
119 setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
120 }
121
122 // Restore HttpContext
123 if (callerThreadContext._httpContext != null)
124 {
125 CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
126 }
127 }
128 }
129
130 #endregion
131
132}
133 46
47#region Private fields
134 48
135/* 49 private HttpContext _httpContext;
136// Ami Bar 50 private LogicalCallContext _callContext;
137// amibar@gmail.com
138 51
139using System; 52 #endregion
140using System.Threading;
141using System.Globalization;
142using System.Security.Principal;
143using System.Reflection;
144using System.Runtime.Remoting.Contexts;
145 53
146namespace Amib.Threading.Internal 54 /// <summary>
147{ 55 /// Constructor
148 #region CallerThreadContext class 56 /// </summary>
149 57 private CallerThreadContext()
150 /// <summary> 58 {
151 /// This class stores the caller thread context in order to restore 59 }
152 /// it when the work item is executed in the context of the thread 60
153 /// from the pool. 61 public bool CapturedCallContext
154 /// Note that we can't store the thread's CompressedStack, because 62 {
155 /// it throws a security exception 63 get
156 /// </summary> 64 {
157 public class CallerThreadContext 65 return (null != _callContext);
158 { 66 }
159 private CultureInfo _culture = null; 67 }
160 private CultureInfo _cultureUI = null; 68
161 private IPrincipal _principal; 69 public bool CapturedHttpContext
162 private System.Runtime.Remoting.Contexts.Context _context; 70 {
163 71 get
164 private static FieldInfo _fieldInfo = GetFieldInfo(); 72 {
165 73 return (null != _httpContext);
166 private static FieldInfo GetFieldInfo() 74 }
167 { 75 }
168 Type threadType = typeof(Thread); 76
169 return threadType.GetField( 77 /// <summary>
170 "m_Context", 78 /// Captures the current thread context
171 BindingFlags.Instance | BindingFlags.NonPublic); 79 /// </summary>
172 } 80 /// <returns></returns>
173 81 public static CallerThreadContext Capture(
174 /// <summary> 82 bool captureCallContext,
175 /// Constructor 83 bool captureHttpContext)
176 /// </summary> 84 {
177 private CallerThreadContext() 85 Debug.Assert(captureCallContext || captureHttpContext);
178 { 86
179 } 87 CallerThreadContext callerThreadContext = new CallerThreadContext();
180 88
181 /// <summary> 89 // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
182 /// Captures the current thread context 90 // Capture Call Context
183 /// </summary> 91 if(captureCallContext && (getLogicalCallContextMethodInfo != null))
184 /// <returns></returns> 92 {
185 public static CallerThreadContext Capture() 93 callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
186 { 94 if (callerThreadContext._callContext != null)
187 CallerThreadContext callerThreadContext = new CallerThreadContext(); 95 {
188 96 callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
189 Thread thread = Thread.CurrentThread; 97 }
190 callerThreadContext._culture = thread.CurrentCulture; 98 }
191 callerThreadContext._cultureUI = thread.CurrentUICulture; 99
192 callerThreadContext._principal = Thread.CurrentPrincipal; 100 // Capture httpContext
193 callerThreadContext._context = Thread.CurrentContext; 101 if (captureHttpContext && (null != HttpContext.Current))
194 return callerThreadContext; 102 {
195 } 103 callerThreadContext._httpContext = HttpContext.Current;
196 104 }
197 /// <summary> 105
198 /// Applies the thread context stored earlier 106 return callerThreadContext;
199 /// </summary> 107 }
200 /// <param name="callerThreadContext"></param> 108
201 public static void Apply(CallerThreadContext callerThreadContext) 109 /// <summary>
202 { 110 /// Applies the thread context stored earlier
203 Thread thread = Thread.CurrentThread; 111 /// </summary>
204 thread.CurrentCulture = callerThreadContext._culture; 112 /// <param name="callerThreadContext"></param>
205 thread.CurrentUICulture = callerThreadContext._cultureUI; 113 public static void Apply(CallerThreadContext callerThreadContext)
206 Thread.CurrentPrincipal = callerThreadContext._principal; 114 {
207 115 if (null == callerThreadContext)
208 // Uncomment the following block to enable the Thread.CurrentThread 116 {
209/* 117 throw new ArgumentNullException("callerThreadContext");
210 if (null != _fieldInfo) 118 }
211 { 119
212 _fieldInfo.SetValue( 120 // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
213 Thread.CurrentThread, 121 // Restore call context
214 callerThreadContext._context); 122 if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
215 } 123 {
216* / 124 setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
217 } 125 }
218 } 126
127 // Restore HttpContext
128 if (callerThreadContext._httpContext != null)
129 {
130 HttpContext.Current = callerThreadContext._httpContext;
131 //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
132 }
133 }
134 }
219 135
220 #endregion 136 #endregion
221} 137}
222*/ 138#endif
223
diff --git a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs
new file mode 100644
index 0000000..5752957
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs
@@ -0,0 +1,14 @@
1namespace Amib.Threading.Internal
2{
3 internal class CanceledWorkItemsGroup
4 {
5 public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
6
7 public CanceledWorkItemsGroup()
8 {
9 IsCanceled = false;
10 }
11
12 public bool IsCanceled { get; set; }
13 }
14} \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandle.cs b/ThirdParty/SmartThreadPool/EventWaitHandle.cs
new file mode 100644
index 0000000..25be07a
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/EventWaitHandle.cs
@@ -0,0 +1,104 @@
1#if (_WINDOWS_CE)
2
3using System;
4using System.Runtime.InteropServices;
5using System.Threading;
6
7namespace Amib.Threading.Internal
8{
9 /// <summary>
10 /// EventWaitHandle class
11 /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation.
12 /// So I wrote this class to implement these two methods with some of their overloads.
13 /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny.
14 /// Note that this class doesn't even inherit from WaitHandle!
15 /// </summary>
16 public class STPEventWaitHandle
17 {
18 #region Public Constants
19
20 public const int WaitTimeout = Timeout.Infinite;
21
22 #endregion
23
24 #region Private External Constants
25
26 private const Int32 WAIT_FAILED = -1;
27 private const Int32 WAIT_TIMEOUT = 0x102;
28 private const UInt32 INFINITE = 0xFFFFFFFF;
29
30 #endregion
31
32 #region WaitAll and WaitAny
33
34 internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
35 {
36 return waitHandle.WaitOne(millisecondsTimeout, exitContext);
37 }
38
39 private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles)
40 {
41 IntPtr[] nativeHandles = new IntPtr[waitHandles.Length];
42 for (int i = 0; i < waitHandles.Length; i++)
43 {
44 nativeHandles[i] = waitHandles[i].Handle;
45 }
46 return nativeHandles;
47 }
48
49 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
50 {
51 uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
52
53 IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
54
55 int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout);
56
57 if (result == WAIT_TIMEOUT || result == WAIT_FAILED)
58 {
59 return false;
60 }
61
62 return true;
63 }
64
65
66 public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
67 {
68 uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
69
70 IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
71
72 int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout);
73
74 if (result >= 0 && result < waitHandles.Length)
75 {
76 return result;
77 }
78
79 return -1;
80 }
81
82 public static int WaitAny(WaitHandle[] waitHandles)
83 {
84 return WaitAny(waitHandles, Timeout.Infinite, false);
85 }
86
87 public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
88 {
89 int millisecondsTimeout = (int)timeout.TotalMilliseconds;
90
91 return WaitAny(waitHandles, millisecondsTimeout, false);
92 }
93
94 #endregion
95
96 #region External methods
97
98 [DllImport("coredll.dll", SetLastError = true)]
99 public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds);
100
101 #endregion
102 }
103}
104#endif \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs
new file mode 100644
index 0000000..3c9c849
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs
@@ -0,0 +1,82 @@
1using System.Threading;
2
3#if (_WINDOWS_CE)
4using System;
5using System.Runtime.InteropServices;
6#endif
7
8namespace Amib.Threading.Internal
9{
10 /// <summary>
11 /// EventWaitHandleFactory class.
12 /// This is a static class that creates AutoResetEvent and ManualResetEvent objects.
13 /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property
14 /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API.
15 /// Consequently this class creates the needed XxxResetEvent and replaces the handle if
16 /// it's a WindowsCE OS.
17 /// </summary>
18 public static class EventWaitHandleFactory
19 {
20 /// <summary>
21 /// Create a new AutoResetEvent object
22 /// </summary>
23 /// <returns>Return a new AutoResetEvent object</returns>
24 public static AutoResetEvent CreateAutoResetEvent()
25 {
26 AutoResetEvent waitHandle = new AutoResetEvent(false);
27
28#if (_WINDOWS_CE)
29 ReplaceEventHandle(waitHandle, false, false);
30#endif
31
32 return waitHandle;
33 }
34
35 /// <summary>
36 /// Create a new ManualResetEvent object
37 /// </summary>
38 /// <returns>Return a new ManualResetEvent object</returns>
39 public static ManualResetEvent CreateManualResetEvent(bool initialState)
40 {
41 ManualResetEvent waitHandle = new ManualResetEvent(initialState);
42
43#if (_WINDOWS_CE)
44 ReplaceEventHandle(waitHandle, true, initialState);
45#endif
46
47 return waitHandle;
48 }
49
50#if (_WINDOWS_CE)
51
52 /// <summary>
53 /// Replace the event handle
54 /// </summary>
55 /// <param name="waitHandle">The WaitHandle object which its handle needs to be replaced.</param>
56 /// <param name="manualReset">Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)</param>
57 /// <param name="initialState">The initial state of the event</param>
58 private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState)
59 {
60 // Store the old handle
61 IntPtr oldHandle = waitHandle.Handle;
62
63 // Create a new event
64 IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null);
65
66 // Replace the old event with the new event
67 waitHandle.Handle = newHandle;
68
69 // Close the old event
70 CloseHandle (oldHandle);
71 }
72
73 [DllImport("coredll.dll", SetLastError = true)]
74 public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
75
76 //Handle
77 [DllImport("coredll.dll", SetLastError = true)]
78 public static extern bool CloseHandle(IntPtr hObject);
79#endif
80
81 }
82}
diff --git a/ThirdParty/SmartThreadPool/Exceptions.cs b/ThirdParty/SmartThreadPool/Exceptions.cs
index c454709..6c6a88b 100644
--- a/ThirdParty/SmartThreadPool/Exceptions.cs
+++ b/ThirdParty/SmartThreadPool/Exceptions.cs
@@ -1,8 +1,7 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
2#if !(_WINDOWS_CE)
5using System.Runtime.Serialization; 3using System.Runtime.Serialization;
4#endif
6 5
7namespace Amib.Threading 6namespace Amib.Threading
8{ 7{
@@ -11,22 +10,39 @@ namespace Amib.Threading
11 /// <summary> 10 /// <summary>
12 /// Represents an exception in case IWorkItemResult.GetResult has been canceled 11 /// Represents an exception in case IWorkItemResult.GetResult has been canceled
13 /// </summary> 12 /// </summary>
14 [Serializable] 13 public sealed partial class WorkItemCancelException : Exception
15 public sealed class WorkItemCancelException : ApplicationException
16 { 14 {
17 public WorkItemCancelException() : base() 15 public WorkItemCancelException()
18 { 16 {
19 } 17 }
20 18
21 public WorkItemCancelException(string message) : base(message) 19 public WorkItemCancelException(string message)
20 : base(message)
22 { 21 {
23 } 22 }
24 23
25 public WorkItemCancelException(string message, Exception e) : base(message, e) 24 public WorkItemCancelException(string message, Exception e)
25 : base(message, e)
26 { 26 {
27 } 27 }
28 }
28 29
29 public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc) 30 /// <summary>
31 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
32 /// </summary>
33 public sealed partial class WorkItemTimeoutException : Exception
34 {
35 public WorkItemTimeoutException()
36 {
37 }
38
39 public WorkItemTimeoutException(string message)
40 : base(message)
41 {
42 }
43
44 public WorkItemTimeoutException(string message, Exception e)
45 : base(message, e)
30 { 46 {
31 } 47 }
32 } 48 }
@@ -34,22 +50,33 @@ namespace Amib.Threading
34 /// <summary> 50 /// <summary>
35 /// Represents an exception in case IWorkItemResult.GetResult has been timed out 51 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
36 /// </summary> 52 /// </summary>
37 [Serializable] 53 public sealed partial class WorkItemResultException : Exception
38 public sealed class WorkItemTimeoutException : ApplicationException
39 { 54 {
40 public WorkItemTimeoutException() : base() 55 public WorkItemResultException()
41 { 56 {
42 } 57 }
43 58
44 public WorkItemTimeoutException(string message) : base(message) 59 public WorkItemResultException(string message)
60 : base(message)
45 { 61 {
46 } 62 }
47 63
48 public WorkItemTimeoutException(string message, Exception e) : base(message, e) 64 public WorkItemResultException(string message, Exception e)
65 : base(message, e)
49 { 66 {
50 } 67 }
68 }
51 69
52 public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc) 70
71#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
72 /// <summary>
73 /// Represents an exception in case IWorkItemResult.GetResult has been canceled
74 /// </summary>
75 [Serializable]
76 public sealed partial class WorkItemCancelException
77 {
78 public WorkItemCancelException(SerializationInfo si, StreamingContext sc)
79 : base(si, sc)
53 { 80 {
54 } 81 }
55 } 82 }
@@ -58,24 +85,27 @@ namespace Amib.Threading
58 /// Represents an exception in case IWorkItemResult.GetResult has been timed out 85 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
59 /// </summary> 86 /// </summary>
60 [Serializable] 87 [Serializable]
61 public sealed class WorkItemResultException : ApplicationException 88 public sealed partial class WorkItemTimeoutException
62 { 89 {
63 public WorkItemResultException() : base() 90 public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc)
64 { 91 : base(si, sc)
65 }
66
67 public WorkItemResultException(string message) : base(message)
68 {
69 }
70
71 public WorkItemResultException(string message, Exception e) : base(message, e)
72 { 92 {
73 } 93 }
94 }
74 95
75 public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc) 96 /// <summary>
97 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
98 /// </summary>
99 [Serializable]
100 public sealed partial class WorkItemResultException
101 {
102 public WorkItemResultException(SerializationInfo si, StreamingContext sc)
103 : base(si, sc)
76 { 104 {
77 } 105 }
78 } 106 }
79 107
108#endif
109
80 #endregion 110 #endregion
81} 111}
diff --git a/ThirdParty/SmartThreadPool/Interfaces.cs b/ThirdParty/SmartThreadPool/Interfaces.cs
index f1c1fcf..513422f 100644
--- a/ThirdParty/SmartThreadPool/Interfaces.cs
+++ b/ThirdParty/SmartThreadPool/Interfaces.cs
@@ -1,271 +1,628 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
5using System.Threading; 2using System.Threading;
6 3
7namespace Amib.Threading 4namespace Amib.Threading
8{ 5{
9 #region Delegates 6 #region Delegates
7
8 /// <summary>
9 /// A delegate that represents the method to run as the work item
10 /// </summary>
11 /// <param name="state">A state object for the method to run</param>
12 public delegate object WorkItemCallback(object state);
13
14 /// <summary>
15 /// A delegate to call after the WorkItemCallback completed
16 /// </summary>
17 /// <param name="wir">The work item result object</param>
18 public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
10 19
11 /// <summary> 20 /// <summary>
12 /// A delegate that represents the method to run as the work item 21 /// A delegate to call after the WorkItemCallback completed
13 /// </summary> 22 /// </summary>
14 /// <param name="state">A state object for the method to run</param> 23 /// <param name="wir">The work item result object</param>
15 public delegate object WorkItemCallback(object state); 24 public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir);
25
26 /// <summary>
27 /// A delegate to call when a WorkItemsGroup becomes idle
28 /// </summary>
29 /// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
30 public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
16 31
17 /// <summary> 32 /// <summary>
18 /// A delegate to call after the WorkItemCallback completed 33 /// A delegate to call after a thread is created, but before
34 /// it's first use.
19 /// </summary> 35 /// </summary>
20 /// <param name="wir">The work item result object</param> 36 public delegate void ThreadInitializationHandler();
21 public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
22 37
23 /// <summary> 38 /// <summary>
24 /// A delegate to call when a WorkItemsGroup becomes idle 39 /// A delegate to call when a thread is about to exit, after
40 /// it is no longer belong to the pool.
25 /// </summary> 41 /// </summary>
26 /// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param> 42 public delegate void ThreadTerminationHandler();
27 public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
28 43
29 #endregion 44 #endregion
30 45
31 #region WorkItem Priority 46 #region WorkItem Priority
32 47
33 public enum WorkItemPriority 48 /// <summary>
34 { 49 /// Defines the availeable priorities of a work item.
35 Lowest, 50 /// The higher the priority a work item has, the sooner
36 BelowNormal, 51 /// it will be executed.
37 Normal, 52 /// </summary>
38 AboveNormal, 53 public enum WorkItemPriority
39 Highest, 54 {
40 } 55 Lowest,
56 BelowNormal,
57 Normal,
58 AboveNormal,
59 Highest,
60 }
61
62 #endregion
63
64 #region IWorkItemsGroup interface
65
66 /// <summary>
67 /// IWorkItemsGroup interface
68 /// Created by SmartThreadPool.CreateWorkItemsGroup()
69 /// </summary>
70 public interface IWorkItemsGroup
71 {
72 /// <summary>
73 /// Get/Set the name of the WorkItemsGroup
74 /// </summary>
75 string Name { get; set; }
41 76
42 #endregion 77 /// <summary>
78 /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
79 /// </summary>
80 int Concurrency { get; set; }
81
82 /// <summary>
83 /// Get the number of work items waiting in the queue.
84 /// </summary>
85 int WaitingCallbacks { get; }
43 86
44 #region IHasWorkItemPriority interface 87 /// <summary>
88 /// Get an array with all the state objects of the currently running items.
89 /// The array represents a snap shot and impact performance.
90 /// </summary>
91 object[] GetStates();
45 92
46 public interface IHasWorkItemPriority 93 /// <summary>
47 { 94 /// Get the WorkItemsGroup start information
48 WorkItemPriority WorkItemPriority { get; } 95 /// </summary>
49 } 96 WIGStartInfo WIGStartInfo { get; }
50 97
51 #endregion 98 /// <summary>
99 /// Starts to execute work items
100 /// </summary>
101 void Start();
52 102
53 #region IWorkItemsGroup interface 103 /// <summary>
104 /// Cancel all the work items.
105 /// Same as Cancel(false)
106 /// </summary>
107 void Cancel();
54 108
55 /// <summary>
56 /// IWorkItemsGroup interface
57 /// </summary>
58 public interface IWorkItemsGroup
59 {
60 /// <summary> 109 /// <summary>
61 /// Get/Set the name of the WorkItemsGroup 110 /// Cancel all work items using thread abortion
62 /// </summary> 111 /// </summary>
63 string Name { get; set; } 112 /// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
113 void Cancel(bool abortExecution);
64 114
115 /// <summary>
116 /// Wait for all work item to complete.
117 /// </summary>
118 void WaitForIdle();
119
120 /// <summary>
121 /// Wait for all work item to complete, until timeout expired
122 /// </summary>
123 /// <param name="timeout">How long to wait for the work items to complete</param>
124 /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
125 bool WaitForIdle(TimeSpan timeout);
126
127 /// <summary>
128 /// Wait for all work item to complete, until timeout expired
129 /// </summary>
130 /// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param>
131 /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
132 bool WaitForIdle(int millisecondsTimeout);
133
134 /// <summary>
135 /// IsIdle is true when there are no work items running or queued.
136 /// </summary>
137 bool IsIdle { get; }
138
139 /// <summary>
140 /// This event is fired when all work items are completed.
141 /// (When IsIdle changes to true)
142 /// This event only work on WorkItemsGroup. On SmartThreadPool
143 /// it throws the NotImplementedException.
144 /// </summary>
145 event WorkItemsGroupIdleHandler OnIdle;
146
147 #region QueueWorkItem
148
149 /// <summary>
150 /// Queue a work item
151 /// </summary>
152 /// <param name="callback">A callback to execute</param>
153 /// <returns>Returns a work item result</returns>
65 IWorkItemResult QueueWorkItem(WorkItemCallback callback); 154 IWorkItemResult QueueWorkItem(WorkItemCallback callback);
155
156 /// <summary>
157 /// Queue a work item
158 /// </summary>
159 /// <param name="callback">A callback to execute</param>
160 /// <param name="workItemPriority">The priority of the work item</param>
161 /// <returns>Returns a work item result</returns>
66 IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); 162 IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
163
164 /// <summary>
165 /// Queue a work item
166 /// </summary>
167 /// <param name="callback">A callback to execute</param>
168 /// <param name="state">
169 /// The context object of the work item. Used for passing arguments to the work item.
170 /// </param>
171 /// <returns>Returns a work item result</returns>
67 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); 172 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
173
174 /// <summary>
175 /// Queue a work item
176 /// </summary>
177 /// <param name="callback">A callback to execute</param>
178 /// <param name="state">
179 /// The context object of the work item. Used for passing arguments to the work item.
180 /// </param>
181 /// <param name="workItemPriority">The work item priority</param>
182 /// <returns>Returns a work item result</returns>
68 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); 183 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
184
185 /// <summary>
186 /// Queue a work item
187 /// </summary>
188 /// <param name="callback">A callback to execute</param>
189 /// <param name="state">
190 /// The context object of the work item. Used for passing arguments to the work item.
191 /// </param>
192 /// <param name="postExecuteWorkItemCallback">
193 /// A delegate to call after the callback completion
194 /// </param>
195 /// <returns>Returns a work item result</returns>
69 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); 196 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
197
198 /// <summary>
199 /// Queue a work item
200 /// </summary>
201 /// <param name="callback">A callback to execute</param>
202 /// <param name="state">
203 /// The context object of the work item. Used for passing arguments to the work item.
204 /// </param>
205 /// <param name="postExecuteWorkItemCallback">
206 /// A delegate to call after the callback completion
207 /// </param>
208 /// <param name="workItemPriority">The work item priority</param>
209 /// <returns>Returns a work item result</returns>
70 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); 210 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
211
212 /// <summary>
213 /// Queue a work item
214 /// </summary>
215 /// <param name="callback">A callback to execute</param>
216 /// <param name="state">
217 /// The context object of the work item. Used for passing arguments to the work item.
218 /// </param>
219 /// <param name="postExecuteWorkItemCallback">
220 /// A delegate to call after the callback completion
221 /// </param>
222 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
223 /// <returns>Returns a work item result</returns>
71 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); 224 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
225
226 /// <summary>
227 /// Queue a work item
228 /// </summary>
229 /// <param name="callback">A callback to execute</param>
230 /// <param name="state">
231 /// The context object of the work item. Used for passing arguments to the work item.
232 /// </param>
233 /// <param name="postExecuteWorkItemCallback">
234 /// A delegate to call after the callback completion
235 /// </param>
236 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
237 /// <param name="workItemPriority">The work item priority</param>
238 /// <returns>Returns a work item result</returns>
72 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); 239 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
73 240
241 /// <summary>
242 /// Queue a work item
243 /// </summary>
244 /// <param name="workItemInfo">Work item info</param>
245 /// <param name="callback">A callback to execute</param>
246 /// <returns>Returns a work item result</returns>
74 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); 247 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
75 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
76
77 void WaitForIdle();
78 bool WaitForIdle(TimeSpan timeout);
79 bool WaitForIdle(int millisecondsTimeout);
80 248
81 int WaitingCallbacks { get; } 249 /// <summary>
82 event WorkItemsGroupIdleHandler OnIdle; 250 /// Queue a work item
83 251 /// </summary>
84 void Cancel(); 252 /// <param name="workItemInfo">Work item information</param>
85 void Start(); 253 /// <param name="callback">A callback to execute</param>
86 } 254 /// <param name="state">
255 /// The context object of the work item. Used for passing arguments to the work item.
256 /// </param>
257 /// <returns>Returns a work item result</returns>
258 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
87 259
88 #endregion 260 #endregion
89 261
90 #region CallToPostExecute enumerator 262 #region QueueWorkItem(Action<...>)
91 263
92 [Flags] 264 /// <summary>
93 public enum CallToPostExecute 265 /// Queue a work item.
94 { 266 /// </summary>
95 Never = 0x00, 267 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
96 WhenWorkItemCanceled = 0x01, 268 IWorkItemResult QueueWorkItem(Action action);
97 WhenWorkItemNotCanceled = 0x02,
98 Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
99 }
100 269
101 #endregion 270 /// <summary>
271 /// Queue a work item.
272 /// </summary>
273 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
274 IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority);
102 275
103 #region IWorkItemResult interface 276 /// <summary>
277 /// Queue a work item.
278 /// </summary>
279 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
280 IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg, WorkItemPriority priority);
104 281
105 /// <summary>
106 /// IWorkItemResult interface
107 /// </summary>
108 public interface IWorkItemResult
109 {
110 /// <summary> 282 /// <summary>
111 /// Get the result of the work item. 283 /// Queue a work item.
112 /// If the work item didn't run yet then the caller waits.
113 /// </summary> 284 /// </summary>
114 /// <returns>The result of the work item</returns> 285 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
115 object GetResult(); 286 IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg);
116 287
117 /// <summary> 288 /// <summary>
118 /// Get the result of the work item. 289 /// Queue a work item.
119 /// If the work item didn't run yet then the caller waits until timeout.
120 /// </summary> 290 /// </summary>
121 /// <returns>The result of the work item</returns> 291 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
122 /// On timeout throws WorkItemTimeoutException 292 IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2);
123 object GetResult(
124 int millisecondsTimeout,
125 bool exitContext);
126 293
127 /// <summary> 294 /// <summary>
128 /// Get the result of the work item. 295 /// Queue a work item.
129 /// If the work item didn't run yet then the caller waits until timeout.
130 /// </summary> 296 /// </summary>
131 /// <returns>The result of the work item</returns> 297 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
132 /// On timeout throws WorkItemTimeoutException 298 IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority);
133 object GetResult(
134 TimeSpan timeout,
135 bool exitContext);
136 299
137 void Abort(); 300 /// <summary>
301 /// Queue a work item.
302 /// </summary>
303 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
304 IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3);
138 305
139 /// <summary> 306 /// <summary>
140 /// Get the result of the work item. 307 /// Queue a work item.
141 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
142 /// </summary> 308 /// </summary>
143 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> 309 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
144 /// <param name="exitContext"> 310 IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority);
145 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
146 /// </param>
147 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
148 /// <returns>The result of the work item</returns>
149 /// On timeout throws WorkItemTimeoutException
150 /// On cancel throws WorkItemCancelException
151 object GetResult(
152 int millisecondsTimeout,
153 bool exitContext,
154 WaitHandle cancelWaitHandle);
155 311
156 /// <summary> 312 /// <summary>
157 /// Get the result of the work item. 313 /// Queue a work item.
158 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
159 /// </summary> 314 /// </summary>
160 /// <returns>The result of the work item</returns> 315 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
161 /// On timeout throws WorkItemTimeoutException 316 IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
162 /// On cancel throws WorkItemCancelException
163 object GetResult(
164 TimeSpan timeout,
165 bool exitContext,
166 WaitHandle cancelWaitHandle);
167 317
168 /// <summary> 318 /// <summary>
169 /// Get the result of the work item. 319 /// Queue a work item.
170 /// If the work item didn't run yet then the caller waits.
171 /// </summary> 320 /// </summary>
172 /// <param name="e">Filled with the exception if one was thrown</param> 321 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
173 /// <returns>The result of the work item</returns> 322 IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority);
174 object GetResult(out Exception e); 323
324 #endregion
325
326 #region QueueWorkItem(Func<...>)
175 327
176 /// <summary> 328 /// <summary>
177 /// Get the result of the work item. 329 /// Queue a work item.
178 /// If the work item didn't run yet then the caller waits until timeout.
179 /// </summary> 330 /// </summary>
180 /// <param name="e">Filled with the exception if one was thrown</param> 331 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
181 /// <returns>The result of the work item</returns> 332 /// its GetResult() returns a TResult object</returns>
182 /// On timeout throws WorkItemTimeoutException 333 IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func);
183 object GetResult(
184 int millisecondsTimeout,
185 bool exitContext,
186 out Exception e);
187 334
188 /// <summary> 335 /// <summary>
189 /// Get the result of the work item. 336 /// Queue a work item.
190 /// If the work item didn't run yet then the caller waits until timeout.
191 /// </summary> 337 /// </summary>
192 /// <param name="e">Filled with the exception if one was thrown</param> 338 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
193 /// <returns>The result of the work item</returns> 339 /// its GetResult() returns a TResult object</returns>
194 /// On timeout throws WorkItemTimeoutException 340 IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg);
195 object GetResult(
196 TimeSpan timeout,
197 bool exitContext,
198 out Exception e);
199 341
200 /// <summary> 342 /// <summary>
201 /// Get the result of the work item. 343 /// Queue a work item.
202 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
203 /// </summary> 344 /// </summary>
204 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> 345 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
205 /// <param name="exitContext"> 346 /// its GetResult() returns a TResult object</returns>
206 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 347 IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2);
207 /// </param>
208 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
209 /// <param name="e">Filled with the exception if one was thrown</param>
210 /// <returns>The result of the work item</returns>
211 /// On timeout throws WorkItemTimeoutException
212 /// On cancel throws WorkItemCancelException
213 object GetResult(
214 int millisecondsTimeout,
215 bool exitContext,
216 WaitHandle cancelWaitHandle,
217 out Exception e);
218 348
219 /// <summary> 349 /// <summary>
220 /// Get the result of the work item. 350 /// Queue a work item.
221 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
222 /// </summary> 351 /// </summary>
223 /// <returns>The result of the work item</returns> 352 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
224 /// <param name="e">Filled with the exception if one was thrown</param> 353 /// its GetResult() returns a TResult object</returns>
225 /// On timeout throws WorkItemTimeoutException 354 IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3);
226 /// On cancel throws WorkItemCancelException
227 object GetResult(
228 TimeSpan timeout,
229 bool exitContext,
230 WaitHandle cancelWaitHandle,
231 out Exception e);
232 355
233 /// <summary> 356 /// <summary>
234 /// Gets an indication whether the asynchronous operation has completed. 357 /// Queue a work item.
235 /// </summary> 358 /// </summary>
236 bool IsCompleted { get; } 359 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
360 /// its GetResult() returns a TResult object</returns>
361 IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
362
363 #endregion
364 }
365
366 #endregion
237 367
368 #region CallToPostExecute enumerator
369
370 [Flags]
371 public enum CallToPostExecute
372 {
238 /// <summary> 373 /// <summary>
239 /// Gets an indication whether the asynchronous operation has been canceled. 374 /// Never call to the PostExecute call back
240 /// </summary> 375 /// </summary>
241 bool IsCanceled { get; } 376 Never = 0x00,
242 377
243 /// <summary> 378 /// <summary>
244 /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. 379 /// Call to the PostExecute only when the work item is cancelled
245 /// </summary> 380 /// </summary>
246 object State { get; } 381 WhenWorkItemCanceled = 0x01,
247 382
248 /// <summary> 383 /// <summary>
249 /// Cancel the work item if it didn't start running yet. 384 /// Call to the PostExecute only when the work item is not cancelled
250 /// </summary> 385 /// </summary>
251 /// <returns>Returns true on success or false if the work item is in progress or already completed</returns> 386 WhenWorkItemNotCanceled = 0x02,
252 bool Cancel();
253 387
254 /// <summary> 388 /// <summary>
255 /// Get the work item's priority 389 /// Always call to the PostExecute
256 /// </summary> 390 /// </summary>
257 WorkItemPriority WorkItemPriority { get; } 391 Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
392 }
393
394 #endregion
258 395
396 #region IWorkItemResult interface
397
398 /// <summary>
399 /// The common interface of IWorkItemResult and IWorkItemResult&lt;T&gt;
400 /// </summary>
401 public interface IWaitableResult
402 {
259 /// <summary> 403 /// <summary>
260 /// Return the result, same as GetResult() 404 /// This method intent is for internal use.
261 /// </summary> 405 /// </summary>
262 object Result { get; } 406 /// <returns></returns>
407 IWorkItemResult GetWorkItemResult();
263 408
264 /// <summary> 409 /// <summary>
265 /// Returns the exception if occured otherwise returns null. 410 /// This method intent is for internal use.
266 /// </summary> 411 /// </summary>
267 object Exception { get; } 412 /// <returns></returns>
413 IWorkItemResult<TResult> GetWorkItemResultT<TResult>();
268 } 414 }
269 415
416 /// <summary>
417 /// IWorkItemResult interface.
418 /// Created when a WorkItemCallback work item is queued.
419 /// </summary>
420 public interface IWorkItemResult : IWorkItemResult<object>
421 {
422 }
423
424 /// <summary>
425 /// IWorkItemResult&lt;TResult&gt; interface.
426 /// Created when a Func&lt;TResult&gt; work item is queued.
427 /// </summary>
428 public interface IWorkItemResult<TResult> : IWaitableResult
429 {
430 /// <summary>
431 /// Get the result of the work item.
432 /// If the work item didn't run yet then the caller waits.
433 /// </summary>
434 /// <returns>The result of the work item</returns>
435 TResult GetResult();
436
437 /// <summary>
438 /// Get the result of the work item.
439 /// If the work item didn't run yet then the caller waits until timeout.
440 /// </summary>
441 /// <returns>The result of the work item</returns>
442 /// On timeout throws WorkItemTimeoutException
443 TResult GetResult(
444 int millisecondsTimeout,
445 bool exitContext);
446
447 /// <summary>
448 /// Get the result of the work item.
449 /// If the work item didn't run yet then the caller waits until timeout.
450 /// </summary>
451 /// <returns>The result of the work item</returns>
452 /// On timeout throws WorkItemTimeoutException
453 TResult GetResult(
454 TimeSpan timeout,
455 bool exitContext);
456
457 /// <summary>
458 /// Get the result of the work item.
459 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
460 /// </summary>
461 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
462 /// <param name="exitContext">
463 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
464 /// </param>
465 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
466 /// <returns>The result of the work item</returns>
467 /// On timeout throws WorkItemTimeoutException
468 /// On cancel throws WorkItemCancelException
469 TResult GetResult(
470 int millisecondsTimeout,
471 bool exitContext,
472 WaitHandle cancelWaitHandle);
473
474 /// <summary>
475 /// Get the result of the work item.
476 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
477 /// </summary>
478 /// <returns>The result of the work item</returns>
479 /// On timeout throws WorkItemTimeoutException
480 /// On cancel throws WorkItemCancelException
481 TResult GetResult(
482 TimeSpan timeout,
483 bool exitContext,
484 WaitHandle cancelWaitHandle);
485
486 /// <summary>
487 /// Get the result of the work item.
488 /// If the work item didn't run yet then the caller waits.
489 /// </summary>
490 /// <param name="e">Filled with the exception if one was thrown</param>
491 /// <returns>The result of the work item</returns>
492 TResult GetResult(out Exception e);
493
494 /// <summary>
495 /// Get the result of the work item.
496 /// If the work item didn't run yet then the caller waits until timeout.
497 /// </summary>
498 /// <param name="millisecondsTimeout"></param>
499 /// <param name="exitContext"></param>
500 /// <param name="e">Filled with the exception if one was thrown</param>
501 /// <returns>The result of the work item</returns>
502 /// On timeout throws WorkItemTimeoutException
503 TResult GetResult(
504 int millisecondsTimeout,
505 bool exitContext,
506 out Exception e);
507
508 /// <summary>
509 /// Get the result of the work item.
510 /// If the work item didn't run yet then the caller waits until timeout.
511 /// </summary>
512 /// <param name="exitContext"></param>
513 /// <param name="e">Filled with the exception if one was thrown</param>
514 /// <param name="timeout"></param>
515 /// <returns>The result of the work item</returns>
516 /// On timeout throws WorkItemTimeoutException
517 TResult GetResult(
518 TimeSpan timeout,
519 bool exitContext,
520 out Exception e);
521
522 /// <summary>
523 /// Get the result of the work item.
524 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
525 /// </summary>
526 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
527 /// <param name="exitContext">
528 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
529 /// </param>
530 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
531 /// <param name="e">Filled with the exception if one was thrown</param>
532 /// <returns>The result of the work item</returns>
533 /// On timeout throws WorkItemTimeoutException
534 /// On cancel throws WorkItemCancelException
535 TResult GetResult(
536 int millisecondsTimeout,
537 bool exitContext,
538 WaitHandle cancelWaitHandle,
539 out Exception e);
540
541 /// <summary>
542 /// Get the result of the work item.
543 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
544 /// </summary>
545 /// <returns>The result of the work item</returns>
546 /// <param name="cancelWaitHandle"></param>
547 /// <param name="e">Filled with the exception if one was thrown</param>
548 /// <param name="timeout"></param>
549 /// <param name="exitContext"></param>
550 /// On timeout throws WorkItemTimeoutException
551 /// On cancel throws WorkItemCancelException
552 TResult GetResult(
553 TimeSpan timeout,
554 bool exitContext,
555 WaitHandle cancelWaitHandle,
556 out Exception e);
557
558 /// <summary>
559 /// Gets an indication whether the asynchronous operation has completed.
560 /// </summary>
561 bool IsCompleted { get; }
562
563 /// <summary>
564 /// Gets an indication whether the asynchronous operation has been canceled.
565 /// </summary>
566 bool IsCanceled { get; }
567
568 /// <summary>
569 /// Gets the user-defined object that contains context data
570 /// for the work item method.
571 /// </summary>
572 object State { get; }
573
574 /// <summary>
575 /// Same as Cancel(false).
576 /// </summary>
577 bool Cancel();
578
579 /// <summary>
580 /// Cancel the work item execution.
581 /// If the work item is in the queue then it won't execute
582 /// If the work item is completed, it will remain completed
583 /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled
584 /// property to check if the work item has been cancelled. If the abortExecution is set to true then
585 /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution
586 /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException.
587 /// If the work item is already cancelled it will remain cancelled
588 /// </summary>
589 /// <param name="abortExecution">When true send an AbortException to the executing thread.</param>
590 /// <returns>Returns true if the work item was not completed, otherwise false.</returns>
591 bool Cancel(bool abortExecution);
592
593 /// <summary>
594 /// Get the work item's priority
595 /// </summary>
596 WorkItemPriority WorkItemPriority { get; }
597
598 /// <summary>
599 /// Return the result, same as GetResult()
600 /// </summary>
601 TResult Result { get; }
602
603 /// <summary>
604 /// Returns the exception if occured otherwise returns null.
605 /// </summary>
606 object Exception { get; }
607 }
608
609 #endregion
610
611 #region .NET 3.5
612
613 // All these delegate are built-in .NET 3.5
614 // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity.
615
616 public delegate void Action();
617 public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
618 public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
619 public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
620
621 public delegate TResult Func<TResult>();
622 public delegate TResult Func<T, TResult>(T arg1);
623 public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
624 public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
625 public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
626
270 #endregion 627 #endregion
271} 628}
diff --git a/ThirdParty/SmartThreadPool/InternalInterfaces.cs b/ThirdParty/SmartThreadPool/InternalInterfaces.cs
new file mode 100644
index 0000000..0072e10
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/InternalInterfaces.cs
@@ -0,0 +1,27 @@
1
2namespace Amib.Threading.Internal
3{
4 /// <summary>
5 /// An internal delegate to call when the WorkItem starts or completes
6 /// </summary>
7 internal delegate void WorkItemStateCallback(WorkItem workItem);
8
9 internal interface IInternalWorkItemResult
10 {
11 event WorkItemStateCallback OnWorkItemStarted;
12 event WorkItemStateCallback OnWorkItemCompleted;
13 }
14
15 internal interface IInternalWaitableResult
16 {
17 /// <summary>
18 /// This method is intent for internal use.
19 /// </summary>
20 IWorkItemResult GetWorkItemResult();
21 }
22
23 public interface IHasWorkItemPriority
24 {
25 WorkItemPriority WorkItemPriority { get; }
26 }
27}
diff --git a/ThirdParty/SmartThreadPool/PriorityQueue.cs b/ThirdParty/SmartThreadPool/PriorityQueue.cs
index 63d5e84..409c879 100644
--- a/ThirdParty/SmartThreadPool/PriorityQueue.cs
+++ b/ThirdParty/SmartThreadPool/PriorityQueue.cs
@@ -1,240 +1,239 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
5using System.Collections; 2using System.Collections;
3using System.Collections.Generic;
6using System.Diagnostics; 4using System.Diagnostics;
7 5
8namespace Amib.Threading.Internal 6namespace Amib.Threading.Internal
9{ 7{
10 #region PriorityQueue class 8 #region PriorityQueue class
11 9
12 /// <summary> 10 /// <summary>
13 /// PriorityQueue class 11 /// PriorityQueue class
14 /// This class is not thread safe because we use external lock 12 /// This class is not thread safe because we use external lock
15 /// </summary> 13 /// </summary>
16 public sealed class PriorityQueue : IEnumerable 14 public sealed class PriorityQueue : IEnumerable
17 { 15 {
18 #region Private members 16 #region Private members
19 17
20 /// <summary> 18 /// <summary>
21 /// The number of queues, there is one for each type of priority 19 /// The number of queues, there is one for each type of priority
22 /// </summary> 20 /// </summary>
23 private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; 21 private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
24 22
25 /// <summary> 23 /// <summary>
26 /// Work items queues. There is one for each type of priority 24 /// Work items queues. There is one for each type of priority
27 /// </summary> 25 /// </summary>
28 private Queue [] _queues = new Queue[_queuesCount]; 26 private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
29 27
30 /// <summary> 28 /// <summary>
31 /// The total number of work items within the queues 29 /// The total number of work items within the queues
32 /// </summary> 30 /// </summary>
33 private int _workItemsCount = 0; 31 private int _workItemsCount;
34 32
35 /// <summary> 33 /// <summary>
36 /// Use with IEnumerable interface 34 /// Use with IEnumerable interface
37 /// </summary> 35 /// </summary>
38 private int _version = 0; 36 private int _version;
39 37
40 #endregion 38 #endregion
41 39
42 #region Contructor 40 #region Contructor
43 41
44 public PriorityQueue() 42 public PriorityQueue()
45 { 43 {
46 for(int i = 0; i < _queues.Length; ++i) 44 for(int i = 0; i < _queues.Length; ++i)
47 { 45 {
48 _queues[i] = new Queue(); 46 _queues[i] = new LinkedList<IHasWorkItemPriority>();
49 } 47 }
50 } 48 }
51 49
52 #endregion 50 #endregion
53 51
54 #region Methods 52 #region Methods
55 53
56 /// <summary> 54 /// <summary>
57 /// Enqueue a work item. 55 /// Enqueue a work item.
58 /// </summary> 56 /// </summary>
59 /// <param name="workItem">A work item</param> 57 /// <param name="workItem">A work item</param>
60 public void Enqueue(IHasWorkItemPriority workItem) 58 public void Enqueue(IHasWorkItemPriority workItem)
61 { 59 {
62 Debug.Assert(null != workItem); 60 Debug.Assert(null != workItem);
63 61
64 int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; 62 int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
65 Debug.Assert(queueIndex >= 0); 63 Debug.Assert(queueIndex >= 0);
66 Debug.Assert(queueIndex < _queuesCount); 64 Debug.Assert(queueIndex < _queuesCount);
67 65
68 _queues[queueIndex].Enqueue(workItem); 66 _queues[queueIndex].AddLast(workItem);
69 ++_workItemsCount; 67 ++_workItemsCount;
70 ++_version; 68 ++_version;
71 } 69 }
72 70
73 /// <summary> 71 /// <summary>
74 /// Dequeque a work item. 72 /// Dequeque a work item.
75 /// </summary> 73 /// </summary>
76 /// <returns>Returns the next work item</returns> 74 /// <returns>Returns the next work item</returns>
77 public IHasWorkItemPriority Dequeue() 75 public IHasWorkItemPriority Dequeue()
78 { 76 {
79 IHasWorkItemPriority workItem = null; 77 IHasWorkItemPriority workItem = null;
80 78
81 if(_workItemsCount > 0) 79 if(_workItemsCount > 0)
82 { 80 {
83 int queueIndex = GetNextNonEmptyQueue(-1); 81 int queueIndex = GetNextNonEmptyQueue(-1);
84 Debug.Assert(queueIndex >= 0); 82 Debug.Assert(queueIndex >= 0);
85 workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority; 83 workItem = _queues[queueIndex].First.Value;
86 Debug.Assert(null != workItem); 84 _queues[queueIndex].RemoveFirst();
87 --_workItemsCount; 85 Debug.Assert(null != workItem);
88 ++_version; 86 --_workItemsCount;
89 } 87 ++_version;
90 88 }
91 return workItem; 89
92 } 90 return workItem;
93 91 }
94 /// <summary> 92
95 /// Find the next non empty queue starting at queue queueIndex+1 93 /// <summary>
96 /// </summary> 94 /// Find the next non empty queue starting at queue queueIndex+1
97 /// <param name="queueIndex">The index-1 to start from</param> 95 /// </summary>
98 /// <returns> 96 /// <param name="queueIndex">The index-1 to start from</param>
99 /// The index of the next non empty queue or -1 if all the queues are empty 97 /// <returns>
100 /// </returns> 98 /// The index of the next non empty queue or -1 if all the queues are empty
101 private int GetNextNonEmptyQueue(int queueIndex) 99 /// </returns>
102 { 100 private int GetNextNonEmptyQueue(int queueIndex)
103 for(int i = queueIndex+1; i < _queuesCount; ++i) 101 {
104 { 102 for(int i = queueIndex+1; i < _queuesCount; ++i)
105 if(_queues[i].Count > 0) 103 {
106 { 104 if(_queues[i].Count > 0)
107 return i; 105 {
108 } 106 return i;
109 } 107 }
110 return -1; 108 }
111 } 109 return -1;
112 110 }
113 /// <summary> 111
114 /// The number of work items 112 /// <summary>
115 /// </summary> 113 /// The number of work items
116 public int Count 114 /// </summary>
117 { 115 public int Count
118 get 116 {
119 { 117 get
120 return _workItemsCount; 118 {
121 } 119 return _workItemsCount;
122 } 120 }
123 121 }
124 /// <summary> 122
125 /// Clear all the work items 123 /// <summary>
126 /// </summary> 124 /// Clear all the work items
127 public void Clear() 125 /// </summary>
128 { 126 public void Clear()
129 if (_workItemsCount > 0) 127 {
130 { 128 if (_workItemsCount > 0)
131 foreach(Queue queue in _queues) 129 {
132 { 130 foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
133 queue.Clear(); 131 {
134 } 132 queue.Clear();
135 _workItemsCount = 0; 133 }
136 ++_version; 134 _workItemsCount = 0;
137 } 135 ++_version;
138 } 136 }
139 137 }
140 #endregion 138
141 139 #endregion
142 #region IEnumerable Members 140
143 141 #region IEnumerable Members
144 /// <summary> 142
145 /// Returns an enumerator to iterate over the work items 143 /// <summary>
146 /// </summary> 144 /// Returns an enumerator to iterate over the work items
147 /// <returns>Returns an enumerator</returns> 145 /// </summary>
148 public IEnumerator GetEnumerator() 146 /// <returns>Returns an enumerator</returns>
149 { 147 public IEnumerator GetEnumerator()
150 return new PriorityQueueEnumerator(this); 148 {
151 } 149 return new PriorityQueueEnumerator(this);
152 150 }
153 #endregion 151
154 152 #endregion
155 #region PriorityQueueEnumerator 153
156 154 #region PriorityQueueEnumerator
157 /// <summary> 155
158 /// The class the implements the enumerator 156 /// <summary>
159 /// </summary> 157 /// The class the implements the enumerator
160 private class PriorityQueueEnumerator : IEnumerator 158 /// </summary>
161 { 159 private class PriorityQueueEnumerator : IEnumerator
162 private PriorityQueue _priorityQueue; 160 {
163 private int _version; 161 private readonly PriorityQueue _priorityQueue;
164 private int _queueIndex; 162 private int _version;
165 private IEnumerator _enumerator; 163 private int _queueIndex;
166 164 private IEnumerator _enumerator;
167 public PriorityQueueEnumerator(PriorityQueue priorityQueue) 165
168 { 166 public PriorityQueueEnumerator(PriorityQueue priorityQueue)
169 _priorityQueue = priorityQueue; 167 {
170 _version = _priorityQueue._version; 168 _priorityQueue = priorityQueue;
171 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); 169 _version = _priorityQueue._version;
172 if (_queueIndex >= 0) 170 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
173 { 171 if (_queueIndex >= 0)
174 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 172 {
175 } 173 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
176 else 174 }
177 { 175 else
178 _enumerator = null; 176 {
179 } 177 _enumerator = null;
180 } 178 }
181 179 }
182 #region IEnumerator Members 180
183 181 #region IEnumerator Members
184 public void Reset() 182
185 { 183 public void Reset()
186 _version = _priorityQueue._version; 184 {
187 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); 185 _version = _priorityQueue._version;
188 if (_queueIndex >= 0) 186 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
189 { 187 if (_queueIndex >= 0)
190 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 188 {
191 } 189 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
192 else 190 }
193 { 191 else
194 _enumerator = null; 192 {
195 } 193 _enumerator = null;
196 } 194 }
197 195 }
198 public object Current 196
199 { 197 public object Current
200 get 198 {
201 { 199 get
202 Debug.Assert(null != _enumerator); 200 {
203 return _enumerator.Current; 201 Debug.Assert(null != _enumerator);
204 } 202 return _enumerator.Current;
205 } 203 }
206 204 }
207 public bool MoveNext() 205
208 { 206 public bool MoveNext()
209 if (null == _enumerator) 207 {
210 { 208 if (null == _enumerator)
211 return false; 209 {
212 } 210 return false;
213 211 }
214 if(_version != _priorityQueue._version) 212
215 { 213 if(_version != _priorityQueue._version)
216 throw new InvalidOperationException("The collection has been modified"); 214 {
217 215 throw new InvalidOperationException("The collection has been modified");
218 } 216
219 if (!_enumerator.MoveNext()) 217 }
220 { 218 if (!_enumerator.MoveNext())
221 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); 219 {
222 if(-1 == _queueIndex) 220 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
223 { 221 if(-1 == _queueIndex)
224 return false; 222 {
225 } 223 return false;
226 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 224 }
227 _enumerator.MoveNext(); 225 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
228 return true; 226 _enumerator.MoveNext();
229 } 227 return true;
230 return true; 228 }
231 } 229 return true;
232 230 }
233 #endregion 231
234 } 232 #endregion
235 233 }
236 #endregion 234
237 } 235 #endregion
238 236 }
239 #endregion 237
238 #endregion
240} 239}
diff --git a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4728c1f
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs
@@ -0,0 +1,23 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5[assembly: AssemblyTitle("Amib.Threading")]
6[assembly: AssemblyDescription("Smart Thread Pool")]
7[assembly: AssemblyConfiguration("")]
8[assembly: AssemblyCompany("")]
9[assembly: AssemblyProduct("Amib.Threading")]
10[assembly: AssemblyCopyright("")]
11[assembly: AssemblyTrademark("")]
12[assembly: AssemblyCulture("")]
13[assembly: ComVisible(false)]
14[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")]
15[assembly: AssemblyVersion("2.2.3.0")]
16
17#if (_PUBLISH)
18[assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")]
19#else
20[assembly: InternalsVisibleTo("STPTests")]
21#endif
22
23
diff --git a/ThirdParty/SmartThreadPool/SLExt.cs b/ThirdParty/SmartThreadPool/SLExt.cs
new file mode 100644
index 0000000..23a60bc
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/SLExt.cs
@@ -0,0 +1,16 @@
1#if _SILVERLIGHT
2
3using System.Threading;
4
5namespace Amib.Threading
6{
7 public enum ThreadPriority
8 {
9 Lowest,
10 BelowNormal,
11 Normal,
12 AboveNormal,
13 Highest,
14 }
15}
16#endif
diff --git a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs
new file mode 100644
index 0000000..9b17f69
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs
@@ -0,0 +1,62 @@
1#if !(_WINDOWS_CE)
2
3using System;
4using System.Threading;
5
6namespace Amib.Threading.Internal
7{
8#if _WINDOWS || WINDOWS_PHONE
9 internal static class STPEventWaitHandle
10 {
11 public const int WaitTimeout = Timeout.Infinite;
12
13 internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
14 {
15 return WaitHandle.WaitAll(waitHandles, millisecondsTimeout);
16 }
17
18 internal static int WaitAny(WaitHandle[] waitHandles)
19 {
20 return WaitHandle.WaitAny(waitHandles);
21 }
22
23 internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
24 {
25 return WaitHandle.WaitAny(waitHandles, millisecondsTimeout);
26 }
27
28 internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
29 {
30 return waitHandle.WaitOne(millisecondsTimeout);
31 }
32 }
33#else
34 internal static class STPEventWaitHandle
35 {
36 public const int WaitTimeout = Timeout.Infinite;
37
38 internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
39 {
40 return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
41 }
42
43 internal static int WaitAny(WaitHandle[] waitHandles)
44 {
45 return WaitHandle.WaitAny(waitHandles);
46 }
47
48 internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
49 {
50 return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
51 }
52
53 internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
54 {
55 return waitHandle.WaitOne(millisecondsTimeout, exitContext);
56 }
57 }
58#endif
59
60}
61
62#endif \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs
index 077cf17..0663d1d 100644
--- a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs
+++ b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs
@@ -1,354 +1,448 @@
1using System; 1using System;
2using System.Diagnostics; 2using System.Diagnostics;
3using System.Threading;
4
5namespace Amib.Threading
6{
7 public interface ISTPPerformanceCountersReader
8 {
9 long InUseThreads { get; }
10 long ActiveThreads { get; }
11 long WorkItemsQueued { get; }
12 long WorkItemsProcessed { get; }
13 }
14}
3 15
4namespace Amib.Threading.Internal 16namespace Amib.Threading.Internal
5{ 17{
6 internal enum STPPerformanceCounterType 18 internal interface ISTPInstancePerformanceCounters : IDisposable
7 { 19 {
8 // Fields 20 void Close();
9 ActiveThreads = 0, 21 void SampleThreads(long activeThreads, long inUseThreads);
10 InUseThreads = 1, 22 void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
11 OverheadThreads = 2, 23 void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
12 OverheadThreadsPercent = 3, 24 void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
13 OverheadThreadsPercentBase = 4, 25 }
26#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
14 27
15 WorkItems = 5, 28 internal enum STPPerformanceCounterType
16 WorkItemsInQueue = 6, 29 {
17 WorkItemsProcessed = 7, 30 // Fields
31 ActiveThreads = 0,
32 InUseThreads = 1,
33 OverheadThreads = 2,
34 OverheadThreadsPercent = 3,
35 OverheadThreadsPercentBase = 4,
18 36
19 WorkItemsQueuedPerSecond = 8, 37 WorkItems = 5,
20 WorkItemsProcessedPerSecond = 9, 38 WorkItemsInQueue = 6,
39 WorkItemsProcessed = 7,
21 40
22 AvgWorkItemWaitTime = 10, 41 WorkItemsQueuedPerSecond = 8,
23 AvgWorkItemWaitTimeBase = 11, 42 WorkItemsProcessedPerSecond = 9,
24 43
25 AvgWorkItemProcessTime = 12, 44 AvgWorkItemWaitTime = 10,
26 AvgWorkItemProcessTimeBase = 13, 45 AvgWorkItemWaitTimeBase = 11,
27 46
28 WorkItemsGroups = 14, 47 AvgWorkItemProcessTime = 12,
48 AvgWorkItemProcessTimeBase = 13,
29 49
30 LastCounter = 14, 50 WorkItemsGroups = 14,
31 }
32
33 51
34 /// <summary> 52 LastCounter = 14,
35 /// Summary description for STPPerformanceCounter. 53 }
36 /// </summary> 54
37 internal class STPPerformanceCounter
38 {
39 // Fields
40 private PerformanceCounterType _pcType;
41 protected string _counterHelp;
42 protected string _counterName;
43
44 // Methods
45 public STPPerformanceCounter(
46 string counterName,
47 string counterHelp,
48 PerformanceCounterType pcType)
49 {
50 this._counterName = counterName;
51 this._counterHelp = counterHelp;
52 this._pcType = pcType;
53 }
54
55 public void AddCounterToCollection(CounterCreationDataCollection counterData)
56 {
57 CounterCreationData counterCreationData = new CounterCreationData(
58 _counterName,
59 _counterHelp,
60 _pcType);
61 55
62 counterData.Add(counterCreationData); 56 /// <summary>
63 } 57 /// Summary description for STPPerformanceCounter.
58 /// </summary>
59 internal class STPPerformanceCounter
60 {
61 // Fields
62 private readonly PerformanceCounterType _pcType;
63 protected string _counterHelp;
64 protected string _counterName;
65
66 // Methods
67 public STPPerformanceCounter(
68 string counterName,
69 string counterHelp,
70 PerformanceCounterType pcType)
71 {
72 _counterName = counterName;
73 _counterHelp = counterHelp;
74 _pcType = pcType;
75 }
76
77 public void AddCounterToCollection(CounterCreationDataCollection counterData)
78 {
79 CounterCreationData counterCreationData = new CounterCreationData(
80 _counterName,
81 _counterHelp,
82 _pcType);
83
84 counterData.Add(counterCreationData);
85 }
86
87 // Properties
88 public string Name
89 {
90 get
91 {
92 return _counterName;
93 }
94 }
95 }
96
97 internal class STPPerformanceCounters
98 {
99 // Fields
100 internal STPPerformanceCounter[] _stpPerformanceCounters;
101 private static readonly STPPerformanceCounters _instance;
102 internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
103 internal const string _stpCategoryName = "SmartThreadPool";
104
105 // Methods
106 static STPPerformanceCounters()
107 {
108 _instance = new STPPerformanceCounters();
109 }
110
111 private STPPerformanceCounters()
112 {
113 STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[]
114 {
115 new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32),
116 new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32),
117 new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32),
118 new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction),
119 new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase),
120
121 new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32),
122 new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32),
123 new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32),
124
125 new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32),
126 new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32),
127
128 new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64),
129 new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase),
130
131 new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64),
132 new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase),
133
134 new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32),
135 };
136
137 _stpPerformanceCounters = stpPerformanceCounters;
138 SetupCategory();
139 }
140
141 private void SetupCategory()
142 {
143 if (!PerformanceCounterCategory.Exists(_stpCategoryName))
144 {
145 CounterCreationDataCollection counters = new CounterCreationDataCollection();
146
147 for (int i = 0; i < _stpPerformanceCounters.Length; i++)
148 {
149 _stpPerformanceCounters[i].AddCounterToCollection(counters);
150 }
151
152 PerformanceCounterCategory.Create(
153 _stpCategoryName,
154 _stpCategoryHelp,
155 PerformanceCounterCategoryType.MultiInstance,
156 counters);
157
158 }
159 }
64 160
65 // Properties 161 // Properties
66 public string Name 162 public static STPPerformanceCounters Instance
163 {
164 get
165 {
166 return _instance;
167 }
168 }
169 }
170
171 internal class STPInstancePerformanceCounter : IDisposable
172 {
173 // Fields
174 private bool _isDisposed;
175 private PerformanceCounter _pcs;
176
177 // Methods
178 protected STPInstancePerformanceCounter()
179 {
180 _isDisposed = false;
181 }
182
183 public STPInstancePerformanceCounter(
184 string instance,
185 STPPerformanceCounterType spcType) : this()
186 {
187 STPPerformanceCounters counters = STPPerformanceCounters.Instance;
188 _pcs = new PerformanceCounter(
189 STPPerformanceCounters._stpCategoryName,
190 counters._stpPerformanceCounters[(int) spcType].Name,
191 instance,
192 false);
193 _pcs.RawValue = _pcs.RawValue;
194 }
195
196
197 public void Close()
198 {
199 if (_pcs != null)
200 {
201 _pcs.RemoveInstance();
202 _pcs.Close();
203 _pcs = null;
204 }
205 }
206
207 public void Dispose()
208 {
209 Dispose(true);
210 }
211
212 public virtual void Dispose(bool disposing)
67 { 213 {
68 get 214 if (!_isDisposed)
69 { 215 {
70 return _counterName; 216 if (disposing)
217 {
218 Close();
219 }
71 } 220 }
72 } 221 _isDisposed = true;
73 }
74
75 internal class STPPerformanceCounters
76 {
77 // Fields
78 internal STPPerformanceCounter[] _stpPerformanceCounters;
79 private static STPPerformanceCounters _instance;
80 internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
81 internal const string _stpCategoryName = "SmartThreadPool";
82
83 // Methods
84 static STPPerformanceCounters()
85 {
86 _instance = new STPPerformanceCounters();
87 } 222 }
88 223
89 private STPPerformanceCounters() 224 public virtual void Increment()
90 { 225 {
91 STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] 226 _pcs.Increment();
92 { 227 }
93 new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), 228
94 new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), 229 public virtual void IncrementBy(long val)
95 new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), 230 {
96 new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), 231 _pcs.IncrementBy(val);
97 new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), 232 }
98 233
99 new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), 234 public virtual void Set(long val)
100 new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), 235 {
101 new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), 236 _pcs.RawValue = val;
102 237 }
103 new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), 238 }
104 new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), 239
105 240 internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
106 new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), 241 {
107 new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), 242 // Methods
243 public override void Increment() {}
244 public override void IncrementBy(long value) {}
245 public override void Set(long val) {}
246 }
247
248
249
250 internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters
251 {
252 private bool _isDisposed;
253 // Fields
254 private STPInstancePerformanceCounter[] _pcs;
255 private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
256
257 // Methods
258 static STPInstancePerformanceCounters()
259 {
260 _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter();
261 }
262
263 public STPInstancePerformanceCounters(string instance)
264 {
265 _isDisposed = false;
266 _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
267
268 // Call the STPPerformanceCounters.Instance so the static constructor will
269 // intialize the STPPerformanceCounters singleton.
270 STPPerformanceCounters.Instance.GetHashCode();
271
272 for (int i = 0; i < _pcs.Length; i++)
273 {
274 if (instance != null)
275 {
276 _pcs[i] = new STPInstancePerformanceCounter(
277 instance,
278 (STPPerformanceCounterType) i);
279 }
280 else
281 {
282 _pcs[i] = _stpInstanceNullPerformanceCounter;
283 }
284 }
285 }
286
108 287
109 new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), 288 public void Close()
110 new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), 289 {
290 if (null != _pcs)
291 {
292 for (int i = 0; i < _pcs.Length; i++)
293 {
294 if (null != _pcs[i])
295 {
296 _pcs[i].Dispose();
297 }
298 }
299 _pcs = null;
300 }
301 }
111 302
112 new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), 303 public void Dispose()
113 }; 304 {
305 Dispose(true);
306 }
114 307
115 _stpPerformanceCounters = stpPerformanceCounters; 308 public virtual void Dispose(bool disposing)
116 SetupCategory();
117 }
118
119 private void SetupCategory()
120 { 309 {
121 if (!PerformanceCounterCategory.Exists(_stpCategoryName)) 310 if (!_isDisposed)
122 { 311 {
123 CounterCreationDataCollection counters = new CounterCreationDataCollection(); 312 if (disposing)
124
125 for (int i = 0; i < _stpPerformanceCounters.Length; i++)
126 { 313 {
127 _stpPerformanceCounters[i].AddCounterToCollection(counters); 314 Close();
128 } 315 }
129
130
131 // *********** Remark for .NET 2.0 ***********
132 // If you are here, it means you got the warning that this overload
133 // of the method is deprecated in .NET 2.0. To use the correct
134 // method overload, uncomment the third argument of
135 // the method.
136 #pragma warning disable 0618
137 PerformanceCounterCategory.Create(
138 _stpCategoryName,
139 _stpCategoryHelp,
140 //PerformanceCounterCategoryType.MultiInstance,
141 counters);
142 #pragma warning restore 0618
143 } 316 }
317 _isDisposed = true;
144 } 318 }
145 319
146 // Properties 320 private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
147 public static STPPerformanceCounters Instance 321 {
148 { 322 return _pcs[(int) spcType];
149 get 323 }
150 { 324
151 return _instance; 325 public void SampleThreads(long activeThreads, long inUseThreads)
152 } 326 {
153 } 327 GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads);
154 } 328 GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads);
329 GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
330
331 GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
332 GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
333 }
334
335 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
336 {
337 GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed);
338 GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued);
339 GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
340
341 GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
342 GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
343 }
344
345 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
346 {
347 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds);
348 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
349 }
350
351 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
352 {
353 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds);
354 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
355 }
356 }
357#endif
155 358
156 internal class STPInstancePerformanceCounter : IDisposable 359 internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
157 { 360 {
158 // Fields 361 private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters();
159 private PerformanceCounter _pcs;
160 362
161 // Methods 363 public static NullSTPInstancePerformanceCounters Instance
162 protected STPInstancePerformanceCounter() 364 {
163 { 365 get { return _instance; }
164 } 366 }
165 367
166 public STPInstancePerformanceCounter( 368 public void Close() {}
167 string instance, 369 public void Dispose() {}
168 STPPerformanceCounterType spcType) 370
371 public void SampleThreads(long activeThreads, long inUseThreads) {}
372 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
373 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
374 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
375 public long InUseThreads
169 { 376 {
170 STPPerformanceCounters counters = STPPerformanceCounters.Instance; 377 get { return 0; }
171 _pcs = new PerformanceCounter(
172 STPPerformanceCounters._stpCategoryName,
173 counters._stpPerformanceCounters[(int) spcType].Name,
174 instance,
175 false);
176 _pcs.RawValue = _pcs.RawValue;
177 } 378 }
178 379
179 ~STPInstancePerformanceCounter() 380 public long ActiveThreads
180 { 381 {
181 Close(); 382 get { return 0; }
182 } 383 }
183 384
184 public void Close() 385 public long WorkItemsQueued
185 {
186 if (_pcs != null)
187 {
188 _pcs.RemoveInstance();
189 _pcs.Close();
190 _pcs = null;
191 }
192 }
193
194 public void Dispose()
195 { 386 {
196 Close(); 387 get { return 0; }
197 GC.SuppressFinalize(this);
198 }
199
200 public virtual void Increment()
201 {
202 _pcs.Increment();
203 }
204
205 public virtual void IncrementBy(long val)
206 {
207 _pcs.IncrementBy(val);
208 } 388 }
209 389
210 public virtual void Set(long val) 390 public long WorkItemsProcessed
211 { 391 {
212 _pcs.RawValue = val; 392 get { return 0; }
213 } 393 }
214 } 394 }
215 395
216 internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter 396 internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
217 { 397 {
218 // Methods 398 public void Close() { }
219 public STPInstanceNullPerformanceCounter() {} 399 public void Dispose() { }
220 public override void Increment() {}
221 public override void IncrementBy(long value) {}
222 public override void Set(long val) {}
223 }
224
225 internal interface ISTPInstancePerformanceCounters : IDisposable
226 {
227 void Close();
228 void SampleThreads(long activeThreads, long inUseThreads);
229 void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
230 void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
231 void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
232 }
233 400
401 private long _activeThreads;
402 private long _inUseThreads;
403 private long _workItemsQueued;
404 private long _workItemsProcessed;
234 405
235 internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable 406 public long InUseThreads
236 {
237 // Fields
238 private STPInstancePerformanceCounter[] _pcs;
239 private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
240
241 // Methods
242 static STPInstancePerformanceCounters()
243 { 407 {
244 _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); 408 get { return _inUseThreads; }
245 }
246
247 public STPInstancePerformanceCounters(string instance)
248 {
249 _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
250 // STPPerformanceCounters counters = STPPerformanceCounters.Instance;
251 for (int i = 0; i < _pcs.Length; i++)
252 {
253 if (instance != null)
254 {
255 _pcs[i] = new STPInstancePerformanceCounter(
256 instance,
257 (STPPerformanceCounterType) i);
258 }
259 else
260 {
261 _pcs[i] = _stpInstanceNullPerformanceCounter;
262 }
263 }
264 } 409 }
265
266 410
267 public void Close() 411 public long ActiveThreads
268 { 412 {
269 if (null != _pcs) 413 get { return _activeThreads; }
270 {
271 for (int i = 0; i < _pcs.Length; i++)
272 {
273 if (null != _pcs[i])
274 {
275 _pcs[i].Close();
276 }
277 }
278 _pcs = null;
279 }
280 } 414 }
281 415
282 ~STPInstancePerformanceCounters() 416 public long WorkItemsQueued
283 { 417 {
284 Close(); 418 get { return _workItemsQueued; }
285 } 419 }
286 420
287 public void Dispose() 421 public long WorkItemsProcessed
288 {
289 Close();
290 GC.SuppressFinalize(this);
291 }
292
293 private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
294 { 422 {
295 return _pcs[(int) spcType]; 423 get { return _workItemsProcessed; }
296 } 424 }
297 425
298 public void SampleThreads(long activeThreads, long inUseThreads) 426 public void SampleThreads(long activeThreads, long inUseThreads)
299 { 427 {
300 GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); 428 _activeThreads = activeThreads;
301 GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); 429 _inUseThreads = inUseThreads;
302 GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
303
304 GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
305 GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
306 } 430 }
307 431
308 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) 432 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
309 { 433 {
310 GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); 434 _workItemsQueued = workItemsQueued;
311 GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); 435 _workItemsProcessed = workItemsProcessed;
312 GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
313
314 GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
315 GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
316 } 436 }
317 437
318 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) 438 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
319 { 439 {
320 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); 440 // Not supported
321 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
322 } 441 }
323 442
324 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) 443 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
325 { 444 {
326 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); 445 // Not supported
327 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
328 }
329 }
330
331 internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
332 {
333 static NullSTPInstancePerformanceCounters()
334 {
335 } 446 }
336
337 private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null);
338
339 public static NullSTPInstancePerformanceCounters Instance
340 {
341 get { return _instance; }
342 }
343
344 public NullSTPInstancePerformanceCounters(string instance) {}
345 public void Close() {}
346 public void Dispose() {}
347
348 public void SampleThreads(long activeThreads, long inUseThreads) {}
349 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
350 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
351 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
352 } 447 }
353
354} 448}
diff --git a/ThirdParty/SmartThreadPool/STPStartInfo.cs b/ThirdParty/SmartThreadPool/STPStartInfo.cs
index fa9ceb4..96fa094 100644
--- a/ThirdParty/SmartThreadPool/STPStartInfo.cs
+++ b/ThirdParty/SmartThreadPool/STPStartInfo.cs
@@ -1,113 +1,212 @@
1// Ami Bar 1using System;
2// amibar@gmail.com
3
4using System.Threading; 2using System.Threading;
5 3
6namespace Amib.Threading 4namespace Amib.Threading
7{ 5{
8 /// <summary> 6 /// <summary>
9 /// Summary description for STPStartInfo. 7 /// Summary description for STPStartInfo.
10 /// </summary> 8 /// </summary>
11 public class STPStartInfo : WIGStartInfo 9 public class STPStartInfo : WIGStartInfo
12 { 10 {
13 /// <summary> 11 private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
14 /// Idle timeout in milliseconds. 12 private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
15 /// If a thread is idle for _idleTimeout milliseconds then 13 private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
16 /// it may quit. 14#if !(WINDOWS_PHONE)
17 /// </summary> 15 private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
18 private int _idleTimeout; 16#endif
19 17 private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
20 /// <summary> 18 private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground;
21 /// The lower limit of threads in the pool. 19 private bool _enableLocalPerformanceCounters;
22 /// </summary> 20 private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
23 private int _minWorkerThreads; 21 private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize;
24 22
25 /// <summary> 23 public STPStartInfo()
26 /// The upper limit of threads in the pool.
27 /// </summary>
28 private int _maxWorkerThreads;
29
30 /// <summary>
31 /// The priority of the threads in the pool
32 /// </summary>
33 private ThreadPriority _threadPriority;
34
35 /// <summary>
36 /// The thread pool name. Threads will get names depending on this.
37 /// </summary>
38 private string _threadPoolName;
39
40 /// <summary>
41 /// If this field is not null then the performance counters are enabled
42 /// and use the string as the name of the instance.
43 /// </summary>
44 private string _pcInstanceName;
45
46 private int _stackSize;
47
48 public STPStartInfo() : base()
49 { 24 {
25 _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
26#if !(WINDOWS_PHONE)
27 _threadPriority = SmartThreadPool.DefaultThreadPriority;
28#endif
29 _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
50 _idleTimeout = SmartThreadPool.DefaultIdleTimeout; 30 _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
51 _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; 31 _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
52 _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
53 _threadPriority = SmartThreadPool.DefaultThreadPriority;
54 _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
55 _pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
56 _stackSize = SmartThreadPool.DefaultStackSize;
57 } 32 }
58 33
59 public STPStartInfo(STPStartInfo stpStartInfo) : base(stpStartInfo) 34 public STPStartInfo(STPStartInfo stpStartInfo)
35 : base(stpStartInfo)
60 { 36 {
61 _idleTimeout = stpStartInfo._idleTimeout; 37 _idleTimeout = stpStartInfo.IdleTimeout;
62 _minWorkerThreads = stpStartInfo._minWorkerThreads; 38 _minWorkerThreads = stpStartInfo.MinWorkerThreads;
63 _maxWorkerThreads = stpStartInfo._maxWorkerThreads; 39 _maxWorkerThreads = stpStartInfo.MaxWorkerThreads;
64 _threadPriority = stpStartInfo._threadPriority; 40#if !(WINDOWS_PHONE)
41 _threadPriority = stpStartInfo.ThreadPriority;
42#endif
43 _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName;
44 _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters;
65 _threadPoolName = stpStartInfo._threadPoolName; 45 _threadPoolName = stpStartInfo._threadPoolName;
66 _pcInstanceName = stpStartInfo._pcInstanceName; 46 _areThreadsBackground = stpStartInfo.AreThreadsBackground;
67 _stackSize = stpStartInfo._stackSize; 47#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
48 _apartmentState = stpStartInfo._apartmentState;
49#endif
68 } 50 }
69 51
70 public int IdleTimeout 52 /// <summary>
71 { 53 /// Get/Set the idle timeout in milliseconds.
72 get { return _idleTimeout; } 54 /// If a thread is idle (starved) longer than IdleTimeout then it may quit.
73 set { _idleTimeout = value; } 55 /// </summary>
56 public virtual int IdleTimeout
57 {
58 get { return _idleTimeout; }
59 set
60 {
61 ThrowIfReadOnly();
62 _idleTimeout = value;
63 }
64 }
65
66
67 /// <summary>
68 /// Get/Set the lower limit of threads in the pool.
69 /// </summary>
70 public virtual int MinWorkerThreads
71 {
72 get { return _minWorkerThreads; }
73 set
74 {
75 ThrowIfReadOnly();
76 _minWorkerThreads = value;
77 }
78 }
79
80
81 /// <summary>
82 /// Get/Set the upper limit of threads in the pool.
83 /// </summary>
84 public virtual int MaxWorkerThreads
85 {
86 get { return _maxWorkerThreads; }
87 set
88 {
89 ThrowIfReadOnly();
90 _maxWorkerThreads = value;
91 }
92 }
93
94#if !(WINDOWS_PHONE)
95 /// <summary>
96 /// Get/Set the scheduling priority of the threads in the pool.
97 /// The Os handles the scheduling.
98 /// </summary>
99 public virtual ThreadPriority ThreadPriority
100 {
101 get { return _threadPriority; }
102 set
103 {
104 ThrowIfReadOnly();
105 _threadPriority = value;
106 }
107 }
108#endif
109 /// <summary>
110 /// Get/Set the thread pool name. Threads will get names depending on this.
111 /// </summary>
112 public virtual string ThreadPoolName {
113 get { return _threadPoolName; }
114 set
115 {
116 ThrowIfReadOnly ();
117 _threadPoolName = value;
118 }
74 } 119 }
75 120
76 public int MinWorkerThreads 121 /// <summary>
77 { 122 /// Get/Set the performance counter instance name of this SmartThreadPool
78 get { return _minWorkerThreads; } 123 /// The default is null which indicate not to use performance counters at all.
79 set { _minWorkerThreads = value; } 124 /// </summary>
80 } 125 public virtual string PerformanceCounterInstanceName
126 {
127 get { return _performanceCounterInstanceName; }
128 set
129 {
130 ThrowIfReadOnly();
131 _performanceCounterInstanceName = value;
132 }
133 }
81 134
82 public int MaxWorkerThreads 135 /// <summary>
83 { 136 /// Enable/Disable the local performance counter.
84 get { return _maxWorkerThreads; } 137 /// This enables the user to get some performance information about the SmartThreadPool
85 set { _maxWorkerThreads = value; } 138 /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.)
86 } 139 /// The default is false.
140 /// </summary>
141 public virtual bool EnableLocalPerformanceCounters
142 {
143 get { return _enableLocalPerformanceCounters; }
144 set
145 {
146 ThrowIfReadOnly();
147 _enableLocalPerformanceCounters = value;
148 }
149 }
87 150
88 public ThreadPriority ThreadPriority 151 /// <summary>
152 /// Get/Set backgroundness of thread in thread pool.
153 /// </summary>
154 public virtual bool AreThreadsBackground
155 {
156 get { return _areThreadsBackground; }
157 set
158 {
159 ThrowIfReadOnly ();
160 _areThreadsBackground = value;
161 }
162 }
163
164 /// <summary>
165 /// Get a readonly version of this STPStartInfo.
166 /// </summary>
167 /// <returns>Returns a readonly reference to this STPStartInfo</returns>
168 public new STPStartInfo AsReadOnly()
89 { 169 {
90 get { return _threadPriority; } 170 return new STPStartInfo(this) { _readOnly = true };
91 set { _threadPriority = value; }
92 } 171 }
93 172
94 public virtual string ThreadPoolName 173#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
95 {
96 get { return _threadPoolName; }
97 set { _threadPoolName = value; }
98 }
99 174
175 private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState;
100 176
101 public string PerformanceCounterInstanceName 177 /// <summary>
178 /// Get/Set the apartment state of threads in the thread pool
179 /// </summary>
180 public ApartmentState ApartmentState
102 { 181 {
103 get { return _pcInstanceName; } 182 get { return _apartmentState; }
104 set { _pcInstanceName = value; } 183 set
105 } 184 {
106 185 ThrowIfReadOnly();
107 public int StackSize 186 _apartmentState = value;
187 }
188 }
189
190#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
191
192 /// <summary>
193 /// Get/Set the max stack size of threads in the thread pool
194 /// </summary>
195 public int? MaxStackSize
108 { 196 {
109 get { return _stackSize; } 197 get { return _maxStackSize; }
110 set { _stackSize = value; } 198 set
199 {
200 ThrowIfReadOnly();
201 if (value.HasValue && value.Value < 0)
202 {
203 throw new ArgumentOutOfRangeException("value", "Value must be greater than 0.");
204 }
205 _maxStackSize = value;
206 }
111 } 207 }
208#endif
209
210#endif
112 } 211 }
113} 212}
diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
new file mode 100644
index 0000000..d9502bb
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
@@ -0,0 +1,60 @@
1
2using System;
3using Amib.Threading.Internal;
4
5namespace Amib.Threading
6{
7 public partial class SmartThreadPool
8 {
9 #region ThreadEntry class
10
11 internal class ThreadEntry
12 {
13 /// <summary>
14 /// The thread creation time
15 /// The value is stored as UTC value.
16 /// </summary>
17 private readonly DateTime _creationTime;
18
19 /// <summary>
20 /// The last time this thread has been running
21 /// It is updated by IAmAlive() method
22 /// The value is stored as UTC value.
23 /// </summary>
24 private DateTime _lastAliveTime;
25
26 /// <summary>
27 /// A reference from each thread in the thread pool to its SmartThreadPool
28 /// object container.
29 /// With this variable a thread can know whatever it belongs to a
30 /// SmartThreadPool.
31 /// </summary>
32 private readonly SmartThreadPool _associatedSmartThreadPool;
33
34 /// <summary>
35 /// A reference to the current work item a thread from the thread pool
36 /// is executing.
37 /// </summary>
38 public WorkItem CurrentWorkItem { get; set; }
39
40 public ThreadEntry(SmartThreadPool stp)
41 {
42 _associatedSmartThreadPool = stp;
43 _creationTime = DateTime.UtcNow;
44 _lastAliveTime = DateTime.MinValue;
45 }
46
47 public SmartThreadPool AssociatedSmartThreadPool
48 {
49 get { return _associatedSmartThreadPool; }
50 }
51
52 public void IAmAlive()
53 {
54 _lastAliveTime = DateTime.UtcNow;
55 }
56 }
57
58 #endregion
59 }
60} \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs
index 19a0007..a4f4ce5 100644
--- a/ThirdParty/SmartThreadPool/SmartThreadPool.cs
+++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs
@@ -1,61 +1,106 @@
1// Ami Bar 1#region Release History
2// amibar@gmail.com 2
3// 3// Smart Thread Pool
4// Smart thread pool in C#.
5// 7 Aug 2004 - Initial release 4// 7 Aug 2004 - Initial release
5//
6// 14 Sep 2004 - Bug fixes 6// 14 Sep 2004 - Bug fixes
7//
7// 15 Oct 2004 - Added new features 8// 15 Oct 2004 - Added new features
8// - Work items return result. 9// - Work items return result.
9// - Support waiting synchronization for multiple work items. 10// - Support waiting synchronization for multiple work items.
10// - Work items can be cancelled. 11// - Work items can be cancelled.
11// - Passage of the caller thread’s context to the thread in the pool. 12// - Passage of the caller thread’s context to the thread in the pool.
12// - Minimal usage of WIN32 handles. 13// - Minimal usage of WIN32 handles.
13// - Minor bug fixes. 14// - Minor bug fixes.
15//
14// 26 Dec 2004 - Changes: 16// 26 Dec 2004 - Changes:
15// - Removed static constructors. 17// - Removed static constructors.
16// - Added finalizers. 18// - Added finalizers.
17// - Changed Exceptions so they are serializable. 19// - Changed Exceptions so they are serializable.
18// - Fixed the bug in one of the SmartThreadPool constructors. 20// - Fixed the bug in one of the SmartThreadPool constructors.
19// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. 21// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters.
20// The SmartThreadPool.WaitAny() is still limited by the .NET Framework. 22// The SmartThreadPool.WaitAny() is still limited by the .NET Framework.
21// - Added PostExecute with options on which cases to call it. 23// - Added PostExecute with options on which cases to call it.
22// - Added option to dispose of the state objects. 24// - Added option to dispose of the state objects.
23// - Added a WaitForIdle() method that waits until the work items queue is empty. 25// - Added a WaitForIdle() method that waits until the work items queue is empty.
24// - Added an STPStartInfo class for the initialization of the thread pool. 26// - Added an STPStartInfo class for the initialization of the thread pool.
25// - Changed exception handling so if a work item throws an exception it 27// - Changed exception handling so if a work item throws an exception it
26// is rethrown at GetResult(), rather then firing an UnhandledException event. 28// is rethrown at GetResult(), rather then firing an UnhandledException event.
27// Note that PostExecute exception are always ignored. 29// Note that PostExecute exception are always ignored.
30//
28// 25 Mar 2005 - Changes: 31// 25 Mar 2005 - Changes:
29// - Fixed lost of work items bug 32// - Fixed lost of work items bug
33//
30// 3 Jul 2005: Changes. 34// 3 Jul 2005: Changes.
31// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. 35// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed.
36//
32// 16 Aug 2005: Changes. 37// 16 Aug 2005: Changes.
33// - Fixed bug where the InUseThreads becomes negative when canceling work items. 38// - Fixed bug where the InUseThreads becomes negative when canceling work items.
34// 39//
35// 31 Jan 2006 - Changes: 40// 31 Jan 2006 - Changes:
36// - Added work items priority 41// - Added work items priority
37// - Removed support of chained delegates in callbacks and post executes (nobody really use this) 42// - Removed support of chained delegates in callbacks and post executes (nobody really use this)
38// - Added work items groups 43// - Added work items groups
39// - Added work items groups idle event 44// - Added work items groups idle event
40// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array 45// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array
41// it returns true rather then throwing an exception. 46// it returns true rather then throwing an exception.
42// - Added option to start the STP and the WIG as suspended 47// - Added option to start the STP and the WIG as suspended
43// - Exception behavior changed, the real exception is returned by an 48// - Exception behavior changed, the real exception is returned by an
44// inner exception 49// inner exception
45// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) 50// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.)
46// - Added performance counters 51// - Added performance counters
47// - Added priority to the threads in the pool 52// - Added priority to the threads in the pool
48// 53//
49// 13 Feb 2006 - Changes: 54// 13 Feb 2006 - Changes:
50// - Added a call to the dispose of the Performance Counter so 55// - Added a call to the dispose of the Performance Counter so
51// their won't be a Performance Counter leak. 56// their won't be a Performance Counter leak.
52// - Added exception catch in case the Performance Counters cannot 57// - Added exception catch in case the Performance Counters cannot
53// be created. 58// be created.
59//
60// 17 May 2008 - Changes:
61// - Changed the dispose behavior and removed the Finalizers.
62// - Enabled the change of the MaxThreads and MinThreads at run time.
63// - Enabled the change of the Concurrency of a IWorkItemsGroup at run
64// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency
65// refers to the MaxThreads.
66// - Improved the cancel behavior.
67// - Added events for thread creation and termination.
68// - Fixed the HttpContext context capture.
69// - Changed internal collections so they use generic collections
70// - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup
71// - Added support for WinCE
72// - Added support for Action<T> and Func<T>
73//
74// 07 April 2009 - Changes:
75// - Added support for Silverlight and Mono
76// - Added Join, Choice, and Pipe to SmartThreadPool.
77// - Added local performance counters (for Mono, Silverlight, and WindowsCE)
78// - Changed duration measures from DateTime.Now to Stopwatch.
79// - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList<T>.
80//
81// 21 December 2009 - Changes:
82// - Added work item timeout (passive)
83//
84// 20 August 2012 - Changes:
85// - Added set name to threads
86// - Fixed the WorkItemsQueue.Dequeue.
87// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... }
88// - Fixed SmartThreadPool.Pipe
89// - Added IsBackground option to threads
90// - Added ApartmentState to threads
91// - Fixed thread creation when queuing many work items at the same time.
92//
93// 24 August 2012 - Changes:
94// - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan
95// - Added option to set MaxStackSize of threads
96
97#endregion
54 98
55using System; 99using System;
56using System.Security; 100using System.Security;
57using System.Threading; 101using System.Threading;
58using System.Collections; 102using System.Collections;
103using System.Collections.Generic;
59using System.Diagnostics; 104using System.Diagnostics;
60using System.Runtime.CompilerServices; 105using System.Runtime.CompilerServices;
61 106
@@ -63,1213 +108,1503 @@ using Amib.Threading.Internal;
63 108
64namespace Amib.Threading 109namespace Amib.Threading
65{ 110{
66 #region SmartThreadPool class 111 #region SmartThreadPool class
67 /// <summary> 112 /// <summary>
68 /// Smart thread pool class. 113 /// Smart thread pool class.
69 /// </summary> 114 /// </summary>
70 public class SmartThreadPool : IWorkItemsGroup, IDisposable 115 public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable
71 { 116 {
72 #region Default Constants 117 #region Public Default Constants
73 118
74 /// <summary> 119 /// <summary>
75 /// Default minimum number of threads the thread pool contains. (0) 120 /// Default minimum number of threads the thread pool contains. (0)
76 /// </summary> 121 /// </summary>
77 public const int DefaultMinWorkerThreads = 0; 122 public const int DefaultMinWorkerThreads = 0;
78 123
79 /// <summary> 124 /// <summary>
80 /// Default maximum number of threads the thread pool contains. (25) 125 /// Default maximum number of threads the thread pool contains. (25)
81 /// </summary> 126 /// </summary>
82 public const int DefaultMaxWorkerThreads = 25; 127 public const int DefaultMaxWorkerThreads = 25;
83 128
84 /// <summary> 129 /// <summary>
85 /// Default idle timeout in milliseconds. (One minute) 130 /// Default idle timeout in milliseconds. (One minute)
131 /// </summary>
132 public const int DefaultIdleTimeout = 60*1000; // One minute
133
134 /// <summary>
135 /// Indicate to copy the security context of the caller and then use it in the call. (false)
136 /// </summary>
137 public const bool DefaultUseCallerCallContext = false;
138
139 /// <summary>
140 /// Indicate to copy the HTTP context of the caller and then use it in the call. (false)
141 /// </summary>
142 public const bool DefaultUseCallerHttpContext = false;
143
144 /// <summary>
145 /// Indicate to dispose of the state objects if they support the IDispose interface. (false)
146 /// </summary>
147 public const bool DefaultDisposeOfStateObjects = false;
148
149 /// <summary>
150 /// The default option to run the post execute (CallToPostExecute.Always)
151 /// </summary>
152 public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always;
153
154 /// <summary>
155 /// The default post execute method to run. (None)
156 /// When null it means not to call it.
157 /// </summary>
158 public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback;
159
160 /// <summary>
161 /// The default work item priority (WorkItemPriority.Normal)
162 /// </summary>
163 public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal;
164
165 /// <summary>
166 /// The default is to work on work items as soon as they arrive
167 /// and not to wait for the start. (false)
168 /// </summary>
169 public const bool DefaultStartSuspended = false;
170
171 /// <summary>
172 /// The default name to use for the performance counters instance. (null)
173 /// </summary>
174 public static readonly string DefaultPerformanceCounterInstanceName;
175
176#if !(WINDOWS_PHONE)
177
178 /// <summary>
179 /// The default thread priority (ThreadPriority.Normal)
180 /// </summary>
181 public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal;
182#endif
183 /// <summary>
184 /// The default thread pool name. (SmartThreadPool)
86 /// </summary> 185 /// </summary>
87 public const int DefaultIdleTimeout = 60*1000; // One minute 186 public const string DefaultThreadPoolName = "SmartThreadPool";
88 187
89 /// <summary> 188 /// <summary>
90 /// Indicate to copy the security context of the caller and then use it in the call. (false) 189 /// The default Max Stack Size. (SmartThreadPool)
91 /// </summary> 190 /// </summary>
92 public const bool DefaultUseCallerCallContext = false; 191 public static readonly int? DefaultMaxStackSize = null;
93 192
94 /// <summary> 193 /// <summary>
95 /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) 194 /// The default fill state with params. (false)
195 /// It is relevant only to QueueWorkItem of Action&lt;...&gt;/Func&lt;...&gt;
96 /// </summary> 196 /// </summary>
97 public const bool DefaultUseCallerHttpContext = false; 197 public const bool DefaultFillStateWithArgs = false;
98 198
99 /// <summary> 199 /// <summary>
100 /// Indicate to dispose of the state objects if they support the IDispose interface. (false) 200 /// The default thread backgroundness. (true)
101 /// </summary> 201 /// </summary>
102 public const bool DefaultDisposeOfStateObjects = false; 202 public const bool DefaultAreThreadsBackground = true;
103 203
204#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
104 /// <summary> 205 /// <summary>
105 /// The default option to run the post execute 206 /// The default apartment state of a thread in the thread pool.
207 /// The default is ApartmentState.Unknown which means the STP will not
208 /// set the apartment of the thread. It will use the .NET default.
106 /// </summary> 209 /// </summary>
107 public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; 210 public const ApartmentState DefaultApartmentState = ApartmentState.Unknown;
211#endif
108 212
109 /// <summary> 213 #endregion
110 /// The default post execute method to run.
111 /// When null it means not to call it.
112 /// </summary>
113 public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback = null;
114 214
115 /// <summary> 215 #region Member Variables
116 /// The default work item priority
117 /// </summary>
118 public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal;
119 216
120 /// <summary> 217 /// <summary>
121 /// The default is to work on work items as soon as they arrive 218 /// Dictionary of all the threads in the thread pool.
122 /// and not to wait for the start. 219 /// </summary>
123 /// </summary> 220 private readonly SynchronizedDictionary<Thread, ThreadEntry> _workerThreads = new SynchronizedDictionary<Thread, ThreadEntry>();
124 public const bool DefaultStartSuspended = false;
125 221
126 /// <summary> 222 /// <summary>
127 /// The default is not to use the performance counters 223 /// Queue of work items.
128 /// </summary> 224 /// </summary>
129 public static readonly string DefaultPerformanceCounterInstanceName = null; 225 private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue();
130 226
131 public static readonly int DefaultStackSize = 0; 227 /// <summary>
228 /// Count the work items handled.
229 /// Used by the performance counter.
230 /// </summary>
231 private int _workItemsProcessed;
132 232
133 /// <summary> 233 /// <summary>
134 /// The default thread priority 234 /// Number of threads that currently work (not idle).
135 /// </summary> 235 /// </summary>
136 public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; 236 private int _inUseWorkerThreads;
137 237
138 /// <summary> 238 /// <summary>
139 /// The default thread pool name 239 /// Stores a copy of the original STPStartInfo.
240 /// It is used to change the MinThread and MaxThreads
140 /// </summary> 241 /// </summary>
141 public const string DefaultThreadPoolName = "SmartThreadPool"; 242 private STPStartInfo _stpStartInfo;
142 243
143 #endregion 244 /// <summary>
245 /// Total number of work items that are stored in the work items queue
246 /// plus the work items that the threads in the pool are working on.
247 /// </summary>
248 private int _currentWorkItemsCount;
144 249
145 #region Member Variables 250 /// <summary>
251 /// Signaled when the thread pool is idle, i.e. no thread is busy
252 /// and the work items queue is empty
253 /// </summary>
254 //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
255 private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
146 256
147 /// <summary> 257 /// <summary>
148 /// Contains the name of this instance of SmartThreadPool. 258 /// An event to signal all the threads to quit immediately.
149 /// Can be changed by the user. 259 /// </summary>
150 /// </summary> 260 //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false);
151 private string _name = DefaultThreadPoolName; 261 private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false);
152 262
153 /// <summary> 263 /// <summary>
154 /// Hashtable of all the threads in the thread pool. 264 /// A flag to indicate if the Smart Thread Pool is now suspended.
155 /// </summary> 265 /// </summary>
156 private Hashtable _workerThreads = Hashtable.Synchronized(new Hashtable()); 266 private bool _isSuspended;
157 267
158 /// <summary> 268 /// <summary>
159 /// Queue of work items. 269 /// A flag to indicate the threads to quit.
160 /// </summary> 270 /// </summary>
161 private WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); 271 private bool _shutdown;
162 272
163 /// <summary> 273 /// <summary>
164 /// Count the work items handled. 274 /// Counts the threads created in the pool.
165 /// Used by the performance counter. 275 /// It is used to name the threads.
166 /// </summary> 276 /// </summary>
167 private long _workItemsProcessed = 0; 277 private int _threadCounter;
168 278
169 /// <summary> 279 /// <summary>
170 /// Number of threads that currently work (not idle). 280 /// Indicate that the SmartThreadPool has been disposed
171 /// </summary> 281 /// </summary>
172 private int _inUseWorkerThreads = 0; 282 private bool _isDisposed;
173 283
174 /// <summary> 284 /// <summary>
175 /// Start information to use. 285 /// Holds all the WorkItemsGroup instaces that have at least one
176 /// It is simpler than providing many constructors. 286 /// work item int the SmartThreadPool
177 /// </summary> 287 /// This variable is used in case of Shutdown
178 private STPStartInfo _stpStartInfo = new STPStartInfo(); 288 /// </summary>
289 private readonly SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup> _workItemsGroups = new SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup>();
179 290
180 /// <summary> 291 /// <summary>
181 /// Total number of work items that are stored in the work items queue 292 /// A common object for all the work items int the STP
182 /// plus the work items that the threads in the pool are working on. 293 /// so we can mark them to cancel in O(1)
183 /// </summary> 294 /// </summary>
184 private int _currentWorkItemsCount = 0; 295 private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup();
185 296
186 /// <summary> 297 /// <summary>
187 /// Signaled when the thread pool is idle, i.e. no thread is busy 298 /// Windows STP performance counters
188 /// and the work items queue is empty
189 /// </summary> 299 /// </summary>
190 private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); 300 private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance;
191 301
192 /// <summary> 302 /// <summary>
193 /// An event to signal all the threads to quit immediately. 303 /// Local STP performance counters
194 /// </summary> 304 /// </summary>
195 private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); 305 private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance;
196 306
197 /// <summary>
198 /// A flag to indicate the threads to quit.
199 /// </summary>
200 private bool _shutdown = false;
201 307
202 /// <summary> 308#if (WINDOWS_PHONE)
203 /// Counts the threads created in the pool. 309 private static readonly Dictionary<int, ThreadEntry> _threadEntries = new Dictionary<int, ThreadEntry>();
204 /// It is used to name the threads. 310#elif (_WINDOWS_CE)
205 /// </summary> 311 private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot();
206 private int _threadCounter = 0; 312#else
313 [ThreadStatic]
314 private static ThreadEntry _threadEntry;
207 315
208 /// <summary> 316#endif
209 /// Indicate that the SmartThreadPool has been disposed
210 /// </summary>
211 private bool _isDisposed = false;
212 317
213 /// <summary> 318 /// <summary>
214 /// Event to send that the thread pool is idle 319 /// An event to call after a thread is created, but before
320 /// it's first use.
215 /// </summary> 321 /// </summary>
216 private event EventHandler _stpIdle; 322 private event ThreadInitializationHandler _onThreadInitialization;
217 323
218 /// <summary> 324 /// <summary>
219 /// On idle event 325 /// An event to call when a thread is about to exit, after
326 /// it is no longer belong to the pool.
220 /// </summary> 327 /// </summary>
221 //private event WorkItemsGroupIdleHandler _onIdle; 328 private event ThreadTerminationHandler _onThreadTermination;
222 329
223 /// <summary> 330 #endregion
224 /// Holds all the WorkItemsGroup instaces that have at least one
225 /// work item int the SmartThreadPool
226 /// This variable is used in case of Shutdown
227 /// </summary>
228 private Hashtable _workItemsGroups = Hashtable.Synchronized(new Hashtable());
229 331
230 /// <summary> 332 #region Per thread properties
231 /// A reference from each thread in the thread pool to its SmartThreadPool
232 /// object container.
233 /// With this variable a thread can know whatever it belongs to a
234 /// SmartThreadPool.
235 /// </summary>
236 [ThreadStatic]
237 private static SmartThreadPool _smartThreadPool;
238 333
239 /// <summary> 334 /// <summary>
240 /// A reference to the current work item a thread from the thread pool 335 /// A reference to the current work item a thread from the thread pool
241 /// is executing. 336 /// is executing.
242 /// </summary> 337 /// </summary>
243 [ThreadStatic] 338 internal static ThreadEntry CurrentThreadEntry
244 private static WorkItem _currentWorkItem; 339 {
245 340#if (WINDOWS_PHONE)
246 /// <summary> 341 get
247 /// STP performance counters 342 {
248 /// </summary> 343 lock(_threadEntries)
249 private ISTPInstancePerformanceCounters _pcs = NullSTPInstancePerformanceCounters.Instance; 344 {
250 345 ThreadEntry threadEntry;
346 if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry))
347 {
348 return threadEntry;
349 }
350 }
351 return null;
352 }
353 set
354 {
355 lock(_threadEntries)
356 {
357 _threadEntries[Thread.CurrentThread.ManagedThreadId] = value;
358 }
359 }
360#elif (_WINDOWS_CE)
361 get
362 {
363 //Thread.CurrentThread.ManagedThreadId
364 return Thread.GetData(_threadEntrySlot) as ThreadEntry;
365 }
366 set
367 {
368 Thread.SetData(_threadEntrySlot, value);
369 }
370#else
371 get
372 {
373 return _threadEntry;
374 }
375 set
376 {
377 _threadEntry = value;
378 }
379#endif
380 }
251 #endregion 381 #endregion
252 382
253 #region Construction and Finalization 383 #region Construction and Finalization
254 384
255 /// <summary> 385 /// <summary>
256 /// Constructor 386 /// Constructor
257 /// </summary> 387 /// </summary>
258 public SmartThreadPool() 388 public SmartThreadPool()
259 { 389 {
390 _stpStartInfo = new STPStartInfo();
260 Initialize(); 391 Initialize();
261 } 392 }
262 393
263 /// <summary> 394 /// <summary>
264 /// Constructor 395 /// Constructor
265 /// </summary> 396 /// </summary>
266 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 397 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
267 public SmartThreadPool(int idleTimeout) 398 public SmartThreadPool(int idleTimeout)
268 { 399 {
269 _stpStartInfo.IdleTimeout = idleTimeout; 400 _stpStartInfo = new STPStartInfo
270 Initialize(); 401 {
271 } 402 IdleTimeout = idleTimeout,
403 };
404 Initialize();
405 }
406
407 /// <summary>
408 /// Constructor
409 /// </summary>
410 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
411 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
412 public SmartThreadPool(
413 int idleTimeout,
414 int maxWorkerThreads)
415 {
416 _stpStartInfo = new STPStartInfo
417 {
418 IdleTimeout = idleTimeout,
419 MaxWorkerThreads = maxWorkerThreads,
420 };
421 Initialize();
422 }
423
424 /// <summary>
425 /// Constructor
426 /// </summary>
427 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
428 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
429 /// <param name="minWorkerThreads">Lower limit of threads in the pool</param>
430 public SmartThreadPool(
431 int idleTimeout,
432 int maxWorkerThreads,
433 int minWorkerThreads)
434 {
435 _stpStartInfo = new STPStartInfo
436 {
437 IdleTimeout = idleTimeout,
438 MaxWorkerThreads = maxWorkerThreads,
439 MinWorkerThreads = minWorkerThreads,
440 };
441 Initialize();
442 }
272 443
273 /// <summary> 444 /// <summary>
274 /// Constructor 445 /// Constructor
275 /// </summary> 446 /// </summary>
276 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 447 /// <param name="stpStartInfo">A SmartThreadPool configuration that overrides the default behavior</param>
277 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param> 448 public SmartThreadPool(STPStartInfo stpStartInfo)
278 public SmartThreadPool( 449 {
279 int idleTimeout, 450 _stpStartInfo = new STPStartInfo(stpStartInfo);
280 int maxWorkerThreads) 451 Initialize();
281 { 452 }
282 _stpStartInfo.IdleTimeout = idleTimeout;
283 _stpStartInfo.MaxWorkerThreads = maxWorkerThreads;
284 Initialize();
285 }
286 453
287 /// <summary> 454 private void Initialize()
288 /// Constructor 455 {
289 /// </summary> 456 Name = _stpStartInfo.ThreadPoolName;
290 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 457 ValidateSTPStartInfo();
291 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
292 /// <param name="minWorkerThreads">Lower limit of threads in the pool</param>
293 public SmartThreadPool(
294 int idleTimeout,
295 int maxWorkerThreads,
296 int minWorkerThreads)
297 {
298 _stpStartInfo.IdleTimeout = idleTimeout;
299 _stpStartInfo.MaxWorkerThreads = maxWorkerThreads;
300 _stpStartInfo.MinWorkerThreads = minWorkerThreads;
301 Initialize();
302 }
303 458
304 /// <summary> 459 // _stpStartInfoRW stores a read/write copy of the STPStartInfo.
305 /// Constructor 460 // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten
306 /// </summary>
307 public SmartThreadPool(STPStartInfo stpStartInfo)
308 {
309 _stpStartInfo = new STPStartInfo(stpStartInfo);
310 Initialize();
311 }
312 461
313 private void Initialize() 462 _isSuspended = _stpStartInfo.StartSuspended;
314 {
315 Name = _stpStartInfo.ThreadPoolName;
316 ValidateSTPStartInfo();
317 463
464#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE)
465 if (null != _stpStartInfo.PerformanceCounterInstanceName)
466 {
467 throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters");
468 }
469#else
318 if (null != _stpStartInfo.PerformanceCounterInstanceName) 470 if (null != _stpStartInfo.PerformanceCounterInstanceName)
319 { 471 {
320 try 472 try
321 { 473 {
322 _pcs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); 474 _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName);
323 } 475 }
324 catch(Exception e) 476 catch (Exception e)
325 { 477 {
326 Debug.WriteLine("Unable to create Performance Counters: " + e.ToString()); 478 Debug.WriteLine("Unable to create Performance Counters: " + e);
327 _pcs = NullSTPInstancePerformanceCounters.Instance; 479 _windowsPCs = NullSTPInstancePerformanceCounters.Instance;
328 } 480 }
329 } 481 }
482#endif
330 483
331 StartOptimalNumberOfThreads(); 484 if (_stpStartInfo.EnableLocalPerformanceCounters)
332 }
333
334 private void StartOptimalNumberOfThreads()
335 {
336 int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads);
337 threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads);
338 StartThreads(threadsCount);
339 }
340
341 private void ValidateSTPStartInfo()
342 {
343 if (_stpStartInfo.MinWorkerThreads < 0)
344 {
345 throw new ArgumentOutOfRangeException(
346 "MinWorkerThreads", "MinWorkerThreads cannot be negative");
347 }
348
349 if (_stpStartInfo.MaxWorkerThreads <= 0)
350 { 485 {
351 throw new ArgumentOutOfRangeException( 486 _localPCs = new LocalSTPInstancePerformanceCounters();
352 "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero");
353 } 487 }
354 488
355 if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) 489 // If the STP is not started suspended then start the threads.
490 if (!_isSuspended)
356 { 491 {
357 throw new ArgumentOutOfRangeException( 492 StartOptimalNumberOfThreads();
358 "MinWorkerThreads, maxWorkerThreads",
359 "MaxWorkerThreads must be greater or equal to MinWorkerThreads");
360 } 493 }
361 } 494 }
362 495
363 private void ValidateCallback(Delegate callback) 496 private void StartOptimalNumberOfThreads()
364 { 497 {
365 if(callback.GetInvocationList().Length > 1) 498 int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads);
499 threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads);
500 threadsCount -= _workerThreads.Count;
501 if (threadsCount > 0)
366 { 502 {
367 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); 503 StartThreads(threadsCount);
368 } 504 }
369 } 505 }
370 506
371 #endregion 507 private void ValidateSTPStartInfo()
508 {
509 if (_stpStartInfo.MinWorkerThreads < 0)
510 {
511 throw new ArgumentOutOfRangeException(
512 "MinWorkerThreads", "MinWorkerThreads cannot be negative");
513 }
372 514
373 #region Thread Processing 515 if (_stpStartInfo.MaxWorkerThreads <= 0)
516 {
517 throw new ArgumentOutOfRangeException(
518 "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero");
519 }
374 520
375 /// <summary> 521 if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads)
376 /// Waits on the queue for a work item, shutdown, or timeout. 522 {
377 /// </summary> 523 throw new ArgumentOutOfRangeException(
378 /// <returns> 524 "MinWorkerThreads, maxWorkerThreads",
379 /// Returns the WaitingCallback or null in case of timeout or shutdown. 525 "MaxWorkerThreads must be greater or equal to MinWorkerThreads");
380 /// </returns> 526 }
381 private WorkItem Dequeue() 527 }
382 { 528
383 WorkItem workItem = 529 private static void ValidateCallback(Delegate callback)
530 {
531 if(callback.GetInvocationList().Length > 1)
532 {
533 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
534 }
535 }
536
537 #endregion
538
539 #region Thread Processing
540
541 /// <summary>
542 /// Waits on the queue for a work item, shutdown, or timeout.
543 /// </summary>
544 /// <returns>
545 /// Returns the WaitingCallback or null in case of timeout or shutdown.
546 /// </returns>
547 private WorkItem Dequeue()
548 {
549 WorkItem workItem =
384 _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); 550 _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent);
385 551
386 return workItem; 552 return workItem;
387 } 553 }
388 554
389 /// <summary> 555 /// <summary>
390 /// Put a new work item in the queue 556 /// Put a new work item in the queue
391 /// </summary> 557 /// </summary>
392 /// <param name="workItem">A work item to queue</param> 558 /// <param name="workItem">A work item to queue</param>
393 private void Enqueue(WorkItem workItem) 559 internal override void Enqueue(WorkItem workItem)
394 { 560 {
395 Enqueue(workItem, true); 561 // Make sure the workItem is not null
396 } 562 Debug.Assert(null != workItem);
397 563
398 /// <summary> 564 IncrementWorkItemsCount();
399 /// Put a new work item in the queue 565
400 /// </summary> 566 workItem.CanceledSmartThreadPool = _canceledSmartThreadPool;
401 /// <param name="workItem">A work item to queue</param> 567 _workItemsQueue.EnqueueWorkItem(workItem);
402 internal void Enqueue(WorkItem workItem, bool incrementWorkItems) 568 workItem.WorkItemIsQueued();
403 { 569
404 // Make sure the workItem is not null 570 // If all the threads are busy then try to create a new one
405 Debug.Assert(null != workItem); 571 if (_currentWorkItemsCount > _workerThreads.Count)
406 572 {
407 if (incrementWorkItems) 573 StartThreads(1);
408 { 574 }
409 IncrementWorkItemsCount(); 575 }
410 } 576
411 577 private void IncrementWorkItemsCount()
412 _workItemsQueue.EnqueueWorkItem(workItem); 578 {
413 workItem.WorkItemIsQueued(); 579 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
414 580 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
415 // If all the threads are busy then try to create a new one 581
416 if ((InUseThreads + WaitingCallbacks) > _workerThreads.Count) 582 int count = Interlocked.Increment(ref _currentWorkItemsCount);
417 { 583 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
418 StartThreads(1); 584 if (count == 1)
419 } 585 {
420 } 586 IsIdle = false;
421
422 private void IncrementWorkItemsCount()
423 {
424 _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
425
426 int count = Interlocked.Increment(ref _currentWorkItemsCount);
427 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
428 if (count == 1)
429 {
430 //Trace.WriteLine("STP is NOT idle");
431 _isIdleWaitHandle.Reset(); 587 _isIdleWaitHandle.Reset();
432 } 588 }
433 } 589 }
434
435 private void DecrementWorkItemsCount()
436 {
437 ++_workItemsProcessed;
438
439 // The counter counts even if the work item was cancelled
440 _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
441 590
591 private void DecrementWorkItemsCount()
592 {
442 int count = Interlocked.Decrement(ref _currentWorkItemsCount); 593 int count = Interlocked.Decrement(ref _currentWorkItemsCount);
443 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); 594 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
444 if (count == 0) 595 if (count == 0)
445 { 596 {
446 //Trace.WriteLine("STP is idle"); 597 IsIdle = true;
447 _isIdleWaitHandle.Set(); 598 _isIdleWaitHandle.Set();
448 } 599 }
449 }
450 600
451 internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) 601 Interlocked.Increment(ref _workItemsProcessed);
452 {
453 _workItemsGroups[workItemsGroup] = workItemsGroup;
454 }
455
456 internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
457 {
458 if (_workItemsGroups.Contains(workItemsGroup))
459 {
460 _workItemsGroups.Remove(workItemsGroup);
461 }
462 }
463 602
464 /// <summary> 603 if (!_shutdown)
465 /// Inform that the current thread is about to quit or quiting.
466 /// The same thread may call this method more than once.
467 /// </summary>
468 private void InformCompleted()
469 {
470 // There is no need to lock the two methods together
471 // since only the current thread removes itself
472 // and the _workerThreads is a synchronized hashtable
473 if (_workerThreads.Contains(Thread.CurrentThread))
474 { 604 {
475 _workerThreads.Remove(Thread.CurrentThread); 605 // The counter counts even if the work item was cancelled
476 _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 606 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
607 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
477 } 608 }
478 }
479 609
480 /// <summary> 610 }
481 /// Starts new threads 611
482 /// </summary> 612 internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
483 /// <param name="threadsCount">The number of threads to start</param> 613 {
484 private void StartThreads(int threadsCount) 614 _workItemsGroups[workItemsGroup] = workItemsGroup;
485 { 615 }
486 if (_stpStartInfo.StartSuspended) 616
487 { 617 internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
488 return; 618 {
489 } 619 if (_workItemsGroups.Contains(workItemsGroup))
620 {
621 _workItemsGroups.Remove(workItemsGroup);
622 }
623 }
624
625 /// <summary>
626 /// Inform that the current thread is about to quit or quiting.
627 /// The same thread may call this method more than once.
628 /// </summary>
629 private void InformCompleted()
630 {
631 // There is no need to lock the two methods together
632 // since only the current thread removes itself
633 // and the _workerThreads is a synchronized dictionary
634 if (_workerThreads.Contains(Thread.CurrentThread))
635 {
636 _workerThreads.Remove(Thread.CurrentThread);
637 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
638 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
639 }
640 }
641
642 /// <summary>
643 /// Starts new threads
644 /// </summary>
645 /// <param name="threadsCount">The number of threads to start</param>
646 private void StartThreads(int threadsCount)
647 {
648 if (_isSuspended)
649 {
650 return;
651 }
652
653 lock(_workerThreads.SyncRoot)
654 {
655 // Don't start threads on shut down
656 if (_shutdown)
657 {
658 return;
659 }
660
661 for(int i = 0; i < threadsCount; ++i)
662 {
663 // Don't create more threads then the upper limit
664 if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads)
665 {
666 return;
667 }
490 668
491 lock(_workerThreads.SyncRoot) 669 // Create a new thread
492 {
493 // Don't start threads on shut down
494 if (_shutdown)
495 {
496 return;
497 }
498 670
499 for(int i = 0; i < threadsCount; ++i) 671#if (_SILVERLIGHT) || (WINDOWS_PHONE)
500 { 672 Thread workerThread = new Thread(ProcessQueuedItems);
501 // Don't create more threads then the upper limit 673#else
502 if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) 674 Thread workerThread =
675 _stpStartInfo.MaxStackSize.HasValue
676 ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value)
677 : new Thread(ProcessQueuedItems);
678#endif
679 // Configure the new thread and start it
680 workerThread.Name = "STP " + Name + " Thread #" + _threadCounter;
681 workerThread.IsBackground = _stpStartInfo.AreThreadsBackground;
682
683#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE)
684 if (_stpStartInfo.ApartmentState != ApartmentState.Unknown)
503 { 685 {
504 return; 686 workerThread.SetApartmentState(_stpStartInfo.ApartmentState);
505 } 687 }
688#endif
506 689
507 // Create a new thread 690#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
508 Thread workerThread;
509 if (_stpStartInfo.StackSize > 0)
510 workerThread = new Thread(ProcessQueuedItems, _stpStartInfo.StackSize);
511 else
512 workerThread = new Thread(ProcessQueuedItems);
513
514 // Configure the new thread and start it
515 workerThread.Name = "STP " + Name + " Thread #" + _threadCounter;
516 workerThread.IsBackground = true;
517 workerThread.Priority = _stpStartInfo.ThreadPriority; 691 workerThread.Priority = _stpStartInfo.ThreadPriority;
692#endif
518 workerThread.Start(); 693 workerThread.Start();
519 ++_threadCounter; 694 ++_threadCounter;
520 695
521 // Add the new thread to the hashtable and update its creation 696 // Add it to the dictionary and update its creation time.
522 // time. 697 _workerThreads[workerThread] = new ThreadEntry(this);
523 _workerThreads[workerThread] = DateTime.Now; 698
524 _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 699 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
525 } 700 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
526 } 701 }
527 } 702 }
528 703 }
529 /// <summary> 704
530 /// A worker thread method that processes work items from the work items queue. 705 /// <summary>
531 /// </summary> 706 /// A worker thread method that processes work items from the work items queue.
532 private void ProcessQueuedItems() 707 /// </summary>
533 { 708 private void ProcessQueuedItems()
534 // Initialize the _smartThreadPool variable 709 {
535 _smartThreadPool = this; 710 // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks
536 711 // of the dictionary.
537 try 712 CurrentThreadEntry = _workerThreads[Thread.CurrentThread];
538 { 713
539 bool bInUseWorkerThreadsWasIncremented = false; 714 FireOnThreadInitialization();
540 715
541 // Process until shutdown. 716 try
542 while(!_shutdown) 717 {
543 { 718 bool bInUseWorkerThreadsWasIncremented = false;
544 // Update the last time this thread was seen alive. 719
545 // It's good for debugging. 720 // Process until shutdown.
546 _workerThreads[Thread.CurrentThread] = DateTime.Now; 721 while(!_shutdown)
547 722 {
548 // Wait for a work item, shutdown, or timeout 723 // Update the last time this thread was seen alive.
549 WorkItem workItem = Dequeue(); 724 // It's good for debugging.
550 725 CurrentThreadEntry.IAmAlive();
551 // Update the last time this thread was seen alive. 726
552 // It's good for debugging. 727 // The following block handles the when the MaxWorkerThreads has been
553 _workerThreads[Thread.CurrentThread] = DateTime.Now; 728 // incremented by the user at run-time.
554 729 // Double lock for quit.
555 // On timeout or shut down. 730 if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads)
556 if (null == workItem)
557 { 731 {
558 // Double lock for quit. 732 lock (_workerThreads.SyncRoot)
559 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
560 { 733 {
561 lock(_workerThreads.SyncRoot) 734 if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads)
562 { 735 {
563 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) 736 // Inform that the thread is quiting and then quit.
564 { 737 // This method must be called within this lock or else
565 // Inform that the thread is quiting and then quit. 738 // more threads will quit and the thread pool will go
566 // This method must be called within this lock or else 739 // below the lower limit.
567 // more threads will quit and the thread pool will go 740 InformCompleted();
568 // below the lower limit. 741 break;
569 InformCompleted();
570 break;
571 }
572 } 742 }
573 } 743 }
574 } 744 }
575 745
576 // If we didn't quit then skip to the next iteration. 746 // Wait for a work item, shutdown, or timeout
577 if (null == workItem) 747 WorkItem workItem = Dequeue();
578 {
579 continue;
580 }
581
582 try
583 {
584 // Initialize the value to false
585 bInUseWorkerThreadsWasIncremented = false;
586
587 // Change the state of the work item to 'in progress' if possible.
588 // We do it here so if the work item has been canceled we won't
589 // increment the _inUseWorkerThreads.
590 // The cancel mechanism doesn't delete items from the queue,
591 // it marks the work item as canceled, and when the work item
592 // is dequeued, we just skip it.
593 // If the post execute of work item is set to always or to
594 // call when the work item is canceled then the StartingWorkItem()
595 // will return true, so the post execute can run.
596 if (!workItem.StartingWorkItem())
597 {
598 continue;
599 }
600 748
601 // Execute the callback. Make sure to accurately 749 // Update the last time this thread was seen alive.
602 // record how many callbacks are currently executing. 750 // It's good for debugging.
603 int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); 751 CurrentThreadEntry.IAmAlive();
604 _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
605 752
606 // Mark that the _inUseWorkerThreads incremented, so in the finally{} 753 // On timeout or shut down.
607 // statement we will decrement it correctly. 754 if (null == workItem)
608 bInUseWorkerThreadsWasIncremented = true; 755 {
609 756 // Double lock for quit.
610 // Set the _currentWorkItem to the current work item 757 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
611 _currentWorkItem = workItem; 758 {
612 759 lock(_workerThreads.SyncRoot)
613 lock(workItem) 760 {
614 { 761 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
615 workItem.currentThread = Thread.CurrentThread; 762 {
616 } 763 // Inform that the thread is quiting and then quit.
617 764 // This method must be called within this lock or else
618 ExecuteWorkItem(workItem); 765 // more threads will quit and the thread pool will go
619 766 // below the lower limit.
620 lock(workItem) 767 InformCompleted();
621 { 768 break;
622 workItem.currentThread = null; 769 }
623 } 770 }
624 771 }
625 } 772 }
626 catch(ThreadAbortException ex) 773
627 { 774 // If we didn't quit then skip to the next iteration.
628 lock(workItem) 775 if (null == workItem)
629 { 776 {
630 workItem.currentThread = null; 777 continue;
631 } 778 }
632 ex.GetHashCode(); 779
633 Thread.ResetAbort(); 780 try
634 } 781 {
635 catch(Exception ex) 782 // Initialize the value to false
636 { 783 bInUseWorkerThreadsWasIncremented = false;
784
785 // Set the Current Work Item of the thread.
786 // Store the Current Work Item before the workItem.StartingWorkItem() is called,
787 // so WorkItem.Cancel can work when the work item is between InQueue and InProgress
788 // states.
789 // If the work item has been cancelled BEFORE the workItem.StartingWorkItem()
790 // (work item is in InQueue state) then workItem.StartingWorkItem() will return false.
791 // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then
792 // (work item is in InProgress state) then the thread will be aborted
793 CurrentThreadEntry.CurrentWorkItem = workItem;
794
795 // Change the state of the work item to 'in progress' if possible.
796 // We do it here so if the work item has been canceled we won't
797 // increment the _inUseWorkerThreads.
798 // The cancel mechanism doesn't delete items from the queue,
799 // it marks the work item as canceled, and when the work item
800 // is dequeued, we just skip it.
801 // If the post execute of work item is set to always or to
802 // call when the work item is canceled then the StartingWorkItem()
803 // will return true, so the post execute can run.
804 if (!workItem.StartingWorkItem())
805 {
806 continue;
807 }
808
809 // Execute the callback. Make sure to accurately
810 // record how many callbacks are currently executing.
811 int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads);
812 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
813 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
814
815 // Mark that the _inUseWorkerThreads incremented, so in the finally{}
816 // statement we will decrement it correctly.
817 bInUseWorkerThreadsWasIncremented = true;
818
819 workItem.FireWorkItemStarted();
820
821 ExecuteWorkItem(workItem);
822 }
823 catch(Exception ex)
824 {
637 ex.GetHashCode(); 825 ex.GetHashCode();
638 // Do nothing 826 // Do nothing
639 } 827 }
640 finally 828 finally
641 { 829 {
642 lock(workItem) 830 workItem.DisposeOfState();
643 { 831
644 workItem.currentThread = null; 832 // Set the CurrentWorkItem to null, since we
645 } 833 // no longer run user's code.
646 834 CurrentThreadEntry.CurrentWorkItem = null;
647 if (null != workItem) 835
648 { 836 // Decrement the _inUseWorkerThreads only if we had
649 workItem.DisposeOfState(); 837 // incremented it. Note the cancelled work items don't
650 } 838 // increment _inUseWorkerThreads.
651 839 if (bInUseWorkerThreadsWasIncremented)
652 // Set the _currentWorkItem to null, since we 840 {
653 // no longer run user's code. 841 int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads);
654 _currentWorkItem = null; 842 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
655 843 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
656 // Decrement the _inUseWorkerThreads only if we had 844 }
657 // incremented it. Note the cancelled work items don't 845
658 // increment _inUseWorkerThreads. 846 // Notify that the work item has been completed.
659 if (bInUseWorkerThreadsWasIncremented) 847 // WorkItemsGroup may enqueue their next work item.
660 { 848 workItem.FireWorkItemCompleted();
661 int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); 849
662 _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); 850 // Decrement the number of work items here so the idle
663 } 851 // ManualResetEvent won't fluctuate.
664 852 DecrementWorkItemsCount();
665 // Notify that the work item has been completed. 853 }
666 // WorkItemsGroup may enqueue their next work item. 854 }
667 workItem.FireWorkItemCompleted(); 855 }
668 856 catch(ThreadAbortException tae)
669 // Decrement the number of work items here so the idle 857 {
670 // ManualResetEvent won't fluctuate.
671 DecrementWorkItemsCount();
672 }
673 }
674 }
675 catch(ThreadAbortException tae)
676 {
677 tae.GetHashCode(); 858 tae.GetHashCode();
678 // Handle the abort exception gracfully. 859 // Handle the abort exception gracfully.
679 Thread.ResetAbort(); 860#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
680 } 861 Thread.ResetAbort();
681 catch(Exception e) 862#endif
682 {
683 Debug.Assert(null != e);
684 }
685 finally
686 {
687 InformCompleted();
688 }
689 }
690
691 private void ExecuteWorkItem(WorkItem workItem)
692 {
693 _pcs.SampleWorkItemsWaitTime(workItem.WaitingTime);
694 try
695 {
696 workItem.Execute();
697 }
698 catch
699 {
700 throw;
701 } 863 }
702 finally 864 catch(Exception e)
865 {
866 Debug.Assert(null != e);
867 }
868 finally
869 {
870 InformCompleted();
871 FireOnThreadTermination();
872 }
873 }
874
875 private void ExecuteWorkItem(WorkItem workItem)
876 {
877 _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime);
878 _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime);
879 try
880 {
881 workItem.Execute();
882 }
883 finally
884 {
885 _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime);
886 _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime);
887 }
888 }
889
890
891 #endregion
892
893 #region Public Methods
894
895 private void ValidateWaitForIdle()
896 {
897 if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this)
898 {
899 throw new NotSupportedException(
900 "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
901 }
902 }
903
904 internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup)
905 {
906 if (null == CurrentThreadEntry)
703 { 907 {
704 _pcs.SampleWorkItemsProcessTime(workItem.ProcessTime); 908 return;
705 } 909 }
706 }
707
708
709 #endregion
710 910
711 #region Public Methods 911 WorkItem workItem = CurrentThreadEntry.CurrentWorkItem;
712 912 ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem);
713 /// <summary> 913 if ((null != workItemsGroup) &&
714 /// Queue a work item 914 (null != workItem) &&
915 CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup))
916 {
917 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
918 }
919 }
920
921 [MethodImpl(MethodImplOptions.NoInlining)]
922 private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem)
923 {
924 if ((null != workItemsGroup) &&
925 (null != workItem) &&
926 workItem.WasQueuedBy(workItemsGroup))
927 {
928 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
929 }
930 }
931
932 /// <summary>
933 /// Force the SmartThreadPool to shutdown
934 /// </summary>
935 public void Shutdown()
936 {
937 Shutdown(true, 0);
938 }
939
940 /// <summary>
941 /// Force the SmartThreadPool to shutdown with timeout
715 /// </summary> 942 /// </summary>
716 /// <param name="callback">A callback to execute</param> 943 public void Shutdown(bool forceAbort, TimeSpan timeout)
717 /// <returns>Returns a work item result</returns> 944 {
718 public IWorkItemResult QueueWorkItem(WorkItemCallback callback) 945 Shutdown(forceAbort, (int)timeout.TotalMilliseconds);
719 { 946 }
720 ValidateNotDisposed(); 947
721 ValidateCallback(callback); 948 /// <summary>
722 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback); 949 /// Empties the queue of work items and abort the threads in the pool.
723 Enqueue(workItem); 950 /// </summary>
724 return workItem.GetWorkItemResult(); 951 public void Shutdown(bool forceAbort, int millisecondsTimeout)
725 } 952 {
953 ValidateNotDisposed();
954
955 ISTPInstancePerformanceCounters pcs = _windowsPCs;
956
957 if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs)
958 {
959 // Set the _pcs to "null" to stop updating the performance
960 // counters
961 _windowsPCs = NullSTPInstancePerformanceCounters.Instance;
962
963 pcs.Dispose();
964 }
965
966 Thread [] threads;
967 lock(_workerThreads.SyncRoot)
968 {
969 // Shutdown the work items queue
970 _workItemsQueue.Dispose();
971
972 // Signal the threads to exit
973 _shutdown = true;
974 _shuttingDownEvent.Set();
975
976 // Make a copy of the threads' references in the pool
977 threads = new Thread [_workerThreads.Count];
978 _workerThreads.Keys.CopyTo(threads, 0);
979 }
980
981 int millisecondsLeft = millisecondsTimeout;
982 Stopwatch stopwatch = Stopwatch.StartNew();
983 //DateTime start = DateTime.UtcNow;
984 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
985 bool timeout = false;
986
987 // Each iteration we update the time left for the timeout.
988 foreach(Thread thread in threads)
989 {
990 // Join don't work with negative numbers
991 if (!waitInfinitely && (millisecondsLeft < 0))
992 {
993 timeout = true;
994 break;
995 }
996
997 // Wait for the thread to terminate
998 bool success = thread.Join(millisecondsLeft);
999 if(!success)
1000 {
1001 timeout = true;
1002 break;
1003 }
1004
1005 if(!waitInfinitely)
1006 {
1007 // Update the time left to wait
1008 //TimeSpan ts = DateTime.UtcNow - start;
1009 millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
1010 }
1011 }
1012
1013 if (timeout && forceAbort)
1014 {
1015 // Abort the threads in the pool
1016 foreach(Thread thread in threads)
1017 {
1018
1019 if ((thread != null)
1020#if !(_WINDOWS_CE)
1021 && thread.IsAlive
1022#endif
1023 )
1024 {
1025 try
1026 {
1027 thread.Abort(); // Shutdown
1028 }
1029 catch(SecurityException e)
1030 {
1031 e.GetHashCode();
1032 }
1033 catch(ThreadStateException ex)
1034 {
1035 ex.GetHashCode();
1036 // In case the thread has been terminated
1037 // after the check if it is alive.
1038 }
1039 }
1040 }
1041 }
1042 }
1043
1044 /// <summary>
1045 /// Wait for all work items to complete
1046 /// </summary>
1047 /// <param name="waitableResults">Array of work item result objects</param>
1048 /// <returns>
1049 /// true when every work item in workItemResults has completed; otherwise false.
1050 /// </returns>
1051 public static bool WaitAll(
1052 IWaitableResult [] waitableResults)
1053 {
1054 return WaitAll(waitableResults, Timeout.Infinite, true);
1055 }
1056
1057 /// <summary>
1058 /// Wait for all work items to complete
1059 /// </summary>
1060 /// <param name="waitableResults">Array of work item result objects</param>
1061 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1062 /// <param name="exitContext">
1063 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1064 /// </param>
1065 /// <returns>
1066 /// true when every work item in workItemResults has completed; otherwise false.
1067 /// </returns>
1068 public static bool WaitAll(
1069 IWaitableResult [] waitableResults,
1070 TimeSpan timeout,
1071 bool exitContext)
1072 {
1073 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext);
1074 }
1075
1076 /// <summary>
1077 /// Wait for all work items to complete
1078 /// </summary>
1079 /// <param name="waitableResults">Array of work item result objects</param>
1080 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1081 /// <param name="exitContext">
1082 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1083 /// </param>
1084 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1085 /// <returns>
1086 /// true when every work item in workItemResults has completed; otherwise false.
1087 /// </returns>
1088 public static bool WaitAll(
1089 IWaitableResult[] waitableResults,
1090 TimeSpan timeout,
1091 bool exitContext,
1092 WaitHandle cancelWaitHandle)
1093 {
1094 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
1095 }
1096
1097 /// <summary>
1098 /// Wait for all work items to complete
1099 /// </summary>
1100 /// <param name="waitableResults">Array of work item result objects</param>
1101 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1102 /// <param name="exitContext">
1103 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1104 /// </param>
1105 /// <returns>
1106 /// true when every work item in workItemResults has completed; otherwise false.
1107 /// </returns>
1108 public static bool WaitAll(
1109 IWaitableResult [] waitableResults,
1110 int millisecondsTimeout,
1111 bool exitContext)
1112 {
1113 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null);
1114 }
1115
1116 /// <summary>
1117 /// Wait for all work items to complete
1118 /// </summary>
1119 /// <param name="waitableResults">Array of work item result objects</param>
1120 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1121 /// <param name="exitContext">
1122 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1123 /// </param>
1124 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1125 /// <returns>
1126 /// true when every work item in workItemResults has completed; otherwise false.
1127 /// </returns>
1128 public static bool WaitAll(
1129 IWaitableResult[] waitableResults,
1130 int millisecondsTimeout,
1131 bool exitContext,
1132 WaitHandle cancelWaitHandle)
1133 {
1134 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle);
1135 }
1136
1137
1138 /// <summary>
1139 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1140 /// </summary>
1141 /// <param name="waitableResults">Array of work item result objects</param>
1142 /// <returns>
1143 /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled.
1144 /// </returns>
1145 public static int WaitAny(
1146 IWaitableResult [] waitableResults)
1147 {
1148 return WaitAny(waitableResults, Timeout.Infinite, true);
1149 }
1150
1151 /// <summary>
1152 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1153 /// </summary>
1154 /// <param name="waitableResults">Array of work item result objects</param>
1155 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1156 /// <param name="exitContext">
1157 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1158 /// </param>
1159 /// <returns>
1160 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1161 /// </returns>
1162 public static int WaitAny(
1163 IWaitableResult[] waitableResults,
1164 TimeSpan timeout,
1165 bool exitContext)
1166 {
1167 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext);
1168 }
1169
1170 /// <summary>
1171 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1172 /// </summary>
1173 /// <param name="waitableResults">Array of work item result objects</param>
1174 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1175 /// <param name="exitContext">
1176 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1177 /// </param>
1178 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1179 /// <returns>
1180 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1181 /// </returns>
1182 public static int WaitAny(
1183 IWaitableResult [] waitableResults,
1184 TimeSpan timeout,
1185 bool exitContext,
1186 WaitHandle cancelWaitHandle)
1187 {
1188 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
1189 }
1190
1191 /// <summary>
1192 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1193 /// </summary>
1194 /// <param name="waitableResults">Array of work item result objects</param>
1195 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1196 /// <param name="exitContext">
1197 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1198 /// </param>
1199 /// <returns>
1200 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1201 /// </returns>
1202 public static int WaitAny(
1203 IWaitableResult [] waitableResults,
1204 int millisecondsTimeout,
1205 bool exitContext)
1206 {
1207 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null);
1208 }
1209
1210 /// <summary>
1211 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1212 /// </summary>
1213 /// <param name="waitableResults">Array of work item result objects</param>
1214 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1215 /// <param name="exitContext">
1216 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1217 /// </param>
1218 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1219 /// <returns>
1220 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1221 /// </returns>
1222 public static int WaitAny(
1223 IWaitableResult [] waitableResults,
1224 int millisecondsTimeout,
1225 bool exitContext,
1226 WaitHandle cancelWaitHandle)
1227 {
1228 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle);
1229 }
1230
1231 /// <summary>
1232 /// Creates a new WorkItemsGroup.
1233 /// </summary>
1234 /// <param name="concurrency">The number of work items that can be run concurrently</param>
1235 /// <returns>A reference to the WorkItemsGroup</returns>
1236 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency)
1237 {
1238 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo);
1239 return workItemsGroup;
1240 }
726 1241
727 /// <summary> 1242 /// <summary>
728 /// Queue a work item 1243 /// Creates a new WorkItemsGroup.
729 /// </summary> 1244 /// </summary>
730 /// <param name="callback">A callback to execute</param> 1245 /// <param name="concurrency">The number of work items that can be run concurrently</param>
731 /// <param name="workItemPriority">The priority of the work item</param> 1246 /// <param name="wigStartInfo">A WorkItemsGroup configuration that overrides the default behavior</param>
732 /// <returns>Returns a work item result</returns> 1247 /// <returns>A reference to the WorkItemsGroup</returns>
733 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) 1248 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo)
734 { 1249 {
735 ValidateNotDisposed(); 1250 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo);
736 ValidateCallback(callback); 1251 return workItemsGroup;
737 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, workItemPriority); 1252 }
738 Enqueue(workItem);
739 return workItem.GetWorkItemResult();
740 }
741 1253
742 /// <summary> 1254 #region Fire Thread's Events
743 /// Queue a work item
744 /// </summary>
745 /// <param name="workItemInfo">Work item info</param>
746 /// <param name="callback">A callback to execute</param>
747 /// <returns>Returns a work item result</returns>
748 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
749 {
750 ValidateNotDisposed();
751 ValidateCallback(callback);
752 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback);
753 Enqueue(workItem);
754 return workItem.GetWorkItemResult();
755 }
756 1255
757 /// <summary> 1256 private void FireOnThreadInitialization()
758 /// Queue a work item
759 /// </summary>
760 /// <param name="callback">A callback to execute</param>
761 /// <param name="state">
762 /// The context object of the work item. Used for passing arguments to the work item.
763 /// </param>
764 /// <returns>Returns a work item result</returns>
765 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
766 { 1257 {
767 ValidateNotDisposed(); 1258 if (null != _onThreadInitialization)
768 ValidateCallback(callback); 1259 {
769 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state); 1260 foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList())
770 Enqueue(workItem); 1261 {
771 return workItem.GetWorkItemResult(); 1262 try
1263 {
1264 tih();
1265 }
1266 catch (Exception e)
1267 {
1268 e.GetHashCode();
1269 Debug.Assert(false);
1270 throw;
1271 }
1272 }
1273 }
772 } 1274 }
773 1275
774 /// <summary> 1276 private void FireOnThreadTermination()
775 /// Queue a work item
776 /// </summary>
777 /// <param name="callback">A callback to execute</param>
778 /// <param name="state">
779 /// The context object of the work item. Used for passing arguments to the work item.
780 /// </param>
781 /// <param name="workItemPriority">The work item priority</param>
782 /// <returns>Returns a work item result</returns>
783 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
784 { 1277 {
785 ValidateNotDisposed(); 1278 if (null != _onThreadTermination)
786 ValidateCallback(callback); 1279 {
787 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, workItemPriority); 1280 foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList())
788 Enqueue(workItem); 1281 {
789 return workItem.GetWorkItemResult(); 1282 try
1283 {
1284 tth();
1285 }
1286 catch (Exception e)
1287 {
1288 e.GetHashCode();
1289 Debug.Assert(false);
1290 throw;
1291 }
1292 }
1293 }
790 } 1294 }
791 1295
792 /// <summary> 1296 #endregion
793 /// Queue a work item
794 /// </summary>
795 /// <param name="workItemInfo">Work item information</param>
796 /// <param name="callback">A callback to execute</param>
797 /// <param name="state">
798 /// The context object of the work item. Used for passing arguments to the work item.
799 /// </param>
800 /// <returns>Returns a work item result</returns>
801 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
802 {
803 ValidateNotDisposed();
804 ValidateCallback(callback);
805 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback, state);
806 Enqueue(workItem);
807 return workItem.GetWorkItemResult();
808 }
809 1297
810 /// <summary> 1298 /// <summary>
811 /// Queue a work item 1299 /// This event is fired when a thread is created.
1300 /// Use it to initialize a thread before the work items use it.
812 /// </summary> 1301 /// </summary>
813 /// <param name="callback">A callback to execute</param> 1302 public event ThreadInitializationHandler OnThreadInitialization
814 /// <param name="state">
815 /// The context object of the work item. Used for passing arguments to the work item.
816 /// </param>
817 /// <param name="postExecuteWorkItemCallback">
818 /// A delegate to call after the callback completion
819 /// </param>
820 /// <returns>Returns a work item result</returns>
821 public IWorkItemResult QueueWorkItem(
822 WorkItemCallback callback,
823 object state,
824 PostExecuteWorkItemCallback postExecuteWorkItemCallback)
825 { 1303 {
826 ValidateNotDisposed(); 1304 add { _onThreadInitialization += value; }
827 ValidateCallback(callback); 1305 remove { _onThreadInitialization -= value; }
828 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback);
829 Enqueue(workItem);
830 return workItem.GetWorkItemResult();
831 } 1306 }
832 1307
833 /// <summary> 1308 /// <summary>
834 /// Queue a work item 1309 /// This event is fired when a thread is terminating.
1310 /// Use it for cleanup.
835 /// </summary> 1311 /// </summary>
836 /// <param name="callback">A callback to execute</param> 1312 public event ThreadTerminationHandler OnThreadTermination
837 /// <param name="state">
838 /// The context object of the work item. Used for passing arguments to the work item.
839 /// </param>
840 /// <param name="postExecuteWorkItemCallback">
841 /// A delegate to call after the callback completion
842 /// </param>
843 /// <param name="workItemPriority">The work item priority</param>
844 /// <returns>Returns a work item result</returns>
845 public IWorkItemResult QueueWorkItem(
846 WorkItemCallback callback,
847 object state,
848 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
849 WorkItemPriority workItemPriority)
850 { 1313 {
851 ValidateNotDisposed(); 1314 add { _onThreadTermination += value; }
852 ValidateCallback(callback); 1315 remove { _onThreadTermination -= value; }
853 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
854 Enqueue(workItem);
855 return workItem.GetWorkItemResult();
856 } 1316 }
857 1317
858 /// <summary>
859 /// Queue a work item
860 /// </summary>
861 /// <param name="callback">A callback to execute</param>
862 /// <param name="state">
863 /// The context object of the work item. Used for passing arguments to the work item.
864 /// </param>
865 /// <param name="postExecuteWorkItemCallback">
866 /// A delegate to call after the callback completion
867 /// </param>
868 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
869 /// <returns>Returns a work item result</returns>
870 public IWorkItemResult QueueWorkItem(
871 WorkItemCallback callback,
872 object state,
873 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
874 CallToPostExecute callToPostExecute)
875 {
876 ValidateNotDisposed();
877 ValidateCallback(callback);
878 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
879 Enqueue(workItem);
880 return workItem.GetWorkItemResult();
881 }
882 1318
883 /// <summary> 1319 internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig)
884 /// Queue a work item
885 /// </summary>
886 /// <param name="callback">A callback to execute</param>
887 /// <param name="state">
888 /// The context object of the work item. Used for passing arguments to the work item.
889 /// </param>
890 /// <param name="postExecuteWorkItemCallback">
891 /// A delegate to call after the callback completion
892 /// </param>
893 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
894 /// <param name="workItemPriority">The work item priority</param>
895 /// <returns>Returns a work item result</returns>
896 public IWorkItemResult QueueWorkItem(
897 WorkItemCallback callback,
898 object state,
899 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
900 CallToPostExecute callToPostExecute,
901 WorkItemPriority workItemPriority)
902 { 1320 {
903 ValidateNotDisposed(); 1321 foreach (ThreadEntry threadEntry in _workerThreads.Values)
904 ValidateCallback(callback); 1322 {
905 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); 1323 WorkItem workItem = threadEntry.CurrentWorkItem;
906 Enqueue(workItem); 1324 if (null != workItem &&
907 return workItem.GetWorkItemResult(); 1325 workItem.WasQueuedBy(wig) &&
1326 !workItem.IsCanceled)
1327 {
1328 threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true);
1329 }
1330 }
908 } 1331 }
909 1332
910 /// <summary> 1333
911 /// Wait for the thread pool to be idle
912 /// </summary>
913 public void WaitForIdle()
914 {
915 WaitForIdle(Timeout.Infinite);
916 }
917 1334
918 /// <summary> 1335 #endregion
919 /// Wait for the thread pool to be idle
920 /// </summary>
921 public bool WaitForIdle(TimeSpan timeout)
922 {
923 return WaitForIdle((int)timeout.TotalMilliseconds);
924 }
925 1336
926 /// <summary> 1337 #region Properties
927 /// Wait for the thread pool to be idle
928 /// </summary>
929 public bool WaitForIdle(int millisecondsTimeout)
930 {
931 ValidateWaitForIdle();
932 return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false);
933 }
934 1338
935 private void ValidateWaitForIdle() 1339 /// <summary>
936 { 1340 /// Get/Set the lower limit of threads in the pool.
937 if(_smartThreadPool == this) 1341 /// </summary>
1342 public int MinThreads
1343 {
1344 get
1345 {
1346 ValidateNotDisposed();
1347 return _stpStartInfo.MinWorkerThreads;
1348 }
1349 set
938 { 1350 {
939 throw new NotSupportedException( 1351 Debug.Assert(value >= 0);
940 "WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); 1352 Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads);
1353 if (_stpStartInfo.MaxWorkerThreads < value)
1354 {
1355 _stpStartInfo.MaxWorkerThreads = value;
1356 }
1357 _stpStartInfo.MinWorkerThreads = value;
1358 StartOptimalNumberOfThreads();
941 } 1359 }
942 } 1360 }
1361
1362 /// <summary>
1363 /// Get/Set the upper limit of threads in the pool.
1364 /// </summary>
1365 public int MaxThreads
1366 {
1367 get
1368 {
1369 ValidateNotDisposed();
1370 return _stpStartInfo.MaxWorkerThreads;
1371 }
943 1372
944 internal void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) 1373 set
1374 {
1375 Debug.Assert(value > 0);
1376 Debug.Assert(value >= _stpStartInfo.MinWorkerThreads);
1377 if (_stpStartInfo.MinWorkerThreads > value)
1378 {
1379 _stpStartInfo.MinWorkerThreads = value;
1380 }
1381 _stpStartInfo.MaxWorkerThreads = value;
1382 StartOptimalNumberOfThreads();
1383 }
1384 }
1385 /// <summary>
1386 /// Get the number of threads in the thread pool.
1387 /// Should be between the lower and the upper limits.
1388 /// </summary>
1389 public int ActiveThreads
1390 {
1391 get
1392 {
1393 ValidateNotDisposed();
1394 return _workerThreads.Count;
1395 }
1396 }
1397
1398 /// <summary>
1399 /// Get the number of busy (not idle) threads in the thread pool.
1400 /// </summary>
1401 public int InUseThreads
1402 {
1403 get
1404 {
1405 ValidateNotDisposed();
1406 return _inUseWorkerThreads;
1407 }
1408 }
1409
1410 /// <summary>
1411 /// Returns true if the current running work item has been cancelled.
1412 /// Must be used within the work item's callback method.
1413 /// The work item should sample this value in order to know if it
1414 /// needs to quit before its completion.
1415 /// </summary>
1416 public static bool IsWorkItemCanceled
945 { 1417 {
946 ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, SmartThreadPool._currentWorkItem); 1418 get
947 if ((null != workItemsGroup) &&
948 (null != SmartThreadPool._currentWorkItem) &&
949 SmartThreadPool._currentWorkItem.WasQueuedBy(workItemsGroup))
950 { 1419 {
951 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); 1420 return CurrentThreadEntry.CurrentWorkItem.IsCanceled;
952 } 1421 }
953 } 1422 }
954 1423
955 [MethodImpl(MethodImplOptions.NoInlining)] 1424 /// <summary>
956 private void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) 1425 /// Checks if the work item has been cancelled, and if yes then abort the thread.
1426 /// Can be used with Cancel and timeout
1427 /// </summary>
1428 public static void AbortOnWorkItemCancel()
957 { 1429 {
958 if ((null != workItemsGroup) && 1430 if (IsWorkItemCanceled)
959 (null != workItem) &&
960 workItem.WasQueuedBy(workItemsGroup))
961 { 1431 {
962 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); 1432 Thread.CurrentThread.Abort();
963 } 1433 }
964 } 1434 }
965 1435
966
967
968 /// <summary> 1436 /// <summary>
969 /// Force the SmartThreadPool to shutdown 1437 /// Thread Pool start information (readonly)
970 /// </summary> 1438 /// </summary>
971 public void Shutdown() 1439 public STPStartInfo STPStartInfo
972 { 1440 {
973 Shutdown(true, 0); 1441 get
1442 {
1443 return _stpStartInfo.AsReadOnly();
1444 }
974 } 1445 }
975 1446
976 public void Shutdown(bool forceAbort, TimeSpan timeout) 1447 public bool IsShuttingdown
977 { 1448 {
978 Shutdown(forceAbort, (int)timeout.TotalMilliseconds); 1449 get { return _shutdown; }
979 } 1450 }
980 1451
981 /// <summary> 1452 /// <summary>
982 /// Empties the queue of work items and abort the threads in the pool. 1453 /// Return the local calculated performance counters
1454 /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true.
983 /// </summary> 1455 /// </summary>
984 public void Shutdown(bool forceAbort, int millisecondsTimeout) 1456 public ISTPPerformanceCountersReader PerformanceCountersReader
985 { 1457 {
986 ValidateNotDisposed(); 1458 get { return (ISTPPerformanceCountersReader)_localPCs; }
987 1459 }
988 ISTPInstancePerformanceCounters pcs = _pcs;
989
990 if (NullSTPInstancePerformanceCounters.Instance != _pcs)
991 {
992 _pcs.Dispose();
993 // Set the _pcs to "null" to stop updating the performance
994 // counters
995 _pcs = NullSTPInstancePerformanceCounters.Instance;
996 }
997
998 Thread [] threads = null;
999 lock(_workerThreads.SyncRoot)
1000 {
1001 // Shutdown the work items queue
1002 _workItemsQueue.Dispose();
1003
1004 // Signal the threads to exit
1005 _shutdown = true;
1006 _shuttingDownEvent.Set();
1007 1460
1008 // Make a copy of the threads' references in the pool 1461 #endregion
1009 threads = new Thread [_workerThreads.Count];
1010 _workerThreads.Keys.CopyTo(threads, 0);
1011 }
1012 1462
1013 int millisecondsLeft = millisecondsTimeout; 1463 #region IDisposable Members
1014 DateTime start = DateTime.Now;
1015 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
1016 bool timeout = false;
1017 1464
1018 // Each iteration we update the time left for the timeout. 1465 public void Dispose()
1019 foreach(Thread thread in threads) 1466 {
1467 if (!_isDisposed)
1020 { 1468 {
1021 // Join don't work with negative numbers 1469 if (!_shutdown)
1022 if (!waitInfinitely && (millisecondsLeft < 0))
1023 { 1470 {
1024 timeout = true; 1471 Shutdown();
1025 break;
1026 } 1472 }
1027 1473
1028 // Wait for the thread to terminate 1474 if (null != _shuttingDownEvent)
1029 bool success = thread.Join(millisecondsLeft);
1030 if(!success)
1031 { 1475 {
1032 timeout = true; 1476 _shuttingDownEvent.Close();
1033 break; 1477 _shuttingDownEvent = null;
1034 } 1478 }
1035 1479 _workerThreads.Clear();
1036 if(!waitInfinitely) 1480
1481 if (null != _isIdleWaitHandle)
1037 { 1482 {
1038 // Update the time left to wait 1483 _isIdleWaitHandle.Close();
1039 TimeSpan ts = DateTime.Now - start; 1484 _isIdleWaitHandle = null;
1040 millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds;
1041 } 1485 }
1042 }
1043 1486
1044 if (timeout && forceAbort) 1487 _isDisposed = true;
1045 {
1046 // Abort the threads in the pool
1047 foreach(Thread thread in threads)
1048 {
1049 if ((thread != null) && thread.IsAlive)
1050 {
1051 try
1052 {
1053 thread.Abort("Shutdown");
1054 }
1055 catch(SecurityException e)
1056 {
1057 e.GetHashCode();
1058 }
1059 catch(ThreadStateException ex)
1060 {
1061 ex.GetHashCode();
1062 // In case the thread has been terminated
1063 // after the check if it is alive.
1064 }
1065 }
1066 }
1067 } 1488 }
1068
1069 // Dispose of the performance counters
1070 pcs.Dispose();
1071 } 1489 }
1072 1490
1073 /// <summary> 1491 private void ValidateNotDisposed()
1074 /// Wait for all work items to complete
1075 /// </summary>
1076 /// <param name="workItemResults">Array of work item result objects</param>
1077 /// <returns>
1078 /// true when every work item in workItemResults has completed; otherwise false.
1079 /// </returns>
1080 public static bool WaitAll(
1081 IWorkItemResult [] workItemResults)
1082 { 1492 {
1083 return WaitAll(workItemResults, Timeout.Infinite, true); 1493 if(_isDisposed)
1494 {
1495 throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
1496 }
1084 } 1497 }
1498 #endregion
1499
1500 #region WorkItemsGroupBase Overrides
1085 1501
1086 /// <summary> 1502 /// <summary>
1087 /// Wait for all work items to complete 1503 /// Get/Set the maximum number of work items that execute cocurrency on the thread pool
1088 /// </summary> 1504 /// </summary>
1089 /// <param name="workItemResults">Array of work item result objects</param> 1505 public override int Concurrency
1090 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1506 {
1091 /// <param name="exitContext"> 1507 get { return MaxThreads; }
1092 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1508 set { MaxThreads = value; }
1093 /// </param> 1509 }
1094 /// <returns> 1510
1095 /// true when every work item in workItemResults has completed; otherwise false. 1511 /// <summary>
1096 /// </returns> 1512 /// Get the number of work items in the queue.
1097 public static bool WaitAll( 1513 /// </summary>
1098 IWorkItemResult [] workItemResults, 1514 public override int WaitingCallbacks
1099 TimeSpan timeout, 1515 {
1100 bool exitContext) 1516 get
1101 { 1517 {
1102 return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext); 1518 ValidateNotDisposed();
1103 } 1519 return _workItemsQueue.Count;
1520 }
1521 }
1104 1522
1105 /// <summary> 1523 /// <summary>
1106 /// Wait for all work items to complete 1524 /// Get an array with all the state objects of the currently running items.
1525 /// The array represents a snap shot and impact performance.
1107 /// </summary> 1526 /// </summary>
1108 /// <param name="workItemResults">Array of work item result objects</param> 1527 public override object[] GetStates()
1109 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1110 /// <param name="exitContext">
1111 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1112 /// </param>
1113 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1114 /// <returns>
1115 /// true when every work item in workItemResults has completed; otherwise false.
1116 /// </returns>
1117 public static bool WaitAll(
1118 IWorkItemResult [] workItemResults,
1119 TimeSpan timeout,
1120 bool exitContext,
1121 WaitHandle cancelWaitHandle)
1122 { 1528 {
1123 return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); 1529 object[] states = _workItemsQueue.GetStates();
1530 return states;
1124 } 1531 }
1125 1532
1126 /// <summary> 1533 /// <summary>
1127 /// Wait for all work items to complete 1534 /// WorkItemsGroup start information (readonly)
1128 /// </summary> 1535 /// </summary>
1129 /// <param name="workItemResults">Array of work item result objects</param> 1536 public override WIGStartInfo WIGStartInfo
1130 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1131 /// <param name="exitContext">
1132 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1133 /// </param>
1134 /// <returns>
1135 /// true when every work item in workItemResults has completed; otherwise false.
1136 /// </returns>
1137 public static bool WaitAll(
1138 IWorkItemResult [] workItemResults,
1139 int millisecondsTimeout,
1140 bool exitContext)
1141 { 1537 {
1142 return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, null); 1538 get { return _stpStartInfo.AsReadOnly(); }
1143 } 1539 }
1144 1540
1145 /// <summary> 1541 /// <summary>
1146 /// Wait for all work items to complete 1542 /// Start the thread pool if it was started suspended.
1543 /// If it is already running, this method is ignored.
1147 /// </summary> 1544 /// </summary>
1148 /// <param name="workItemResults">Array of work item result objects</param> 1545 public override void Start()
1149 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1150 /// <param name="exitContext">
1151 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1152 /// </param>
1153 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1154 /// <returns>
1155 /// true when every work item in workItemResults has completed; otherwise false.
1156 /// </returns>
1157 public static bool WaitAll(
1158 IWorkItemResult [] workItemResults,
1159 int millisecondsTimeout,
1160 bool exitContext,
1161 WaitHandle cancelWaitHandle)
1162 { 1546 {
1163 return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle); 1547 if (!_isSuspended)
1164 } 1548 {
1549 return;
1550 }
1551 _isSuspended = false;
1165 1552
1553 ICollection workItemsGroups = _workItemsGroups.Values;
1554 foreach (WorkItemsGroup workItemsGroup in workItemsGroups)
1555 {
1556 workItemsGroup.OnSTPIsStarting();
1557 }
1166 1558
1167 /// <summary> 1559 StartOptimalNumberOfThreads();
1168 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1169 /// </summary>
1170 /// <param name="workItemResults">Array of work item result objects</param>
1171 /// <returns>
1172 /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled.
1173 /// </returns>
1174 public static int WaitAny(
1175 IWorkItemResult [] workItemResults)
1176 {
1177 return WaitAny(workItemResults, Timeout.Infinite, true);
1178 } 1560 }
1179 1561
1180 /// <summary> 1562 /// <summary>
1181 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1563 /// Cancel all work items using thread abortion
1182 /// </summary> 1564 /// </summary>
1183 /// <param name="workItemResults">Array of work item result objects</param> 1565 /// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
1184 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1566 public override void Cancel(bool abortExecution)
1185 /// <param name="exitContext">
1186 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1187 /// </param>
1188 /// <returns>
1189 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1190 /// </returns>
1191 public static int WaitAny(
1192 IWorkItemResult [] workItemResults,
1193 TimeSpan timeout,
1194 bool exitContext)
1195 { 1567 {
1196 return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext); 1568 _canceledSmartThreadPool.IsCanceled = true;
1197 } 1569 _canceledSmartThreadPool = new CanceledWorkItemsGroup();
1198 1570
1199 /// <summary> 1571 ICollection workItemsGroups = _workItemsGroups.Values;
1200 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1572 foreach (WorkItemsGroup workItemsGroup in workItemsGroups)
1201 /// </summary> 1573 {
1202 /// <param name="workItemResults">Array of work item result objects</param> 1574 workItemsGroup.Cancel(abortExecution);
1203 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1575 }
1204 /// <param name="exitContext"> 1576
1205 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1577 if (abortExecution)
1206 /// </param> 1578 {
1207 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1579 foreach (ThreadEntry threadEntry in _workerThreads.Values)
1208 /// <returns> 1580 {
1209 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1581 WorkItem workItem = threadEntry.CurrentWorkItem;
1210 /// </returns> 1582 if (null != workItem &&
1211 public static int WaitAny( 1583 threadEntry.AssociatedSmartThreadPool == this &&
1212 IWorkItemResult [] workItemResults, 1584 !workItem.IsCanceled)
1213 TimeSpan timeout, 1585 {
1214 bool exitContext, 1586 threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true);
1215 WaitHandle cancelWaitHandle) 1587 }
1216 { 1588 }
1217 return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); 1589 }
1218 } 1590 }
1219 1591
1220 /// <summary> 1592 /// <summary>
1221 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1593 /// Wait for the thread pool to be idle
1222 /// </summary> 1594 /// </summary>
1223 /// <param name="workItemResults">Array of work item result objects</param> 1595 public override bool WaitForIdle(int millisecondsTimeout)
1224 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1225 /// <param name="exitContext">
1226 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1227 /// </param>
1228 /// <returns>
1229 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1230 /// </returns>
1231 public static int WaitAny(
1232 IWorkItemResult [] workItemResults,
1233 int millisecondsTimeout,
1234 bool exitContext)
1235 { 1596 {
1236 return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, null); 1597 ValidateWaitForIdle();
1598 return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
1237 } 1599 }
1238 1600
1239 /// <summary> 1601 /// <summary>
1240 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1602 /// This event is fired when all work items are completed.
1603 /// (When IsIdle changes to true)
1604 /// This event only work on WorkItemsGroup. On SmartThreadPool
1605 /// it throws the NotImplementedException.
1241 /// </summary> 1606 /// </summary>
1242 /// <param name="workItemResults">Array of work item result objects</param> 1607 public override event WorkItemsGroupIdleHandler OnIdle
1243 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1244 /// <param name="exitContext">
1245 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1246 /// </param>
1247 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1248 /// <returns>
1249 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1250 /// </returns>
1251 public static int WaitAny(
1252 IWorkItemResult [] workItemResults,
1253 int millisecondsTimeout,
1254 bool exitContext,
1255 WaitHandle cancelWaitHandle)
1256 {
1257 return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle);
1258 }
1259
1260 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency)
1261 {
1262 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo);
1263 return workItemsGroup;
1264 }
1265
1266 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo)
1267 {
1268 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo);
1269 return workItemsGroup;
1270 }
1271
1272 public event WorkItemsGroupIdleHandler OnIdle
1273 { 1608 {
1274 add 1609 add
1275 { 1610 {
@@ -1283,166 +1618,115 @@ namespace Amib.Threading
1283 } 1618 }
1284 } 1619 }
1285 1620
1286 public void Cancel() 1621 internal override void PreQueueWorkItem()
1287 {
1288 ICollection workItemsGroups = _workItemsGroups.Values;
1289 foreach(WorkItemsGroup workItemsGroup in workItemsGroups)
1290 {
1291 workItemsGroup.Cancel();
1292 }
1293 }
1294
1295 public void Start()
1296 { 1622 {
1297 lock (this) 1623 ValidateNotDisposed();
1298 {
1299 if (!this._stpStartInfo.StartSuspended)
1300 {
1301 return;
1302 }
1303 _stpStartInfo.StartSuspended = false;
1304 }
1305
1306 ICollection workItemsGroups = _workItemsGroups.Values;
1307 foreach(WorkItemsGroup workItemsGroup in workItemsGroups)
1308 {
1309 workItemsGroup.OnSTPIsStarting();
1310 }
1311
1312 StartOptimalNumberOfThreads();
1313 } 1624 }
1314 1625
1315 #endregion 1626 #endregion
1316 1627
1317 #region Properties 1628 #region Join, Choice, Pipe, etc.
1318 1629
1319 /// <summary> 1630 /// <summary>
1320 /// Get/Set the name of the SmartThreadPool instance 1631 /// Executes all actions in parallel.
1632 /// Returns when they all finish.
1321 /// </summary> 1633 /// </summary>
1322 public string Name 1634 /// <param name="actions">Actions to execute</param>
1323 { 1635 public void Join(IEnumerable<Action> actions)
1324 get 1636 {
1325 { 1637 WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true };
1326 return _name; 1638 IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo);
1327 } 1639 foreach (Action action in actions)
1328
1329 set
1330 {
1331 _name = value;
1332 }
1333 }
1334
1335 /// <summary>
1336 /// Get the lower limit of threads in the pool.
1337 /// </summary>
1338 public int MinThreads
1339 {
1340 get
1341 { 1640 {
1342 ValidateNotDisposed(); 1641 workItemsGroup.QueueWorkItem(action);
1343 return _stpStartInfo.MinWorkerThreads;
1344 } 1642 }
1643 workItemsGroup.Start();
1644 workItemsGroup.WaitForIdle();
1345 } 1645 }
1346 1646
1347 /// <summary> 1647 /// <summary>
1348 /// Get the upper limit of threads in the pool. 1648 /// Executes all actions in parallel.
1349 /// </summary> 1649 /// Returns when they all finish.
1350 public int MaxThreads
1351 {
1352 get
1353 {
1354 ValidateNotDisposed();
1355 return _stpStartInfo.MaxWorkerThreads;
1356 }
1357 }
1358 /// <summary>
1359 /// Get the number of threads in the thread pool.
1360 /// Should be between the lower and the upper limits.
1361 /// </summary> 1650 /// </summary>
1362 public int ActiveThreads 1651 /// <param name="actions">Actions to execute</param>
1363 { 1652 public void Join(params Action[] actions)
1364 get 1653 {
1365 { 1654 Join((IEnumerable<Action>)actions);
1366 ValidateNotDisposed();
1367 return _workerThreads.Count;
1368 }
1369 } 1655 }
1370 1656
1371 /// <summary> 1657 private class ChoiceIndex
1372 /// Get the number of busy (not idle) threads in the thread pool. 1658 {
1373 /// </summary> 1659 public int _index = -1;
1374 public int InUseThreads
1375 {
1376 get
1377 {
1378 ValidateNotDisposed();
1379 return _inUseWorkerThreads;
1380 }
1381 } 1660 }
1382 1661
1383 /// <summary> 1662 /// <summary>
1384 /// Get the number of work items in the queue. 1663 /// Executes all actions in parallel
1664 /// Returns when the first one completes
1385 /// </summary> 1665 /// </summary>
1386 public int WaitingCallbacks 1666 /// <param name="actions">Actions to execute</param>
1387 { 1667 public int Choice(IEnumerable<Action> actions)
1388 get 1668 {
1389 { 1669 WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true };
1390 ValidateNotDisposed(); 1670 IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo);
1391 return _workItemsQueue.Count;
1392 }
1393 }
1394 1671
1672 ManualResetEvent anActionCompleted = new ManualResetEvent(false);
1395 1673
1396 public event EventHandler Idle 1674 ChoiceIndex choiceIndex = new ChoiceIndex();
1397 { 1675
1398 add 1676 int i = 0;
1677 foreach (Action action in actions)
1399 { 1678 {
1400 _stpIdle += value; 1679 Action act = action;
1680 int value = i;
1681 workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); });
1682 ++i;
1401 } 1683 }
1684 workItemsGroup.Start();
1685 anActionCompleted.WaitOne();
1402 1686
1403 remove 1687 return choiceIndex._index;
1404 {
1405 _stpIdle -= value;
1406 }
1407 } 1688 }
1408 1689
1409 #endregion 1690 /// <summary>
1410 1691 /// Executes all actions in parallel
1411 #region IDisposable Members 1692 /// Returns when the first one completes
1412 1693 /// </summary>
1413// ~SmartThreadPool() 1694 /// <param name="actions">Actions to execute</param>
1414// { 1695 public int Choice(params Action[] actions)
1415// Dispose(); 1696 {
1416// } 1697 return Choice((IEnumerable<Action>)actions);
1698 }
1417 1699
1418 public void Dispose() 1700 /// <summary>
1701 /// Executes actions in sequence asynchronously.
1702 /// Returns immediately.
1703 /// </summary>
1704 /// <param name="pipeState">A state context that passes </param>
1705 /// <param name="actions">Actions to execute in the order they should run</param>
1706 public void Pipe<T>(T pipeState, IEnumerable<Action<T>> actions)
1419 { 1707 {
1420 if (!_isDisposed) 1708 WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true };
1709 IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo);
1710 foreach (Action<T> action in actions)
1421 { 1711 {
1422 if (!_shutdown) 1712 Action<T> act = action;
1423 { 1713 workItemsGroup.QueueWorkItem(() => act(pipeState));
1424 Shutdown();
1425 }
1426
1427 if (null != _shuttingDownEvent)
1428 {
1429 _shuttingDownEvent.Close();
1430 _shuttingDownEvent = null;
1431 }
1432 _workerThreads.Clear();
1433 _isDisposed = true;
1434 GC.SuppressFinalize(this);
1435 } 1714 }
1715 workItemsGroup.Start();
1716 workItemsGroup.WaitForIdle();
1436 } 1717 }
1437 1718
1438 private void ValidateNotDisposed() 1719 /// <summary>
1720 /// Executes actions in sequence asynchronously.
1721 /// Returns immediately.
1722 /// </summary>
1723 /// <param name="pipeState"></param>
1724 /// <param name="actions">Actions to execute in the order they should run</param>
1725 public void Pipe<T>(T pipeState, params Action<T>[] actions)
1439 { 1726 {
1440 if(_isDisposed) 1727 Pipe(pipeState, (IEnumerable<Action<T>>)actions);
1441 {
1442 throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
1443 }
1444 } 1728 }
1445 #endregion 1729 #endregion
1446 } 1730 }
1447 #endregion 1731 #endregion
1448} 1732}
diff --git a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs
new file mode 100644
index 0000000..0cce19f
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs
@@ -0,0 +1,89 @@
1using System.Collections.Generic;
2
3namespace Amib.Threading.Internal
4{
5 internal class SynchronizedDictionary<TKey, TValue>
6 {
7 private readonly Dictionary<TKey, TValue> _dictionary;
8 private readonly object _lock;
9
10 public SynchronizedDictionary()
11 {
12 _lock = new object();
13 _dictionary = new Dictionary<TKey, TValue>();
14 }
15
16 public int Count
17 {
18 get { return _dictionary.Count; }
19 }
20
21 public bool Contains(TKey key)
22 {
23 lock (_lock)
24 {
25 return _dictionary.ContainsKey(key);
26 }
27 }
28
29 public void Remove(TKey key)
30 {
31 lock (_lock)
32 {
33 _dictionary.Remove(key);
34 }
35 }
36
37 public object SyncRoot
38 {
39 get { return _lock; }
40 }
41
42 public TValue this[TKey key]
43 {
44 get
45 {
46 lock (_lock)
47 {
48 return _dictionary[key];
49 }
50 }
51 set
52 {
53 lock (_lock)
54 {
55 _dictionary[key] = value;
56 }
57 }
58 }
59
60 public Dictionary<TKey, TValue>.KeyCollection Keys
61 {
62 get
63 {
64 lock (_lock)
65 {
66 return _dictionary.Keys;
67 }
68 }
69 }
70
71 public Dictionary<TKey, TValue>.ValueCollection Values
72 {
73 get
74 {
75 lock (_lock)
76 {
77 return _dictionary.Values;
78 }
79 }
80 }
81 public void Clear()
82 {
83 lock (_lock)
84 {
85 _dictionary.Clear();
86 }
87 }
88 }
89}
diff --git a/ThirdParty/SmartThreadPool/WIGStartInfo.cs b/ThirdParty/SmartThreadPool/WIGStartInfo.cs
index 150317f..8af195b 100644
--- a/ThirdParty/SmartThreadPool/WIGStartInfo.cs
+++ b/ThirdParty/SmartThreadPool/WIGStartInfo.cs
@@ -1,99 +1,171 @@
1// Ami Bar 1using System;
2// amibar@gmail.com
3 2
4namespace Amib.Threading 3namespace Amib.Threading
5{ 4{
6 /// <summary> 5 /// <summary>
7 /// Summary description for WIGStartInfo. 6 /// Summary description for WIGStartInfo.
8 /// </summary> 7 /// </summary>
9 public class WIGStartInfo 8 public class WIGStartInfo
10 { 9 {
11 /// <summary>
12 /// Use the caller's security context
13 /// </summary>
14 private bool _useCallerCallContext; 10 private bool _useCallerCallContext;
15
16 /// <summary>
17 /// Use the caller's HTTP context
18 /// </summary>
19 private bool _useCallerHttpContext; 11 private bool _useCallerHttpContext;
20
21 /// <summary>
22 /// Dispose of the state object of a work item
23 /// </summary>
24 private bool _disposeOfStateObjects; 12 private bool _disposeOfStateObjects;
25
26 /// <summary>
27 /// The option to run the post execute
28 /// </summary>
29 private CallToPostExecute _callToPostExecute; 13 private CallToPostExecute _callToPostExecute;
30
31 /// <summary>
32 /// A post execute callback to call when none is provided in
33 /// the QueueWorkItem method.
34 /// </summary>
35 private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; 14 private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
36
37 /// <summary>
38 /// Indicate the WorkItemsGroup to suspend the handling of the work items
39 /// until the Start() method is called.
40 /// </summary>
41 private bool _startSuspended; 15 private bool _startSuspended;
16 private WorkItemPriority _workItemPriority;
17 private bool _fillStateWithArgs;
42 18
43 public WIGStartInfo() 19 protected bool _readOnly;
20
21 public WIGStartInfo()
44 { 22 {
45 _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; 23 _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
46 _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; 24 _workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
47 _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
48 _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
49 _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
50 _startSuspended = SmartThreadPool.DefaultStartSuspended; 25 _startSuspended = SmartThreadPool.DefaultStartSuspended;
26 _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
27 _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
28 _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
29 _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
30 _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
51 } 31 }
52 32
53 public WIGStartInfo(WIGStartInfo wigStartInfo) 33 public WIGStartInfo(WIGStartInfo wigStartInfo)
54 { 34 {
55 _useCallerCallContext = wigStartInfo._useCallerCallContext; 35 _useCallerCallContext = wigStartInfo.UseCallerCallContext;
56 _useCallerHttpContext = wigStartInfo._useCallerHttpContext; 36 _useCallerHttpContext = wigStartInfo.UseCallerHttpContext;
57 _disposeOfStateObjects = wigStartInfo._disposeOfStateObjects; 37 _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
58 _callToPostExecute = wigStartInfo._callToPostExecute; 38 _callToPostExecute = wigStartInfo.CallToPostExecute;
59 _postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback; 39 _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
60 _startSuspended = wigStartInfo._startSuspended; 40 _workItemPriority = wigStartInfo.WorkItemPriority;
41 _startSuspended = wigStartInfo.StartSuspended;
42 _fillStateWithArgs = wigStartInfo.FillStateWithArgs;
61 } 43 }
62 44
63 public bool UseCallerCallContext 45 protected void ThrowIfReadOnly()
64 { 46 {
65 get { return _useCallerCallContext; } 47 if (_readOnly)
66 set { _useCallerCallContext = value; } 48 {
49 throw new NotSupportedException("This is a readonly instance and set is not supported");
50 }
67 } 51 }
68 52
69 public bool UseCallerHttpContext 53 /// <summary>
70 { 54 /// Get/Set if to use the caller's security context
71 get { return _useCallerHttpContext; } 55 /// </summary>
72 set { _useCallerHttpContext = value; } 56 public virtual bool UseCallerCallContext
73 } 57 {
58 get { return _useCallerCallContext; }
59 set
60 {
61 ThrowIfReadOnly();
62 _useCallerCallContext = value;
63 }
64 }
74 65
75 public bool DisposeOfStateObjects
76 {
77 get { return _disposeOfStateObjects; }
78 set { _disposeOfStateObjects = value; }
79 }
80 66
81 public CallToPostExecute CallToPostExecute 67 /// <summary>
82 { 68 /// Get/Set if to use the caller's HTTP context
83 get { return _callToPostExecute; } 69 /// </summary>
84 set { _callToPostExecute = value; } 70 public virtual bool UseCallerHttpContext
85 } 71 {
72 get { return _useCallerHttpContext; }
73 set
74 {
75 ThrowIfReadOnly();
76 _useCallerHttpContext = value;
77 }
78 }
86 79
87 public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
88 {
89 get { return _postExecuteWorkItemCallback; }
90 set { _postExecuteWorkItemCallback = value; }
91 }
92 80
93 public bool StartSuspended 81 /// <summary>
94 { 82 /// Get/Set if to dispose of the state object of a work item
95 get { return _startSuspended; } 83 /// </summary>
96 set { _startSuspended = value; } 84 public virtual bool DisposeOfStateObjects
97 } 85 {
86 get { return _disposeOfStateObjects; }
87 set
88 {
89 ThrowIfReadOnly();
90 _disposeOfStateObjects = value;
91 }
92 }
93
94
95 /// <summary>
96 /// Get/Set the run the post execute options
97 /// </summary>
98 public virtual CallToPostExecute CallToPostExecute
99 {
100 get { return _callToPostExecute; }
101 set
102 {
103 ThrowIfReadOnly();
104 _callToPostExecute = value;
105 }
106 }
107
108
109 /// <summary>
110 /// Get/Set the default post execute callback
111 /// </summary>
112 public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback
113 {
114 get { return _postExecuteWorkItemCallback; }
115 set
116 {
117 ThrowIfReadOnly();
118 _postExecuteWorkItemCallback = value;
119 }
120 }
121
122
123 /// <summary>
124 /// Get/Set if the work items execution should be suspended until the Start()
125 /// method is called.
126 /// </summary>
127 public virtual bool StartSuspended
128 {
129 get { return _startSuspended; }
130 set
131 {
132 ThrowIfReadOnly();
133 _startSuspended = value;
134 }
135 }
136
137
138 /// <summary>
139 /// Get/Set the default priority that a work item gets when it is enqueued
140 /// </summary>
141 public virtual WorkItemPriority WorkItemPriority
142 {
143 get { return _workItemPriority; }
144 set { _workItemPriority = value; }
145 }
146
147 /// <summary>
148 /// Get/Set the if QueueWorkItem of Action&lt;...&gt;/Func&lt;...&gt; fill the
149 /// arguments as an object array into the state of the work item.
150 /// The arguments can be access later by IWorkItemResult.State.
151 /// </summary>
152 public virtual bool FillStateWithArgs
153 {
154 get { return _fillStateWithArgs; }
155 set
156 {
157 ThrowIfReadOnly();
158 _fillStateWithArgs = value;
159 }
160 }
161
162 /// <summary>
163 /// Get a readonly version of this WIGStartInfo
164 /// </summary>
165 /// <returns>Returns a readonly reference to this WIGStartInfoRO</returns>
166 public WIGStartInfo AsReadOnly()
167 {
168 return new WIGStartInfo(this) { _readOnly = true };
169 }
98 } 170 }
99} 171}
diff --git a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs
new file mode 100644
index 0000000..435a14b
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs
@@ -0,0 +1,190 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading;
5
6namespace Amib.Threading.Internal
7{
8 public partial class WorkItem
9 {
10 #region WorkItemResult class
11
12 private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult
13 {
14 /// <summary>
15 /// A back reference to the work item
16 /// </summary>
17 private readonly WorkItem _workItem;
18
19 public WorkItemResult(WorkItem workItem)
20 {
21 _workItem = workItem;
22 }
23
24 internal WorkItem GetWorkItem()
25 {
26 return _workItem;
27 }
28
29 #region IWorkItemResult Members
30
31 public bool IsCompleted
32 {
33 get
34 {
35 return _workItem.IsCompleted;
36 }
37 }
38
39 public bool IsCanceled
40 {
41 get
42 {
43 return _workItem.IsCanceled;
44 }
45 }
46
47 public object GetResult()
48 {
49 return _workItem.GetResult(Timeout.Infinite, true, null);
50 }
51
52 public object GetResult(int millisecondsTimeout, bool exitContext)
53 {
54 return _workItem.GetResult(millisecondsTimeout, exitContext, null);
55 }
56
57 public object GetResult(TimeSpan timeout, bool exitContext)
58 {
59 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
60 }
61
62 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
63 {
64 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
65 }
66
67 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
68 {
69 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
70 }
71
72 public object GetResult(out Exception e)
73 {
74 return _workItem.GetResult(Timeout.Infinite, true, null, out e);
75 }
76
77 public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
78 {
79 return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
80 }
81
82 public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
83 {
84 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
85 }
86
87 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
88 {
89 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
90 }
91
92 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
93 {
94 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
95 }
96
97 public bool Cancel()
98 {
99 return Cancel(false);
100 }
101
102 public bool Cancel(bool abortExecution)
103 {
104 return _workItem.Cancel(abortExecution);
105 }
106
107 public object State
108 {
109 get
110 {
111 return _workItem._state;
112 }
113 }
114
115 public WorkItemPriority WorkItemPriority
116 {
117 get
118 {
119 return _workItem._workItemInfo.WorkItemPriority;
120 }
121 }
122
123 /// <summary>
124 /// Return the result, same as GetResult()
125 /// </summary>
126 public object Result
127 {
128 get { return GetResult(); }
129 }
130
131 /// <summary>
132 /// Returns the exception if occured otherwise returns null.
133 /// This value is valid only after the work item completed,
134 /// before that it is always null.
135 /// </summary>
136 public object Exception
137 {
138 get { return _workItem._exception; }
139 }
140
141 #endregion
142
143 #region IInternalWorkItemResult Members
144
145 public event WorkItemStateCallback OnWorkItemStarted
146 {
147 add
148 {
149 _workItem.OnWorkItemStarted += value;
150 }
151 remove
152 {
153 _workItem.OnWorkItemStarted -= value;
154 }
155 }
156
157
158 public event WorkItemStateCallback OnWorkItemCompleted
159 {
160 add
161 {
162 _workItem.OnWorkItemCompleted += value;
163 }
164 remove
165 {
166 _workItem.OnWorkItemCompleted -= value;
167 }
168 }
169
170 #endregion
171
172 #region IInternalWorkItemResult Members
173
174 public IWorkItemResult GetWorkItemResult()
175 {
176 return this;
177 }
178
179 public IWorkItemResult<TResult> GetWorkItemResultT<TResult>()
180 {
181 return new WorkItemResultTWrapper<TResult>(this);
182 }
183
184 #endregion
185 }
186
187 #endregion
188
189 }
190}
diff --git a/ThirdParty/SmartThreadPool/WorkItem.cs b/ThirdParty/SmartThreadPool/WorkItem.cs
index d0c0524..185f10c 100644
--- a/ThirdParty/SmartThreadPool/WorkItem.cs
+++ b/ThirdParty/SmartThreadPool/WorkItem.cs
@@ -1,58 +1,13 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
5using System.Threading; 2using System.Threading;
6using System.Diagnostics; 3using System.Diagnostics;
7 4
8namespace Amib.Threading.Internal 5namespace Amib.Threading.Internal
9{ 6{
10 #region WorkItem Delegate
11
12 /// <summary>
13 /// An internal delegate to call when the WorkItem starts or completes
14 /// </summary>
15 internal delegate void WorkItemStateCallback(WorkItem workItem);
16
17 #endregion
18
19 #region IInternalWorkItemResult interface
20
21 public class CanceledWorkItemsGroup
22 {
23 public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
24
25 private bool _isCanceled = false;
26 public bool IsCanceled
27 {
28 get { return _isCanceled; }
29 set { _isCanceled = value; }
30 }
31 }
32
33 internal interface IInternalWorkItemResult
34 {
35 event WorkItemStateCallback OnWorkItemStarted;
36 event WorkItemStateCallback OnWorkItemCompleted;
37 }
38
39 #endregion
40
41 #region IWorkItem interface
42
43 public interface IWorkItem
44 {
45
46 }
47
48 #endregion
49
50 #region WorkItem class
51
52 /// <summary> 7 /// <summary>
53 /// Holds a callback delegate and the state for that delegate. 8 /// Holds a callback delegate and the state for that delegate.
54 /// </summary> 9 /// </summary>
55 public class WorkItem : IHasWorkItemPriority, IWorkItem 10 public partial class WorkItem : IHasWorkItemPriority
56 { 11 {
57 #region WorkItemState enum 12 #region WorkItemState enum
58 13
@@ -61,33 +16,57 @@ namespace Amib.Threading.Internal
61 /// </summary> 16 /// </summary>
62 private enum WorkItemState 17 private enum WorkItemState
63 { 18 {
64 InQueue, 19 InQueue = 0, // Nexts: InProgress, Canceled
65 InProgress, 20 InProgress = 1, // Nexts: Completed, Canceled
66 Completed, 21 Completed = 2, // Stays Completed
67 Canceled, 22 Canceled = 3, // Stays Canceled
68 } 23 }
69 24
70 #endregion 25 private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState)
26 {
27 bool valid = false;
28
29 switch (currentState)
30 {
31 case WorkItemState.InQueue:
32 valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState);
33 break;
34 case WorkItemState.InProgress:
35 valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState);
36 break;
37 case WorkItemState.Completed:
38 case WorkItemState.Canceled:
39 // Cannot be changed
40 break;
41 default:
42 // Unknown state
43 Debug.Assert(false);
44 break;
45 }
71 46
72 #region Member Variables 47 return valid;
48 }
73 49
74 public Thread currentThread; 50 #endregion
51
52 #region Fields
75 53
76 /// <summary> 54 /// <summary>
77 /// Callback delegate for the callback. 55 /// Callback delegate for the callback.
78 /// </summary> 56 /// </summary>
79 private WorkItemCallback _callback; 57 private readonly WorkItemCallback _callback;
80 58
81 /// <summary> 59 /// <summary>
82 /// State with which to call the callback delegate. 60 /// State with which to call the callback delegate.
83 /// </summary> 61 /// </summary>
84 private object _state; 62 private object _state;
85 63
64#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
86 /// <summary> 65 /// <summary>
87 /// Stores the caller's context 66 /// Stores the caller's context
88 /// </summary> 67 /// </summary>
89 private CallerThreadContext _callerContext; 68 private readonly CallerThreadContext _callerContext;
90 69#endif
91 /// <summary> 70 /// <summary>
92 /// Holds the result of the mehtod 71 /// Holds the result of the mehtod
93 /// </summary> 72 /// </summary>
@@ -117,12 +96,12 @@ namespace Amib.Threading.Internal
117 /// <summary> 96 /// <summary>
118 /// Represents the result state of the work item 97 /// Represents the result state of the work item
119 /// </summary> 98 /// </summary>
120 private WorkItemResult _workItemResult; 99 private readonly WorkItemResult _workItemResult;
121 100
122 /// <summary> 101 /// <summary>
123 /// Work item info 102 /// Work item info
124 /// </summary> 103 /// </summary>
125 private WorkItemInfo _workItemInfo; 104 private readonly WorkItemInfo _workItemInfo;
126 105
127 /// <summary> 106 /// <summary>
128 /// Called when the WorkItem starts 107 /// Called when the WorkItem starts
@@ -141,30 +120,41 @@ namespace Amib.Threading.Internal
141 private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; 120 private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
142 121
143 /// <summary> 122 /// <summary>
123 /// A reference to an object that indicates whatever the
124 /// SmartThreadPool has been canceled
125 /// </summary>
126 private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
127
128 /// <summary>
144 /// The work item group this work item belong to. 129 /// The work item group this work item belong to.
145 ///
146 /// </summary> 130 /// </summary>
147 private IWorkItemsGroup _workItemsGroup; 131 private readonly IWorkItemsGroup _workItemsGroup;
148 132
149 #region Performance Counter fields 133 /// <summary>
134 /// The thread that executes this workitem.
135 /// This field is available for the period when the work item is executed, before and after it is null.
136 /// </summary>
137 private Thread _executingThread;
150 138
151 /// <summary> 139 /// <summary>
152 /// The time when the work items is queued. 140 /// The absulote time when the work item will be timeout
153 /// Used with the performance counter.
154 /// </summary> 141 /// </summary>
155 private DateTime _queuedTime; 142 private long _expirationTime;
143
144 #region Performance Counter fields
145
146
147
156 148
157 /// <summary> 149 /// <summary>
158 /// The time when the work items starts its execution. 150 /// Stores how long the work item waited on the stp queue
159 /// Used with the performance counter.
160 /// </summary> 151 /// </summary>
161 private DateTime _beginProcessTime; 152 private Stopwatch _waitingOnQueueStopwatch;
162 153
163 /// <summary> 154 /// <summary>
164 /// The time when the work items ends its execution. 155 /// Stores how much time it took the work item to execute after it went out of the queue
165 /// Used with the performance counter.
166 /// </summary> 156 /// </summary>
167 private DateTime _endProcessTime; 157 private Stopwatch _processingStopwatch;
168 158
169 #endregion 159 #endregion
170 160
@@ -174,17 +164,25 @@ namespace Amib.Threading.Internal
174 164
175 public TimeSpan WaitingTime 165 public TimeSpan WaitingTime
176 { 166 {
177 get 167 get
178 { 168 {
179 return (_beginProcessTime - _queuedTime); 169 return _waitingOnQueueStopwatch.Elapsed;
180 } 170 }
181 } 171 }
182 172
183 public TimeSpan ProcessTime 173 public TimeSpan ProcessTime
184 { 174 {
185 get 175 get
176 {
177 return _processingStopwatch.Elapsed;
178 }
179 }
180
181 internal WorkItemInfo WorkItemInfo
182 {
183 get
186 { 184 {
187 return (_endProcessTime - _beginProcessTime); 185 return _workItemInfo;
188 } 186 }
189 } 187 }
190 188
@@ -195,6 +193,8 @@ namespace Amib.Threading.Internal
195 /// <summary> 193 /// <summary>
196 /// Initialize the callback holding object. 194 /// Initialize the callback holding object.
197 /// </summary> 195 /// </summary>
196 /// <param name="workItemsGroup">The workItemGroup of the workitem</param>
197 /// <param name="workItemInfo">The WorkItemInfo of te workitem</param>
198 /// <param name="callback">Callback delegate for the callback.</param> 198 /// <param name="callback">Callback delegate for the callback.</param>
199 /// <param name="state">State with which to call the callback delegate.</param> 199 /// <param name="state">State with which to call the callback delegate.</param>
200 /// 200 ///
@@ -203,16 +203,18 @@ namespace Amib.Threading.Internal
203 public WorkItem( 203 public WorkItem(
204 IWorkItemsGroup workItemsGroup, 204 IWorkItemsGroup workItemsGroup,
205 WorkItemInfo workItemInfo, 205 WorkItemInfo workItemInfo,
206 WorkItemCallback callback, 206 WorkItemCallback callback,
207 object state) 207 object state)
208 { 208 {
209 _workItemsGroup = workItemsGroup; 209 _workItemsGroup = workItemsGroup;
210 _workItemInfo = workItemInfo; 210 _workItemInfo = workItemInfo;
211 211
212#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
212 if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext) 213 if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
213 { 214 {
214 _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext); 215 _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
215 } 216 }
217#endif
216 218
217 _callback = callback; 219 _callback = callback;
218 _state = state; 220 _state = state;
@@ -222,9 +224,18 @@ namespace Amib.Threading.Internal
222 224
223 internal void Initialize() 225 internal void Initialize()
224 { 226 {
227 // The _workItemState is changed directly instead of using the SetWorkItemState
228 // method since we don't want to go throught IsValidStateTransition.
225 _workItemState = WorkItemState.InQueue; 229 _workItemState = WorkItemState.InQueue;
230
226 _workItemCompleted = null; 231 _workItemCompleted = null;
227 _workItemCompletedRefCount = 0; 232 _workItemCompletedRefCount = 0;
233 _waitingOnQueueStopwatch = new Stopwatch();
234 _processingStopwatch = new Stopwatch();
235 _expirationTime =
236 _workItemInfo.Timeout > 0 ?
237 DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond :
238 long.MaxValue;
228 } 239 }
229 240
230 internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup) 241 internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
@@ -237,17 +248,16 @@ namespace Amib.Threading.Internal
237 248
238 #region Methods 249 #region Methods
239 250
240 public CanceledWorkItemsGroup CanceledWorkItemsGroup 251 internal CanceledWorkItemsGroup CanceledWorkItemsGroup
241 { 252 {
242 get 253 get { return _canceledWorkItemsGroup; }
243 { 254 set { _canceledWorkItemsGroup = value; }
244 return _canceledWorkItemsGroup; 255 }
245 }
246 256
247 set 257 internal CanceledWorkItemsGroup CanceledSmartThreadPool
248 { 258 {
249 _canceledWorkItemsGroup = value; 259 get { return _canceledSmartThreadPool; }
250 } 260 set { _canceledSmartThreadPool = value; }
251 } 261 }
252 262
253 /// <summary> 263 /// <summary>
@@ -259,9 +269,10 @@ namespace Amib.Threading.Internal
259 /// </returns> 269 /// </returns>
260 public bool StartingWorkItem() 270 public bool StartingWorkItem()
261 { 271 {
262 _beginProcessTime = DateTime.Now; 272 _waitingOnQueueStopwatch.Stop();
273 _processingStopwatch.Start();
263 274
264 lock(this) 275 lock (this)
265 { 276 {
266 if (IsCanceled) 277 if (IsCanceled)
267 { 278 {
@@ -277,6 +288,9 @@ namespace Amib.Threading.Internal
277 288
278 Debug.Assert(WorkItemState.InQueue == GetWorkItemState()); 289 Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
279 290
291 // No need for a lock yet, only after the state has changed to InProgress
292 _executingThread = Thread.CurrentThread;
293
280 SetWorkItemState(WorkItemState.InProgress); 294 SetWorkItemState(WorkItemState.InProgress);
281 } 295 }
282 296
@@ -291,7 +305,7 @@ namespace Amib.Threading.Internal
291 CallToPostExecute currentCallToPostExecute = 0; 305 CallToPostExecute currentCallToPostExecute = 0;
292 306
293 // Execute the work item if we are in the correct state 307 // Execute the work item if we are in the correct state
294 switch(GetWorkItemState()) 308 switch (GetWorkItemState())
295 { 309 {
296 case WorkItemState.InProgress: 310 case WorkItemState.InProgress:
297 currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled; 311 currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled;
@@ -311,7 +325,7 @@ namespace Amib.Threading.Internal
311 PostExecute(); 325 PostExecute();
312 } 326 }
313 327
314 _endProcessTime = DateTime.Now; 328 _processingStopwatch.Stop();
315 } 329 }
316 330
317 internal void FireWorkItemCompleted() 331 internal void FireWorkItemCompleted()
@@ -323,8 +337,21 @@ namespace Amib.Threading.Internal
323 _workItemCompletedEvent(this); 337 _workItemCompletedEvent(this);
324 } 338 }
325 } 339 }
326 catch // Ignore exceptions 340 catch // Suppress exceptions
327 {} 341 { }
342 }
343
344 internal void FireWorkItemStarted()
345 {
346 try
347 {
348 if (null != _workItemStartedEvent)
349 {
350 _workItemStartedEvent(this);
351 }
352 }
353 catch // Suppress exceptions
354 { }
328 } 355 }
329 356
330 /// <summary> 357 /// <summary>
@@ -332,32 +359,70 @@ namespace Amib.Threading.Internal
332 /// </summary> 359 /// </summary>
333 private void ExecuteWorkItem() 360 private void ExecuteWorkItem()
334 { 361 {
362
363#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
335 CallerThreadContext ctc = null; 364 CallerThreadContext ctc = null;
336 if (null != _callerContext) 365 if (null != _callerContext)
337 { 366 {
338 ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext); 367 ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
339 CallerThreadContext.Apply(_callerContext); 368 CallerThreadContext.Apply(_callerContext);
340 } 369 }
370#endif
341 371
342 Exception exception = null; 372 Exception exception = null;
343 object result = null; 373 object result = null;
344 374
345 try 375 try
346 { 376 {
347 result = _callback(_state); 377 try
378 {
379 result = _callback(_state);
380 }
381 catch (Exception e)
382 {
383 // Save the exception so we can rethrow it later
384 exception = e;
385 }
386
387 // Remove the value of the execution thread, so it will be impossible to cancel the work item,
388 // since it is already completed.
389 // Cancelling a work item that already completed may cause the abortion of the next work item!!!
390 Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
391
392 if (null == executionThread)
393 {
394 // Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException
395 Thread.Sleep(60 * 1000);
396
397 // If after 1 minute this thread was not aborted then let it continue working.
398 }
348 } 399 }
349 catch (Exception e) 400 // We must treat the ThreadAbortException or else it will be stored in the exception variable
401 catch (ThreadAbortException tae)
350 { 402 {
351 // Save the exception so we can rethrow it later 403 tae.GetHashCode();
352 exception = e; 404 // Check if the work item was cancelled
405 // If we got a ThreadAbortException and the STP is not shutting down, it means the
406 // work items was cancelled.
407 if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown)
408 {
409#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
410 Thread.ResetAbort();
411#endif
412 }
353 } 413 }
354 414
415#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
355 if (null != _callerContext) 416 if (null != _callerContext)
356 { 417 {
357 CallerThreadContext.Apply(ctc); 418 CallerThreadContext.Apply(ctc);
358 } 419 }
420#endif
359 421
360 SetResult(result, exception); 422 if (!SmartThreadPool.IsWorkItemCanceled)
423 {
424 SetResult(result, exception);
425 }
361 } 426 }
362 427
363 /// <summary> 428 /// <summary>
@@ -369,9 +434,9 @@ namespace Amib.Threading.Internal
369 { 434 {
370 try 435 try
371 { 436 {
372 _workItemInfo.PostExecuteWorkItemCallback(this._workItemResult); 437 _workItemInfo.PostExecuteWorkItemCallback(_workItemResult);
373 } 438 }
374 catch (Exception e) 439 catch (Exception e)
375 { 440 {
376 Debug.Assert(null != e); 441 Debug.Assert(null != e);
377 } 442 }
@@ -382,6 +447,8 @@ namespace Amib.Threading.Internal
382 /// Set the result of the work item to return 447 /// Set the result of the work item to return
383 /// </summary> 448 /// </summary>
384 /// <param name="result">The result of the work item</param> 449 /// <param name="result">The result of the work item</param>
450 /// <param name="exception">The exception that was throw while the workitem executed, null
451 /// if there was no exception.</param>
385 internal void SetResult(object result, Exception exception) 452 internal void SetResult(object result, Exception exception)
386 { 453 {
387 _result = result; 454 _result = result;
@@ -401,48 +468,48 @@ namespace Amib.Threading.Internal
401 /// <summary> 468 /// <summary>
402 /// Wait for all work items to complete 469 /// Wait for all work items to complete
403 /// </summary> 470 /// </summary>
404 /// <param name="workItemResults">Array of work item result objects</param> 471 /// <param name="waitableResults">Array of work item result objects</param>
405 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 472 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
406 /// <param name="exitContext"> 473 /// <param name="exitContext">
407 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 474 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
408 /// </param> 475 /// </param>
409 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 476 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
410 /// <returns> 477 /// <returns>
411 /// true when every work item in workItemResults has completed; otherwise false. 478 /// true when every work item in waitableResults has completed; otherwise false.
412 /// </returns> 479 /// </returns>
413 internal static bool WaitAll( 480 internal static bool WaitAll(
414 IWorkItemResult [] workItemResults, 481 IWaitableResult[] waitableResults,
415 int millisecondsTimeout, 482 int millisecondsTimeout,
416 bool exitContext, 483 bool exitContext,
417 WaitHandle cancelWaitHandle) 484 WaitHandle cancelWaitHandle)
418 { 485 {
419 if (0 == workItemResults.Length) 486 if (0 == waitableResults.Length)
420 { 487 {
421 return true; 488 return true;
422 } 489 }
423 490
424 bool success; 491 bool success;
425 WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];; 492 WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
426 GetWaitHandles(workItemResults, waitHandles); 493 GetWaitHandles(waitableResults, waitHandles);
427 494
428 if ((null == cancelWaitHandle) && (waitHandles.Length <= 64)) 495 if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
429 { 496 {
430 success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); 497 success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
431 } 498 }
432 else 499 else
433 { 500 {
434 success = true; 501 success = true;
435 int millisecondsLeft = millisecondsTimeout; 502 int millisecondsLeft = millisecondsTimeout;
436 DateTime start = DateTime.Now; 503 Stopwatch stopwatch = Stopwatch.StartNew();
437 504
438 WaitHandle [] whs; 505 WaitHandle[] whs;
439 if (null != cancelWaitHandle) 506 if (null != cancelWaitHandle)
440 { 507 {
441 whs = new WaitHandle [] { null, cancelWaitHandle }; 508 whs = new WaitHandle[] { null, cancelWaitHandle };
442 } 509 }
443 else 510 else
444 { 511 {
445 whs = new WaitHandle [] { null }; 512 whs = new WaitHandle[] { null };
446 } 513 }
447 514
448 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); 515 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
@@ -450,7 +517,7 @@ namespace Amib.Threading.Internal
450 // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle 517 // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
451 // won't affect it. 518 // won't affect it.
452 // Each iteration we update the time left for the timeout. 519 // Each iteration we update the time left for the timeout.
453 for(int i = 0; i < workItemResults.Length; ++i) 520 for (int i = 0; i < waitableResults.Length; ++i)
454 { 521 {
455 // WaitAny don't work with negative numbers 522 // WaitAny don't work with negative numbers
456 if (!waitInfinitely && (millisecondsLeft < 0)) 523 if (!waitInfinitely && (millisecondsLeft < 0))
@@ -460,23 +527,22 @@ namespace Amib.Threading.Internal
460 } 527 }
461 528
462 whs[0] = waitHandles[i]; 529 whs[0] = waitHandles[i];
463 int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext); 530 int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
464 if((result > 0) || (WaitHandle.WaitTimeout == result)) 531 if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result))
465 { 532 {
466 success = false; 533 success = false;
467 break; 534 break;
468 } 535 }
469 536
470 if(!waitInfinitely) 537 if (!waitInfinitely)
471 { 538 {
472 // Update the time left to wait 539 // Update the time left to wait
473 TimeSpan ts = DateTime.Now - start; 540 millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
474 millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds;
475 } 541 }
476 } 542 }
477 } 543 }
478 // Release the wait handles 544 // Release the wait handles
479 ReleaseWaitHandles(workItemResults); 545 ReleaseWaitHandles(waitableResults);
480 546
481 return success; 547 return success;
482 } 548 }
@@ -484,7 +550,7 @@ namespace Amib.Threading.Internal
484 /// <summary> 550 /// <summary>
485 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 551 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
486 /// </summary> 552 /// </summary>
487 /// <param name="workItemResults">Array of work item result objects</param> 553 /// <param name="waitableResults">Array of work item result objects</param>
488 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 554 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
489 /// <param name="exitContext"> 555 /// <param name="exitContext">
490 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 556 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
@@ -493,38 +559,38 @@ namespace Amib.Threading.Internal
493 /// <returns> 559 /// <returns>
494 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 560 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
495 /// </returns> 561 /// </returns>
496 internal static int WaitAny( 562 internal static int WaitAny(
497 IWorkItemResult [] workItemResults, 563 IWaitableResult[] waitableResults,
498 int millisecondsTimeout, 564 int millisecondsTimeout,
499 bool exitContext, 565 bool exitContext,
500 WaitHandle cancelWaitHandle) 566 WaitHandle cancelWaitHandle)
501 { 567 {
502 WaitHandle [] waitHandles = null; 568 WaitHandle[] waitHandles;
503 569
504 if (null != cancelWaitHandle) 570 if (null != cancelWaitHandle)
505 { 571 {
506 waitHandles = new WaitHandle[workItemResults.Length+1]; 572 waitHandles = new WaitHandle[waitableResults.Length + 1];
507 GetWaitHandles(workItemResults, waitHandles); 573 GetWaitHandles(waitableResults, waitHandles);
508 waitHandles[workItemResults.Length] = cancelWaitHandle; 574 waitHandles[waitableResults.Length] = cancelWaitHandle;
509 } 575 }
510 else 576 else
511 { 577 {
512 waitHandles = new WaitHandle[workItemResults.Length]; 578 waitHandles = new WaitHandle[waitableResults.Length];
513 GetWaitHandles(workItemResults, waitHandles); 579 GetWaitHandles(waitableResults, waitHandles);
514 } 580 }
515 581
516 int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); 582 int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
517 583
518 // Treat cancel as timeout 584 // Treat cancel as timeout
519 if (null != cancelWaitHandle) 585 if (null != cancelWaitHandle)
520 { 586 {
521 if (result == workItemResults.Length) 587 if (result == waitableResults.Length)
522 { 588 {
523 result = WaitHandle.WaitTimeout; 589 result = STPEventWaitHandle.WaitTimeout;
524 } 590 }
525 } 591 }
526 592
527 ReleaseWaitHandles(workItemResults); 593 ReleaseWaitHandles(waitableResults);
528 594
529 return result; 595 return result;
530 } 596 }
@@ -532,16 +598,16 @@ namespace Amib.Threading.Internal
532 /// <summary> 598 /// <summary>
533 /// Fill an array of wait handles with the work items wait handles. 599 /// Fill an array of wait handles with the work items wait handles.
534 /// </summary> 600 /// </summary>
535 /// <param name="workItemResults">An array of work item results</param> 601 /// <param name="waitableResults">An array of work item results</param>
536 /// <param name="waitHandles">An array of wait handles to fill</param> 602 /// <param name="waitHandles">An array of wait handles to fill</param>
537 private static void GetWaitHandles( 603 private static void GetWaitHandles(
538 IWorkItemResult [] workItemResults, 604 IWaitableResult[] waitableResults,
539 WaitHandle [] waitHandles) 605 WaitHandle[] waitHandles)
540 { 606 {
541 for(int i = 0; i < workItemResults.Length; ++i) 607 for (int i = 0; i < waitableResults.Length; ++i)
542 { 608 {
543 WorkItemResult wir = workItemResults[i] as WorkItemResult; 609 WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult;
544 Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects"); 610 Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects");
545 611
546 waitHandles[i] = wir.GetWorkItem().GetWaitHandle(); 612 waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
547 } 613 }
@@ -550,40 +616,64 @@ namespace Amib.Threading.Internal
550 /// <summary> 616 /// <summary>
551 /// Release the work items' wait handles 617 /// Release the work items' wait handles
552 /// </summary> 618 /// </summary>
553 /// <param name="workItemResults">An array of work item results</param> 619 /// <param name="waitableResults">An array of work item results</param>
554 private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults) 620 private static void ReleaseWaitHandles(IWaitableResult[] waitableResults)
555 { 621 {
556 for(int i = 0; i < workItemResults.Length; ++i) 622 for (int i = 0; i < waitableResults.Length; ++i)
557 { 623 {
558 WorkItemResult wir = workItemResults[i] as WorkItemResult; 624 WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult();
559 625
560 wir.GetWorkItem().ReleaseWaitHandle(); 626 wir.GetWorkItem().ReleaseWaitHandle();
561 } 627 }
562 } 628 }
563 629
564
565 #endregion 630 #endregion
566 631
567 #region Private Members 632 #region Private Members
568 633
569 private WorkItemState GetWorkItemState() 634 private WorkItemState GetWorkItemState()
570 { 635 {
571 if (_canceledWorkItemsGroup.IsCanceled) 636 lock (this)
572 { 637 {
573 return WorkItemState.Canceled; 638 if (WorkItemState.Completed == _workItemState)
574 } 639 {
575 return _workItemState; 640 return _workItemState;
641 }
642
643 long nowTicks = DateTime.UtcNow.Ticks;
576 644
645 if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime)
646 {
647 _workItemState = WorkItemState.Canceled;
648 }
649
650 if (WorkItemState.InProgress == _workItemState)
651 {
652 return _workItemState;
653 }
654
655 if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled)
656 {
657 return WorkItemState.Canceled;
658 }
659
660 return _workItemState;
661 }
577 } 662 }
663
664
578 /// <summary> 665 /// <summary>
579 /// Sets the work item's state 666 /// Sets the work item's state
580 /// </summary> 667 /// </summary>
581 /// <param name="workItemState">The state to set the work item to</param> 668 /// <param name="workItemState">The state to set the work item to</param>
582 private void SetWorkItemState(WorkItemState workItemState) 669 private void SetWorkItemState(WorkItemState workItemState)
583 { 670 {
584 lock(this) 671 lock (this)
585 { 672 {
586 _workItemState = workItemState; 673 if (IsValidStatesTransition(_workItemState, workItemState))
674 {
675 _workItemState = workItemState;
676 }
587 } 677 }
588 } 678 }
589 679
@@ -594,7 +684,7 @@ namespace Amib.Threading.Internal
594 private void SignalComplete(bool canceled) 684 private void SignalComplete(bool canceled)
595 { 685 {
596 SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed); 686 SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed);
597 lock(this) 687 lock (this)
598 { 688 {
599 // If someone is waiting then signal. 689 // If someone is waiting then signal.
600 if (null != _workItemCompleted) 690 if (null != _workItemCompleted)
@@ -606,40 +696,93 @@ namespace Amib.Threading.Internal
606 696
607 internal void WorkItemIsQueued() 697 internal void WorkItemIsQueued()
608 { 698 {
609 _queuedTime = DateTime.Now; 699 _waitingOnQueueStopwatch.Start();
610 } 700 }
611 701
612 #endregion 702 #endregion
613 703
614 #region Members exposed by WorkItemResult 704 #region Members exposed by WorkItemResult
615 705
616 /// <summary> 706 /// <summary>
617 /// Cancel the work item if it didn't start running yet. 707 /// Cancel the work item if it didn't start running yet.
618 /// </summary> 708 /// </summary>
619 /// <returns>Returns true on success or false if the work item is in progress or already completed</returns> 709 /// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
620 private bool Cancel() 710 private bool Cancel(bool abortExecution)
621 { 711 {
622 lock(this) 712#if (_WINDOWS_CE)
713 if(abortExecution)
714 {
715 throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
716 }
717#endif
718 bool success = false;
719 bool signalComplete = false;
720
721 lock (this)
623 { 722 {
624 switch(GetWorkItemState()) 723 switch (GetWorkItemState())
625 { 724 {
626 case WorkItemState.Canceled: 725 case WorkItemState.Canceled:
627 //Debug.WriteLine("Work item already canceled"); 726 //Debug.WriteLine("Work item already canceled");
628 return true; 727 if (abortExecution)
728 {
729 Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
730 if (null != executionThread)
731 {
732 executionThread.Abort(); // "Cancel"
733 // No need to signalComplete, because we already cancelled this work item
734 // so it already signaled its completion.
735 //signalComplete = true;
736 }
737 }
738 success = true;
739 break;
629 case WorkItemState.Completed: 740 case WorkItemState.Completed:
630 case WorkItemState.InProgress:
631 //Debug.WriteLine("Work item cannot be canceled"); 741 //Debug.WriteLine("Work item cannot be canceled");
632 return false; 742 break;
743 case WorkItemState.InProgress:
744 if (abortExecution)
745 {
746 Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
747 if (null != executionThread)
748 {
749 executionThread.Abort(); // "Cancel"
750 success = true;
751 signalComplete = true;
752 }
753 }
754 else
755 {
756 // **************************
757 // Stock SmartThreadPool 2.2.3 sets these to true and relies on the thread to check the
758 // WorkItem cancellation status. However, OpenSimulator uses a different mechanism to notify
759 // scripts of co-operative termination and the abort code also relies on this method
760 // returning false in order to implement a small wait.
761 //
762 // Therefore, as was the case previously with STP, we will not signal successful cancellation
763 // here. It's possible that OpenSimulator code could be changed in the future to remove
764 // the need for this change.
765 // **************************
766 success = false;
767 signalComplete = false;
768 }
769 break;
633 case WorkItemState.InQueue: 770 case WorkItemState.InQueue:
634 // Signal to the wait for completion that the work 771 // Signal to the wait for completion that the work
635 // item has been completed (canceled). There is no 772 // item has been completed (canceled). There is no
636 // reason to wait for it to get out of the queue 773 // reason to wait for it to get out of the queue
637 SignalComplete(true); 774 signalComplete = true;
638 //Debug.WriteLine("Work item canceled"); 775 //Debug.WriteLine("Work item canceled");
639 return true; 776 success = true;
777 break;
778 }
779
780 if (signalComplete)
781 {
782 SignalComplete(true);
640 } 783 }
641 } 784 }
642 return false; 785 return success;
643 } 786 }
644 787
645 /// <summary> 788 /// <summary>
@@ -653,7 +796,7 @@ namespace Amib.Threading.Internal
653 bool exitContext, 796 bool exitContext,
654 WaitHandle cancelWaitHandle) 797 WaitHandle cancelWaitHandle)
655 { 798 {
656 Exception e = null; 799 Exception e;
657 object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); 800 object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
658 if (null != e) 801 if (null != e)
659 { 802 {
@@ -694,7 +837,7 @@ namespace Amib.Threading.Internal
694 { 837 {
695 WaitHandle wh = GetWaitHandle(); 838 WaitHandle wh = GetWaitHandle();
696 839
697 bool timeout = !wh.WaitOne(millisecondsTimeout, exitContext); 840 bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext);
698 841
699 ReleaseWaitHandle(); 842 ReleaseWaitHandle();
700 843
@@ -706,10 +849,10 @@ namespace Amib.Threading.Internal
706 else 849 else
707 { 850 {
708 WaitHandle wh = GetWaitHandle(); 851 WaitHandle wh = GetWaitHandle();
709 int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle }); 852 int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
710 ReleaseWaitHandle(); 853 ReleaseWaitHandle();
711 854
712 switch(result) 855 switch (result)
713 { 856 {
714 case 0: 857 case 0:
715 // The work item signaled 858 // The work item signaled
@@ -717,7 +860,7 @@ namespace Amib.Threading.Internal
717 // work item (not the get result) 860 // work item (not the get result)
718 break; 861 break;
719 case 1: 862 case 1:
720 case WaitHandle.WaitTimeout: 863 case STPEventWaitHandle.WaitTimeout:
721 throw new WorkItemTimeoutException("Work item timeout"); 864 throw new WorkItemTimeoutException("Work item timeout");
722 default: 865 default:
723 Debug.Assert(false); 866 Debug.Assert(false);
@@ -745,11 +888,11 @@ namespace Amib.Threading.Internal
745 /// </summary> 888 /// </summary>
746 private WaitHandle GetWaitHandle() 889 private WaitHandle GetWaitHandle()
747 { 890 {
748 lock(this) 891 lock (this)
749 { 892 {
750 if (null == _workItemCompleted) 893 if (null == _workItemCompleted)
751 { 894 {
752 _workItemCompleted = new ManualResetEvent(IsCompleted); 895 _workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
753 } 896 }
754 ++_workItemCompletedRefCount; 897 ++_workItemCompletedRefCount;
755 } 898 }
@@ -758,7 +901,7 @@ namespace Amib.Threading.Internal
758 901
759 private void ReleaseWaitHandle() 902 private void ReleaseWaitHandle()
760 { 903 {
761 lock(this) 904 lock (this)
762 { 905 {
763 if (null != _workItemCompleted) 906 if (null != _workItemCompleted)
764 { 907 {
@@ -779,10 +922,10 @@ namespace Amib.Threading.Internal
779 { 922 {
780 get 923 get
781 { 924 {
782 lock(this) 925 lock (this)
783 { 926 {
784 WorkItemState workItemState = GetWorkItemState(); 927 WorkItemState workItemState = GetWorkItemState();
785 return ((workItemState == WorkItemState.Completed) || 928 return ((workItemState == WorkItemState.Completed) ||
786 (workItemState == WorkItemState.Canceled)); 929 (workItemState == WorkItemState.Canceled));
787 } 930 }
788 } 931 }
@@ -795,7 +938,7 @@ namespace Amib.Threading.Internal
795 { 938 {
796 get 939 get
797 { 940 {
798 lock(this) 941 lock (this)
799 { 942 {
800 return (GetWorkItemState() == WorkItemState.Canceled); 943 return (GetWorkItemState() == WorkItemState.Canceled);
801 } 944 }
@@ -843,172 +986,6 @@ namespace Amib.Threading.Internal
843 } 986 }
844 } 987 }
845 988
846
847 #region WorkItemResult class
848
849 private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult
850 {
851 /// <summary>
852 /// A back reference to the work item
853 /// </summary>
854 private WorkItem _workItem;
855
856 public WorkItemResult(WorkItem workItem)
857 {
858 _workItem = workItem;
859 }
860
861 internal WorkItem GetWorkItem()
862 {
863 return _workItem;
864 }
865
866 #region IWorkItemResult Members
867
868 public bool IsCompleted
869 {
870 get
871 {
872 return _workItem.IsCompleted;
873 }
874 }
875
876 public void Abort()
877 {
878 _workItem.Abort();
879 }
880
881 public bool IsCanceled
882 {
883 get
884 {
885 return _workItem.IsCanceled;
886 }
887 }
888
889 public object GetResult()
890 {
891 return _workItem.GetResult(Timeout.Infinite, true, null);
892 }
893
894 public object GetResult(int millisecondsTimeout, bool exitContext)
895 {
896 return _workItem.GetResult(millisecondsTimeout, exitContext, null);
897 }
898
899 public object GetResult(TimeSpan timeout, bool exitContext)
900 {
901 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
902 }
903
904 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
905 {
906 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
907 }
908
909 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
910 {
911 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
912 }
913
914 public object GetResult(out Exception e)
915 {
916 return _workItem.GetResult(Timeout.Infinite, true, null, out e);
917 }
918
919 public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
920 {
921 return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
922 }
923
924 public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
925 {
926 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
927 }
928
929 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
930 {
931 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
932 }
933
934 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
935 {
936 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
937 }
938
939 public bool Cancel()
940 {
941 return _workItem.Cancel();
942 }
943
944 public object State
945 {
946 get
947 {
948 return _workItem._state;
949 }
950 }
951
952 public WorkItemPriority WorkItemPriority
953 {
954 get
955 {
956 return _workItem._workItemInfo.WorkItemPriority;
957 }
958 }
959
960 /// <summary>
961 /// Return the result, same as GetResult()
962 /// </summary>
963 public object Result
964 {
965 get { return GetResult(); }
966 }
967
968 /// <summary>
969 /// Returns the exception if occured otherwise returns null.
970 /// This value is valid only after the work item completed,
971 /// before that it is always null.
972 /// </summary>
973 public object Exception
974 {
975 get { return _workItem._exception; }
976 }
977
978 #endregion
979
980 #region IInternalWorkItemResult Members
981
982 public event WorkItemStateCallback OnWorkItemStarted
983 {
984 add
985 {
986 _workItem.OnWorkItemStarted += value;
987 }
988 remove
989 {
990 _workItem.OnWorkItemStarted -= value;
991 }
992 }
993
994
995 public event WorkItemStateCallback OnWorkItemCompleted
996 {
997 add
998 {
999 _workItem.OnWorkItemCompleted += value;
1000 }
1001 remove
1002 {
1003 _workItem.OnWorkItemCompleted -= value;
1004 }
1005 }
1006
1007 #endregion
1008 }
1009
1010 #endregion
1011
1012 public void DisposeOfState() 989 public void DisposeOfState()
1013 { 990 {
1014 if (_workItemInfo.DisposeOfStateObjects) 991 if (_workItemInfo.DisposeOfStateObjects)
@@ -1021,15 +998,5 @@ namespace Amib.Threading.Internal
1021 } 998 }
1022 } 999 }
1023 } 1000 }
1024
1025 public void Abort()
1026 {
1027 lock (this)
1028 {
1029 if(currentThread != null)
1030 currentThread.Abort();
1031 }
1032 }
1033 } 1001 }
1034 #endregion
1035} 1002}
diff --git a/ThirdParty/SmartThreadPool/WorkItemFactory.cs b/ThirdParty/SmartThreadPool/WorkItemFactory.cs
index dfcb54f..16ccd81 100644
--- a/ThirdParty/SmartThreadPool/WorkItemFactory.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemFactory.cs
@@ -1,148 +1,152 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
5 2
6namespace Amib.Threading.Internal 3namespace Amib.Threading.Internal
7{ 4{
8 #region WorkItemFactory class 5 #region WorkItemFactory class
9 6
10 public class WorkItemFactory 7 public class WorkItemFactory
11 { 8 {
12 /// <summary> 9 /// <summary>
13 /// Create a new work item 10 /// Create a new work item
14 /// </summary> 11 /// </summary>
12 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
13 /// <param name="wigStartInfo">Work item group start information</param>
14 /// <param name="callback">A callback to execute</param>
15 /// <returns>Returns a work item</returns>
16 public static WorkItem CreateWorkItem(
17 IWorkItemsGroup workItemsGroup,
18 WIGStartInfo wigStartInfo,
19 WorkItemCallback callback)
20 {
21 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
22 }
23
24 /// <summary>
25 /// Create a new work item
26 /// </summary>
27 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
15 /// <param name="wigStartInfo">Work item group start information</param> 28 /// <param name="wigStartInfo">Work item group start information</param>
16 /// <param name="callback">A callback to execute</param> 29 /// <param name="callback">A callback to execute</param>
17 /// <returns>Returns a work item</returns> 30 /// <param name="workItemPriority">The priority of the work item</param>
18 public static WorkItem CreateWorkItem( 31 /// <returns>Returns a work item</returns>
19 IWorkItemsGroup workItemsGroup, 32 public static WorkItem CreateWorkItem(
20 WIGStartInfo wigStartInfo, 33 IWorkItemsGroup workItemsGroup,
21 WorkItemCallback callback) 34 WIGStartInfo wigStartInfo,
22 { 35 WorkItemCallback callback,
23 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); 36 WorkItemPriority workItemPriority)
24 } 37 {
25 38 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
26 /// <summary> 39 }
27 /// Create a new work item 40
28 /// </summary> 41 /// <summary>
29 /// <param name="wigStartInfo">Work item group start information</param> 42 /// Create a new work item
30 /// <param name="callback">A callback to execute</param> 43 /// </summary>
31 /// <param name="workItemPriority">The priority of the work item</param> 44 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
32 /// <returns>Returns a work item</returns>
33 public static WorkItem CreateWorkItem(
34 IWorkItemsGroup workItemsGroup,
35 WIGStartInfo wigStartInfo,
36 WorkItemCallback callback,
37 WorkItemPriority workItemPriority)
38 {
39 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
40 }
41
42 /// <summary>
43 /// Create a new work item
44 /// </summary>
45 /// <param name="wigStartInfo">Work item group start information</param> 45 /// <param name="wigStartInfo">Work item group start information</param>
46 /// <param name="workItemInfo">Work item info</param> 46 /// <param name="workItemInfo">Work item info</param>
47 /// <param name="callback">A callback to execute</param> 47 /// <param name="callback">A callback to execute</param>
48 /// <returns>Returns a work item</returns> 48 /// <returns>Returns a work item</returns>
49 public static WorkItem CreateWorkItem( 49 public static WorkItem CreateWorkItem(
50 IWorkItemsGroup workItemsGroup, 50 IWorkItemsGroup workItemsGroup,
51 WIGStartInfo wigStartInfo, 51 WIGStartInfo wigStartInfo,
52 WorkItemInfo workItemInfo, 52 WorkItemInfo workItemInfo,
53 WorkItemCallback callback) 53 WorkItemCallback callback)
54 { 54 {
55 return CreateWorkItem( 55 return CreateWorkItem(
56 workItemsGroup, 56 workItemsGroup,
57 wigStartInfo, 57 wigStartInfo,
58 workItemInfo, 58 workItemInfo,
59 callback, 59 callback,
60 null); 60 null);
61 } 61 }
62 62
63 /// <summary> 63 /// <summary>
64 /// Create a new work item 64 /// Create a new work item
65 /// </summary> 65 /// </summary>
66 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
66 /// <param name="wigStartInfo">Work item group start information</param> 67 /// <param name="wigStartInfo">Work item group start information</param>
67 /// <param name="callback">A callback to execute</param> 68 /// <param name="callback">A callback to execute</param>
68 /// <param name="state"> 69 /// <param name="state">
69 /// The context object of the work item. Used for passing arguments to the work item. 70 /// The context object of the work item. Used for passing arguments to the work item.
70 /// </param> 71 /// </param>
71 /// <returns>Returns a work item</returns> 72 /// <returns>Returns a work item</returns>
72 public static WorkItem CreateWorkItem( 73 public static WorkItem CreateWorkItem(
73 IWorkItemsGroup workItemsGroup, 74 IWorkItemsGroup workItemsGroup,
74 WIGStartInfo wigStartInfo, 75 WIGStartInfo wigStartInfo,
75 WorkItemCallback callback, 76 WorkItemCallback callback,
76 object state) 77 object state)
77 { 78 {
78 ValidateCallback(callback); 79 ValidateCallback(callback);
79 80
80 WorkItemInfo workItemInfo = new WorkItemInfo(); 81 WorkItemInfo workItemInfo = new WorkItemInfo();
81 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 82 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
82 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 83 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
83 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; 84 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
84 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 85 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
85 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 86 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
86 87 workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
87 WorkItem workItem = new WorkItem( 88
88 workItemsGroup, 89 WorkItem workItem = new WorkItem(
89 workItemInfo, 90 workItemsGroup,
90 callback, 91 workItemInfo,
91 state); 92 callback,
92 return workItem; 93 state);
93 } 94 return workItem;
94 95 }
95 /// <summary> 96
96 /// Create a new work item 97 /// <summary>
97 /// </summary> 98 /// Create a new work item
98 /// <param name="wigStartInfo">Work item group start information</param> 99 /// </summary>
99 /// <param name="callback">A callback to execute</param> 100 /// <param name="workItemsGroup">The work items group</param>
100 /// <param name="state"> 101 /// <param name="wigStartInfo">Work item group start information</param>
101 /// The context object of the work item. Used for passing arguments to the work item. 102 /// <param name="callback">A callback to execute</param>
102 /// </param> 103 /// <param name="state">
103 /// <param name="workItemPriority">The work item priority</param> 104 /// The context object of the work item. Used for passing arguments to the work item.
104 /// <returns>Returns a work item</returns> 105 /// </param>
105 public static WorkItem CreateWorkItem( 106 /// <param name="workItemPriority">The work item priority</param>
106 IWorkItemsGroup workItemsGroup, 107 /// <returns>Returns a work item</returns>
107 WIGStartInfo wigStartInfo, 108 public static WorkItem CreateWorkItem(
108 WorkItemCallback callback, 109 IWorkItemsGroup workItemsGroup,
109 object state, 110 WIGStartInfo wigStartInfo,
110 WorkItemPriority workItemPriority) 111 WorkItemCallback callback,
111 { 112 object state,
112 ValidateCallback(callback); 113 WorkItemPriority workItemPriority)
113 114 {
114 WorkItemInfo workItemInfo = new WorkItemInfo(); 115 ValidateCallback(callback);
115 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 116
116 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 117 WorkItemInfo workItemInfo = new WorkItemInfo();
117 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; 118 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
118 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 119 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
119 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 120 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
120 workItemInfo.WorkItemPriority = workItemPriority; 121 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
121 122 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
122 WorkItem workItem = new WorkItem( 123 workItemInfo.WorkItemPriority = workItemPriority;
123 workItemsGroup, 124
124 workItemInfo, 125 WorkItem workItem = new WorkItem(
125 callback, 126 workItemsGroup,
126 state); 127 workItemInfo,
127 128 callback,
128 return workItem; 129 state);
129 } 130
130 131 return workItem;
131 /// <summary> 132 }
132 /// Create a new work item 133
133 /// </summary> 134 /// <summary>
134 /// <param name="wigStartInfo">Work item group start information</param> 135 /// Create a new work item
135 /// <param name="workItemInfo">Work item information</param> 136 /// </summary>
136 /// <param name="callback">A callback to execute</param> 137 /// <param name="workItemsGroup">The work items group</param>
137 /// <param name="state"> 138 /// <param name="wigStartInfo">Work item group start information</param>
138 /// The context object of the work item. Used for passing arguments to the work item. 139 /// <param name="workItemInfo">Work item information</param>
139 /// </param> 140 /// <param name="callback">A callback to execute</param>
140 /// <returns>Returns a work item</returns> 141 /// <param name="state">
142 /// The context object of the work item. Used for passing arguments to the work item.
143 /// </param>
144 /// <returns>Returns a work item</returns>
141 public static WorkItem CreateWorkItem( 145 public static WorkItem CreateWorkItem(
142 IWorkItemsGroup workItemsGroup, 146 IWorkItemsGroup workItemsGroup,
143 WIGStartInfo wigStartInfo, 147 WIGStartInfo wigStartInfo,
144 WorkItemInfo workItemInfo, 148 WorkItemInfo workItemInfo,
145 WorkItemCallback callback, 149 WorkItemCallback callback,
146 object state) 150 object state)
147 { 151 {
148 ValidateCallback(callback); 152 ValidateCallback(callback);
@@ -151,183 +155,189 @@ namespace Amib.Threading.Internal
151 WorkItem workItem = new WorkItem( 155 WorkItem workItem = new WorkItem(
152 workItemsGroup, 156 workItemsGroup,
153 new WorkItemInfo(workItemInfo), 157 new WorkItemInfo(workItemInfo),
154 callback, 158 callback,
155 state); 159 state);
156 160
157 return workItem; 161 return workItem;
158 } 162 }
159 163
160 /// <summary> 164 /// <summary>
161 /// Create a new work item 165 /// Create a new work item
162 /// </summary> 166 /// </summary>
163 /// <param name="wigStartInfo">Work item group start information</param> 167 /// <param name="workItemsGroup">The work items group</param>
164 /// <param name="callback">A callback to execute</param> 168 /// <param name="wigStartInfo">Work item group start information</param>
165 /// <param name="state"> 169 /// <param name="callback">A callback to execute</param>
166 /// The context object of the work item. Used for passing arguments to the work item. 170 /// <param name="state">
167 /// </param> 171 /// The context object of the work item. Used for passing arguments to the work item.
168 /// <param name="postExecuteWorkItemCallback"> 172 /// </param>
169 /// A delegate to call after the callback completion 173 /// <param name="postExecuteWorkItemCallback">
170 /// </param> 174 /// A delegate to call after the callback completion
171 /// <returns>Returns a work item</returns> 175 /// </param>
172 public static WorkItem CreateWorkItem( 176 /// <returns>Returns a work item</returns>
173 IWorkItemsGroup workItemsGroup, 177 public static WorkItem CreateWorkItem(
174 WIGStartInfo wigStartInfo, 178 IWorkItemsGroup workItemsGroup,
175 WorkItemCallback callback, 179 WIGStartInfo wigStartInfo,
176 object state, 180 WorkItemCallback callback,
177 PostExecuteWorkItemCallback postExecuteWorkItemCallback) 181 object state,
178 { 182 PostExecuteWorkItemCallback postExecuteWorkItemCallback)
179 ValidateCallback(callback); 183 {
180 ValidateCallback(postExecuteWorkItemCallback); 184 ValidateCallback(callback);
181 185 ValidateCallback(postExecuteWorkItemCallback);
182 WorkItemInfo workItemInfo = new WorkItemInfo(); 186
183 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 187 WorkItemInfo workItemInfo = new WorkItemInfo();
184 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 188 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
185 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 189 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
186 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 190 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
187 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 191 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
188 192 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
189 WorkItem workItem = new WorkItem( 193 workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
190 workItemsGroup, 194
191 workItemInfo, 195 WorkItem workItem = new WorkItem(
192 callback, 196 workItemsGroup,
193 state); 197 workItemInfo,
194 198 callback,
195 return workItem; 199 state);
196 } 200
197 201 return workItem;
198 /// <summary> 202 }
199 /// Create a new work item 203
200 /// </summary> 204 /// <summary>
201 /// <param name="wigStartInfo">Work item group start information</param> 205 /// Create a new work item
202 /// <param name="callback">A callback to execute</param> 206 /// </summary>
203 /// <param name="state"> 207 /// <param name="workItemsGroup">The work items group</param>
204 /// The context object of the work item. Used for passing arguments to the work item. 208 /// <param name="wigStartInfo">Work item group start information</param>
205 /// </param> 209 /// <param name="callback">A callback to execute</param>
206 /// <param name="postExecuteWorkItemCallback"> 210 /// <param name="state">
207 /// A delegate to call after the callback completion 211 /// The context object of the work item. Used for passing arguments to the work item.
208 /// </param> 212 /// </param>
209 /// <param name="workItemPriority">The work item priority</param> 213 /// <param name="postExecuteWorkItemCallback">
210 /// <returns>Returns a work item</returns> 214 /// A delegate to call after the callback completion
211 public static WorkItem CreateWorkItem( 215 /// </param>
212 IWorkItemsGroup workItemsGroup, 216 /// <param name="workItemPriority">The work item priority</param>
213 WIGStartInfo wigStartInfo, 217 /// <returns>Returns a work item</returns>
214 WorkItemCallback callback, 218 public static WorkItem CreateWorkItem(
215 object state, 219 IWorkItemsGroup workItemsGroup,
216 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 220 WIGStartInfo wigStartInfo,
217 WorkItemPriority workItemPriority) 221 WorkItemCallback callback,
218 { 222 object state,
219 ValidateCallback(callback); 223 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
220 ValidateCallback(postExecuteWorkItemCallback); 224 WorkItemPriority workItemPriority)
221 225 {
222 WorkItemInfo workItemInfo = new WorkItemInfo(); 226 ValidateCallback(callback);
223 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 227 ValidateCallback(postExecuteWorkItemCallback);
224 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 228
225 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 229 WorkItemInfo workItemInfo = new WorkItemInfo();
226 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 230 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
227 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 231 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
228 workItemInfo.WorkItemPriority = workItemPriority; 232 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
229 233 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
230 WorkItem workItem = new WorkItem( 234 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
231 workItemsGroup, 235 workItemInfo.WorkItemPriority = workItemPriority;
232 workItemInfo, 236
233 callback, 237 WorkItem workItem = new WorkItem(
234 state); 238 workItemsGroup,
235 239 workItemInfo,
236 return workItem; 240 callback,
237 } 241 state);
238 242
239 /// <summary> 243 return workItem;
240 /// Create a new work item 244 }
241 /// </summary> 245
242 /// <param name="wigStartInfo">Work item group start information</param> 246 /// <summary>
243 /// <param name="callback">A callback to execute</param> 247 /// Create a new work item
244 /// <param name="state"> 248 /// </summary>
245 /// The context object of the work item. Used for passing arguments to the work item. 249 /// <param name="workItemsGroup">The work items group</param>
246 /// </param> 250 /// <param name="wigStartInfo">Work item group start information</param>
247 /// <param name="postExecuteWorkItemCallback"> 251 /// <param name="callback">A callback to execute</param>
248 /// A delegate to call after the callback completion 252 /// <param name="state">
249 /// </param> 253 /// The context object of the work item. Used for passing arguments to the work item.
250 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 254 /// </param>
251 /// <returns>Returns a work item</returns> 255 /// <param name="postExecuteWorkItemCallback">
252 public static WorkItem CreateWorkItem( 256 /// A delegate to call after the callback completion
253 IWorkItemsGroup workItemsGroup, 257 /// </param>
254 WIGStartInfo wigStartInfo, 258 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
255 WorkItemCallback callback, 259 /// <returns>Returns a work item</returns>
256 object state, 260 public static WorkItem CreateWorkItem(
257 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 261 IWorkItemsGroup workItemsGroup,
258 CallToPostExecute callToPostExecute) 262 WIGStartInfo wigStartInfo,
259 { 263 WorkItemCallback callback,
260 ValidateCallback(callback); 264 object state,
261 ValidateCallback(postExecuteWorkItemCallback); 265 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
262 266 CallToPostExecute callToPostExecute)
263 WorkItemInfo workItemInfo = new WorkItemInfo(); 267 {
264 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 268 ValidateCallback(callback);
265 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 269 ValidateCallback(postExecuteWorkItemCallback);
266 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 270
267 workItemInfo.CallToPostExecute = callToPostExecute; 271 WorkItemInfo workItemInfo = new WorkItemInfo();
268 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 272 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
269 273 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
270 WorkItem workItem = new WorkItem( 274 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
271 workItemsGroup, 275 workItemInfo.CallToPostExecute = callToPostExecute;
272 workItemInfo, 276 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
273 callback, 277 workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
274 state); 278
275 279 WorkItem workItem = new WorkItem(
276 return workItem; 280 workItemsGroup,
277 } 281 workItemInfo,
278 282 callback,
279 /// <summary> 283 state);
280 /// Create a new work item 284
281 /// </summary> 285 return workItem;
282 /// <param name="wigStartInfo">Work item group start information</param> 286 }
283 /// <param name="callback">A callback to execute</param> 287
284 /// <param name="state"> 288 /// <summary>
285 /// The context object of the work item. Used for passing arguments to the work item. 289 /// Create a new work item
286 /// </param> 290 /// </summary>
287 /// <param name="postExecuteWorkItemCallback"> 291 /// <param name="workItemsGroup">The work items group</param>
288 /// A delegate to call after the callback completion 292 /// <param name="wigStartInfo">Work item group start information</param>
289 /// </param> 293 /// <param name="callback">A callback to execute</param>
290 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 294 /// <param name="state">
291 /// <param name="workItemPriority">The work item priority</param> 295 /// The context object of the work item. Used for passing arguments to the work item.
292 /// <returns>Returns a work item</returns> 296 /// </param>
293 public static WorkItem CreateWorkItem( 297 /// <param name="postExecuteWorkItemCallback">
294 IWorkItemsGroup workItemsGroup, 298 /// A delegate to call after the callback completion
295 WIGStartInfo wigStartInfo, 299 /// </param>
296 WorkItemCallback callback, 300 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
297 object state, 301 /// <param name="workItemPriority">The work item priority</param>
298 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 302 /// <returns>Returns a work item</returns>
299 CallToPostExecute callToPostExecute, 303 public static WorkItem CreateWorkItem(
300 WorkItemPriority workItemPriority) 304 IWorkItemsGroup workItemsGroup,
301 { 305 WIGStartInfo wigStartInfo,
302 306 WorkItemCallback callback,
303 ValidateCallback(callback); 307 object state,
304 ValidateCallback(postExecuteWorkItemCallback); 308 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
305 309 CallToPostExecute callToPostExecute,
306 WorkItemInfo workItemInfo = new WorkItemInfo(); 310 WorkItemPriority workItemPriority)
307 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 311 {
308 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 312
309 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 313 ValidateCallback(callback);
310 workItemInfo.CallToPostExecute = callToPostExecute; 314 ValidateCallback(postExecuteWorkItemCallback);
311 workItemInfo.WorkItemPriority = workItemPriority; 315
312 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 316 WorkItemInfo workItemInfo = new WorkItemInfo();
313 317 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
314 WorkItem workItem = new WorkItem( 318 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
315 workItemsGroup, 319 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
316 workItemInfo, 320 workItemInfo.CallToPostExecute = callToPostExecute;
317 callback, 321 workItemInfo.WorkItemPriority = workItemPriority;
318 state); 322 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
319 323
320 return workItem; 324 WorkItem workItem = new WorkItem(
321 } 325 workItemsGroup,
322 326 workItemInfo,
323 private static void ValidateCallback(Delegate callback) 327 callback,
324 { 328 state);
325 if(callback.GetInvocationList().Length > 1) 329
326 { 330 return workItem;
327 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); 331 }
328 } 332
329 } 333 private static void ValidateCallback(Delegate callback)
330 } 334 {
331 335 if (callback != null && callback.GetInvocationList().Length > 1)
332 #endregion 336 {
337 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
338 }
339 }
340 }
341
342 #endregion
333} 343}
diff --git a/ThirdParty/SmartThreadPool/WorkItemInfo.cs b/ThirdParty/SmartThreadPool/WorkItemInfo.cs
index c259339..0d7fc85 100644
--- a/ThirdParty/SmartThreadPool/WorkItemInfo.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemInfo.cs
@@ -1,102 +1,69 @@
1// Ami Bar
2// amibar@gmail.com
3
4namespace Amib.Threading 1namespace Amib.Threading
5{ 2{
6 #region WorkItemInfo class 3 #region WorkItemInfo class
7
8 /// <summary>
9 /// Summary description for WorkItemInfo.
10 /// </summary>
11 public class WorkItemInfo
12 {
13 /// <summary>
14 /// Use the caller's security context
15 /// </summary>
16 private bool _useCallerCallContext;
17
18 /// <summary>
19 /// Use the caller's security context
20 /// </summary>
21 private bool _useCallerHttpContext;
22
23 /// <summary>
24 /// Dispose of the state object of a work item
25 /// </summary>
26 private bool _disposeOfStateObjects;
27
28 /// <summary>
29 /// The option to run the post execute
30 /// </summary>
31 private CallToPostExecute _callToPostExecute;
32 4
33 /// <summary> 5 /// <summary>
34 /// A post execute callback to call when none is provided in 6 /// Summary description for WorkItemInfo.
35 /// the QueueWorkItem method. 7 /// </summary>
36 /// </summary> 8 public class WorkItemInfo
37 private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; 9 {
38 10 public WorkItemInfo()
39 /// <summary> 11 {
40 /// The priority of the work item 12 UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
41 /// </summary> 13 UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
42 private WorkItemPriority _workItemPriority; 14 DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
15 CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
16 PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
17 WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
18 }
43 19
44 public WorkItemInfo() 20 public WorkItemInfo(WorkItemInfo workItemInfo)
45 { 21 {
46 _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; 22 UseCallerCallContext = workItemInfo.UseCallerCallContext;
47 _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; 23 UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
48 _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; 24 DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
49 _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; 25 CallToPostExecute = workItemInfo.CallToPostExecute;
50 _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; 26 PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
51 _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; 27 WorkItemPriority = workItemInfo.WorkItemPriority;
52 } 28 Timeout = workItemInfo.Timeout;
29 }
53 30
54 public WorkItemInfo(WorkItemInfo workItemInfo) 31 /// <summary>
55 { 32 /// Get/Set if to use the caller's security context
56 _useCallerCallContext = workItemInfo._useCallerCallContext; 33 /// </summary>
57 _useCallerHttpContext = workItemInfo._useCallerHttpContext; 34 public bool UseCallerCallContext { get; set; }
58 _disposeOfStateObjects = workItemInfo._disposeOfStateObjects;
59 _callToPostExecute = workItemInfo._callToPostExecute;
60 _postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback;
61 _workItemPriority = workItemInfo._workItemPriority;
62 }
63 35
64 public bool UseCallerCallContext 36 /// <summary>
65 { 37 /// Get/Set if to use the caller's HTTP context
66 get { return _useCallerCallContext; } 38 /// </summary>
67 set { _useCallerCallContext = value; } 39 public bool UseCallerHttpContext { get; set; }
68 }
69 40
70 public bool UseCallerHttpContext 41 /// <summary>
71 { 42 /// Get/Set if to dispose of the state object of a work item
72 get { return _useCallerHttpContext; } 43 /// </summary>
73 set { _useCallerHttpContext = value; } 44 public bool DisposeOfStateObjects { get; set; }
74 }
75 45
76 public bool DisposeOfStateObjects 46 /// <summary>
77 { 47 /// Get/Set the run the post execute options
78 get { return _disposeOfStateObjects; } 48 /// </summary>
79 set { _disposeOfStateObjects = value; } 49 public CallToPostExecute CallToPostExecute { get; set; }
80 }
81 50
82 public CallToPostExecute CallToPostExecute 51 /// <summary>
83 { 52 /// Get/Set the post execute callback
84 get { return _callToPostExecute; } 53 /// </summary>
85 set { _callToPostExecute = value; } 54 public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
86 }
87 55
88 public PostExecuteWorkItemCallback PostExecuteWorkItemCallback 56 /// <summary>
89 { 57 /// Get/Set the work item's priority
90 get { return _postExecuteWorkItemCallback; } 58 /// </summary>
91 set { _postExecuteWorkItemCallback = value; } 59 public WorkItemPriority WorkItemPriority { get; set; }
92 }
93 60
94 public WorkItemPriority WorkItemPriority 61 /// <summary>
95 { 62 /// Get/Set the work item's timout in milliseconds.
96 get { return _workItemPriority; } 63 /// This is a passive timout. When the timout expires the work item won't be actively aborted!
97 set { _workItemPriority = value; } 64 /// </summary>
98 } 65 public long Timeout { get; set; }
99 } 66 }
100 67
101 #endregion 68 #endregion
102} 69}
diff --git a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs
new file mode 100644
index 0000000..d1eff95
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs
@@ -0,0 +1,128 @@
1using System;
2using System.Threading;
3
4namespace Amib.Threading.Internal
5{
6 #region WorkItemResultTWrapper class
7
8 internal class WorkItemResultTWrapper<TResult> : IWorkItemResult<TResult>, IInternalWaitableResult
9 {
10 private readonly IWorkItemResult _workItemResult;
11
12 public WorkItemResultTWrapper(IWorkItemResult workItemResult)
13 {
14 _workItemResult = workItemResult;
15 }
16
17 #region IWorkItemResult<TResult> Members
18
19 public TResult GetResult()
20 {
21 return (TResult)_workItemResult.GetResult();
22 }
23
24 public TResult GetResult(int millisecondsTimeout, bool exitContext)
25 {
26 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext);
27 }
28
29 public TResult GetResult(TimeSpan timeout, bool exitContext)
30 {
31 return (TResult)_workItemResult.GetResult(timeout, exitContext);
32 }
33
34 public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
35 {
36 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
37 }
38
39 public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
40 {
41 return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle);
42 }
43
44 public TResult GetResult(out Exception e)
45 {
46 return (TResult)_workItemResult.GetResult(out e);
47 }
48
49 public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
50 {
51 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e);
52 }
53
54 public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e)
55 {
56 return (TResult)_workItemResult.GetResult(timeout, exitContext, out e);
57 }
58
59 public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
60 {
61 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
62 }
63
64 public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
65 {
66 return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e);
67 }
68
69 public bool IsCompleted
70 {
71 get { return _workItemResult.IsCompleted; }
72 }
73
74 public bool IsCanceled
75 {
76 get { return _workItemResult.IsCanceled; }
77 }
78
79 public object State
80 {
81 get { return _workItemResult.State; }
82 }
83
84 public bool Cancel()
85 {
86 return _workItemResult.Cancel();
87 }
88
89 public bool Cancel(bool abortExecution)
90 {
91 return _workItemResult.Cancel(abortExecution);
92 }
93
94 public WorkItemPriority WorkItemPriority
95 {
96 get { return _workItemResult.WorkItemPriority; }
97 }
98
99 public TResult Result
100 {
101 get { return (TResult)_workItemResult.Result; }
102 }
103
104 public object Exception
105 {
106 get { return (TResult)_workItemResult.Exception; }
107 }
108
109 #region IInternalWorkItemResult Members
110
111 public IWorkItemResult GetWorkItemResult()
112 {
113 return _workItemResult.GetWorkItemResult();
114 }
115
116 public IWorkItemResult<TRes> GetWorkItemResultT<TRes>()
117 {
118 return (IWorkItemResult<TRes>)this;
119 }
120
121 #endregion
122
123 #endregion
124 }
125
126 #endregion
127
128}
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
index 01ac8dd..d9d34ac 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
@@ -1,6 +1,3 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
5using System.Threading; 2using System.Threading;
6using System.Runtime.CompilerServices; 3using System.Runtime.CompilerServices;
@@ -8,505 +5,357 @@ using System.Diagnostics;
8 5
9namespace Amib.Threading.Internal 6namespace Amib.Threading.Internal
10{ 7{
11 #region WorkItemsGroup class
12
13 /// <summary>
14 /// Summary description for WorkItemsGroup.
15 /// </summary>
16 public class WorkItemsGroup : IWorkItemsGroup
17 {
18 #region Private members
19
20 private object _lock = new object();
21 /// <summary>
22 /// Contains the name of this instance of SmartThreadPool.
23 /// Can be changed by the user.
24 /// </summary>
25 private string _name = "WorkItemsGroup";
26
27 /// <summary>
28 /// A reference to the SmartThreadPool instance that created this
29 /// WorkItemsGroup.
30 /// </summary>
31 private SmartThreadPool _stp;
32
33 /// <summary>
34 /// The OnIdle event
35 /// </summary>
36 private event WorkItemsGroupIdleHandler _onIdle;
37 8
38 /// <summary> 9 #region WorkItemsGroup class
39 /// Defines how many work items of this WorkItemsGroup can run at once.
40 /// </summary>
41 private int _concurrency;
42 10
43 /// <summary> 11 /// <summary>
44 /// Priority queue to hold work items before they are passed 12 /// Summary description for WorkItemsGroup.
45 /// to the SmartThreadPool. 13 /// </summary>
46 /// </summary> 14 public class WorkItemsGroup : WorkItemsGroupBase
47 private PriorityQueue _workItemsQueue; 15 {
16 #region Private members
48 17
49 /// <summary> 18 private readonly object _lock = new object();
50 /// Indicate how many work items are waiting in the SmartThreadPool
51 /// queue.
52 /// This value is used to apply the concurrency.
53 /// </summary>
54 private int _workItemsInStpQueue;
55 19
56 /// <summary> 20 /// <summary>
57 /// Indicate how many work items are currently running in the SmartThreadPool. 21 /// A reference to the SmartThreadPool instance that created this
58 /// This value is used with the Cancel, to calculate if we can send new 22 /// WorkItemsGroup.
59 /// work items to the STP. 23 /// </summary>
60 /// </summary> 24 private readonly SmartThreadPool _stp;
61 private int _workItemsExecutingInStp = 0;
62 25
63 /// <summary> 26 /// <summary>
64 /// WorkItemsGroup start information 27 /// The OnIdle event
65 /// </summary> 28 /// </summary>
66 private WIGStartInfo _workItemsGroupStartInfo; 29 private event WorkItemsGroupIdleHandler _onIdle;
67 30
68 /// <summary> 31 /// <summary>
69 /// Signaled when all of the WorkItemsGroup's work item completed. 32 /// A flag to indicate if the Work Items Group is now suspended.
70 /// </summary> 33 /// </summary>
71 private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); 34 private bool _isSuspended;
72 35
73 /// <summary> 36 /// <summary>
74 /// A common object for all the work items that this work items group 37 /// Defines how many work items of this WorkItemsGroup can run at once.
75 /// generate so we can mark them to cancel in O(1) 38 /// </summary>
76 /// </summary> 39 private int _concurrency;
77 private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); 40
78 41 /// <summary>
79 #endregion 42 /// Priority queue to hold work items before they are passed
80 43 /// to the SmartThreadPool.
81 #region Construction 44 /// </summary>
82 45 private readonly PriorityQueue _workItemsQueue;
83 public WorkItemsGroup( 46
84 SmartThreadPool stp, 47 /// <summary>
85 int concurrency, 48 /// Indicate how many work items are waiting in the SmartThreadPool
86 WIGStartInfo wigStartInfo) 49 /// queue.
50 /// This value is used to apply the concurrency.
51 /// </summary>
52 private int _workItemsInStpQueue;
53
54 /// <summary>
55 /// Indicate how many work items are currently running in the SmartThreadPool.
56 /// This value is used with the Cancel, to calculate if we can send new
57 /// work items to the STP.
58 /// </summary>
59 private int _workItemsExecutingInStp = 0;
60
61 /// <summary>
62 /// WorkItemsGroup start information
63 /// </summary>
64 private readonly WIGStartInfo _workItemsGroupStartInfo;
65
66 /// <summary>
67 /// Signaled when all of the WorkItemsGroup's work item completed.
68 /// </summary>
69 //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
70 private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
71
72 /// <summary>
73 /// A common object for all the work items that this work items group
74 /// generate so we can mark them to cancel in O(1)
75 /// </summary>
76 private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
77
78 #endregion
79
80 #region Construction
81
82 public WorkItemsGroup(
83 SmartThreadPool stp,
84 int concurrency,
85 WIGStartInfo wigStartInfo)
86 {
87 if (concurrency <= 0)
88 {
89 throw new ArgumentOutOfRangeException(
90 "concurrency",
91#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
92 concurrency,
93#endif
94 "concurrency must be greater than zero");
95 }
96 _stp = stp;
97 _concurrency = concurrency;
98 _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
99 _workItemsQueue = new PriorityQueue();
100 Name = "WorkItemsGroup";
101
102 // The _workItemsInStpQueue gets the number of currently executing work items,
103 // because once a work item is executing, it cannot be cancelled.
104 _workItemsInStpQueue = _workItemsExecutingInStp;
105
106 _isSuspended = _workItemsGroupStartInfo.StartSuspended;
107 }
108
109 #endregion
110
111 #region WorkItemsGroupBase Overrides
112
113 public override int Concurrency
87 { 114 {
88 if (concurrency <= 0) 115 get { return _concurrency; }
89 {
90 throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero");
91 }
92 _stp = stp;
93 _concurrency = concurrency;
94 _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo);
95 _workItemsQueue = new PriorityQueue();
96
97 // The _workItemsInStpQueue gets the number of currently executing work items,
98 // because once a work item is executing, it cannot be cancelled.
99 _workItemsInStpQueue = _workItemsExecutingInStp;
100 }
101
102 #endregion
103
104 #region IWorkItemsGroup implementation
105
106 /// <summary>
107 /// Get/Set the name of the SmartThreadPool instance
108 /// </summary>
109 public string Name
110 {
111 get
112 {
113 return _name;
114 }
115
116 set 116 set
117 { 117 {
118 _name = value; 118 Debug.Assert(value > 0);
119 }
120 }
121
122 /// <summary>
123 /// Queue a work item
124 /// </summary>
125 /// <param name="callback">A callback to execute</param>
126 /// <returns>Returns a work item result</returns>
127 public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
128 {
129 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback);
130 EnqueueToSTPNextWorkItem(workItem);
131 return workItem.GetWorkItemResult();
132 }
133 119
134 /// <summary> 120 int diff = value - _concurrency;
135 /// Queue a work item 121 _concurrency = value;
136 /// </summary> 122 if (diff > 0)
137 /// <param name="callback">A callback to execute</param> 123 {
138 /// <param name="workItemPriority">The priority of the work item</param> 124 EnqueueToSTPNextNWorkItem(diff);
139 /// <returns>Returns a work item result</returns> 125 }
140 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) 126 }
141 {
142 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority);
143 EnqueueToSTPNextWorkItem(workItem);
144 return workItem.GetWorkItemResult();
145 }
146
147 /// <summary>
148 /// Queue a work item
149 /// </summary>
150 /// <param name="workItemInfo">Work item info</param>
151 /// <param name="callback">A callback to execute</param>
152 /// <returns>Returns a work item result</returns>
153 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
154 {
155 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback);
156 EnqueueToSTPNextWorkItem(workItem);
157 return workItem.GetWorkItemResult();
158 }
159
160 /// <summary>
161 /// Queue a work item
162 /// </summary>
163 /// <param name="callback">A callback to execute</param>
164 /// <param name="state">
165 /// The context object of the work item. Used for passing arguments to the work item.
166 /// </param>
167 /// <returns>Returns a work item result</returns>
168 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
169 {
170 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state);
171 EnqueueToSTPNextWorkItem(workItem);
172 return workItem.GetWorkItemResult();
173 }
174
175 /// <summary>
176 /// Queue a work item
177 /// </summary>
178 /// <param name="callback">A callback to execute</param>
179 /// <param name="state">
180 /// The context object of the work item. Used for passing arguments to the work item.
181 /// </param>
182 /// <param name="workItemPriority">The work item priority</param>
183 /// <returns>Returns a work item result</returns>
184 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
185 {
186 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, workItemPriority);
187 EnqueueToSTPNextWorkItem(workItem);
188 return workItem.GetWorkItemResult();
189 }
190
191 /// <summary>
192 /// Queue a work item
193 /// </summary>
194 /// <param name="workItemInfo">Work item information</param>
195 /// <param name="callback">A callback to execute</param>
196 /// <param name="state">
197 /// The context object of the work item. Used for passing arguments to the work item.
198 /// </param>
199 /// <returns>Returns a work item result</returns>
200 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
201 {
202 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback, state);
203 EnqueueToSTPNextWorkItem(workItem);
204 return workItem.GetWorkItemResult();
205 }
206
207 /// <summary>
208 /// Queue a work item
209 /// </summary>
210 /// <param name="callback">A callback to execute</param>
211 /// <param name="state">
212 /// The context object of the work item. Used for passing arguments to the work item.
213 /// </param>
214 /// <param name="postExecuteWorkItemCallback">
215 /// A delegate to call after the callback completion
216 /// </param>
217 /// <returns>Returns a work item result</returns>
218 public IWorkItemResult QueueWorkItem(
219 WorkItemCallback callback,
220 object state,
221 PostExecuteWorkItemCallback postExecuteWorkItemCallback)
222 {
223 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback);
224 EnqueueToSTPNextWorkItem(workItem);
225 return workItem.GetWorkItemResult();
226 }
227
228 /// <summary>
229 /// Queue a work item
230 /// </summary>
231 /// <param name="callback">A callback to execute</param>
232 /// <param name="state">
233 /// The context object of the work item. Used for passing arguments to the work item.
234 /// </param>
235 /// <param name="postExecuteWorkItemCallback">
236 /// A delegate to call after the callback completion
237 /// </param>
238 /// <param name="workItemPriority">The work item priority</param>
239 /// <returns>Returns a work item result</returns>
240 public IWorkItemResult QueueWorkItem(
241 WorkItemCallback callback,
242 object state,
243 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
244 WorkItemPriority workItemPriority)
245 {
246 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
247 EnqueueToSTPNextWorkItem(workItem);
248 return workItem.GetWorkItemResult();
249 }
250
251 /// <summary>
252 /// Queue a work item
253 /// </summary>
254 /// <param name="callback">A callback to execute</param>
255 /// <param name="state">
256 /// The context object of the work item. Used for passing arguments to the work item.
257 /// </param>
258 /// <param name="postExecuteWorkItemCallback">
259 /// A delegate to call after the callback completion
260 /// </param>
261 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
262 /// <returns>Returns a work item result</returns>
263 public IWorkItemResult QueueWorkItem(
264 WorkItemCallback callback,
265 object state,
266 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
267 CallToPostExecute callToPostExecute)
268 {
269 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
270 EnqueueToSTPNextWorkItem(workItem);
271 return workItem.GetWorkItemResult();
272 } 127 }
273 128
274 /// <summary> 129 public override int WaitingCallbacks
275 /// Queue a work item
276 /// </summary>
277 /// <param name="callback">A callback to execute</param>
278 /// <param name="state">
279 /// The context object of the work item. Used for passing arguments to the work item.
280 /// </param>
281 /// <param name="postExecuteWorkItemCallback">
282 /// A delegate to call after the callback completion
283 /// </param>
284 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
285 /// <param name="workItemPriority">The work item priority</param>
286 /// <returns>Returns a work item result</returns>
287 public IWorkItemResult QueueWorkItem(
288 WorkItemCallback callback,
289 object state,
290 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
291 CallToPostExecute callToPostExecute,
292 WorkItemPriority workItemPriority)
293 { 130 {
294 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); 131 get { return _workItemsQueue.Count; }
295 EnqueueToSTPNextWorkItem(workItem);
296 return workItem.GetWorkItemResult();
297 } 132 }
298 133
299 /// <summary> 134 public override object[] GetStates()
300 /// Wait for the thread pool to be idle
301 /// </summary>
302 public void WaitForIdle()
303 { 135 {
304 WaitForIdle(Timeout.Infinite); 136 lock (_lock)
137 {
138 object[] states = new object[_workItemsQueue.Count];
139 int i = 0;
140 foreach (WorkItem workItem in _workItemsQueue)
141 {
142 states[i] = workItem.GetWorkItemResult().State;
143 ++i;
144 }
145 return states;
146 }
305 } 147 }
306 148
307 /// <summary> 149 /// <summary>
308 /// Wait for the thread pool to be idle 150 /// WorkItemsGroup start information
309 /// </summary> 151 /// </summary>
310 public bool WaitForIdle(TimeSpan timeout) 152 public override WIGStartInfo WIGStartInfo
311 { 153 {
312 return WaitForIdle((int)timeout.TotalMilliseconds); 154 get { return _workItemsGroupStartInfo; }
313 } 155 }
314 156
315 /// <summary> 157 /// <summary>
158 /// Start the Work Items Group if it was started suspended
159 /// </summary>
160 public override void Start()
161 {
162 // If the Work Items Group already started then quit
163 if (!_isSuspended)
164 {
165 return;
166 }
167 _isSuspended = false;
168
169 EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
170 }
171
172 public override void Cancel(bool abortExecution)
173 {
174 lock (_lock)
175 {
176 _canceledWorkItemsGroup.IsCanceled = true;
177 _workItemsQueue.Clear();
178 _workItemsInStpQueue = 0;
179 _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
180 }
181
182 if (abortExecution)
183 {
184 _stp.CancelAbortWorkItemsGroup(this);
185 }
186 }
187
188 /// <summary>
316 /// Wait for the thread pool to be idle 189 /// Wait for the thread pool to be idle
317 /// </summary> 190 /// </summary>
318 public bool WaitForIdle(int millisecondsTimeout) 191 public override bool WaitForIdle(int millisecondsTimeout)
319 { 192 {
320 _stp.ValidateWorkItemsGroupWaitForIdle(this); 193 SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
321 return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false); 194 return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
322 } 195 }
323 196
324 public int WaitingCallbacks 197 public override event WorkItemsGroupIdleHandler OnIdle
325 { 198 {
326 get 199 add { _onIdle += value; }
327 { 200 remove { _onIdle -= value; }
328 return _workItemsQueue.Count; 201 }
329 }
330 }
331 202
332 public event WorkItemsGroupIdleHandler OnIdle 203 #endregion
333 {
334 add
335 {
336 _onIdle += value;
337 }
338 remove
339 {
340 _onIdle -= value;
341 }
342 }
343 204
344 public void Cancel() 205 #region Private methods
345 {
346 lock(_lock)
347 {
348 _canceledWorkItemsGroup.IsCanceled = true;
349 _workItemsQueue.Clear();
350 _workItemsInStpQueue = 0;
351 _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
352 }
353 }
354 206
355 public void Start() 207 private void RegisterToWorkItemCompletion(IWorkItemResult wir)
356 { 208 {
357 lock (this) 209 IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
358 { 210 iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
359 if (!_workItemsGroupStartInfo.StartSuspended) 211 iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
360 { 212 }
361 return;
362 }
363 _workItemsGroupStartInfo.StartSuspended = false;
364 }
365
366 for(int i = 0; i < _concurrency; ++i)
367 {
368 EnqueueToSTPNextWorkItem(null, false);
369 }
370 }
371
372 #endregion
373 213
374 #region Private methods 214 public void OnSTPIsStarting()
375 215 {
376 private void RegisterToWorkItemCompletion(IWorkItemResult wir) 216 if (_isSuspended)
377 {
378 IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
379 iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
380 iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
381 }
382
383 public void OnSTPIsStarting()
384 {
385 lock (this)
386 {
387 if (_workItemsGroupStartInfo.StartSuspended)
388 {
389 return;
390 }
391 }
392
393 for(int i = 0; i < _concurrency; ++i)
394 {
395 EnqueueToSTPNextWorkItem(null, false);
396 }
397 }
398
399 private object FireOnIdle(object state)
400 {
401 FireOnIdleImpl(_onIdle);
402 return null;
403 }
404
405 [MethodImpl(MethodImplOptions.NoInlining)]
406 private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
407 {
408 if(null == onIdle)
409 { 217 {
410 return; 218 return;
411 } 219 }
220
221 EnqueueToSTPNextNWorkItem(_concurrency);
222 }
412 223
413 Delegate[] delegates = onIdle.GetInvocationList(); 224 public void EnqueueToSTPNextNWorkItem(int count)
414 foreach(WorkItemsGroupIdleHandler eh in delegates)
415 {
416 try
417 {
418 eh(this);
419 }
420 // Ignore exceptions
421 catch{}
422 }
423 }
424
425 private void OnWorkItemStartedCallback(WorkItem workItem)
426 { 225 {
427 lock(_lock) 226 for (int i = 0; i < count; ++i)
428 { 227 {
429 ++_workItemsExecutingInStp; 228 EnqueueToSTPNextWorkItem(null, false);
430 } 229 }
431 } 230 }
432 231
433 private void OnWorkItemCompletedCallback(WorkItem workItem) 232 private object FireOnIdle(object state)
434 { 233 {
435 EnqueueToSTPNextWorkItem(null, true); 234 FireOnIdleImpl(_onIdle);
436 } 235 return null;
437 236 }
438 private void EnqueueToSTPNextWorkItem(WorkItem workItem) 237
238 [MethodImpl(MethodImplOptions.NoInlining)]
239 private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
240 {
241 if(null == onIdle)
242 {
243 return;
244 }
245
246 Delegate[] delegates = onIdle.GetInvocationList();
247 foreach(WorkItemsGroupIdleHandler eh in delegates)
248 {
249 try
250 {
251 eh(this);
252 }
253 catch { } // Suppress exceptions
254 }
255 }
256
257 private void OnWorkItemStartedCallback(WorkItem workItem)
258 {
259 lock(_lock)
260 {
261 ++_workItemsExecutingInStp;
262 }
263 }
264
265 private void OnWorkItemCompletedCallback(WorkItem workItem)
266 {
267 EnqueueToSTPNextWorkItem(null, true);
268 }
269
270 internal override void Enqueue(WorkItem workItem)
439 { 271 {
440 EnqueueToSTPNextWorkItem(workItem, false); 272 EnqueueToSTPNextWorkItem(workItem);
441 } 273 }
442 274
443 private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) 275 private void EnqueueToSTPNextWorkItem(WorkItem workItem)
444 { 276 {
445 lock(_lock) 277 EnqueueToSTPNextWorkItem(workItem, false);
446 { 278 }
447 // Got here from OnWorkItemCompletedCallback() 279
448 if (decrementWorkItemsInStpQueue) 280 private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
449 { 281 {
450 --_workItemsInStpQueue; 282 lock(_lock)
451 283 {
452 if(_workItemsInStpQueue < 0) 284 // Got here from OnWorkItemCompletedCallback()
453 { 285 if (decrementWorkItemsInStpQueue)
454 _workItemsInStpQueue = 0; 286 {
455 } 287 --_workItemsInStpQueue;
456 288
457 --_workItemsExecutingInStp; 289 if(_workItemsInStpQueue < 0)
458 290 {
459 if(_workItemsExecutingInStp < 0) 291 _workItemsInStpQueue = 0;
460 { 292 }
461 _workItemsExecutingInStp = 0; 293
462 } 294 --_workItemsExecutingInStp;
463 } 295
464 296 if(_workItemsExecutingInStp < 0)
465 // If the work item is not null then enqueue it 297 {
466 if (null != workItem) 298 _workItemsExecutingInStp = 0;
467 { 299 }
468 workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; 300 }
469 301
470 RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); 302 // If the work item is not null then enqueue it
471 _workItemsQueue.Enqueue(workItem); 303 if (null != workItem)
472 //_stp.IncrementWorkItemsCount(); 304 {
473 305 workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
474 if ((1 == _workItemsQueue.Count) && 306
475 (0 == _workItemsInStpQueue)) 307 RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
476 { 308 _workItemsQueue.Enqueue(workItem);
477 _stp.RegisterWorkItemsGroup(this); 309 //_stp.IncrementWorkItemsCount();
478 Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle"); 310
311 if ((1 == _workItemsQueue.Count) &&
312 (0 == _workItemsInStpQueue))
313 {
314 _stp.RegisterWorkItemsGroup(this);
315 IsIdle = false;
479 _isIdleWaitHandle.Reset(); 316 _isIdleWaitHandle.Reset();
480 } 317 }
481 } 318 }
482 319
483 // If the work items queue of the group is empty than quit 320 // If the work items queue of the group is empty than quit
484 if (0 == _workItemsQueue.Count) 321 if (0 == _workItemsQueue.Count)
485 { 322 {
486 if (0 == _workItemsInStpQueue) 323 if (0 == _workItemsInStpQueue)
487 { 324 {
488 _stp.UnregisterWorkItemsGroup(this); 325 _stp.UnregisterWorkItemsGroup(this);
489 Trace.WriteLine("WorkItemsGroup " + Name + " is idle"); 326 IsIdle = true;
490 _isIdleWaitHandle.Set(); 327 _isIdleWaitHandle.Set();
491 _stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle)); 328 if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
492 } 329 {
493 return; 330 _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
494 } 331 }
495 332 }
496 if (!_workItemsGroupStartInfo.StartSuspended) 333 return;
497 { 334 }
498 if (_workItemsInStpQueue < _concurrency) 335
499 { 336 if (!_isSuspended)
500 WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; 337 {
501 _stp.Enqueue(nextWorkItem, true); 338 if (_workItemsInStpQueue < _concurrency)
502 ++_workItemsInStpQueue; 339 {
503 } 340 WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
504 } 341 try
505 } 342 {
506 } 343 _stp.Enqueue(nextWorkItem);
507 344 }
508 #endregion 345 catch (ObjectDisposedException e)
346 {
347 e.GetHashCode();
348 // The STP has been shutdown
349 }
350
351 ++_workItemsInStpQueue;
352 }
353 }
354 }
355 }
356
357 #endregion
509 } 358 }
510 359
511 #endregion 360 #endregion
512} 361}
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs
new file mode 100644
index 0000000..27fae5e
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs
@@ -0,0 +1,471 @@
1using System;
2using System.Threading;
3
4namespace Amib.Threading.Internal
5{
6 public abstract class WorkItemsGroupBase : IWorkItemsGroup
7 {
8 #region Private Fields
9
10 /// <summary>
11 /// Contains the name of this instance of SmartThreadPool.
12 /// Can be changed by the user.
13 /// </summary>
14 private string _name = "WorkItemsGroupBase";
15
16 public WorkItemsGroupBase()
17 {
18 IsIdle = true;
19 }
20
21 #endregion
22
23 #region IWorkItemsGroup Members
24
25 #region Public Methods
26
27 /// <summary>
28 /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance
29 /// </summary>
30 public string Name
31 {
32 get { return _name; }
33 set { _name = value; }
34 }
35
36 #endregion
37
38 #region Abstract Methods
39
40 public abstract int Concurrency { get; set; }
41 public abstract int WaitingCallbacks { get; }
42 public abstract object[] GetStates();
43 public abstract WIGStartInfo WIGStartInfo { get; }
44 public abstract void Start();
45 public abstract void Cancel(bool abortExecution);
46 public abstract bool WaitForIdle(int millisecondsTimeout);
47 public abstract event WorkItemsGroupIdleHandler OnIdle;
48
49 internal abstract void Enqueue(WorkItem workItem);
50 internal virtual void PreQueueWorkItem() { }
51
52 #endregion
53
54 #region Common Base Methods
55
56 /// <summary>
57 /// Cancel all the work items.
58 /// Same as Cancel(false)
59 /// </summary>
60 public virtual void Cancel()
61 {
62 Cancel(false);
63 }
64
65 /// <summary>
66 /// Wait for the SmartThreadPool/WorkItemsGroup to be idle
67 /// </summary>
68 public void WaitForIdle()
69 {
70 WaitForIdle(Timeout.Infinite);
71 }
72
73 /// <summary>
74 /// Wait for the SmartThreadPool/WorkItemsGroup to be idle
75 /// </summary>
76 public bool WaitForIdle(TimeSpan timeout)
77 {
78 return WaitForIdle((int)timeout.TotalMilliseconds);
79 }
80
81 /// <summary>
82 /// IsIdle is true when there are no work items running or queued.
83 /// </summary>
84 public bool IsIdle { get; protected set; }
85
86 #endregion
87
88 #region QueueWorkItem
89
90 /// <summary>
91 /// Queue a work item
92 /// </summary>
93 /// <param name="callback">A callback to execute</param>
94 /// <returns>Returns a work item result</returns>
95 public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
96 {
97 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback);
98 Enqueue(workItem);
99 return workItem.GetWorkItemResult();
100 }
101
102 /// <summary>
103 /// Queue a work item
104 /// </summary>
105 /// <param name="callback">A callback to execute</param>
106 /// <param name="workItemPriority">The priority of the work item</param>
107 /// <returns>Returns a work item result</returns>
108 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
109 {
110 PreQueueWorkItem();
111 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority);
112 Enqueue(workItem);
113 return workItem.GetWorkItemResult();
114 }
115
116 /// <summary>
117 /// Queue a work item
118 /// </summary>
119 /// <param name="workItemInfo">Work item info</param>
120 /// <param name="callback">A callback to execute</param>
121 /// <returns>Returns a work item result</returns>
122 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
123 {
124 PreQueueWorkItem();
125 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback);
126 Enqueue(workItem);
127 return workItem.GetWorkItemResult();
128 }
129
130 /// <summary>
131 /// Queue a work item
132 /// </summary>
133 /// <param name="callback">A callback to execute</param>
134 /// <param name="state">
135 /// The context object of the work item. Used for passing arguments to the work item.
136 /// </param>
137 /// <returns>Returns a work item result</returns>
138 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
139 {
140 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state);
141 Enqueue(workItem);
142 return workItem.GetWorkItemResult();
143 }
144
145 /// <summary>
146 /// Queue a work item
147 /// </summary>
148 /// <param name="callback">A callback to execute</param>
149 /// <param name="state">
150 /// The context object of the work item. Used for passing arguments to the work item.
151 /// </param>
152 /// <param name="workItemPriority">The work item priority</param>
153 /// <returns>Returns a work item result</returns>
154 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
155 {
156 PreQueueWorkItem();
157 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority);
158 Enqueue(workItem);
159 return workItem.GetWorkItemResult();
160 }
161
162 /// <summary>
163 /// Queue a work item
164 /// </summary>
165 /// <param name="workItemInfo">Work item information</param>
166 /// <param name="callback">A callback to execute</param>
167 /// <param name="state">
168 /// The context object of the work item. Used for passing arguments to the work item.
169 /// </param>
170 /// <returns>Returns a work item result</returns>
171 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
172 {
173 PreQueueWorkItem();
174 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state);
175 Enqueue(workItem);
176 return workItem.GetWorkItemResult();
177 }
178
179 /// <summary>
180 /// Queue a work item
181 /// </summary>
182 /// <param name="callback">A callback to execute</param>
183 /// <param name="state">
184 /// The context object of the work item. Used for passing arguments to the work item.
185 /// </param>
186 /// <param name="postExecuteWorkItemCallback">
187 /// A delegate to call after the callback completion
188 /// </param>
189 /// <returns>Returns a work item result</returns>
190 public IWorkItemResult QueueWorkItem(
191 WorkItemCallback callback,
192 object state,
193 PostExecuteWorkItemCallback postExecuteWorkItemCallback)
194 {
195 PreQueueWorkItem();
196 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback);
197 Enqueue(workItem);
198 return workItem.GetWorkItemResult();
199 }
200
201 /// <summary>
202 /// Queue a work item
203 /// </summary>
204 /// <param name="callback">A callback to execute</param>
205 /// <param name="state">
206 /// The context object of the work item. Used for passing arguments to the work item.
207 /// </param>
208 /// <param name="postExecuteWorkItemCallback">
209 /// A delegate to call after the callback completion
210 /// </param>
211 /// <param name="workItemPriority">The work item priority</param>
212 /// <returns>Returns a work item result</returns>
213 public IWorkItemResult QueueWorkItem(
214 WorkItemCallback callback,
215 object state,
216 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
217 WorkItemPriority workItemPriority)
218 {
219 PreQueueWorkItem();
220 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
221 Enqueue(workItem);
222 return workItem.GetWorkItemResult();
223 }
224
225 /// <summary>
226 /// Queue a work item
227 /// </summary>
228 /// <param name="callback">A callback to execute</param>
229 /// <param name="state">
230 /// The context object of the work item. Used for passing arguments to the work item.
231 /// </param>
232 /// <param name="postExecuteWorkItemCallback">
233 /// A delegate to call after the callback completion
234 /// </param>
235 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
236 /// <returns>Returns a work item result</returns>
237 public IWorkItemResult QueueWorkItem(
238 WorkItemCallback callback,
239 object state,
240 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
241 CallToPostExecute callToPostExecute)
242 {
243 PreQueueWorkItem();
244 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
245 Enqueue(workItem);
246 return workItem.GetWorkItemResult();
247 }
248
249 /// <summary>
250 /// Queue a work item
251 /// </summary>
252 /// <param name="callback">A callback to execute</param>
253 /// <param name="state">
254 /// The context object of the work item. Used for passing arguments to the work item.
255 /// </param>
256 /// <param name="postExecuteWorkItemCallback">
257 /// A delegate to call after the callback completion
258 /// </param>
259 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
260 /// <param name="workItemPriority">The work item priority</param>
261 /// <returns>Returns a work item result</returns>
262 public IWorkItemResult QueueWorkItem(
263 WorkItemCallback callback,
264 object state,
265 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
266 CallToPostExecute callToPostExecute,
267 WorkItemPriority workItemPriority)
268 {
269 PreQueueWorkItem();
270 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
271 Enqueue(workItem);
272 return workItem.GetWorkItemResult();
273 }
274
275 #endregion
276
277 #region QueueWorkItem(Action<...>)
278
279 public IWorkItemResult QueueWorkItem(Action action)
280 {
281 return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority);
282 }
283
284 public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority)
285 {
286 PreQueueWorkItem ();
287 WorkItem workItem = WorkItemFactory.CreateWorkItem (
288 this,
289 WIGStartInfo,
290 delegate
291 {
292 action.Invoke ();
293 return null;
294 }, priority);
295 Enqueue (workItem);
296 return workItem.GetWorkItemResult ();
297 }
298
299 public IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg)
300 {
301 return QueueWorkItem<T> (action, arg, SmartThreadPool.DefaultWorkItemPriority);
302 }
303
304 public IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg, WorkItemPriority priority)
305 {
306 PreQueueWorkItem ();
307 WorkItem workItem = WorkItemFactory.CreateWorkItem (
308 this,
309 WIGStartInfo,
310 state =>
311 {
312 action.Invoke (arg);
313 return null;
314 },
315 WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority);
316 Enqueue (workItem);
317 return workItem.GetWorkItemResult ();
318 }
319
320 public IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
321 {
322 return QueueWorkItem<T1, T2> (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority);
323 }
324
325 public IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority)
326 {
327 PreQueueWorkItem ();
328 WorkItem workItem = WorkItemFactory.CreateWorkItem (
329 this,
330 WIGStartInfo,
331 state =>
332 {
333 action.Invoke (arg1, arg2);
334 return null;
335 },
336 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority);
337 Enqueue (workItem);
338 return workItem.GetWorkItemResult ();
339 }
340
341 public IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
342 {
343 return QueueWorkItem<T1, T2, T3> (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority);
344 ;
345 }
346
347 public IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority)
348 {
349 PreQueueWorkItem ();
350 WorkItem workItem = WorkItemFactory.CreateWorkItem (
351 this,
352 WIGStartInfo,
353 state =>
354 {
355 action.Invoke (arg1, arg2, arg3);
356 return null;
357 },
358 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority);
359 Enqueue (workItem);
360 return workItem.GetWorkItemResult ();
361 }
362
363 public IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(
364 Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
365 {
366 return QueueWorkItem<T1, T2, T3, T4> (action, arg1, arg2, arg3, arg4,
367 SmartThreadPool.DefaultWorkItemPriority);
368 }
369
370 public IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (
371 Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority)
372 {
373 PreQueueWorkItem ();
374 WorkItem workItem = WorkItemFactory.CreateWorkItem (
375 this,
376 WIGStartInfo,
377 state =>
378 {
379 action.Invoke (arg1, arg2, arg3, arg4);
380 return null;
381 },
382 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority);
383 Enqueue (workItem);
384 return workItem.GetWorkItemResult ();
385 }
386
387 #endregion
388
389 #region QueueWorkItem(Func<...>)
390
391 public IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func)
392 {
393 PreQueueWorkItem();
394 WorkItem workItem = WorkItemFactory.CreateWorkItem(
395 this,
396 WIGStartInfo,
397 state =>
398 {
399 return func.Invoke();
400 });
401 Enqueue(workItem);
402 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
403 }
404
405 public IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg)
406 {
407 PreQueueWorkItem();
408 WorkItem workItem = WorkItemFactory.CreateWorkItem(
409 this,
410 WIGStartInfo,
411 state =>
412 {
413 return func.Invoke(arg);
414 },
415 WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null);
416 Enqueue(workItem);
417 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
418 }
419
420 public IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
421 {
422 PreQueueWorkItem();
423 WorkItem workItem = WorkItemFactory.CreateWorkItem(
424 this,
425 WIGStartInfo,
426 state =>
427 {
428 return func.Invoke(arg1, arg2);
429 },
430 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null);
431 Enqueue(workItem);
432 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
433 }
434
435 public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(
436 Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3)
437 {
438 PreQueueWorkItem();
439 WorkItem workItem = WorkItemFactory.CreateWorkItem(
440 this,
441 WIGStartInfo,
442 state =>
443 {
444 return func.Invoke(arg1, arg2, arg3);
445 },
446 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null);
447 Enqueue(workItem);
448 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
449 }
450
451 public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(
452 Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
453 {
454 PreQueueWorkItem();
455 WorkItem workItem = WorkItemFactory.CreateWorkItem(
456 this,
457 WIGStartInfo,
458 state =>
459 {
460 return func.Invoke(arg1, arg2, arg3, arg4);
461 },
462 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null);
463 Enqueue(workItem);
464 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
465 }
466
467 #endregion
468
469 #endregion
470 }
471} \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
index af5af07..e0bc916 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
@@ -1,109 +1,151 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
2using System.Collections.Generic;
5using System.Threading; 3using System.Threading;
6 4
7namespace Amib.Threading.Internal 5namespace Amib.Threading.Internal
8{ 6{
9 #region WorkItemsQueue class 7 #region WorkItemsQueue class
10 8
11 /// <summary> 9 /// <summary>
12 /// WorkItemsQueue class. 10 /// WorkItemsQueue class.
13 /// </summary> 11 /// </summary>
14 public class WorkItemsQueue : IDisposable 12 public class WorkItemsQueue : IDisposable
15 { 13 {
16 #region Member variables 14 #region Member variables
17 15
18 /// <summary> 16 /// <summary>
19 /// Waiters queue (implemented as stack). 17 /// Waiters queue (implemented as stack).
20 /// </summary> 18 /// </summary>
21 private WaiterEntry _headWaiterEntry = new WaiterEntry(); 19 private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
22 20
23 /// <summary> 21 /// <summary>
24 /// Waiters count 22 /// Waiters count
25 /// </summary> 23 /// </summary>
26 private int _waitersCount = 0; 24 private int _waitersCount = 0;
27 25
28 /// <summary> 26 /// <summary>
29 /// Work items queue 27 /// Work items queue
30 /// </summary> 28 /// </summary>
31 private PriorityQueue _workItems = new PriorityQueue(); 29 private readonly PriorityQueue _workItems = new PriorityQueue();
32 30
33 /// <summary> 31 /// <summary>
34 /// Indicate that work items are allowed to be queued 32 /// Indicate that work items are allowed to be queued
35 /// </summary> 33 /// </summary>
36 private bool _isWorkItemsQueueActive = true; 34 private bool _isWorkItemsQueueActive = true;
37 35
38 /// <summary>
39 /// Each thread in the thread pool keeps its own waiter entry.
40 /// </summary>
41 [ThreadStatic]
42 private static WaiterEntry _waiterEntry;
43 36
44 /// <summary> 37#if (WINDOWS_PHONE)
45 /// A flag that indicates if the WorkItemsQueue has been disposed. 38 private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>();
46 /// </summary> 39#elif (_WINDOWS_CE)
47 private bool _isDisposed = false; 40 private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
41#else
48 42
49 #endregion 43 [ThreadStatic]
44 private static WaiterEntry _waiterEntry;
45#endif
50 46
51 #region Public properties
52 47
53 /// <summary> 48 /// <summary>
54 /// Returns the current number of work items in the queue 49 /// Each thread in the thread pool keeps its own waiter entry.
55 /// </summary> 50 /// </summary>
56 public int Count 51 private static WaiterEntry CurrentWaiterEntry
57 { 52 {
53#if (WINDOWS_PHONE)
58 get 54 get
59 { 55 {
60 lock(this) 56 lock (_waiterEntries)
61 { 57 {
62 ValidateNotDisposed(); 58 WaiterEntry waiterEntry;
63 return _workItems.Count; 59 if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry))
60 {
61 return waiterEntry;
62 }
64 } 63 }
64 return null;
65 } 65 }
66 } 66 set
67
68 /// <summary>
69 /// Returns the current number of waiters
70 /// </summary>
71 public int WaitersCount
72 {
73 get
74 { 67 {
75 lock(this) 68 lock (_waiterEntries)
76 { 69 {
77 ValidateNotDisposed(); 70 _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value;
78 return _waitersCount;
79 } 71 }
80 } 72 }
73#elif (_WINDOWS_CE)
74 get
75 {
76 return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
77 }
78 set
79 {
80 Thread.SetData(_waiterEntrySlot, value);
81 }
82#else
83 get
84 {
85 return _waiterEntry;
86 }
87 set
88 {
89 _waiterEntry = value;
90 }
91#endif
81 } 92 }
82 93
94 /// <summary>
95 /// A flag that indicates if the WorkItemsQueue has been disposed.
96 /// </summary>
97 private bool _isDisposed = false;
83 98
84 #endregion 99 #endregion
85 100
86 #region Public methods 101 #region Public properties
87 102
88 /// <summary> 103 /// <summary>
89 /// Enqueue a work item to the queue. 104 /// Returns the current number of work items in the queue
90 /// </summary> 105 /// </summary>
91 public bool EnqueueWorkItem(WorkItem workItem) 106 public int Count
92 { 107 {
93 // A work item cannot be null, since null is used in the 108 get
94 // WaitForWorkItem() method to indicate timeout or cancel 109 {
95 if (null == workItem) 110 return _workItems.Count;
96 { 111 }
97 throw new ArgumentNullException("workItem" , "workItem cannot be null"); 112 }
98 } 113
114 /// <summary>
115 /// Returns the current number of waiters
116 /// </summary>
117 public int WaitersCount
118 {
119 get
120 {
121 return _waitersCount;
122 }
123 }
99 124
100 bool enqueue = true;
101 125
102 // First check if there is a waiter waiting for work item. During 126 #endregion
103 // the check, timed out waiters are ignored. If there is no 127
104 // waiter then the work item is queued. 128 #region Public methods
105 lock(this) 129
106 { 130 /// <summary>
131 /// Enqueue a work item to the queue.
132 /// </summary>
133 public bool EnqueueWorkItem(WorkItem workItem)
134 {
135 // A work item cannot be null, since null is used in the
136 // WaitForWorkItem() method to indicate timeout or cancel
137 if (null == workItem)
138 {
139 throw new ArgumentNullException("workItem" , "workItem cannot be null");
140 }
141
142 bool enqueue = true;
143
144 // First check if there is a waiter waiting for work item. During
145 // the check, timed out waiters are ignored. If there is no
146 // waiter then the work item is queued.
147 lock(this)
148 {
107 ValidateNotDisposed(); 149 ValidateNotDisposed();
108 150
109 if (!_isWorkItemsQueueActive) 151 if (!_isWorkItemsQueueActive)
@@ -111,56 +153,55 @@ namespace Amib.Threading.Internal
111 return false; 153 return false;
112 } 154 }
113 155
114 while(_waitersCount > 0) 156 while(_waitersCount > 0)
115 { 157 {
116 // Dequeue a waiter. 158 // Dequeue a waiter.
117 WaiterEntry waiterEntry = PopWaiter(); 159 WaiterEntry waiterEntry = PopWaiter();
118 160
119 // Signal the waiter. On success break the loop 161 // Signal the waiter. On success break the loop
120 if (waiterEntry.Signal(workItem)) 162 if (waiterEntry.Signal(workItem))
121 { 163 {
122 enqueue = false; 164 enqueue = false;
123 break; 165 break;
124 } 166 }
125 } 167 }
126 168
127 if (enqueue) 169 if (enqueue)
128 { 170 {
129 // Enqueue the work item 171 // Enqueue the work item
130 _workItems.Enqueue(workItem); 172 _workItems.Enqueue(workItem);
131 } 173 }
132 } 174 }
133 return true; 175 return true;
134 } 176 }
135 177
136 178
137 /// <summary> 179 /// <summary>
138 /// Waits for a work item or exits on timeout or cancel 180 /// Waits for a work item or exits on timeout or cancel
139 /// </summary> 181 /// </summary>
140 /// <param name="millisecondsTimeout">Timeout in milliseconds</param> 182 /// <param name="millisecondsTimeout">Timeout in milliseconds</param>
141 /// <param name="cancelEvent">Cancel wait handle</param> 183 /// <param name="cancelEvent">Cancel wait handle</param>
142 /// <returns>Returns true if the resource was granted</returns> 184 /// <returns>Returns true if the resource was granted</returns>
143 public WorkItem DequeueWorkItem( 185 public WorkItem DequeueWorkItem(
144 int millisecondsTimeout, 186 int millisecondsTimeout,
145 WaitHandle cancelEvent) 187 WaitHandle cancelEvent)
146 { 188 {
147 /// This method cause the caller to wait for a work item. 189 // This method cause the caller to wait for a work item.
148 /// If there is at least one waiting work item then the 190 // If there is at least one waiting work item then the
149 /// method returns immidiately with true. 191 // method returns immidiately with it.
150 /// 192 //
151 /// If there are no waiting work items then the caller 193 // If there are no waiting work items then the caller
152 /// is queued between other waiters for a work item to arrive. 194 // is queued between other waiters for a work item to arrive.
153 /// 195 //
154 /// If a work item didn't come within millisecondsTimeout or 196 // If a work item didn't come within millisecondsTimeout or
155 /// the user canceled the wait by signaling the cancelEvent 197 // the user canceled the wait by signaling the cancelEvent
156 /// then the method returns false to indicate that the caller 198 // then the method returns null to indicate that the caller
157 /// didn't get a work item. 199 // didn't get a work item.
158 200
159 WaiterEntry waiterEntry = null; 201 WaiterEntry waiterEntry;
160 WorkItem workItem = null; 202 WorkItem workItem = null;
161 203 lock (this)
162 lock(this) 204 {
163 {
164 ValidateNotDisposed(); 205 ValidateNotDisposed();
165 206
166 // If there are waiting work items then take one and return. 207 // If there are waiting work items then take one and return.
@@ -169,80 +210,79 @@ namespace Amib.Threading.Internal
169 workItem = _workItems.Dequeue() as WorkItem; 210 workItem = _workItems.Dequeue() as WorkItem;
170 return workItem; 211 return workItem;
171 } 212 }
172 // No waiting work items ...
173 else
174 {
175 // Get the wait entry for the waiters queue
176 waiterEntry = GetThreadWaiterEntry();
177
178 // Put the waiter with the other waiters
179 PushWaiter(waiterEntry);
180 }
181 }
182
183 // Prepare array of wait handle for the WaitHandle.WaitAny()
184 WaitHandle [] waitHandles = new WaitHandle [] {
185 waiterEntry.WaitHandle,
186 cancelEvent };
187
188 // Wait for an available resource, cancel event, or timeout.
189 213
190 // During the wait we are supposes to exit the synchronization 214 // No waiting work items ...
191 // domain. (Placing true as the third argument of the WaitAny()) 215
192 // It just doesn't work, I don't know why, so I have lock(this) 216 // Get the waiter entry for the waiters queue
193 // statments insted of one. 217 waiterEntry = GetThreadWaiterEntry();
194 218
195 int index = WaitHandle.WaitAny( 219 // Put the waiter with the other waiters
196 waitHandles, 220 PushWaiter(waiterEntry);
197 millisecondsTimeout, 221 }
198 true); 222
199 223 // Prepare array of wait handle for the WaitHandle.WaitAny()
200 lock(this) 224 WaitHandle [] waitHandles = new WaitHandle[] {
201 { 225 waiterEntry.WaitHandle,
202 // success is true if it got a work item. 226 cancelEvent };
203 bool success = (0 == index); 227
204 228 // Wait for an available resource, cancel event, or timeout.
205 // The timeout variable is used only for readability. 229
206 // (We treat cancel as timeout) 230 // During the wait we are supposes to exit the synchronization
207 bool timeout = !success; 231 // domain. (Placing true as the third argument of the WaitAny())
208 232 // It just doesn't work, I don't know why, so I have two lock(this)
209 // On timeout update the waiterEntry that it is timed out 233 // statments instead of one.
210 if (timeout) 234
211 { 235 int index = STPEventWaitHandle.WaitAny(
212 // The Timeout() fails if the waiter has already been signaled 236 waitHandles,
213 timeout = waiterEntry.Timeout(); 237 millisecondsTimeout,
214 238 true);
215 // On timeout remove the waiter from the queue. 239
216 // Note that the complexity is O(1). 240 lock(this)
217 if(timeout) 241 {
218 { 242 // success is true if it got a work item.
219 RemoveWaiter(waiterEntry, false); 243 bool success = (0 == index);
220 } 244
221 245 // The timeout variable is used only for readability.
222 // Again readability 246 // (We treat cancel as timeout)
223 success = !timeout; 247 bool timeout = !success;
224 } 248
225 249 // On timeout update the waiterEntry that it is timed out
226 // On success return the work item 250 if (timeout)
227 if (success) 251 {
228 { 252 // The Timeout() fails if the waiter has already been signaled
229 workItem = waiterEntry.WorkItem; 253 timeout = waiterEntry.Timeout();
230 254
231 if (null == workItem) 255 // On timeout remove the waiter from the queue.
232 { 256 // Note that the complexity is O(1).
233 workItem = _workItems.Dequeue() as WorkItem; 257 if(timeout)
234 } 258 {
235 } 259 RemoveWaiter(waiterEntry, false);
236 } 260 }
237 // On failure return null. 261
238 return workItem; 262 // Again readability
239 } 263 success = !timeout;
264 }
265
266 // On success return the work item
267 if (success)
268 {
269 workItem = waiterEntry.WorkItem;
270
271 if (null == workItem)
272 {
273 workItem = _workItems.Dequeue() as WorkItem;
274 }
275 }
276 }
277 // On failure return null.
278 return workItem;
279 }
240 280
241 /// <summary> 281 /// <summary>
242 /// Cleanup the work items queue, hence no more work 282 /// Cleanup the work items queue, hence no more work
243 /// items are allowed to be queue 283 /// items are allowed to be queue
244 /// </summary> 284 /// </summary>
245 protected virtual void Cleanup() 285 private void Cleanup()
246 { 286 {
247 lock(this) 287 lock(this)
248 { 288 {
@@ -271,301 +311,312 @@ namespace Amib.Threading.Internal
271 // Tell the waiters that they were timed out. 311 // Tell the waiters that they were timed out.
272 // It won't signal them to exit, but to ignore their 312 // It won't signal them to exit, but to ignore their
273 // next work item. 313 // next work item.
274 while(_waitersCount > 0) 314 while(_waitersCount > 0)
275 { 315 {
276 WaiterEntry waiterEntry = PopWaiter(); 316 WaiterEntry waiterEntry = PopWaiter();
277 waiterEntry.Timeout(); 317 waiterEntry.Timeout();
278 } 318 }
279 } 319 }
280 } 320 }
281 321
282 #endregion 322 public object[] GetStates()
283
284 #region Private methods
285
286 /// <summary>
287 /// Returns the WaiterEntry of the current thread
288 /// </summary>
289 /// <returns></returns>
290 /// In order to avoid creation and destuction of WaiterEntry
291 /// objects each thread has its own WaiterEntry object.
292 private WaiterEntry GetThreadWaiterEntry()
293 { 323 {
294 if (null == _waiterEntry) 324 lock (this)
295 { 325 {
296 _waiterEntry = new WaiterEntry(); 326 object[] states = new object[_workItems.Count];
327 int i = 0;
328 foreach (WorkItem workItem in _workItems)
329 {
330 states[i] = workItem.GetWorkItemResult().State;
331 ++i;
332 }
333 return states;
297 } 334 }
298 _waiterEntry.Reset();
299 return _waiterEntry;
300 } 335 }
301 336
302 #region Waiters stack methods 337 #endregion
303 338
304 /// <summary> 339 #region Private methods
305 /// Push a new waiter into the waiter's stack 340
306 /// </summary> 341 /// <summary>
307 /// <param name="newWaiterEntry">A waiter to put in the stack</param> 342 /// Returns the WaiterEntry of the current thread
308 public void PushWaiter(WaiterEntry newWaiterEntry) 343 /// </summary>
309 { 344 /// <returns></returns>
310 // Remove the waiter if it is already in the stack and 345 /// In order to avoid creation and destuction of WaiterEntry
311 // update waiter's count as needed 346 /// objects each thread has its own WaiterEntry object.
312 RemoveWaiter(newWaiterEntry, false); 347 private static WaiterEntry GetThreadWaiterEntry()
313 348 {
314 // If the stack is empty then newWaiterEntry is the new head of the stack 349 if (null == CurrentWaiterEntry)
315 if (null == _headWaiterEntry._nextWaiterEntry) 350 {
316 { 351 CurrentWaiterEntry = new WaiterEntry();
317 _headWaiterEntry._nextWaiterEntry = newWaiterEntry; 352 }
318 newWaiterEntry._prevWaiterEntry = _headWaiterEntry; 353 CurrentWaiterEntry.Reset();
319 354 return CurrentWaiterEntry;
320 } 355 }
321 // If the stack is not empty then put newWaiterEntry as the new head 356
322 // of the stack. 357 #region Waiters stack methods
323 else 358
324 { 359 /// <summary>
325 // Save the old first waiter entry 360 /// Push a new waiter into the waiter's stack
326 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; 361 /// </summary>
362 /// <param name="newWaiterEntry">A waiter to put in the stack</param>
363 public void PushWaiter(WaiterEntry newWaiterEntry)
364 {
365 // Remove the waiter if it is already in the stack and
366 // update waiter's count as needed
367 RemoveWaiter(newWaiterEntry, false);
368
369 // If the stack is empty then newWaiterEntry is the new head of the stack
370 if (null == _headWaiterEntry._nextWaiterEntry)
371 {
372 _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
373 newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
374
375 }
376 // If the stack is not empty then put newWaiterEntry as the new head
377 // of the stack.
378 else
379 {
380 // Save the old first waiter entry
381 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
327 382
328 // Update the links 383 // Update the links
329 _headWaiterEntry._nextWaiterEntry = newWaiterEntry; 384 _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
330 newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; 385 newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
331 newWaiterEntry._prevWaiterEntry = _headWaiterEntry; 386 newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
332 oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; 387 oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
333 } 388 }
334 389
335 // Increment the number of waiters 390 // Increment the number of waiters
336 ++_waitersCount; 391 ++_waitersCount;
337 } 392 }
338 393
339 /// <summary> 394 /// <summary>
340 /// Pop a waiter from the waiter's stack 395 /// Pop a waiter from the waiter's stack
341 /// </summary> 396 /// </summary>
342 /// <returns>Returns the first waiter in the stack</returns> 397 /// <returns>Returns the first waiter in the stack</returns>
343 private WaiterEntry PopWaiter() 398 private WaiterEntry PopWaiter()
344 { 399 {
345 // Store the current stack head 400 // Store the current stack head
346 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; 401 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
347 402
348 // Store the new stack head 403 // Store the new stack head
349 WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; 404 WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
350 405
351 // Update the old stack head list links and decrement the number 406 // Update the old stack head list links and decrement the number
352 // waiters. 407 // waiters.
353 RemoveWaiter(oldFirstWaiterEntry, true); 408 RemoveWaiter(oldFirstWaiterEntry, true);
354 409
355 // Update the new stack head 410 // Update the new stack head
356 _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; 411 _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
357 if (null != newHeadWaiterEntry) 412 if (null != newHeadWaiterEntry)
358 { 413 {
359 newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; 414 newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
360 } 415 }
361 416
362 // Return the old stack head 417 // Return the old stack head
363 return oldFirstWaiterEntry; 418 return oldFirstWaiterEntry;
364 } 419 }
365 420
366 /// <summary> 421 /// <summary>
367 /// Remove a waiter from the stack 422 /// Remove a waiter from the stack
368 /// </summary> 423 /// </summary>
369 /// <param name="waiterEntry">A waiter entry to remove</param> 424 /// <param name="waiterEntry">A waiter entry to remove</param>
370 /// <param name="popDecrement">If true the waiter count is always decremented</param> 425 /// <param name="popDecrement">If true the waiter count is always decremented</param>
371 private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) 426 private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
372 { 427 {
373 // Store the prev entry in the list 428 // Store the prev entry in the list
374 WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; 429 WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
375 430
376 // Store the next entry in the list 431 // Store the next entry in the list
377 WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; 432 WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
378 433
379 // A flag to indicate if we need to decrement the waiters count. 434 // A flag to indicate if we need to decrement the waiters count.
380 // If we got here from PopWaiter then we must decrement. 435 // If we got here from PopWaiter then we must decrement.
381 // If we got here from PushWaiter then we decrement only if 436 // If we got here from PushWaiter then we decrement only if
382 // the waiter was already in the stack. 437 // the waiter was already in the stack.
383 bool decrementCounter = popDecrement; 438 bool decrementCounter = popDecrement;
384 439
385 // Null the waiter's entry links 440 // Null the waiter's entry links
386 waiterEntry._prevWaiterEntry = null; 441 waiterEntry._prevWaiterEntry = null;
387 waiterEntry._nextWaiterEntry = null; 442 waiterEntry._nextWaiterEntry = null;
388 443
389 // If the waiter entry had a prev link then update it. 444 // If the waiter entry had a prev link then update it.
390 // It also means that the waiter is already in the list and we 445 // It also means that the waiter is already in the list and we
391 // need to decrement the waiters count. 446 // need to decrement the waiters count.
392 if (null != prevWaiterEntry) 447 if (null != prevWaiterEntry)
393 { 448 {
394 prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; 449 prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
395 decrementCounter = true; 450 decrementCounter = true;
396 } 451 }
397 452
398 // If the waiter entry had a next link then update it. 453 // If the waiter entry had a next link then update it.
399 // It also means that the waiter is already in the list and we 454 // It also means that the waiter is already in the list and we
400 // need to decrement the waiters count. 455 // need to decrement the waiters count.
401 if (null != nextWaiterEntry) 456 if (null != nextWaiterEntry)
402 { 457 {
403 nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; 458 nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
404 decrementCounter = true; 459 decrementCounter = true;
405 } 460 }
406 461
407 // Decrement the waiters count if needed 462 // Decrement the waiters count if needed
408 if (decrementCounter) 463 if (decrementCounter)
409 { 464 {
410 --_waitersCount; 465 --_waitersCount;
411 } 466 }
412 } 467 }
413 468
414 #endregion 469 #endregion
415 470
416 #endregion 471 #endregion
417 472
418 #region WaiterEntry class 473 #region WaiterEntry class
419 474
420 // A waiter entry in the _waiters queue. 475 // A waiter entry in the _waiters queue.
421 public class WaiterEntry : IDisposable 476 public sealed class WaiterEntry : IDisposable
422 { 477 {
423 #region Member variables 478 #region Member variables
424 479
425 /// <summary> 480 /// <summary>
426 /// Event to signal the waiter that it got the work item. 481 /// Event to signal the waiter that it got the work item.
427 /// </summary> 482 /// </summary>
428 private AutoResetEvent _waitHandle = new AutoResetEvent(false); 483 //private AutoResetEvent _waitHandle = new AutoResetEvent(false);
429 484 private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
430 /// <summary> 485
431 /// Flag to know if this waiter already quited from the queue 486 /// <summary>
432 /// because of a timeout. 487 /// Flag to know if this waiter already quited from the queue
433 /// </summary> 488 /// because of a timeout.
434 private bool _isTimedout = false; 489 /// </summary>
435 490 private bool _isTimedout = false;
436 /// <summary> 491
437 /// Flag to know if the waiter was signaled and got a work item. 492 /// <summary>
438 /// </summary> 493 /// Flag to know if the waiter was signaled and got a work item.
439 private bool _isSignaled = false; 494 /// </summary>
495 private bool _isSignaled = false;
440 496
441 /// <summary> 497 /// <summary>
442 /// A work item that passed directly to the waiter withou going 498 /// A work item that passed directly to the waiter withou going
443 /// through the queue 499 /// through the queue
444 /// </summary> 500 /// </summary>
445 private WorkItem _workItem = null; 501 private WorkItem _workItem = null;
446 502
447 private bool _isDisposed = false; 503 private bool _isDisposed = false;
448 504
449 // Linked list members 505 // Linked list members
450 internal WaiterEntry _nextWaiterEntry = null; 506 internal WaiterEntry _nextWaiterEntry = null;
451 internal WaiterEntry _prevWaiterEntry = null; 507 internal WaiterEntry _prevWaiterEntry = null;
452 508
453 #endregion 509 #endregion
454 510
455 #region Construction 511 #region Construction
456 512
457 public WaiterEntry() 513 public WaiterEntry()
458 { 514 {
459 Reset(); 515 Reset();
460 } 516 }
461 517
462 #endregion 518 #endregion
463 519
464 #region Public methods 520 #region Public methods
465 521
466 public WaitHandle WaitHandle 522 public WaitHandle WaitHandle
467 { 523 {
468 get { return _waitHandle; } 524 get { return _waitHandle; }
469 } 525 }
470 526
471 public WorkItem WorkItem 527 public WorkItem WorkItem
472 { 528 {
473 get 529 get
474 { 530 {
475 lock(this) 531 return _workItem;
476 { 532 }
477 return _workItem; 533 }
478 } 534
479 } 535 /// <summary>
480 } 536 /// Signal the waiter that it got a work item.
481 537 /// </summary>
482 /// <summary> 538 /// <returns>Return true on success</returns>
483 /// Signal the waiter that it got a work item. 539 /// The method fails if Timeout() preceded its call
484 /// </summary> 540 public bool Signal(WorkItem workItem)
485 /// <returns>Return true on success</returns> 541 {
486 /// The method fails if Timeout() preceded its call 542 lock(this)
487 public bool Signal(WorkItem workItem) 543 {
488 { 544 if (!_isTimedout)
489 lock(this) 545 {
490 { 546 _workItem = workItem;
491 if (!_isTimedout) 547 _isSignaled = true;
492 { 548 _waitHandle.Set();
493 _workItem = workItem; 549 return true;
494 _isSignaled = true; 550 }
495 _waitHandle.Set(); 551 }
496 return true; 552 return false;
497 } 553 }
498 } 554
499 return false; 555 /// <summary>
500 } 556 /// Mark the wait entry that it has been timed out
501 557 /// </summary>
502 /// <summary> 558 /// <returns>Return true on success</returns>
503 /// Mark the wait entry that it has been timed out 559 /// The method fails if Signal() preceded its call
504 /// </summary> 560 public bool Timeout()
505 /// <returns>Return true on success</returns> 561 {
506 /// The method fails if Signal() preceded its call 562 lock(this)
507 public bool Timeout() 563 {
508 { 564 // Time out can happen only if the waiter wasn't marked as
509 lock(this) 565 // signaled
566 if (!_isSignaled)
567 {
568 // We don't remove the waiter from the queue, the DequeueWorkItem
569 // method skips _waiters that were timed out.
570 _isTimedout = true;
571 return true;
572 }
573 }
574 return false;
575 }
576
577 /// <summary>
578 /// Reset the wait entry so it can be used again
579 /// </summary>
580 public void Reset()
581 {
582 _workItem = null;
583 _isTimedout = false;
584 _isSignaled = false;
585 _waitHandle.Reset();
586 }
587
588 /// <summary>
589 /// Free resources
590 /// </summary>
591 public void Close()
592 {
593 if (null != _waitHandle)
594 {
595 _waitHandle.Close();
596 _waitHandle = null;
597 }
598 }
599
600 #endregion
601
602 #region IDisposable Members
603
604 public void Dispose()
605 {
606 lock (this)
510 { 607 {
511 // Time out can happen only if the waiter wasn't marked as 608 if (!_isDisposed)
512 // signaled
513 if (!_isSignaled)
514 { 609 {
515 // We don't remove the waiter from the queue, the DequeueWorkItem 610 Close();
516 // method skips _waiters that were timed out.
517 _isTimedout = true;
518 return true;
519 } 611 }
520 }
521 return false;
522 }
523
524 /// <summary>
525 /// Reset the wait entry so it can be used again
526 /// </summary>
527 public void Reset()
528 {
529 _workItem = null;
530 _isTimedout = false;
531 _isSignaled = false;
532 _waitHandle.Reset();
533 }
534
535 /// <summary>
536 /// Free resources
537 /// </summary>
538 public void Close()
539 {
540 if (null != _waitHandle)
541 {
542 _waitHandle.Close();
543 _waitHandle = null;
544 }
545 }
546
547 #endregion
548
549 #region IDisposable Members
550
551 public void Dispose()
552 {
553 if (!_isDisposed)
554 {
555 Close();
556 _isDisposed = true; 612 _isDisposed = true;
557 } 613 }
558 } 614 }
559 615
560 ~WaiterEntry() 616 #endregion
561 { 617 }
562 Dispose();
563 }
564 618
565 #endregion 619 #endregion
566 }
567
568 #endregion
569 620
570 #region IDisposable Members 621 #region IDisposable Members
571 622
@@ -574,14 +625,8 @@ namespace Amib.Threading.Internal
574 if (!_isDisposed) 625 if (!_isDisposed)
575 { 626 {
576 Cleanup(); 627 Cleanup();
577 _isDisposed = true;
578 GC.SuppressFinalize(this);
579 } 628 }
580 } 629 _isDisposed = true;
581
582 ~WorkItemsQueue()
583 {
584 Cleanup();
585 } 630 }
586 631
587 private void ValidateNotDisposed() 632 private void ValidateNotDisposed()
@@ -595,6 +640,6 @@ namespace Amib.Threading.Internal
595 #endregion 640 #endregion
596 } 641 }
597 642
598 #endregion 643 #endregion
599} 644}
600 645
diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example
index 581c31d..fee2a87 100644
--- a/bin/Robust.HG.ini.example
+++ b/bin/Robust.HG.ini.example
@@ -21,18 +21,21 @@
21; * [[<ConfigName>@]<port>/]<dll name>[:<class name>] 21; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
22; * 22; *
23[Startup] 23[Startup]
24 24 ; Place to create a PID file
25 ; Plugin Registry Location 25 ; If no path if specified then a PID file is not created.
26 ; Set path to directory for plugin registry. Information 26 ; PIDFile = "/tmp/my.pid"
27 ; about the registered repositories and installed plugins 27
28 ; will be stored here 28 ; Plugin Registry Location
29 ; The Robust.exe process must have R/W access to the location 29 ; Set path to directory for plugin registry. Information
30 RegistryLocation = "." 30 ; about the registered repositories and installed plugins
31 31 ; will be stored here
32 ; Modular configurations 32 ; The Robust.exe process must have R/W access to the location
33 ; Set path to directory for modular ini files... 33 RegistryLocation = "."
34 ; The Robust.exe process must have R/W access to the location 34
35 ConfigDirectory = "/home/opensim/etc/Configs" 35 ; Modular configurations
36 ; Set path to directory for modular ini files...
37 ; The Robust.exe process must have R/W access to the location
38 ConfigDirectory = "."
36 39
37[ServiceList] 40[ServiceList]
38 41
diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example
index b98132e..2d5aa8c 100644
--- a/bin/Robust.ini.example
+++ b/bin/Robust.ini.example
@@ -13,19 +13,21 @@
13; * [[<ConfigName>@]<port>/]<dll name>[:<class name>] 13; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
14; * 14; *
15[Startup] 15[Startup]
16 16 ; Place to create a PID file
17 ; Plugin Registry Location 17 ; If no path if specified then a PID file is not created.
18 ; Set path to directory for plugin registry. Information 18 ; PIDFile = "/tmp/my.pid"
19 ; about the registered repositories and installed plugins 19
20 ; will be stored here 20 ; Plugin Registry Location
21 ; The Robust.exe process must have R/W access to the location 21 ; Set path to directory for plugin registry. Information
22 RegistryLocation = "." 22 ; about the registered repositories and installed plugins
23 23 ; will be stored here
24 24 ; The Robust.exe process must have R/W access to the location
25 ; Modular configurations 25 RegistryLocation = "."
26 ; Set path to directory for modular ini files... 26
27 ; The Robust.exe process must have R/W access to the location 27 ; Modular configurations
28 ConfigDirectory = "/home/opensim/etc/Configs" 28 ; Set path to directory for modular ini files...
29 ; The Robust.exe process must have R/W access to the location
30 ConfigDirectory = "."
29 31
30[ServiceList] 32[ServiceList]
31AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector" 33AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
diff --git a/prebuild.xml b/prebuild.xml
index 29d7c90..9fbe08b 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -3055,6 +3055,7 @@
3055 <Match path="Avatar/AvatarFactory/Tests" pattern="*.cs" recurse="true"/> 3055 <Match path="Avatar/AvatarFactory/Tests" pattern="*.cs" recurse="true"/>
3056 <Match path="Avatar/Friends/Tests" pattern="*.cs" recurse="true"/> 3056 <Match path="Avatar/Friends/Tests" pattern="*.cs" recurse="true"/>
3057 <Match path="Avatar/Inventory/Archiver/Tests" pattern="*.cs" recurse="true"/> 3057 <Match path="Avatar/Inventory/Archiver/Tests" pattern="*.cs" recurse="true"/>
3058 <Match path="Avatar/Inventory/Transfer/Tests" pattern="*.cs" recurse="true"/>
3058 <Match path="Framework/InventoryAccess/Tests" pattern="*.cs" recurse="true"/> 3059 <Match path="Framework/InventoryAccess/Tests" pattern="*.cs" recurse="true"/>
3059 <Match path="Scripting/VectorRender/Tests" pattern="*.cs" recurse="true"/> 3060 <Match path="Scripting/VectorRender/Tests" pattern="*.cs" recurse="true"/>
3060 <Match path="World/Archiver/Tests" pattern="*.cs" recurse="true"/> 3061 <Match path="World/Archiver/Tests" pattern="*.cs" recurse="true"/>