1 /*
2  * safecoll.cxx
3  *
4  * Thread safe collection classes.
5  *
6  * Portable Windows Library
7  *
8  * Copyright (c) 2002 Equivalence Pty. Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Contributor(s): ______________________________________.
25  *
26  * $Revision: 27948 $
27  * $Author: rjongbloed $
28  * $Date: 2012-06-30 22:54:23 -0500 (Sat, 30 Jun 2012) $
29  */
30 
31 #ifdef __GNUC__
32 #pragma implementation "safecoll.h"
33 #endif
34 
35 #include <ptlib.h>
36 #include <ptlib/safecoll.h>
37 
38 
39 #define new PNEW
40 
41 
42 /////////////////////////////////////////////////////////////////////////////
43 
PSafeObject(PSafeObject * indirectLock)44 PSafeObject::PSafeObject(PSafeObject * indirectLock)
45   : safeReferenceCount(0)
46   , safelyBeingRemoved(PFalse)
47   , safeInUse(indirectLock != NULL ? indirectLock->safeInUse : &safeInUseMutex)
48 {
49 }
50 
51 
SafeReference()52 PBoolean PSafeObject::SafeReference()
53 {
54 #if PTRACING
55   unsigned tracedReferenceCount;
56 #endif
57 
58   {
59     PWaitAndSignal mutex(safetyMutex);
60     if (safelyBeingRemoved)
61       return PFalse;
62     safeReferenceCount++;
63 #if PTRACING
64     tracedReferenceCount = safeReferenceCount;
65 #endif
66   }
67 
68   PTRACE(7, "SafeColl\tIncrement reference count to " << tracedReferenceCount << " for " << GetClass() << ' ' << (void *)this);
69   return PTrue;
70 }
71 
72 
SafeDereference()73 PBoolean PSafeObject::SafeDereference()
74 {
75   PBoolean mayBeDeleted = PFalse;
76 #if PTRACING
77   unsigned tracedReferenceCount;
78 #endif
79 
80   safetyMutex.Wait();
81   if (PAssert(safeReferenceCount > 0, PLogicError)) {
82     safeReferenceCount--;
83     mayBeDeleted = safeReferenceCount == 0 && !safelyBeingRemoved;
84   }
85 #if PTRACING
86   tracedReferenceCount = safeReferenceCount;
87 #endif
88   safetyMutex.Signal();
89 
90   PTRACE(7, "SafeColl\tDecrement reference count to " << tracedReferenceCount << " for " << GetClass() << ' ' << (void *)this);
91 
92   return mayBeDeleted;
93 }
94 
95 
LockReadOnly() const96 PBoolean PSafeObject::LockReadOnly() const
97 {
98   PTRACE(7, "SafeColl\tWaiting read ("<<(void *)this<<")");
99   safetyMutex.Wait();
100 
101   if (safelyBeingRemoved) {
102     safetyMutex.Signal();
103     PTRACE(6, "SafeColl\tBeing removed while waiting read ("<<(void *)this<<")");
104     return PFalse;
105   }
106 
107   safetyMutex.Signal();
108   safeInUse->StartRead();
109   PTRACE(6, "SafeColl\tLocked read ("<<(void *)this<<")");
110   return PTrue;
111 }
112 
113 
UnlockReadOnly() const114 void PSafeObject::UnlockReadOnly() const
115 {
116   PTRACE(6, "SafeColl\tUnlocked read ("<<(void *)this<<")");
117   safeInUse->EndRead();
118 }
119 
120 
LockReadWrite()121 PBoolean PSafeObject::LockReadWrite()
122 {
123   PTRACE(7, "SafeColl\tWaiting readWrite ("<<(void *)this<<")");
124   safetyMutex.Wait();
125 
126   if (safelyBeingRemoved) {
127     safetyMutex.Signal();
128     PTRACE(6, "SafeColl\tBeing removed while waiting readWrite ("<<(void *)this<<")");
129     return PFalse;
130   }
131 
132   safetyMutex.Signal();
133   safeInUse->StartWrite();
134   PTRACE(6, "SafeColl\tLocked readWrite ("<<(void *)this<<")");
135   return PTrue;
136 }
137 
138 
UnlockReadWrite()139 void PSafeObject::UnlockReadWrite()
140 {
141   PTRACE(6, "SafeColl\tUnlocked readWrite ("<<(void *)this<<")");
142   safeInUse->EndWrite();
143 }
144 
145 
SafeRemove()146 void PSafeObject::SafeRemove()
147 {
148   safetyMutex.Wait();
149   safelyBeingRemoved = PTrue;
150   safetyMutex.Signal();
151 }
152 
153 
SafelyCanBeDeleted() const154 PBoolean PSafeObject::SafelyCanBeDeleted() const
155 {
156   PWaitAndSignal mutex(safetyMutex);
157   return safelyBeingRemoved && safeReferenceCount == 0;
158 }
159 
160 
GarbageCollection()161 bool PSafeObject::GarbageCollection()
162 {
163   return true;
164 }
165 
166 
167 /////////////////////////////////////////////////////////////////////////////
168 
PSafeLockReadOnly(const PSafeObject & object)169 PSafeLockReadOnly::PSafeLockReadOnly(const PSafeObject & object)
170   : safeObject((PSafeObject &)object)
171 {
172   locked = safeObject.LockReadOnly();
173 }
174 
175 
~PSafeLockReadOnly()176 PSafeLockReadOnly::~PSafeLockReadOnly()
177 {
178   if (locked)
179     safeObject.UnlockReadOnly();
180 }
181 
182 
Lock()183 PBoolean PSafeLockReadOnly::Lock()
184 {
185   locked = safeObject.LockReadOnly();
186   return locked;
187 }
188 
189 
Unlock()190 void PSafeLockReadOnly::Unlock()
191 {
192   if (locked) {
193     safeObject.UnlockReadOnly();
194     locked = PFalse;
195   }
196 }
197 
198 
199 
200 /////////////////////////////////////////////////////////////////////////////
201 
PSafeLockReadWrite(const PSafeObject & object)202 PSafeLockReadWrite::PSafeLockReadWrite(const PSafeObject & object)
203   : safeObject((PSafeObject &)object)
204 {
205   locked = safeObject.LockReadWrite();
206 }
207 
208 
~PSafeLockReadWrite()209 PSafeLockReadWrite::~PSafeLockReadWrite()
210 {
211   if (locked)
212     safeObject.UnlockReadWrite();
213 }
214 
215 
Lock()216 PBoolean PSafeLockReadWrite::Lock()
217 {
218   locked = safeObject.LockReadWrite();
219   return locked;
220 }
221 
222 
Unlock()223 void PSafeLockReadWrite::Unlock()
224 {
225   if (locked) {
226     safeObject.UnlockReadWrite();
227     locked = PFalse;
228   }
229 }
230 
231 
232 /////////////////////////////////////////////////////////////////////////////
233 
PSafeCollection(PCollection * coll)234 PSafeCollection::PSafeCollection(PCollection * coll)
235 {
236   collection = coll;
237   collection->DisallowDeleteObjects();
238   toBeRemoved.DisallowDeleteObjects();
239   deleteObjects = PTrue;
240 }
241 
242 
~PSafeCollection()243 PSafeCollection::~PSafeCollection()
244 {
245   deleteObjectsTimer.Stop();
246 
247   RemoveAll();
248 
249   /* Delete objects moved to deleted list in RemoveAll(), we don't use
250      DeleteObjectsToBeRemoved() as that will do a garbage collection which might
251      prevent deletion. Need to be a bit more forceful here. */
252   for (PList<PSafeObject>::iterator i = toBeRemoved.begin(); i != toBeRemoved.end(); ++i) {
253     i->GarbageCollection();
254     if (i->SafelyCanBeDeleted())
255       delete &*i;
256     else {
257       // If anything still has a PSafePtr .. "detach" it from the collection so
258       // will be deleted whan that PSafePtr finally goes out of scope.
259       i->safelyBeingRemoved = false;
260     }
261   }
262 
263   delete collection;
264 }
265 
266 
SafeRemove(PSafeObject * obj)267 PBoolean PSafeCollection::SafeRemove(PSafeObject * obj)
268 {
269   if (obj == NULL)
270     return PFalse;
271 
272   PWaitAndSignal mutex(collectionMutex);
273   if (!collection->Remove(obj))
274     return PFalse;
275 
276   SafeRemoveObject(obj);
277   return PTrue;
278 }
279 
280 
SafeRemoveAt(PINDEX idx)281 PBoolean PSafeCollection::SafeRemoveAt(PINDEX idx)
282 {
283   PWaitAndSignal mutex(collectionMutex);
284   PSafeObject * obj = PDownCast(PSafeObject, collection->RemoveAt(idx));
285   if (obj == NULL)
286     return PFalse;
287 
288   SafeRemoveObject(obj);
289   return PTrue;
290 }
291 
292 
RemoveAll(PBoolean synchronous)293 void PSafeCollection::RemoveAll(PBoolean synchronous)
294 {
295   collectionMutex.Wait();
296 
297   while (collection->GetSize() > 0)
298     SafeRemoveObject(PDownCast(PSafeObject, collection->RemoveAt(0)));
299 
300   collectionMutex.Signal();
301 
302   if (synchronous) {
303     // Have unfortunate busy loop here, but it should be very
304     // rare that it will be here for long
305     while (!DeleteObjectsToBeRemoved())
306       PThread::Sleep(100);
307   }
308 }
309 
310 
SafeRemoveObject(PSafeObject * obj)311 void PSafeCollection::SafeRemoveObject(PSafeObject * obj)
312 {
313   if (obj == NULL)
314     return;
315 
316   // Make sure SfeRemove() called before SafeDereference() to avoid race condition
317   if (deleteObjects) {
318     obj->SafeRemove();
319 
320     removalMutex.Wait();
321     toBeRemoved.Append(obj);
322     removalMutex.Signal();
323   }
324 
325   /* Even though we are marked as not to delete objects, we still need to obey
326      the rule that if there are no references left the object is deleted. If
327      the object is still "owned" by a PSafeCollection that has NOT got
328      deleteObjects false, then SafeDereference returns false so we don't delete
329      is here. If there are no PSafePtr()s or PSafeCollections()'s anywhere we
330      need to delete it.
331      */
332   if (obj->SafeDereference() && !deleteObjects)
333     delete obj;
334 }
335 
336 
DeleteObjectsToBeRemoved()337 PBoolean PSafeCollection::DeleteObjectsToBeRemoved()
338 {
339   PWaitAndSignal lock(removalMutex);
340 
341   PList<PSafeObject>::iterator i = toBeRemoved.begin();
342   while (i != toBeRemoved.end()) {
343     if (i->GarbageCollection() && i->SafelyCanBeDeleted()) {
344       PObject * obj = &*i;
345       toBeRemoved.Remove(obj);
346       removalMutex.Signal();
347       DeleteObject(obj);
348       removalMutex.Wait();
349 
350       i = toBeRemoved.begin(); // Restart looking through list
351     }
352     else
353       i++;
354   }
355 
356   return toBeRemoved.IsEmpty() && collection->IsEmpty();
357 }
358 
359 
DeleteObject(PObject * object) const360 void PSafeCollection::DeleteObject(PObject * object) const
361 {
362   delete object;
363 }
364 
365 
SetAutoDeleteObjects()366 void PSafeCollection::SetAutoDeleteObjects()
367 {
368   if (deleteObjectsTimer.IsRunning())
369     return;
370 
371   deleteObjectsTimer.SetNotifier(PCREATE_NOTIFIER(DeleteObjectsTimeout));
372   deleteObjectsTimer.RunContinuous(1000); // EVery second
373 }
374 
375 
DeleteObjectsTimeout(PTimer &,INT)376 void PSafeCollection::DeleteObjectsTimeout(PTimer &, INT)
377 {
378   DeleteObjectsToBeRemoved();
379 }
380 
381 
GetSize() const382 PINDEX PSafeCollection::GetSize() const
383 {
384   PWaitAndSignal lock(collectionMutex);
385   return collection->GetSize();
386 }
387 
388 
CopySafeCollection(PCollection * other)389 void PSafeCollection::CopySafeCollection(PCollection * other)
390 {
391   DisallowDeleteObjects();
392 
393   for (PINDEX i = 0; i < other->GetSize(); ++i) {
394     PSafeObject * obj = dynamic_cast<PSafeObject *>(other->GetAt(i));
395     if (obj != NULL && obj->SafeReference())
396       collection->Append(obj);
397   }
398 }
399 
400 
CopySafeDictionary(PAbstractDictionary * other)401 void PSafeCollection::CopySafeDictionary(PAbstractDictionary * other)
402 {
403   DisallowDeleteObjects();
404 
405   for (PINDEX i = 0; i < other->GetSize(); ++i) {
406     PSafeObject * obj = dynamic_cast<PSafeObject *>(&other->AbstractGetDataAt(i));
407     if (obj != NULL && obj->SafeReference())
408       collection->Insert(other->AbstractGetKeyAt(i), obj);
409   }
410 }
411 
412 
413 /////////////////////////////////////////////////////////////////////////////
414 
PSafePtrBase(PSafeObject * obj,PSafetyMode mode)415 PSafePtrBase::PSafePtrBase(PSafeObject * obj, PSafetyMode mode)
416 {
417   collection = NULL;
418   currentObject = obj;
419   lockMode = mode;
420 
421   EnterSafetyMode(WithReference);
422 }
423 
424 
PSafePtrBase(const PSafeCollection & safeCollection,PSafetyMode mode,PINDEX idx)425 PSafePtrBase::PSafePtrBase(const PSafeCollection & safeCollection,
426                            PSafetyMode mode,
427                            PINDEX idx)
428 {
429   collection = &safeCollection;
430   currentObject = NULL;
431   lockMode = mode;
432 
433   Assign(idx);
434 }
435 
436 
PSafePtrBase(const PSafeCollection & safeCollection,PSafetyMode mode,PSafeObject * obj)437 PSafePtrBase::PSafePtrBase(const PSafeCollection & safeCollection,
438                            PSafetyMode mode,
439                            PSafeObject * obj)
440 {
441   collection = &safeCollection;
442   currentObject = NULL;
443   lockMode = mode;
444 
445   Assign(obj);
446 }
447 
448 
PSafePtrBase(const PSafePtrBase & enumerator)449 PSafePtrBase::PSafePtrBase(const PSafePtrBase & enumerator)
450 {
451   collection = enumerator.collection;
452   currentObject = enumerator.currentObject;
453   lockMode = enumerator.lockMode;
454 
455   EnterSafetyMode(WithReference);
456 }
457 
458 
~PSafePtrBase()459 PSafePtrBase::~PSafePtrBase()
460 {
461   ExitSafetyMode(WithDereference);
462 }
463 
464 
Compare(const PObject & obj) const465 PObject::Comparison PSafePtrBase::Compare(const PObject & obj) const
466 {
467   const PSafePtrBase * other = PDownCast(const PSafePtrBase, &obj);
468   if (other == NULL)
469     return GreaterThan;
470 
471   if (currentObject < other->currentObject)
472     return LessThan;
473   if (currentObject > other->currentObject)
474     return GreaterThan;
475   return EqualTo;
476 }
477 
478 
PrintOn(ostream & strm) const479 void PSafePtrBase::PrintOn(ostream &strm) const
480 {
481   strm << currentObject;
482 }
483 
484 
Assign(const PSafePtrBase & enumerator)485 void PSafePtrBase::Assign(const PSafePtrBase & enumerator)
486 {
487   if (this == &enumerator)
488     return;
489 
490   // lockCount ends up zero after this
491   ExitSafetyMode(WithDereference);
492 
493   collection = enumerator.collection;
494   currentObject = enumerator.currentObject;
495   lockMode = enumerator.lockMode;
496 
497   EnterSafetyMode(WithReference);
498 }
499 
500 
Assign(const PSafeCollection & safeCollection)501 void PSafePtrBase::Assign(const PSafeCollection & safeCollection)
502 {
503   // lockCount ends up zero after this
504   ExitSafetyMode(WithDereference);
505 
506   collection = &safeCollection;
507   currentObject = NULL;
508   lockMode = PSafeReadWrite;
509 
510   Assign((PINDEX)0);
511 }
512 
513 
Assign(PSafeObject * newObj)514 void PSafePtrBase::Assign(PSafeObject * newObj)
515 {
516   ExitSafetyMode(WithDereference);
517 
518   currentObject = newObj;
519 
520   if (newObj == NULL)
521     return;
522 
523   if (collection == NULL) {
524     lockMode = PSafeReference;
525     if (!EnterSafetyMode(WithReference))
526       currentObject = NULL;
527     return;
528   }
529 
530   collection->collectionMutex.Wait();
531 
532   if (collection->collection->GetObjectsIndex(newObj) == P_MAX_INDEX) {
533     collection->collectionMutex.Signal();
534     collection = NULL;
535     lockMode = PSafeReference;
536     if (!EnterSafetyMode(WithReference))
537       currentObject = NULL;
538   }
539   else {
540     if (!newObj->SafeReference())
541       currentObject = NULL;
542     collection->collectionMutex.Signal();
543     EnterSafetyMode(AlreadyReferenced);
544   }
545 }
546 
547 
Assign(PINDEX idx)548 void PSafePtrBase::Assign(PINDEX idx)
549 {
550   ExitSafetyMode(WithDereference);
551 
552   currentObject = NULL;
553 
554   if (collection == NULL)
555     return;
556 
557   collection->collectionMutex.Wait();
558 
559   while (idx < collection->collection->GetSize()) {
560     currentObject = (PSafeObject *)collection->collection->GetAt(idx);
561     if (currentObject != NULL) {
562       if (currentObject->SafeReference())
563         break;
564       currentObject = NULL;
565     }
566     idx++;
567   }
568 
569   collection->collectionMutex.Signal();
570 
571   EnterSafetyMode(AlreadyReferenced);
572 }
573 
574 
Next()575 void PSafePtrBase::Next()
576 {
577   if (collection == NULL || currentObject == NULL)
578     return;
579 
580   ExitSafetyMode(NoDereference);
581 
582   collection->collectionMutex.Wait();
583 
584   PINDEX idx = collection->collection->GetObjectsIndex(currentObject);
585 
586   currentObject->SafeDereference();
587   currentObject = NULL;
588 
589   if (idx != P_MAX_INDEX) {
590     while (++idx < collection->collection->GetSize()) {
591       currentObject = (PSafeObject *)collection->collection->GetAt(idx);
592       if (currentObject != NULL) {
593         if (currentObject->SafeReference())
594           break;
595         currentObject = NULL;
596       }
597     }
598   }
599 
600   collection->collectionMutex.Signal();
601 
602   EnterSafetyMode(AlreadyReferenced);
603 }
604 
605 
Previous()606 void PSafePtrBase::Previous()
607 {
608   if (collection == NULL || currentObject == NULL)
609     return;
610 
611   ExitSafetyMode(NoDereference);
612 
613   collection->collectionMutex.Wait();
614 
615   PINDEX idx = collection->collection->GetObjectsIndex(currentObject);
616 
617   currentObject->SafeDereference();
618   currentObject = NULL;
619 
620   if (idx != P_MAX_INDEX) {
621     while (idx-- > 0) {
622       currentObject = (PSafeObject *)collection->collection->GetAt(idx);
623       if (currentObject != NULL) {
624         if (currentObject->SafeReference())
625           break;
626         currentObject = NULL;
627       }
628     }
629   }
630 
631   collection->collectionMutex.Signal();
632 
633   EnterSafetyMode(AlreadyReferenced);
634 }
635 
636 
SetNULL()637 void PSafePtrBase::SetNULL()
638 {
639   // lockCount ends up zero after this
640   ExitSafetyMode(WithDereference);
641 
642   collection = NULL;
643   currentObject = NULL;
644   lockMode = PSafeReference;
645 }
646 
647 
SetSafetyMode(PSafetyMode mode)648 PBoolean PSafePtrBase::SetSafetyMode(PSafetyMode mode)
649 {
650   if (lockMode == mode)
651     return PTrue;
652 
653   ExitSafetyMode(NoDereference);
654   lockMode = mode;
655   return EnterSafetyMode(AlreadyReferenced);
656 }
657 
658 
EnterSafetyMode(EnterSafetyModeOption ref)659 PBoolean PSafePtrBase::EnterSafetyMode(EnterSafetyModeOption ref)
660 {
661   if (currentObject == NULL)
662     return PFalse;
663 
664   if (ref == WithReference && !currentObject->SafeReference()) {
665     currentObject = NULL;
666     return PFalse;
667   }
668 
669   switch (lockMode) {
670     case PSafeReadOnly :
671       if (currentObject->LockReadOnly())
672         return PTrue;
673       break;
674 
675     case PSafeReadWrite :
676       if (currentObject->LockReadWrite())
677         return PTrue;
678       break;
679 
680     case PSafeReference :
681       return PTrue;
682   }
683 
684   currentObject->SafeDereference();
685   currentObject = NULL;
686   return PFalse;
687 }
688 
689 
ExitSafetyMode(ExitSafetyModeOption ref)690 void PSafePtrBase::ExitSafetyMode(ExitSafetyModeOption ref)
691 {
692   if (currentObject == NULL)
693     return;
694 
695   switch (lockMode) {
696     case PSafeReadOnly :
697       currentObject->UnlockReadOnly();
698       break;
699 
700     case PSafeReadWrite :
701       currentObject->UnlockReadWrite();
702       break;
703 
704     case PSafeReference :
705       break;
706   }
707 
708   if (ref == WithDereference && currentObject->SafeDereference()) {
709     PSafeObject * objectToDelete = currentObject;
710     currentObject = NULL;
711     DeleteObject(objectToDelete);
712   }
713 }
714 
715 
DeleteObject(PSafeObject * obj)716 void PSafePtrBase::DeleteObject(PSafeObject * obj)
717 {
718   if (obj == NULL)
719     return;
720 
721   PTRACE(6, "SafeColl\tDeleting object (" << obj << ')');
722   delete obj;
723 }
724 
725 
726 /////////////////////////////////////////////////////////////////////////////
727 
PSafePtrMultiThreaded(PSafeObject * obj,PSafetyMode mode)728 PSafePtrMultiThreaded::PSafePtrMultiThreaded(PSafeObject * obj, PSafetyMode mode)
729   : PSafePtrBase(NULL, mode)
730   , m_objectToDelete(NULL)
731 {
732   LockPtr();
733 
734   currentObject = obj;
735   EnterSafetyMode(WithReference);
736 
737   UnlockPtr();
738 }
739 
740 
PSafePtrMultiThreaded(const PSafeCollection & safeCollection,PSafetyMode mode,PINDEX idx)741 PSafePtrMultiThreaded::PSafePtrMultiThreaded(const PSafeCollection & safeCollection,
742                                              PSafetyMode mode,
743                                              PINDEX idx)
744   : PSafePtrBase(NULL, mode)
745   , m_objectToDelete(NULL)
746 {
747   LockPtr();
748 
749   collection = &safeCollection;
750   Assign(idx);
751 
752   UnlockPtr();
753 }
754 
755 
PSafePtrMultiThreaded(const PSafeCollection & safeCollection,PSafetyMode mode,PSafeObject * obj)756 PSafePtrMultiThreaded::PSafePtrMultiThreaded(const PSafeCollection & safeCollection,
757                                              PSafetyMode mode,
758                                              PSafeObject * obj)
759   : PSafePtrBase(NULL, mode)
760   , m_objectToDelete(NULL)
761 {
762   LockPtr();
763 
764   collection = &safeCollection;
765   Assign(obj);
766 
767   UnlockPtr();
768 }
769 
770 
PSafePtrMultiThreaded(const PSafePtrMultiThreaded & enumerator)771 PSafePtrMultiThreaded::PSafePtrMultiThreaded(const PSafePtrMultiThreaded & enumerator)
772   : m_objectToDelete(NULL)
773 {
774   LockPtr();
775   enumerator.m_mutex.Wait();
776 
777   collection = enumerator.collection;
778   currentObject = enumerator.currentObject;
779   lockMode = enumerator.lockMode;
780 
781   EnterSafetyMode(WithReference);
782 
783   enumerator.m_mutex.Signal();
784   UnlockPtr();
785 }
786 
787 
~PSafePtrMultiThreaded()788 PSafePtrMultiThreaded::~PSafePtrMultiThreaded()
789 {
790   LockPtr();
791   ExitSafetyMode(WithDereference);
792   currentObject = NULL;
793   UnlockPtr();
794 }
795 
796 
Compare(const PObject & obj) const797 PObject::Comparison PSafePtrMultiThreaded::Compare(const PObject & obj) const
798 {
799   PWaitAndSignal mutex(m_mutex);
800   return PSafePtrBase::Compare(obj);
801 }
802 
803 
SetNULL()804 void PSafePtrMultiThreaded::SetNULL()
805 {
806   LockPtr();
807   PSafePtrBase::SetNULL();
808   UnlockPtr();
809 }
810 
811 
SetSafetyMode(PSafetyMode mode)812 PBoolean PSafePtrMultiThreaded::SetSafetyMode(PSafetyMode mode)
813 {
814   PWaitAndSignal mutex(m_mutex);
815   return PSafePtrBase::SetSafetyMode(mode);
816 }
817 
818 
Assign(const PSafePtrMultiThreaded & ptr)819 void PSafePtrMultiThreaded::Assign(const PSafePtrMultiThreaded & ptr)
820 {
821   LockPtr();
822   ptr.m_mutex.Wait();
823   PSafePtrBase::Assign(ptr);
824   ptr.m_mutex.Signal();
825   UnlockPtr();
826 }
827 
828 
Assign(const PSafePtrBase & ptr)829 void PSafePtrMultiThreaded::Assign(const PSafePtrBase & ptr)
830 {
831   LockPtr();
832   PSafePtrBase::Assign(ptr);
833   UnlockPtr();
834 }
835 
836 
Assign(const PSafeCollection & safeCollection)837 void PSafePtrMultiThreaded::Assign(const PSafeCollection & safeCollection)
838 {
839   LockPtr();
840   PSafePtrBase::Assign(safeCollection);
841   UnlockPtr();
842 }
843 
844 
Assign(PSafeObject * obj)845 void PSafePtrMultiThreaded::Assign(PSafeObject * obj)
846 {
847   LockPtr();
848   PSafePtrBase::Assign(obj);
849   UnlockPtr();
850 }
851 
852 
Assign(PINDEX idx)853 void PSafePtrMultiThreaded::Assign(PINDEX idx)
854 {
855   LockPtr();
856   PSafePtrBase::Assign(idx);
857   UnlockPtr();
858 }
859 
860 
Next()861 void PSafePtrMultiThreaded::Next()
862 {
863   LockPtr();
864   PSafePtrBase::Next();
865   UnlockPtr();
866 }
867 
868 
Previous()869 void PSafePtrMultiThreaded::Previous()
870 {
871   LockPtr();
872   PSafePtrBase::Previous();
873   UnlockPtr();
874 }
875 
876 
DeleteObject(PSafeObject * obj)877 void PSafePtrMultiThreaded::DeleteObject(PSafeObject * obj)
878 {
879   m_objectToDelete = obj;
880 }
881 
882 
UnlockPtr()883 void PSafePtrMultiThreaded::UnlockPtr()
884 {
885   PSafeObject * obj = m_objectToDelete;
886   m_objectToDelete = NULL;
887   m_mutex.Signal();
888   PSafePtrBase::DeleteObject(obj);
889 }
890 
891 
892 // End of File ///////////////////////////////////////////////////////////////
893