18564292ac4b9adf51c45517cca2878732feb5bb4sewardj/*
286562bd89ac23ce795d19c71fabcb9d1c8f956d3bart  This file is part of drd, a thread error detector.
38564292ac4b9adf51c45517cca2878732feb5bb4sewardj
4d4bab99f83dbc53665c5769c3f6b50ffcd2a9a7dbart  Copyright (C) 2006-2013 Bart Van Assche <bvanassche@acm.org>.
58564292ac4b9adf51c45517cca2878732feb5bb4sewardj
68564292ac4b9adf51c45517cca2878732feb5bb4sewardj  This program is free software; you can redistribute it and/or
78564292ac4b9adf51c45517cca2878732feb5bb4sewardj  modify it under the terms of the GNU General Public License as
88564292ac4b9adf51c45517cca2878732feb5bb4sewardj  published by the Free Software Foundation; either version 2 of the
98564292ac4b9adf51c45517cca2878732feb5bb4sewardj  License, or (at your option) any later version.
108564292ac4b9adf51c45517cca2878732feb5bb4sewardj
118564292ac4b9adf51c45517cca2878732feb5bb4sewardj  This program is distributed in the hope that it will be useful, but
128564292ac4b9adf51c45517cca2878732feb5bb4sewardj  WITHOUT ANY WARRANTY; without even the implied warranty of
138564292ac4b9adf51c45517cca2878732feb5bb4sewardj  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
148564292ac4b9adf51c45517cca2878732feb5bb4sewardj  General Public License for more details.
158564292ac4b9adf51c45517cca2878732feb5bb4sewardj
168564292ac4b9adf51c45517cca2878732feb5bb4sewardj  You should have received a copy of the GNU General Public License
178564292ac4b9adf51c45517cca2878732feb5bb4sewardj  along with this program; if not, write to the Free Software
188564292ac4b9adf51c45517cca2878732feb5bb4sewardj  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
198564292ac4b9adf51c45517cca2878732feb5bb4sewardj  02111-1307, USA.
208564292ac4b9adf51c45517cca2878732feb5bb4sewardj
218564292ac4b9adf51c45517cca2878732feb5bb4sewardj  The GNU General Public License is contained in the file COPYING.
228564292ac4b9adf51c45517cca2878732feb5bb4sewardj*/
238564292ac4b9adf51c45517cca2878732feb5bb4sewardj
248564292ac4b9adf51c45517cca2878732feb5bb4sewardj
2528230a3734e045791173aca660efc7d7aeef78cebart#include "drd_clientobj.h"
268564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "drd_error.h"
278564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "drd_semaphore.h"
288564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "drd_suppression.h"
298564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "pub_tool_errormgr.h"    // VG_(maybe_record_error)()
308564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "pub_tool_libcassert.h"  // tl_assert()
318564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "pub_tool_libcprint.h"   // VG_(printf)()
328564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "pub_tool_machine.h"     // VG_(get_IP)()
333e017fa58a7c090cee54809baa4f5be78cb4eef9bart#include "pub_tool_mallocfree.h"  // VG_(malloc), VG_(free)
348564292ac4b9adf51c45517cca2878732feb5bb4sewardj#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
358564292ac4b9adf51c45517cca2878732feb5bb4sewardj
368564292ac4b9adf51c45517cca2878732feb5bb4sewardj
37dc1ef03a8d13efe24661a89091e66169bf3f1091bart/* Local functions. */
388564292ac4b9adf51c45517cca2878732feb5bb4sewardj
39d2c5eae561040706a7eb45c0f3988dcd538c8d7ebartstatic void semaphore_cleanup(struct semaphore_info* p);
408564292ac4b9adf51c45517cca2878732feb5bb4sewardj
418564292ac4b9adf51c45517cca2878732feb5bb4sewardj
42dc1ef03a8d13efe24661a89091e66169bf3f1091bart/* Local variables. */
438564292ac4b9adf51c45517cca2878732feb5bb4sewardj
44d2c5eae561040706a7eb45c0f3988dcd538c8d7ebartstatic Bool s_trace_semaphore;
45d2c5eae561040706a7eb45c0f3988dcd538c8d7ebartstatic ULong s_semaphore_segment_creation_count;
468564292ac4b9adf51c45517cca2878732feb5bb4sewardj
478564292ac4b9adf51c45517cca2878732feb5bb4sewardj
48dc1ef03a8d13efe24661a89091e66169bf3f1091bart/* Function definitions. */
498564292ac4b9adf51c45517cca2878732feb5bb4sewardj
50dc1ef03a8d13efe24661a89091e66169bf3f1091bart/** Push a segment at the end of the queue 'p->last_sem_post_seg'. */
5125f9f5411f64046c2ffc0822f727aedc21f07720bartstatic void drd_segment_push(struct semaphore_info* p, Segment* sg)
523e017fa58a7c090cee54809baa4f5be78cb4eef9bart{
53bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   Word n;
543e017fa58a7c090cee54809baa4f5be78cb4eef9bart
55bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(sg);
56bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   n = VG_(addToXA)(p->last_sem_post_seg, &sg);
573e017fa58a7c090cee54809baa4f5be78cb4eef9bart#if 0
589af04c49df08365aa568b3a27ffa5b2a1274a987florian   VG_(message)(Vg_DebugMsg, "0x%lx push: added at position %ld/%ld\n",
59bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                p->a1, n, VG_(sizeXA)(p->last_sem_post_seg));
603e017fa58a7c090cee54809baa4f5be78cb4eef9bart#endif
61bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(*(Segment**)VG_(indexXA)(p->last_sem_post_seg, n) == sg);
623e017fa58a7c090cee54809baa4f5be78cb4eef9bart}
633e017fa58a7c090cee54809baa4f5be78cb4eef9bart
64dc1ef03a8d13efe24661a89091e66169bf3f1091bart/** Pop a segment from the beginning of the queue 'p->last_sem_post_seg'. */
6525f9f5411f64046c2ffc0822f727aedc21f07720bartstatic Segment* drd_segment_pop(struct semaphore_info* p)
663e017fa58a7c090cee54809baa4f5be78cb4eef9bart{
67bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   Word sz;
68bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   Segment* sg;
693e017fa58a7c090cee54809baa4f5be78cb4eef9bart
70bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   sz = VG_(sizeXA)(p->last_sem_post_seg);
713e017fa58a7c090cee54809baa4f5be78cb4eef9bart#if 0
729af04c49df08365aa568b3a27ffa5b2a1274a987florian   VG_(message)(Vg_DebugMsg, "0x%lx pop:  removed from position %ld/%ld\n",
73bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                p->a1, sz - 1, sz);
743e017fa58a7c090cee54809baa4f5be78cb4eef9bart#endif
75bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   sg = 0;
76bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (sz > 0)
77bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
78bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      sg = *(Segment**)VG_(indexXA)(p->last_sem_post_seg, sz - 1);
79bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      tl_assert(sg);
80bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(dropTailXA)(p->last_sem_post_seg, 1);
81bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
82bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   return sg;
833e017fa58a7c090cee54809baa4f5be78cb4eef9bart}
843e017fa58a7c090cee54809baa4f5be78cb4eef9bart
85dc1ef03a8d13efe24661a89091e66169bf3f1091bart/** Enable or disable tracing of semaphore actions. */
86dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(semaphore_set_trace)(const Bool trace_semaphore)
878564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
88bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   s_trace_semaphore = trace_semaphore;
898564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
908564292ac4b9adf51c45517cca2878732feb5bb4sewardj
91dc1ef03a8d13efe24661a89091e66169bf3f1091bart/**
92dc1ef03a8d13efe24661a89091e66169bf3f1091bart * Initialize the memory 'p' points at as a semaphore_info structure for the
93dc1ef03a8d13efe24661a89091e66169bf3f1091bart * client semaphore at client addres 'semaphore'.
94dc1ef03a8d13efe24661a89091e66169bf3f1091bart */
958564292ac4b9adf51c45517cca2878732feb5bb4sewardjstatic
9625f9f5411f64046c2ffc0822f727aedc21f07720bartvoid drd_semaphore_initialize(struct semaphore_info* const p,
9725f9f5411f64046c2ffc0822f727aedc21f07720bart                              const Addr semaphore)
988564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
99bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(semaphore != 0);
100bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(p->a1 == semaphore);
101bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(p->type == ClientSemaphore);
102bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
103bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->cleanup           = (void(*)(DrdClientobj*))semaphore_cleanup;
104bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->delete_thread     = 0;
105bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->waits_to_skip     = 0;
106bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->value             = 0;
107bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->waiters           = 0;
108bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->last_sem_post_tid = DRD_INVALID_THREADID;
109bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->last_sem_post_seg = VG_(newXA)(VG_(malloc), "drd.sg-stack",
110bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                                     VG_(free), sizeof(Segment*));
1118564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
1128564292ac4b9adf51c45517cca2878732feb5bb4sewardj
113195e41fe2b9e02e142a0461113bfa55c89d24c5ebart/**
114195e41fe2b9e02e142a0461113bfa55c89d24c5ebart * Free the memory that was allocated by semaphore_initialize(). Called by
115195e41fe2b9e02e142a0461113bfa55c89d24c5ebart * DRD_(clientobj_remove)().
11628230a3734e045791173aca660efc7d7aeef78cebart */
117d2c5eae561040706a7eb45c0f3988dcd538c8d7ebartstatic void semaphore_cleanup(struct semaphore_info* p)
11828230a3734e045791173aca660efc7d7aeef78cebart{
119bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   Segment* sg;
120bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
121bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p->waiters > 0)
122bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
123d45d99553c15a361bb797d21ec6afb9bad22d2d4bart      SemaphoreErrInfo sei = { DRD_(thread_get_running_tid)(), p->a1 };
124bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
125bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              SemaphoreErr,
126bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(VG_(get_running_tid)()),
127bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "Destruction of semaphore that is being waited"
128bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              " upon",
129bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &sei);
130bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
13125f9f5411f64046c2ffc0822f727aedc21f07720bart   while ((sg = drd_segment_pop(p)))
132bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      DRD_(sg_put)(sg);
133bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   VG_(deleteXA)(p->last_sem_post_seg);
13428230a3734e045791173aca660efc7d7aeef78cebart}
13528230a3734e045791173aca660efc7d7aeef78cebart
136dc1ef03a8d13efe24661a89091e66169bf3f1091bart/**
137dc1ef03a8d13efe24661a89091e66169bf3f1091bart * Return a pointer to the structure with information about the specified
138dc1ef03a8d13efe24661a89091e66169bf3f1091bart * client semaphore. Allocate a new structure if such a structure did not
139dc1ef03a8d13efe24661a89091e66169bf3f1091bart * yet exist.
140dc1ef03a8d13efe24661a89091e66169bf3f1091bart */
1418564292ac4b9adf51c45517cca2878732feb5bb4sewardjstatic
1428564292ac4b9adf51c45517cca2878732feb5bb4sewardjstruct semaphore_info*
14325f9f5411f64046c2ffc0822f727aedc21f07720bartdrd_semaphore_get_or_allocate(const Addr semaphore)
1448564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
145bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct semaphore_info *p;
146bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
147bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(offsetof(DrdClientobj, semaphore) == 0);
148bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p = &(DRD_(clientobj_get)(semaphore, ClientSemaphore)->semaphore);
149bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p == 0)
150bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
151bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      tl_assert(offsetof(DrdClientobj, semaphore) == 0);
152bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      p = &(DRD_(clientobj_add)(semaphore, ClientSemaphore)->semaphore);
15325f9f5411f64046c2ffc0822f727aedc21f07720bart      drd_semaphore_initialize(p, semaphore);
154bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
155bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   return p;
15628230a3734e045791173aca660efc7d7aeef78cebart}
15728230a3734e045791173aca660efc7d7aeef78cebart
158dc1ef03a8d13efe24661a89091e66169bf3f1091bart/**
159dc1ef03a8d13efe24661a89091e66169bf3f1091bart * Return a pointer to the structure with information about the specified
160dc1ef03a8d13efe24661a89091e66169bf3f1091bart * client semaphore, or null if no such structure was found.
161dc1ef03a8d13efe24661a89091e66169bf3f1091bart */
162d45d99553c15a361bb797d21ec6afb9bad22d2d4bartstatic struct semaphore_info* semaphore_get(const Addr semaphore)
16328230a3734e045791173aca660efc7d7aeef78cebart{
164bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(offsetof(DrdClientobj, semaphore) == 0);
165bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   return &(DRD_(clientobj_get)(semaphore, ClientSemaphore)->semaphore);
1668564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
1678564292ac4b9adf51c45517cca2878732feb5bb4sewardj
16828230a3734e045791173aca660efc7d7aeef78cebart/** Called before sem_init(). */
169dc1ef03a8d13efe24661a89091e66169bf3f1091bartstruct semaphore_info* DRD_(semaphore_init)(const Addr semaphore,
170dc1ef03a8d13efe24661a89091e66169bf3f1091bart                                            const Word pshared,
171dc1ef03a8d13efe24661a89091e66169bf3f1091bart                                            const UInt value)
1728564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
173bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct semaphore_info* p;
174bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   Segment* sg;
175bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
176bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (s_trace_semaphore)
177ad994e885caeb5241cbedf4e47e7821cf164f4e7bart      DRD_(trace_msg)("[%d] sem_init      0x%lx value %u",
178b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), semaphore, value);
179b92ff0fd192dd05700f7d20db00795965e20b5c5bart
180d45d99553c15a361bb797d21ec6afb9bad22d2d4bart   p = semaphore_get(semaphore);
181bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p)
182bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
183bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      const ThreadId vg_tid = VG_(get_running_tid)();
184d45d99553c15a361bb797d21ec6afb9bad22d2d4bart      SemaphoreErrInfo SEI = { DRD_(thread_get_running_tid)(), semaphore };
185bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(vg_tid,
186bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              SemaphoreErr,
187bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(vg_tid),
188bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "Semaphore reinitialization",
189bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &SEI);
190bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      // Remove all segments from the segment stack.
19125f9f5411f64046c2ffc0822f727aedc21f07720bart      while ((sg = drd_segment_pop(p)))
192bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      {
193bedfd237fbdc80d0c917cfcb85a94b5561c92633bart         DRD_(sg_put)(sg);
194bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      }
195bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
196bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   else
197bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
198b7037bb42882b1783dbd79823573ad8027ad2978bart#if defined(VGO_darwin)
199b7037bb42882b1783dbd79823573ad8027ad2978bart      const ThreadId vg_tid = VG_(get_running_tid)();
200a9d292ea80e21d5987cab5954771ef02b7890737bart      GenericErrInfo GEI = { DRD_(thread_get_running_tid)(), 0 };
201b7037bb42882b1783dbd79823573ad8027ad2978bart      VG_(maybe_record_error)(vg_tid,
202b7037bb42882b1783dbd79823573ad8027ad2978bart			      GenericErr,
203b7037bb42882b1783dbd79823573ad8027ad2978bart			      VG_(get_IP)(vg_tid),
204b7037bb42882b1783dbd79823573ad8027ad2978bart			      "sem_init() is not yet supported on Darwin",
205b7037bb42882b1783dbd79823573ad8027ad2978bart			      &GEI);
206b7037bb42882b1783dbd79823573ad8027ad2978bart      return NULL;
207b7037bb42882b1783dbd79823573ad8027ad2978bart#else
20825f9f5411f64046c2ffc0822f727aedc21f07720bart      p = drd_semaphore_get_or_allocate(semaphore);
209b7037bb42882b1783dbd79823573ad8027ad2978bart#endif
210bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
211bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(p);
212bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->waits_to_skip = value;
213bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->value         = value;
214bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   return p;
2158564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
2168564292ac4b9adf51c45517cca2878732feb5bb4sewardj
21728230a3734e045791173aca660efc7d7aeef78cebart/** Called after sem_destroy(). */
218dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(semaphore_destroy)(const Addr semaphore)
2198564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
220bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct semaphore_info* p;
221bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
222d45d99553c15a361bb797d21ec6afb9bad22d2d4bart   p = semaphore_get(semaphore);
223bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
224bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (s_trace_semaphore)
225ad994e885caeb5241cbedf4e47e7821cf164f4e7bart      DRD_(trace_msg)("[%d] sem_destroy   0x%lx value %u",
226b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), semaphore,
227b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      p ? p->value : 0);
228bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
229bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p == 0)
230bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
23162cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      GenericErrInfo GEI = {
23262cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 .tid  = DRD_(thread_get_running_tid)(),
23362cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 .addr = semaphore,
23462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      };
235bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
236bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              GenericErr,
237bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(VG_(get_running_tid)()),
238bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "Not a semaphore",
239bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &GEI);
240bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      return;
241bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
242bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
243bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   DRD_(clientobj_remove)(semaphore, ClientSemaphore);
2448564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
2458564292ac4b9adf51c45517cca2878732feb5bb4sewardj
24625f9f5411f64046c2ffc0822f727aedc21f07720bart/** Called after sem_open(). */
24725f9f5411f64046c2ffc0822f727aedc21f07720bartstruct semaphore_info* DRD_(semaphore_open)(const Addr semaphore,
24819f91bbaedb4caef8a60ce94b0f507193cc0bc10florian                                            const HChar* name, const Word oflag,
24925f9f5411f64046c2ffc0822f727aedc21f07720bart                                            const Word mode, const UInt value)
25025f9f5411f64046c2ffc0822f727aedc21f07720bart{
25125f9f5411f64046c2ffc0822f727aedc21f07720bart   struct semaphore_info* p;
25225f9f5411f64046c2ffc0822f727aedc21f07720bart   Segment* sg;
25325f9f5411f64046c2ffc0822f727aedc21f07720bart
25425f9f5411f64046c2ffc0822f727aedc21f07720bart   if (s_trace_semaphore)
255b92ff0fd192dd05700f7d20db00795965e20b5c5bart      DRD_(trace_msg)("[%d] sem_open      0x%lx name %s"
256ad994e885caeb5241cbedf4e47e7821cf164f4e7bart                      " oflag %#lx mode %#lo value %u",
257b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(),
258b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      semaphore, name, oflag, mode, value);
25925f9f5411f64046c2ffc0822f727aedc21f07720bart
26025f9f5411f64046c2ffc0822f727aedc21f07720bart   /* Return if the sem_open() call failed. */
26125f9f5411f64046c2ffc0822f727aedc21f07720bart   if (! semaphore)
26225f9f5411f64046c2ffc0822f727aedc21f07720bart      return NULL;
26325f9f5411f64046c2ffc0822f727aedc21f07720bart
26425f9f5411f64046c2ffc0822f727aedc21f07720bart   p = semaphore_get(semaphore);
26525f9f5411f64046c2ffc0822f727aedc21f07720bart   if (p)
26625f9f5411f64046c2ffc0822f727aedc21f07720bart   {
26725f9f5411f64046c2ffc0822f727aedc21f07720bart      const ThreadId vg_tid = VG_(get_running_tid)();
26825f9f5411f64046c2ffc0822f727aedc21f07720bart      SemaphoreErrInfo SEI = { DRD_(thread_get_running_tid)(), semaphore };
26925f9f5411f64046c2ffc0822f727aedc21f07720bart      VG_(maybe_record_error)(vg_tid,
27025f9f5411f64046c2ffc0822f727aedc21f07720bart                              SemaphoreErr,
27125f9f5411f64046c2ffc0822f727aedc21f07720bart                              VG_(get_IP)(vg_tid),
27225f9f5411f64046c2ffc0822f727aedc21f07720bart                              "Semaphore reinitialization",
27325f9f5411f64046c2ffc0822f727aedc21f07720bart                              &SEI);
27425f9f5411f64046c2ffc0822f727aedc21f07720bart      // Remove all segments from the segment stack.
27525f9f5411f64046c2ffc0822f727aedc21f07720bart      while ((sg = drd_segment_pop(p)))
27625f9f5411f64046c2ffc0822f727aedc21f07720bart      {
27725f9f5411f64046c2ffc0822f727aedc21f07720bart         DRD_(sg_put)(sg);
27825f9f5411f64046c2ffc0822f727aedc21f07720bart      }
27925f9f5411f64046c2ffc0822f727aedc21f07720bart   }
28025f9f5411f64046c2ffc0822f727aedc21f07720bart   else
28125f9f5411f64046c2ffc0822f727aedc21f07720bart   {
28225f9f5411f64046c2ffc0822f727aedc21f07720bart      p = drd_semaphore_get_or_allocate(semaphore);
28325f9f5411f64046c2ffc0822f727aedc21f07720bart   }
28425f9f5411f64046c2ffc0822f727aedc21f07720bart   tl_assert(p);
28525f9f5411f64046c2ffc0822f727aedc21f07720bart   p->waits_to_skip = value;
28625f9f5411f64046c2ffc0822f727aedc21f07720bart   p->value         = value;
28725f9f5411f64046c2ffc0822f727aedc21f07720bart   return p;
28825f9f5411f64046c2ffc0822f727aedc21f07720bart}
28925f9f5411f64046c2ffc0822f727aedc21f07720bart
29025f9f5411f64046c2ffc0822f727aedc21f07720bart/** Called before sem_close(). */
29125f9f5411f64046c2ffc0822f727aedc21f07720bartvoid DRD_(semaphore_close)(const Addr semaphore)
29225f9f5411f64046c2ffc0822f727aedc21f07720bart{
29325f9f5411f64046c2ffc0822f727aedc21f07720bart   struct semaphore_info* p;
29425f9f5411f64046c2ffc0822f727aedc21f07720bart
29525f9f5411f64046c2ffc0822f727aedc21f07720bart   p = semaphore_get(semaphore);
29625f9f5411f64046c2ffc0822f727aedc21f07720bart
29725f9f5411f64046c2ffc0822f727aedc21f07720bart   if (s_trace_semaphore)
298ad994e885caeb5241cbedf4e47e7821cf164f4e7bart      DRD_(trace_msg)("[%d] sem_close     0x%lx value %u",
299b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), semaphore,
300b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      p ? p->value : 0);
30125f9f5411f64046c2ffc0822f727aedc21f07720bart
30225f9f5411f64046c2ffc0822f727aedc21f07720bart   if (p == 0)
30325f9f5411f64046c2ffc0822f727aedc21f07720bart   {
30462cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      GenericErrInfo GEI = {
30562cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 .tid  = DRD_(thread_get_running_tid)(),
30662cc23286aa2d2cbeb6643a15ef37fe020a3d159bart	 .addr = semaphore,
30762cc23286aa2d2cbeb6643a15ef37fe020a3d159bart      };
30825f9f5411f64046c2ffc0822f727aedc21f07720bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
30925f9f5411f64046c2ffc0822f727aedc21f07720bart                              GenericErr,
31025f9f5411f64046c2ffc0822f727aedc21f07720bart                              VG_(get_IP)(VG_(get_running_tid)()),
31125f9f5411f64046c2ffc0822f727aedc21f07720bart                              "Not a semaphore",
31225f9f5411f64046c2ffc0822f727aedc21f07720bart                              &GEI);
31325f9f5411f64046c2ffc0822f727aedc21f07720bart      return;
31425f9f5411f64046c2ffc0822f727aedc21f07720bart   }
31525f9f5411f64046c2ffc0822f727aedc21f07720bart
31625f9f5411f64046c2ffc0822f727aedc21f07720bart   DRD_(clientobj_remove)(semaphore, ClientSemaphore);
31725f9f5411f64046c2ffc0822f727aedc21f07720bart}
31825f9f5411f64046c2ffc0822f727aedc21f07720bart
31928230a3734e045791173aca660efc7d7aeef78cebart/** Called before sem_wait(). */
320dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(semaphore_pre_wait)(const Addr semaphore)
3218564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
322bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct semaphore_info* p;
32328230a3734e045791173aca660efc7d7aeef78cebart
3247a06e12b210e31acaa960be429f086726a67f6ddbart   tl_assert(semaphore < semaphore + 1);
32525f9f5411f64046c2ffc0822f727aedc21f07720bart   p = drd_semaphore_get_or_allocate(semaphore);
326bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(p);
327bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->waiters++;
3283eecd9a3377cb6dd7637ea051ef2167023c93a61bart
3299986c99e20f6f0acd5a3ce547a53a5df4f95f70fbart   if ((Word)(p->waiters) <= 0)
3303eecd9a3377cb6dd7637ea051ef2167023c93a61bart   {
3313eecd9a3377cb6dd7637ea051ef2167023c93a61bart      SemaphoreErrInfo sei = { DRD_(thread_get_running_tid)(), semaphore };
3323eecd9a3377cb6dd7637ea051ef2167023c93a61bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
3333eecd9a3377cb6dd7637ea051ef2167023c93a61bart                              SemaphoreErr,
3343eecd9a3377cb6dd7637ea051ef2167023c93a61bart                              VG_(get_IP)(VG_(get_running_tid)()),
3353eecd9a3377cb6dd7637ea051ef2167023c93a61bart                              "Invalid semaphore",
3363eecd9a3377cb6dd7637ea051ef2167023c93a61bart                              &sei);
3373eecd9a3377cb6dd7637ea051ef2167023c93a61bart   }
3388564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
3398564292ac4b9adf51c45517cca2878732feb5bb4sewardj
340dc1ef03a8d13efe24661a89091e66169bf3f1091bart/**
341dc1ef03a8d13efe24661a89091e66169bf3f1091bart * Called after sem_wait() finished.
342333e42bd5e2617c804d336ad6009b0ad13960d46bart * @note Some C libraries do not set the 'waited' value correctly.
34328230a3734e045791173aca660efc7d7aeef78cebart */
344dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore,
345dc1ef03a8d13efe24661a89091e66169bf3f1091bart                               const Bool waited)
3468564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
347bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct semaphore_info* p;
348bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   Segment* sg;
349bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
350311abd6254c497dcbb2c1ef09d94593fb5524369bart   tl_assert(waited == 0 || waited == 1);
351d45d99553c15a361bb797d21ec6afb9bad22d2d4bart   p = semaphore_get(semaphore);
352bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (s_trace_semaphore)
353311abd6254c497dcbb2c1ef09d94593fb5524369bart      DRD_(trace_msg)("[%d] sem_wait      0x%lx value %u -> %u%s",
354b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(), semaphore,
355311abd6254c497dcbb2c1ef09d94593fb5524369bart                      p ? p->value : 0, p ? p->value - waited : 0,
356311abd6254c497dcbb2c1ef09d94593fb5524369bart		      waited ? "" : " (did not wait)");
35757ae7ad7e5b468d976ef43001f603bdbc842c53ebart
358333e42bd5e2617c804d336ad6009b0ad13960d46bart   if (p) {
35957ae7ad7e5b468d976ef43001f603bdbc842c53ebart      p->waiters--;
360311abd6254c497dcbb2c1ef09d94593fb5524369bart      p->value -= waited;
36157ae7ad7e5b468d976ef43001f603bdbc842c53ebart   }
36257ae7ad7e5b468d976ef43001f603bdbc842c53ebart
36357ae7ad7e5b468d976ef43001f603bdbc842c53ebart   /*
36457ae7ad7e5b468d976ef43001f603bdbc842c53ebart    * Note: if another thread destroyed and reinitialized a semaphore while
36557ae7ad7e5b468d976ef43001f603bdbc842c53ebart    * the current thread was waiting in sem_wait, p->waiters may have been
36625f9f5411f64046c2ffc0822f727aedc21f07720bart    * set to zero by drd_semaphore_initialize() after
36757ae7ad7e5b468d976ef43001f603bdbc842c53ebart    * DRD_(semaphore_pre_wait)() has finished before
36857ae7ad7e5b468d976ef43001f603bdbc842c53ebart    * DRD_(semaphore_post_wait)() has been called.
36957ae7ad7e5b468d976ef43001f603bdbc842c53ebart    */
3709986c99e20f6f0acd5a3ce547a53a5df4f95f70fbart   if (p == NULL || (Int)(p->value) < 0 || (Word)(p->waiters) < 0)
371bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
372d45d99553c15a361bb797d21ec6afb9bad22d2d4bart      SemaphoreErrInfo sei = { DRD_(thread_get_running_tid)(), semaphore };
373bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      VG_(maybe_record_error)(VG_(get_running_tid)(),
374bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              SemaphoreErr,
375bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              VG_(get_IP)(VG_(get_running_tid)()),
376bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              "Invalid semaphore",
377bedfd237fbdc80d0c917cfcb85a94b5561c92633bart                              &sei);
378bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      return;
379bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
38057ae7ad7e5b468d976ef43001f603bdbc842c53ebart
381333e42bd5e2617c804d336ad6009b0ad13960d46bart   if (!waited)
382333e42bd5e2617c804d336ad6009b0ad13960d46bart      return;
383333e42bd5e2617c804d336ad6009b0ad13960d46bart
384bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (p->waits_to_skip > 0)
385bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      p->waits_to_skip--;
386bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   else
387bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   {
38825f9f5411f64046c2ffc0822f727aedc21f07720bart      sg = drd_segment_pop(p);
389bedfd237fbdc80d0c917cfcb85a94b5561c92633bart      tl_assert(sg);
3907a2cc3c5be225eb49813c1460d861481ee490d6ebart      if (p->last_sem_post_tid != tid
3917a2cc3c5be225eb49813c1460d861481ee490d6ebart          && p->last_sem_post_tid != DRD_INVALID_THREADID)
39294866ccb7b8476762d57ab41c61e59c1189a0107bart      {
3937a2cc3c5be225eb49813c1460d861481ee490d6ebart         DRD_(thread_new_segment_and_combine_vc)(tid, sg);
39494866ccb7b8476762d57ab41c61e59c1189a0107bart      }
3957a2cc3c5be225eb49813c1460d861481ee490d6ebart      else
3967a2cc3c5be225eb49813c1460d861481ee490d6ebart         DRD_(thread_new_segment)(tid);
3977a2cc3c5be225eb49813c1460d861481ee490d6ebart      s_semaphore_segment_creation_count++;
3987a2cc3c5be225eb49813c1460d861481ee490d6ebart      DRD_(sg_put)(sg);
399bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   }
4008564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
4018564292ac4b9adf51c45517cca2878732feb5bb4sewardj
4028564292ac4b9adf51c45517cca2878732feb5bb4sewardj/** Called before sem_post(). */
403dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore)
4048564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
405bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   struct semaphore_info* p;
406bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   Segment* sg;
407bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
40825f9f5411f64046c2ffc0822f727aedc21f07720bart   p = drd_semaphore_get_or_allocate(semaphore);
409bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->value++;
410bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
411bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   if (s_trace_semaphore)
412ad994e885caeb5241cbedf4e47e7821cf164f4e7bart      DRD_(trace_msg)("[%d] sem_post      0x%lx value %u -> %u",
413b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      DRD_(thread_get_running_tid)(),
414b92ff0fd192dd05700f7d20db00795965e20b5c5bart                      semaphore, p->value - 1, p->value);
415bedfd237fbdc80d0c917cfcb85a94b5561c92633bart
416bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   p->last_sem_post_tid = tid;
417bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   sg = 0;
418bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   DRD_(thread_get_latest_segment)(&sg, tid);
419bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   tl_assert(sg);
42025f9f5411f64046c2ffc0822f727aedc21f07720bart   drd_segment_push(p, sg);
421c02dde4a6856703692de465fa621d20c9ec65ca4bart   DRD_(thread_new_segment)(tid);
422bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   s_semaphore_segment_creation_count++;
4238564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
4248564292ac4b9adf51c45517cca2878732feb5bb4sewardj
425d45d99553c15a361bb797d21ec6afb9bad22d2d4bart/** Called after sem_post() finished. */
426dc1ef03a8d13efe24661a89091e66169bf3f1091bartvoid DRD_(semaphore_post_post)(const DrdThreadId tid, const Addr semaphore,
427d45d99553c15a361bb797d21ec6afb9bad22d2d4bart                               const Bool succeeded)
4288564292ac4b9adf51c45517cca2878732feb5bb4sewardj{
429d45d99553c15a361bb797d21ec6afb9bad22d2d4bart   /*
43031b983d29affe6c30a2283be8824c6d75c74d848bart    * Note: it is hard to implement the sem_post() wrapper correctly in
43131b983d29affe6c30a2283be8824c6d75c74d848bart    * case sem_post() returns an error code. This is because handling this
43231b983d29affe6c30a2283be8824c6d75c74d848bart    * case correctly requires restoring the vector clock associated with
433d45d99553c15a361bb797d21ec6afb9bad22d2d4bart    * the semaphore to its original value here. In order to do that without
43431b983d29affe6c30a2283be8824c6d75c74d848bart    * introducing a race condition, extra locking has to be added around
43531b983d29affe6c30a2283be8824c6d75c74d848bart    * each semaphore call. Such extra locking would have to be added in
436d45d99553c15a361bb797d21ec6afb9bad22d2d4bart    * drd_pthread_intercepts.c. However, it is hard to implement
437d45d99553c15a361bb797d21ec6afb9bad22d2d4bart    * synchronization in drd_pthread_intercepts.c in a portable way without
438d45d99553c15a361bb797d21ec6afb9bad22d2d4bart    * calling already redirected functions.
439d45d99553c15a361bb797d21ec6afb9bad22d2d4bart    */
4408564292ac4b9adf51c45517cca2878732feb5bb4sewardj}
4418564292ac4b9adf51c45517cca2878732feb5bb4sewardj
442dc1ef03a8d13efe24661a89091e66169bf3f1091bartULong DRD_(get_semaphore_segment_creation_count)(void)
4436bbefaf8418f3e225c4eefcc726b6874bef15d8cbart{
444bedfd237fbdc80d0c917cfcb85a94b5561c92633bart   return s_semaphore_segment_creation_count;
4456bbefaf8418f3e225c4eefcc726b6874bef15d8cbart}
446