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