* Description The testbed subsystem's barriers API facilitates coordination among the peers run by the testbed and the experiment driver. The concept is similar to the barrier synchronisation mechanism found in parallel programming or multi-threading paradigms - a peer waits at a barrier upon reaching it until the barrier is reached by a predefined number of peers. This predefined number of peers required to cross a barrier is also called quorum. We say a peer has reached a barrier if the peer is waiting for the barrier to be crossed. Similarly a barrier is said to be reached if the required quorum of peers reach the barrier. A barrier which is reached is deemed as crossed after all the peers waiting on it are notified. The barriers API provides the following functions: 1) GNUNET_TESTBED_barrier_init(): function to initialse a barrier in the experiment 2) GNUNET_TESTBED_barrier_cancel(): function to cancel a barrier which has been initialised before 3) GNUNET_TESTBED_barrier_wait(): function to signal barrier service that the caller has reached a barrier and is waiting for it to be crossed 4) GNUNET_TESTBED_barrier_wait_cancel(): function to stop waiting for a barrier to be crossed Among the above functions, the first two, namely GNUNET_TESTBED_barrier_init() and GNUNET_TESTBED_barrier_cacel() are used by experiment drivers. All barriers should be initialised by the experiment driver by calling GNUNET_TESTBED_barrier_init(). This function takes a name to identify the barrier, the quorum required for the barrier to be crossed and a notification callback for notifying the experiment driver when the barrier is crossed. The GNUNET_TESTBED_function barrier_cancel() cancels an initialised barrier and frees the resources allocated for it. This function can be called upon a initialised barrier before it is crossed. The remaining two functions GNUNET_TESTBED_barrier_wait() and GNUNET_TESTBED_barrier_wait_cancel() are used in the peer's processes. GNUNET_TESTBED_barrier_wait() connects to the local barrier service running on the same host the peer is running on and registers that the caller has reached the barrier and is waiting for the barrier to be crossed. Note that this function can only be used by peers which are started by testbed as this function tries to access the local barrier service which is part of the testbed controller service. Calling GNUNET_TESTBED_barrier_wait() on an uninitialised barrier results in failure. GNUNET_TESTBED_barrier_wait_cancel() cancels the notification registered by GNUNET_TESTBED_barrier_wait(). * Implementation Since barriers involve coordination between experiment driver and peers, the barrier service in the testbed controller is split into two components. The first component responds to the message generated by the barrier API used by the experiment driver (functions GNUNET_TESTBED_barrier_init() and GNUNET_TESTBED_barrier_cancel()) and the second component to the messages generated by barrier API used by peers (functions GNUNET_TESTBED_barrier_wait() and GNUNET_TESTBED_barrier_wait_cancel()). Calling GNUNET_TESTBED_barrier_init() sends a BARRIER_INIT message to the master controller. The master controller then registers a barrier and calls GNUNET_TESTBED_barrier_init() for each its subcontrollers. In this way barrier initialisation is propagated to the controller hierarchy. While propagating initialisation, any errors at a subcontroller such as timeout during further propagation are reported up the hierarchy back to the experiment driver. Similar to GNUNET_TESTBED_barrier_init(), GNUNET_TESTBED_barrier_cancel() propagates BARRIER_CANCEL message which causes controllers to remove an initialised barrier. The second component is implemented as a separate service in the binary `gnunet-service-testbed' which already has the testbed controller service. Although this deviates from the gnunet process architecture of having one service per binary, it is needed in this case as this component needs access to barrier data created by the first component. This component responds to BARRIER_WAIT messages from local peers when they call GNUNET_TESTBED_barrier_wait(). Upon receiving BARRIER_WAIT message, the service checks if the requested barrier has been initialised before and if it was not initialised, an error status is sent through BARRIER_STATUS message to the local peer and the connection from the peer is terminated. If the barrier is initialised before, the barrier's counter for reached peers is incremented and a notification is registered to notify the peer when the barrier is reached. The connection from the peer is left open. When enough peers required to attain the quorum send BARRIER_WAIT messages, the controller sends a BARRIER_STATUS message to its parent informing that the barrier is crossed. If the controller has started further subcontrollers, it delays this message until it receives a similar notification from each of those subcontrollers. Finally, the barriers API at the experiment driver receives the BARRIER_STATUS when the barrier is reached at all the controllers. The barriers API at the experiment driver responds to the BARRIER_STATUS message by echoing it back to the master controller and notifying the experiment controller through the notification callback that a barrier has been crossed. The echoed BARRIER_STATUS message is propagated by the master controller to the controller hierarchy. This propagation triggers the notifications registered by peers at each of the controllers in the hierarchy. Note the difference between this downward propagation of the BARRIER_STATUS message from its upward propagation -- the upward propagation is needed for ensuring that the barrier is reached by all the controllers and the downward propagation is for triggering that the barrier is crossed.