mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-08 18:34:00 +00:00
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.
135 lines
3.2 KiB
C
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
|