<commit_before>#include <parrot/parrot.h>
#include <parrot/atomic.h>

/*
=head1 NAME

src/stm/backend.c -- Software transactional memory implementation

=head1 DESCRIPTION

This file implements the non-user-visible parts of the Software
Transactional Memory implementation, including handling of all
the low-level synchornization.

=head2 Functions

=over 4

=cut
*/


#include "stm_internal.h"

#define STM_DEBUG 0

#if STM_DEBUG
#  define STM_TRACE(x...) PIO_fprintf(interp, PIO_STDERR(interp), x); PIO_fprintf(interp, PIO_STDERR(interp), "\n")
#undef fprintf
#  define STM_TRACE_SAFE(x...) fprintf(stderr, x); fprintf(stderr, "\n");
#else
static void STM_TRACE(const char *x, ...) {
}
static void STM_TRACE_SAFE(const char *x, ...) {
}
#endif

static PMC *force_sharing(Interp *, PMC *);

static UINTVAL handle_is_version(Parrot_STM_PMC_handle data) {
    void *ptr;
    PARROT_ATOMIC_PTR_GET(ptr, data->owner_or_version);
    return PTR2UINTVAL(ptr) & 1;
}

static STM_tx_log *Parrot_STM_tx_log_alloc(Interp *interp, size_t size) {
    int i;
    STM_tx_log *log;
    log = mem_sys_allocate_zeroed(size);

    interp->thread_data->stm_log = (void *) log;

    /* initialize the various fields of the transaction log */

    for (i = 0; i < STM_MAX_TX_DEPTH; ++i) {
        PARROT_ATOMIC_INT_INIT(log->inner[i].status);
        PARROT_ATOMIC_INT_INIT(log->inner[i].wait_length);
        PARROT_ATOMIC_INT_SET(log->inner[i].status, STM_STATUS_INVALID);
        assert((PTR2UINTVAL(&log->inner[i]) & 1) == 0);
    }
    log->inner[0].first_read = log->inner[0].first_write = 0;

    log->writes = mem_sys_allocate(sizeof(STM_write_record) * STM_START_RECORDS);
    log->writes_alloced = STM_START_RECORDS;
    log->reads = mem_sys_allocate(sizeof(STM_read_record) * STM_START_RECORDS);
    log->reads_alloced = STM_START_RECORDS;

    log->last_read = log->last_write = -1;

    log->depth = 0;

    return log;
}

/*

=item C<void Parrot_STM_destroy(Interp *interp)>

Free all resources associated with STM in the interpreter C<interp>.

=cut

*/

void Parrot_STM_destroy(Interp *interp) {
    STM_tx_log *log;
    if (!interp->thread_data || !interp->thread_data->stm_log)
        return;

    log = interp->thread_data->stm_log;
    mem_sys_free(log->writes);
    mem_sys_free(log->reads);
    Parrot_STM_waitlist_destroy_thread(interp);
    mem_sys_free(log);
    interp->thread_data->stm_log = NULL;
}


STM_tx_log *Parrot_STM_tx_log_get(Interp *interp) {
    STM_tx_log *log = interp->thread_data->stm_log; /* FIXME */
    if (!log)
        log = Parrot_STM_tx_log_alloc(interp, sizeof(STM_tx_log));

    assert(log->depth >= 0);
    return log;
}

typedef struct Parrot_STM_PMC_handle_data handle_data;

/*
=item C<Parrot_STM_PMC_handle Parrot_STM_alloc(Interp *interp, PMC *pmc)>

Create a new handle that will wrap a STM-managed PMC. The initial value
of the PMC will be a copy of C<pmc>.

=cut
*/
Parrot_STM_PMC_handle Parrot_STM_alloc(Interp *interp, PMC *pmc) {
    handle_data *handle;
    STM_TRACE("Parrot_STM_alloc");

    make_bufferlike_pool(interp, sizeof(handle_data));
    handle = new_bufferlike_header(interp, sizeof(handle_data));
    PObj_external_SET(&handle->buf);
    PObj_is_shared_SET(&handle->buf);
    PARROT_ATOMIC_PTR_SET(handle->owner_or_version, UINTVAL2PTR(void *, 1)); /* XXX */
    handle->last_version = UINTVAL2PTR(void *, 1);
    handle->value = force_sharing(interp, pmc);
    Parrot_STM_waitlist_init(interp, &handle->change_waitlist);
    return handle;
}

/* XXX FIXME these are just to make Parrot_clone work.
 * Real solution will require knowing when we are cloning
 * and when it is a normal freeze/thaw -- or implementing
 * cloning seperately.
 */<commit_msg>Call PARROT_ATOMIC_PTR_INIT.<commit_after>#include <parrot/parrot.h>
#include <parrot/atomic.h>

