]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/drd/drd_cond.c
456b290f3e7a750a6b6675317b52da797132ef5a
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / drd / drd_cond.c
1 /* -*- mode: C; c-basic-offset: 3; -*- */
2 /*
3   This file is part of drd, a thread error detector.
4
5   Copyright (C) 2006-2010 Bart Van Assche <bart.vanassche@gmail.com>.
6
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_clientobj.h"
27 #include "drd_cond.h"
28 #include "drd_error.h"
29 #include "drd_mutex.h"
30 #include "pub_tool_errormgr.h"    /* VG_(maybe_record_error)() */
31 #include "pub_tool_libcassert.h"  /* tl_assert()               */
32 #include "pub_tool_libcprint.h"   /* VG_(printf)()             */
33 #include "pub_tool_machine.h"     /* VG_(get_IP)()             */
34 #include "pub_tool_threadstate.h" /* VG_(get_running_tid)()    */
35
36
37 /* Local functions. */
38
39 static void DRD_(cond_cleanup)(struct cond_info* p);
40
41
42 /* Local variables. */
43
44 static Bool DRD_(s_report_signal_unlocked) = True;
45 static Bool DRD_(s_trace_cond);
46
47
48 /* Function definitions. */
49
50 void DRD_(cond_set_report_signal_unlocked)(const Bool r)
51 {
52    DRD_(s_report_signal_unlocked) = r;
53 }
54
55 void DRD_(cond_set_trace)(const Bool trace_cond)
56 {
57    DRD_(s_trace_cond) = trace_cond;
58 }
59
60 static
61 void DRD_(cond_initialize)(struct cond_info* const p, const Addr cond)
62 {
63    tl_assert(cond != 0);
64    tl_assert(p->a1   == cond);
65    tl_assert(p->type == ClientCondvar);
66
67    p->cleanup       = (void(*)(DrdClientobj*))(DRD_(cond_cleanup));
68    p->delete_thread = 0;
69    p->waiter_count  = 0;
70    p->mutex         = 0;
71 }
72
73 /**
74  * Free the memory that was allocated by cond_initialize(). Called by
75  * DRD_(clientobj_remove)().
76  */
77 static void DRD_(cond_cleanup)(struct cond_info* p)
78 {
79    tl_assert(p);
80    if (p->mutex)
81    {
82       struct mutex_info* q;
83       q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
84       {
85          CondDestrErrInfo cde = {
86             DRD_(thread_get_running_tid)(),
87             p->a1,
88             q ? q->a1 : 0,
89             q ? q->owner : DRD_INVALID_THREADID
90          };
91          VG_(maybe_record_error)(VG_(get_running_tid)(),
92                                  CondDestrErr,
93                                  VG_(get_IP)(VG_(get_running_tid)()),
94                                  "Destroying condition variable that is being"
95                                  " waited upon",
96                                  &cde);
97       }
98    }
99 }
100
101 /**
102  * Report that the synchronization object at address 'addr' is of the
103  * wrong type.
104  */
105 static void wrong_type(const Addr addr)
106 {
107    GenericErrInfo gei = {
108       .tid  = DRD_(thread_get_running_tid)(),
109       .addr = addr,
110    };
111    VG_(maybe_record_error)(VG_(get_running_tid)(),
112                            GenericErr,
113                            VG_(get_IP)(VG_(get_running_tid)()),
114                            "wrong type of synchronization object",
115                            &gei);
116 }
117
118 static struct cond_info* cond_get_or_allocate(const Addr cond)
119 {
120    struct cond_info *p;
121
122    tl_assert(offsetof(DrdClientobj, cond) == 0);
123    p = &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
124    if (p)
125       return p;
126
127    if (DRD_(clientobj_present)(cond, cond + 1))
128    {
129       wrong_type(cond);
130       return 0;
131    }
132
133    p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
134    DRD_(cond_initialize)(p, cond);
135    return p;
136 }
137
138 struct cond_info* DRD_(cond_get)(const Addr cond)
139 {
140    tl_assert(offsetof(DrdClientobj, cond) == 0);
141    return &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
142 }
143
144 /** Called before pthread_cond_init(). */
145 void DRD_(cond_pre_init)(const Addr cond)
146 {
147    struct cond_info* p;
148
149    if (DRD_(s_trace_cond))
150    {
151       VG_(message)(Vg_UserMsg,
152                    "[%d] cond_init       cond 0x%lx\n",
153                    DRD_(thread_get_running_tid)(),
154                    cond);
155    }
156
157    p = DRD_(cond_get)(cond);
158
159    if (p)
160    {
161       CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
162       VG_(maybe_record_error)(VG_(get_running_tid)(),
163                               CondErr,
164                               VG_(get_IP)(VG_(get_running_tid)()),
165                               "initialized twice",
166                               &cei);
167    }
168
169    p = cond_get_or_allocate(cond);
170 }
171
172 /** Called after pthread_cond_destroy(). */
173 void DRD_(cond_post_destroy)(const Addr cond)
174 {
175    struct cond_info* p;
176
177    if (DRD_(s_trace_cond))
178    {
179       VG_(message)(Vg_UserMsg,
180                    "[%d] cond_destroy    cond 0x%lx\n",
181                    DRD_(thread_get_running_tid)(),
182                    cond);
183    }
184
185    p = DRD_(cond_get)(cond);
186    if (p == 0)
187    {
188       CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
189       VG_(maybe_record_error)(VG_(get_running_tid)(),
190                               CondErr,
191                               VG_(get_IP)(VG_(get_running_tid)()),
192                               "not a condition variable",
193                               &cei);
194       return;
195    }
196
197    if (p->waiter_count != 0)
198    {
199       CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
200       VG_(maybe_record_error)(VG_(get_running_tid)(),
201                               CondErr,
202                               VG_(get_IP)(VG_(get_running_tid)()),
203                               "destruction of condition variable being waited"
204                               " upon",
205                               &cei);
206    }
207
208    DRD_(clientobj_remove)(p->a1, ClientCondvar);
209 }
210
211 /**
212  * Called before pthread_cond_wait(). Note: before this function is called,
213  * mutex_unlock() has already been called from drd_clientreq.c.
214  */
215 void DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
216 {
217    struct cond_info* p;
218    struct mutex_info* q;
219
220    if (DRD_(s_trace_cond))
221    {
222       VG_(message)(Vg_UserMsg,
223                    "[%d] cond_pre_wait   cond 0x%lx\n",
224                    DRD_(thread_get_running_tid)(),
225                    cond);
226    }
227
228    p = cond_get_or_allocate(cond);
229    if (!p)
230    {
231       CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
232       VG_(maybe_record_error)(VG_(get_running_tid)(),
233                               CondErr,
234                               VG_(get_IP)(VG_(get_running_tid)()),
235                               "not a condition variable",
236                               &cei);
237       return;
238    }
239
240    if (p->waiter_count == 0)
241    {
242       p->mutex = mutex;
243    }
244    else if (p->mutex != mutex)
245    {
246       CondWaitErrInfo cwei
247          = { .tid = DRD_(thread_get_running_tid)(),
248              .cond = cond, .mutex1 = p->mutex, .mutex2 = mutex };
249       VG_(maybe_record_error)(VG_(get_running_tid)(),
250                               CondWaitErr,
251                               VG_(get_IP)(VG_(get_running_tid)()),
252                               "Inconsistent association of condition variable"
253                               " and mutex",
254                               &cwei);
255    }
256    tl_assert(p->mutex);
257    q = DRD_(mutex_get)(p->mutex);
258    if (q
259        && q->owner == DRD_(thread_get_running_tid)() && q->recursion_count > 0)
260    {
261       const ThreadId vg_tid = VG_(get_running_tid)();
262       MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
263                            q->a1, q->recursion_count, q->owner };
264       VG_(maybe_record_error)(vg_tid,
265                               MutexErr,
266                               VG_(get_IP)(vg_tid),
267                               "Mutex locked recursively",
268                               &MEI);
269    }
270    else if (q == 0)
271    {
272       DRD_(not_a_mutex)(p->mutex);
273    }
274
275    ++p->waiter_count;
276 }
277
278 /**
279  * Called after pthread_cond_wait().
280  */
281 void DRD_(cond_post_wait)(const Addr cond)
282 {
283    struct cond_info* p;
284
285    if (DRD_(s_trace_cond))
286    {
287       VG_(message)(Vg_UserMsg,
288                    "[%d] cond_post_wait  cond 0x%lx\n",
289                    DRD_(thread_get_running_tid)(),
290                    cond);
291    }
292
293    p = DRD_(cond_get)(cond);
294    if (!p)
295    {
296       struct mutex_info* q;
297       q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
298       {
299          CondDestrErrInfo cde = {
300             DRD_(thread_get_running_tid)(),
301             p->a1,
302             q ? q->a1 : 0,
303             q ? q->owner : DRD_INVALID_THREADID
304          };
305          VG_(maybe_record_error)(VG_(get_running_tid)(),
306                                  CondDestrErr,
307                                  VG_(get_IP)(VG_(get_running_tid)()),
308                                  "condition variable has been destroyed while"
309                                  " being waited upon",
310                                  &cde);
311       }
312       return;
313    }
314
315    if (p->waiter_count > 0)
316    {
317       --p->waiter_count;
318       if (p->waiter_count == 0)
319       {
320          p->mutex = 0;
321       }
322    }
323 }
324
325 static void cond_signal(const DrdThreadId tid, struct cond_info* const cond_p)
326 {
327    const ThreadId vg_tid = VG_(get_running_tid)();
328    const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
329
330    tl_assert(cond_p);
331
332    if (cond_p->waiter_count > 0)
333    {
334       if (DRD_(s_report_signal_unlocked)
335           && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
336       {
337          /*
338           * A signal is sent while the associated mutex has not been locked.
339           * This can indicate but is not necessarily a race condition.
340           */
341          CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
342                                  .cond  = cond_p->a1,
343                                  .mutex = cond_p->mutex,
344          };
345          VG_(maybe_record_error)(vg_tid,
346                                  CondRaceErr,
347                                  VG_(get_IP)(vg_tid),
348                                  "CondErr",
349                                  &cei);
350       }
351    }
352    else
353    {
354       /*
355        * No other thread is waiting for the signal, hence the signal will
356        * be lost. This is normal in a POSIX threads application.
357        */
358    }
359 }
360
361 static void not_initialized(Addr const cond)
362 {
363    CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
364    VG_(maybe_record_error)(VG_(get_running_tid)(),
365                            CondErr,
366                            VG_(get_IP)(VG_(get_running_tid)()),
367                            "condition variable has not been initialized",
368                            &cei);
369 }
370
371 /** Called before pthread_cond_signal(). */
372 void DRD_(cond_pre_signal)(Addr const cond)
373 {
374    struct cond_info* p;
375
376    p = DRD_(cond_get)(cond);
377    if (DRD_(s_trace_cond))
378    {
379       VG_(message)(Vg_UserMsg,
380                    "[%d] cond_signal     cond 0x%lx\n",
381                    DRD_(thread_get_running_tid)(),
382                    cond);
383    }
384
385    if (!p)
386    {
387       not_initialized(cond);
388       return;
389    }
390
391    cond_signal(DRD_(thread_get_running_tid)(), p);
392 }
393
394 /** Called before pthread_cond_broadcast(). */
395 void DRD_(cond_pre_broadcast)(Addr const cond)
396 {
397    struct cond_info* p;
398
399    if (DRD_(s_trace_cond))
400    {
401       VG_(message)(Vg_UserMsg,
402                    "[%d] cond_broadcast  cond 0x%lx\n",
403                    DRD_(thread_get_running_tid)(),
404                    cond);
405    }
406
407    p = DRD_(cond_get)(cond);
408    if (!p)
409    {
410       not_initialized(cond);
411       return;
412    }
413
414    cond_signal(DRD_(thread_get_running_tid)(), p);
415 }