1 /*
2  * safecoll.h
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 #ifndef PTLIB_SAFE_COLLECTION_H
32 #define PTLIB_SAFE_COLLECTION_H
33 
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37 
38 
39 /** This class defines a thread-safe object in a collection.
40 
41   This is part of a set of classes to solve the general problem of a
42   collection (eg a PList or PDictionary) of objects that needs to be a made
43   thread safe. Any thread can add, read, write or remove an object with both
44   the object and the database of objects itself kept thread safe.
45 
46   The act of adding a new object is simple and only requires locking the
47   collection itself during the add.
48 
49   Locating an object is more complicated. The obvious lock on the collection
50   is made for the initial search. But we wish to have the full collection lock
51   for as short a period as possible (for performance reasons) so we lock the
52   individual object and release the lock on the collection.
53 
54   A simple mutex on the object however is very dangerous as it can be (and
55   should be able to be!) locked from other threads independently of the
56   collection. If one of these threads subsequently needs to get at the
57   collection (eg it wants to remove the object) then we will have a deadlock.
58   Also, to avoid a race condition with the object begin deleted, the objects
59   lock must be made while the collection lock is set. The performance gains
60   are then lost as if something has the object locked for a long time, then
61   another object wanting that object will actually lock the collection for a
62   long time as well.
63 
64   So, an object has 4 states: unused, referenced, reading & writing. With the
65   additional rider of "being removed". This flag prevents new locks from being
66   acquired and waits for all locks to be relinquished before removing the
67   object from the system. This prevents numerous race conditions and accesses
68   to deleted objects.
69 
70   The "unused" state indicates the object exists in the collection but no
71   threads anywhere is using it. It may be moved to any state by any thread
72   while in this state. An object cannot be deleted (ie memory deallocated)
73   until it is unused.
74 
75   The "referenced" state indicates that a thread has a reference (eg pointer)
76   to the object and it should not be deleted. It may be locked for reading or
77   writing at any time thereafter.
78 
79   The "reading" state is a form of lock that indicates that a thread is
80   reading from the object but not writing. Multiple threads can obtain a read
81   lock. Note the read lock has an implicit "reference" state in it.
82 
83   The "writing" state is a form of lock where the data in the object may
84   be changed. It can only be obtained exclusively and if there are no read
85   locks present. Again there is an implicit reference state in this lock.
86 
87   Note that threads going to the "referenced" state may do so regardless of
88   the read or write locks present.
89 
90   Access to safe objects (especially when in a safe collection) is recommended
91   to by the PSafePtr<> class which will manage reference counting and the
92   automatic unlocking of objects ones the pointer goes out of scope. It may
93   also be used to lock each object of a collection in turn.
94 
95   The enumeration of a PSafeCollection of PSafeObjects utilises the PSafePtr
96   class in a classic "for loop" manner.
97 
98   <CODE>
99     for (PSafePtr<MyClass> iter(collection, PSafeReadWrite); iter != NULL; ++iter)
100       iter->Process();
101   </CODE>
102 
103   There is one piece if important behaviour in the above. If while enumerating
104   a specic object in the collection, that object is "safely deleted", you are
105   guaranteed that the object is still usable and has not been phsyically
106   deleted, however it will no longer be in the collection, so the enumeration
107   will stop as it can no longer determine where in the collection it was.
108 
109   What to do in this case is to take a "snapshot" at a point of time that can be safely and completely
110   iterated over:
111 
112   <CODE>
113     PSafeList<MyClass> collCopy = collection;
114     for (PSafePtr<MyClass> iter(callCopy, PSafeReadWrite); iter != NULL; ++iter)
115       iter->Process();
116   </CODE>
117 
118  */
119 class PSafeObject : public PObject
120 {
121     PCLASSINFO(PSafeObject, PObject);
122   public:
123   /**@name Construction */
124   //@{
125     /**Create a thread safe object.
126      */
127     PSafeObject(
128         PSafeObject * indirectLock = NULL ///< Other safe object to be locked when this is locked
129     );
130   //@}
131 
132   /**@name Operations */
133   //@{
134     /**Increment the reference count for object.
135        This will guarantee that the object is not deleted (ie memory
136        deallocated) as the caller thread is using the object, but not
137        necessarily at this time locking it.
138 
139        If the function returns false, then the object has been flagged for
140        deletion and the calling thread should immediately cease using the
141        object.
142 
143        A typical use of this would be when an entity (eg a thread) has a
144        pointer to the object but is not currenty accessing the objects data.
145        The LockXXX functions may be called independetly of the reference
146        system and the pointer beiong used for the LockXXX call is guaranteed
147        to be usable.
148 
149        It is recommended that the PSafePtr<> class is used to manage this
150        rather than the application calling this function directly.
151       */
152     PBoolean SafeReference();
153 
154     /**Decrement the reference count for object.
155        This indicates that the thread no longer has anything to do with the
156        object and it may be deleted (ie memory deallocated).
157 
158        It is recommended that the PSafePtr<> class is used to manage this
159        rather than the application calling this function directly.
160 
161        @return true if reference count has reached zero and is not being
162                safely deleted elsewhere ie SafeRemove() not called
163       */
164     PBoolean SafeDereference();
165 
166     /**Lock the object for Read Only access.
167        This will lock the object in read only mode. Multiple threads may lock
168        the object read only, but only one thread can lock for read/write.
169        Also, no read only threads can be present for the read/write lock to
170        occur and no read/write lock can be present for any read only locks to
171        occur.
172 
173        If the function returns false, then the object has been flagged for
174        deletion and the calling thread should immediately cease use of the
175        object, possibly executing the SafeDereference() function to remove
176        any references it may have acquired.
177 
178        It is expected that the caller had already called the SafeReference()
179        function (directly or implicitly) before calling this function. It is
180        recommended that the PSafePtr<> class is used to automatically manage
181        the reference counting and locking of objects.
182       */
183     PBoolean LockReadOnly() const;
184 
185     /**Release the read only lock on an object.
186        Unlock the read only mutex that a thread had obtained. Multiple threads
187        may lock the object read only, but only one thread can lock for
188        read/write. Also, no read only threads can be present for the
189        read/write lock to occur and no read/write lock can be present for any
190        read only locks to occur.
191 
192        It is recommended that the PSafePtr<> class is used to automatically
193        manage the reference counting and unlocking of objects.
194       */
195     void UnlockReadOnly() const;
196 
197     /**Lock the object for Read/Write access.
198        This will lock the object in read/write mode. Multiple threads may lock
199        the object read only, but only one thread can lock for read/write.
200        Also no read only threads can be present for the read/write lock to
201        occur and no read/write lock can be present for any read only locks to
202        occur.
203 
204        If the function returns false, then the object has been flagged for
205        deletion and the calling thread should immediately cease use of the
206        object, possibly executing the SafeDereference() function to remove
207        any references it may have acquired.
208 
209        It is expected that the caller had already called the SafeReference()
210        function (directly or implicitly) before calling this function. It is
211        recommended that the PSafePtr<> class is used to automatically manage
212        the reference counting and locking of objects.
213       */
214     PBoolean LockReadWrite();
215 
216     /**Release the read/write lock on an object.
217        Unlock the read/write mutex that a thread had obtained. Multiple threads
218        may lock the object read only, but only one thread can lock for
219        read/write. Also, no read only threads can be present for the
220        read/write lock to occur and no read/write lock can be present for any
221        read only locks to occur.
222 
223        It is recommended that the PSafePtr<> class is used to automatically
224        manage the reference counting and unlocking of objects.
225       */
226     void UnlockReadWrite();
227 
228     /**Set the removed flag.
229        This flags the object as beeing removed but does not physically delete
230        the memory being used by it. The SafelyCanBeDeleted() can then be used
231        to determine when all references to the object have been released so it
232        may be safely deleted.
233 
234        This is typically used by the PSafeCollection class and is not expected
235        to be used directly by an application.
236       */
237     void SafeRemove();
238 
239     /**Determine if the object can be safely deleted.
240        This determines if the object has been flagged for deletion and all
241        references to it have been released.
242 
243        This is typically used by the PSafeCollection class and is not expected
244        to be used directly by an application.
245       */
246     PBoolean SafelyCanBeDeleted() const;
247 
248     /**Do any garbage collection that may be required by the object so that it
249        may be finally deleted. This is especially useful if there a references
250        back to this object which this object is in charge of disposing of. This
251        reference "glare" is to be resolved by this function being called every
252        time the owner collection is cleaning up, causing a cascade of clean ups
253        that might need to be required.
254 
255        Default implementation simply returns true.
256 
257        @return true if object may be deleted.
258       */
259     virtual bool GarbageCollection();
260   //@}
261 
262   private:
263     mutable PMutex    safetyMutex;
264     unsigned          safeReferenceCount;
265     bool              safelyBeingRemoved;
266     PReadWriteMutex   safeInUseMutex;
267     PReadWriteMutex * safeInUse;
268 
269   friend class PSafeCollection;
270 };
271 
272 
273 /**Lock a PSafeObject for read only and automatically unlock it when go out of scope.
274   */
275 class PSafeLockReadOnly
276 {
277   public:
278     PSafeLockReadOnly(const PSafeObject & object);
279     ~PSafeLockReadOnly();
280     PBoolean Lock();
281     void Unlock();
IsLocked()282     PBoolean IsLocked() const { return locked; }
283     bool operator!() const { return !locked; }
284 
285   protected:
286     PSafeObject & safeObject;
287     PBoolean          locked;
288 };
289 
290 
291 
292 /**Lock a PSafeObject for read/write and automatically unlock it when go out of scope.
293   */
294 class PSafeLockReadWrite
295 {
296   public:
297     PSafeLockReadWrite(const PSafeObject & object);
298     ~PSafeLockReadWrite();
299     PBoolean Lock();
300     void Unlock();
IsLocked()301     PBoolean IsLocked() const { return locked; }
302     bool operator!() const { return !locked; }
303 
304   protected:
305     PSafeObject & safeObject;
306     PBoolean          locked;
307 };
308 
309 
310 
311 /** This class defines a thread-safe collection of objects.
312   This class is a wrapper around a standard PCollection class which allows
313   only safe, mutexed, access to the collection.
314 
315   This is part of a set of classes to solve the general problem of a
316   collection (eg a PList or PDictionary) of objects that needs to be a made
317   thread safe. Any thread can add, read, write or remove an object with both
318   the object and the database of objects itself kept thread safe.
319 
320   See the PSafeObject class for more details. Especially in regard to
321   enumeration of collections.
322  */
323 class PSafeCollection : public PObject
324 {
325     PCLASSINFO(PSafeCollection, PObject);
326   public:
327   /**@name Construction */
328   //@{
329     /**Create a thread safe collection of objects.
330        Note the collection is automatically deleted on destruction.
331      */
332     PSafeCollection(
333       PCollection * collection    ///< Actual collection of objects
334      );
335 
336     /**Destroy the thread safe collection.
337        The will delete the collection object provided in the constructor.
338       */
339     ~PSafeCollection();
340   //@}
341 
342   /**@name Operations */
343   //@{
344   protected:
345     /**Remove an object to the collection.
346        This function removes the object from the collection itself, but does
347        not actually delete the object. It simply moves the object to a list
348        of objects to be garbage collected at a later time.
349 
350        As for Append() full mutual exclusion locking on the collection itself
351        is maintained.
352       */
353     virtual PBoolean SafeRemove(
354       PSafeObject * obj   ///< Object to remove from collection
355     );
356 
357     /**Remove an object to the collection.
358        This function removes the object from the collection itself, but does
359        not actually delete the object. It simply moves the object to a list
360        of objects to be garbage collected at a later time.
361 
362        As for Append() full mutual exclusion locking on the collection itself
363        is maintained.
364       */
365     virtual PBoolean SafeRemoveAt(
366       PINDEX idx    ///< Object index to remove
367     );
368 
369   public:
370     /**Remove all objects in collection.
371       */
372     virtual void RemoveAll(
373       PBoolean synchronous = false  ///< Wait till objects are deleted before returning
374     );
375 
376     /**Disallow the automatic delete any objects that have been removed.
377        Objects are simply removed from the collection and not marked for
378        deletion using PSafeObject::SafeRemove() and DeleteObject().
379       */
380     void AllowDeleteObjects(
381       PBoolean yes = true   ///< New value for flag for deleting objects
382     ) { deleteObjects = yes; }
383 
384     /**Disallow the automatic delete any objects that have been removed.
385        Objects are simply removed from the collection and not marked for
386        deletion using PSafeObject::SafeRemove() and DeleteObject().
387       */
DisallowDeleteObjects()388     void DisallowDeleteObjects() { deleteObjects = false; }
389 
390     /**Delete any objects that have been removed.
391        Returns true if all objects in the collection have been removed and
392        their pending deletions carried out.
393       */
394     virtual PBoolean DeleteObjectsToBeRemoved();
395 
396     /**Delete an objects that has been removed.
397       */
398     virtual void DeleteObject(PObject * object) const;
399 
400     /**Start a timer to automatically call DeleteObjectsToBeRemoved().
401       */
402     virtual void SetAutoDeleteObjects();
403 
404     /**Get the current size of the collection.
405        Note that usefulness of this function is limited as it is merely an
406        instantaneous snapshot of the state of the collection.
407       */
408     PINDEX GetSize() const;
409 
410     /**Determine if the collection is empty.
411        Note that usefulness of this function is limited as it is merely an
412        instantaneous snapshot of the state of the collection.
413       */
IsEmpty()414     PBoolean IsEmpty() const { return GetSize() == 0; }
415 
416     /**Get the mutex for the collection.
417       */
GetMutex()418     const PMutex & GetMutex() const { return collectionMutex; }
419   //@}
420 
421   protected:
422     void CopySafeCollection(PCollection * other);
423     void CopySafeDictionary(PAbstractDictionary * other);
424     void SafeRemoveObject(PSafeObject * obj);
425     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
426 
427     PCollection      * collection;
428     mutable PMutex     collectionMutex;
429     bool               deleteObjects;
430     PList<PSafeObject> toBeRemoved;
431     PMutex             removalMutex;
432     PTimer             deleteObjectsTimer;
433 
434   private:
PSafeCollection(const PSafeCollection & other)435     PSafeCollection(const PSafeCollection & other) : PObject(other) { }
436     void operator=(const PSafeCollection &) { }
437 
438   friend class PSafePtrBase;
439 };
440 
441 
442 enum PSafetyMode {
443   PSafeReference,
444   PSafeReadOnly,
445   PSafeReadWrite
446 };
447 
448 /** This class defines a base class for thread-safe pointer to an object.
449 
450   This is part of a set of classes to solve the general problem of a
451   collection (eg a PList or PDictionary) of objects that needs to be a made
452   thread safe. Any thread can add, read, write or remove an object with both
453   the object and the database of objects itself kept thread safe.
454 
455   NOTE: the PSafePtr will allow safe and mutexed access to objects but is not
456   thread safe itself! You should not share PSafePtr instances across threads.
457 
458   See the PSafeObject class for more details.
459  */
460 class PSafePtrBase : public PObject
461 {
462     PCLASSINFO(PSafePtrBase, PObject);
463 
464   /**@name Construction */
465   //@{
466   protected:
467     /**Create a new pointer to a PSafeObject.
468        An optional locking mode may be provided to lock the object for reading
469        or writing and automatically unlock it on destruction.
470 
471        Note that this version is not associated with a collection so the ++
472        and -- operators will not work.
473      */
474     PSafePtrBase(
475       PSafeObject * obj = NULL,         ///< Physical object to point to.
476       PSafetyMode mode = PSafeReference ///< Locking mode for the object
477     );
478 
479     /**Create a new pointer to a PSafeObject.
480        An optional locking mode may be provided to lock the object for reading
481        or writing and automatically unlock it on destruction.
482 
483        The idx'th entry of the collection is pointed to by this object. If the
484        idx is beyond the size of the collection, the pointer is NULL.
485      */
486     PSafePtrBase(
487       const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
488       PSafetyMode mode,                       ///< Locking mode for the object
489       PINDEX idx                              ///< Index into collection to point to
490     );
491 
492     /**Create a new pointer to a PSafeObject.
493        An optional locking mode may be provided to lock the object for reading
494        or writing and automatically unlock it on destruction.
495 
496        The obj parameter is only set if it contained in the collection,
497        otherwise the pointer is NULL.
498      */
499     PSafePtrBase(
500       const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
501       PSafetyMode mode,                       ///< Locking mode for the object
502       PSafeObject * obj                       ///< Inital object in collection to point to
503     );
504 
505     /**Copy the pointer to the PSafeObject.
506        This will create a copy of the pointer with the same locking mode and
507        lock on the PSafeObject. It will also increment the reference count on
508        the PSafeObject as well.
509       */
510     PSafePtrBase(
511       const PSafePtrBase & enumerator   ///< Pointer to copy
512     );
513 
514   public:
515     /**Unlock and dereference the PSafeObject this is pointing to.
516       */
517     ~PSafePtrBase();
518   //@}
519 
520   /**@name Overrides from class PObject */
521   //@{
522     /**Compare the pointers.
523        Note this is not a value comparison and will only return EqualTo if the
524        two PSafePtrBase instances are pointing to the same instance.
525       */
526     virtual Comparison Compare(
527       const PObject & obj   ///< Other instance to compare against
528     ) const;
529 
530     /** Output the contents of the object to the stream. The exact output is
531        dependent on the exact semantics of the descendent class. This is
532        primarily used by the standard <code>#operator<<</code> function.
533 
534        The default behaviour is to print the class name.
535      */
536     virtual void PrintOn(
537       ostream &strm   // Stream to print the object into.
538     ) const;
539   //@}
540 
541   /**@name Operations */
542   //@{
543     /**Set the pointer to NULL, unlocking/dereferencing existing pointer value.
544       */
545     virtual void SetNULL();
546 
547     /**Return true if pointer is NULL.
548       */
549     bool operator!() const { return currentObject == NULL; }
550 
551     /**Get the locking mode used by this pointer.
552       */
GetSafetyMode()553     PSafetyMode GetSafetyMode() const { return lockMode; }
554 
555     /**Change the locking mode used by this pointer.
556 
557        If the function returns false, then the object has been flagged for
558        deletion and the calling thread should immediately cease use of the
559        object. This instance pointer will be set to NULL.
560       */
561     virtual PBoolean SetSafetyMode(
562       PSafetyMode mode  ///< New locking mode
563     );
564 
565     /**Get the associated collection this pointer may be contained in.
566       */
GetCollection()567     const PSafeCollection * GetCollection() const { return collection; }
568   //@}
569 
570     virtual void Assign(const PSafePtrBase & ptr);
571     virtual void Assign(const PSafeCollection & safeCollection);
572     virtual void Assign(PSafeObject * obj);
573     virtual void Assign(PINDEX idx);
574 
575   protected:
576     virtual void Next();
577     virtual void Previous();
578     virtual void DeleteObject(PSafeObject * obj);
579 
580     enum EnterSafetyModeOption {
581       WithReference,
582       AlreadyReferenced
583     };
584     PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
585 
586     enum ExitSafetyModeOption {
587       WithDereference,
588       NoDereference
589     };
590     void ExitSafetyMode(ExitSafetyModeOption ref);
591 
LockPtr()592     virtual void LockPtr() { }
UnlockPtr()593     virtual void UnlockPtr() { }
594 
595   protected:
596     const PSafeCollection * collection;
597     PSafeObject           * currentObject;
598     PSafetyMode             lockMode;
599 };
600 
601 
602 /** This class defines a base class for thread-safe pointer to an object.
603 
604   This is part of a set of classes to solve the general problem of a
605   collection (eg a PList or PDictionary) of objects that needs to be a made
606   thread safe. Any thread can add, read, write or remove an object with both
607   the object and the database of objects itself kept thread safe.
608 
609   NOTE: unlikel PSafePtrBase, pointers based on this class are thread safe
610   themseleves, at the expense of performance on every operation.
611 
612   See the PSafeObject class for more details.
613  */
614 class PSafePtrMultiThreaded : public PSafePtrBase
615 {
616     PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
617 
618   /**@name Construction */
619   //@{
620   protected:
621     /**Create a new pointer to a PSafeObject.
622        An optional locking mode may be provided to lock the object for reading
623        or writing and automatically unlock it on destruction.
624 
625        Note that this version is not associated with a collection so the ++
626        and -- operators will not work.
627      */
628     PSafePtrMultiThreaded(
629       PSafeObject * obj = NULL,         ///< Physical object to point to.
630       PSafetyMode mode = PSafeReference ///< Locking mode for the object
631     );
632 
633     /**Create a new pointer to a PSafeObject.
634        An optional locking mode may be provided to lock the object for reading
635        or writing and automatically unlock it on destruction.
636 
637        The idx'th entry of the collection is pointed to by this object. If the
638        idx is beyond the size of the collection, the pointer is NULL.
639      */
640     PSafePtrMultiThreaded(
641       const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
642       PSafetyMode mode,                       ///< Locking mode for the object
643       PINDEX idx                              ///< Index into collection to point to
644     );
645 
646     /**Create a new pointer to a PSafeObject.
647        An optional locking mode may be provided to lock the object for reading
648        or writing and automatically unlock it on destruction.
649 
650        The obj parameter is only set if it contained in the collection,
651        otherwise the pointer is NULL.
652      */
653     PSafePtrMultiThreaded(
654       const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
655       PSafetyMode mode,                       ///< Locking mode for the object
656       PSafeObject * obj                       ///< Inital object in collection to point to
657     );
658 
659     /**Copy the pointer to the PSafeObject.
660        This will create a copy of the pointer with the same locking mode and
661        lock on the PSafeObject. It will also increment the reference count on
662        the PSafeObject as well.
663       */
664     PSafePtrMultiThreaded(
665       const PSafePtrMultiThreaded & enumerator   ///< Pointer to copy
666     );
667 
668   public:
669     /**Unlock and dereference the PSafeObject this is pointing to.
670       */
671     ~PSafePtrMultiThreaded();
672   //@}
673 
674   /**@name Overrides from class PObject */
675   //@{
676     /**Compare the pointers.
677        Note this is not a value comparison and will only return EqualTo if the
678        two PSafePtrBase instances are pointing to the same instance.
679       */
680     virtual Comparison Compare(
681       const PObject & obj   ///< Other instance to compare against
682     ) const;
683   //@}
684 
685   /**@name Operations */
686   //@{
687     /**Set the pointer to NULL, unlocking/dereferencing existing pointer value.
688       */
689     virtual void SetNULL();
690 
691     /**Change the locking mode used by this pointer.
692 
693        If the function returns false, then the object has been flagged for
694        deletion and the calling thread should immediately cease use of the
695        object. This instance pointer will be set to NULL.
696       */
697     virtual PBoolean SetSafetyMode(
698       PSafetyMode mode  ///< New locking mode
699     );
700   //@}
701 
702     virtual void Assign(const PSafePtrMultiThreaded & ptr);
703     virtual void Assign(const PSafePtrBase & ptr);
704     virtual void Assign(const PSafeCollection & safeCollection);
705     virtual void Assign(PSafeObject * obj);
706     virtual void Assign(PINDEX idx);
707 
708   protected:
709     virtual void Next();
710     virtual void Previous();
711     virtual void DeleteObject(PSafeObject * obj);
712 
LockPtr()713     virtual void LockPtr() { m_mutex.Wait(); }
714     virtual void UnlockPtr();
715 
716   protected:
717     mutable PMutex m_mutex;
718     PSafeObject  * m_objectToDelete;
719 };
720 
721 
722 /** This class defines a thread-safe enumeration of object in a collection.
723 
724   This is part of a set of classes to solve the general problem of a
725   collection (eg a PList or PDictionary) of objects that needs to be a made
726   thread safe. Any thread can add, read, write or remove an object with both
727   the object and the database of objects itself kept thread safe.
728 
729   There are two modes of safe pointer: one that is enumerating a collection;
730   and one that is independent of the collection that the safe object is in.
731   There are subtle semantics that must be observed in each of these two
732   modes especially when switching from one to the other.
733 
734   NOTE: the PSafePtr will allow safe and mutexed access to objects but may not
735   be thread safe itself! This depends on the base class being used. If the more
736   efficient PSafePtrBase class is used you should not share PSafePtr instances
737   across threads.
738 
739   See the PSafeObject class for more details, especially in regards to
740   enumeration of collections.
741  */
742 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
743 {
744   public:
745   /**@name Construction */
746   //@{
747     /**Create a new pointer to a PSafeObject.
748        An optional locking mode may be provided to lock the object for reading
749        or writing and automatically unlock it on destruction.
750 
751        Note that this version is not associated with a collection so the ++
752        and -- operators will not work.
753      */
754     PSafePtr(
755       T * obj = NULL,                   ///< Physical object to point to.
756       PSafetyMode mode = PSafeReference ///< Locking mode for the object
BaseClass(obj,mode)757     ) : BaseClass(obj, mode) { }
758 
759     /**Create a new pointer to a PSafeObject.
760        An optional locking mode may be provided to lock the object for reading
761        or writing and automatically unlock it on destruction.
762 
763        The idx'th entry of the collection is pointed to by this object. If the
764        idx is beyond the size of the collection, the pointer is NULL.
765      */
766     PSafePtr(
767       const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
768       PSafetyMode mode = PSafeReadWrite,      ///< Locking mode for the object
769       PINDEX idx = 0                          ///< Index into collection to point to
BaseClass(safeCollection,mode,idx)770     ) : BaseClass(safeCollection, mode, idx) { }
771 
772     /**Create a new pointer to a PSafeObject.
773        An optional locking mode may be provided to lock the object for reading
774        or writing and automatically unlock it on destruction.
775 
776        The obj parameter is only set if it contained in the collection,
777        otherwise the pointer is NULL.
778      */
PSafePtr(const PSafeCollection & safeCollection,PSafetyMode mode,PSafeObject * obj)779     PSafePtr(
780       const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
781       PSafetyMode mode,                       ///< Locking mode for the object
782       PSafeObject * obj                       ///< Inital object in collection to point to
783     ) : BaseClass(safeCollection, mode, obj) { }
784 
785     /**Copy the pointer to the PSafeObject.
786        This will create a copy of the pointer with the same locking mode and
787        lock on the PSafeObject. It will also increment the reference count on
788        the PSafeObject as well.
789       */
PSafePtr(const PSafePtr & ptr)790     PSafePtr(
791       const PSafePtr & ptr   ///< Pointer to copy
792     ) : BaseClass(ptr) { }
793 
794     /**Copy the pointer to the PSafeObject.
795        This will create a copy of the pointer with the same locking mode and
796        lock on the PSafeObject. It will also increment the reference count on
797        the PSafeObject as well.
798       */
799     PSafePtr & operator=(const PSafePtr & ptr)
800       {
801         BaseClass::Assign(ptr);
802         return *this;
803       }
804 
805     /**Start an enumerated PSafeObject.
806        This will create a read/write locked reference to teh first element in
807        the collection.
808       */
809     PSafePtr & operator=(const PSafeCollection & safeCollection)
810       {
811         BaseClass::Assign(safeCollection);
812         return *this;
813       }
814 
815     /**Set the new pointer to a PSafeObject.
816        This will set the pointer to the new object. The old object pointed to
817        will be unlocked and dereferenced and the new object referenced.
818 
819        If the safe pointer has an associated collection and the new object is
820        in that collection, then the object is set to the same locking mode as
821        the previous pointer value. This, in effect, jumps the enumeration of a
822        collection to the specifed object.
823 
824        If the safe pointer has no associated collection or the object is not
825        in the associated collection, then the object is always only referenced
826        and there is no read only or read/write lock done. In addition any
827        associated collection is removed so this becomes a non enumerating
828        safe pointer.
829      */
830     PSafePtr & operator=(T * obj)
831       {
832         this->Assign(obj);
833         return *this;
834       }
835 
836     /**Set the new pointer to a collection index.
837        This will set the pointer to the new object to the index entry in the
838        colelction that the pointer was created with. The old object pointed to
839        will be unlocked and dereferenced and the new object referenced and set
840        to the same locking mode as the previous pointer value.
841 
842        If the idx'th object is not in the collection, then the safe pointer
843        is set to NULL.
844      */
845     PSafePtr & operator=(PINDEX idx)
846       {
847         BaseClass::Assign(idx);
848         return *this;
849       }
850 
851     /**Set the safe pointer to the specified object.
852        This will return a PSafePtr for the previous value of this. It does
853        this in a thread safe manner so "test and set" semantics are obeyed.
854       */
Set(T * obj)855     PSafePtr Set(T * obj)
856       {
857         this->LockPtr();
858         PSafePtr oldPtr = *this;
859         this->Assign(obj);
860         this->UnlockPtr();
861         return oldPtr;
862       }
863   //@}
864 
865   /**@name Operations */
866   //@{
867     /**Return the physical pointer to the object.
868       */
869     operator T*()    const { return  (T *)BaseClass::currentObject; }
870 
871     /**Return the physical pointer to the object.
872       */
873     T & operator*()  const { return *(T *)PAssertNULL(BaseClass::currentObject); }
874 
875     /**Allow access to the physical object the pointer is pointing to.
876       */
877     T * operator->() const { return  (T *)PAssertNULL(BaseClass::currentObject); }
878 
879     /**Post-increment the pointer.
880        This requires that the pointer has been created with a PSafeCollection
881        object so that it can enumerate the collection.
882       */
883     T * operator++(int)
884       {
885         T * previous = (T *)BaseClass::currentObject;
886         BaseClass::Next();
887         return previous;
888       }
889 
890     /**Pre-increment the pointer.
891        This requires that the pointer has been created with a PSafeCollection
892        object so that it can enumerate the collection.
893       */
894     T * operator++()
895       {
896         BaseClass::Next();
897         return (T *)BaseClass::currentObject;
898       }
899 
900     /**Post-decrement the pointer.
901        This requires that the pointer has been created with a PSafeCollection
902        object so that it can enumerate the collection.
903       */
904     T * operator--(int)
905       {
906         T * previous = (T *)BaseClass::currentObject;
907         BaseClass::Previous();
908         return previous;
909       }
910 
911     /**Pre-decrement the pointer.
912        This requires that the pointer has been created with a PSafeCollection
913        object so that it can enumerate the collection.
914       */
915     T * operator--()
916       {
917         BaseClass::Previous();
918         return (T *)BaseClass::currentObject;
919       }
920   //@}
921 };
922 
923 
924 /**Cast the pointer to a different type. The pointer being cast to MUST
925     be a derived class or NULL is returned.
926   */
927 template <class Base, class Derived>
PSafePtrCast(const PSafePtr<Base> & oldPtr)928 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
929 {
930 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
931     PSafePtr<Derived> newPtr;
932     Base * realPtr = oldPtr;
933     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
934       newPtr.Assign(oldPtr);
935     return newPtr;
936 }
937 
938 
939 /** This class defines a thread-safe collection of objects.
940 
941   This is part of a set of classes to solve the general problem of a
942   collection (eg a PList or PDictionary) of objects that needs to be a made
943   thread safe. Any thread can add, read, write or remove an object with both
944   the object and the database of objects itself kept thread safe.
945 
946   See the PSafeObject class for more details. Especially in regard to
947   enumeration of collections.
948  */
949 template <class Coll, class Base> class PSafeColl : public PSafeCollection
950 {
951     PCLASSINFO(PSafeColl, PSafeCollection);
952   public:
953   /**@name Construction */
954   //@{
955     /**Create a safe list collection wrapper around the real collection.
956       */
PSafeColl()957     PSafeColl()
958       : PSafeCollection(new Coll)
959       { }
960 
961     /**Copy constructor for safe collection.
962        Note the left hand side will always have DisallowDeleteObjects() set.
963       */
PSafeColl(const PSafeColl & other)964     PSafeColl(const PSafeColl & other)
965       : PSafeCollection(new Coll)
966     {
967       PWaitAndSignal lock2(other.collectionMutex);
968       CopySafeCollection(dynamic_cast<Coll *>(other.collection));
969     }
970 
971     /**Assign one safe collection to another.
972        Note the left hand side will always have DisallowDeleteObjects() set.
973       */
974     PSafeColl & operator=(const PSafeColl & other)
975     {
976       if (&other != this) {
977         RemoveAll(true);
978         PWaitAndSignal lock1(collectionMutex);
979         PWaitAndSignal lock2(other.collectionMutex);
980         CopySafeCollection(dynamic_cast<Coll *>(other.collection));
981       }
982       return *this;
983     }
984   //@}
985 
986   /**@name Operations */
987   //@{
988     /**Add an object to the collection.
989        This uses the PCollection::Append() function to add the object to the
990        collection, with full mutual exclusion locking on the collection.
991       */
992     virtual PSafePtr<Base> Append(
993       Base * obj,       ///< Object to add to safe collection.
994       PSafetyMode mode = PSafeReference   ///< Safety mode for returned locked PSafePtr
995     ) {
996         PWaitAndSignal mutex(collectionMutex);
997         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
998             obj->SafeReference())
999           return PSafePtr<Base>(*this, mode, collection->Append(obj));
1000         return NULL;
1001       }
1002 
1003     /**Remove an object to the collection.
1004        This function removes the object from the collection itself, but does
1005        not actually delete the object. It simply moves the object to a list
1006        of objects to be garbage collected at a later time.
1007 
1008        As for Append() full mutual exclusion locking on the collection itself
1009        is maintained.
1010       */
Remove(Base * obj)1011     virtual PBoolean Remove(
1012       Base * obj          ///< Object to remove from safe collection
1013     ) {
1014         return SafeRemove(obj);
1015       }
1016 
1017     /**Remove an object to the collection.
1018        This function removes the object from the collection itself, but does
1019        not actually delete the object. It simply moves the object to a list
1020        of objects to be garbage collected at a later time.
1021 
1022        As for Append() full mutual exclusion locking on the collection itself
1023        is maintained.
1024       */
RemoveAt(PINDEX idx)1025     virtual PBoolean RemoveAt(
1026       PINDEX idx     ///< Index to remove
1027     ) {
1028         return SafeRemoveAt(idx);
1029       }
1030 
1031     /**Get the instance in the collection of the index.
1032        The returned safe pointer will increment the reference count on the
1033        PSafeObject and lock to the object in the mode specified. The lock
1034        will remain until the PSafePtr goes out of scope.
1035       */
1036     virtual PSafePtr<Base> GetAt(
1037       PINDEX idx,
1038       PSafetyMode mode = PSafeReadWrite
1039     ) {
1040         return PSafePtr<Base>(*this, mode, idx);
1041       }
1042 
1043     /**Find the instance in the collection of an object with the same value.
1044        The returned safe pointer will increment the reference count on the
1045        PSafeObject and lock to the object in the mode specified. The lock
1046        will remain until the PSafePtr goes out of scope.
1047       */
1048     virtual PSafePtr<Base> FindWithLock(
1049       const Base & value,
1050       PSafetyMode mode = PSafeReadWrite
1051     ) {
1052         collectionMutex.Wait();
1053         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
1054         collectionMutex.Signal();
1055         ptr.SetSafetyMode(mode);
1056         return ptr;
1057       }
1058   //@}
1059 };
1060 
1061 
1062 /** This class defines a thread-safe array of objects.
1063   See the PSafeObject class for more details. Especially in regard to
1064   enumeration of collections.
1065  */
1066 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
1067 {
1068   public:
1069     typedef PSafePtr<Base> value_type;
1070 };
1071 
1072 
1073 /** This class defines a thread-safe list of objects.
1074   See the PSafeObject class for more details. Especially in regard to
1075   enumeration of collections.
1076  */
1077 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
1078 {
1079   public:
1080     typedef PSafePtr<Base> value_type;
1081 };
1082 
1083 
1084 /** This class defines a thread-safe sorted array of objects.
1085   See the PSafeObject class for more details. Especially in regard to
1086   enumeration of collections.
1087  */
1088 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
1089 {
1090   public:
1091     typedef PSafePtr<Base> value_type;
1092 };
1093 
1094 
1095 /** This class defines a thread-safe dictionary of objects.
1096 
1097   This is part of a set of classes to solve the general problem of a
1098   collection (eg a PList or PDictionary) of objects that needs to be a made
1099   thread safe. Any thread can add, read, write or remove an object with both
1100   the object and the database of objects itself kept thread safe.
1101 
1102   See the PSafeObject class for more details. Especially in regard to
1103   enumeration of collections.
1104  */
1105 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
1106 {
1107     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
1108   public:
1109   /**@name Construction */
1110   //@{
1111     /**Create a safe dictionary wrapper around the real collection.
1112       */
PSafeDictionaryBase()1113     PSafeDictionaryBase()
1114       : PSafeCollection(new Coll) { }
1115 
1116     /**Copy constructor for safe collection.
1117        Note the left hand side will always have DisallowDeleteObjects() set.
1118       */
PSafeDictionaryBase(const PSafeDictionaryBase & other)1119     PSafeDictionaryBase(const PSafeDictionaryBase & other)
1120       : PSafeCollection(new Coll)
1121     {
1122       PWaitAndSignal lock2(other.collectionMutex);
1123       CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1124     }
1125 
1126     /**Assign one safe collection to another.
1127        Note the left hand side will always have DisallowDeleteObjects() set.
1128       */
1129     PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
1130     {
1131       if (&other != this) {
1132         RemoveAll(true);
1133         PWaitAndSignal lock1(collectionMutex);
1134         PWaitAndSignal lock2(other.collectionMutex);
1135         CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1136       }
1137       return *this;
1138     }
1139   //@}
1140 
1141   /**@name Operations */
1142   //@{
1143     /**Add an object to the collection.
1144        This uses the PCollection::Append() function to add the object to the
1145        collection, with full mutual exclusion locking on the collection.
1146       */
SetAt(const Key & key,Base * obj)1147     virtual void SetAt(const Key & key, Base * obj)
1148       {
1149         collectionMutex.Wait();
1150         SafeRemove(((Coll *)collection)->GetAt(key));
1151         if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
1152             obj->SafeReference())
1153           ((Coll *)collection)->SetAt(key, obj);
1154         collectionMutex.Signal();
1155       }
1156 
1157     /**Remove an object to the collection.
1158        This function removes the object from the collection itself, but does
1159        not actually delete the object. It simply moves the object to a list
1160        of objects to be garbage collected at a later time.
1161 
1162        As for Append() full mutual exclusion locking on the collection itself
1163        is maintained.
1164       */
RemoveAt(const Key & key)1165     virtual PBoolean RemoveAt(
1166       const Key & key   ///< Key to fund object to delete
1167     ) {
1168         PWaitAndSignal mutex(collectionMutex);
1169         return SafeRemove(((Coll *)collection)->GetAt(key));
1170       }
1171 
1172     /**Determine of the dictionary contains an entry for the key.
1173       */
Contains(const Key & key)1174     virtual PBoolean Contains(
1175       const Key & key
1176     ) {
1177         PWaitAndSignal lock(collectionMutex);
1178         return ((Coll *)collection)->Contains(key);
1179       }
1180 
1181     /**Get the instance in the collection of the index.
1182        The returned safe pointer will increment the reference count on the
1183        PSafeObject and lock to the object in the mode specified. The lock
1184        will remain until the PSafePtr goes out of scope.
1185       */
1186     virtual PSafePtr<Base> GetAt(
1187       PINDEX idx,
1188       PSafetyMode mode = PSafeReadWrite
1189     ) {
1190         return PSafePtr<Base>(*this, mode, idx);
1191       }
1192 
1193     /**Find the instance in the collection of an object with the same value.
1194        The returned safe pointer will increment the reference count on the
1195        PSafeObject and lock to the object in the mode specified. The lock
1196        will remain until the PSafePtr goes out of scope.
1197       */
1198     virtual PSafePtr<Base> FindWithLock(
1199       const Key & key,
1200       PSafetyMode mode = PSafeReadWrite
1201     ) {
1202         collectionMutex.Wait();
1203         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
1204         collectionMutex.Signal();
1205         ptr.SetSafetyMode(mode);
1206         return ptr;
1207       }
1208 
1209     /**Get an array containing all the keys for the dictionary.
1210       */
GetKeys()1211     PArray<Key> GetKeys() const
1212     {
1213       PArray<Key> keys;
1214       collectionMutex.Wait();
1215       ((Coll *)collection)->AbstractGetKeys(keys);
1216       collectionMutex.Signal();
1217       return keys;
1218     }
1219   //@}
1220 };
1221 
1222 
1223 /** This class defines a thread-safe array of objects.
1224   See the PSafeObject class for more details. Especially in regard to
1225   enumeration of collections.
1226  */
1227 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
1228 {
1229   public:
1230     typedef PSafePtr<Base> value_type;
1231 };
1232 
1233 
1234 #endif // PTLIB_SAFE_COLLECTION_H
1235 
1236 
1237 // End Of File ///////////////////////////////////////////////////////////////
1238