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.

794 lines
23 KiB

  1. #ifdef __TANDEM
  2. #pragma columns 79
  3. #pragma page "srgputl.c - T9050 - utility routines for Regroup Module"
  4. #endif
  5. /* @@@ START COPYRIGHT @@@
  6. ** Tandem Confidential: Need to Know only
  7. ** Copyright (c) 1995, Tandem Computers Incorporated
  8. ** Protected as an unpublished work.
  9. ** All Rights Reserved.
  10. **
  11. ** The computer program listings, specifications, and documentation
  12. ** herein are the property of Tandem Computers Incorporated and shall
  13. ** not be reproduced, copied, disclosed, or used in whole or in part
  14. ** for any reason without the prior express written permission of
  15. ** Tandem Computers Incorporated.
  16. **
  17. ** @@@ END COPYRIGHT @@@
  18. **/
  19. /*---------------------------------------------------------------------------
  20. * This file (srgputl.c) contains the cluster_t data type implementation
  21. * and the node pruning algorithm used by Regroup.
  22. *---------------------------------------------------------------------------*/
  23. #ifdef __cplusplus
  24. extern "C" {
  25. #endif /* __cplusplus */
  26. #include <wrgp.h>
  27. /************************************************************************
  28. * ClusterInit,
  29. * ClusterUnion,
  30. * ClusterIntersection,
  31. * ClusterDifference,
  32. * ClusterCompare,
  33. * ClusterSubsetOf,
  34. * ClusterComplement,
  35. * ClusterMember,
  36. * ClusterInsert,
  37. * ClusterDelete,
  38. * ClusterCopy,
  39. * ClusterSwap,
  40. * ClusterNumMembers
  41. * =================
  42. *
  43. * Description:
  44. *
  45. * Functions that implement operations on the cluster_t type.
  46. *
  47. * Algorithm:
  48. *
  49. * Operates on the byte array that is the cluster_t type.
  50. *
  51. ************************************************************************/
  52. _priv _resident void
  53. ClusterInit(cluster_t c)
  54. {
  55. int i;
  56. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  57. c[i] = 0;
  58. }
  59. _priv _resident void
  60. ClusterUnion(cluster_t dst, cluster_t src1, cluster_t src2)
  61. {
  62. int i;
  63. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  64. dst[i] = src1[i] | src2[i];
  65. }
  66. _priv _resident void
  67. ClusterIntersection(cluster_t dst, cluster_t src1, cluster_t src2)
  68. {
  69. int i;
  70. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  71. dst[i] = src1[i] & src2[i];
  72. }
  73. _priv _resident void
  74. ClusterDifference(cluster_t dst, cluster_t src1, cluster_t src2)
  75. {
  76. int i;
  77. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  78. dst[i] = src1[i] & (~src2[i]);
  79. }
  80. _priv _resident int ClusterCompare(cluster_t c1, cluster_t c2)
  81. {
  82. int identical, i;
  83. identical = 1;
  84. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  85. {
  86. if (c1[i] != c2[i])
  87. {
  88. identical = 0;
  89. break;
  90. }
  91. }
  92. return(identical);
  93. }
  94. _priv _resident int ClusterSubsetOf(cluster_t big, cluster_t small)
  95. /* Returns 1 if set small = set big or small is a subset of big. */
  96. {
  97. int subset, i;
  98. subset = 1;
  99. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  100. {
  101. if ( (big[i] != small[i]) && ((big[i] ^ small[i]) & small[i]) )
  102. {
  103. subset = 0;
  104. break;
  105. }
  106. }
  107. return(subset);
  108. }
  109. _priv _resident void ClusterComplement(cluster_t dst, cluster_t src)
  110. {
  111. int i;
  112. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  113. dst[i] = ~src[i];
  114. }
  115. _priv _resident int ClusterMember(cluster_t c, node_t i)
  116. {
  117. return((BYTE(c,i) >> (BYTEL-1-BIT(i))) & 1);
  118. }
  119. _priv _resident void ClusterInsert(cluster_t c, node_t i)
  120. {
  121. BYTE(c, i) |= (1 << (BYTEL-1-BIT(i)));
  122. }
  123. _priv _resident void ClusterDelete(cluster_t c, node_t i)
  124. {
  125. BYTE(c, i) &= ~(1 << (BYTEL-1-BIT(i)));
  126. }
  127. _priv _resident void ClusterCopy(cluster_t dst, cluster_t src)
  128. {
  129. int i;
  130. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  131. dst[i] = src[i];
  132. }
  133. _priv _resident void ClusterSwap(cluster_t c1, cluster_t c2)
  134. {
  135. int i;
  136. unsigned char temp;
  137. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  138. {
  139. temp = c1[i];
  140. c1[i] = c2[i];
  141. c2[i] = temp;
  142. }
  143. }
  144. _priv _resident int ClusterNumMembers(cluster_t c)
  145. /* Returns the number of nodes in the cluster. */
  146. {
  147. int num_members = 0, i, j;
  148. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  149. {
  150. if (c[i])
  151. {
  152. for (j = 0; j < BYTEL; j++)
  153. if (c[i] & (1 << j))
  154. num_members++;
  155. }
  156. }
  157. return(num_members);
  158. }
  159. /************************************************************************
  160. * ClusterEmpty
  161. * =================
  162. *
  163. * Description:
  164. *
  165. * Checks that a cluster has no members
  166. *
  167. * Parameters:
  168. *
  169. * cluster_t c
  170. * cluster to be examined
  171. *
  172. * Returns:
  173. *
  174. * 0 - cluster contains at least one node
  175. * 1 - cluster is empty
  176. *
  177. * Comment:
  178. *
  179. * The proper place for this function is in srgputl.c
  180. *
  181. ************************************************************************/
  182. int ClusterEmpty(cluster_t c)
  183. {
  184. int i;
  185. for (i = 0; i < BYTES_IN_CLUSTER; i++)
  186. {
  187. if (c[i])
  188. {
  189. return 0;
  190. }
  191. }
  192. return 1;
  193. }
  194. /************************************************************************
  195. * rgp_select_tiebreaker
  196. * =====================
  197. *
  198. * Description:
  199. *
  200. * Simple algorithm to select the tie-breaker.
  201. *
  202. * Parameters:
  203. *
  204. * cluster_t cluster -
  205. * cluster from which a tie-breaker is to be selected
  206. *
  207. * Returns:
  208. *
  209. * node_t - the node number of the selected tie-breaker
  210. *
  211. * Algorithm:
  212. *
  213. * The tie-breaker is defined as the lowest numbered node in the
  214. * cluster.
  215. *
  216. ************************************************************************/
  217. _priv _resident node_t
  218. rgp_select_tiebreaker(cluster_t cluster)
  219. {
  220. node_t i;
  221. for (i = 0; (i < (node_t) rgp->num_nodes) && !ClusterMember(cluster, i); i++);
  222. /* If the cluster does not have any members, we have a problem! */
  223. if (i >= (node_t) rgp->num_nodes)
  224. RGP_ERROR(RGP_INTERNAL_ERROR);
  225. return(i);
  226. }
  227. /*---------------------------------------------------------------------------
  228. * Node pruning algorithm used by Regroup.
  229. *---------------------------------------------------------------------------
  230. */
  231. /************************************************************************
  232. * group_exists
  233. * ============
  234. *
  235. * Description:
  236. *
  237. * Check if a specific group already exists or is a subset of a
  238. * group that already exists.
  239. *
  240. * Parameters:
  241. *
  242. * cluster_t groups[] -
  243. * array of groups to examine
  244. *
  245. * int numgroups -
  246. * number of groups discovered so far
  247. *
  248. * cluster_t g -
  249. * specific group to check
  250. *
  251. * Returns:
  252. *
  253. * int - 1 if the specified group exists in the array; 0 therwise.
  254. *
  255. * Algorithm:
  256. *
  257. * Goes through the array and calls ClusterSubsetOf to check if the
  258. * specified group g is a subset of the the array element.
  259. *
  260. ************************************************************************/
  261. #if !defined(NT)
  262. _priv _resident static
  263. int
  264. #endif
  265. group_exists(cluster_t groups[], int numgroups, cluster_t g)
  266. {
  267. int exists, i;
  268. exists = 0;
  269. for (i = 0; i < numgroups; i++)
  270. {
  271. if (ClusterSubsetOf(groups[i],g))
  272. {
  273. exists = 1;
  274. break;
  275. }
  276. }
  277. return(exists);
  278. }
  279. /************************************************************************
  280. * prune
  281. * =====
  282. *
  283. * Description:
  284. *
  285. * Algorithm to find all fully connected groups based on # of
  286. * disconnects in the matrix.
  287. *
  288. * Parameters:
  289. *
  290. * disconnect_array disconnects -
  291. * input : array of disconnects
  292. *
  293. * int D -
  294. * input : size of disconnects array
  295. *
  296. * cluster_t live_nodes -
  297. * input : set of all live nodes
  298. *
  299. * cluster_t groups[] -
  300. * output: array of fully-connected groups
  301. *
  302. * Returns:
  303. *
  304. * int - the number of groups made; 0 if no groups or other error
  305. *
  306. * Algorithm:
  307. *
  308. * Start with one group that contains the set of live nodes.
  309. * More groups will be generated as disconnects are examined.
  310. *
  311. * Process each disconnect in the disconnects array by applying
  312. * the disconnect to the current set of fully-connected groups.
  313. *
  314. * The effect of a disconnect on a fully-conncted group depends on
  315. * whether the end points of the disconnect are in the group or not.
  316. *
  317. * If the group contains neither or only one of the endpoints of
  318. * the disconnect, the disconnect has no effect on the group.
  319. *
  320. * If both endpoints of the disconnect are in the group, then the
  321. * group is split into two groups - the original group without
  322. * endpoint 1 and the original group without endpoint 2.
  323. * New groups so generated should be discarded if they already
  324. * exist or are subsets of currently existing groups.
  325. *
  326. * After every disconnect is processed, we end up with the final
  327. * set of fully-connected groups.
  328. *
  329. ************************************************************************/
  330. #if !defined(NT)
  331. _priv _resident static
  332. #endif
  333. int
  334. prune(
  335. disconnect_array disconnects,
  336. int D,
  337. cluster_t live_nodes,
  338. cluster_t groups[])
  339. {
  340. int numgroups = 1, i, j;
  341. ClusterCopy(groups[0], live_nodes);
  342. for (i = 0; i < D; i ++)
  343. {
  344. for (j = 0; j < numgroups; j++)
  345. {
  346. /* Split a group that has both ends of the disconnect. */
  347. if (ClusterMember(groups[j],disconnects[i][0]) &&
  348. ClusterMember(groups[j],disconnects[i][1]))
  349. {
  350. /* Correct current group in place.
  351. * Add new group at the end of the array.
  352. */
  353. numgroups++;
  354. ClusterCopy(groups[numgroups-1], groups[j]);
  355. ClusterDelete(groups[j], disconnects[i][0]);
  356. ClusterDelete(groups[numgroups-1], disconnects[i][1]);
  357. /* Check if the new groups already exist or are subgroups
  358. * of existing groups.
  359. */
  360. /* First, check the group added at the end of the array. */
  361. if (group_exists(groups, numgroups-1, groups[numgroups-1]))
  362. numgroups--;
  363. /* Next, check the modified group at j.
  364. * To simplify the checking, switch it with the last element
  365. * of the array. If the group already exists, it should be
  366. * removed. Since the group is now the last element of the
  367. * array, removal requires only decrementing the array count.
  368. */
  369. ClusterSwap(groups[j], groups[numgroups-1]);
  370. if (group_exists(groups, numgroups-1, groups[numgroups-1]))
  371. numgroups--;
  372. j--; /* The j-th entry has been switched with the last entry;
  373. it has to be examined again */
  374. }
  375. }
  376. }
  377. return(numgroups);
  378. }
  379. /************************************************************************
  380. * select_group_with_designated_node
  381. * =================================
  382. *
  383. * Description:
  384. *
  385. * Function to pick an arbitrary fully connected group that
  386. * includes a specified node.
  387. *
  388. * Parameters:
  389. *
  390. * connectivity_matrix_t c -
  391. * input : cluster's connectivity info
  392. *
  393. * node_t selected_node -
  394. * input : just find a fully-connected group that includes this node
  395. *
  396. * cluster_t *group -
  397. * output: group that includes selected_node
  398. *
  399. * Returns:
  400. *
  401. * int - returns 1 if the specified node is alive and 0 if it is not
  402. *
  403. * Algorithm:
  404. *
  405. * Start with a group that includes just the selected node.
  406. * Then, examine nodes starting with node 0 and go up till the
  407. * largest node number. If a node is alive, include it in the group
  408. * if and only if it is connected to all current members of the
  409. * group.
  410. *
  411. * When all nodes are examined, we get a fully-connected group that
  412. * includes the selected node. This is only one of potentially many
  413. * fully-connected groups and is not necessarily the largest
  414. * solution.
  415. *
  416. * This order of examining nodes gives higher priority to lower
  417. * numbered nodes.
  418. *
  419. ************************************************************************/
  420. #if !defined(NT)
  421. _priv _resident static
  422. #endif
  423. int
  424. select_group_with_designated_node(
  425. connectivity_matrix_t c,
  426. node_t selected_node,
  427. cluster_t *group)
  428. {
  429. node_t i, j;
  430. if (!node_considered_alive(selected_node))
  431. return(0);
  432. else
  433. {
  434. ClusterInit(*group);
  435. ClusterInsert(*group, selected_node);
  436. for (i = 0; i < (node_t) rgp->num_nodes; i++)
  437. {
  438. if ((i != selected_node) &&
  439. node_considered_alive(i) &&
  440. connected(i, selected_node)
  441. )
  442. {
  443. /* Check if i is connected to all members of the group
  444. * built so far.
  445. */
  446. for (j = 0; j < i; j++)
  447. {
  448. if (ClusterMember(*group, j) && !connected(j, i))
  449. break;
  450. }
  451. if (j == i) /* i is connected to all current members*/
  452. ClusterInsert(*group, i);
  453. }
  454. }
  455. return(1);
  456. }
  457. }
  458. /************************************************************************
  459. * MatrixInit
  460. * ==========
  461. *
  462. * Description:
  463. *
  464. * Initialize the matrix c to show 0 connectivity.
  465. *
  466. * Parameters:
  467. *
  468. * connectivity_matrix_t c - matrix to be set to 0s.
  469. *
  470. * Returns:
  471. *
  472. * void - no return value
  473. *
  474. * Algorithm:
  475. *
  476. * Calls ClusterInit to initialize the clusters in the matrix.
  477. *
  478. ************************************************************************/
  479. _priv _resident void
  480. MatrixInit(connectivity_matrix_t c)
  481. {
  482. int i;
  483. for (i = 0; i < (node_t) rgp->num_nodes; i++)
  484. {
  485. ClusterInit(c[i]);
  486. }
  487. }
  488. /************************************************************************
  489. * MatrixSet
  490. * =========
  491. *
  492. * Description:
  493. *
  494. * Set matrix[row,column] to 1.
  495. *
  496. * Parameters:
  497. *
  498. * connectivity_matrix_t c - matrix to be modified
  499. *
  500. * int row - row number
  501. *
  502. * int column - column number
  503. *
  504. * Returns:
  505. *
  506. * void - no return value
  507. *
  508. * Algorithm:
  509. *
  510. * Calls ClusterInsert to set the appropriate bit (column) in the
  511. * appropriate cluster (row) in the matrix.
  512. *
  513. ************************************************************************/
  514. _priv _resident void
  515. MatrixSet(connectivity_matrix_t c, int row, int column)
  516. {
  517. ClusterInsert(c[row], (node_t) column);
  518. }
  519. /************************************************************************
  520. * MatrixOr
  521. * ========
  522. *
  523. * Description:
  524. *
  525. * matrix t := t OR s
  526. *
  527. * Parameters:
  528. *
  529. * connectivity_matrix_t t - target matrix
  530. *
  531. * connectivity_matrix_t s - source matrix to be ORed into target
  532. *
  533. * Returns:
  534. *
  535. * void - no return value
  536. *
  537. * Algorithm:
  538. *
  539. * Calls ClusterUnion to OR the appropriate clusters (rows) in the
  540. * matrices.
  541. *
  542. ************************************************************************/
  543. _priv _resident void
  544. MatrixOr(connectivity_matrix_t t, connectivity_matrix_t s)
  545. {
  546. int i;
  547. for (i = 0; i < (node_t) rgp->num_nodes; i++)
  548. ClusterUnion(t[i], s[i], t[i]);
  549. }
  550. /************************************************************************
  551. * connectivity_complete
  552. * =====================
  553. *
  554. * Description:
  555. *
  556. * Boolean function that checks if a given connectivity matrix implies
  557. * full connectivity (all nodes can talk to all others).
  558. *
  559. * Parameters:
  560. *
  561. * connectivity_matrix_t c - connectivity matrix of the cluster
  562. *
  563. * Returns:
  564. *
  565. * int - 0 if there are disconnects in the cluster; 1 if it has full
  566. * connectivity.
  567. *
  568. * Algorithm:
  569. *
  570. * Checks to see if there is any live node in the cluster that cannot
  571. * communicate to another live node in the cluster. Node i is
  572. * considered alive if c[i,i] is set. Nodes i and j are deemed to
  573. * be able to communicate if c[i,j] and c[j,i] are both set.
  574. *
  575. ************************************************************************/
  576. _priv _resident int
  577. connectivity_complete(connectivity_matrix_t c)
  578. {
  579. node_t i, j;
  580. for (i = 0; i < (node_t) rgp->num_nodes; i++)
  581. {
  582. if (node_considered_alive(i))
  583. {
  584. for (j = 0; j < i; j++)
  585. {
  586. if (node_considered_alive(j) && !connected(i, j))
  587. {
  588. /* i and j are a pair of live nodes which are not
  589. connected. Thus, there is at least one disconnect.
  590. Return 0. */
  591. return(0);
  592. }
  593. }
  594. }
  595. }
  596. /* No disconnects found; return 1. */
  597. return(1);
  598. }
  599. /************************************************************************
  600. * find_all_fully_connected_groups
  601. * ===============================
  602. *
  603. * Description:
  604. *
  605. * Function to find all fully connected groups in a graph specified
  606. * by a connectivity matrix. An optional "selected_node" can be
  607. * used to simplify the search in case of too large a number of
  608. * possibilities. In that case, a fully-connected group that
  609. * includes selected_node is returned.
  610. *
  611. * Parameters:
  612. *
  613. * connectivity_matrix_t c -
  614. * input : cluster's connectivity info
  615. *
  616. * node_t selected_node -
  617. * input : if there are too many potential groups, just find one
  618. * that includes this node; if all groups can be listed, ignore this.
  619. *
  620. * cluster_t groups[] -
  621. * output: array of potential clusters
  622. *
  623. * Returns:
  624. *
  625. * int - the number of groups made; 0 if no groups or other error
  626. *
  627. * Algorithm:
  628. *
  629. * First the set of live nodes and the set of disconnects in the
  630. * cluster are evaluated. Then, if the number of live nodes and
  631. * disconnects indicates a potentially large number of
  632. * possibilities, select_group_with_designated_node() is called to
  633. * limit the search to a group including the specified node.
  634. * Otherwise, prune() is called to get the list of all possible
  635. * fully-connected groups.
  636. *
  637. ************************************************************************/
  638. _priv _resident int
  639. find_all_fully_connected_groups(
  640. connectivity_matrix_t c,
  641. node_t selected_node,
  642. cluster_t groups[])
  643. {
  644. disconnect_array disconnects;
  645. cluster_t live_nodes;
  646. int num_livenodes = 0, num_disconnects = 0;
  647. node_t i, j;
  648. ClusterInit(live_nodes);
  649. for (i = 0; i < (node_t) rgp->num_nodes; i++)
  650. {
  651. if (node_considered_alive(i))
  652. {
  653. ClusterInsert(live_nodes, i);
  654. num_livenodes++;
  655. for (j = 0; j < i; j++)
  656. {
  657. if (node_considered_alive(j) && !connected(i, j))
  658. {
  659. /* i and j are a pair of live nodes which are not
  660. connected. */
  661. disconnects[num_disconnects][0] = i;
  662. disconnects[num_disconnects][1] = j;
  663. num_disconnects++;
  664. }
  665. }
  666. if (too_many_groups(num_livenodes, num_disconnects))
  667. {
  668. RGP_TRACE( "RGP Too many dis",
  669. num_livenodes, /* TRACE */
  670. num_disconnects, /* TRACE */
  671. 0, 0 ); /* TRACE */
  672. /* There may be too many choices to consider in reasonable
  673. * time/space. Just return a fully-connected group that
  674. * includes the selected node.
  675. */
  676. return(select_group_with_designated_node(c,selected_node,groups));
  677. }
  678. }
  679. }
  680. if (num_livenodes == 0)
  681. return(0);
  682. else
  683. return(prune(disconnects, num_disconnects, live_nodes, groups));
  684. }
  685. /*---------------------------------------------------------------------------*/
  686. #ifdef __cplusplus
  687. }
  688. #endif /* __cplusplus */
  689. #if 0
  690. History of changes to this file:
  691. -------------------------------------------------------------------------
  692. 1995, December 13 F40:KSK0610 /*F40:KSK06102.2*/
  693. This file is part of the portable Regroup Module used in the NonStop
  694. Kernel (NSK) and Loosely Coupled UNIX (LCU) operating systems. There
  695. are 10 files in the module - jrgp.h, jrgpos.h, wrgp.h, wrgpos.h,
  696. srgpif.c, srgpos.c, srgpsm.c, srgputl.c, srgpcli.c and srgpsvr.c.
  697. The last two are simulation files to test the Regroup Module on a
  698. UNIX workstation in user mode with processes simulating processor nodes
  699. and UDP datagrams used to send unacknowledged datagrams.
  700. This file was first submitted for release into NSK on 12/13/95.
  701. ------------------------------------------------------------------------------
  702. This change occurred on 19 Jan 1996 /*F40:MB06458.1*/
  703. Changes for phase IV Sierra message system release. Includes: /*F40:MB06458.2*/
  704. - Some cleanup of the code /*F40:MB06458.3*/
  705. - Increment KCCB counters to count the number of setup messages and /*F40:MB06458.4*/
  706. unsequenced messages sent. /*F40:MB06458.5*/
  707. - Fixed some bugs /*F40:MB06458.6*/
  708. - Disable interrupts before allocating broadcast sibs. /*F40:MB06458.7*/
  709. - Change per-packet-timeout to 5ms /*F40:MB06458.8*/
  710. - Make the regroup and powerfail broadcast use highest priority /*F40:MB06458.9*/
  711. tnet services queue. /*F40:MB06458.10*/
  712. - Call the millicode backdoor to get the processor status from SP /*F40:MB06458.11*/
  713. - Fixed expand bug in msg_listen_ and msg_readctrl_ /*F40:MB06458.12*/
  714. - Added enhancement to msngr_sendmsg_ so that clients do not need /*F40:MB06458.13*/
  715. to be unstoppable before calling this routine. /*F40:MB06458.14*/
  716. - Added new steps in the build file called /*F40:MB06458.15*/
  717. MSGSYS_C - compiles all the message system C files /*F40:MB06458.16*/
  718. MSDRIVER - compiles all the MSDriver files /*F40:MB06458.17*/
  719. REGROUP - compiles all the regroup files /*F40:MB06458.18*/
  720. - remove #pragma env libspace because we set it as a command line /*F40:MB06458.19*/
  721. parameter. /*F40:MB06458.20*/
  722. ----------------------------------------------------------------------- /*F40:MB06458.21*/
  723. #endif /* 0 - change descriptions */
  724.