p99_tp.h 4.23 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/* This may look like nonsense, but it really is -*- mode: C -*-              */
/*                                                                            */
/* Except for parts copied from previous work and as explicitly stated below, */
/* the author and copyright holder for this work is                           */
/* (C) copyright  2013 Jens Gustedt, INRIA, France                            */
/*                                                                            */
/* This file is free software; it is part of the P99 project.                 */
/* You can redistribute it and/or modify it under the terms of the QPL as     */
/* given in the file LICENSE. It is distributed without any warranty;         */
/* without even the implied warranty of merchantability or fitness for a      */
/* particular purpose.                                                        */
/*                                                                            */
#ifndef P99_RP_H
#define P99_RP_H 1

#include "p99_enum.h"
#include "p99_generic.h"

/* Additions by C11 */
# if __STDC_VERSION__ < 201100L
#  include "p99_atomic.h"
# endif

#if UINTPTR_MAX == UINT32_MAX
25
typedef uint64_t p00_tp_state;
26 27
#else
# if defined(UINT128_MAX)
28
typedef uint128_t p00_tp_state;
29
# else
30
typedef p99x_uint128 p00_tp_state;
31 32 33
# endif
#endif

34
P99_CONSTANT(int, p00_tp_bits, sizeof(p00_tp_state)*CHAR_BIT);
35 36
P99_CONSTANT(int, p00_tp_shift, p00_tp_bits/2);

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
p99_inline
p00_tp_state p00_tp_p2i(void * p, uintptr_t t) {
  return (((p00_tp_state)t)<<p00_tp_shift)|(uintptr_t)p;
}

p99_inline
void * p00_tp_i2p(p00_tp_state v) {
  return (void*)(uintptr_t)v;
}

p99_inline
uintptr_t p00_tp_i2i(p00_tp_state v) {
  return v >> p00_tp_shift;
}

P99_DECLARE_ATOMIC(p00_tp_state);
53 54 55 56

P99_DECLARE_STRUCT(p99_tp);
P99_DECLARE_STRUCT(p99_tp_state);

Jens Gustedt's avatar
Jens Gustedt committed
57 58 59 60 61 62 63 64 65
/**
 ** @brief A tagged pointer for atomic storage.
 **
 ** The idea of this data structure is to store a unique transaction
 ** ID together with a pointer such that different usages of the same
 ** pointer can be distinguished.
 **
 ** @see p99_tp_state
 **/
66
struct p99_tp {
67
  _Atomic(p00_tp_state) p00_val;
68 69 70
  _Atomic(uintptr_t) p00_tic;
};

Jens Gustedt's avatar
Jens Gustedt committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
/**
 ** @brief A local view of a tagged pointer for atomic storage.
 **
 ** This is to be used together with ::p99_tp.
 **
 ** @code
 ** p99_tp tp = P99_TP_INITIALIZER(0);
 ** ...
 ** void * fut = &(int){ 37 };
 ** p99_tp_state st = p99_tp_state_initializer(&tp, fut);
 ** void * val = p99_tp_state_get(&st);
 ** // do something with the current value, then
 ** // commit the new value "fut" if possible
 ** if (!p99_tp_state_commit(&st)) abort();
 ** @endcode
 **
 ** @see p99_tp_state_get
 ** @see p99_tp_state_set
 ** @see p99_tp_state_commit
 ** @see p99_tp_state_initializer
 **/
92
struct p99_tp_state {
93 94
  p00_tp_state p00_val;
  p00_tp_state p00_next;
95 96 97 98 99 100 101 102 103
  p99_tp* p00_tp;
};

# define P99_TP_INITIALIZER(VAL) {                             \
    .p00_val = ATOMIC_VAR_INIT((uintptr_t)(void*)VAL),         \
      .p00_tic = ATOMIC_VAR_INIT(UINTPTR_C(1)),                \
}

p99_inline
104
p00_tp_state p00_tp_get(p99_tp* p00_tp) {
105 106 107
  return atomic_load(&p00_tp->p00_val);
}

Jens Gustedt's avatar
Jens Gustedt committed
108 109 110 111
/**
 ** @brief Load the value of @a p00_tp into the state variable and
 ** prepare it to commit value @a p00_p later.
 **/
112 113 114
p99_inline
p99_tp_state p99_tp_state_initializer(p99_tp* p00_tp, void* p00_p) {
  uintptr_t p00_tic = atomic_fetch_add(&p00_tp->p00_tic, UINTPTR_C(1));
115 116
  return (p99_tp_state) {
    .p00_val = p00_tp_get(p00_tp),
117
      .p00_next = p00_tp_p2i(p00_p, p00_tic),
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
      .p00_tp = p00_tp,
  };
}

p99_inline
void * p99_tp_state_get(p99_tp_state* p00_state) {
  return p00_tp_i2p(p00_state->p00_val);
}

p99_inline
void * p99_tp_get(p99_tp* p00_tp) {
  return p00_tp_i2p(p00_tp_get(p00_tp));
}

p99_inline
void p99_tp_state_set(p99_tp_state* p00_state, void* p00_p) {
134
  p00_state->p00_next = p00_tp_p2i(p00_p, p00_tp_i2i(p00_state->p00_next));
135 136 137
}

p99_inline
138
bool p00_tp_cmpxchg(_Atomic(p00_tp_state)* p00_p, p00_tp_state* p00_prev, p00_tp_state p00_new) {
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
  P99_MARK("wide cmpxchg start");
  bool ret = atomic_compare_exchange_weak(p00_p, p00_prev, p00_new);
  P99_MARK("wide cmpxchg end");
  return ret;
}

p99_inline
bool p99_tp_state_commit(p99_tp_state* p00_state) {
  return p00_tp_cmpxchg(&p00_state->p00_tp->p00_val, &p00_state->p00_val, p00_state->p00_next);
}





#endif