PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/sources/common/object.h

https://github.com/umonkey/librascal
C Header | 165 lines | 47 code | 8 blank | 110 comment | 1 complexity | 74b61230d776ffd9299a501930917520 MD5 | raw file
Possible License(s): 0BSD
  1. // RASCAL: Realtime Asynchronous Connection Abstraction Layer.
  2. // Copyright (c) 2003-2004 hex@faerion.oss
  3. // Distributed under the terms of GNU LGPL, read 'LICENSE'.
  4. //
  5. // $Id: object.h 3 2006-12-16 00:47:17Z justin.forest $
  6. //
  7. // Objects represent every operation that is performed asynchronously.
  8. // This currently includes all types of connections (incoming, outgoing
  9. // and established) and DNS requests. The `object' class maintains a
  10. // single list of objects and assigns them unique ids. This is the
  11. // main purpose of the class: to serve as a central collection of all
  12. // operations issued by other parts of the library.
  13. //
  14. // The `object' implements a reference counter to ensure that objects
  15. // are only deleted when they are not used by the library. Objects
  16. // must never be deleted using the `delete' operator; instead, the
  17. // `cancel' method must be used. Should you need to know whether a
  18. // request was cancelled, use the `is_cancelled' method of the base
  19. // class; you are likely to want to exclude cancelled requests from the
  20. // regular processing.
  21. //
  22. // The way the reference counter works is simple: you find an object
  23. // by its id (the automatically assigned one) and call the base class'
  24. // `incref' method. You do what you need, then release the object by
  25. // calling the `decref' method. When an object that has been marked
  26. // as cancelled is released and the reference counter for that object
  27. // becomes zero, the object is automatically deleted.
  28. //
  29. // PROBLEMS.
  30. //
  31. // The first weak place of this technique is the time between obtaining
  32. // the pointer to the object and calling `incref'. The object might
  33. // have been released and deleted during that time. This would
  34. // effectively introduce a race condition crash vulnerability.
  35. //
  36. // The second weak place is the amount of trust we must have in the
  37. // client application to assume it never passes an id of a DNS request
  38. // to `rascal_write', or do anything like that.
  39. //
  40. // SOLUTIONS.
  41. //
  42. // To mitigate both of these problems, a helper class `pobject' was
  43. // introduced. It automates finding objects (optionally of a specific
  44. // type) and maintaining the reference counter. You must only
  45. // instantiate `pobject' on stack, never leaving it float in the
  46. // memory longer than necessary.
  47. //
  48. // To find an object by its id you would construct a `pobject' this way:
  49. //
  50. // pobject<getaddr> tmp(id);
  51. //
  52. // The type specification is optional; if absent, an objects of any
  53. // type will be returned. To know whether the object with the given
  54. // id was successfully found, the `is_valid' method should be used
  55. // before any other action on `tmp' is taken. (We avoid using
  56. // exceptions because it would cause significant performance loss,
  57. // while the execution time is critical.) To access the underlying
  58. // object, use the `->' operator.
  59. //
  60. // To allow objects of a class to be located by id, the class must
  61. // define the following method:
  62. //
  63. // void * get_type_id(void) const;
  64. //
  65. // The method must return a value unique to the class, to avoid
  66. // collisions. The easiest way to achieve this is to return a
  67. // pointer to a static class member (there can be no two static
  68. // members with the same address, obviously). Objects of a class
  69. // that does not define the `get_type_id' method can still be
  70. // located as type `object'.
  71. //
  72. // PERFORMANCE NOTES.
  73. //
  74. // The `object' class is thread safe and uses thread locking internally.
  75. // There is only one mutex for all objects, the number of objects does
  76. // not affect performance in any way. This also implies that retreiving
  77. // an object by id is a fast operation. However, using it more often
  78. // than actually needed is bad.
  79. //
  80. // TODO.
  81. //
  82. // We want to use spinlocks instead of mutexes to lock the stock.
  83. #ifndef __rascal_object_h
  84. #define __rascal_object_h
  85. #include "util/mutex.h"
  86. #include "util/sem.h"
  87. #include "../rascal.h"
  88. #define DECLARE_CLASSID(name) \
  89. static ot_t get_class_ot(void) { static ot_t _t = "ot_" #name; return _t; } \
  90. virtual ot_t get_object_ot(void) const { return get_class_ot(); }
  91. template <class T> class pobject;
  92. class object
  93. {
  94. public:
  95. // Dynamic type identification.
  96. typedef const char * ot_t;
  97. private:
  98. friend class pobject<object>;
  99. // Reference counter; the number of times incref() was called for this
  100. // object, see below. When this is zero, the object is safe to
  101. // delete (automatically done in decref()).
  102. unsigned int refc;
  103. // Set when the object needs to be deleted, but is in use.
  104. bool cancelled;
  105. // Object identifier, assigned on creation.
  106. rrid_t id;
  107. // Object guard.
  108. mutex mx;
  109. protected:
  110. // Increments the reference counter.
  111. void incref();
  112. // Decrements the reference counter, deletes the object
  113. // if it was cancelled and is no longer in use.
  114. void decref();
  115. public:
  116. // Initializes the object and assigns the id.
  117. // The object is inserted into the global list.
  118. object();
  119. // Removes the object from the global list.
  120. virtual ~object();
  121. // Returns the object id.
  122. rrid_t get_id() const { return id; }
  123. // Interlocked connection fitering.
  124. typedef bool (*list_filter)(object *, void *);
  125. static unsigned int list(object **, unsigned int, list_filter, void * = 0);
  126. // Marks the object for deletion. The object must be locked
  127. // when this method is executed. This method is virtual to
  128. // allow custom client notifications (calling dispatchers, and
  129. // so on); the inherited method MUST call the original one.
  130. virtual void cancel() { cancelled = true; }
  131. // Checks whether the object is cancelled.
  132. bool is_cancelled() const { return cancelled; }
  133. // Waits for the request to finish.
  134. void wait();
  135. // Dynamic type identification.
  136. DECLARE_CLASSID(object);
  137. static void _lookup(object **host, int id, ot_t tid);
  138. static void _release(object **host);
  139. };
  140. template <class T = object> class pobject
  141. {
  142. T *host;
  143. // Generic lookup function.
  144. static void lookup(int id, void *type);
  145. // Generic release function.
  146. static void release(void);
  147. public:
  148. // Lookup constructor.
  149. pobject(int id) { object::_lookup(reinterpret_cast<object **>(&host), id, T::get_class_ot()); }
  150. // Standard destructor.
  151. ~pobject(void) { object::_release(reinterpret_cast<object **>(&host)); }
  152. // Indirect access.
  153. T* operator -> (void) { return host; }
  154. // Determines whether the object was found.
  155. bool is_valid(void) const { return host != NULL; }
  156. };
  157. #endif // __rascal_object_h