_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST, /* pth_cond_t* */
_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,/* pth_cond_t* */
_VG_USERREQ__HG_RTLD_BIND_GUARD, /* int flags */
- _VG_USERREQ__HG_RTLD_BIND_CLEAR /* int flags */
+ _VG_USERREQ__HG_RTLD_BIND_CLEAR, /* int flags */
+ _VG_USERREQ__HG_GNAT_DEPENDENT_MASTER_JOIN /* void*d, void*m */
} Vg_TCheckClientRequest;
_res; \
}))
+/* End-user request for Ada applications compiled with GNAT.
+ Helgrind understands the Ada concept of Ada task dependencies and
+ terminations. See Ada Reference Manual section 9.3 "Task Dependence
+ - Termination of Tasks".
+ However, in some cases, the master of (terminated) tasks completes
+ only when the application exits. An example of this is dynamically
+ allocated tasks with an access type defined at Library Level.
+ By default, the state of such tasks in Helgrind will be 'exited but
+ join not done yet'. Many tasks in such a state are however causing
+ Helgrind CPU and memory to increase significantly.
+ VALGRIND_HG_GNAT_DEPENDENT_MASTER_JOIN can be used to indicate
+ to Helgrind that a not yet completed master has however already
+ 'seen' the termination of a dependent : this is conceptually the
+ same as a pthread_join and causes the cleanup of the dependent
+ as done by Helgrind when a master completes.
+ This allows to avoid the overhead in helgrind caused by such tasks.
+ A typical usage for a master to indicate it has done conceptually a join
+ with a dependent task before the master completes is:
+ while not Dep_Task'Terminated loop
+ ... do whatever to wait for Dep_Task termination.
+ end loop;
+ VALGRIND_HG_GNAT_DEPENDENT_MASTER_JOIN
+ (Dep_Task'Identity,
+ Ada.Task_Identification.Current_Task);
+ Note that VALGRIND_HG_GNAT_DEPENDENT_MASTER_JOIN should be a binding
+ to a C function built with the below macro. */
+#define VALGRIND_HG_GNAT_DEPENDENT_MASTER_JOIN(_qzz_dep, _qzz_master) \
+ DO_CREQ_v_WW(_VG_USERREQ__HG_GNAT_DEPENDENT_MASTER_JOIN, \
+ void*,(_qzz_dep), \
+ void*,(_qzz_master))
+
/*----------------------------------------------------------------*/
/*--- ---*/
/*--- ThreadSanitizer-compatible requests ---*/
Word master_level; // level of dependency between master and dependent
Thread* hg_dependent; // helgrind Thread* for dependent task.
}
- GNAT_dmml;
+ GNAT_dmml; // (d)ependent (m)aster (m)aster_(l)evel.
static XArray* gnat_dmmls; /* of GNAT_dmml */
static void gnat_dmmls_INIT (void)
{
*ret = -1;
break;
+ /* This thread (tid) (a master) is informing us that it has
+ seen the termination of a dependent task, and that this should
+ be considered as a join between master and dependent. */
+ case _VG_USERREQ__HG_GNAT_DEPENDENT_MASTER_JOIN: {
+ Word n;
+ const Thread *stayer = map_threads_maybe_lookup( tid );
+ const void *dependent = (void*)args[1];
+ const void *master = (void*)args[2];
+
+ if (0)
+ VG_(printf)("HG_GNAT_DEPENDENT_MASTER_JOIN (tid %d): "
+ "self_id = %p Thread* = %p dependent %p\n",
+ (Int)tid, master, stayer, dependent);
+
+ gnat_dmmls_INIT();
+ /* Similar loop as for master completed hook below, but stops at
+ the first matching occurence, only comparing master and
+ dependent. */
+ for (n = VG_(sizeXA) (gnat_dmmls) - 1; n >= 0; n--) {
+ GNAT_dmml *dmml = (GNAT_dmml*) VG_(indexXA)(gnat_dmmls, n);
+ if (dmml->master == master
+ && dmml->dependent == dependent) {
+ if (0)
+ VG_(printf)("quitter %p dependency to stayer %p (join)\n",
+ dmml->hg_dependent->hbthr, stayer->hbthr);
+ tl_assert(dmml->hg_dependent->hbthr != stayer->hbthr);
+ generate_quitter_stayer_dependence (dmml->hg_dependent->hbthr,
+ stayer->hbthr);
+ VG_(removeIndexXA) (gnat_dmmls, n);
+ break;
+ }
+ }
+ break;
+ }
+
/* --- --- Client requests for Helgrind's use only --- --- */
/* Some thread is telling us its pthread_t value. Record the