/* ------------------------------ $Id: abar.c,v 1.2 2006/02/03 07:45:04 marquet Exp $ ------------------------------------------------------------ Asymmetric barrier synchronization Philippe Marquet, Jan 2006 */ #include #include #include #include #include "abar.h" #include "tools.h" struct abar_s { pthread_mutex_t ab_lock; unsigned ab_n_slaves; unsigned ab_n_waiting; unsigned ab_spin; pthread_cond_t ab_slaves_cond; pthread_cond_t ab_master_cond; }; /* Called by the master to allocate and initialize a barrier for use by n_slaves slave processes */ struct abar_s * abar_init(int n_slaves) { int status; struct abar_s *ab; ab = malloc(sizeof(struct abar_s)); fatal((int)ab, "abar_init", "Allocation of a new asymmetric barrier"); ab->ab_n_slaves = n_slaves; ab->ab_n_waiting = 0; ab->ab_spin = 0; status = pthread_mutex_init(&ab->ab_lock, NULL); status += pthread_cond_init(&ab->ab_slaves_cond, NULL); status += pthread_cond_init(&ab->ab_master_cond, NULL); fatal(!status, "abar_init", "Condition or lock initialization of a new abar"); return ab; } /* Called by master to indicate it is finished with the barrier. No slaves must be waiting in the barrier at the time of the call */ int abar_destroy(struct abar_s *ab) { int status; fatal(!ab->ab_n_waiting, "abar_destroy", "Trying to destroy a used abar"); status = pthread_mutex_destroy(&ab->ab_lock); status += pthread_cond_destroy(&ab->ab_slaves_cond); status += pthread_cond_destroy(&ab->ab_master_cond); fatal(!status, "abar_destroy", "Condition or lock destruction in abar destruction"); return RETURN_SUCCESS; } /* Called by the master to wait for all slaves to enter the barrier. Returns when all slaves have called barrier_slave. */ int abar_master(struct abar_s *ab) { int status; status = pthread_mutex_lock(&ab->ab_lock); fatal(!status, "abar_master", "Unable to lock mutex"); while (ab->ab_n_waiting != ab->ab_n_slaves) { status = pthread_cond_wait(&ab->ab_master_cond, &ab->ab_lock); fatal(!status, "abar_master", "Unable to wait on the condtion"); } status = pthread_mutex_unlock(&ab->ab_lock); fatal(!status, "abar_master", "Unable to unlock mutex"); return RETURN_SUCCESS; } /* Called by a slave to enter the barrier. Returns after the master has released the barrier (barrier_release) */ int abar_slave(struct abar_s *ab) { int myspin; int status; status = pthread_mutex_lock(&ab->ab_lock); fatal(!status, "abar_slave", "Unable to lock mutex"); ab->ab_n_waiting++; if (ab->ab_n_waiting == ab->ab_n_slaves) { status = pthread_cond_signal(&ab->ab_master_cond); fatal(!status, "abar_slave", "Unable to signal master cond"); } myspin = ab->ab_spin; while (ab->ab_spin == myspin) { status = pthread_cond_wait(&ab->ab_slaves_cond, &ab->ab_lock); fatal(!status, "abar_slave", "Unable to wait on the condtion"); } status = pthread_mutex_unlock(&ab->ab_lock); fatal(!status, "abar_slave", "Unable to unlock mutex"); return RETURN_SUCCESS; } /* Called by the master to release all the slaves that have entered the barrier */ int abar_release(struct abar_s *ab) { int status; status = pthread_mutex_lock(&ab->ab_lock); fatal(!status, "abar_release", "Unable to lock mutex"); fatal(ab->ab_n_waiting == ab->ab_n_slaves, "abar_release", "Not all slaves at the abarrier!"); ab->ab_n_waiting = 0; ab->ab_spin = 1-ab->ab_spin; status = pthread_mutex_unlock(&ab->ab_lock); fatal(!status, "abar_release", "Unable to unlock mutex"); status = pthread_cond_broadcast(&ab->ab_slaves_cond); fatal(!status, "abar_release", "Unable to broadcast on cond"); return RETURN_SUCCESS; }