Based on API interface file.

Signed-off-by: Christophe Milard <christophe.mil...@linaro.org>
---
 include/odp/drv/spec/atomic.h | 634 ++++++++++++++++++++++++++++++++++++++++++
 platform/Makefile.inc         |   1 +
 2 files changed, 635 insertions(+)
 create mode 100644 include/odp/drv/spec/atomic.h

diff --git a/include/odp/drv/spec/atomic.h b/include/odp/drv/spec/atomic.h
new file mode 100644
index 0000000..3cb6e9b
--- /dev/null
+++ b/include/odp/drv/spec/atomic.h
@@ -0,0 +1,634 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODPDRV atomic operations
+ */
+
+#ifndef ODPDRV_API_ATOMIC_H_
+#define ODPDRV_API_ATOMIC_H_
+#include <odp/visibility_begin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup odpdrv_atomic ODPDRV ATOMIC
+ * @details
+ * <b> Atomic integers using relaxed memory ordering </b>
+ *
+ * Atomic integer types (odpdrv_atomic_u32_t and odpdrv_atomic_u64_t) can be
+ * used to implement e.g. shared counters. If not otherwise documented,
+ * operations in this API are implemented using <b> RELAXED memory ordering 
</b>
+ * (see memory order descriptions in the C11 specification). Relaxed operations
+ * do not provide synchronization or ordering for other memory accesses
+ * (initiated before or after the operation), only atomicity of the operation
+ * itself is guaranteed.
+ *
+ * <b> Operations with non-relaxed memory ordering </b>
+ *
+ * <b> An operation with RELEASE </b> memory ordering
+ * (odpdrv_atomic_xxx_rel_xxx()) ensures that other threads loading the same
+ * atomic variable with ACQUIRE memory ordering see all stores (from the
+ * calling thread) that happened before this releasing store.
+ *
+ * <b> An operation with ACQUIRE </b> memory ordering
+ * (odpdrv_atomic_xxx_acq_xxx()) ensures that the calling thread sees all 
stores
+ * (done by the releasing thread) that happened before a RELEASE memory ordered
+ * store to the same atomic variable.
+ *
+ * <b> An operation with ACQUIRE-and-RELEASE </b> memory ordering
+ * (odpdrv_atomic_xxx_acq_rel_xxx()) combines the effects of ACQUIRE and 
RELEASE
+ * memory orders. A single operation acts as both an acquiring load and
+ * a releasing store.
+ *
+ * @{
+ */
+
+/**
+ * @typedef odpdrv_atomic_u64_t
+ * Atomic 64-bit unsigned integer
+ *
+ * @typedef odpdrv_atomic_u32_t
+ * Atomic 32-bit unsigned integer
+ */
+
+/*
+ * 32-bit operations in RELAXED memory ordering
+ * --------------------------------------------
+ */
+
+/**
+ * Initialize atomic uint32 variable
+ *
+ * Initializes the atomic variable with 'val'. This operation is not atomic.
+ * Drivers must ensure that there's no race condition while initializing
+ * the variable.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to initialize the variable with
+ */
+void odpdrv_atomic_init_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Load value of atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable
+ */
+uint32_t odpdrv_atomic_load_u32(odpdrv_atomic_u32_t *atom);
+
+/**
+ * Store value to atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to store in the variable
+ */
+void odpdrv_atomic_store_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Fetch and add to atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be added to the variable
+ *
+ * @return Value of the variable before the addition
+ */
+uint32_t odpdrv_atomic_fetch_add_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Add to atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be added to the variable
+ */
+void odpdrv_atomic_add_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Fetch and subtract from atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be subracted from the variable
+ *
+ * @return Value of the variable before the subtraction
+ */
+uint32_t odpdrv_atomic_fetch_sub_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Subtract from atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be subtracted from the variable
+ */
+void odpdrv_atomic_sub_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Fetch and increment atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable before the increment
+ */
+uint32_t odpdrv_atomic_fetch_inc_u32(odpdrv_atomic_u32_t *atom);
+
+/**
+ * Increment atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ */
+void odpdrv_atomic_inc_u32(odpdrv_atomic_u32_t *atom);
+
+/**
+ * Fetch and decrement atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable before the subtraction
+ */
+uint32_t odpdrv_atomic_fetch_dec_u32(odpdrv_atomic_u32_t *atom);
+
+/**
+ * Decrement atomic uint32 variable
+ *
+ * @param atom    Pointer to atomic variable
+ */
+void odpdrv_atomic_dec_u32(odpdrv_atomic_u32_t *atom);
+
+/**
+ * Update maximum value of atomic uint32 variable
+ *
+ * Compares value of atomic variable to the new maximum value. If the new value
+ * is greater than the current value, writes the new value into the variable.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param new_max New maximum value to be written into the atomic variable
+ */
+void odpdrv_atomic_max_u32(odpdrv_atomic_u32_t *atom, uint32_t new_max);
+
+/**
+ * Update minimum value of atomic uint32 variable
+ *
+ * Compares value of atomic variable to the new minimum value. If the new value
+ * is less than the current value, writes the new value into the variable.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param new_min New minimum value to be written into the atomic variable
+ */
+void odpdrv_atomic_min_u32(odpdrv_atomic_u32_t *atom, uint32_t new_min);
+
+/**
+ * Compare and swap atomic uint32 variable
+ *
+ * Compares value of atomic variable to the value pointed by 'old_val'.
+ * If values are equal, the operation writes 'new_val' into the atomic variable
+ * and returns success. If they are not equal, the operation writes current
+ * value of atomic variable into 'old_val' and returns failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ *
+ */
+int odpdrv_atomic_cas_u32(odpdrv_atomic_u32_t *atom, uint32_t *old_val,
+                         uint32_t new_val);
+
+/**
+ * Exchange value of atomic uint32 variable
+ *
+ * Atomically replaces the value of atomic variable with the new value. Returns
+ * the old value.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param new_val New value of the atomic variable
+ *
+ * @return Value of the variable before the operation
+ */
+uint32_t odpdrv_atomic_xchg_u32(odpdrv_atomic_u32_t *atom, uint32_t new_val);
+
+/*
+ * 64-bit operations in RELAXED memory ordering
+ * --------------------------------------------
+ */
+
+/**
+ * Initialize atomic uint64 variable
+ *
+ * Initializes the atomic variable with 'val'. This operation is not atomic.
+ * Drivers must ensure that there's no race condition while initializing
+ * the variable.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to initialize the variable with
+ */
+void odpdrv_atomic_init_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Load value of atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable
+ */
+uint64_t odpdrv_atomic_load_u64(odpdrv_atomic_u64_t *atom);
+
+/**
+ * Store value to atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to store in the variable
+ */
+void odpdrv_atomic_store_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Fetch and add to atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be added to the variable
+ *
+ * @return Value of the variable before the addition
+ */
+uint64_t odpdrv_atomic_fetch_add_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Add to atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be added to the variable
+ */
+void odpdrv_atomic_add_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Fetch and subtract from atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be subtracted from the variable
+ *
+ * @return Value of the variable before the subtraction
+ */
+uint64_t odpdrv_atomic_fetch_sub_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Subtract from atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be subtracted from the variable
+ */
+void odpdrv_atomic_sub_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Fetch and increment atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable before the increment
+ */
+uint64_t odpdrv_atomic_fetch_inc_u64(odpdrv_atomic_u64_t *atom);
+
+/**
+ * Increment atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ */
+void odpdrv_atomic_inc_u64(odpdrv_atomic_u64_t *atom);
+
+/**
+ * Fetch and decrement atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable before the decrement
+ */
+uint64_t odpdrv_atomic_fetch_dec_u64(odpdrv_atomic_u64_t *atom);
+
+/**
+ * Decrement atomic uint64 variable
+ *
+ * @param atom    Pointer to atomic variable
+ */
+void odpdrv_atomic_dec_u64(odpdrv_atomic_u64_t *atom);
+
+/**
+ * Update maximum value of atomic uint64 variable
+ *
+ * Compares value of atomic variable to the new maximum value. If the new value
+ * is greater than the current value, writes the new value into the variable.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param new_max New maximum value to be written into the atomic variable
+ */
+void odpdrv_atomic_max_u64(odpdrv_atomic_u64_t *atom, uint64_t new_max);
+
+/**
+ * Update minimum value of atomic uint64 variable
+ *
+ * Compares value of atomic variable to the new minimum value. If the new value
+ * is less than the current value, writes the new value into the variable.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param new_min New minimum value to be written into the atomic variable
+ */
+void odpdrv_atomic_min_u64(odpdrv_atomic_u64_t *atom, uint64_t new_min);
+
+/**
+ * Compare and swap atomic uint64 variable
+ *
+ * Compares value of atomic variable to the value pointed by 'old_val'.
+ * If values are equal, the operation writes 'new_val' into the atomic variable
+ * and returns success. If they are not equal, the operation writes current
+ * value of atomic variable into 'old_val' and returns failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ */
+int odpdrv_atomic_cas_u64(odpdrv_atomic_u64_t *atom, uint64_t *old_val,
+                         uint64_t new_val);
+
+/**
+ * Exchange value of atomic uint64 variable
+ *
+ * Atomically replaces the value of atomic variable with the new value. Returns
+ * the old value.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param new_val New value of the atomic variable
+ *
+ * @return Value of the variable before the operation
+ */
+uint64_t odpdrv_atomic_xchg_u64(odpdrv_atomic_u64_t *atom, uint64_t new_val);
+
+/*
+ * 32-bit operations in non-RELAXED memory ordering
+ * ------------------------------------------------
+ */
+
+/**
+ * Load value of atomic uint32 variable using ACQUIRE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_load_u32() but ensures ACQUIRE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable
+ */
+uint32_t odpdrv_atomic_load_acq_u32(odpdrv_atomic_u32_t *atom);
+
+/**
+ * Store value to atomic uint32 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_store_u32() but ensures RELEASE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to store in the variable
+ */
+void odpdrv_atomic_store_rel_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Add to atomic uint32 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_add_u32() but ensures RELEASE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be added to the variable
+ */
+void odpdrv_atomic_add_rel_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Subtract from atomic uint32 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_sub_u32() but ensures RELEASE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be subtracted from the variable
+ */
+void odpdrv_atomic_sub_rel_u32(odpdrv_atomic_u32_t *atom, uint32_t val);
+
+/**
+ * Compare and swap atomic uint32 variable using ACQUIRE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_cas_u32() but ensures ACQUIRE memory
+ * ordering on success. Memory ordering is RELAXED on failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ */
+int odpdrv_atomic_cas_acq_u32(odpdrv_atomic_u32_t *atom, uint32_t *old_val,
+                             uint32_t new_val);
+
+/**
+ * Compare and swap atomic uint32 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_cas_u32() but ensures RELEASE memory
+ * ordering on success. Memory ordering is RELAXED on failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ */
+int odpdrv_atomic_cas_rel_u32(odpdrv_atomic_u32_t *atom, uint32_t *old_val,
+                             uint32_t new_val);
+
+/**
+ * Compare and swap atomic uint32 variable using ACQUIRE-and-RELEASE memory
+ * ordering
+ *
+ * Otherwise identical to odpdrv_atomic_cas_u32() but ensures
+ * ACQUIRE-and-RELEASE memory ordering on success.
+ * Memory ordering is RELAXED on failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ */
+int odpdrv_atomic_cas_acq_rel_u32(odpdrv_atomic_u32_t *atom, uint32_t *old_val,
+                                 uint32_t new_val);
+
+/*
+ * 64-bit operations in non-RELAXED memory ordering
+ * ------------------------------------------------
+ */
+
+/**
+ * Load value of atomic uint64 variable using ACQUIRE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_load_u64() but ensures ACQUIRE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ *
+ * @return Value of the variable
+ */
+uint64_t odpdrv_atomic_load_acq_u64(odpdrv_atomic_u64_t *atom);
+
+/**
+ * Store value to atomic uint64 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_store_u64() but ensures RELEASE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to store in the variable
+ */
+void odpdrv_atomic_store_rel_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Add to atomic uint64 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_add_u64() but ensures RELEASE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be added to the variable
+ */
+void odpdrv_atomic_add_rel_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Subtract from atomic uint64 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_sub_u64() but ensures RELEASE memory
+ * ordering.
+ *
+ * @param atom    Pointer to atomic variable
+ * @param val     Value to be subtracted from the variable
+ */
+void odpdrv_atomic_sub_rel_u64(odpdrv_atomic_u64_t *atom, uint64_t val);
+
+/**
+ * Compare and swap atomic uint64 variable using ACQUIRE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_cas_u64() but ensures ACQUIRE memory
+ * ordering on success. Memory ordering is RELAXED on failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ */
+int odpdrv_atomic_cas_acq_u64(odpdrv_atomic_u64_t *atom, uint64_t *old_val,
+                             uint64_t new_val);
+
+/**
+ * Compare and swap atomic uint64 variable using RELEASE memory ordering
+ *
+ * Otherwise identical to odpdrv_atomic_cas_u64() but ensures RELEASE memory
+ * ordering on success. Memory ordering is RELAXED on failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ */
+int odpdrv_atomic_cas_rel_u64(odpdrv_atomic_u64_t *atom, uint64_t *old_val,
+                             uint64_t new_val);
+
+/**
+ * Compare and swap atomic uint64 variable using ACQUIRE-and-RELEASE memory
+ * ordering
+ *
+ * Otherwise identical to odpdrv_atomic_cas_u64() but ensures
+ * ACQUIRE-and-RELEASE memory ordering on success. Memory ordering is RELAXED
+ * on failure.
+ *
+ * @param         atom      Pointer to atomic variable
+ * @param[in,out] old_val   Pointer to the old value of the atomic variable.
+ *                          Operation updates this value on failure.
+ * @param         new_val   New value to be written into the atomic variable
+ *
+ * @return 0 on failure, !0 on success
+ */
+int odpdrv_atomic_cas_acq_rel_u64(odpdrv_atomic_u64_t *atom, uint64_t *old_val,
+                                 uint64_t new_val);
+
+/**
+ * Atomic operations
+ *
+ * Atomic operations listed in a bit field structure.
+ */
+typedef union odpdrv_atomic_op_t {
+       /** Operation flags */
+       struct {
+               uint32_t init      : 1;  /**< Init atomic variable */
+               uint32_t load      : 1;  /**< Atomic load */
+               uint32_t store     : 1;  /**< Atomic store */
+               uint32_t fetch_add : 1;  /**< Atomic fetch and add */
+               uint32_t add       : 1;  /**< Atomic add */
+               uint32_t fetch_sub : 1;  /**< Atomic fetch and subtract */
+               uint32_t sub       : 1;  /**< Atomic subtract */
+               uint32_t fetch_inc : 1;  /**< Atomic fetch and increment */
+               uint32_t inc       : 1;  /**< Atomic increment */
+               uint32_t fetch_dec : 1;  /**< Atomic fetch and decrement */
+               uint32_t dec       : 1;  /**< Atomic decrement */
+               uint32_t min       : 1;  /**< Atomic minimum */
+               uint32_t max       : 1;  /**< Atomic maximum */
+               uint32_t cas       : 1;  /**< Atomic compare and swap */
+               uint32_t xchg      : 1;  /**< Atomic exchange */
+       } op;
+
+       /** All bits of the bit field structure.
+         * Operation flag mapping is architecture specific. This field can be
+         * used to set/clear all flags, or bitwise operations over the entire
+         * structure. */
+       uint32_t all_bits;
+} odpdrv_atomic_op_t;
+
+/**
+ * Query which atomic uint64 operations are lock-free
+ *
+ * Lock-free implementations have higher performance and scale better than
+ * implementations using locks. User can decide to use e.g. uint32 atomic
+ * variables instead of uint64 to optimize performance on platforms that
+ * implement a performance critical operation using locks.
+ *
+ * Init operations (e.g. odpdrv_atomic_init_64()) are not atomic. This function
+ * clears the op.init bit but will never set it to one.
+ *
+ * @param atomic_op  Pointer to atomic operation structure for storing
+ *                   operation flags. All bits are initialized to zero during
+ *                   the operation. The parameter is ignored when NULL.
+ * @retval 0 None of the operations are lock-free
+ * @retval 1 Some of the operations are lock-free
+ * @retval 2 All operations are lock-free
+ */
+int odpdrv_atomic_lock_free_u64(odpdrv_atomic_op_t *atomic_op);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <odp/visibility_end.h>
+#endif
diff --git a/platform/Makefile.inc b/platform/Makefile.inc
index edb598f..900b023 100644
--- a/platform/Makefile.inc
+++ b/platform/Makefile.inc
@@ -64,6 +64,7 @@ odpapispecinclude_HEADERS = \
 odpdrvspecincludedir= $(includedir)/odp/drv/spec
 odpdrvspecinclude_HEADERS = \
                  $(top_srcdir)/include/odp/drv/spec/align.h \
+                 $(top_srcdir)/include/odp/drv/spec/atomic.h \
                  $(top_srcdir)/include/odp/drv/spec/byteorder.h \
                  $(top_srcdir)/include/odp/drv/spec/compiler.h \
                  $(top_srcdir)/include/odp/drv/spec/std_types.h \
-- 
2.7.4

Reply via email to