-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaction.h
261 lines (225 loc) · 8.4 KB
/
action.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/** @file action.h
* @brief Models actions taken by threads.
*/
#ifndef __ACTION_H__
#define __ACTION_H__
#include <cstddef>
#include <inttypes.h>
#include "mymemory.h"
#include "memoryorder.h"
#include "modeltypes.h"
#include "mypthread.h"
#include "classlist.h"
namespace cdsc {
class mutex;
}
using std::memory_order;
using std::memory_order_relaxed;
using std::memory_order_consume;
using std::memory_order_acquire;
using std::memory_order_release;
using std::memory_order_acq_rel;
using std::memory_order_seq_cst;
/**
* @brief A recognizable don't-care value for use in the ModelAction::value
* field
*
* Note that this value can be legitimately used by a program, and hence by
* iteself does not indicate no value.
*/
#define VALUE_NONE 0xdeadbeef
#define WRITE_REFERENCED ((void *)0x1)
/**
* @brief The "location" at which a fence occurs
*
* We need a non-zero memory location to associate with fences, since our hash
* tables don't handle NULL-pointer keys. HACK: Hopefully this doesn't collide
* with any legitimate memory locations.
*/
#define FENCE_LOCATION ((void *)0x7)
/** @brief Represents an action type, identifying one of several types of
* ModelAction */
typedef enum action_type {
THREAD_CREATE, // < A thread creation action
THREAD_START, // < First action in each thread
THREAD_YIELD, // < A thread yield action
THREAD_JOIN, // < A thread join action
THREAD_FINISH, // < A thread completion action
THREADONLY_FINISH, // < A thread completion action
THREAD_SLEEP, // < A sleep operation
PTHREAD_CREATE, // < A pthread creation action
PTHREAD_JOIN, // < A pthread join action
NONATOMIC_WRITE, // < Represents a non-atomic store
ATOMIC_INIT, // < Initialization of an atomic object (e.g., atomic_init())
ATOMIC_WRITE, // < An atomic write action
ATOMIC_RMW, // < The write part of an atomic RMW action
ATOMIC_READ, // < An atomic read action
ATOMIC_RMWR, // < The read part of an atomic RMW action
ATOMIC_RMWRCAS, // < The read part of an atomic RMW action
ATOMIC_RMWC, // < Convert an atomic RMW action into a READ
ATOMIC_FENCE, // < A fence action
ATOMIC_LOCK, // < A lock action
ATOMIC_TRYLOCK, // < A trylock action
ATOMIC_UNLOCK, // < An unlock action
ATOMIC_NOTIFY_ONE, // < A notify_one action
ATOMIC_NOTIFY_ALL, // < A notify all action
ATOMIC_WAIT, // < A wait action
ATOMIC_TIMEDWAIT, // < A timed wait action
ATOMIC_ANNOTATION, // < An annotation action to pass information to a trace analysis
READY_FREE, // < Write is ready to be freed
ATOMIC_NOP // < Placeholder
} action_type_t;
/**
* @brief Represents a single atomic action
*
* A ModelAction is always allocated as non-snapshotting, because it is used in
* multiple executions during backtracking. Except for non-atomic write
* ModelActions, each action is assigned a unique sequence
* number.
*/
class ModelAction {
public:
ModelAction(action_type_t type, memory_order order, void *loc, uint64_t value = VALUE_NONE, Thread *thread = NULL);
ModelAction(action_type_t type, memory_order order, void *loc, uint64_t value, int size);
ModelAction(action_type_t type, const char * position, memory_order order, void *loc, uint64_t value, int size);
ModelAction(action_type_t type, memory_order order, uint64_t value, uint64_t time);
ModelAction(action_type_t type, const char * position, memory_order order, void *loc, uint64_t value = VALUE_NONE, Thread *thread = NULL);
~ModelAction();
void print() const;
thread_id_t get_tid() const { return tid; }
action_type get_type() const { return type; }
void set_type(action_type _type) { type = _type; }
void set_free() { type = READY_FREE; }
memory_order get_mo() const { return order; }
memory_order get_original_mo() const { return original_order; }
void set_mo(memory_order order) { this->order = order; }
void * get_location() const { return location; }
const char * get_position() const { return position; }
modelclock_t get_seq_number() const { return seq_number; }
uint64_t get_value() const { return value; }
uint64_t get_reads_from_value() const;
uint64_t get_write_value() const;
uint64_t get_return_value() const;
ModelAction * get_reads_from() const { return reads_from; }
uint64_t get_time() const { return time; }
void set_time(uint64_t _time) { time = _time; }
cdsc::mutex * get_mutex() const;
void set_read_from(ModelAction *act);
/** Store the most recent fence-release from the same thread
* @param fence The fence-release that occured prior to this */
void set_last_fence_release(const ModelAction *fence) { last_fence_release = fence; }
/** @return The most recent fence-release from the same thread */
const ModelAction * get_last_fence_release() const { return last_fence_release; }
void copy_from_new(ModelAction *newaction);
void set_seq_number(modelclock_t num);
void reset_seq_number();
void set_try_lock(bool obtainedlock);
bool is_thread_start() const;
bool is_thread_join() const;
bool is_mutex_op() const;
bool is_lock() const;
bool is_sleep() const;
bool is_trylock() const;
bool is_unlock() const;
bool is_wait() const;
bool is_timedwait() const;
bool is_create() const;
bool is_notify() const;
bool is_notify_one() const;
bool is_success_lock() const;
bool is_failed_trylock() const;
bool is_atomic_var() const;
bool is_read() const;
bool is_write() const;
bool is_free() const;
bool is_yield() const;
bool could_be_write() const;
bool is_rmwr() const;
bool is_rmwrcas() const;
bool is_rmwc() const;
bool is_rmw() const;
bool is_fence() const;
bool is_initialization() const;
bool is_annotation() const;
bool is_relaxed() const;
bool is_acquire() const;
bool is_release() const;
bool is_seqcst() const;
bool same_var(const ModelAction *act) const;
bool same_thread(const ModelAction *act) const;
bool is_conflicting_lock(const ModelAction *act) const;
bool could_synchronize_with(const ModelAction *act) const;
int getSize() const;
Thread * get_thread_operand() const;
void create_cv(const ModelAction *parent = NULL);
ClockVector * get_cv() const { return cv; }
ClockVector * get_rfcv() const { return rf_cv; }
void set_rfcv(ClockVector * rfcv) { rf_cv = rfcv; }
bool synchronize_with(const ModelAction *act);
bool has_synchronized_with(const ModelAction *act) const;
bool happens_before(const ModelAction *act) const;
inline bool operator <(const ModelAction& act) const {
return get_seq_number() < act.get_seq_number();
}
inline bool operator >(const ModelAction& act) const {
return get_seq_number() > act.get_seq_number();
}
void process_rmw(ModelAction * act);
void copy_typeandorder(ModelAction * act);
unsigned int hash() const;
bool equals(const ModelAction *x) const { return this == x; }
void set_value(uint64_t val) { value = val; }
/* to accomodate pthread create and join */
Thread * thread_operand;
void set_thread_operand(Thread *th) { thread_operand = th; }
void setActionRef(sllnode<ModelAction *> *ref) { action_ref = ref; }
sllnode<ModelAction *> * getActionRef() { return action_ref; }
SNAPSHOTALLOC
private:
const char * get_type_str() const;
const char * get_mo_str() const;
/** @brief A pointer to the memory location for this action. */
void *location;
/** @brief A pointer to the source line for this atomic action. */
const char * position;
union {
/**
* @brief The store that this action reads from
*
* Only valid for reads
*/
ModelAction *reads_from;
int size;
uint64_t time; //used for sleep
};
/** @brief The last fence release from the same thread */
const ModelAction *last_fence_release;
/**
* @brief The clock vector for this operation
*
* Technically, this is only needed for potentially synchronizing
* (e.g., non-relaxed) operations, but it is very handy to have these
* vectors for all operations.
*/
ClockVector *cv;
ClockVector *rf_cv;
sllnode<ModelAction *> * action_ref;
/** @brief The value written (for write or RMW; undefined for read) */
uint64_t value;
/** @brief Type of action (read, write, RMW, fence, thread create, etc.) */
action_type type;
/** @brief The memory order for this operation. */
memory_order order;
/** @brief The original memory order parameter for this operation. */
memory_order original_order;
/** @brief The thread id that performed this action. */
thread_id_t tid;
/**
* @brief The sequence number of this action
*
* Except for non atomic write actions, this number should be unique and
* should represent the action's position in the execution order.
*/
modelclock_t seq_number;
};
#endif /* __ACTION_H__ */