1af44c8236f7a73e71b16b707bba56f33af4d01cesewardj/*
286562bd89ac23ce795d19c71fabcb9d1c8f956d3bart  This file is part of drd, a thread error detector.
3af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
4ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes  Copyright (C) 2006-2017 Bart Van Assche <bvanassche@acm.org>.
5af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
6af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  This program is free software; you can redistribute it and/or
7af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  modify it under the terms of the GNU General Public License as
8af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  published by the Free Software Foundation; either version 2 of the
9af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  License, or (at your option) any later version.
10af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
11af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  This program is distributed in the hope that it will be useful, but
12af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  WITHOUT ANY WARRANTY; without even the implied warranty of
13af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  General Public License for more details.
15af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
16af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  You should have received a copy of the GNU General Public License
17af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  along with this program; if not, write to the Free Software
18af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  02111-1307, USA.
20af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
21af44c8236f7a73e71b16b707bba56f33af4d01cesewardj  The GNU General Public License is contained in the file COPYING.
22af44c8236f7a73e71b16b707bba56f33af4d01cesewardj*/
23af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
24af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
2528230a3734e045791173aca660efc7d7aeef78cebart#include "drd_clientobj.h"
26af44c8236f7a73e71b16b707bba56f33af4d01cesewardj#include "drd_cond.h"
27af44c8236f7a73e71b16b707bba56f33af4d01cesewardj#include "drd_error.h"
28af44c8236f7a73e71b16b707bba56f33af4d01cesewardj#include "drd_mutex.h"
2946b5fcebcf676fcc950a359d9dee5ac0d5755afcbart#include "pub_tool_errormgr.h"    /* VG_(maybe_record_error)() */
3046b5fcebcf676fcc950a359d9dee5ac0d5755afcbart#include "pub_tool_libcassert.h"  /* tl_assert()               */
31850f1990e89f10e7efb33a140ab14baaebacc864bart#include "pub_tool_libcbase.h"    /* VG_(memcmp)()             */
3246b5fcebcf676fcc950a359d9dee5ac0d5755afcbart#include "pub_tool_libcprint.h"   /* VG_(printf)()             */
3346b5fcebcf676fcc950a359d9dee5ac0d5755afcbart#include "pub_tool_machine.h"     /* VG_(get_IP)()             */
3446b5fcebcf676fcc950a359d9dee5ac0d5755afcbart#include "pub_tool_threadstate.h" /* VG_(get_running_tid)()    */
35af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
36af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
3746b5fcebcf676fcc950a359d9dee5ac0d5755afcbart/* Local functions. */
3828230a3734e045791173aca660efc7d7aeef78cebart
39dc1ef03a8d13efe24661a89091e66169bf3f1091bartstatic void DRD_(cond_cleanup)(struct cond_info* p);
4028230a3734e045791173aca660efc7d7aeef78cebart
4128230a3734e045791173aca660efc7d7aeef78cebart
4246b5fcebcf676fcc950a359d9dee5ac0d5755afcbart/* Local variables. */
4328230a3734e045791173aca660efc7d7aeef78cebart
44dc1ef03a8d13efe24661a89091e66169bf3f1091bartstatic Bool DRD_(s_report_signal_unlocked) = True;
45dc1ef03a8d13efe24661a89091e66169bf3f1091bartstatic Bool DRD_(s_trace_cond);
46af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
47af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
4846b5fcebcf676fcc950a359d9dee5ac0d5755afcbart/* Function definitions. */
4928230a3734e045791173aca660efc7d7aeef78cebart
50dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(cond_set_report_signal_unlocked)(const Bool r)
51764dea2795ab46dadc2198a1123c0943181c6e70bart{
52bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   DRD_(s_report_signal_unlocked) = r;
53764dea2795ab46dadc2198a1123c0943181c6e70bart}
54764dea2795ab46dadc2198a1123c0943181c6e70bart
55dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(cond_set_trace)(const Bool trace_cond)
56af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
57bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   DRD_(s_trace_cond) = trace_cond;
58af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
59af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
60af44c8236f7a73e71b16b707bba56f33af4d01cesewardjstatic
61dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(cond_initialize)(struct cond_info* const p, const Addr cond)
62af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
63bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(cond != 0);
6462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   tl_assert(p->a1   == cond);
6562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   tl_assert(p->type == ClientCondvar);
66bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
67bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->cleanup       = (void(*)(DrdClientobj*))(DRD_(cond_cleanup));
68bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->delete_thread = 0;
69bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->waiter_count  = 0;
70bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->mutex         = 0;
71af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
72af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
73195e41fe2b9e02e142a0461113bfa55c89d24c5ebart/**
74195e41fe2b9e02e142a0461113bfa55c89d24c5ebart * Free the memory that was allocated by cond_initialize(). Called by
75195e41fe2b9e02e142a0461113bfa55c89d24c5ebart * DRD_(clientobj_remove)().
7628230a3734e045791173aca660efc7d7aeef78cebart */
77dc1ef03a8d13efe24661a89091e66169bf3f1091bartstatic void DRD_(cond_cleanup)(struct cond_info* p)
78af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
79bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(p);
80bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p->mutex)
81bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
82bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      struct mutex_info* q;
83bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
84bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      {
8562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart         CondDestrErrInfo cde = {
8662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	    DRD_(thread_get_running_tid)(),
8762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	    p->a1,
8862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	    q ? q->a1 : 0,
8962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	    q ? q->owner : DRD_INVALID_THREADID
9062cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 };
91bedfd237fbdc80d0c917cfcb85a94b5561c92633bart         VG_(maybe_record_error)(VG_(get_running_tid)(),
92bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                                 CondDestrErr,
93bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                                 VG_(get_IP)(VG_(get_running_tid)()),
94bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                                 "Destroying condition variable that is being"
95bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                                 " waited upon",
96bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                                 &cde);
97bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      }
98bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
9928230a3734e045791173aca660efc7d7aeef78cebart}
10028230a3734e045791173aca660efc7d7aeef78cebart
10162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart/**
10262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart * Report that the synchronization object at address 'addr' is of the
10362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart * wrong type.
10462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart */
10562cc23286aa2d2cbeb6643a15ef37fe020a3d159bartstatic void wrong_type(const Addr addr)
10662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart{
10762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   GenericErrInfo gei = {
10862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      .tid  = DRD_(thread_get_running_tid)(),
10962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      .addr = addr,
11062cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   };
11162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   VG_(maybe_record_error)(VG_(get_running_tid)(),
11262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           GenericErr,
11362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           VG_(get_IP)(VG_(get_running_tid)()),
11462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           "wrong type of synchronization object",
11562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           &gei);
11662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart}
11762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
118d45d99553c15a361bb797d21ec6afb9bad22d2d4bartstatic struct cond_info* cond_get_or_allocate(const Addr cond)
11928230a3734e045791173aca660efc7d7aeef78cebart{
120bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct cond_info *p;
121bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
122bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(offsetof(DrdClientobj, cond) == 0);
123bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p = &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
12462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   if (p)
12562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      return p;
12662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
12762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   if (DRD_(clientobj_present)(cond, cond + 1))
128bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
12962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      wrong_type(cond);
13062cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      return 0;
131bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
13262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
13362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
13462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   DRD_(cond_initialize)(p, cond);
135bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   return p;
136af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
137af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
138d45d99553c15a361bb797d21ec6afb9bad22d2d4bartstruct cond_info* DRD_(cond_get)(const Addr cond)
13928230a3734e045791173aca660efc7d7aeef78cebart{
140bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(offsetof(DrdClientobj, cond) == 0);
141bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   return &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
14228230a3734e045791173aca660efc7d7aeef78cebart}
14328230a3734e045791173aca660efc7d7aeef78cebart
14428230a3734e045791173aca660efc7d7aeef78cebart/** Called before pthread_cond_init(). */
145dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(cond_pre_init)(const Addr cond)
146af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
147bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct cond_info* p;
148bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
149bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (DRD_(s_trace_cond))
150ea71ffb08eccc0869c5b9421160fef4052e35c23florian      DRD_(trace_msg)("[%u] cond_init       cond 0x%lx",
151b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), cond);
152bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
153bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p = DRD_(cond_get)(cond);
154bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
1554005d47b84b5ab8ae64eeb4b4e73102d3bdb4b09bart   if (p) {
156d45d99553c15a361bb797d21ec6afb9bad22d2d4bart      CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
157bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
158bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              CondErr,
159bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(VG_(get_running_tid)()),
160bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "initialized twice",
161bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &cei);
162bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
163bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
1644005d47b84b5ab8ae64eeb4b4e73102d3bdb4b09bart   cond_get_or_allocate(cond);
165af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
166af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
16728230a3734e045791173aca660efc7d7aeef78cebart/** Called after pthread_cond_destroy(). */
168d36fa80de3fb0350509a3714bb795392aca21849bartvoid DRD_(cond_post_destroy)(const Addr cond, const Bool destroy_succeeded)
169af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
170bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct cond_info* p;
171bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
172bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (DRD_(s_trace_cond))
173ea71ffb08eccc0869c5b9421160fef4052e35c23florian      DRD_(trace_msg)("[%u] cond_destroy    cond 0x%lx",
174b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), cond);
175bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
176bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p = DRD_(cond_get)(cond);
177bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p == 0)
178bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
179d45d99553c15a361bb797d21ec6afb9bad22d2d4bart      CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
180bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
181bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              CondErr,
182bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(VG_(get_running_tid)()),
183bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "not a condition variable",
184bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &cei);
185bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      return;
186bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
187bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
188bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p->waiter_count != 0)
189bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
190d45d99553c15a361bb797d21ec6afb9bad22d2d4bart      CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
191bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
192bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              CondErr,
193bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(VG_(get_running_tid)()),
194bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "destruction of condition variable being waited"
195bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              " upon",
196bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &cei);
197bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
198bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
199d36fa80de3fb0350509a3714bb795392aca21849bart   if (destroy_succeeded)
200d36fa80de3fb0350509a3714bb795392aca21849bart      DRD_(clientobj_remove)(p->a1, ClientCondvar);
201af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
202af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
20362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart/**
20462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart * Called before pthread_cond_wait(). Note: before this function is called,
20562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart * mutex_unlock() has already been called from drd_clientreq.c.
20608e6d6ac35bce1b6a2203a23c4dafd96035fdc29bart */
20762cc23286aa2d2cbeb6643a15ef37fe020a3d159bartvoid DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
208af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
209bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct cond_info* p;
210bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct mutex_info* q;
211bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
212bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (DRD_(s_trace_cond))
213ea71ffb08eccc0869c5b9421160fef4052e35c23florian      DRD_(trace_msg)("[%u] cond_pre_wait   cond 0x%lx",
214b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), cond);
215bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
216d45d99553c15a361bb797d21ec6afb9bad22d2d4bart   p = cond_get_or_allocate(cond);
21762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   if (!p)
21862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   {
21962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
22062cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
22162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                              CondErr,
22262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                              VG_(get_IP)(VG_(get_running_tid)()),
22362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                              "not a condition variable",
22462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                              &cei);
22562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      return;
22662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   }
227bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
228bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p->waiter_count == 0)
229bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
230bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      p->mutex = mutex;
231bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
232bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   else if (p->mutex != mutex)
233bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
234bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      CondWaitErrInfo cwei
235d45d99553c15a361bb797d21ec6afb9bad22d2d4bart         = { .tid = DRD_(thread_get_running_tid)(),
236d45d99553c15a361bb797d21ec6afb9bad22d2d4bart             .cond = cond, .mutex1 = p->mutex, .mutex2 = mutex };
237bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
238bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              CondWaitErr,
239bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(VG_(get_running_tid)()),
240bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "Inconsistent association of condition variable"
241bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              " and mutex",
242bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &cwei);
243bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
244bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(p->mutex);
245bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   q = DRD_(mutex_get)(p->mutex);
246bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (q
247bedfd237fbdc80d0c917cfcb85a94b5561c92633bart       && q->owner == DRD_(thread_get_running_tid)() && q->recursion_count > 0)
248bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
249bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      const ThreadId vg_tid = VG_(get_running_tid)();
250d45d99553c15a361bb797d21ec6afb9bad22d2d4bart      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
251d45d99553c15a361bb797d21ec6afb9bad22d2d4bart                           q->a1, q->recursion_count, q->owner };
252bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(vg_tid,
253bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              MutexErr,
254bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(vg_tid),
255bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "Mutex locked recursively",
256bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &MEI);
257bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
258bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   else if (q == 0)
259bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
260bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      DRD_(not_a_mutex)(p->mutex);
261bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
262bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
26362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   ++p->waiter_count;
264af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
265af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
26662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart/**
26762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart * Called after pthread_cond_wait().
26862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart */
26962cc23286aa2d2cbeb6643a15ef37fe020a3d159bartvoid DRD_(cond_post_wait)(const Addr cond)
270af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
271bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct cond_info* p;
272bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
273bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (DRD_(s_trace_cond))
274ea71ffb08eccc0869c5b9421160fef4052e35c23florian      DRD_(trace_msg)("[%u] cond_post_wait  cond 0x%lx",
275b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), cond);
276bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
277bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p = DRD_(cond_get)(cond);
27862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   if (!p)
279bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
2807a2cc3c5be225eb49813c1460d861481ee490d6ebart      CondDestrErrInfo cde = {
2817a2cc3c5be225eb49813c1460d861481ee490d6ebart         DRD_(thread_get_running_tid)(), cond, 0, DRD_INVALID_THREADID
2827a2cc3c5be225eb49813c1460d861481ee490d6ebart      };
2837a2cc3c5be225eb49813c1460d861481ee490d6ebart      VG_(maybe_record_error)(VG_(get_running_tid)(),
2847a2cc3c5be225eb49813c1460d861481ee490d6ebart                              CondDestrErr,
2857a2cc3c5be225eb49813c1460d861481ee490d6ebart                              VG_(get_IP)(VG_(get_running_tid)()),
2867a2cc3c5be225eb49813c1460d861481ee490d6ebart                              "condition variable has been destroyed while"
2877a2cc3c5be225eb49813c1460d861481ee490d6ebart                              " being waited upon",
2887a2cc3c5be225eb49813c1460d861481ee490d6ebart                              &cde);
28962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      return;
29062cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   }
29162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
29262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   if (p->waiter_count > 0)
29362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   {
29462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      --p->waiter_count;
29562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      if (p->waiter_count == 0)
29662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      {
29762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 p->mutex = 0;
298a9c5508b2963e498de4fa95777ff3efd59d65a3abart      }
299bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
300af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
301af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
30262cc23286aa2d2cbeb6643a15ef37fe020a3d159bartstatic void cond_signal(const DrdThreadId tid, struct cond_info* const cond_p)
303af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
304bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   const ThreadId vg_tid = VG_(get_running_tid)();
305bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
306bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
30762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   tl_assert(cond_p);
30862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
30962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   if (cond_p->waiter_count > 0)
310bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
311bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      if (DRD_(s_report_signal_unlocked)
31262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	  && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
313bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      {
31462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 /*
31562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	  * A signal is sent while the associated mutex has not been locked.
31662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	  * This can indicate but is not necessarily a race condition.
31762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	  */
31862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
31962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart				 .cond  = cond_p->a1,
32062cc23286aa2d2cbeb6643a15ef37fe020a3d159bart				 .mutex = cond_p->mutex,
32162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 };
32262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 VG_(maybe_record_error)(vg_tid,
32362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart				 CondRaceErr,
32462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart				 VG_(get_IP)(vg_tid),
32562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart				 "CondErr",
32662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart				 &cei);
327bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      }
328bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
329bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   else
330bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
33162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      /*
33262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart       * No other thread is waiting for the signal, hence the signal will
33362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart       * be lost. This is normal in a POSIX threads application.
33462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart       */
335bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
336af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
337af44c8236f7a73e71b16b707bba56f33af4d01cesewardj
33862cc23286aa2d2cbeb6643a15ef37fe020a3d159bartstatic void not_initialized(Addr const cond)
33962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart{
34062cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
34162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   VG_(maybe_record_error)(VG_(get_running_tid)(),
34262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           CondErr,
34362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           VG_(get_IP)(VG_(get_running_tid)()),
34462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           "condition variable has not been initialized",
34562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart                           &cei);
34662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart}
34762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
3483b1ee459c4a59f6479a7b2803f7ccd952aab44bbbart/** Called before pthread_cond_signal(). */
349dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(cond_pre_signal)(Addr const cond)
3503b1ee459c4a59f6479a7b2803f7ccd952aab44bbbart{
35162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   struct cond_info* p;
35262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
35362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   p = DRD_(cond_get)(cond);
354bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (DRD_(s_trace_cond))
355ea71ffb08eccc0869c5b9421160fef4052e35c23florian      DRD_(trace_msg)("[%u] cond_signal     cond 0x%lx",
356b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), cond);
357bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
358850f1990e89f10e7efb33a140ab14baaebacc864bart   tl_assert(DRD_(pthread_cond_initializer));
359850f1990e89f10e7efb33a140ab14baaebacc864bart   if (!p && VG_(memcmp)((void*)cond, (void*)DRD_(pthread_cond_initializer),
360850f1990e89f10e7efb33a140ab14baaebacc864bart                         DRD_(pthread_cond_initializer_size)) != 0)
36162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   {
36262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      not_initialized(cond);
36362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      return;
36462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   }
36562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
366850f1990e89f10e7efb33a140ab14baaebacc864bart   if (!p)
367850f1990e89f10e7efb33a140ab14baaebacc864bart      p = cond_get_or_allocate(cond);
368850f1990e89f10e7efb33a140ab14baaebacc864bart
36962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   cond_signal(DRD_(thread_get_running_tid)(), p);
3703b1ee459c4a59f6479a7b2803f7ccd952aab44bbbart}
3713b1ee459c4a59f6479a7b2803f7ccd952aab44bbbart
37228230a3734e045791173aca660efc7d7aeef78cebart/** Called before pthread_cond_broadcast(). */
373dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(cond_pre_broadcast)(Addr const cond)
374af44c8236f7a73e71b16b707bba56f33af4d01cesewardj{
37562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   struct cond_info* p;
37662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
377bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (DRD_(s_trace_cond))
378ea71ffb08eccc0869c5b9421160fef4052e35c23florian      DRD_(trace_msg)("[%u] cond_broadcast  cond 0x%lx",
379b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), cond);
380bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
38162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   p = DRD_(cond_get)(cond);
382850f1990e89f10e7efb33a140ab14baaebacc864bart   tl_assert(DRD_(pthread_cond_initializer));
383850f1990e89f10e7efb33a140ab14baaebacc864bart   if (!p && VG_(memcmp)((void*)cond, (void*)DRD_(pthread_cond_initializer),
384850f1990e89f10e7efb33a140ab14baaebacc864bart                         DRD_(pthread_cond_initializer_size)) != 0)
38562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   {
38662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      not_initialized(cond);
38762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      return;
38862cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   }
38962cc23286aa2d2cbeb6643a15ef37fe020a3d159bart
390850f1990e89f10e7efb33a140ab14baaebacc864bart   if (!p)
391850f1990e89f10e7efb33a140ab14baaebacc864bart      p = cond_get_or_allocate(cond);
392850f1990e89f10e7efb33a140ab14baaebacc864bart
39362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart   cond_signal(DRD_(thread_get_running_tid)(), p);
394af44c8236f7a73e71b16b707bba56f33af4d01cesewardj}
395