blob: f238ecdcf52ab785afbba6cd847f913bf1330b5d [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
bart86562bd2009-02-16 19:43:56 +00002 This file is part of drd, a thread error detector.
sewardjaf44c822007-11-25 14:01:38 +00003
Elliott Hughesed398002017-06-21 14:41:24 -07004 Copyright (C) 2006-2017 Bart Van Assche <bvanassche@acm.org>.
sewardjaf44c822007-11-25 14:01:38 +00005
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307, USA.
20
21 The GNU General Public License is contained in the file COPYING.
22*/
23
24
25#include "drd_vc.h"
26#include "pub_tool_basics.h" // Addr, SizeT
27#include "pub_tool_libcassert.h" // tl_assert()
bart41b226c2009-02-14 16:55:19 +000028#include "pub_tool_libcbase.h" // VG_(memcpy)
sewardjaf44c822007-11-25 14:01:38 +000029#include "pub_tool_libcprint.h" // VG_(printf)
30#include "pub_tool_mallocfree.h" // VG_(malloc), VG_(free)
sewardjaf44c822007-11-25 14:01:38 +000031
32
bart41b226c2009-02-14 16:55:19 +000033/* Local function declarations. */
34
sewardjaf44c822007-11-25 14:01:38 +000035static
bart41b226c2009-02-14 16:55:19 +000036void DRD_(vc_reserve)(VectorClock* const vc, const unsigned new_capacity);
sewardjaf44c822007-11-25 14:01:38 +000037
38
bart41b226c2009-02-14 16:55:19 +000039/* Function definitions. */
40
41/**
42 * Initialize the memory 'vc' points at as a vector clock with size 'size'.
43 * If the pointer 'vcelem' is not null, it is assumed to be an array with
44 * 'size' elements and it becomes the initial value of the vector clock.
45 */
46void DRD_(vc_init)(VectorClock* const vc,
47 const VCElem* const vcelem,
48 const unsigned size)
sewardjaf44c822007-11-25 14:01:38 +000049{
bartbedfd232009-03-26 19:07:15 +000050 tl_assert(vc);
51 vc->size = 0;
52 vc->capacity = 0;
53 vc->vc = 0;
54 DRD_(vc_reserve)(vc, size);
55 tl_assert(size == 0 || vc->vc != 0);
56 if (vcelem)
57 {
58 VG_(memcpy)(vc->vc, vcelem, size * sizeof(vcelem[0]));
59 vc->size = size;
60 }
bart52048382014-11-26 12:47:19 +000061#ifdef ENABLE_DRD_CONSISTENCY_CHECKS
62 DRD_(vc_check)(vc);
63#endif
sewardjaf44c822007-11-25 14:01:38 +000064}
65
bart41b226c2009-02-14 16:55:19 +000066/** Reset vc to the empty vector clock. */
67void DRD_(vc_cleanup)(VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +000068{
bartbedfd232009-03-26 19:07:15 +000069 DRD_(vc_reserve)(vc, 0);
sewardjaf44c822007-11-25 14:01:38 +000070}
71
bartc46c2322008-02-24 18:26:46 +000072/** Copy constructor -- initializes *new. */
bart41b226c2009-02-14 16:55:19 +000073void DRD_(vc_copy)(VectorClock* const new, const VectorClock* const rhs)
sewardjaf44c822007-11-25 14:01:38 +000074{
bartbedfd232009-03-26 19:07:15 +000075 DRD_(vc_init)(new, rhs->vc, rhs->size);
sewardjaf44c822007-11-25 14:01:38 +000076}
77
bartc46c2322008-02-24 18:26:46 +000078/** Assignment operator -- *lhs is already a valid vector clock. */
bart41b226c2009-02-14 16:55:19 +000079void DRD_(vc_assign)(VectorClock* const lhs, const VectorClock* const rhs)
bartc46c2322008-02-24 18:26:46 +000080{
bartbedfd232009-03-26 19:07:15 +000081 DRD_(vc_cleanup)(lhs);
82 DRD_(vc_copy)(lhs, rhs);
bartc46c2322008-02-24 18:26:46 +000083}
84
bart41b226c2009-02-14 16:55:19 +000085/** Increment the clock of thread 'tid' in vector clock 'vc'. */
86void DRD_(vc_increment)(VectorClock* const vc, DrdThreadId const tid)
sewardjaf44c822007-11-25 14:01:38 +000087{
bartbedfd232009-03-26 19:07:15 +000088 unsigned i;
89 for (i = 0; i < vc->size; i++)
90 {
91 if (vc->vc[i].threadid == tid)
92 {
93 typeof(vc->vc[i].count) const oldcount = vc->vc[i].count;
94 vc->vc[i].count++;
95 // Check for integer overflow.
96 tl_assert(oldcount < vc->vc[i].count);
97 return;
98 }
99 }
sewardjaf44c822007-11-25 14:01:38 +0000100
bartbedfd232009-03-26 19:07:15 +0000101 /*
102 * The specified thread ID does not yet exist in the vector clock
103 * -- insert it.
104 */
105 {
106 const VCElem vcelem = { tid, 1 };
107 VectorClock vc2;
108 DRD_(vc_init)(&vc2, &vcelem, 1);
109 DRD_(vc_combine)(vc, &vc2);
110 DRD_(vc_cleanup)(&vc2);
111 }
sewardjaf44c822007-11-25 14:01:38 +0000112}
113
114/**
sewardjaf44c822007-11-25 14:01:38 +0000115 * @return True if vector clocks vc1 and vc2 are ordered, and false otherwise.
116 * Order is as imposed by thread synchronization actions ("happens before").
117 */
bart41b226c2009-02-14 16:55:19 +0000118Bool DRD_(vc_ordered)(const VectorClock* const vc1,
119 const VectorClock* const vc2)
sewardjaf44c822007-11-25 14:01:38 +0000120{
bartbedfd232009-03-26 19:07:15 +0000121 return DRD_(vc_lte)(vc1, vc2) || DRD_(vc_lte)(vc2, vc1);
sewardjaf44c822007-11-25 14:01:38 +0000122}
123
bart5bd9f2d2008-03-03 20:31:58 +0000124/** Compute elementwise minimum. */
bart41b226c2009-02-14 16:55:19 +0000125void DRD_(vc_min)(VectorClock* const result, const VectorClock* const rhs)
sewardjaf44c822007-11-25 14:01:38 +0000126{
bartbedfd232009-03-26 19:07:15 +0000127 unsigned i;
128 unsigned j;
sewardjaf44c822007-11-25 14:01:38 +0000129
bartbedfd232009-03-26 19:07:15 +0000130 tl_assert(result);
131 tl_assert(rhs);
sewardjaf44c822007-11-25 14:01:38 +0000132
bartbedfd232009-03-26 19:07:15 +0000133 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000134
bartbedfd232009-03-26 19:07:15 +0000135 /* Next, combine both vector clocks into one. */
136 i = 0;
137 for (j = 0; j < rhs->size; j++)
138 {
139 while (i < result->size && result->vc[i].threadid < rhs->vc[j].threadid)
sewardjaf44c822007-11-25 14:01:38 +0000140 {
bartbedfd232009-03-26 19:07:15 +0000141 /* Thread ID is missing in second vector clock. Clear the count. */
142 result->vc[i].count = 0;
143 i++;
sewardjaf44c822007-11-25 14:01:38 +0000144 }
bartbedfd232009-03-26 19:07:15 +0000145 if (i >= result->size)
146 {
147 break;
148 }
149 if (result->vc[i].threadid <= rhs->vc[j].threadid)
150 {
151 /* The thread ID is present in both vector clocks. Compute the */
152 /* minimum of vc[i].count and vc[j].count. */
153 tl_assert(result->vc[i].threadid == rhs->vc[j].threadid);
154 if (rhs->vc[j].count < result->vc[i].count)
155 {
156 result->vc[i].count = rhs->vc[j].count;
157 }
158 }
159 }
160 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000161}
162
163/**
164 * Compute elementwise maximum.
165 */
bart41b226c2009-02-14 16:55:19 +0000166void DRD_(vc_combine)(VectorClock* const result, const VectorClock* const rhs)
sewardjaf44c822007-11-25 14:01:38 +0000167{
bartbedfd232009-03-26 19:07:15 +0000168 unsigned i;
169 unsigned j;
170 unsigned shared;
171 unsigned new_size;
sewardjaf44c822007-11-25 14:01:38 +0000172
bartbedfd232009-03-26 19:07:15 +0000173 tl_assert(result);
174 tl_assert(rhs);
sewardjaf44c822007-11-25 14:01:38 +0000175
bartbedfd232009-03-26 19:07:15 +0000176 // First count the number of shared thread id's.
177 j = 0;
178 shared = 0;
179 for (i = 0; i < result->size; i++)
180 {
181 while (j < rhs->size && rhs->vc[j].threadid < result->vc[i].threadid)
182 j++;
183 if (j >= rhs->size)
184 break;
185 if (result->vc[i].threadid == rhs->vc[j].threadid)
186 shared++;
187 }
sewardjaf44c822007-11-25 14:01:38 +0000188
bartbedfd232009-03-26 19:07:15 +0000189 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000190
bartbedfd232009-03-26 19:07:15 +0000191 new_size = result->size + rhs->size - shared;
192 if (new_size > result->capacity)
193 DRD_(vc_reserve)(result, new_size);
sewardjaf44c822007-11-25 14:01:38 +0000194
bartbedfd232009-03-26 19:07:15 +0000195 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000196
bartbedfd232009-03-26 19:07:15 +0000197 // Next, combine both vector clocks into one.
198 i = 0;
199 for (j = 0; j < rhs->size; j++)
200 {
201 /* First of all, skip those clocks in result->vc[] for which there */
202 /* is no corresponding clock in rhs->vc[]. */
203 while (i < result->size && result->vc[i].threadid < rhs->vc[j].threadid)
bartfbbac092008-04-06 14:57:37 +0000204 {
bartbedfd232009-03-26 19:07:15 +0000205 i++;
bartfbbac092008-04-06 14:57:37 +0000206 }
bartbedfd232009-03-26 19:07:15 +0000207 /* If the end of *result is met, append rhs->vc[j] to *result. */
208 if (i >= result->size)
bartfbbac092008-04-06 14:57:37 +0000209 {
bartbedfd232009-03-26 19:07:15 +0000210 result->size++;
211 result->vc[i] = rhs->vc[j];
bartfbbac092008-04-06 14:57:37 +0000212 }
bartbedfd232009-03-26 19:07:15 +0000213 /* If clock rhs->vc[j] is not in *result, insert it. */
214 else if (result->vc[i].threadid > rhs->vc[j].threadid)
sewardjaf44c822007-11-25 14:01:38 +0000215 {
bartbedfd232009-03-26 19:07:15 +0000216 unsigned k;
217 for (k = result->size; k > i; k--)
218 {
219 result->vc[k] = result->vc[k - 1];
220 }
221 result->size++;
222 result->vc[i] = rhs->vc[j];
sewardjaf44c822007-11-25 14:01:38 +0000223 }
bartbedfd232009-03-26 19:07:15 +0000224 /* Otherwise, both *result and *rhs have a clock for thread */
225 /* result->vc[i].threadid == rhs->vc[j].threadid. Compute the maximum. */
226 else
bartfbbac092008-04-06 14:57:37 +0000227 {
bartbedfd232009-03-26 19:07:15 +0000228 tl_assert(result->vc[i].threadid == rhs->vc[j].threadid);
bartbedfd232009-03-26 19:07:15 +0000229 if (rhs->vc[j].count > result->vc[i].count)
230 {
231 result->vc[i].count = rhs->vc[j].count;
232 }
bartfbbac092008-04-06 14:57:37 +0000233 }
bartbedfd232009-03-26 19:07:15 +0000234 }
235 DRD_(vc_check)(result);
236 tl_assert(result->size == new_size);
sewardjaf44c822007-11-25 14:01:38 +0000237}
238
bart41b226c2009-02-14 16:55:19 +0000239/** Print the contents of vector clock 'vc'. */
240void DRD_(vc_print)(const VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +0000241{
florian19f91bb2012-11-10 22:29:54 +0000242 HChar* str;
sewardjaf44c822007-11-25 14:01:38 +0000243
bart8f822af2009-06-08 18:20:42 +0000244 if ((str = DRD_(vc_aprint)(vc)) != NULL)
bartbedfd232009-03-26 19:07:15 +0000245 {
bart8f822af2009-06-08 18:20:42 +0000246 VG_(printf)("%s", str);
247 VG_(free)(str);
bartbedfd232009-03-26 19:07:15 +0000248 }
sewardjaf44c822007-11-25 14:01:38 +0000249}
250
bart41b226c2009-02-14 16:55:19 +0000251/**
bart8f822af2009-06-08 18:20:42 +0000252 * Print the contents of vector clock 'vc' to a newly allocated string.
253 * The caller must call VG_(free)() on the return value of this function.
bart41b226c2009-02-14 16:55:19 +0000254 */
florian19f91bb2012-11-10 22:29:54 +0000255HChar* DRD_(vc_aprint)(const VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +0000256{
bartbedfd232009-03-26 19:07:15 +0000257 unsigned i;
bart8f822af2009-06-08 18:20:42 +0000258 unsigned reserved;
259 unsigned size;
florian19f91bb2012-11-10 22:29:54 +0000260 HChar* str = 0;
sewardjaf44c822007-11-25 14:01:38 +0000261
bartbedfd232009-03-26 19:07:15 +0000262 tl_assert(vc);
bart8f822af2009-06-08 18:20:42 +0000263 reserved = 64;
264 size = 0;
265 str = VG_(realloc)("drd.vc.aprint.1", str, reserved);
266 if (! str)
267 return str;
268 size += VG_(snprintf)(str, reserved, "[");
bartbedfd232009-03-26 19:07:15 +0000269 for (i = 0; i < vc->size; i++)
270 {
271 tl_assert(vc->vc);
bart8f822af2009-06-08 18:20:42 +0000272 if (VG_(strlen)(str) + 32 > reserved)
bartbedfd232009-03-26 19:07:15 +0000273 {
bart8f822af2009-06-08 18:20:42 +0000274 reserved *= 2;
275 str = VG_(realloc)("drd.vc.aprint.2", str, reserved);
276 if (! str)
277 return str;
bartbedfd232009-03-26 19:07:15 +0000278 }
bart8f822af2009-06-08 18:20:42 +0000279 size += VG_(snprintf)(str + size, reserved - size,
florianea71ffb2015-08-05 14:38:57 +0000280 "%s %u: %u", i > 0 ? "," : "",
bart8f822af2009-06-08 18:20:42 +0000281 vc->vc[i].threadid, vc->vc[i].count);
bartbedfd232009-03-26 19:07:15 +0000282 }
bart8f822af2009-06-08 18:20:42 +0000283 size += VG_(snprintf)(str + size, reserved - size, " ]");
284
285 return str;
sewardjaf44c822007-11-25 14:01:38 +0000286}
287
288/**
289 * Invariant test.
bart41b226c2009-02-14 16:55:19 +0000290 *
291 * The function below tests whether the following two conditions are
292 * satisfied:
293 * - size <= capacity.
294 * - Vector clock elements are stored in thread ID order.
295 *
296 * If one of these conditions is not met, an assertion failure is triggered.
sewardjaf44c822007-11-25 14:01:38 +0000297 */
bart41b226c2009-02-14 16:55:19 +0000298void DRD_(vc_check)(const VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +0000299{
bartbedfd232009-03-26 19:07:15 +0000300 unsigned i;
bart52048382014-11-26 12:47:19 +0000301
bartbedfd232009-03-26 19:07:15 +0000302 tl_assert(vc->size <= vc->capacity);
bart52048382014-11-26 12:47:19 +0000303
bartbedfd232009-03-26 19:07:15 +0000304 for (i = 1; i < vc->size; i++)
bartbedfd232009-03-26 19:07:15 +0000305 tl_assert(vc->vc[i-1].threadid < vc->vc[i].threadid);
sewardjaf44c822007-11-25 14:01:38 +0000306}
307
308/**
309 * Change the size of the memory block pointed at by vc->vc.
310 * Changes capacity, but does not change size. If the size of the memory
311 * block is increased, the newly allocated memory is not initialized.
312 */
313static
bart41b226c2009-02-14 16:55:19 +0000314void DRD_(vc_reserve)(VectorClock* const vc, const unsigned new_capacity)
sewardjaf44c822007-11-25 14:01:38 +0000315{
bartbedfd232009-03-26 19:07:15 +0000316 tl_assert(vc);
bart8f822af2009-06-08 18:20:42 +0000317 tl_assert(vc->capacity > VC_PREALLOCATED
318 || vc->vc == 0
319 || vc->vc == vc->preallocated);
320
bartbedfd232009-03-26 19:07:15 +0000321 if (new_capacity > vc->capacity)
322 {
bart8f822af2009-06-08 18:20:42 +0000323 if (vc->vc && vc->capacity > VC_PREALLOCATED)
bartbedfd232009-03-26 19:07:15 +0000324 {
bart8f822af2009-06-08 18:20:42 +0000325 tl_assert(vc->vc
326 && vc->vc != vc->preallocated
327 && vc->capacity > VC_PREALLOCATED);
bartbedfd232009-03-26 19:07:15 +0000328 vc->vc = VG_(realloc)("drd.vc.vr.1",
329 vc->vc, new_capacity * sizeof(vc->vc[0]));
330 }
bart8f822af2009-06-08 18:20:42 +0000331 else if (vc->vc && new_capacity > VC_PREALLOCATED)
bartbedfd232009-03-26 19:07:15 +0000332 {
bart8f822af2009-06-08 18:20:42 +0000333 tl_assert((vc->vc == 0 || vc->vc == vc->preallocated)
334 && new_capacity > VC_PREALLOCATED
335 && vc->capacity <= VC_PREALLOCATED);
bartbedfd232009-03-26 19:07:15 +0000336 vc->vc = VG_(malloc)("drd.vc.vr.2",
337 new_capacity * sizeof(vc->vc[0]));
bart8f822af2009-06-08 18:20:42 +0000338 VG_(memcpy)(vc->vc, vc->preallocated,
339 vc->capacity * sizeof(vc->vc[0]));
340 }
341 else if (vc->vc)
342 {
343 tl_assert(vc->vc == vc->preallocated
344 && new_capacity <= VC_PREALLOCATED
345 && vc->capacity <= VC_PREALLOCATED);
346 }
347 else if (new_capacity > VC_PREALLOCATED)
348 {
349 tl_assert(vc->vc == 0
350 && new_capacity > VC_PREALLOCATED
351 && vc->capacity == 0);
352 vc->vc = VG_(malloc)("drd.vc.vr.3",
353 new_capacity * sizeof(vc->vc[0]));
bartbedfd232009-03-26 19:07:15 +0000354 }
355 else
356 {
bart8f822af2009-06-08 18:20:42 +0000357 tl_assert(vc->vc == 0
358 && new_capacity <= VC_PREALLOCATED
359 && vc->capacity == 0);
360 vc->vc = vc->preallocated;
bartbedfd232009-03-26 19:07:15 +0000361 }
362 vc->capacity = new_capacity;
363 }
bart48fcfc62009-06-03 12:44:50 +0000364 else if (new_capacity == 0 && vc->vc)
365 {
bart8f822af2009-06-08 18:20:42 +0000366 if (vc->capacity > VC_PREALLOCATED)
367 VG_(free)(vc->vc);
bart48fcfc62009-06-03 12:44:50 +0000368 vc->vc = 0;
bart8f822af2009-06-08 18:20:42 +0000369 vc->capacity = 0;
bart48fcfc62009-06-03 12:44:50 +0000370 }
bart8f822af2009-06-08 18:20:42 +0000371
bartbedfd232009-03-26 19:07:15 +0000372 tl_assert(new_capacity == 0 || vc->vc != 0);
bart8f822af2009-06-08 18:20:42 +0000373 tl_assert(vc->capacity > VC_PREALLOCATED
374 || vc->vc == 0
375 || vc->vc == vc->preallocated);
sewardjaf44c822007-11-25 14:01:38 +0000376}