aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSree Harsha Totakura <totakura@in.tum.de>2013-09-05 09:49:58 +0000
committerSree Harsha Totakura <totakura@in.tum.de>2013-09-05 09:49:58 +0000
commit96884ee94297035e20e29eed83d15e38e9e7797b (patch)
tree4ca00d5688e998cce07f7149473bc767869f5a53
parent49f7d44deb51f4cd7f8027d5a1fac9d7ddef1f27 (diff)
downloadgnunet-96884ee94297035e20e29eed83d15e38e9e7797b.tar.gz
gnunet-96884ee94297035e20e29eed83d15e38e9e7797b.zip
- warn and wait for all operations to be completed
-rw-r--r--src/testbed/testbed_api.c3
-rw-r--r--src/testbed/testbed_api.h74
-rw-r--r--src/testbed/testbed_api_testbed.c182
3 files changed, 95 insertions, 164 deletions
diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c
index d5486b1c3..e328456de 100644
--- a/src/testbed/testbed_api.c
+++ b/src/testbed/testbed_api.c
@@ -352,6 +352,9 @@ GNUNET_TESTBED_remove_opc_ (const struct GNUNET_TESTBED_Controller *c,
352 GNUNET_CONTAINER_multihashmap32_remove (c->opc_map, 352 GNUNET_CONTAINER_multihashmap32_remove (c->opc_map,
353 (uint32_t) opc->id, 353 (uint32_t) opc->id,
354 opc)); 354 opc));
355 if ( (0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map))
356 && (NULL != c->opcq_empty_cb) )
357 c->opcq_empty_cb (c->opcq_empty_cls);
355} 358}
356 359
357 360
diff --git a/src/testbed/testbed_api.h b/src/testbed/testbed_api.h
index 39a2f711a..f09bb61b9 100644
--- a/src/testbed/testbed_api.h
+++ b/src/testbed/testbed_api.h
@@ -27,6 +27,7 @@
27#ifndef TESTBED_API_H 27#ifndef TESTBED_API_H
28#define TESTBED_API_H 28#define TESTBED_API_H
29 29
30#include "gnunet_scheduler_lib.h"
30#include "gnunet_testbed_service.h" 31#include "gnunet_testbed_service.h"
31#include "testbed.h" 32#include "testbed.h"
32#include "testbed_helper.h" 33#include "testbed_helper.h"
@@ -178,6 +179,14 @@ struct OperationContext
178 179
179 180
180/** 181/**
182 * Operation empty callback
183 *
184 * @param cls closure
185 */
186typedef void (*TESTBED_opcq_empty_cb) (void *cls);
187
188
189/**
181 * Handle to interact with a GNUnet testbed controller. Each 190 * Handle to interact with a GNUnet testbed controller. Each
182 * controller has at least one master handle which is created when the 191 * controller has at least one master handle which is created when the
183 * controller is created; this master handle interacts with the 192 * controller is created; this master handle interacts with the
@@ -240,6 +249,16 @@ struct GNUNET_TESTBED_Controller
240 struct GNUNET_CONTAINER_MultiHashMap32 *opc_map; 249 struct GNUNET_CONTAINER_MultiHashMap32 *opc_map;
241 250
242 /** 251 /**
252 * If this callback is not NULL, schedule it as a task when opc_map gets empty
253 */
254 TESTBED_opcq_empty_cb opcq_empty_cb;
255
256 /**
257 * Closure for the above task
258 */
259 void *opcq_empty_cls;
260
261 /**
243 * Operation queue for simultaneous operations 262 * Operation queue for simultaneous operations
244 */ 263 */
245 struct OperationQueue *opq_parallel_operations; 264 struct OperationQueue *opq_parallel_operations;
@@ -442,61 +461,6 @@ GNUNET_TESTBED_get_slave_config_ (void *op_cls,
442 461
443 462
444/** 463/**
445 * Same as the GNUNET_TESTBED_controller_link_2, but with ids for delegated host
446 * and slave host
447 *
448 * @param op_cls the operation closure for the event which is generated to
449 * signal success or failure of this operation
450 * @param master handle to the master controller who creates the association
451 * @param delegated_host_id id of the host to which requests should be delegated
452 * @param slave_host_id id of the host which is used to run the slave controller
453 * @param sxcfg serialized and compressed configuration
454 * @param sxcfg_size the size sxcfg
455 * @param scfg_size the size of uncompressed serialized configuration
456 * @param is_subordinate GNUNET_YES if the controller at delegated_host should
457 * be started by the slave controller; GNUNET_NO if the slave
458 * controller has to connect to the already started delegated
459 * controller via TCP/IP
460 * @return the operation handle
461 */
462struct GNUNET_TESTBED_Operation *
463GNUNET_TESTBED_controller_link_2_ (void *op_cls,
464 struct GNUNET_TESTBED_Controller *master,
465 uint32_t delegated_host_id,
466 uint32_t slave_host_id, const char *sxcfg,
467 size_t sxcfg_size, size_t scfg_size,
468 int is_subordinate);
469
470
471/**
472 * Same as the GNUNET_TESTBED_controller_link, but with ids for delegated host
473 * and slave host
474 *
475 * @param op_cls the operation closure for the event which is generated to
476 * signal success or failure of this operation
477 * @param master handle to the master controller who creates the association
478 * @param delegated_host_id id of the host to which requests should be
479 * delegated; cannot be NULL
480 * @param slave_host_id id of the host which should connect to controller
481 * running on delegated host ; use NULL to make the master controller
482 * connect to the delegated host
483 * @param slave_cfg configuration to use for the slave controller
484 * @param is_subordinate GNUNET_YES if the controller at delegated_host should
485 * be started by the slave controller; GNUNET_NO if the slave
486 * controller has to connect to the already started delegated
487 * controller via TCP/IP
488 * @return the operation handle
489 */
490struct GNUNET_TESTBED_Operation *
491GNUNET_TESTBED_controller_link_ (void *op_cls,
492 struct GNUNET_TESTBED_Controller *master,
493 uint32_t delegated_host_id,
494 uint32_t slave_host_id,
495 const struct GNUNET_CONFIGURATION_Handle
496 *slave_cfg, int is_subordinate);
497
498
499/**
500 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages. This 464 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages. This
501 * function is defined in @file testbed_api_barriers.c 465 * function is defined in @file testbed_api_barriers.c
502 * 466 *
diff --git a/src/testbed/testbed_api_testbed.c b/src/testbed/testbed_api_testbed.c
index 064e43b9f..dae364699 100644
--- a/src/testbed/testbed_api_testbed.c
+++ b/src/testbed/testbed_api_testbed.c
@@ -28,6 +28,7 @@
28#include "platform.h" 28#include "platform.h"
29#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
30#include "gnunet_testbed_service.h" 30#include "gnunet_testbed_service.h"
31#include "testbed_api.h"
31#include "testbed_api_peers.h" 32#include "testbed_api_peers.h"
32#include "testbed_api_hosts.h" 33#include "testbed_api_hosts.h"
33#include "testbed_api_topology.h" 34#include "testbed_api_topology.h"
@@ -242,11 +243,6 @@ struct RunContext
242 GNUNET_SCHEDULER_TaskIdentifier register_hosts_task; 243 GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
243 244
244 /** 245 /**
245 * Task to be run while shutting down
246 */
247 GNUNET_SCHEDULER_TaskIdentifier shutdown_run_task;
248
249 /**
250 * Task to be run of a timeout 246 * Task to be run of a timeout
251 */ 247 */
252 GNUNET_SCHEDULER_TaskIdentifier timeout_task; 248 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
@@ -257,11 +253,6 @@ struct RunContext
257 GNUNET_SCHEDULER_TaskIdentifier interrupt_task; 253 GNUNET_SCHEDULER_TaskIdentifier interrupt_task;
258 254
259 /** 255 /**
260 * Task for cleaning up the run context and various resources it uses
261 */
262 GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
263
264 /**
265 * The event mask for the controller 256 * The event mask for the controller
266 */ 257 */
267 uint64_t event_mask; 258 uint64_t event_mask;
@@ -448,7 +439,7 @@ remove_rcop (struct RunContext *rc, struct RunContextOperation *rcop)
448 * @param tc the task context from scheduler 439 * @param tc the task context from scheduler
449 */ 440 */
450static void 441static void
451cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 442cleanup (void *cls)
452{ 443{
453 struct RunContext *rc = cls; 444 struct RunContext *rc = cls;
454 unsigned int hid; 445 unsigned int hid;
@@ -478,20 +469,6 @@ cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
478 469
479 470
480/** 471/**
481 * Perform the cleanup task now
482 *
483 * @param rc the run context to be cleaned up
484 */
485static void
486cleanup_now (struct RunContext *rc)
487{
488 if (GNUNET_SCHEDULER_NO_TASK != rc->cleanup_task)
489 GNUNET_SCHEDULER_cancel (rc->cleanup_task);
490 rc->cleanup_task = GNUNET_SCHEDULER_add_now (&cleanup, rc);
491}
492
493
494/**
495 * Iterator for cleaning up elements from rcop_map 472 * Iterator for cleaning up elements from rcop_map
496 * 473 *
497 * @param cls the RunContext 474 * @param cls the RunContext
@@ -514,21 +491,6 @@ rcop_cleanup_iterator (void *cls, uint32_t key, void *value)
514 491
515 492
516/** 493/**
517 * Cleanup existing operation in given run context
518 *
519 * @param rc the run context
520 */
521static void
522cleanup_operations (struct RunContext *rc)
523{
524 GNUNET_assert (GNUNET_SYSERR !=
525 GNUNET_CONTAINER_multihashmap32_iterate (rc->rcop_map,
526 &rcop_cleanup_iterator,
527 rc));
528}
529
530
531/**
532 * Cancels operations and tasks which are assigned to the given run context 494 * Cancels operations and tasks which are assigned to the given run context
533 * 495 *
534 * @param rc the RunContext 496 * @param rc the RunContext
@@ -561,11 +523,6 @@ rc_cleanup_operations (struct RunContext *rc)
561 GNUNET_SCHEDULER_cancel (rc->timeout_task); 523 GNUNET_SCHEDULER_cancel (rc->timeout_task);
562 rc->timeout_task = GNUNET_SCHEDULER_NO_TASK; 524 rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
563 } 525 }
564 if (GNUNET_SCHEDULER_NO_TASK != rc->interrupt_task)
565 {
566 GNUNET_SCHEDULER_cancel (rc->interrupt_task);
567 rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK;
568 }
569 if (NULL != rc->reg_handle) 526 if (NULL != rc->reg_handle)
570 { 527 {
571 GNUNET_TESTBED_cancel_registration (rc->reg_handle); 528 GNUNET_TESTBED_cancel_registration (rc->reg_handle);
@@ -577,66 +534,71 @@ rc_cleanup_operations (struct RunContext *rc)
577 rc->topology_operation = NULL; 534 rc->topology_operation = NULL;
578 } 535 }
579 /* cancel any exiting operations */ 536 /* cancel any exiting operations */
580 cleanup_operations (rc); 537 GNUNET_assert (GNUNET_SYSERR !=
538 GNUNET_CONTAINER_multihashmap32_iterate (rc->rcop_map,
539 &rcop_cleanup_iterator,
540 rc));
581} 541}
582 542
583 543
584/** 544/**
585 * Stops the testbed run and releases any used resources 545 * Cancels the scheduled interrupt task
586 * 546 *
587 * @param cls the tesbed run handle 547 * @param rc the run context
588 * @param tc the task context from scheduler
589 */ 548 */
590static void 549static void
591shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 550cancel_interrupt_task (struct RunContext *rc)
551{
552 GNUNET_SCHEDULER_cancel (rc->interrupt_task);
553 rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK;
554}
555
556
557/**
558 * This callback will be called when all the operations are completed
559 * (done/cancelled)
560 *
561 * @param cls run context
562 * @param tc scheduler task context
563 */
564static void
565wait_op_completion (void *cls)
592{ 566{
593 struct RunContext *rc = cls; 567 struct RunContext *rc = cls;
594 struct RunContextOperation *rcop; 568 struct RunContextOperation *rcop;
595 569
596 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task); 570 if ( (NULL == rc->cproc)
597 rc->shutdown_run_task = GNUNET_SCHEDULER_NO_TASK; 571 || (NULL == rc->c)
598 GNUNET_assert (GNUNET_NO == rc->shutdown); 572 || (GNUNET_YES == rc->shutdown) )
599 rc->shutdown = GNUNET_YES;
600 rc_cleanup_operations (rc);
601 if (NULL != rc->c)
602 { 573 {
603 if (NULL != rc->peers) 574 if (NULL != rc->peers)
604 { 575 {
605 rcop = GNUNET_malloc (sizeof (struct RunContextOperation)); 576 GNUNET_free (rc->peers);
606 rcop->rc = rc; 577 rc->peers = NULL;
607 rcop->op = GNUNET_TESTBED_shutdown_peers (rc->c, rcop, NULL, NULL);
608 GNUNET_assert (NULL != rcop->op);
609 DEBUG ("Shutting down peers\n");
610 rc->pstart_time = GNUNET_TIME_absolute_get ();
611 insert_rcop (rc, rcop);
612 return;
613 } 578 }
579 goto cleanup_;
614 } 580 }
615 rc->state = RC_PEERS_SHUTDOWN; /* No peers are present so we consider the 581 if (NULL == rc->peers)
616 * state where all peers are SHUTDOWN */ 582 goto cleanup_;
617 cleanup_now (rc); 583 rc->shutdown = GNUNET_YES;
618} 584 rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
619 585 rcop->rc = rc;
586 rcop->op = GNUNET_TESTBED_shutdown_peers (rc->c, rcop, NULL, NULL);
587 GNUNET_assert (NULL != rcop->op);
588 DEBUG ("Shutting down peers\n");
589 rc->pstart_time = GNUNET_TIME_absolute_get ();
590 insert_rcop (rc, rcop);
591 return;
620 592
621/** 593 cleanup_:
622 * Function to shutdown now 594 rc->state = RC_PEERS_SHUTDOWN;
623 * 595 cancel_interrupt_task (rc);
624 * @param rc the RunContext 596 cleanup (rc);
625 */
626static void
627shutdown_now (struct RunContext *rc)
628{
629 if (GNUNET_YES == rc->shutdown)
630 return;
631 if (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task)
632 GNUNET_SCHEDULER_cancel (rc->shutdown_run_task);
633 GNUNET_SCHEDULER_shutdown (); /* Trigger shutdown in programs using this API */
634 rc->shutdown_run_task = GNUNET_SCHEDULER_add_now (&shutdown_run, rc);
635} 597}
636 598
637 599
638/** 600/**
639 * Task run upon any interrupt. Common ones are SIGINT & SIGTERM. 601 * Task run upon interrupts (SIGINT, SIGTERM) and upon scheduler shutdown.
640 * 602 *
641 * @param cls the RunContext which has to be acted upon 603 * @param cls the RunContext which has to be acted upon
642 * @param tc the scheduler task context 604 * @param tc the scheduler task context
@@ -645,9 +607,24 @@ static void
645interrupt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 607interrupt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
646{ 608{
647 struct RunContext *rc = cls; 609 struct RunContext *rc = cls;
610 struct GNUNET_TESTBED_Controller *c = rc->c;
611 unsigned int size;
648 612
649 rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK; 613 /* reschedule */
650 shutdown_now (rc); 614 rc->interrupt_task = GNUNET_SCHEDULER_add_delayed
615 (GNUNET_TIME_UNIT_FOREVER_REL, &interrupt, rc);
616 rc_cleanup_operations (rc);
617 if ( (GNUNET_NO == rc->shutdown)
618 && (NULL != c)
619 && (0 != (size = GNUNET_CONTAINER_multihashmap32_size (c->opc_map))))
620 {
621 LOG (GNUNET_ERROR_TYPE_WARNING, "Shutdown postponed as there are "
622 "%u operations currently active\n", size);
623 c->opcq_empty_cb = &wait_op_completion;
624 c->opcq_empty_cls = rc;
625 return;
626 }
627 wait_op_completion (rc);
651} 628}
652 629
653 630
@@ -721,7 +698,7 @@ peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
721 if (NULL != emsg) 698 if (NULL != emsg)
722 LOG (GNUNET_ERROR_TYPE_ERROR, "Error while creating a peer: %s\n", 699 LOG (GNUNET_ERROR_TYPE_ERROR, "Error while creating a peer: %s\n",
723 emsg); 700 emsg);
724 shutdown_now (rc); 701 GNUNET_SCHEDULER_shutdown ();
725 return; 702 return;
726 } 703 }
727 rc->peers[rc->peer_count] = peer; 704 rc->peers[rc->peer_count] = peer;
@@ -830,7 +807,7 @@ event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
830 if (NULL != event->details.operation_finished.emsg) 807 if (NULL != event->details.operation_finished.emsg)
831 { 808 {
832 LOG (GNUNET_ERROR_TYPE_ERROR, _("Linking controllers failed. Exiting")); 809 LOG (GNUNET_ERROR_TYPE_ERROR, _("Linking controllers failed. Exiting"));
833 shutdown_now (rc); 810 GNUNET_SCHEDULER_shutdown ();
834 } 811 }
835 else 812 else
836 rc->reg_hosts++; 813 rc->reg_hosts++;
@@ -846,7 +823,7 @@ event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
846 return; 823 return;
847 default: 824 default:
848 GNUNET_break (0); 825 GNUNET_break (0);
849 shutdown_now (rc); 826 GNUNET_SCHEDULER_shutdown ();
850 return; 827 return;
851 } 828 }
852 } 829 }
@@ -862,7 +839,7 @@ event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
862 { 839 {
863 LOG (GNUNET_ERROR_TYPE_ERROR, "A operation has failed with error: %s\n", 840 LOG (GNUNET_ERROR_TYPE_ERROR, "A operation has failed with error: %s\n",
864 event->details.operation_finished.emsg); 841 event->details.operation_finished.emsg);
865 shutdown_now (rc); 842 GNUNET_SCHEDULER_shutdown ();
866 return; 843 return;
867 } 844 }
868 GNUNET_assert (GNUNET_YES == rc->shutdown); 845 GNUNET_assert (GNUNET_YES == rc->shutdown);
@@ -875,7 +852,7 @@ event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
875 GNUNET_free_non_null (rc->peers); 852 GNUNET_free_non_null (rc->peers);
876 rc->peers = NULL; 853 rc->peers = NULL;
877 DEBUG ("Peers shut down in %s\n", prof_time (rc)); 854 DEBUG ("Peers shut down in %s\n", prof_time (rc));
878 cleanup_now (rc); 855 GNUNET_SCHEDULER_shutdown ();
879 break; 856 break;
880 default: 857 default:
881 GNUNET_assert (0); 858 GNUNET_assert (0);
@@ -972,7 +949,7 @@ host_registration_completion (void *cls, const char *emsg)
972 { 949 {
973 LOG (GNUNET_ERROR_TYPE_WARNING, 950 LOG (GNUNET_ERROR_TYPE_WARNING,
974 _("Host registration failed for a host. Error: %s\n"), emsg); 951 _("Host registration failed for a host. Error: %s\n"), emsg);
975 shutdown_now (rc); 952 GNUNET_SCHEDULER_shutdown ();
976 return; 953 return;
977 } 954 }
978 rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc); 955 rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
@@ -1037,20 +1014,7 @@ controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1037 { 1014 {
1038 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1015 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1039 _("Controller crash detected. Shutting down.\n")); 1016 _("Controller crash detected. Shutting down.\n"));
1040 rc->cproc = NULL; 1017 GNUNET_SCHEDULER_shutdown ();
1041 rc_cleanup_operations (rc);
1042 if (NULL != rc->peers)
1043 {
1044 GNUNET_free (rc->peers);
1045 rc->peers = NULL;
1046 }
1047 if (GNUNET_YES == rc->shutdown)
1048 {
1049 rc->state = RC_PEERS_SHUTDOWN;
1050 cleanup_now (rc);
1051 }
1052 else
1053 shutdown_now (rc);
1054 return; 1018 return;
1055 } 1019 }
1056 GNUNET_CONFIGURATION_destroy (rc->cfg); 1020 GNUNET_CONFIGURATION_destroy (rc->cfg);
@@ -1143,7 +1107,7 @@ host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
1143 else 1107 else
1144 LOG (GNUNET_ERROR_TYPE_ERROR, 1108 LOG (GNUNET_ERROR_TYPE_ERROR,
1145 _("Testbed cannot be started on localhost\n")); 1109 _("Testbed cannot be started on localhost\n"));
1146 shutdown_now (rc); 1110 GNUNET_SCHEDULER_shutdown ();
1147 return; 1111 return;
1148 } 1112 }
1149 rc->reg_hosts++; 1113 rc->reg_hosts++;
@@ -1181,7 +1145,7 @@ host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
1181 if (NULL == rc->cproc) 1145 if (NULL == rc->cproc)
1182 { 1146 {
1183 LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller")); 1147 LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
1184 shutdown_now (rc); 1148 GNUNET_SCHEDULER_shutdown ();
1185 } 1149 }
1186} 1150}
1187 1151
@@ -1199,7 +1163,7 @@ timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1199 1163
1200 rc->timeout_task = GNUNET_SCHEDULER_NO_TASK; 1164 rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1201 LOG (GNUNET_ERROR_TYPE_ERROR, _("Shutting down testbed due to timeout while setup.\n")); 1165 LOG (GNUNET_ERROR_TYPE_ERROR, _("Shutting down testbed due to timeout while setup.\n"));
1202 shutdown_now (rc); 1166 GNUNET_SCHEDULER_shutdown ();
1203 if (NULL != rc->test_master) 1167 if (NULL != rc->test_master)
1204 rc->test_master (rc->test_master_cls, 0, NULL, 0, 0); 1168 rc->test_master (rc->test_master_cls, 0, NULL, 0, 0);
1205 rc->test_master = NULL; 1169 rc->test_master = NULL;