aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing_group.c
diff options
context:
space:
mode:
authorNathan S. Evans <evans@in.tum.de>2011-02-05 14:19:42 +0000
committerNathan S. Evans <evans@in.tum.de>2011-02-05 14:19:42 +0000
commit5d67c7671b669eec8d63d3af345217bcf10768fd (patch)
treee1abf089630ba9d540f97b2d67fda0073744e247 /src/testing/testing_group.c
parent59b233b7e3b3d70006fc8b40bd566e67bc487231 (diff)
downloadgnunet-5d67c7671b669eec8d63d3af345217bcf10768fd.tar.gz
gnunet-5d67c7671b669eec8d63d3af345217bcf10768fd.zip
configurable connect options
Diffstat (limited to 'src/testing/testing_group.c')
-rw-r--r--src/testing/testing_group.c109
1 files changed, 79 insertions, 30 deletions
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c
index 24a98e612..929cc9128 100644
--- a/src/testing/testing_group.c
+++ b/src/testing/testing_group.c
@@ -53,21 +53,11 @@
53 */ 53 */
54#define HIGH_PORT 56000 54#define HIGH_PORT 56000
55 55
56#define MAX_OUTSTANDING_CONNECTIONS 200
57
58/* Maximum time to delay connect attempt */ 56/* Maximum time to delay connect attempt */
59#define MAX_CONNECT_DELAY 300 57#define MAX_CONNECT_DELAY 300
60 58
61#define MAX_CONCURRENT_HOSTKEYS 500 59#define MAX_CONCURRENT_HOSTKEYS 500
62 60
63#define MAX_CONCURRENT_STARTING 200
64
65#define MAX_CONCURRENT_SHUTDOWN 200
66
67#define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
68
69#define CONNECT_ATTEMPTS 12
70
71/** 61/**
72 * Which list of peers do we need to modify? 62 * Which list of peers do we need to modify?
73 */ 63 */
@@ -106,6 +96,11 @@ typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct
106struct ChurnContext 96struct ChurnContext
107{ 97{
108 /** 98 /**
99 * The peergroup we are dealing with.
100 */
101 struct GNUNET_TESTING_PeerGroup *pg;
102
103 /**
109 * Callback used to notify of churning finished 104 * Callback used to notify of churning finished
110 */ 105 */
111 GNUNET_TESTING_NotifyCompletion cb; 106 GNUNET_TESTING_NotifyCompletion cb;
@@ -168,6 +163,7 @@ struct RestartContext
168 163
169struct ShutdownContext 164struct ShutdownContext
170{ 165{
166 struct GNUNET_TESTING_PeerGroup *pg;
171 /** 167 /**
172 * Total peers to wait for 168 * Total peers to wait for
173 */ 169 */
@@ -349,6 +345,11 @@ struct InternalStartContext
349struct ChurnRestartContext 345struct ChurnRestartContext
350{ 346{
351 /** 347 /**
348 * PeerGroup that we are working with.
349 */
350 struct GNUNET_TESTING_PeerGroup *pg;
351
352 /**
352 * Number of restarts currently in flight. 353 * Number of restarts currently in flight.
353 */ 354 */
354 unsigned int outstanding; 355 unsigned int outstanding;
@@ -494,6 +495,11 @@ struct HostData
494struct TopologyIterateContext 495struct TopologyIterateContext
495{ 496{
496 /** 497 /**
498 * The peergroup we are working with.
499 */
500 struct GNUNET_TESTING_PeerGroup *pg;
501
502 /**
497 * Callback for notifying of two connected peers. 503 * Callback for notifying of two connected peers.
498 */ 504 */
499 GNUNET_TESTING_NotifyTopology topology_cb; 505 GNUNET_TESTING_NotifyTopology topology_cb;
@@ -522,6 +528,11 @@ struct TopologyIterateContext
522struct StatsIterateContext 528struct StatsIterateContext
523{ 529{
524 /** 530 /**
531 * The peergroup that we are dealing with.
532 */
533 struct GNUNET_TESTING_PeerGroup *pg;
534
535 /**
525 * Continuation to call once all stats information has been retrieved. 536 * Continuation to call once all stats information has been retrieved.
526 */ 537 */
527 GNUNET_STATISTICS_Callback cont; 538 GNUNET_STATISTICS_Callback cont;
@@ -639,6 +650,18 @@ struct GNUNET_TESTING_PeerGroup
639 unsigned int started; 650 unsigned int started;
640 651
641 /** 652 /**
653 * Number of possible connections to peers
654 * at a time.
655 */
656 unsigned int max_outstanding_connections;
657
658 /**
659 * Number of connects we are waiting on, allows us to rate limit
660 * connect attempts.
661 */
662 unsigned int outstanding_connects;
663
664 /**
642 * Hostkeys loaded from a file. 665 * Hostkeys loaded from a file.
643 */ 666 */
644 char *hostkey_data; 667 char *hostkey_data;
@@ -701,6 +724,16 @@ struct ConnectContext
701 struct ConnectTopologyContext *ct_ctx; 724 struct ConnectTopologyContext *ct_ctx;
702 725
703 /** 726 /**
727 * How long to try this connection before timing out.
728 */
729 struct GNUNET_TIME_Relative connect_timeout;
730
731 /**
732 * How many times to retry connecting the two peers.
733 */
734 unsigned int connect_attempts;
735
736 /**
704 * Whether this connection has been accounted for in the schedule_connect call. 737 * Whether this connection has been accounted for in the schedule_connect call.
705 */ 738 */
706 int counted; 739 int counted;
@@ -837,12 +870,6 @@ uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid)
837#endif 870#endif
838 871
839/** 872/**
840 * Number of connects we are waiting on, allows us to rate limit
841 * connect attempts.
842 */
843static int outstanding_connects;
844
845/**
846 * Get a topology from a string input. 873 * Get a topology from a string input.
847 * 874 *
848 * @param topology where to write the retrieved topology 875 * @param topology where to write the retrieved topology
@@ -2806,7 +2833,7 @@ internal_connect_notify (void *cls,
2806{ 2833{
2807 struct ConnectTopologyContext *ct_ctx = cls; 2834 struct ConnectTopologyContext *ct_ctx = cls;
2808 struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; 2835 struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg;
2809 outstanding_connects--; 2836 pg->outstanding_connects--;
2810 ct_ctx->remaining_connections--; 2837 ct_ctx->remaining_connections--;
2811 if (ct_ctx->remaining_connections == 0) 2838 if (ct_ctx->remaining_connections == 0)
2812 { 2839 {
@@ -2833,11 +2860,12 @@ static void
2833schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 2860schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2834{ 2861{
2835 struct ConnectContext *connect_context = cls; 2862 struct ConnectContext *connect_context = cls;
2863 struct GNUNET_TESTING_PeerGroup *pg = connect_context->ct_ctx->pg;
2836 2864
2837 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) 2865 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2838 return; 2866 return;
2839 2867
2840 if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS) 2868 if (pg->outstanding_connects > pg->max_outstanding_connections)
2841 { 2869 {
2842#if VERBOSE_TESTING > 2 2870#if VERBOSE_TESTING > 2
2843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2855,11 +2883,11 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2855 _("Creating connection, outstanding_connections is %d\n"), 2883 _("Creating connection, outstanding_connections is %d\n"),
2856 outstanding_connects); 2884 outstanding_connects);
2857#endif 2885#endif
2858 outstanding_connects++; 2886 pg->outstanding_connects++;
2859 GNUNET_TESTING_daemons_connect (connect_context->first, 2887 GNUNET_TESTING_daemons_connect (connect_context->first,
2860 connect_context->second, 2888 connect_context->second,
2861 CONNECT_TIMEOUT, 2889 connect_context->connect_timeout,
2862 CONNECT_ATTEMPTS, 2890 connect_context->connect_attempts,
2863 &internal_connect_notify, 2891 &internal_connect_notify,
2864 connect_context->ct_ctx); 2892 connect_context->ct_ctx);
2865 GNUNET_free (connect_context); 2893 GNUNET_free (connect_context);
@@ -2970,6 +2998,8 @@ copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
2970 * of each peer in the peer group 2998 * of each peer in the peer group
2971 * 2999 *
2972 * @param pg the peer group we are dealing with 3000 * @param pg the peer group we are dealing with
3001 * @param connect_timeout how long try connecting two peers
3002 * @param connect_attempts how many times (max) to attempt
2973 * @param notify_callback callback to notify when finished 3003 * @param notify_callback callback to notify when finished
2974 * @param notify_cls closure for notify callback 3004 * @param notify_cls closure for notify callback
2975 * 3005 *
@@ -2977,6 +3007,8 @@ copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
2977 */ 3007 */
2978static int 3008static int
2979connect_topology (struct GNUNET_TESTING_PeerGroup *pg, 3009connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
3010 struct GNUNET_TIME_Relative connect_timeout,
3011 unsigned int connect_attempts,
2980 GNUNET_TESTING_NotifyCompletion notify_callback, 3012 GNUNET_TESTING_NotifyCompletion notify_callback,
2981 void *notify_cls) 3013 void *notify_cls)
2982{ 3014{
@@ -3030,6 +3062,8 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
3030 connect_context->first = pg->peers[pg_iter].daemon; 3062 connect_context->first = pg->peers[pg_iter].daemon;
3031 connect_context->second = pg->peers[connection_iter->index].daemon; 3063 connect_context->second = pg->peers[connection_iter->index].daemon;
3032 connect_context->ct_ctx = ct_ctx; 3064 connect_context->ct_ctx = ct_ctx;
3065 connect_context->connect_timeout = connect_timeout;
3066 connect_context->connect_attempts = connect_attempts;
3033 GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); 3067 GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
3034 connection_iter = connection_iter->next; 3068 connection_iter = connection_iter->next;
3035 total++; 3069 total++;
@@ -4010,7 +4044,7 @@ schedule_get_topology (void *cls,
4010 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) 4044 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
4011 return; 4045 return;
4012 4046
4013 if (topology_context->connected > MAX_OUTSTANDING_CONNECTIONS) 4047 if (topology_context->connected > topology_context->pg->max_outstanding_connections)
4014 { 4048 {
4015#if VERBOSE_TESTING > 2 4049#if VERBOSE_TESTING > 2
4016 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -4058,6 +4092,7 @@ GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg,
4058 topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext)); 4092 topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext));
4059 topology_context->topology_cb = cb; 4093 topology_context->topology_cb = cb;
4060 topology_context->cls = cls; 4094 topology_context->cls = cls;
4095 topology_context->pg = pg;
4061 total_count = 0; 4096 total_count = 0;
4062 for (i = 0; i < pg->total; i++) 4097 for (i = 0; i < pg->total; i++)
4063 { 4098 {
@@ -4152,7 +4187,7 @@ schedule_get_statistics (void *cls,
4152 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) 4187 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
4153 return; 4188 return;
4154 4189
4155 if (stats_context->connected > MAX_OUTSTANDING_CONNECTIONS) 4190 if (stats_context->connected > stats_context->pg->max_outstanding_connections)
4156 { 4191 {
4157#if VERBOSE_TESTING > 2 4192#if VERBOSE_TESTING > 2
4158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -4290,6 +4325,7 @@ GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg,
4290 stats_context->cont = cont; 4325 stats_context->cont = cont;
4291 stats_context->proc = proc; 4326 stats_context->proc = proc;
4292 stats_context->cls = cls; 4327 stats_context->cls = cls;
4328 stats_context->pg = pg;
4293 total_count = 0; 4329 total_count = 0;
4294 4330
4295 for (i = 0; i < pg->total; i++) 4331 for (i = 0; i < pg->total; i++)
@@ -4338,6 +4374,10 @@ GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg,
4338 * @param topology which topology to connect the peers in 4374 * @param topology which topology to connect the peers in
4339 * @param options options for connecting the topology 4375 * @param options options for connecting the topology
4340 * @param option_modifier modifier for options that take a parameter 4376 * @param option_modifier modifier for options that take a parameter
4377 * @param connect_timeout how long to wait before giving up on connecting
4378 * two peers
4379 * @param connect_attempts how many times to attempt to connect two peers
4380 * over the connect_timeout duration
4341 * @param notify_callback notification to be called once all connections completed 4381 * @param notify_callback notification to be called once all connections completed
4342 * @param notify_cls closure for notification callback 4382 * @param notify_cls closure for notification callback
4343 * 4383 *
@@ -4348,6 +4388,8 @@ GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
4348 enum GNUNET_TESTING_Topology topology, 4388 enum GNUNET_TESTING_Topology topology,
4349 enum GNUNET_TESTING_TopologyOption options, 4389 enum GNUNET_TESTING_TopologyOption options,
4350 double option_modifier, 4390 double option_modifier,
4391 struct GNUNET_TIME_Relative connect_timeout,
4392 unsigned int connect_attempts,
4351 GNUNET_TESTING_NotifyCompletion 4393 GNUNET_TESTING_NotifyCompletion
4352 notify_callback, void *notify_cls) 4394 notify_callback, void *notify_cls)
4353{ 4395{
@@ -4480,7 +4522,7 @@ GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
4480 break; 4522 break;
4481 } 4523 }
4482 4524
4483 return connect_topology (pg, notify_callback, notify_cls); 4525 return connect_topology (pg, connect_timeout, connect_attempts, notify_callback, notify_cls);
4484} 4526}
4485 4527
4486/** 4528/**
@@ -4547,7 +4589,7 @@ internal_continue_startup (void *cls,
4547 return; 4589 return;
4548 } 4590 }
4549 4591
4550 if (internal_context->peer->pg->starting < MAX_CONCURRENT_STARTING) 4592 if (internal_context->peer->pg->starting < internal_context->peer->pg->max_outstanding_connections)
4551 { 4593 {
4552 internal_context->peer->pg->starting++; 4594 internal_context->peer->pg->starting++;
4553 GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon); 4595 GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
@@ -4630,7 +4672,7 @@ schedule_churn_restart (void *cls,
4630 struct ChurnRestartContext *startup_ctx = 4672 struct ChurnRestartContext *startup_ctx =
4631 peer_restart_ctx->churn_restart_ctx; 4673 peer_restart_ctx->churn_restart_ctx;
4632 4674
4633 if (startup_ctx->outstanding > MAX_CONCURRENT_STARTING) 4675 if (startup_ctx->outstanding > startup_ctx->pg->max_outstanding_connections)
4634 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 4676 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4635 (GNUNET_TIME_UNIT_MILLISECONDS, 100), 4677 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4636 &schedule_churn_restart, peer_restart_ctx); 4678 &schedule_churn_restart, peer_restart_ctx);
@@ -4706,6 +4748,8 @@ GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg)
4706 * 4748 *
4707 * @param cfg configuration template to use 4749 * @param cfg configuration template to use
4708 * @param total number of daemons to start 4750 * @param total number of daemons to start
4751 * @param max_concurrent_connections for testing, how many peers can
4752 * we connect to simultaneously
4709 * @param timeout total time allowed for peers to start 4753 * @param timeout total time allowed for peers to start
4710 * @param hostkey_callback function to call on each peers hostkey generation 4754 * @param hostkey_callback function to call on each peers hostkey generation
4711 * if NULL, peers will be started by this call, if non-null, 4755 * if NULL, peers will be started by this call, if non-null,
@@ -4724,6 +4768,7 @@ GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg)
4724struct GNUNET_TESTING_PeerGroup * 4768struct GNUNET_TESTING_PeerGroup *
4725GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, 4769GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
4726 unsigned int total, 4770 unsigned int total,
4771 unsigned int max_concurrent_connections,
4727 struct GNUNET_TIME_Relative timeout, 4772 struct GNUNET_TIME_Relative timeout,
4728 GNUNET_TESTING_NotifyHostkeyCreated 4773 GNUNET_TESTING_NotifyHostkeyCreated
4729 hostkey_callback, void *hostkey_cls, 4774 hostkey_callback, void *hostkey_cls,
@@ -4776,6 +4821,7 @@ GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
4776 pg->total = total; 4821 pg->total = total;
4777 pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); 4822 pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
4778 pg->peers = GNUNET_malloc (total * sizeof (struct PeerData)); 4823 pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
4824 pg->max_outstanding_connections = max_concurrent_connections;
4779 if (NULL != hostnames) 4825 if (NULL != hostnames)
4780 { 4826 {
4781 off = 0; 4827 off = 0;
@@ -5176,12 +5222,12 @@ schedule_churn_shutdown_task (void *cls,
5176{ 5222{
5177 struct PeerShutdownContext *peer_shutdown_ctx = cls; 5223 struct PeerShutdownContext *peer_shutdown_ctx = cls;
5178 struct ShutdownContext *shutdown_ctx; 5224 struct ShutdownContext *shutdown_ctx;
5179 5225 struct ChurnContext *churn_ctx;
5180 GNUNET_assert (peer_shutdown_ctx != NULL); 5226 GNUNET_assert (peer_shutdown_ctx != NULL);
5181 shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; 5227 shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
5182 GNUNET_assert (shutdown_ctx != NULL); 5228 GNUNET_assert (shutdown_ctx != NULL);
5183 5229 churn_ctx = (struct ChurnContext *)shutdown_ctx->cb_cls;
5184 if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN) 5230 if (shutdown_ctx->outstanding > churn_ctx->pg->max_outstanding_connections)
5185 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 5231 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
5186 (GNUNET_TIME_UNIT_MILLISECONDS, 100), 5232 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
5187 &schedule_churn_shutdown_task, 5233 &schedule_churn_shutdown_task,
@@ -5308,6 +5354,7 @@ GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
5308 churn_ctx->num_to_stop = voff; 5354 churn_ctx->num_to_stop = voff;
5309 churn_ctx->cb = cb; 5355 churn_ctx->cb = cb;
5310 churn_ctx->cb_cls = cb_cls; 5356 churn_ctx->cb_cls = cb_cls;
5357 churn_ctx->pg = pg;
5311 5358
5312 for (i = 0; i < pg->total; i++) 5359 for (i = 0; i < pg->total; i++)
5313 { 5360 {
@@ -5362,6 +5409,7 @@ GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
5362 churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); 5409 churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext));
5363 churn_startup_ctx->churn_ctx = churn_ctx; 5410 churn_startup_ctx->churn_ctx = churn_ctx;
5364 churn_startup_ctx->timeout = timeout; 5411 churn_startup_ctx->timeout = timeout;
5412 churn_startup_ctx->pg = pg;
5365 } 5413 }
5366 for (i = 0; i < von; i++) 5414 for (i = 0; i < von; i++)
5367 { 5415 {
@@ -5529,7 +5577,7 @@ schedule_shutdown_task (void *cls,
5529 shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; 5577 shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
5530 GNUNET_assert (shutdown_ctx != NULL); 5578 GNUNET_assert (shutdown_ctx != NULL);
5531 5579
5532 if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN) 5580 if (shutdown_ctx->outstanding > shutdown_ctx->pg->max_outstanding_connections)
5533 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 5581 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
5534 (GNUNET_TIME_UNIT_MILLISECONDS, 100), 5582 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
5535 &schedule_shutdown_task, peer_shutdown_ctx); 5583 &schedule_shutdown_task, peer_shutdown_ctx);
@@ -5572,6 +5620,7 @@ GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg,
5572 shutdown_ctx->cb_cls = cb_cls; 5620 shutdown_ctx->cb_cls = cb_cls;
5573 shutdown_ctx->total_peers = pg->total; 5621 shutdown_ctx->total_peers = pg->total;
5574 shutdown_ctx->timeout = timeout; 5622 shutdown_ctx->timeout = timeout;
5623 shutdown_ctx->pg = pg;
5575 /* shtudown_ctx->outstanding = 0; */ 5624 /* shtudown_ctx->outstanding = 0; */
5576 5625
5577 for (off = 0; off < pg->total; off++) 5626 for (off = 0; off < pg->total; off++)