+#include "internal_config.h"
+#include <unistd.h>
+
+#ifndef _XBT_WIN32
+#include <sys/syscall.h>
+#endif
+
+#ifdef HAVE_FUTEX_H
+#include <linux/futex.h>
+#include <limits.h>
+#endif
+
+#include "xbt/parmap.h"
+#include "xbt/log.h"
+#include "xbt/function_types.h"
+#include "xbt/dynar.h"
+#include "xbt/xbt_os_thread.h"
+#include "xbt/sysdep.h"
+#include "simix/smx_private.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_parmap, xbt, "parmap: parallel map");
+
+typedef enum {
+ XBT_PARMAP_WORK,
+ XBT_PARMAP_DESTROY
+} e_xbt_parmap_flag_t;
+
+static void xbt_parmap_set_mode(xbt_parmap_t parmap, e_xbt_parmap_mode_t mode);
+static void *xbt_parmap_worker_main(void *parmap);
+static void xbt_parmap_work(xbt_parmap_t parmap);
+
+static void xbt_parmap_posix_master_wait(xbt_parmap_t parmap);
+static void xbt_parmap_posix_worker_signal(xbt_parmap_t parmap);
+static void xbt_parmap_posix_master_signal(xbt_parmap_t parmap);
+static void xbt_parmap_posix_worker_wait(xbt_parmap_t parmap, unsigned round);
+
+#ifdef HAVE_FUTEX_H
+static void xbt_parmap_futex_master_wait(xbt_parmap_t parmap);
+static void xbt_parmap_futex_worker_signal(xbt_parmap_t parmap);
+static void xbt_parmap_futex_master_signal(xbt_parmap_t parmap);
+static void xbt_parmap_futex_worker_wait(xbt_parmap_t parmap, unsigned round);
+static void futex_wait(unsigned *uaddr, unsigned val);
+static void futex_wake(unsigned *uaddr, unsigned val);
+#endif
+
+static void xbt_parmap_busy_master_wait(xbt_parmap_t parmap);
+static void xbt_parmap_busy_worker_signal(xbt_parmap_t parmap);
+static void xbt_parmap_busy_master_signal(xbt_parmap_t parmap);
+static void xbt_parmap_busy_worker_wait(xbt_parmap_t parmap, unsigned round);
+
+#ifdef HAVE_MC
+static void xbt_parmap_mc_work(xbt_parmap_t parmap, int worker_id);
+static void *xbt_parmap_mc_worker_main(void *arg);
+#endif
+
+/**
+ * \brief Parallel map structure
+ */
+typedef struct s_xbt_parmap {
+ e_xbt_parmap_flag_t status; /**< is the parmap active or being destroyed? */
+ unsigned work; /**< index of the current round */
+ unsigned thread_counter; /**< number of workers that have done the work */
+
+ unsigned int num_workers; /**< total number of worker threads including the controller */
+ xbt_os_thread_t *workers; /**< worker thread handlers */
+ void_f_pvoid_t fun; /**< function to run in parallel on each element of data */
+ xbt_dynar_t data; /**< parameters to pass to fun in parallel */
+ unsigned int index; /**< index of the next element of data to pick */
+
+#ifdef HAVE_MC
+ int finish;
+ void* ref_snapshot;
+ int_f_pvoid_pvoid_t snapshot_compare;
+ unsigned int length;
+ void* mc_data;
+#endif
+
+ /* posix only */
+ xbt_os_cond_t ready_cond;
+ xbt_os_mutex_t ready_mutex;
+ xbt_os_cond_t done_cond;
+ xbt_os_mutex_t done_mutex;
+
+ /* fields that depend on the synchronization mode */
+ e_xbt_parmap_mode_t mode; /**< synchronization mode */
+ void (*master_wait_f)(xbt_parmap_t); /**< wait for the workers to have done the work */
+ void (*worker_signal_f)(xbt_parmap_t); /**< signal the master that a worker has done the work */
+ void (*master_signal_f)(xbt_parmap_t); /**< wakes the workers threads to process tasks */
+ void (*worker_wait_f)(xbt_parmap_t, unsigned); /**< waits for more work */
+} s_xbt_parmap_t;
+
+/**
+ * \brief Thread data transmission structure
+ */
+typedef struct s_xbt_parmap_thread_data{
+ xbt_parmap_t parmap;
+ int worker_id;
+} s_xbt_parmap_thread_data_t;
+
+typedef s_xbt_parmap_thread_data_t *xbt_parmap_thread_data_t;
+
+/**
+ * \brief Creates a parallel map object
+ * \param num_workers number of worker threads to create
+ * \param mode how to synchronize the worker threads
+ * \return the parmap created
+ */
+xbt_parmap_t xbt_parmap_new(unsigned int num_workers, e_xbt_parmap_mode_t mode)
+{
+ unsigned int i;
+
+ XBT_DEBUG("Create new parmap (%u workers)", num_workers);