aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2011-09-12 21:57:22 +0100
committerJustin Clark-Casey (justincc)2011-09-12 21:57:22 +0100
commitea0f78c97152d3aa54822487e5343ca2db0b47b9 (patch)
tree1496c7d6ebbed346209f1513f2affa3f1ba6f62a
parentlock AvatarAppearance.m_attachments when we use it (diff)
downloadopensim-SC-ea0f78c97152d3aa54822487e5343ca2db0b47b9.zip
opensim-SC-ea0f78c97152d3aa54822487e5343ca2db0b47b9.tar.gz
opensim-SC-ea0f78c97152d3aa54822487e5343ca2db0b47b9.tar.bz2
opensim-SC-ea0f78c97152d3aa54822487e5343ca2db0b47b9.tar.xz
Start locking entire add/remove operations on an IScenePresence.AttachmentsSyncLock object
Attach and detach packets are processed asynchronously when received from a viewer. Bugs like http://opensimulator.org/mantis/view.php?id=5644 indicate that in some situations (such as attaching/detaching entire folders of objects at once), there are race conditions between these threads. Since multiple data structures need to be updated on attach/detach, it's not enough to lock the individual collections. Therefore, this commit introduces a new IScenePresence.AttachmentsSyncLock which add/remove operations lock on.
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs382
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs9
-rw-r--r--OpenSim/Region/Framework/Interfaces/IScenePresence.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs4
4 files changed, 228 insertions, 175 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 996e2ab..2fa233b 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -240,80 +240,83 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
240 240
241 private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) 241 private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent)
242 { 242 {
243// m_log.DebugFormat( 243 lock (sp.AttachmentsSyncLock)
244// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
245// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
246
247 if (sp.GetAttachments(attachmentPt).Contains(group))
248 {
249// m_log.WarnFormat(
250// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
251// group.Name, group.LocalId, sp.Name, AttachmentPt);
252
253 return false;
254 }
255
256 Vector3 attachPos = group.AbsolutePosition;
257
258 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
259 // be removed when that functionality is implemented in opensim
260 attachmentPt &= 0x7f;
261
262 // If the attachment point isn't the same as the one previously used
263 // set it's offset position = 0 so that it appears on the attachment point
264 // and not in a weird location somewhere unknown.
265 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint)
266 {
267 attachPos = Vector3.Zero;
268 }
269
270 // AttachmentPt 0 means the client chose to 'wear' the attachment.
271 if (attachmentPt == 0)
272 {
273 // Check object for stored attachment point
274 attachmentPt = group.AttachmentPoint;
275 }
276
277 // if we still didn't find a suitable attachment point.......
278 if (attachmentPt == 0)
279 { 244 {
280 // Stick it on left hand with Zero Offset from the attachment point. 245 // m_log.DebugFormat(
281 attachmentPt = (uint)AttachmentPoint.LeftHand; 246 // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
282 attachPos = Vector3.Zero; 247 // group.Name, group.LocalId, sp.Name, attachmentPt, silent);
283 } 248
284 249 if (sp.GetAttachments(attachmentPt).Contains(group))
285 group.AttachmentPoint = attachmentPt;
286 group.AbsolutePosition = attachPos;
287
288 // We also don't want to do any of the inventory operations for an NPC.
289 if (sp.PresenceType != PresenceType.Npc)
290 {
291 // Remove any previous attachments
292 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
293
294 // At the moment we can only deal with a single attachment
295 if (attachments.Count != 0)
296 { 250 {
297 UUID oldAttachmentItemID = attachments[0].GetFromItemID(); 251 // m_log.WarnFormat(
252 // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
253 // group.Name, group.LocalId, sp.Name, AttachmentPt);
298 254
299 if (oldAttachmentItemID != UUID.Zero) 255 return false;
300 DetachSingleAttachmentToInv(oldAttachmentItemID, sp);
301 else
302 m_log.WarnFormat(
303 "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
304 attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
305 } 256 }
306
307 // Add the new attachment to inventory if we don't already have it.
308 UUID newAttachmentItemID = group.GetFromItemID();
309 if (newAttachmentItemID == UUID.Zero)
310 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID;
311 257
312 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); 258 Vector3 attachPos = group.AbsolutePosition;
259
260 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
261 // be removed when that functionality is implemented in opensim
262 attachmentPt &= 0x7f;
263
264 // If the attachment point isn't the same as the one previously used
265 // set it's offset position = 0 so that it appears on the attachment point
266 // and not in a weird location somewhere unknown.
267 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint)
268 {
269 attachPos = Vector3.Zero;
270 }
271
272 // AttachmentPt 0 means the client chose to 'wear' the attachment.
273 if (attachmentPt == 0)
274 {
275 // Check object for stored attachment point
276 attachmentPt = group.AttachmentPoint;
277 }
278
279 // if we still didn't find a suitable attachment point.......
280 if (attachmentPt == 0)
281 {
282 // Stick it on left hand with Zero Offset from the attachment point.
283 attachmentPt = (uint)AttachmentPoint.LeftHand;
284 attachPos = Vector3.Zero;
285 }
286
287 group.AttachmentPoint = attachmentPt;
288 group.AbsolutePosition = attachPos;
289
290 // We also don't want to do any of the inventory operations for an NPC.
291 if (sp.PresenceType != PresenceType.Npc)
292 {
293 // Remove any previous attachments
294 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
295
296 // At the moment we can only deal with a single attachment
297 if (attachments.Count != 0)
298 {
299 UUID oldAttachmentItemID = attachments[0].GetFromItemID();
300
301 if (oldAttachmentItemID != UUID.Zero)
302 DetachSingleAttachmentToInv(oldAttachmentItemID, sp);
303 else
304 m_log.WarnFormat(
305 "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
306 attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
307 }
308
309 // Add the new attachment to inventory if we don't already have it.
310 UUID newAttachmentItemID = group.GetFromItemID();
311 if (newAttachmentItemID == UUID.Zero)
312 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID;
313
314 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
315 }
316
317 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
313 } 318 }
314 319
315 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
316
317 return true; 320 return true;
318 } 321 }
319 322
@@ -322,14 +325,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
322 RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, 325 RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header,
323 RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) 326 RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects)
324 { 327 {
325 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) 328 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
329
330 if (sp == null)
326 { 331 {
327 RezSingleAttachmentFromInventory(remoteClient, obj.ItemID, obj.AttachmentPt); 332 m_log.ErrorFormat(
333 "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()",
334 remoteClient.Name, remoteClient.AgentId);
335 return;
336 }
337
338 lock (sp.AttachmentsSyncLock)
339 {
340 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects)
341 {
342 RezSingleAttachmentFromInventory(sp, obj.ItemID, obj.AttachmentPt);
343 }
328 } 344 }
329 } 345 }
330 346
331 public ISceneEntity RezSingleAttachmentFromInventory( 347 public ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
332 IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
333 { 348 {
334// m_log.DebugFormat( 349// m_log.DebugFormat(
335// "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", 350// "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}",
@@ -344,7 +359,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
344 remoteClient.Name, remoteClient.AgentId); 359 remoteClient.Name, remoteClient.AgentId);
345 return null; 360 return null;
346 } 361 }
347 362
363 return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt);
364 }
365
366 public ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt)
367 {
348 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 368 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
349 // be removed when that functionality is implemented in opensim 369 // be removed when that functionality is implemented in opensim
350 AttachmentPt &= 0x7f; 370 AttachmentPt &= 0x7f;
@@ -363,65 +383,68 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
363 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 383 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
364 if (invAccess != null) 384 if (invAccess != null)
365 { 385 {
366 SceneObjectGroup objatt; 386 lock (sp.AttachmentsSyncLock)
367
368 if (itemID != UUID.Zero)
369 objatt = invAccess.RezObject(sp.ControllingClient,
370 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
371 false, false, sp.UUID, true);
372 else
373 objatt = invAccess.RezObject(sp.ControllingClient,
374 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
375 false, false, sp.UUID, true);
376
377// m_log.DebugFormat(
378// "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
379// objatt.Name, remoteClient.Name, AttachmentPt);
380
381 if (objatt != null)
382 { 387 {
383 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. 388 SceneObjectGroup objatt;
384 objatt.HasGroupChanged = false; 389
385 bool tainted = false; 390 if (itemID != UUID.Zero)
386 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) 391 objatt = invAccess.RezObject(sp.ControllingClient,
387 tainted = true; 392 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
388 393 false, false, sp.UUID, true);
389 // This will throw if the attachment fails 394 else
390 try 395 objatt = invAccess.RezObject(sp.ControllingClient,
396 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
397 false, false, sp.UUID, true);
398
399 // m_log.DebugFormat(
400 // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
401 // objatt.Name, remoteClient.Name, AttachmentPt);
402
403 if (objatt != null)
391 { 404 {
392 AttachObject(sp, objatt, attachmentPt, false); 405 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
406 objatt.HasGroupChanged = false;
407 bool tainted = false;
408 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
409 tainted = true;
410
411 // This will throw if the attachment fails
412 try
413 {
414 AttachObject(sp, objatt, attachmentPt, false);
415 }
416 catch (Exception e)
417 {
418 m_log.ErrorFormat(
419 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
420 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
421
422 // Make sure the object doesn't stick around and bail
423 sp.RemoveAttachment(objatt);
424 m_scene.DeleteSceneObject(objatt, false);
425 return null;
426 }
427
428 if (tainted)
429 objatt.HasGroupChanged = true;
430
431 // Fire after attach, so we don't get messy perms dialogs
432 // 4 == AttachedRez
433 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
434 objatt.ResumeScripts();
435
436 // Do this last so that event listeners have access to all the effects of the attachment
437 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
438
439 return objatt;
393 } 440 }
394 catch (Exception e) 441 else
395 { 442 {
396 m_log.ErrorFormat( 443 m_log.WarnFormat(
397 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", 444 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
398 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); 445 itemID, sp.Name, attachmentPt);
399
400 // Make sure the object doesn't stick around and bail
401 sp.RemoveAttachment(objatt);
402 m_scene.DeleteSceneObject(objatt, false);
403 return null;
404 } 446 }
405
406 if (tainted)
407 objatt.HasGroupChanged = true;
408
409 // Fire after attach, so we don't get messy perms dialogs
410 // 4 == AttachedRez
411 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
412 objatt.ResumeScripts();
413
414 // Do this last so that event listeners have access to all the effects of the attachment
415 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
416 } 447 }
417 else
418 {
419 m_log.WarnFormat(
420 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
421 itemID, sp.Name, attachmentPt);
422 }
423
424 return objatt;
425 } 448 }
426 449
427 return null; 450 return null;
@@ -474,14 +497,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
474 ScenePresence presence; 497 ScenePresence presence;
475 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 498 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
476 { 499 {
477 // Save avatar attachment information 500 lock (presence.AttachmentsSyncLock)
478 m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); 501 {
479 502 // Save avatar attachment information
480 bool changed = presence.Appearance.DetachAttachment(itemID); 503 m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID);
481 if (changed && m_scene.AvatarFactory != null)
482 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
483 504
484 DetachSingleAttachmentToInv(itemID, presence); 505 bool changed = presence.Appearance.DetachAttachment(itemID);
506 if (changed && m_scene.AvatarFactory != null)
507 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
508
509 DetachSingleAttachmentToInv(itemID, presence);
510 }
485 } 511 }
486 } 512 }
487 513
@@ -508,24 +534,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
508 ScenePresence presence; 534 ScenePresence presence;
509 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 535 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
510 { 536 {
511 if (!m_scene.Permissions.CanRezObject( 537 lock (presence.AttachmentsSyncLock)
512 so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) 538 {
513 return; 539 if (!m_scene.Permissions.CanRezObject(
540 so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition))
541 return;
514 542
515 bool changed = presence.Appearance.DetachAttachment(inventoryID); 543 bool changed = presence.Appearance.DetachAttachment(inventoryID);
516 if (changed && m_scene.AvatarFactory != null) 544 if (changed && m_scene.AvatarFactory != null)
517 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); 545 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
518 546
519 presence.RemoveAttachment(so); 547 presence.RemoveAttachment(so);
520 DetachSceneObjectToGround(so, presence); 548 DetachSceneObjectToGround(so, presence);
521 549
522 List<UUID> uuids = new List<UUID>(); 550 List<UUID> uuids = new List<UUID>();
523 uuids.Add(inventoryID); 551 uuids.Add(inventoryID);
524 m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids); 552 m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids);
525 remoteClient.SendRemoveInventoryItem(inventoryID); 553 remoteClient.SendRemoveInventoryItem(inventoryID);
526 } 554 }
527 555
528 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); 556 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero);
557 }
529 } 558 }
530 559
531 /// <summary> 560 /// <summary>
@@ -567,37 +596,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
567 EntityBase[] detachEntities = m_scene.GetEntities(); 596 EntityBase[] detachEntities = m_scene.GetEntities();
568 SceneObjectGroup group; 597 SceneObjectGroup group;
569 598
570 foreach (EntityBase entity in detachEntities) 599 lock (sp.AttachmentsSyncLock)
571 { 600 {
572 if (entity is SceneObjectGroup) 601 foreach (EntityBase entity in detachEntities)
573 { 602 {
574 group = (SceneObjectGroup)entity; 603 if (entity is SceneObjectGroup)
575 if (group.GetFromItemID() == itemID)
576 { 604 {
577 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); 605 group = (SceneObjectGroup)entity;
578 sp.RemoveAttachment(group); 606 if (group.GetFromItemID() == itemID)
579 607 {
580 // Prepare sog for storage 608 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
581 group.AttachedAvatar = UUID.Zero; 609 sp.RemoveAttachment(group);
582 610
583 group.ForEachPart( 611 // Prepare sog for storage
584 delegate(SceneObjectPart part) 612 group.AttachedAvatar = UUID.Zero;
585 { 613
586 // If there are any scripts, 614 group.ForEachPart(
587 // then always trigger a new object and state persistence in UpdateKnownItem() 615 delegate(SceneObjectPart part)
588 if (part.Inventory.ContainsScripts()) 616 {
589 group.HasGroupChanged = true; 617 // If there are any scripts,
590 } 618 // then always trigger a new object and state persistence in UpdateKnownItem()
591 ); 619 if (part.Inventory.ContainsScripts())
592 620 group.HasGroupChanged = true;
593 group.RootPart.SetParentLocalId(0); 621 }
594 group.IsAttachment = false; 622 );
595 group.AbsolutePosition = group.RootPart.AttachedPos; 623
596 624 group.RootPart.SetParentLocalId(0);
597 UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID); 625 group.IsAttachment = false;
598 m_scene.DeleteSceneObject(group, false); 626 group.AbsolutePosition = group.RootPart.AttachedPos;
599 627
600 return; 628 UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID);
629 m_scene.DeleteSceneObject(group, false);
630
631 return;
632 }
601 } 633 }
602 } 634 }
603 } 635 }
@@ -829,4 +861,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
829 return item; 861 return item;
830 } 862 }
831 } 863 }
832} 864} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index 73d15a5..e6ac6b5 100644
--- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
@@ -88,6 +88,15 @@ namespace OpenSim.Region.Framework.Interfaces
88 ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); 88 ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt);
89 89
90 /// <summary> 90 /// <summary>
91 /// Rez an attachment from user inventory and change inventory status to match.
92 /// </summary>
93 /// <param name="sp"></param>
94 /// <param name="itemID"></param>
95 /// <param name="AttachmentPt"></param>
96 /// <returns>The scene object that was attached. Null if the scene object could not be found</returns>
97 ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt);
98
99 /// <summary>
91 /// Rez multiple attachments from a user's inventory 100 /// Rez multiple attachments from a user's inventory
92 /// </summary> 101 /// </summary>
93 /// <param name="remoteClient"></param> 102 /// <param name="remoteClient"></param>
diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
index 8913133..95688ab 100644
--- a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
@@ -61,6 +61,14 @@ namespace OpenSim.Region.Framework.Interfaces
61 AvatarAppearance Appearance { get; set; } 61 AvatarAppearance Appearance { get; set; }
62 62
63 /// <summary> 63 /// <summary>
64 /// The AttachmentsModule synchronizes on this to avoid race conditions between commands to add and remove attachments.
65 /// </summary>
66 /// <remarks>
67 /// All add and remove attachment operations must synchronize on this for the lifetime of their operations.
68 /// </remarks>
69 Object AttachmentsSyncLock { get; }
70
71 /// <summary>
64 /// The scene objects attached to this avatar. 72 /// The scene objects attached to this avatar.
65 /// </summary> 73 /// </summary>
66 /// <returns> 74 /// <returns>
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index d65d78d..86e1e11 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -120,6 +120,8 @@ namespace OpenSim.Region.Framework.Scenes
120 /// </remarks> 120 /// </remarks>
121 protected List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>(); 121 protected List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>();
122 122
123 public Object AttachmentsSyncLock { get; private set; }
124
123 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>(); 125 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>();
124 private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO; 126 private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO;
125 private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO; 127 private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO;
@@ -709,6 +711,8 @@ namespace OpenSim.Region.Framework.Scenes
709 public ScenePresence( 711 public ScenePresence(
710 IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance, PresenceType type) 712 IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance, PresenceType type)
711 { 713 {
714 AttachmentsSyncLock = new Object();
715
712 m_sendCourseLocationsMethod = SendCoarseLocationsDefault; 716 m_sendCourseLocationsMethod = SendCoarseLocationsDefault;
713 m_sceneViewer = new SceneViewer(this); 717 m_sceneViewer = new SceneViewer(this);
714 m_animator = new ScenePresenceAnimator(this); 718 m_animator = new ScenePresenceAnimator(this);