/*
=head1 NAME

src/stm/backend.c -- Software transactional memory implementation

=head1 DESCRIPTION

This file implements the non-user-visible parts of the Software
Transactional Memory implementation, including handling of all
the low-level synchornization.

=head2 Functions

=over 4

=cut
*/


#include "stm_internal.h"

#define STM_DEBUG 0

#if STM_DEBUG
#  define STM_TRACE(x...) PIO_fprintf(interp, PIO_STDERR(interp), x); PIO_fprintf(interp, PIO_STDERR(interp), "\n")
#undef fprintf
#  define STM_TRACE_SAFE(x...) fprintf(stderr, x); fprintf(stderr, "\n");
#else
static void STM_TRACE(const char *x, ...) {
}
static void STM_TRACE_SAFE(const char *x, ...) {
}
#endif

static PMC *force_sharing(Interp *, PMC *);

static UINTVAL handle_is_version(Parrot_STM_PMC_handle data) {
    void *ptr;
    PARROT_ATOMIC_PTR_GET(ptr, data->owner_or_version);
    return PTR2UINTVAL(ptr) & 1;
}

static STM_tx_log *Parrot_STM_tx_log_alloc(Interp *interp, size_t size) {
    int i;
    STM_tx_log *log;
    log = mem_sys_allocate_zeroed(size);

    interp->thread_data->stm_log = (void *) log;

    /* initialize the various fields of the transaction log */

    for (i = 0; i < STM_MAX_TX_DEPTH; ++i) {
        PARROT_ATOMIC_INT_INIT(log->inner[i].status);
        PARROT_ATOMIC_INT_INIT(log->inner[i].wait_length);
        PARROT_ATOMIC_INT_SET(log->inner[i].status, STM_STATUS_INVALID);
        assert((PTR2UINTVAL(&log->inner[i]) & 1) == 0);
    }
    log->inner[0].first_read = log->inner[0].first_write = 0;

    log->writes = mem_sys_allocate(sizeof(STM_write_record) * STM_START_RECORDS);
    log->writes_alloced = STM_START_RECORDS;
    log->reads = mem_sys_allocate(sizeof(STM_read_record) * STM_START_RECORDS);
    log->reads_alloced = STM_START_RECORDS;

    log->last_read = log->last_write = -1;

    log->depth = 0;

    return log;
}

/*

=item C<void Parrot_STM_destroy(Interp *interp)>

Free all resources associated with STM in the interpreter C<interp>.

=cut

*/

void Parrot_STM_destroy(Interp *interp) {
    STM_tx_log *log;
    if (!interp->thread_data || !interp->thread_data->stm_log)
        return;

    log = interp->thread_data->stm_log;
    mem_sys_free(log->writes);
    mem_sys_free(log->reads);
    Parrot_STM_waitlist_destroy_thread(interp);
    mem_sys_free(log);
    interp->thread_data->stm_log = NULL;
}


STM_tx_log *Parrot_STM_tx_log_get(Interp *interp) {
    STM_tx_log *log = interp->thread_data->stm_log; /* FIXME */
    if (!log)
        log = Parrot_STM_tx_log_alloc(interp, sizeof(STM_tx_log));

    assert(log->depth >= 0);
    return log;
}

typedef struct Parrot_STM_PMC_handle_data handle_data;

/*
=item C<Parrot_STM_PMC_handle Parrot_STM_alloc(Interp *interp, PMC *pmc)>

Create a new handle that will wrap a STM-managed PMC. The initial value
of the PMC will be a copy of C<pmc>.

=cut
*/
Parrot_STM_PMC_handle Parrot_STM_alloc(Interp *interp, PMC *pmc) {
    handle_data *handle;
    STM_TRACE("Parrot_STM_alloc");

    make_bufferlike_pool(interp, sizeof(handle_data));
    handle = new_bufferlike_header(interp, sizeof(handle_data));
    PObj_external_SET(&handle->buf);
    PObj_is_shared_SET(&handle->buf);
    PARROT_ATOMIC_PTR_INIT(handle->owner_or_version);
    PARROT_ATOMIC_PTR_SET(handle->owner_or_version, UINTVAL2PTR(void *, 1)); /* XXX */
    handle->last_version = UINTVAL2PTR(void *, 1);
    handle->value = force_sharing(interp, pmc);
    Parrot_STM_waitlist_init(interp, &handle->change_waitlist);
    return handle;
}

/* XXX FIXME these are just to make Parrot_clone work.
 * Real solution will require knowing when we are cloning
 * and when it is a normal freeze/thaw -- or implementing
 * cloning seperately.
 */
{'fraction_non_alphanumeric': 0.12198051514747098, 'fraction_numerical': 0.00560523154944615, 'mean_word_length': 4.333807829181494, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 86, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2834856', 'n_tokens_mistral': 2876, 'n_tokens_neox': 2753, 'n_words': 566}