#include "memops.h"
#include "obj.h"
#include "out.h"
#include "valgrind_internal.h"
void
operation_init(struct operation_context *ctx, const void *base,
const struct redo_ctx *redo_ctx, struct redo_log *redo)
{
ctx->base = base;
ctx->redo_ctx = redo_ctx;
ctx->redo = redo;
if (redo_ctx)
ctx->p_ops = redo_get_pmem_ops(redo_ctx);
else
ctx->p_ops = NULL;
ctx->nentries[ENTRY_PERSISTENT] = 0;
ctx->nentries[ENTRY_TRANSIENT] = 0;
}
static inline void
operation_perform(uint64_t *field, uint64_t value,
enum operation_type op_type)
{
switch (op_type) {
case OPERATION_AND:
*field &= value;
break;
case OPERATION_OR:
*field |= value;
break;
case OPERATION_SET:
break;
default:
ASSERT(0);
}
}
void
operation_add_typed_entry(struct operation_context *ctx,
void *ptr, uint64_t value,
enum operation_type type, enum operation_entry_type en_type)
{
ASSERT(ctx->nentries[ENTRY_PERSISTENT] < MAX_MEMOPS_ENTRIES);
ASSERT(ctx->nentries[ENTRY_TRANSIENT] < MAX_MEMOPS_ENTRIES);
struct operation_entry en = {ptr, value, OPERATION_SET};
struct operation_entry *e;
for (size_t i = 0; i < ctx->nentries[en_type]; ++i) {
e = &ctx->entries[en_type][i];
if (e->ptr == ptr) {
operation_perform(&e->value, value, type);
return;
}
}
if (type == OPERATION_AND || type == OPERATION_OR) {
en.value = *(uint64_t *)ptr;
operation_perform(&en.value, value, type);
}
ctx->entries[en_type][ctx->nentries[en_type]] = en;
ctx->nentries[en_type]++;
}
void
operation_add_entry(struct operation_context *ctx, void *ptr, uint64_t value,
enum operation_type type)
{
const struct pmem_ops *p_ops = ctx->p_ops;
PMEMobjpool *pop = (PMEMobjpool *)p_ops->base;
int from_pool = OBJ_OFF_IS_VALID(pop,
(uintptr_t)ptr - (uintptr_t)p_ops->base);
operation_add_typed_entry(ctx, ptr, value, type,
from_pool ? ENTRY_PERSISTENT : ENTRY_TRANSIENT);
}
static void
operation_process_persistent_redo(struct operation_context *ctx)
{
struct operation_entry *e;
const struct redo_ctx *redo = ctx->redo_ctx;
size_t i;
for (i = 0; i < ctx->nentries[ENTRY_PERSISTENT]; ++i) {
e = &ctx->entries[ENTRY_PERSISTENT][i];
redo_log_store(redo, ctx->redo, i,
(uintptr_t)e->ptr - (uintptr_t)ctx->base,
e->value);
}
redo_log_set_last(redo, ctx->redo, i - 1);
redo_log_process(redo, ctx->redo, i);
}
void
operation_process(struct operation_context *ctx)
{
struct operation_entry *e;
if (ctx->nentries[ENTRY_PERSISTENT] == 1) {
e = &ctx->entries[ENTRY_PERSISTENT][0];
VALGRIND_ADD_TO_TX(e->ptr, sizeof(uint64_t));
*e->ptr = e->value;
pmemops_persist(ctx->p_ops, e->ptr,
sizeof(uint64_t));
VALGRIND_REMOVE_FROM_TX(e->ptr, sizeof(uint64_t));
} else if (ctx->nentries[ENTRY_PERSISTENT] != 0) {
operation_process_persistent_redo(ctx);
}
for (size_t i = 0; i < ctx->nentries[ENTRY_TRANSIENT]; ++i) {
e = &ctx->entries[ENTRY_TRANSIENT][i];
*e->ptr = e->value;
VALGRIND_SET_CLEAN(e->ptr, sizeof(e->value));
}
}