aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules
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 /OpenSim/Region/CoreModules
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.
Diffstat (limited to 'OpenSim/Region/CoreModules')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs382
1 files changed, 207 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