Files
mercury/runtime/mercury_wsdeque.c
Mark Brown d465fa53cb Update the COPYING.LIB file and references to it.
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.

COPYING.LIB:
    Add a special linking exception to the LGPL.

*:
    Update references to COPYING.LIB.

    Clean up some minor errors that have accumulated in copyright
    messages.
2018-06-09 17:43:12 +10:00

135 lines
3.2 KiB
C

// vim: ts=4 sw=4 expandtab ft=c
// Copyright (C) 2007, 2010-2011 The University of Melbourne.
// Copyright (C) 2016, 2018 The Mercury team.
// This file is distributed under the terms specified in COPYING.LIB.
// mercury_wsdeque.c
//
// This file implements the basic algorithm from David Chase, Yossi Lev:
// "Dynamic circular work-stealing deque". SPAA 2005: 21-28.
//
// A work-stealing deque is a double ended queue in which only one thread can
// access one end of the queue (the bottom) while other threads can only pop
// elements from the other end (the top).
//
// XXX: We need to insert memory barriers in the right places.
#include "mercury_imp.h"
#include "mercury_memory_handlers.h"
#include "mercury_context.h"
#include "mercury_wsdeque.h"
////////////////////////////////////////////////////////////////////////////
#ifdef MR_LL_PARALLEL_CONJ
static MR_SparkArray *
MR_alloc_spark_array(MR_Integer size);
void
MR_init_wsdeque(MR_SparkDeque *dq, MR_Integer size)
{
dq->MR_sd_bottom = 0;
dq->MR_sd_top = 0;
dq->MR_sd_active_array = MR_alloc_spark_array(size);
}
MR_bool
MR_wsdeque_is_empty(const MR_SparkDeque *dq)
{
return dq->MR_sd_bottom == dq->MR_sd_top;
}
void
MR_wsdeque_putback_bottom(MR_SparkDeque *dq, const MR_Spark *spark)
{
MR_Integer bot;
volatile MR_SparkArray *arr;
bot = dq->MR_sd_bottom;
arr = dq->MR_sd_active_array;
MR_sa_element(arr, bot) = *spark;
dq->MR_sd_bottom = bot + 1;
}
int
MR_wsdeque_steal_top(MR_SparkDeque *dq, MR_Spark *ret_spark)
{
MR_Integer top;
MR_Integer bot;
volatile MR_SparkArray *arr;
MR_Integer size;
top = dq->MR_sd_top;
bot = dq->MR_sd_bottom;
arr = dq->MR_sd_active_array;
size = bot - top;
if (size <= 0) {
return 0; // empty
}
*ret_spark = MR_sa_element(arr, top);
if (!MR_compare_and_swap_int(&dq->MR_sd_top, top, top + 1)) {
return -1; // abort
}
return 1; // success
}
int
MR_wsdeque_take_top(MR_SparkDeque *dq, MR_Spark *ret_spark)
{
MR_Integer top;
MR_Integer bot;
volatile MR_SparkArray *arr;
MR_Integer size;
top = dq->MR_sd_top;
bot = dq->MR_sd_bottom;
arr = dq->MR_sd_active_array;
size = bot - top;
if (size <= 0) {
return 0; // empty
}
*ret_spark = MR_sa_element(arr, top);
dq->MR_sd_top = top + 1;
return 1; // success
}
static MR_SparkArray *
MR_alloc_spark_array(MR_Integer size)
{
MR_SparkArray *arr;
size_t num_bytes;
num_bytes = sizeof(MR_SparkArray) + (size - 1) * sizeof(MR_Spark);
arr = MR_GC_malloc_attrib(num_bytes, MR_ALLOC_SITE_RUNTIME);
arr->MR_sa_max = size - 1;
return arr;
}
MR_SparkArray *
MR_grow_spark_array(const MR_SparkArray *old_arr, MR_Integer bot,
MR_Integer top)
{
MR_Integer new_size;
MR_SparkArray *new_arr;
MR_Integer i;
new_size = 2 * (old_arr->MR_sa_max + 1);
new_arr = MR_alloc_spark_array(new_size);
for (i = top; i < bot; i++) {
MR_sa_element(new_arr, i) = MR_sa_element(old_arr, i);
}
return new_arr;
}
#endif // !MR_LL_PARALLEL_CONJ