2 * Eddie Kohler, Yandong Mao, Robert Morris
3 * Copyright (c) 2012-2014 President and Fellows of Harvard College
4 * Copyright (c) 2012-2014 Massachusetts Institute of Technology
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, subject to the conditions
9 * listed in the Masstree LICENSE file. These conditions include: you must
10 * preserve this copyright notice, and you cannot mention the copyright
11 * holders in advertising related to the Software without their permission.
12 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
13 * notice is a summary of the Masstree LICENSE file; the license in that file
18 #include "mtcounters.hh"
19 #include "compiler.hh"
20 #include "circular_int.hh"
21 #include "timestamp.hh"
30 extern volatile uint64_t globalepoch; // global epoch, updated regularly
31 extern volatile bool recovering;
36 magic_value = 389612313 /* = 0x17390319 */,
37 magic_free_value = 2015593488 /* = 0x78238410 */
46 static void* make(void* p, size_t size, int freetype) {
48 memdebug *m = reinterpret_cast<memdebug *>(p);
49 m->magic = magic_value;
50 m->freetype = freetype;
59 static void set_landmark(void* p, const char* file, int line) {
61 memdebug* m = reinterpret_cast<memdebug*>(p) - 1;
66 static void *check_free(void *p, size_t size, int freetype) {
67 memdebug *m = reinterpret_cast<memdebug *>(p) - 1;
68 free_checks(m, size, freetype, false, "deallocate");
69 m->magic = magic_free_value;
72 static void check_rcu(void *p, size_t size, int freetype) {
73 memdebug *m = reinterpret_cast<memdebug *>(p) - 1;
74 free_checks(m, size, freetype, false, "deallocate_rcu");
77 static void *check_free_after_rcu(void *p, int freetype) {
78 memdebug *m = reinterpret_cast<memdebug *>(p) - 1;
79 free_checks(m, 0, freetype, true, "free_after_rcu");
80 m->magic = magic_free_value;
83 static bool check_use(const void *p, int type) {
84 const memdebug *m = reinterpret_cast<const memdebug *>(p) - 1;
85 return m->magic == magic_value && (type == 0 || (m->freetype >> 8) == type);
87 static bool check_use(const void *p, int type1, int type2) {
88 const memdebug *m = reinterpret_cast<const memdebug *>(p) - 1;
89 return m->magic == magic_value
90 && ((m->freetype >> 8) == type1 || (m->freetype >> 8) == type2);
92 static void assert_use(const void *p, memtag tag) {
93 if (!check_use(p, tag))
94 hard_assert_use(p, tag, (memtag) -1);
96 static void assert_use(const void *p, memtag tag1, memtag tag2) {
97 if (!check_use(p, tag1, tag2))
98 hard_assert_use(p, tag1, tag2);
101 static void free_checks(const memdebug *m, size_t size, int freetype,
102 int after_rcu, const char *op) {
103 if (m->magic != magic_value
104 || m->freetype != freetype
105 || (!after_rcu && m->size != size)
106 || m->after_rcu != after_rcu)
107 hard_free_checks(m, freetype, size, after_rcu, op);
109 void landmark(char* buf, size_t size) const;
110 static void hard_free_checks(const memdebug* m, size_t size, int freetype,
111 int after_rcu, const char* op);
112 static void hard_assert_use(const void* ptr, memtag tag1, memtag tag2);
114 static void *make(void *p, size_t, int) {
117 static void set_landmark(void*, const char*, int) {
119 static void *check_free(void *p, size_t, int) {
122 static void check_rcu(void *, size_t, int) {
124 static void *check_free_after_rcu(void *p, int) {
127 static bool check_use(void *, memtag) {
130 static bool check_use(void *, memtag, memtag) {
133 static void assert_use(void *, memtag) {
135 static void assert_use(void *, memtag, memtag) {
142 memdebug_size = sizeof(memdebug)
148 struct limbo_element {
155 enum { capacity = (4076 - sizeof(limbo_group *)) / sizeof(limbo_element) };
158 limbo_element e_[capacity];
161 : head_(0), tail_(0), next_() {
163 void push_back(void *ptr, int freetype, uint64_t epoch) {
164 assert(tail_ < capacity);
165 e_[tail_].ptr_ = ptr;
166 e_[tail_].freetype_ = freetype;
167 e_[tail_].epoch_ = epoch;
172 template <int N> struct has_threadcounter {
173 static bool test(threadcounter ci) {
174 return unsigned(ci) < unsigned(N);
177 template <> struct has_threadcounter<0> {
178 static bool test(threadcounter) {
183 struct rcu_callback {
184 virtual ~rcu_callback() {
186 virtual void operator()(threadinfo& ti) = 0;
192 TI_MAIN, TI_PROCESS, TI_LOG, TI_CHECKPOINT
195 static threadinfo *make(int purpose, int index);
197 static pthread_key_t key;
199 // thread information
200 int purpose() const {
206 loginfo* logger() const {
209 void set_logger(loginfo* logger) {
210 assert(!logger_ && logger);
213 static threadinfo *allthreads;
214 threadinfo* next() const {
219 kvtimestamp_t operation_timestamp() const {
222 kvtimestamp_t update_timestamp() const {
225 kvtimestamp_t update_timestamp(kvtimestamp_t x) const {
226 if (circular_int<kvtimestamp_t>::less_equal(ts_, x))
227 // x might be a marker timestamp; ensure result is not
231 kvtimestamp_t update_timestamp(kvtimestamp_t x, kvtimestamp_t y) const {
232 if (circular_int<kvtimestamp_t>::less(x, y))
234 if (circular_int<kvtimestamp_t>::less_equal(ts_, x))
235 // x might be a marker timestamp; ensure result is not
239 void increment_timestamp() {
242 void advance_timestamp(kvtimestamp_t x) {
243 if (circular_int<kvtimestamp_t>::less(ts_, x))
248 void mark(threadcounter ci) {
249 if (has_threadcounter<int(ncounters)>::test(ci))
252 void mark(threadcounter ci, int64_t delta) {
253 if (has_threadcounter<int(ncounters)>::test(ci))
254 counters_[ci] += delta;
256 bool has_counter(threadcounter ci) const {
257 return has_threadcounter<int(ncounters)>::test(ci);
259 uint64_t counter(threadcounter ci) const {
260 return has_threadcounter<int(ncounters)>::test(ci) ? counters_[ci] : 0;
263 struct accounting_relax_fence_function {
266 accounting_relax_fence_function(threadinfo *ti, threadcounter ci)
274 /** @brief Return a function object that calls mark(ci); relax_fence().
276 * This function object can be used to count the number of relax_fence()s
278 accounting_relax_fence_function accounting_relax_fence(threadcounter ci) {
279 return accounting_relax_fence_function(this, ci);
282 struct stable_accounting_relax_fence_function {
284 stable_accounting_relax_fence_function(threadinfo *ti)
287 template <typename V>
288 void operator()(V v) {
290 ti_->mark(threadcounter(tc_stable + (v.isleaf() << 1) + v.splitting()));
293 /** @brief Return a function object that calls mark(ci); relax_fence().
295 * This function object can be used to count the number of relax_fence()s
297 stable_accounting_relax_fence_function stable_fence() {
298 return stable_accounting_relax_fence_function(this);
301 accounting_relax_fence_function lock_fence(threadcounter ci) {
302 return accounting_relax_fence_function(this, ci);
306 void* allocate(size_t sz, memtag tag) {
307 void *p = malloc(sz + memdebug_size);
308 p = memdebug::make(p, sz, tag << 8);
310 mark(threadcounter(tc_alloc + (tag > memtag_value)), sz);
313 void deallocate(void* p, size_t sz, memtag tag) {
314 // in C++ allocators, 'p' must be nonnull
316 p = memdebug::check_free(p, sz, tag << 8);
318 mark(threadcounter(tc_alloc + (tag > memtag_value)), -sz);
320 void deallocate_rcu(void *p, size_t sz, memtag tag) {
322 memdebug::check_rcu(p, sz, tag << 8);
323 record_rcu(p, tag << 8);
324 mark(threadcounter(tc_alloc + (tag > memtag_value)), -sz);
327 void* pool_allocate(size_t sz, memtag tag) {
328 int nl = (sz + memdebug_size + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE;
329 assert(nl <= pool_max_nlines);
330 if (unlikely(!pool_[nl - 1]))
332 void *p = pool_[nl - 1];
334 pool_[nl - 1] = *reinterpret_cast<void **>(p);
335 p = memdebug::make(p, sz, (tag << 8) + nl);
336 mark(threadcounter(tc_alloc + (tag > memtag_value)),
337 nl * CACHE_LINE_SIZE);
341 void pool_deallocate(void* p, size_t sz, memtag tag) {
342 int nl = (sz + memdebug_size + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE;
343 assert(p && nl <= pool_max_nlines);
344 p = memdebug::check_free(p, sz, (tag << 8) + nl);
346 *reinterpret_cast<void **>(p) = pool_[nl - 1];
350 mark(threadcounter(tc_alloc + (tag > memtag_value)),
351 -nl * CACHE_LINE_SIZE);
353 void pool_deallocate_rcu(void* p, size_t sz, memtag tag) {
354 int nl = (sz + memdebug_size + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE;
355 assert(p && nl <= pool_max_nlines);
356 memdebug::check_rcu(p, sz, (tag << 8) + nl);
357 record_rcu(p, (tag << 8) + nl);
358 mark(threadcounter(tc_alloc + (tag > memtag_value)),
359 -nl * CACHE_LINE_SIZE);
364 if (gc_epoch_ != globalepoch)
365 gc_epoch_ = globalepoch;
368 if (limbo_epoch_ && (gc_epoch_ - limbo_epoch_) > 1)
374 if (limbo_epoch_ && (gc_epoch_ - limbo_epoch_) > 2)
377 typedef ::rcu_callback rcu_callback;
378 void rcu_register(rcu_callback* cb) {
384 int run(void* (*thread_func)(threadinfo*), void* thread_data = 0);
385 pthread_t threadid() const {
388 void* thread_data() const {
392 static threadinfo *current() {
393 return (threadinfo *) pthread_getspecific(key);
396 void report_rcu(void *ptr) const;
397 static void report_rcu_all(void *ptr);
403 uint64_t limbo_epoch_;
408 int index_; // the index of a udp, logging, tcp,
409 // checkpoint or recover thread
413 char padding1[CACHE_LINE_SIZE];
417 enum { pool_max_nlines = 20 };
418 void *pool_[pool_max_nlines];
420 limbo_group *limbo_head_;
421 limbo_group *limbo_tail_;
422 mutable kvtimestamp_t ts_;
424 //enum { ncounters = (int) tc_max };
425 enum { ncounters = 0 };
426 uint64_t counters_[ncounters];
428 void* (*thread_func_)(threadinfo*);
431 void refill_pool(int nl);
434 void free_rcu(void *p, int freetype) {
435 if ((freetype & 255) == 0) {
436 p = memdebug::check_free_after_rcu(p, freetype);
438 } else if (freetype == -1)
439 (*static_cast<rcu_callback *>(p))(*this);
441 p = memdebug::check_free_after_rcu(p, freetype);
442 int nl = freetype & 255;
443 *reinterpret_cast<void **>(p) = pool_[nl - 1];
448 void record_rcu(void* ptr, int freetype) {
449 if (recovering && freetype == (memtag_value << 8)) {
450 free_rcu(ptr, freetype);
453 if (limbo_tail_->tail_ == limbo_tail_->capacity)
455 uint64_t epoch = globalepoch;
456 limbo_tail_->push_back(ptr, freetype, epoch);
458 limbo_epoch_ = epoch;
461 #if ENABLE_ASSERTIONS
462 static int no_pool_value;
463 static bool use_pool() {
464 return !no_pool_value;
467 static bool use_pool() {
472 void hard_rcu_quiesce();
473 static void* thread_trampoline(void*);
474 friend class loginfo;