blob: 1c0f1149f8f66fea904d207109c60fb31108f099 [file] [log] [blame]
bartbedfd232009-03-26 19:07:15 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
sewardjaf44c822007-11-25 14:01:38 +00002/*
bart86562bd2009-02-16 19:43:56 +00003 This file is part of drd, a thread error detector.
sewardjaf44c822007-11-25 14:01:38 +00004
bart86562bd2009-02-16 19:43:56 +00005 Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
sewardjaf44c822007-11-25 14:01:38 +00006
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
21
22 The GNU General Public License is contained in the file COPYING.
23*/
24
25
26#include "drd_vc.h"
27#include "pub_tool_basics.h" // Addr, SizeT
28#include "pub_tool_libcassert.h" // tl_assert()
bart41b226c2009-02-14 16:55:19 +000029#include "pub_tool_libcbase.h" // VG_(memcpy)
sewardjaf44c822007-11-25 14:01:38 +000030#include "pub_tool_libcprint.h" // VG_(printf)
31#include "pub_tool_mallocfree.h" // VG_(malloc), VG_(free)
sewardjaf44c822007-11-25 14:01:38 +000032
33
bart41b226c2009-02-14 16:55:19 +000034/* Local function declarations. */
35
sewardjaf44c822007-11-25 14:01:38 +000036static
bart41b226c2009-02-14 16:55:19 +000037void DRD_(vc_reserve)(VectorClock* const vc, const unsigned new_capacity);
sewardjaf44c822007-11-25 14:01:38 +000038
39
bart41b226c2009-02-14 16:55:19 +000040/* Function definitions. */
41
42/**
43 * Initialize the memory 'vc' points at as a vector clock with size 'size'.
44 * If the pointer 'vcelem' is not null, it is assumed to be an array with
45 * 'size' elements and it becomes the initial value of the vector clock.
46 */
47void DRD_(vc_init)(VectorClock* const vc,
48 const VCElem* const vcelem,
49 const unsigned size)
sewardjaf44c822007-11-25 14:01:38 +000050{
bartbedfd232009-03-26 19:07:15 +000051 tl_assert(vc);
52 vc->size = 0;
53 vc->capacity = 0;
54 vc->vc = 0;
55 DRD_(vc_reserve)(vc, size);
56 tl_assert(size == 0 || vc->vc != 0);
57 if (vcelem)
58 {
59 VG_(memcpy)(vc->vc, vcelem, size * sizeof(vcelem[0]));
60 vc->size = size;
61 }
sewardjaf44c822007-11-25 14:01:38 +000062}
63
bart41b226c2009-02-14 16:55:19 +000064/** Reset vc to the empty vector clock. */
65void DRD_(vc_cleanup)(VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +000066{
bartbedfd232009-03-26 19:07:15 +000067 DRD_(vc_reserve)(vc, 0);
sewardjaf44c822007-11-25 14:01:38 +000068}
69
bartc46c2322008-02-24 18:26:46 +000070/** Copy constructor -- initializes *new. */
bart41b226c2009-02-14 16:55:19 +000071void DRD_(vc_copy)(VectorClock* const new, const VectorClock* const rhs)
sewardjaf44c822007-11-25 14:01:38 +000072{
bartbedfd232009-03-26 19:07:15 +000073 DRD_(vc_init)(new, rhs->vc, rhs->size);
sewardjaf44c822007-11-25 14:01:38 +000074}
75
bartc46c2322008-02-24 18:26:46 +000076/** Assignment operator -- *lhs is already a valid vector clock. */
bart41b226c2009-02-14 16:55:19 +000077void DRD_(vc_assign)(VectorClock* const lhs, const VectorClock* const rhs)
bartc46c2322008-02-24 18:26:46 +000078{
bartbedfd232009-03-26 19:07:15 +000079 DRD_(vc_cleanup)(lhs);
80 DRD_(vc_copy)(lhs, rhs);
bartc46c2322008-02-24 18:26:46 +000081}
82
bart41b226c2009-02-14 16:55:19 +000083/** Increment the clock of thread 'tid' in vector clock 'vc'. */
84void DRD_(vc_increment)(VectorClock* const vc, DrdThreadId const tid)
sewardjaf44c822007-11-25 14:01:38 +000085{
bartbedfd232009-03-26 19:07:15 +000086 unsigned i;
87 for (i = 0; i < vc->size; i++)
88 {
89 if (vc->vc[i].threadid == tid)
90 {
91 typeof(vc->vc[i].count) const oldcount = vc->vc[i].count;
92 vc->vc[i].count++;
93 // Check for integer overflow.
94 tl_assert(oldcount < vc->vc[i].count);
95 return;
96 }
97 }
sewardjaf44c822007-11-25 14:01:38 +000098
bartbedfd232009-03-26 19:07:15 +000099 /*
100 * The specified thread ID does not yet exist in the vector clock
101 * -- insert it.
102 */
103 {
104 const VCElem vcelem = { tid, 1 };
105 VectorClock vc2;
106 DRD_(vc_init)(&vc2, &vcelem, 1);
107 DRD_(vc_combine)(vc, &vc2);
108 DRD_(vc_cleanup)(&vc2);
109 }
sewardjaf44c822007-11-25 14:01:38 +0000110}
111
112/**
sewardjaf44c822007-11-25 14:01:38 +0000113 * @return True if vector clocks vc1 and vc2 are ordered, and false otherwise.
114 * Order is as imposed by thread synchronization actions ("happens before").
115 */
bart41b226c2009-02-14 16:55:19 +0000116Bool DRD_(vc_ordered)(const VectorClock* const vc1,
117 const VectorClock* const vc2)
sewardjaf44c822007-11-25 14:01:38 +0000118{
bartbedfd232009-03-26 19:07:15 +0000119 return DRD_(vc_lte)(vc1, vc2) || DRD_(vc_lte)(vc2, vc1);
sewardjaf44c822007-11-25 14:01:38 +0000120}
121
bart5bd9f2d2008-03-03 20:31:58 +0000122/** Compute elementwise minimum. */
bart41b226c2009-02-14 16:55:19 +0000123void DRD_(vc_min)(VectorClock* const result, const VectorClock* const rhs)
sewardjaf44c822007-11-25 14:01:38 +0000124{
bartbedfd232009-03-26 19:07:15 +0000125 unsigned i;
126 unsigned j;
sewardjaf44c822007-11-25 14:01:38 +0000127
bartbedfd232009-03-26 19:07:15 +0000128 tl_assert(result);
129 tl_assert(rhs);
sewardjaf44c822007-11-25 14:01:38 +0000130
bartbedfd232009-03-26 19:07:15 +0000131 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000132
bartbedfd232009-03-26 19:07:15 +0000133 /* Next, combine both vector clocks into one. */
134 i = 0;
135 for (j = 0; j < rhs->size; j++)
136 {
137 while (i < result->size && result->vc[i].threadid < rhs->vc[j].threadid)
sewardjaf44c822007-11-25 14:01:38 +0000138 {
bartbedfd232009-03-26 19:07:15 +0000139 /* Thread ID is missing in second vector clock. Clear the count. */
140 result->vc[i].count = 0;
141 i++;
sewardjaf44c822007-11-25 14:01:38 +0000142 }
bartbedfd232009-03-26 19:07:15 +0000143 if (i >= result->size)
144 {
145 break;
146 }
147 if (result->vc[i].threadid <= rhs->vc[j].threadid)
148 {
149 /* The thread ID is present in both vector clocks. Compute the */
150 /* minimum of vc[i].count and vc[j].count. */
151 tl_assert(result->vc[i].threadid == rhs->vc[j].threadid);
152 if (rhs->vc[j].count < result->vc[i].count)
153 {
154 result->vc[i].count = rhs->vc[j].count;
155 }
156 }
157 }
158 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000159}
160
161/**
162 * Compute elementwise maximum.
163 */
bart41b226c2009-02-14 16:55:19 +0000164void DRD_(vc_combine)(VectorClock* const result, const VectorClock* const rhs)
sewardjaf44c822007-11-25 14:01:38 +0000165{
bartbedfd232009-03-26 19:07:15 +0000166 DRD_(vc_combine2)(result, rhs, -1);
bartfbbac092008-04-06 14:57:37 +0000167}
168
bart41b226c2009-02-14 16:55:19 +0000169/**
170 * Compute elementwise maximum.
bartfbbac092008-04-06 14:57:37 +0000171 *
bart41b226c2009-02-14 16:55:19 +0000172 * @return True if *result and *rhs are equal, or if *result and *rhs only
173 * differ in the component with thread ID tid.
bartfbbac092008-04-06 14:57:37 +0000174 */
bart41b226c2009-02-14 16:55:19 +0000175Bool DRD_(vc_combine2)(VectorClock* const result,
176 const VectorClock* const rhs,
177 const DrdThreadId tid)
bartfbbac092008-04-06 14:57:37 +0000178{
bartbedfd232009-03-26 19:07:15 +0000179 unsigned i;
180 unsigned j;
181 unsigned shared;
182 unsigned new_size;
183 Bool almost_equal = True;
sewardjaf44c822007-11-25 14:01:38 +0000184
bartbedfd232009-03-26 19:07:15 +0000185 tl_assert(result);
186 tl_assert(rhs);
sewardjaf44c822007-11-25 14:01:38 +0000187
bartbedfd232009-03-26 19:07:15 +0000188 // First count the number of shared thread id's.
189 j = 0;
190 shared = 0;
191 for (i = 0; i < result->size; i++)
192 {
193 while (j < rhs->size && rhs->vc[j].threadid < result->vc[i].threadid)
194 j++;
195 if (j >= rhs->size)
196 break;
197 if (result->vc[i].threadid == rhs->vc[j].threadid)
198 shared++;
199 }
sewardjaf44c822007-11-25 14:01:38 +0000200
bartbedfd232009-03-26 19:07:15 +0000201 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000202
bartbedfd232009-03-26 19:07:15 +0000203 new_size = result->size + rhs->size - shared;
204 if (new_size > result->capacity)
205 DRD_(vc_reserve)(result, new_size);
sewardjaf44c822007-11-25 14:01:38 +0000206
bartbedfd232009-03-26 19:07:15 +0000207 DRD_(vc_check)(result);
sewardjaf44c822007-11-25 14:01:38 +0000208
bartbedfd232009-03-26 19:07:15 +0000209 // Next, combine both vector clocks into one.
210 i = 0;
211 for (j = 0; j < rhs->size; j++)
212 {
213 /* First of all, skip those clocks in result->vc[] for which there */
214 /* is no corresponding clock in rhs->vc[]. */
215 while (i < result->size && result->vc[i].threadid < rhs->vc[j].threadid)
bartfbbac092008-04-06 14:57:37 +0000216 {
bartbedfd232009-03-26 19:07:15 +0000217 if (result->vc[i].threadid != tid)
218 {
219 almost_equal = False;
220 }
221 i++;
bartfbbac092008-04-06 14:57:37 +0000222 }
bartbedfd232009-03-26 19:07:15 +0000223 /* If the end of *result is met, append rhs->vc[j] to *result. */
224 if (i >= result->size)
bartfbbac092008-04-06 14:57:37 +0000225 {
bartbedfd232009-03-26 19:07:15 +0000226 result->size++;
227 result->vc[i] = rhs->vc[j];
228 if (result->vc[i].threadid != tid)
229 {
230 almost_equal = False;
231 }
bartfbbac092008-04-06 14:57:37 +0000232 }
bartbedfd232009-03-26 19:07:15 +0000233 /* If clock rhs->vc[j] is not in *result, insert it. */
234 else if (result->vc[i].threadid > rhs->vc[j].threadid)
sewardjaf44c822007-11-25 14:01:38 +0000235 {
bartbedfd232009-03-26 19:07:15 +0000236 unsigned k;
237 for (k = result->size; k > i; k--)
238 {
239 result->vc[k] = result->vc[k - 1];
240 }
241 result->size++;
242 result->vc[i] = rhs->vc[j];
243 if (result->vc[i].threadid != tid)
244 {
245 almost_equal = False;
246 }
sewardjaf44c822007-11-25 14:01:38 +0000247 }
bartbedfd232009-03-26 19:07:15 +0000248 /* Otherwise, both *result and *rhs have a clock for thread */
249 /* result->vc[i].threadid == rhs->vc[j].threadid. Compute the maximum. */
250 else
bartfbbac092008-04-06 14:57:37 +0000251 {
bartbedfd232009-03-26 19:07:15 +0000252 tl_assert(result->vc[i].threadid == rhs->vc[j].threadid);
253 if (result->vc[i].threadid != tid
254 && rhs->vc[j].count != result->vc[i].count)
255 {
256 almost_equal = False;
257 }
258 if (rhs->vc[j].count > result->vc[i].count)
259 {
260 result->vc[i].count = rhs->vc[j].count;
261 }
bartfbbac092008-04-06 14:57:37 +0000262 }
bartbedfd232009-03-26 19:07:15 +0000263 }
264 DRD_(vc_check)(result);
265 tl_assert(result->size == new_size);
bartfbbac092008-04-06 14:57:37 +0000266
bartbedfd232009-03-26 19:07:15 +0000267 return almost_equal;
sewardjaf44c822007-11-25 14:01:38 +0000268}
269
bart41b226c2009-02-14 16:55:19 +0000270/** Print the contents of vector clock 'vc'. */
271void DRD_(vc_print)(const VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +0000272{
bartbedfd232009-03-26 19:07:15 +0000273 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000274
bartbedfd232009-03-26 19:07:15 +0000275 tl_assert(vc);
276 VG_(printf)("[");
277 for (i = 0; i < vc->size; i++)
278 {
279 tl_assert(vc->vc);
280 VG_(printf)("%s %d: %d", i > 0 ? "," : "",
281 vc->vc[i].threadid, vc->vc[i].count);
282 }
283 VG_(printf)(" ]");
sewardjaf44c822007-11-25 14:01:38 +0000284}
285
bart41b226c2009-02-14 16:55:19 +0000286/**
287 * Print the contents of vector clock 'vc' to the character array 'str' that
288 * has 'size' elements.
289 */
290void DRD_(vc_snprint)(Char* const str, const Int size,
291 const VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +0000292{
bartbedfd232009-03-26 19:07:15 +0000293 unsigned i;
294 unsigned j = 1;
sewardjaf44c822007-11-25 14:01:38 +0000295
bartbedfd232009-03-26 19:07:15 +0000296 tl_assert(vc);
297 VG_(snprintf)(str, size, "[");
298 for (i = 0; i < vc->size; i++)
299 {
300 tl_assert(vc->vc);
301 for ( ; j <= vc->vc[i].threadid; j++)
302 {
303 VG_(snprintf)(str + VG_(strlen)(str), size - VG_(strlen)(str),
304 "%s %d",
305 i > 0 ? "," : "",
306 (j == vc->vc[i].threadid) ? vc->vc[i].count : 0);
307 }
308 }
309 VG_(snprintf)(str + VG_(strlen)(str), size - VG_(strlen)(str), " ]");
sewardjaf44c822007-11-25 14:01:38 +0000310}
311
312/**
313 * Invariant test.
bart41b226c2009-02-14 16:55:19 +0000314 *
315 * The function below tests whether the following two conditions are
316 * satisfied:
317 * - size <= capacity.
318 * - Vector clock elements are stored in thread ID order.
319 *
320 * If one of these conditions is not met, an assertion failure is triggered.
sewardjaf44c822007-11-25 14:01:38 +0000321 */
bart41b226c2009-02-14 16:55:19 +0000322void DRD_(vc_check)(const VectorClock* const vc)
sewardjaf44c822007-11-25 14:01:38 +0000323{
bartbedfd232009-03-26 19:07:15 +0000324 unsigned i;
325 tl_assert(vc->size <= vc->capacity);
326 for (i = 1; i < vc->size; i++)
327 {
328 tl_assert(vc->vc[i-1].threadid < vc->vc[i].threadid);
329 }
sewardjaf44c822007-11-25 14:01:38 +0000330}
331
332/**
333 * Change the size of the memory block pointed at by vc->vc.
334 * Changes capacity, but does not change size. If the size of the memory
335 * block is increased, the newly allocated memory is not initialized.
336 */
337static
bart41b226c2009-02-14 16:55:19 +0000338void DRD_(vc_reserve)(VectorClock* const vc, const unsigned new_capacity)
sewardjaf44c822007-11-25 14:01:38 +0000339{
bartbedfd232009-03-26 19:07:15 +0000340 tl_assert(vc);
341 if (new_capacity > vc->capacity)
342 {
343 if (vc->vc)
344 {
345 vc->vc = VG_(realloc)("drd.vc.vr.1",
346 vc->vc, new_capacity * sizeof(vc->vc[0]));
347 }
348 else if (new_capacity > 0)
349 {
350 vc->vc = VG_(malloc)("drd.vc.vr.2",
351 new_capacity * sizeof(vc->vc[0]));
352 }
353 else
354 {
355 tl_assert(vc->vc == 0 && new_capacity == 0);
356 }
357 vc->capacity = new_capacity;
358 }
bart48fcfc62009-06-03 12:44:50 +0000359 else if (new_capacity == 0 && vc->vc)
360 {
361 VG_(free)(vc->vc);
362 vc->vc = 0;
363 }
bartbedfd232009-03-26 19:07:15 +0000364 tl_assert(new_capacity == 0 || vc->vc != 0);
sewardjaf44c822007-11-25 14:01:38 +0000365}
366
bart41b226c2009-02-14 16:55:19 +0000367#if 0
sewardjaf44c822007-11-25 14:01:38 +0000368/**
369 * Unit test.
370 */
bart41b226c2009-02-14 16:55:19 +0000371void DRD_(vc_test)(void)
sewardjaf44c822007-11-25 14:01:38 +0000372{
bartbedfd232009-03-26 19:07:15 +0000373 VectorClock vc1;
374 VCElem vc1elem[] = { { 3, 7 }, { 5, 8 }, };
375 VectorClock vc2;
376 VCElem vc2elem[] = { { 1, 4 }, { 3, 9 }, };
377 VectorClock vc3;
378 VCElem vc4elem[] = { { 1, 3 }, { 2, 1 }, };
379 VectorClock vc4;
380 VCElem vc5elem[] = { { 1, 4 }, };
381 VectorClock vc5;
sewardjaf44c822007-11-25 14:01:38 +0000382
bartbedfd232009-03-26 19:07:15 +0000383 vc_init(&vc1, vc1elem, sizeof(vc1elem)/sizeof(vc1elem[0]));
384 vc_init(&vc2, vc2elem, sizeof(vc2elem)/sizeof(vc2elem[0]));
385 vc_init(&vc3, 0, 0);
386 vc_init(&vc4, vc4elem, sizeof(vc4elem)/sizeof(vc4elem[0]));
387 vc_init(&vc5, vc5elem, sizeof(vc5elem)/sizeof(vc5elem[0]));
sewardjaf44c822007-11-25 14:01:38 +0000388
bartbedfd232009-03-26 19:07:15 +0000389 vc_combine(&vc3, &vc1);
390 vc_combine(&vc3, &vc2);
sewardjaf44c822007-11-25 14:01:38 +0000391
bartbedfd232009-03-26 19:07:15 +0000392 VG_(printf)("vc1: ");
393 vc_print(&vc1);
394 VG_(printf)("\nvc2: ");
395 vc_print(&vc2);
396 VG_(printf)("\nvc3: ");
397 vc_print(&vc3);
398 VG_(printf)("\n");
399 VG_(printf)("vc_lte(vc1, vc2) = %d, vc_lte(vc1, vc3) = %d,"
400 " vc_lte(vc2, vc3) = %d, vc_lte(",
401 vc_lte(&vc1, &vc2), vc_lte(&vc1, &vc3), vc_lte(&vc2, &vc3));
402 vc_print(&vc4);
403 VG_(printf)(", ");
404 vc_print(&vc5);
405 VG_(printf)(") = %d sw %d\n", vc_lte(&vc4, &vc5), vc_lte(&vc5, &vc4));
sewardjaf44c822007-11-25 14:01:38 +0000406
bartbedfd232009-03-26 19:07:15 +0000407 vc_cleanup(&vc1);
408 vc_cleanup(&vc2);
409 vc_cleanup(&vc3);
sewardjaf44c822007-11-25 14:01:38 +0000410}
bart41b226c2009-02-14 16:55:19 +0000411#endif