ipc_splay.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1991,1990,1989 Carnegie Mellon University
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify and distribute this software and its
  7. * documentation is hereby granted, provided that both the copyright
  8. * notice and this permission notice appear in all copies of the
  9. * software, derivative works or modified versions, and any portions
  10. * thereof, and that both notices appear in supporting documentation.
  11. *
  12. * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13. * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14. * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15. *
  16. * Carnegie Mellon requests users of this software to return to
  17. *
  18. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  19. * School of Computer Science
  20. * Carnegie Mellon University
  21. * Pittsburgh PA 15213-3890
  22. *
  23. * any improvements or extensions that they make and grant Carnegie Mellon
  24. * the rights to redistribute these changes.
  25. */
  26. /*
  27. */
  28. /*
  29. * File: ipc/ipc_splay.c
  30. * Author: Rich Draves
  31. * Date: 1989
  32. *
  33. * Primitive splay tree operations.
  34. */
  35. #pragma GCC diagnostic error "-Wundef"
  36. #include <glue/gnulinux.h>
  37. #include <mach/port.h>
  38. #include <kern/assert.h>
  39. //#include <kern/macro_help.h>
  40. #include <ipc/ipc_entry.h>
  41. #include <ipc/ipc_splay.h>
  42. /*
  43. * Splay trees are self-adjusting binary search trees.
  44. * They have the following attractive properties:
  45. * 1) Space efficient; only two pointers per entry.
  46. * 2) Robust performance; amortized O(log n) per operation.
  47. * 3) Recursion not needed.
  48. * This makes them a good fall-back data structure for those
  49. * entries that don't fit into the lookup table.
  50. *
  51. * The paper by Sleator and Tarjan, JACM v. 32, no. 3, pp. 652-686,
  52. * describes the splaying operation. ipc_splay_prim_lookup
  53. * and ipc_splay_prim_assemble implement the top-down splay
  54. * described on p. 669.
  55. *
  56. * The tree is stored in an unassembled form. If ist_root is null,
  57. * then the tree has no entries. Otherwise, ist_name records
  58. * the value used for the last lookup. ist_root points to the
  59. * middle tree obtained from the top-down splay. ist_ltree and
  60. * ist_rtree point to left and right subtrees, whose entries
  61. * are all smaller (larger) than those in the middle tree.
  62. * ist_ltreep and ist_rtreep are pointers to fields in the
  63. * left and right subtrees. ist_ltreep points to the rchild field
  64. * of the largest entry in ltree, and ist_rtreep points to the
  65. * lchild field of the smallest entry in rtree. The pointed-to
  66. * fields aren't initialized. If the left (right) subtree is null,
  67. * then ist_ltreep (ist_rtreep) points to the ist_ltree (ist_rtree)
  68. * field in the splay structure itself.
  69. *
  70. * The primary advantage of the unassembled form is that repeated
  71. * unsuccessful lookups are efficient. In particular, an unsuccessful
  72. * lookup followed by an insert only requires one splaying operation.
  73. *
  74. * The traversal algorithm works via pointer inversion.
  75. * When descending down the tree, child pointers are reversed
  76. * to point back to the parent entry. When ascending,
  77. * the pointers are restored to their original value.
  78. *
  79. * The biggest potential problem with the splay tree implementation
  80. * is that the operations, even lookup, require an exclusive lock.
  81. * If IPC spaces are protected with exclusive locks, then
  82. * the splay tree doesn't require its own lock, and ist_lock/ist_unlock
  83. * needn't do anything. If IPC spaces are protected with read/write
  84. * locks then ist_lock/ist_unlock should provide exclusive access.
  85. *
  86. * If it becomes important to let lookups run in parallel,
  87. * or if the restructuring makes lookups too expensive, then
  88. * there is hope. Use a read/write lock on the splay tree.
  89. * Keep track of the number of entries in the tree. When doing
  90. * a lookup, first try a non-restructuring lookup with a read lock held,
  91. * with a bound (based on log of size of the tree) on the number of
  92. * entries to traverse. If the lookup runs up against the bound,
  93. * then take a write lock and do a reorganizing lookup.
  94. * This way, if lookups only access roughly balanced parts
  95. * of the tree, then lookups run in parallel and do no restructuring.
  96. *
  97. * The traversal algorithm currently requires an exclusive lock.
  98. * If that is a problem, the tree could be changed from an lchild/rchild
  99. * representation to a leftmost child/right sibling representation.
  100. * In conjunction with non-restructing lookups, this would let
  101. * lookups and traversals all run in parallel. But this representation
  102. * is more complicated and would slow down the operations.
  103. */
  104. /*
  105. * Boundary values to hand to ipc_splay_prim_lookup:
  106. */
  107. #define MACH_PORT_SMALLEST ((mach_port_t) 0)
  108. #define MACH_PORT_LARGEST ((mach_port_t) ~0)
  109. /*
  110. * Routine: ipc_splay_prim_lookup
  111. * Purpose:
  112. * Searches for the node labeled name in the splay tree.
  113. * Returns three nodes (treep, ltreep, rtreep) and
  114. * two pointers to nodes (ltreepp, rtreepp).
  115. *
  116. * ipc_splay_prim_lookup splits the supplied tree into
  117. * three subtrees, left, middle, and right, returned
  118. * in ltreep, treep, and rtreep.
  119. *
  120. * If name is present in the tree, then it is at
  121. * the root of the middle tree. Otherwise, the root
  122. * of the middle tree is the last node traversed.
  123. *
  124. * ipc_splay_prim_lookup returns a pointer into
  125. * the left subtree, to the rchild field of its
  126. * largest node, in ltreepp. It returns a pointer
  127. * into the right subtree, to the lchild field of its
  128. * smallest node, in rtreepp.
  129. */
  130. static void
  131. ipc_splay_prim_lookup(
  132. mach_port_t name,
  133. ipc_tree_entry_t tree,
  134. ipc_tree_entry_t *treep,
  135. ipc_tree_entry_t *ltreep,
  136. ipc_tree_entry_t **ltreepp,
  137. ipc_tree_entry_t *rtreep,
  138. ipc_tree_entry_t **rtreepp)
  139. {
  140. mach_port_t tname; /* temp name */
  141. ipc_tree_entry_t lchild, rchild; /* temp child pointers */
  142. assert(tree != ITE_NULL);
  143. #define link_left \
  144. MACRO_BEGIN \
  145. *ltreep = tree; \
  146. ltreep = &tree->ite_rchild; \
  147. tree = *ltreep; \
  148. MACRO_END
  149. #define link_right \
  150. MACRO_BEGIN \
  151. *rtreep = tree; \
  152. rtreep = &tree->ite_lchild; \
  153. tree = *rtreep; \
  154. MACRO_END
  155. #define rotate_left \
  156. MACRO_BEGIN \
  157. ipc_tree_entry_t temp = tree; \
  158. \
  159. tree = temp->ite_rchild; \
  160. temp->ite_rchild = tree->ite_lchild; \
  161. tree->ite_lchild = temp; \
  162. MACRO_END
  163. #define rotate_right \
  164. MACRO_BEGIN \
  165. ipc_tree_entry_t temp = tree; \
  166. \
  167. tree = temp->ite_lchild; \
  168. temp->ite_lchild = tree->ite_rchild; \
  169. tree->ite_rchild = temp; \
  170. MACRO_END
  171. while (name != (tname = tree->ite_name)) {
  172. if (name < tname) {
  173. /* descend to left */
  174. lchild = tree->ite_lchild;
  175. if (lchild == ITE_NULL)
  176. break;
  177. tname = lchild->ite_name;
  178. if ((name < tname) &&
  179. (lchild->ite_lchild != ITE_NULL))
  180. rotate_right;
  181. link_right;
  182. if ((name > tname) &&
  183. (lchild->ite_rchild != ITE_NULL))
  184. link_left;
  185. } else {
  186. /* descend to right */
  187. rchild = tree->ite_rchild;
  188. if (rchild == ITE_NULL)
  189. break;
  190. tname = rchild->ite_name;
  191. if ((name > tname) &&
  192. (rchild->ite_rchild != ITE_NULL))
  193. rotate_left;
  194. link_left;
  195. if ((name < tname) &&
  196. (rchild->ite_lchild != ITE_NULL))
  197. link_right;
  198. }
  199. assert(tree != ITE_NULL);
  200. }
  201. *treep = tree;
  202. *ltreepp = ltreep;
  203. *rtreepp = rtreep;
  204. #undef link_left
  205. #undef link_right
  206. #undef rotate_left
  207. #undef rotate_right
  208. }
  209. /*
  210. * Routine: ipc_splay_prim_assemble
  211. * Purpose:
  212. * Assembles the results of ipc_splay_prim_lookup
  213. * into a splay tree with the found node at the root.
  214. *
  215. * ltree and rtree are by-reference so storing
  216. * through ltreep and rtreep can change them.
  217. */
  218. static void
  219. ipc_splay_prim_assemble(
  220. ipc_tree_entry_t tree,
  221. ipc_tree_entry_t *ltree,
  222. ipc_tree_entry_t *ltreep,
  223. ipc_tree_entry_t *rtree,
  224. ipc_tree_entry_t *rtreep)
  225. {
  226. assert(tree != ITE_NULL);
  227. *ltreep = tree->ite_lchild;
  228. *rtreep = tree->ite_rchild;
  229. tree->ite_lchild = *ltree;
  230. tree->ite_rchild = *rtree;
  231. }
  232. /*
  233. * Routine: ipc_splay_tree_init
  234. * Purpose:
  235. * Initialize a raw splay tree for use.
  236. */
  237. void
  238. ipc_splay_tree_init(
  239. ipc_splay_tree_t splay)
  240. {
  241. splay->ist_root = ITE_NULL;
  242. }
  243. /*
  244. * Routine: ipc_splay_tree_pick
  245. * Purpose:
  246. * Picks and returns a random entry in a splay tree.
  247. * Returns FALSE if the splay tree is empty.
  248. */
  249. boolean_t
  250. ipc_splay_tree_pick(
  251. ipc_splay_tree_t splay,
  252. mach_port_t *namep,
  253. ipc_tree_entry_t *entryp)
  254. {
  255. ipc_tree_entry_t root;
  256. ist_lock(splay);
  257. root = splay->ist_root;
  258. if (root != ITE_NULL) {
  259. *namep = root->ite_name;
  260. *entryp = root;
  261. }
  262. ist_unlock(splay);
  263. return root != ITE_NULL;
  264. }
  265. /*
  266. * Routine: ipc_splay_tree_lookup
  267. * Purpose:
  268. * Finds an entry in a splay tree.
  269. * Returns ITE_NULL if not found.
  270. */
  271. ipc_tree_entry_t
  272. ipc_splay_tree_lookup(
  273. ipc_splay_tree_t splay,
  274. mach_port_t name)
  275. {
  276. ipc_tree_entry_t root;
  277. ist_lock(splay);
  278. root = splay->ist_root;
  279. if (root != ITE_NULL) {
  280. if (splay->ist_name != name) {
  281. ipc_splay_prim_assemble(root,
  282. &splay->ist_ltree, splay->ist_ltreep,
  283. &splay->ist_rtree, splay->ist_rtreep);
  284. ipc_splay_prim_lookup(name, root, &root,
  285. &splay->ist_ltree, &splay->ist_ltreep,
  286. &splay->ist_rtree, &splay->ist_rtreep);
  287. splay->ist_name = name;
  288. splay->ist_root = root;
  289. }
  290. if (name != root->ite_name)
  291. root = ITE_NULL;
  292. }
  293. ist_unlock(splay);
  294. return root;
  295. }
  296. /*
  297. * Routine: ipc_splay_tree_insert
  298. * Purpose:
  299. * Inserts a new entry into a splay tree.
  300. * The caller supplies a new entry.
  301. * The name can't already be present in the tree.
  302. */
  303. void
  304. ipc_splay_tree_insert(
  305. ipc_splay_tree_t splay,
  306. mach_port_t name,
  307. ipc_tree_entry_t entry)
  308. {
  309. ipc_tree_entry_t root;
  310. assert(entry != ITE_NULL);
  311. ist_lock(splay);
  312. root = splay->ist_root;
  313. if (root == ITE_NULL) {
  314. entry->ite_lchild = ITE_NULL;
  315. entry->ite_rchild = ITE_NULL;
  316. } else {
  317. if (splay->ist_name != name) {
  318. ipc_splay_prim_assemble(root,
  319. &splay->ist_ltree, splay->ist_ltreep,
  320. &splay->ist_rtree, splay->ist_rtreep);
  321. ipc_splay_prim_lookup(name, root, &root,
  322. &splay->ist_ltree, &splay->ist_ltreep,
  323. &splay->ist_rtree, &splay->ist_rtreep);
  324. }
  325. assert(root->ite_name != name);
  326. if (name < root->ite_name) {
  327. assert(root->ite_lchild == ITE_NULL);
  328. *splay->ist_ltreep = ITE_NULL;
  329. *splay->ist_rtreep = root;
  330. } else {
  331. assert(root->ite_rchild == ITE_NULL);
  332. *splay->ist_ltreep = root;
  333. *splay->ist_rtreep = ITE_NULL;
  334. }
  335. entry->ite_lchild = splay->ist_ltree;
  336. entry->ite_rchild = splay->ist_rtree;
  337. }
  338. entry->ite_name = name;
  339. splay->ist_root = entry;
  340. splay->ist_name = name;
  341. splay->ist_ltreep = &splay->ist_ltree;
  342. splay->ist_rtreep = &splay->ist_rtree;
  343. ist_unlock(splay);
  344. }
  345. /*
  346. * Routine: ipc_splay_tree_delete
  347. * Purpose:
  348. * Deletes an entry from a splay tree.
  349. * The name must be present in the tree.
  350. * Frees the entry.
  351. *
  352. * The "entry" argument isn't currently used.
  353. * Other implementations might want it, though.
  354. */
  355. void
  356. ipc_splay_tree_delete(
  357. ipc_splay_tree_t splay,
  358. mach_port_t name,
  359. ipc_tree_entry_t entry)
  360. {
  361. ipc_tree_entry_t root, saved;
  362. ist_lock(splay);
  363. root = splay->ist_root;
  364. assert(root != ITE_NULL);
  365. if (splay->ist_name != name) {
  366. ipc_splay_prim_assemble(root,
  367. &splay->ist_ltree, splay->ist_ltreep,
  368. &splay->ist_rtree, splay->ist_rtreep);
  369. ipc_splay_prim_lookup(name, root, &root,
  370. &splay->ist_ltree, &splay->ist_ltreep,
  371. &splay->ist_rtree, &splay->ist_rtreep);
  372. }
  373. assert(root->ite_name == name);
  374. assert(root == entry);
  375. *splay->ist_ltreep = root->ite_lchild;
  376. *splay->ist_rtreep = root->ite_rchild;
  377. ite_free(root);
  378. root = splay->ist_ltree;
  379. saved = splay->ist_rtree;
  380. if (root == ITE_NULL)
  381. root = saved;
  382. else if (saved != ITE_NULL) {
  383. /*
  384. * Find the largest node in the left subtree, and splay it
  385. * to the root. Then add the saved right subtree.
  386. */
  387. ipc_splay_prim_lookup(MACH_PORT_LARGEST, root, &root,
  388. &splay->ist_ltree, &splay->ist_ltreep,
  389. &splay->ist_rtree, &splay->ist_rtreep);
  390. ipc_splay_prim_assemble(root,
  391. &splay->ist_ltree, splay->ist_ltreep,
  392. &splay->ist_rtree, splay->ist_rtreep);
  393. assert(root->ite_rchild == ITE_NULL);
  394. root->ite_rchild = saved;
  395. }
  396. splay->ist_root = root;
  397. if (root != ITE_NULL) {
  398. splay->ist_name = root->ite_name;
  399. splay->ist_ltreep = &splay->ist_ltree;
  400. splay->ist_rtreep = &splay->ist_rtree;
  401. }
  402. ist_unlock(splay);
  403. }
  404. /*
  405. * Routine: ipc_splay_tree_split
  406. * Purpose:
  407. * Split a splay tree. Puts all entries smaller than "name"
  408. * into a new tree, "small".
  409. *
  410. * Doesn't do locking on "small", because nobody else
  411. * should be fiddling with the uninitialized tree.
  412. */
  413. void
  414. ipc_splay_tree_split(
  415. ipc_splay_tree_t splay,
  416. mach_port_t name,
  417. ipc_splay_tree_t small)
  418. {
  419. ipc_tree_entry_t root;
  420. ipc_splay_tree_init(small);
  421. ist_lock(splay);
  422. root = splay->ist_root;
  423. if (root != ITE_NULL) {
  424. /* lookup name, to get it (or last traversed) to the top */
  425. if (splay->ist_name != name) {
  426. ipc_splay_prim_assemble(root,
  427. &splay->ist_ltree, splay->ist_ltreep,
  428. &splay->ist_rtree, splay->ist_rtreep);
  429. ipc_splay_prim_lookup(name, root, &root,
  430. &splay->ist_ltree, &splay->ist_ltreep,
  431. &splay->ist_rtree, &splay->ist_rtreep);
  432. }
  433. if (root->ite_name < name) {
  434. /* root goes into small */
  435. *splay->ist_ltreep = root->ite_lchild;
  436. *splay->ist_rtreep = ITE_NULL;
  437. root->ite_lchild = splay->ist_ltree;
  438. assert(root->ite_rchild == ITE_NULL);
  439. small->ist_root = root;
  440. small->ist_name = root->ite_name;
  441. small->ist_ltreep = &small->ist_ltree;
  442. small->ist_rtreep = &small->ist_rtree;
  443. /* rtree goes into splay */
  444. root = splay->ist_rtree;
  445. splay->ist_root = root;
  446. if (root != ITE_NULL) {
  447. splay->ist_name = root->ite_name;
  448. splay->ist_ltreep = &splay->ist_ltree;
  449. splay->ist_rtreep = &splay->ist_rtree;
  450. }
  451. } else {
  452. /* root stays in splay */
  453. *splay->ist_ltreep = root->ite_lchild;
  454. root->ite_lchild = ITE_NULL;
  455. splay->ist_root = root;
  456. splay->ist_name = name;
  457. splay->ist_ltreep = &splay->ist_ltree;
  458. /* ltree goes into small */
  459. root = splay->ist_ltree;
  460. small->ist_root = root;
  461. if (root != ITE_NULL) {
  462. small->ist_name = root->ite_name;
  463. small->ist_ltreep = &small->ist_ltree;
  464. small->ist_rtreep = &small->ist_rtree;
  465. }
  466. }
  467. }
  468. ist_unlock(splay);
  469. }
  470. /*
  471. * Routine: ipc_splay_tree_join
  472. * Purpose:
  473. * Joins two splay trees. Merges the entries in "small",
  474. * which must all be smaller than the entries in "splay",
  475. * into "splay".
  476. */
  477. void
  478. ipc_splay_tree_join(
  479. ipc_splay_tree_t splay,
  480. ipc_splay_tree_t small)
  481. {
  482. ipc_tree_entry_t sroot;
  483. /* pull entries out of small */
  484. ist_lock(small);
  485. sroot = small->ist_root;
  486. if (sroot != ITE_NULL) {
  487. ipc_splay_prim_assemble(sroot,
  488. &small->ist_ltree, small->ist_ltreep,
  489. &small->ist_rtree, small->ist_rtreep);
  490. small->ist_root = ITE_NULL;
  491. }
  492. ist_unlock(small);
  493. /* put entries, if any, into splay */
  494. if (sroot != ITE_NULL) {
  495. ipc_tree_entry_t root;
  496. ist_lock(splay);
  497. root = splay->ist_root;
  498. if (root == ITE_NULL) {
  499. root = sroot;
  500. } else {
  501. /* get smallest entry in splay tree to top */
  502. if (splay->ist_name != MACH_PORT_SMALLEST) {
  503. ipc_splay_prim_assemble(root,
  504. &splay->ist_ltree, splay->ist_ltreep,
  505. &splay->ist_rtree, splay->ist_rtreep);
  506. ipc_splay_prim_lookup(MACH_PORT_SMALLEST,
  507. root, &root,
  508. &splay->ist_ltree, &splay->ist_ltreep,
  509. &splay->ist_rtree, &splay->ist_rtreep);
  510. }
  511. ipc_splay_prim_assemble(root,
  512. &splay->ist_ltree, splay->ist_ltreep,
  513. &splay->ist_rtree, splay->ist_rtreep);
  514. assert(root->ite_lchild == ITE_NULL);
  515. assert(sroot->ite_name < root->ite_name);
  516. root->ite_lchild = sroot;
  517. }
  518. splay->ist_root = root;
  519. splay->ist_name = root->ite_name;
  520. splay->ist_ltreep = &splay->ist_ltree;
  521. splay->ist_rtreep = &splay->ist_rtree;
  522. ist_unlock(splay);
  523. }
  524. }
  525. /*
  526. * Routine: ipc_splay_tree_bounds
  527. * Purpose:
  528. * Given a name, returns the largest value present
  529. * in the tree that is smaller than or equal to the name,
  530. * or ~0 if no such value exists. Similarly, returns
  531. * the smallest value present that is greater than or
  532. * equal to the name, or 0 if no such value exists.
  533. *
  534. * Hence, if
  535. * lower = upper, then lower = name = upper
  536. * and name is present in the tree
  537. * lower = ~0 and upper = 0,
  538. * then the tree is empty
  539. * lower = ~0 and upper > 0, then name < upper
  540. * and upper is smallest value in tree
  541. * lower < ~0 and upper = 0, then lower < name
  542. * and lower is largest value in tree
  543. * lower < ~0 and upper > 0, then lower < name < upper
  544. * and they are tight bounds on name
  545. *
  546. * (Note MACH_PORT_SMALLEST = 0 and MACH_PORT_LARGEST = ~0.)
  547. */
  548. void
  549. ipc_splay_tree_bounds(
  550. ipc_splay_tree_t splay,
  551. mach_port_t name,
  552. mach_port_t *lowerp,
  553. mach_port_t *upperp)
  554. {
  555. ipc_tree_entry_t root;
  556. ist_lock(splay);
  557. root = splay->ist_root;
  558. if (root == ITE_NULL) {
  559. *lowerp = MACH_PORT_LARGEST;
  560. *upperp = MACH_PORT_SMALLEST;
  561. } else {
  562. mach_port_t rname;
  563. if (splay->ist_name != name) {
  564. ipc_splay_prim_assemble(root,
  565. &splay->ist_ltree, splay->ist_ltreep,
  566. &splay->ist_rtree, splay->ist_rtreep);
  567. ipc_splay_prim_lookup(name, root, &root,
  568. &splay->ist_ltree, &splay->ist_ltreep,
  569. &splay->ist_rtree, &splay->ist_rtreep);
  570. splay->ist_name = name;
  571. splay->ist_root = root;
  572. }
  573. rname = root->ite_name;
  574. /*
  575. * OK, it's a hack. We convert the ltreep and rtreep
  576. * pointers back into real entry pointers,
  577. * so we can pick the names out of the entries.
  578. */
  579. if (rname <= name)
  580. *lowerp = rname;
  581. else if (splay->ist_ltreep == &splay->ist_ltree)
  582. *lowerp = MACH_PORT_LARGEST;
  583. else {
  584. ipc_tree_entry_t entry;
  585. entry = (ipc_tree_entry_t)
  586. ((char *)splay->ist_ltreep -
  587. ((char *)&root->ite_rchild -
  588. (char *)root));
  589. *lowerp = entry->ite_name;
  590. }
  591. if (rname >= name)
  592. *upperp = rname;
  593. else if (splay->ist_rtreep == &splay->ist_rtree)
  594. *upperp = MACH_PORT_SMALLEST;
  595. else {
  596. ipc_tree_entry_t entry;
  597. entry = (ipc_tree_entry_t)
  598. ((char *)splay->ist_rtreep -
  599. ((char *)&root->ite_lchild -
  600. (char *)root));
  601. *upperp = entry->ite_name;
  602. }
  603. }
  604. ist_unlock(splay);
  605. }
  606. /*
  607. * Routine: ipc_splay_traverse_start
  608. * Routine: ipc_splay_traverse_next
  609. * Routine: ipc_splay_traverse_finish
  610. * Purpose:
  611. * Perform a symmetric order traversal of a splay tree.
  612. * Usage:
  613. * for (entry = ipc_splay_traverse_start(splay);
  614. * entry != ITE_NULL;
  615. * entry = ipc_splay_traverse_next(splay, delete)) {
  616. * do something with entry
  617. * }
  618. * ipc_splay_traverse_finish(splay);
  619. *
  620. * If "delete" is TRUE, then the current entry
  621. * is removed from the tree and deallocated.
  622. *
  623. * During the traversal, the splay tree is locked.
  624. */
  625. ipc_tree_entry_t
  626. ipc_splay_traverse_start(
  627. ipc_splay_tree_t splay)
  628. {
  629. ipc_tree_entry_t current, parent;
  630. ist_lock(splay);
  631. current = splay->ist_root;
  632. if (current != ITE_NULL) {
  633. ipc_splay_prim_assemble(current,
  634. &splay->ist_ltree, splay->ist_ltreep,
  635. &splay->ist_rtree, splay->ist_rtreep);
  636. parent = ITE_NULL;
  637. while (current->ite_lchild != ITE_NULL) {
  638. ipc_tree_entry_t next;
  639. next = current->ite_lchild;
  640. current->ite_lchild = parent;
  641. parent = current;
  642. current = next;
  643. }
  644. splay->ist_ltree = current;
  645. splay->ist_rtree = parent;
  646. }
  647. return current;
  648. }
  649. ipc_tree_entry_t
  650. ipc_splay_traverse_next(
  651. ipc_splay_tree_t splay,
  652. boolean_t delete)
  653. {
  654. ipc_tree_entry_t current, parent;
  655. /* pick up where traverse_entry left off */
  656. current = splay->ist_ltree;
  657. parent = splay->ist_rtree;
  658. assert(current != ITE_NULL);
  659. if (!delete)
  660. goto traverse_right;
  661. /* we must delete current and patch the tree */
  662. if (current->ite_lchild == ITE_NULL) {
  663. if (current->ite_rchild == ITE_NULL) {
  664. /* like traverse_back, but with deletion */
  665. if (parent == ITE_NULL) {
  666. ite_free(current);
  667. splay->ist_root = ITE_NULL;
  668. return ITE_NULL;
  669. }
  670. if (current->ite_name < parent->ite_name) {
  671. ite_free(current);
  672. current = parent;
  673. parent = current->ite_lchild;
  674. current->ite_lchild = ITE_NULL;
  675. goto traverse_entry;
  676. } else {
  677. ite_free(current);
  678. current = parent;
  679. parent = current->ite_rchild;
  680. current->ite_rchild = ITE_NULL;
  681. goto traverse_back;
  682. }
  683. } else {
  684. ipc_tree_entry_t prev;
  685. prev = current;
  686. current = current->ite_rchild;
  687. ite_free(prev);
  688. goto traverse_left;
  689. }
  690. } else {
  691. if (current->ite_rchild == ITE_NULL) {
  692. ipc_tree_entry_t prev;
  693. prev = current;
  694. current = current->ite_lchild;
  695. ite_free(prev);
  696. goto traverse_back;
  697. } else {
  698. ipc_tree_entry_t prev;
  699. ipc_tree_entry_t ltree, rtree;
  700. ipc_tree_entry_t *ltreep, *rtreep;
  701. /* replace current with largest of left children */
  702. prev = current;
  703. ipc_splay_prim_lookup(MACH_PORT_LARGEST,
  704. current->ite_lchild, &current,
  705. &ltree, &ltreep, &rtree, &rtreep);
  706. ipc_splay_prim_assemble(current,
  707. &ltree, ltreep, &rtree, rtreep);
  708. assert(current->ite_rchild == ITE_NULL);
  709. current->ite_rchild = prev->ite_rchild;
  710. ite_free(prev);
  711. goto traverse_right;
  712. }
  713. }
  714. /*NOTREACHED*/
  715. /*
  716. * A state machine: for each entry, we
  717. * 1) traverse left subtree
  718. * 2) traverse the entry
  719. * 3) traverse right subtree
  720. * 4) traverse back to parent
  721. */
  722. traverse_left:
  723. if (current->ite_lchild != ITE_NULL) {
  724. ipc_tree_entry_t next;
  725. next = current->ite_lchild;
  726. current->ite_lchild = parent;
  727. parent = current;
  728. current = next;
  729. goto traverse_left;
  730. }
  731. traverse_entry:
  732. splay->ist_ltree = current;
  733. splay->ist_rtree = parent;
  734. return current;
  735. traverse_right:
  736. if (current->ite_rchild != ITE_NULL) {
  737. ipc_tree_entry_t next;
  738. next = current->ite_rchild;
  739. current->ite_rchild = parent;
  740. parent = current;
  741. current = next;
  742. goto traverse_left;
  743. }
  744. traverse_back:
  745. if (parent == ITE_NULL) {
  746. splay->ist_root = current;
  747. return ITE_NULL;
  748. }
  749. if (current->ite_name < parent->ite_name) {
  750. ipc_tree_entry_t prev;
  751. prev = current;
  752. current = parent;
  753. parent = current->ite_lchild;
  754. current->ite_lchild = prev;
  755. goto traverse_entry;
  756. } else {
  757. ipc_tree_entry_t prev;
  758. prev = current;
  759. current = parent;
  760. parent = current->ite_rchild;
  761. current->ite_rchild = prev;
  762. goto traverse_back;
  763. }
  764. }
  765. void
  766. ipc_splay_traverse_finish(
  767. ipc_splay_tree_t splay)
  768. {
  769. ipc_tree_entry_t root;
  770. root = splay->ist_root;
  771. if (root != ITE_NULL) {
  772. splay->ist_name = root->ite_name;
  773. splay->ist_ltreep = &splay->ist_ltree;
  774. splay->ist_rtreep = &splay->ist_rtree;
  775. }
  776. ist_unlock(splay);
  777. }