barrier.hpp 3.65 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
/*
 * Copyright (c) 2017 UChicago Argonne, LLC
 *
 * See COPYRIGHT in top-level directory.
 */

#ifndef __THALLIUM_BARRIER_HPP
#define __THALLIUM_BARRIER_HPP

#include <abt.h>
#include <thallium/abt_errors.hpp>
#include <thallium/exception.hpp>

namespace thallium {

/**
 * Exception class thrown by the barrier class.
 */
class barrier_exception : public exception {

    public:

    template<typename ... Args>
    barrier_exception(Args&&... args)
    : exception(std::forward<Args>(args)...) {}
};

#define TL_BARRIER_EXCEPTION(__fun,__ret) \
    barrier_exception(#__fun," returned ", abt_error_get_name(__ret),\
            " (", abt_error_get_description(__ret),") in ",__FILE__,":",__LINE__);

#define TL_BARRIER_ASSERT(__call) {\
    int __ret = __call; \
    if(__ret != ABT_SUCCESS) {\
        throw TL_BARRIER_EXCEPTION(__call, __ret);\
    }\
}

/**
 * @brief Wrapper for Argobots' ABT_barrier.
 */
class barrier {
	
	ABT_barrier m_barrier;

	public:

    /**
     * @brief Native handle type (ABT_barrier)
     */
    typedef ABT_barrier native_handle_type;

    /**
     * @brief Constructor.
     *
     * @param num_waiters Number of waiters.
     */
    explicit barrier(uint32_t num_waiters) {
        TL_BARRIER_ASSERT(ABT_barrier_create(num_waiters, &m_barrier));
    }

    /**
     * @brief Copy constructor is deleted.
     */
    barrier(const barrier& other)            = delete;

    /**
     * @brief Copy assignment operator is deleted.
     */
    barrier& operator=(const barrier& other) = delete;
    
    /**
     * @brief Move assignment operator.
     *
     * If the right and left operands are different,
     * this method will free the left operand's resource (if
     * necessary), and assign it the right operand's resource.
     * The right operand will be invalidated.
     */
    barrier& operator=(barrier&& other) {
        if(this == &other) return *this;
        if(m_barrier != ABT_BARRIER_NULL) {
            TL_BARRIER_ASSERT(ABT_barrier_free(&m_barrier));
        }
        m_barrier = other.m_barrier;
        other.m_barrier = ABT_BARRIER_NULL;
        return *this;
    }

    /**
     * @brief Move constructor. The right operand
     * will be invalidated.
     *
     * @param other barrier object to move from.
     */
    barrier(barrier&& other) 
    : m_barrier(other.m_barrier) {
        other.m_barrier = ABT_BARRIER_NULL;
    }

    /**
     * @brief Destructor.
     */
    ~barrier() {
        if(m_barrier != ABT_BARRIER_NULL)
            ABT_barrier_free(&m_barrier);
    }

    /**
     * @brief Reinitializes the barrier for a given
     * number of waiters.
     *
     * @param num_waiters Number of waiters.
     */
    void reinit(uint32_t num_waiters) {
        if(m_barrier == ABT_BARRIER_NULL) {
            TL_BARRIER_ASSERT(ABT_barrier_create(num_waiters, &m_barrier));
        } else {
            TL_BARRIER_ASSERT(ABT_barrier_reinit(m_barrier, num_waiters));
        }
    }

    /**
     * @brief Waits on the barrier.
     */
    void wait() {
        TL_BARRIER_ASSERT(ABT_barrier_wait(m_barrier));
    }

    /**
     * @brief Get the number of waiters that the barrier
     * is expecting (passed to the constructor or to reinit).
     *
     * @return The number of waiters.
     */
    uint32_t get_num_waiters() const {
        uint32_t n;
        TL_BARRIER_ASSERT(ABT_barrier_get_num_waiters(m_barrier, &n));
        return n;
    }

    /**
     * @brief Get the underlying ABT_barrier handle.
     *
     * @return the underlying ABT_barrier handle.
     */
    native_handle_type native_handle() const noexcept {
        return m_barrier;
    }
};

}

#undef TL_BARRIER_EXCEPTION
#undef TL_BARRIER_ASSERT

#endif /* end of include guard */