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.

565 lines
11 KiB

  1. /*++
  2. Microsoft Windows NT RPC Name Service
  3. Copyright (C) Microsoft Corporation, 1995 - 1999
  4. Module Name:
  5. linklist.hxx
  6. Abstract:
  7. This module contains definitions of class CLinkList, and templates derived
  8. from it for type safety and multi-threading safety.
  9. Author:
  10. Satish Thatte (SatishT) 08/16/95 Created all the code below except where
  11. otherwise indicated.
  12. --*/
  13. #ifndef __LINKLIST_HXX_
  14. #define __LINKLIST_HXX_
  15. /* the type of comparison function used in CLinkList::find below */
  16. typedef int (*TcompFun)(IDataItem*,IDataItem*);
  17. /*++
  18. Class Definition:
  19. CLinkList
  20. Abstract:
  21. This is the linked list class. It has a private Link class.
  22. Note that the links are garbage collected through reference
  23. counting, in order to accommodate iterators that share access
  24. to links.
  25. --*/
  26. extern char * LLname;
  27. extern char * Lname;
  28. class CLinkList
  29. {
  30. friend class CLinkListIterator;
  31. protected:
  32. // a Link object should never be directly deleted, only released
  33. struct Link : public CRefCounted
  34. {
  35. int fDeleteData; // this flag is used to signal that the data is
  36. // expendable. Typically, we don't delete the
  37. // data during self-destruct since it may be shared
  38. Link* next;
  39. IDataItem* data;
  40. Link(IDataItem* a, Link* n);
  41. virtual ~Link();
  42. };
  43. Link * pLnkLast, * pLnkFirst;
  44. long ulCount;
  45. static void releaseAll(Link*); // protected utility
  46. public:
  47. CLinkList()
  48. {
  49. pLnkFirst = pLnkLast = NULL;
  50. ulCount = 0;
  51. }
  52. ~CLinkList()
  53. {
  54. releaseAll(pLnkFirst);
  55. }
  56. ULONG size()
  57. {
  58. return ulCount;
  59. }
  60. // insert at the end
  61. void enque(IDataItem* x);
  62. // insert at the beginning
  63. void push(IDataItem* x);
  64. // insert at the end
  65. void insert(IDataItem* x)
  66. { enque(x); }
  67. IDataItem* pop(); // remove first item and return it
  68. /* remove the specified item and return it -- use pointer equality
  69. -- the return flag signifies success (TRUE) or failure (FALSE) */
  70. int remove(IDataItem *);
  71. /* Unlike remove, this method is designed to use a client-supplied
  72. comparison function instead of pointer equality. The comparison
  73. function is expected to behave like strcmp (returning <0 if less,
  74. 0 if equal and >0 if greater).
  75. */
  76. IDataItem* find(IDataItem*,TcompFun);
  77. IDataItem* nth(long lOrdinal);
  78. void rotate(long lDegree);
  79. void catenate(CLinkList& ll);
  80. // mark all links and all data for deletion
  81. void wipeOut(); // use with great caution!
  82. };
  83. /*++
  84. Class Definition:
  85. CLinkListIterator
  86. Abstract:
  87. An iterator class for traversing a CLinkList.
  88. --*/
  89. class CLinkListIterator {
  90. CLinkList::Link* ptr; // the current link
  91. CLinkList::Link* first; // the first link
  92. public:
  93. CLinkListIterator(CLinkList& source);
  94. ~CLinkListIterator()
  95. {
  96. CLinkList::releaseAll(ptr);
  97. }
  98. IDataItem* next(); // advance the iterator and return next IDataItem
  99. int finished()
  100. {
  101. return ptr == NULL;
  102. }
  103. };
  104. /*++
  105. Template Class Definition:
  106. TCSafeLinkList
  107. Abstract:
  108. The template TCSafeLinkList make it easy to produce "type safe" incarnations of
  109. the CLinkList classe, avoiding the use of casts in client code.
  110. Note that Data must be a subtype of IDataItem.
  111. --*/
  112. #if (_MSC_VER >= 1100 && defined(__BOOL_DEFINED)) || defined(_AMD64_) || defined(IA64)
  113. template <class Data> class TCSafeLinkListIterator;
  114. #endif
  115. template <class Data>
  116. class TCSafeLinkList : private CLinkList
  117. {
  118. friend class TCSafeLinkListIterator<Data>;
  119. public:
  120. inline
  121. void enque(Data* x) {
  122. CLinkList::enque(x);
  123. }
  124. inline
  125. void push(Data* x) {
  126. CLinkList::push(x);
  127. }
  128. inline
  129. void insert(Data* x) {
  130. enque(x);
  131. }
  132. inline
  133. void wipeOut() {
  134. CLinkList::wipeOut();
  135. }
  136. inline
  137. void rotate(long lDegree) {
  138. CLinkList::rotate(lDegree);
  139. }
  140. inline
  141. void catenate(TCSafeLinkList& ll) {
  142. CLinkList::catenate(ll);
  143. }
  144. inline
  145. Data* pop() {
  146. return (Data*) CLinkList::pop();
  147. }
  148. inline
  149. int remove(Data* x) {
  150. return CLinkList::remove(x);
  151. }
  152. inline
  153. Data* find(Data* pD,int comp(Data*,Data*)) {
  154. return (Data*) CLinkList::find(pD, (TcompFun) comp);
  155. }
  156. inline
  157. Data* nth(long lOrdinal) {
  158. return (Data*) CLinkList::nth(lOrdinal);
  159. }
  160. inline
  161. ULONG size() { return CLinkList::size(); }
  162. };
  163. /*++
  164. Template Class Definition:
  165. TCSafeLinkListIterator
  166. Abstract:
  167. The iterator for TCSafeLinkLists.
  168. The inheritance from TIIterator<Data> has the potential for considerable code bloat
  169. for this template because it forces the separate incarnation of every (virtual)
  170. function for every instance of the template in the code. If code size become a
  171. serious concern, this is one easy place to start the shrinkage, at some cost
  172. in flexibility.
  173. In practice, however, due to the small size of method implementations, the bloat
  174. was found to be insignificant (~1K in retail builds of the locator).
  175. --*/
  176. template <class Data>
  177. class TCSafeLinkListIterator : public TIIterator<Data> {
  178. CLinkListIterator rep;
  179. public:
  180. inline
  181. TCSafeLinkListIterator(TCSafeLinkList<Data>& l) : rep(l)
  182. {}
  183. inline
  184. Data* next()
  185. {
  186. return (Data*) rep.next();
  187. }
  188. inline
  189. int finished()
  190. {
  191. return rep.finished();
  192. }
  193. };
  194. /*++
  195. Template Class Definition:
  196. TCGuardedLinkList
  197. Abstract:
  198. The template TCGuardedLinkList makes it easy to produce thread safe incarnations of
  199. the CLinkList class.
  200. The guarded linked list below uses a simple CSharedCriticalSection. A more complex
  201. version using a CReadWriteSection is also possible -- see the guarded skip
  202. list template as an example.
  203. Even though the template uses CSharedCriticalSection, "sem.hxx" is not included
  204. here -- it must be included before the template can be instantiated.
  205. The reason why the TCSafeLinkList<Data> object representation used underneath
  206. is a member rather than a private base is that the constructor and destructor
  207. calls on the representation must themselves be guarded .. Especially the
  208. latter because it does iterative release of links underneath, whereas those
  209. links may be shared by several iterators still outstanding. We guard the
  210. constructor basically "on principle", so any future changes to the representation
  211. will be transparent wrt thread safety.
  212. --*/
  213. #if (_MSC_VER >= 1100 && defined(__BOOL_DEFINED)) || defined(_AMD64_) || defined(IA64)
  214. template <class Data> class TCGuardedLinkListIterator;
  215. class CSharedCriticalSection;
  216. #endif
  217. template <class Data>
  218. class TCGuardedLinkList {
  219. friend class TCGuardedLinkListIterator<Data>;
  220. /* A Linked List is not a search oriented structure. It is therefore
  221. hard to justify a CReadWriteSection to guard it */
  222. CSharedCriticalSection *csLock; // shared with iterators
  223. TCSafeLinkList<Data> *psllRep; // links shared with iterators
  224. public:
  225. /* For those operations which are subject to any kind of exceptions,
  226. we must use SEH to avoid deadlock */
  227. TCGuardedLinkList() {
  228. csLock = new CSharedCriticalSection; // has ref count of 1 already
  229. csLock->Enter();
  230. __try {
  231. psllRep = new TCSafeLinkList<Data>();
  232. }
  233. __finally {
  234. csLock->Leave();
  235. }
  236. }
  237. ~TCGuardedLinkList() {
  238. csLock->Enter();
  239. __try {
  240. delete psllRep;
  241. }
  242. __finally {
  243. csLock->Leave();
  244. }
  245. csLock->release();
  246. }
  247. // since the following does not chase pointers and just reads a mem location
  248. // and especially since it is inline, I don't see a reason to guard it
  249. ULONG size() {
  250. return psllRep->size();
  251. }
  252. void enque(Data* x) {
  253. csLock->Enter();
  254. __try {
  255. psllRep->enque(x);
  256. }
  257. __finally {
  258. csLock->Leave();
  259. }
  260. }
  261. void push(Data* x) {
  262. csLock->Enter();
  263. __try {
  264. psllRep->push(x);
  265. }
  266. __finally {
  267. csLock->Leave();
  268. }
  269. }
  270. void catenate(TCGuardedLinkList& ll) {
  271. csLock->Enter();
  272. __try {
  273. psllRep->catenate(*ll.psllRep);
  274. }
  275. __finally {
  276. csLock->Leave();
  277. }
  278. }
  279. void rotate(long lDegree) {
  280. csLock->Enter();
  281. __try {
  282. psllRep->rotate(lDegree);
  283. }
  284. __finally {
  285. csLock->Leave();
  286. }
  287. }
  288. void insert(Data* x) {
  289. enque(x);
  290. }
  291. /* wipeOut may cause faults due to delete calls on stored items */
  292. void wipeOut() {
  293. csLock->Enter();
  294. __try {
  295. psllRep->wipeOut();
  296. }
  297. __finally {
  298. csLock->Leave();
  299. }
  300. }
  301. Data* pop() {
  302. csLock->Enter();
  303. Data* result = psllRep->pop();
  304. csLock->Leave();
  305. return result;
  306. }
  307. int remove(Data* x) {
  308. csLock->Enter();
  309. int result = psllRep->remove(x);
  310. csLock->Leave();
  311. return result;
  312. }
  313. Data* find(Data* x,int comp(Data*,Data*)) {
  314. csLock->Enter();
  315. Data* result = (Data*) psllRep->find(x,comp);
  316. csLock->Leave();
  317. return result;
  318. }
  319. Data* nth(long lOrdinal) {
  320. csLock->Enter();
  321. Data* result = psllRep->nth(lOrdinal);
  322. csLock->Leave();
  323. return result;
  324. }
  325. };
  326. /*++
  327. Template Class Definition:
  328. TCGuardedLinkListIterator
  329. Abstract:
  330. The iterator for TCGuardedLinkLists. It shares the CSharedCriticalSection
  331. object used to guard the list being iterated over.
  332. --*/
  333. template <class Data>
  334. class TCGuardedLinkListIterator : public TIIterator<Data> {
  335. CSharedCriticalSection* csLock; // shared
  336. TCSafeLinkListIterator<Data> *pSLLIiter; // not shared
  337. public:
  338. TCGuardedLinkListIterator(TCGuardedLinkList<Data>& l)
  339. : csLock(l.csLock)
  340. {
  341. /* Question: what if this csLock is released and self-destructs before
  342. this constructor can hold it?
  343. Answer: the guarded list must exist for it to be used as a parameter here,
  344. and the list has a reference to the csLock so it cannot self-destruct.
  345. However, a wipeOut call on the list concurrently with its use as a
  346. parameter to this constructor is a possibility, hence the construction
  347. process must be guarded.
  348. */
  349. csLock->hold();
  350. csLock->Enter();
  351. pSLLIiter = new TCSafeLinkListIterator<Data>(*(l.psllRep));
  352. csLock->Leave();
  353. }
  354. /* the destructor does not use the guard because if the iterator
  355. is being destroyed even though it is shared, we are in big
  356. trouble anyway -- it then ought to be reference counted!
  357. */
  358. ~TCGuardedLinkListIterator() {
  359. csLock->Enter();
  360. delete pSLLIiter;
  361. csLock->Leave();
  362. csLock->release();
  363. }
  364. Data* next() {
  365. Data* result;
  366. csLock->Enter();
  367. result = pSLLIiter->next();
  368. csLock->Leave();
  369. return result;
  370. }
  371. int finished() {
  372. int result;
  373. csLock->Enter();
  374. result = pSLLIiter->finished();
  375. csLock->Leave();
  376. return result;
  377. }
  378. };
  379. #endif // __LINKLIST_HXX_