1/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3#ident "$Id$"
4/*======
5This file is part of PerconaFT.
6
7
8Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9
10 PerconaFT is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License, version 2,
12 as published by the Free Software Foundation.
13
14 PerconaFT is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
21
22----------------------------------------
23
24 PerconaFT is free software: you can redistribute it and/or modify
25 it under the terms of the GNU Affero General Public License, version 3,
26 as published by the Free Software Foundation.
27
28 PerconaFT is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU Affero General Public License for more details.
32
33 You should have received a copy of the GNU Affero General Public License
34 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
35======= */
36
37#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38
39#pragma once
40
41#include <portability/toku_config.h>
42
43#ifdef HAVE_valgrind
44#undef USE_VALGRIND
45#define USE_VALGRIND 1
46#endif
47
48#if defined(__linux__) && USE_VALGRIND
49
50# include <valgrind/helgrind.h>
51# include <valgrind/drd.h>
52
53# define TOKU_ANNOTATE_NEW_MEMORY(p, size) ANNOTATE_NEW_MEMORY(p, size)
54# define TOKU_VALGRIND_HG_ENABLE_CHECKING(p, size) VALGRIND_HG_ENABLE_CHECKING(p, size)
55# define TOKU_VALGRIND_HG_DISABLE_CHECKING(p, size) VALGRIND_HG_DISABLE_CHECKING(p, size)
56# define TOKU_DRD_IGNORE_VAR(v) DRD_IGNORE_VAR(v)
57# define TOKU_DRD_STOP_IGNORING_VAR(v) DRD_STOP_IGNORING_VAR(v)
58# define TOKU_ANNOTATE_IGNORE_READS_BEGIN() ANNOTATE_IGNORE_READS_BEGIN()
59# define TOKU_ANNOTATE_IGNORE_READS_END() ANNOTATE_IGNORE_READS_END()
60# define TOKU_ANNOTATE_IGNORE_WRITES_BEGIN() ANNOTATE_IGNORE_WRITES_BEGIN()
61# define TOKU_ANNOTATE_IGNORE_WRITES_END() ANNOTATE_IGNORE_WRITES_END()
62
63/*
64 * How to make helgrind happy about tree rotations and new mutex orderings:
65 *
66 * // Tell helgrind that we unlocked it so that the next call doesn't get a "destroyed a locked mutex" error.
67 * // Tell helgrind that we destroyed the mutex.
68 * VALGRIND_HG_MUTEX_UNLOCK_PRE(&locka);
69 * VALGRIND_HG_MUTEX_DESTROY_PRE(&locka);
70 *
71 * // And recreate it. It would be better to simply be able to say that the order on these two can now be reversed, because this code forgets all the ordering information for this mutex.
72 * // Then tell helgrind that we have locked it again.
73 * VALGRIND_HG_MUTEX_INIT_POST(&locka, 0);
74 * VALGRIND_HG_MUTEX_LOCK_POST(&locka);
75 *
76 * When the ordering of two locks changes, we don't need tell Helgrind about do both locks. Just one is good enough.
77 */
78
79# define TOKU_VALGRIND_RESET_MUTEX_ORDERING_INFO(mutex) \
80 VALGRIND_HG_MUTEX_UNLOCK_PRE(mutex); \
81 VALGRIND_HG_MUTEX_DESTROY_PRE(mutex); \
82 VALGRIND_HG_MUTEX_INIT_POST(mutex, 0); \
83 VALGRIND_HG_MUTEX_LOCK_POST(mutex);
84
85#else // !defined(__linux__) || !USE_VALGRIND
86
87# define NVALGRIND 1
88# define TOKU_ANNOTATE_NEW_MEMORY(p, size) ((void) 0)
89# define TOKU_VALGRIND_HG_ENABLE_CHECKING(p, size) ((void) 0)
90# define TOKU_VALGRIND_HG_DISABLE_CHECKING(p, size) ((void) 0)
91# define TOKU_DRD_IGNORE_VAR(v)
92# define TOKU_DRD_STOP_IGNORING_VAR(v)
93# define TOKU_ANNOTATE_IGNORE_READS_BEGIN() ((void) 0)
94# define TOKU_ANNOTATE_IGNORE_READS_END() ((void) 0)
95# define TOKU_ANNOTATE_IGNORE_WRITES_BEGIN() ((void) 0)
96# define TOKU_ANNOTATE_IGNORE_WRITES_END() ((void) 0)
97# define TOKU_VALGRIND_RESET_MUTEX_ORDERING_INFO(mutex)
98#undef RUNNING_ON_VALGRIND
99# define RUNNING_ON_VALGRIND (0U)
100#endif
101
102// Valgrind 3.10.1 (and previous versions).
103// Problems with VALGRIND_HG_DISABLE_CHECKING and VALGRIND_HG_ENABLE_CHECKING.
104// Helgrind's implementation of disable and enable checking causes false races to be
105// reported. In addition, the race report does not include ANY information about
106// the code that uses the helgrind disable and enable functions. Therefore, it is
107// very difficult to figure out the cause of the race.
108// DRD does implement the disable and enable functions.
109
110// Problems with ANNOTATE_IGNORE_READS.
111// Helgrind does not implement ignore reads.
112// Annotate ignore reads is the way to inform DRD to ignore racy reads.
113
114// FT code uses unsafe reads in several places. These unsafe reads have been noted
115// as valid since they use the toku_unsafe_fetch function. Unfortunately, this
116// causes helgrind to report erroneous data races which makes use of helgrind problematic.
117
118// Unsafely fetch and return a `T' from src, telling drd to ignore
119// racey access to src for the next sizeof(*src) bytes
120template <typename T>
121T toku_unsafe_fetch(T *src) {
122 if (0) TOKU_VALGRIND_HG_DISABLE_CHECKING(src, sizeof *src); // disabled, see comment
123 TOKU_ANNOTATE_IGNORE_READS_BEGIN();
124 T r = *src;
125 TOKU_ANNOTATE_IGNORE_READS_END();
126 if (0) TOKU_VALGRIND_HG_ENABLE_CHECKING(src, sizeof *src); // disabled, see comment
127 return r;
128}
129
130template <typename T>
131T toku_unsafe_fetch(T &src) {
132 return toku_unsafe_fetch(&src);
133}
134
135// Unsafely set a `T' value into *dest from src, telling drd to ignore
136// racey access to dest for the next sizeof(*dest) bytes
137template <typename T>
138void toku_unsafe_set(T *dest, const T src) {
139 if (0) TOKU_VALGRIND_HG_DISABLE_CHECKING(dest, sizeof *dest); // disabled, see comment
140 TOKU_ANNOTATE_IGNORE_WRITES_BEGIN();
141 *dest = src;
142 TOKU_ANNOTATE_IGNORE_WRITES_END();
143 if (0) TOKU_VALGRIND_HG_ENABLE_CHECKING(dest, sizeof *dest); // disabled, see comment
144}
145
146template <typename T>
147void toku_unsafe_set(T &dest, const T src) {
148 toku_unsafe_set(&dest, src);
149}
150