Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

497 lines
11 KiB

  1. /*++
  2. Microsoft Windows NT RPC Name Service
  3. Copyright (C) Microsoft Corporation, 1995 - 1999
  4. Module Name:
  5. skiplist.hxx
  6. Abstract:
  7. This module contains a definition of skip Lists which
  8. are used to represent the internal cache of the RPC
  9. locator, and other collections where duplicate removal
  10. and search are required.
  11. Author:
  12. Satish Thatte (SatishT) 08/16/95 Created all the code below except where
  13. otherwise indicated.
  14. --*/
  15. #ifndef __SKIPLIST_HXX__
  16. #define __SKIPLIST_HXX__
  17. enum SkipStatus { // for insert only
  18. OK,
  19. Duplicate
  20. };
  21. // the following is for debugging purposes only
  22. extern char * CSListName;
  23. extern char * CSLinkName;
  24. // end of debugging inserts
  25. /*++
  26. Class Definition:
  27. CSkipList
  28. Abstract:
  29. This class is used to keep dictionaries of entries for fast
  30. search and insertion. Skip lists were invented by William Pugh
  31. and described in a 1990 CACM article (pages 668-676). Our skip
  32. lists are flexible -- they do not require an estimation of the
  33. maximal list size in advance. We have a member called maxlevel
  34. which keeps track of the size of the largest node currently required.
  35. We must ensure that the First node is always of the largest size.
  36. This is the purpose of the resizing constructor.
  37. The items stored in CSkipList are expected to be of a class derived
  38. from the abstract class IOrderedItem (defined in abstract.hxx) which
  39. defines a pure virtual comparison operator, as well as several
  40. dependent relational operators.
  41. Instead of instantiating this class and its iterator directly, it is
  42. far better to instantiate their "safe" versions defined below.
  43. Note that CSkipLinks are reference counted. For this purpose, we view
  44. the skip lists as essentially (sorted) linked lists, threaded through
  45. level 0 linkages. Linkages at other levels are seen as an optimization.
  46. Thus, hold/release apply through level 0 linkages only.
  47. Direct deletion of CSkipLinks is prohibited.
  48. --*/
  49. #if _MSC_VER >= 1100 && defined(__BOOL_DEFINED)
  50. class CSkipListIterator; // Forward ref
  51. #endif
  52. class CSkipList {
  53. protected:
  54. friend class CSkipListIterator;
  55. struct CSkipLink : public CRefCounted
  56. {
  57. IOrderedItem * data;
  58. CSkipLink* *next;
  59. short levels;
  60. int fDeleteData; // this flag is used to signal that the data is
  61. // expendable. Typically, we don't delete the
  62. // data during self-destruct since it may be shared
  63. CSkipLink(IOrderedItem * d, short l); // regular constructor
  64. CSkipLink(CSkipLink * old, short newSize); // resizing constructor
  65. virtual ~CSkipLink();
  66. };
  67. ULONG count; // current size of list
  68. short maxlevel; // current max node level
  69. ULONG maxcount; // courrent max node count
  70. CSkipLink *pLnkFirst;
  71. static void releaseAll(CSkipLink*); // utility for destructor and wipeOut
  72. public:
  73. CSkipList();
  74. inline
  75. ~CSkipList()
  76. {
  77. releaseAll(pLnkFirst);
  78. }
  79. inline
  80. ULONG size()
  81. {
  82. return count;
  83. }
  84. SkipStatus insert(IOrderedItem *);
  85. // remove and return the first (and smallest) item
  86. IOrderedItem *CSkipList::pop();
  87. // find the given item using IOrderedItem::compare
  88. IOrderedItem * find(IOrderedItem *);
  89. // find and remove the given item using IOrderedItem::compare
  90. IOrderedItem * remove(IOrderedItem *);
  91. // release all SkipLinks and all data and reinitialize to empty list
  92. void wipeOut(); // use with extreme caution!
  93. };
  94. /*++
  95. Class Definition:
  96. CSkipListIterator
  97. Abstract:
  98. An iterator class for traversing a CSkipList.
  99. --*/
  100. class CSkipListIterator {
  101. CSkipList::CSkipLink* ptr; // the current link
  102. public:
  103. inline
  104. CSkipListIterator(CSkipList& sl) {
  105. ptr = sl.pLnkFirst;
  106. if (ptr) ptr->hold();
  107. }
  108. inline
  109. ~CSkipListIterator() {
  110. CSkipList::releaseAll(ptr);
  111. }
  112. IOrderedItem* next(); // advance the iterator and return next IDataItem
  113. inline
  114. int finished() { return ptr == NULL; }
  115. };
  116. /*++
  117. Template Class Definition:
  118. TCSafeSkipList
  119. Abstract:
  120. The template TCSafeSkipList make it easy to produce "type safe" incarnations of
  121. the CSkipList classe, avoiding the use of casts in client code.
  122. Note that Data must be a subtype of IOrderedItem.
  123. --*/
  124. #if (_MSC_VER >= 1100 && defined(__BOOL_DEFINED)) || defined(_AMD64_) || defined(IA64)
  125. template <class Data> class TCSafeSkipListIterator;
  126. #endif
  127. template <class Data>
  128. class TCSafeSkipList
  129. {
  130. CSkipList rep;
  131. friend class TCSafeSkipListIterator<Data>;
  132. public:
  133. inline
  134. ULONG size() { return rep.size(); }
  135. inline
  136. SkipStatus insert(Data * I) { return rep.insert(I); }
  137. inline
  138. Data * pop() { return (Data *) rep.pop(); }
  139. inline
  140. Data * remove(IOrderedItem * I) { return (Data *) rep.remove(I); }
  141. inline
  142. Data * find(IOrderedItem * I) { return (Data *) rep.find(I); }
  143. inline
  144. void wipeOut() { // delete all SkipLinks and all data
  145. rep.wipeOut();
  146. }
  147. };
  148. /*++
  149. Template Class Definition:
  150. TCSafeSkipListIterator
  151. Abstract:
  152. The iterator for TCSafeSkipLists.
  153. The inheritance from TIIterator<Data> has the potential for considerable code bloat
  154. for this template because it forces the separate incarnation of every (virtual)
  155. function for every instance of the template in the code.
  156. In practice, however, due to the small size of method implementations, the bloat
  157. was found to be insignificant (~1K in retail builds of the locator).
  158. --*/
  159. template <class Data>
  160. class TCSafeSkipListIterator : public TIIterator<Data>
  161. {
  162. CSkipListIterator rep;
  163. public:
  164. inline
  165. TCSafeSkipListIterator(TCSafeSkipList<Data>& l) : rep(l.rep)
  166. {}
  167. inline
  168. Data* next() {
  169. return (Data*) rep.next();
  170. }
  171. inline
  172. int finished() { return rep.finished(); }
  173. };
  174. /*++
  175. Template Class Definition:
  176. TCGuardedSkipList
  177. Abstract:
  178. The templates TCGuardedSkipList makes it easy to produce "guarded" incarnations of
  179. the TCSafeSkipList template. The new template uses a CReadWriteSection
  180. to guard the list using the usual solution based on the readers/writers
  181. metaphor.
  182. Even though the template uses CReadWriteSection, "mutex.hxx" is not included
  183. here -- it must be included before the template can be instantiated.
  184. If we are paranoid about thread safety, the TCSafeSkipList<Data> object
  185. representation used underneath would have to be a member rather than a private
  186. base so that the constructor and destructor calls on the representation could
  187. themselves be guarded. For our uses, this is unnecessary.
  188. --*/
  189. #if (_MSC_VER >= 1100 && defined(__BOOL_DEFINED)) || defined(IA64)
  190. template <class Data> class TCGuardedSkipListIterator;
  191. class CReadWriteSection;
  192. #endif
  193. template <class Data>
  194. class TCGuardedSkipList : private TCSafeSkipList<Data> {
  195. friend class TCGuardedSkipListIterator<Data>;
  196. CReadWriteSection *rwGuard;
  197. public:
  198. TCGuardedSkipList()
  199. {
  200. rwGuard = new CReadWriteSection;
  201. }
  202. ~TCGuardedSkipList()
  203. {
  204. rwGuard->release();
  205. }
  206. inline
  207. ULONG size() // this is probably more elaborate than it needs to be
  208. {
  209. CriticalReader me(*rwGuard);
  210. return TCSafeSkipList<Data>::size();
  211. }
  212. SkipStatus insert(Data * I);
  213. Data * pop();
  214. inline
  215. Data * remove(IOrderedItem * I)
  216. {
  217. CriticalWriter me(*rwGuard);
  218. return TCSafeSkipList<Data>::remove(I);
  219. }
  220. Data * find(IOrderedItem * I);
  221. void wipeOut();
  222. };
  223. template <class Data>
  224. SkipStatus
  225. TCGuardedSkipList<Data>::insert(Data * I) {
  226. /* this one may cause exceptions due to memory problems,
  227. hence the SEH */
  228. SkipStatus result;
  229. rwGuard->writerEnter();
  230. __try {
  231. result = TCSafeSkipList<Data>::insert(I);
  232. }
  233. __finally {
  234. rwGuard->writerLeave();
  235. }
  236. return result;
  237. }
  238. template <class Data>
  239. inline Data *
  240. TCGuardedSkipList<Data>::pop()
  241. {
  242. CriticalWriter me(*rwGuard);
  243. return TCSafeSkipList<Data>::pop();
  244. }
  245. #if !(_MSC_VER >= 1100 && defined(__BOOL_DEFINED)) && !defined(_AMD64_) && !defined(IA64)
  246. template <class Data>
  247. inline Data *
  248. TCGuardedSkipList<Data>::remove(IOrderedItem * I)
  249. {
  250. CriticalWriter me(*rwGuard);
  251. return TCSafeSkipList<Data>::remove(I);
  252. }
  253. #endif
  254. template <class Data>
  255. inline Data *
  256. TCGuardedSkipList<Data>::find(IOrderedItem * I)
  257. {
  258. CriticalReader me(*rwGuard);
  259. return TCSafeSkipList<Data>::find(I);
  260. }
  261. template <class Data>
  262. inline void
  263. TCGuardedSkipList<Data>::wipeOut() { // delete all SkipLinks and all data
  264. rwGuard->writerEnter();
  265. /* this one may cause exceptions due to delete on stored items,
  266. hence the SEH */
  267. __try {
  268. TCSafeSkipList<Data>::wipeOut();
  269. }
  270. __finally {
  271. rwGuard->writerLeave();
  272. }
  273. }
  274. /*++
  275. Template Class Definition:
  276. TCGuardedSkipListIterator
  277. Abstract:
  278. The iterator for TCGuardedLinkLists.
  279. The iterator template in this case is nontrivial since it traverses
  280. private data structures in the GuardedSkipList. It must therefore use
  281. the private CReadWriteSection in its source to ensure thread safety.
  282. It also uses a private variable of type TCSafeSkipListIterator<Data> *
  283. instead of private inheritance for the same reason the TCGuardedSkipList
  284. template above does.
  285. Unfortunately, since the SkipLinks are shared and reference counted, iterator
  286. operations modify the reference counts and must therefore be treated as
  287. writer operations even though they do not modify the client-visible state.
  288. The iterator is not safe to use if the guarded list object it is iterating over is
  289. destroyed -- because it holds a reference to the CReadWriteSection in the list.
  290. This is in contrast to the unguarded list objects, where an iterator can be
  291. "grandfathered" and will continue safely with its traversal even after the list
  292. has been deleted, because reference counting preserves the links and data items.
  293. With some effort, the guarded lists can be made to confirm to the unguarded
  294. pattern. However, this entails making critical sections reference counted
  295. and does not seem warranted at the moment.
  296. */
  297. template <class Data>
  298. class TCGuardedSkipListIterator : public TIIterator<Data>
  299. {
  300. CReadWriteSection *rwGuard; // shared
  301. TCSafeSkipListIterator<Data> *pSSLIiter; // not shared
  302. public:
  303. TCGuardedSkipListIterator(TCGuardedSkipList<Data>& l)
  304. : rwGuard(l.rwGuard)
  305. {
  306. rwGuard->hold();
  307. CriticalWriter me(*rwGuard);
  308. pSSLIiter = new TCSafeSkipListIterator<Data>(l);
  309. }
  310. ~TCGuardedSkipListIterator() {
  311. rwGuard->writerEnter();
  312. delete pSSLIiter;
  313. rwGuard->writerLeave();
  314. rwGuard->release();
  315. }
  316. inline
  317. Data* next()
  318. {
  319. CriticalWriter me(*rwGuard);
  320. return pSSLIiter->next();
  321. }
  322. int finished()
  323. {
  324. CriticalReader me(*rwGuard);
  325. return pSSLIiter->finished();
  326. }
  327. };
  328. #endif // __SKIPLIST_HXX__