<commit_before>// -*-Mode: C++;-*- // technically C99

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// --------------------------------------------------------------------------
// Part of HPCToolkit (hpctoolkit.org)
//
// Information about sources of support for research and development of
// HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
// --------------------------------------------------------------------------
//
// Copyright ((c)) 2002-2018, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

/*
 * Maintain a map from address Intervals to unwind intervals.
 *
 * Note: the caller need not acquire/release locks as part
 * of using the map.
 *
 * $Id$
 */

//---------------------------------------------------------------------
// debugging support
//---------------------------------------------------------------------

#define UW_RECIPE_MAP_DEBUG 0

#define UW_RECIPE_MAP_DEBUG_VERBOSE 0

#if UW_RECIPE_MAP_DEBUG_VERBOSE
#undef UW_RECIPE_MAP_DEBUG
#define UW_RECIPE_MAP_DEBUG 1
#endif


#if UW_RECIPE_MAP_DEBUG
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#endif



//---------------------------------------------------------------------
// local include files
//---------------------------------------------------------------------
#include <memory/hpcrun-malloc.h>
#include <main.h>
#include "uw_recipe_map.h"
#include "unwind-interval.h"
#include <fnbounds/fnbounds_interface.h>
#include <lib/prof-lean/cskiplist.h>
#include <lib/prof-lean/mcs-lock.h>
#include <lib/prof-lean/binarytree.h>
#include "binarytree_uwi.h"
#include "segv_handler.h"
#include <messages/messages.h>

// libmonitor functions
#include <monitor.h>

//******************************************************************************
// global include files
//******************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//---------------------------------------------------------------------
// macros
//---------------------------------------------------------------------

#define SKIPLIST_HEIGHT 8

#define NUM_NODES 10

//******************************************************************************
// type
//******************************************************************************

typedef struct ilmstat_btuwi_pair_s {
  interval_t interval;
  load_module_t *lm;
  _Atomic(tree_stat_t) stat;
  bitree_uwi_t *btuwi;
} ilmstat_btuwi_pair_t;

//******************************************************************************
// Comparators
//******************************************************************************

/*
 * pre-condition: lhs, rhs are ilmstat_btuwi_pair_t*
 */
static int
ilmstat_btuwi_pair_cmp(void *lhs, void *rhs)
{
  ilmstat_btuwi_pair_t *l = (ilmstat_btuwi_pair_t*)lhs;
  ilmstat_btuwi_pair_t *r = (ilmstat_btuwi_pair_t*)rhs;
  return interval_t_cmp(
	 &l->interval,
	 &r->interval);
}

/*
 * pre-condition: itp is a ilmstat_btuwi_pair_t*, address is a uintptr_t
 * return interval_ldmod_pair_inrange(itp->first, address)
 */
static int
ilmstat_btuwi_pair_inrange(void *itp, void *address)
{
  ilmstat_btuwi_pair_t *p = (ilmstat_btuwi_pair_t*)itp;
  return interval_t_inrange(&p->interval, address);
}

static ilmstat_btuwi_pair_t *GF_ilmstat_btuwi = NULL; // global free list of ilmstat_btuwi_pair_t*
static mcs_lock_t GFL_lock;  // lock for GF_ilmstat_btuwi
static __thread  ilmstat_btuwi_pair_t *_lf_ilmstat_btuwi = NULL;  // thread local free list of ilmstat_btuwi_pair_t*
// for storing the current btuwi in case of segv
static  __thread  ilmstat_btuwi_pair_t *current_btuwi = NULL;

//******************************************************************************
// Constructors
//******************************************************************************

static inline ilmstat_btuwi_pair_t *
ilmstat__btuwi_pair_init(ilmstat_btuwi_pair_t *node,
			 tree_stat_t treestat,
			 load_module_t *lm,
			 uintptr_t start,
			 uintptr_t end)
{
  atomic_store_explicit(&node->stat, treestat, memory_order_relaxed);
  node->lm = lm;
  node->interval.start = start;
  node->interval.end = end;
  node->btuwi = NULL;
  return node;
}

static inline ilmstat_btuwi_pair_t*
ilmstat_btuwi_pair_build(uintptr_t start, uintptr_t end, load_module_t *lm,
	tree_stat_t treestat, mem_alloc m_alloc)
{
  ilmstat_btuwi_pair_t* node = m_alloc(sizeof(*node));
  return ilmstat__btuwi_pair_init(node, treestat, lm, start, end);
}

static inline void
push_free_pair(ilmstat_btuwi_pair_t **list, ilmstat_btuwi_pair_t *pair)
{
  pair->btuwi = (bitree_uwi_t *)*list;
  *list = pair;
}

static inline ilmstat_btuwi_pair_t *
pop_free_pair(ilmstat_btuwi_pair_t **list)
{
  ilmstat_btuwi_pair_t *head = *list;
  *list = (ilmstat_btuwi_pair_t *)head->btuwi;
  return head;
}

static ilmstat_btuwi_pair_t*
ilmstat_btuwi_pair_malloc(
	uintptr_t start,
	uintptr_t end,
	load_module_t *lm,
	tree_stat_t treestat,
	mem_alloc m_alloc)
{
  if (!_lf_ilmstat_btuwi) {
    /*
     * Look for nodes in the global free list.
     * If the global free list is not empty,
     *   transfer a bunch of nodes to the local free list,
     * otherwise add a bunch of nodes to the local free list.
     */
    mcs_node_t me;
    bool acquired = mcs_trylock(&GFL_lock, &me);
    if (acquired) {
      if (GF_ilmstat_btuwi) {
	// transfer a bunch of nodes the global free list to the local free list
	int n = 0;
	while (GF_ilmstat_btuwi && n < NUM_NODES) {
	  ilmstat_btuwi_pair_t *head = pop_free_pair(&GF_ilmstat_btuwi);
	  push_free_pair(&_lf_ilmstat_btuwi, head);
	  n++;
	}
      }
      mcs_unlock(&GFL_lock, &me);
    }
    if (!_lf_ilmstat_btuwi) {
      /* add a bunch of nodes to _lf_ilmstat_btuwi */
      for (int i = 0; i < NUM_NODES; i++) {
	ilmstat_btuwi_pair_t *node = m_alloc(sizeof(*node));
	push_free_pair(&_lf_ilmstat_btuwi, node);
      }
    }
  }

#if UW_RECIPE_MAP_DEBUG
  assert (_lf_ilmstat_btuwi);
#endif

/*
 * remove the head node of the local free list
 * set its fields using the appropriate parameters
 * return the head node.
 */
  ilmstat_btuwi_pair_t *ans = pop_free_pair(&_lf_ilmstat_btuwi);
  return ilmstat__btuwi_pair_init(ans, treestat, lm, start, end);
}

//******************************************************************************
// Destructor
//******************************************************************************

static void
ilmstat_btuwi_pair_free(ilmstat_btuwi_pair_t* pair)
{
  if (!pair) return;
  bitree_uwi_free(0, pair->btuwi);

  // add pair to the front of the  global free list of ilmstat_btuwi_pair_t*:
  mcs_node_t me;
  mcs_lock(&GFL_lock, &me);
  push_free_pair(&GF_ilmstat_btuwi, pair);
  mcs_unlock(&GFL_lock, &me);
}

//---------------------------------------------------------------------
// local data
//---------------------------------------------------------------------

// The concrete representation of the abstract data type unwind recipe map.
static cskiplist_t *addr2recipe_map[NUM_UNWINDERS];

// memory allocator for creating addr2recipe_map
// and inserting entries into addr2recipe_map:
static mem_alloc my_alloc = hpcrun_malloc;

//******************************************************************************
// String output
//******************************************************************************


#define MAX_STAT_STR 14
#define LDMOD_NAME_LEN 128
#define MAX_ILDMODSTAT_STR MAX_INTERVAL_STR+LDMOD_NAME_LEN+MAX_STAT_STR

static void
load_module_tostr(void* lm, char str[])
{
  load_module_t* ldmod = (load_module_t*)lm;
  if (ldmod) {
	snprintf(str, LDMOD_NAME_LEN, "%s%s%d", ldmod->name, " ", ldmod->id);
  }
  else {
	snprintf(str, LDMOD_NAME_LEN, "%s", "nil");
  }
}

static void
treestat_tostr(tree_stat_t stat, char str[])
{
  switch (stat) {
  case NEVER: strcpy(str, "      NEVER"); break;
  case DEFERRED: strcpy(str, "   DEFERRED"); break;
  case FORTHCOMING: strcpy(str, "FORTHCOMING"); break;
  case READY: strcpy(str, "      READY"); break;
  default: strcpy(str, "STAT_ERROR");
  }
}

static void
ildmod_stat_tostr(void* ilms, char str[])
{
  ilmstat_btuwi_pair_t *pair = ilms;
  char intervalstr[MAX_INTERVAL_STR];
  interval_t_tostr(&pair->interval, intervalstr);
  char ldmodstr[LDMOD_NAME_LEN];
  load_module_tostr(pair->lm, ldmodstr);
  char statstr[MAX_STAT_STR];
  treestat_tostr(atomic_load_explicit(&pair->stat, memory_order_relaxed), statstr);
  sprintf(str, "(%s %s %s)", intervalstr, ldmodstr, statstr);
}

/*
 * Compute the string representation of ilmstat_btuwi_pair_t with appropriate
 * indentation of the second component which is a binary tree.
 * Return the result in the parameter str.
 */
static void
ilmstat_btuwi_pair_tostr_indent(void* itp, char* indents, char str[])
{
  ilmstat_btuwi_pair_t* it_pair = (ilmstat_btuwi_pair_t*)itp;
  bitree_uwi_t *tree = it_pair->btuwi;
  char firststr[MAX_ILDMODSTAT_STR];
  char secondstr[MAX_TREE_STR];
  ildmod_stat_tostr(it_pair, firststr);
  bitree_uwi_tostring_indent(tree, indents, secondstr);
  snprintf(str, strlen(firststr) + strlen(secondstr) + 6, "%s%s%s%s%s",
	  "(", firststr, ",  ", secondstr, ")");
}

static int
max_ilmstat_btuwi_pair_len()
{
  return MAX_ILDMODSTAT_STR + MAX_TREE_STR + 4;
}


static char
ILdMod_Stat_MaxSpaces[] = "                                                                              ";

/*
 * the max spaces occupied by "([start_address ... end_address), load module xx, status)
 */
static char*
ildmod_stat_maxspaces()
{
  return ILdMod_Stat_MaxSpaces;
}

//---------------------------------------------------------------------
// private operations
//---------------------------------------------------------------------

#if UW_RECIPE_MAP_DEBUG
static void
uw_recipe_map_report(const char *op, void *start, void *end)
{
  fprintf(stderr, "%s [start=%p, end=%p)\n", op, start, end);
}
#else
#define uw_recipe_map_report(op, start, end)
#endif

static void
uw_recipe_map_poison(uintptr_t start, uintptr_t end, unwinder_t uw)
{
  uw_recipe_map_report("uw_recipe_map_poison", (void *) start, (void *) end);

  ilmstat_btuwi_pair_t* itpair =
	  ilmstat_btuwi_pair_build(start, end, NULL, NEVER, my_alloc);
  csklnode_t *node = cskl_insert(addr2recipe_map[uw], itpair, my_alloc);
  if (itpair != (ilmstat_btuwi_pair_t*)node->val)
    ilmstat_btuwi_pair_free(itpair);
}


/*
 * if the given address, value, is in the range of a node in the cskiplist,
 * return that node, otherwise return NULL.
 */
static ilmstat_btuwi_pair_t*
uw_recipe_map_inrange_find(uintptr_t addr, unwinder_t uw)
{
  return (ilmstat_btuwi_pair_t*)cskl_inrange_find(addr2recipe_map[uw], (void*)addr);
}

static void
cskl_ilmstat_btuwi_free(void *anode)
{
#if CSKL_ILS_BTU
//  printf("DXN_DBG cskl_ilmstat_btuwi_free(%p)...\n", anode);
#endif

  csklnode_t *node = (csklnode_t*) anode;
  ilmstat_btuwi_pair_t *ilmstat_btuwi = (ilmstat_btuwi_pair_t*)node->val;
  ilmstat_btuwi_pair_free(ilmstat_btuwi);
  node->val = NULL;
  cskl_free(node);
}

static bool
uw_recipe_map_cmp_del_bulk_unsynch(
	const interval_t *ival, unwinder_t uw)
{
  return cskl_cmp_del_bulk_unsynch(addr2recipe_map[uw], ival->start, ival->end,
				   cskl_ilmstat_btuwi_free);
}

static void
uw_recipe_map_unpoison(uintptr_t start, uintptr_t end, unwinder_t uw)
{
  ilmstat_btuwi_pair_t* ilmstat_btuwi =	uw_recipe_map_inrange_find(start, uw);
  if (ilmstat_btuwi == NULL)
    return;

  uw_recipe_map_report("uw_recipe_map_unpoison", (void *) start, (void *) end);

#if UW_RECIPE_MAP_DEBUG
  assert(ilmstat_btuwi != NULL); // start should be in range of some poisoned interval
  assert(atomic_load_explicit(&ilmstat_btuwi->stat, memory_order_relaxed) == NEVER);  // should be a poisoned node
#endif

  uintptr_t s0 = ilmstat_btuwi->interval.start;
  uintptr_t e0 = ilmstat_btuwi->interval.end;
  uw_recipe_map_cmp_del_bulk_unsynch(&ilmstat_btuwi->interval, uw);
  uw_recipe_map_poison(s0, start, uw);
  uw_recipe_map_poison(end, e0, uw);
}


static void
uw_recipe_map_repoison(uintptr_t start, uintptr_t end, unwinder_t uw)
{
  if (start > 1) {
    ilmstat_btuwi_pair_t* ileft = uw_recipe_map_inrange_find(start - 1, uw);
    if (ileft) { 
      if ((ileft->interval.end == start) &&
          (NEVER == atomic_load_explicit(&ileft->stat, memory_order_acquire))) {
        // poisoned interval adjacent on the left
        uw_recipe_map_cmp_del_bulk_unsynch(&ileft->interval, uw);
        start = ileft->interval.start;
      }
    }
  }
  if (end < UINTPTR_MAX - 1) {
    ilmstat_btuwi_pair_t* iright = uw_recipe_map_inrange_find(end+1, uw);
    if (iright) { 
      if ((iright->interval.start == end) &&
          (NEVER == atomic_load_explicit(&iright->stat, memory_order_acquire))) {
        // poisoned interval adjacent on the right
        uw_recipe_map_cmp_del_bulk_unsynch(&iright->interval, uw);
        end = iright->interval.end;
      }
    }
  }
  uw_recipe_map_poison(start, end, uw);
}
<commit_msg>Revert previous change.<commit_after>// -*-Mode: C++;-*- // technically C99

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// --------------------------------------------------------------------------
// Part of HPCToolkit (hpctoolkit.org)
//
// Information about sources of support for research and development of
// HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
// --------------------------------------------------------------------------
//
// Copyright ((c)) 2002-2018, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

/*
 * Maintain a map from address Intervals to unwind intervals.
 *
 * Note: the caller need not acquire/release locks as part
 * of using the map.
 *
 * $Id$
 */

//---------------------------------------------------------------------
// debugging support
//---------------------------------------------------------------------

#define UW_RECIPE_MAP_DEBUG 0

#define UW_RECIPE_MAP_DEBUG_VERBOSE 0

#if UW_RECIPE_MAP_DEBUG_VERBOSE
#undef UW_RECIPE_MAP_DEBUG
#define UW_RECIPE_MAP_DEBUG 1
#endif


#if UW_RECIPE_MAP_DEBUG
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#endif



//---------------------------------------------------------------------
// local include files
//---------------------------------------------------------------------
#include <memory/hpcrun-malloc.h>
#include <main.h>
#include "uw_recipe_map.h"
#include "unwind-interval.h"
#include <fnbounds/fnbounds_interface.h>
#include <lib/prof-lean/cskiplist.h>
#include <lib/prof-lean/mcs-lock.h>
#include <lib/prof-lean/binarytree.h>
#include "binarytree_uwi.h"
#include "segv_handler.h"
#include <messages/messages.h>

// libmonitor functions
#include <monitor.h>

//******************************************************************************
// global include files
//******************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//---------------------------------------------------------------------
// macros
//---------------------------------------------------------------------

#define SKIPLIST_HEIGHT 8

#define NUM_NODES 10

//******************************************************************************
// type
//******************************************************************************

typedef struct ilmstat_btuwi_pair_s {
  interval_t interval;
  load_module_t *lm;
  _Atomic(tree_stat_t) stat;
  bitree_uwi_t *btuwi;
} ilmstat_btuwi_pair_t;

//******************************************************************************
// Comparators
//******************************************************************************

/*
 * pre-condition: lhs, rhs are ilmstat_btuwi_pair_t*
 */
static int
ilmstat_btuwi_pair_cmp(void *lhs, void *rhs)
{
  ilmstat_btuwi_pair_t *l = (ilmstat_btuwi_pair_t*)lhs;
  ilmstat_btuwi_pair_t *r = (ilmstat_btuwi_pair_t*)rhs;
  return interval_t_cmp(
	 &l->interval,
	 &r->interval);
}

/*
 * pre-condition: itp is a ilmstat_btuwi_pair_t*, address is a uintptr_t
 * return interval_ldmod_pair_inrange(itp->first, address)
 */
static int
ilmstat_btuwi_pair_inrange(void *itp, void *address)
{
  ilmstat_btuwi_pair_t *p = (ilmstat_btuwi_pair_t*)itp;
  return interval_t_inrange(&p->interval, address);
}

static ilmstat_btuwi_pair_t *GF_ilmstat_btuwi = NULL; // global free list of ilmstat_btuwi_pair_t*
static mcs_lock_t GFL_lock;  // lock for GF_ilmstat_btuwi
static __thread  ilmstat_btuwi_pair_t *_lf_ilmstat_btuwi = NULL;  // thread local free list of ilmstat_btuwi_pair_t*
// for storing the current btuwi in case of segv
static  __thread  ilmstat_btuwi_pair_t *current_btuwi = NULL;

//******************************************************************************
// Constructors
//******************************************************************************

static inline ilmstat_btuwi_pair_t *
ilmstat__btuwi_pair_init(ilmstat_btuwi_pair_t *node,
			 tree_stat_t treestat,
			 load_module_t *lm,
			 uintptr_t start,
			 uintptr_t end)
{
  atomic_store_explicit(&node->stat, treestat, memory_order_relaxed);
  node->lm = lm;
  node->interval.start = start;
  node->interval.end = end;
  node->btuwi = NULL;
  return node;
}

static inline ilmstat_btuwi_pair_t*
ilmstat_btuwi_pair_build(uintptr_t start, uintptr_t end, load_module_t *lm,
	tree_stat_t treestat, mem_alloc m_alloc)
{
  ilmstat_btuwi_pair_t* node = m_alloc(sizeof(*node));
  return ilmstat__btuwi_pair_init(node, treestat, lm, start, end);
}

static inline void
push_free_pair(ilmstat_btuwi_pair_t **list, ilmstat_btuwi_pair_t *pair)
{
  pair->btuwi = (bitree_uwi_t *)*list;
  *list = pair;
}

static inline ilmstat_btuwi_pair_t *
pop_free_pair(ilmstat_btuwi_pair_t **list)
{
  ilmstat_btuwi_pair_t *head = *list;
  *list = (ilmstat_btuwi_pair_t *)head->btuwi;
  return head;
}

static ilmstat_btuwi_pair_t*
ilmstat_btuwi_pair_malloc(
	uintptr_t start,
	uintptr_t end,
	load_module_t *lm,
	tree_stat_t treestat,
	mem_alloc m_alloc)
{
  if (!_lf_ilmstat_btuwi) {
    /*
     * Look for nodes in the global free list.
     * If the global free list is not empty,
     *   transfer a bunch of nodes to the local free list,
     * otherwise add a bunch of nodes to the local free list.
     */
    mcs_node_t me;
    bool acquired = mcs_trylock(&GFL_lock, &me);
    if (acquired) {
      if (GF_ilmstat_btuwi) {
	// transfer a bunch of nodes the global free list to the local free list
	int n = 0;
	while (GF_ilmstat_btuwi && n < NUM_NODES) {
	  ilmstat_btuwi_pair_t *head = pop_free_pair(&GF_ilmstat_btuwi);
	  push_free_pair(&_lf_ilmstat_btuwi, head);
	  n++;
	}
      }
      mcs_unlock(&GFL_lock, &me);
    }
    if (!_lf_ilmstat_btuwi) {
      /* add a bunch of nodes to _lf_ilmstat_btuwi */
      for (int i = 0; i < NUM_NODES; i++) {
	ilmstat_btuwi_pair_t *node = m_alloc(sizeof(*node));
	push_free_pair(&_lf_ilmstat_btuwi, node);
      }
    }
  }

#if UW_RECIPE_MAP_DEBUG
  assert (_lf_ilmstat_btuwi);
#endif

/*
 * remove the head node of the local free list
 * set its fields using the appropriate parameters
 * return the head node.
 */
  ilmstat_btuwi_pair_t *ans = pop_free_pair(&_lf_ilmstat_btuwi);
  return ilmstat__btuwi_pair_init(ans, treestat, lm, start, end);
}

//******************************************************************************
// Destructor
//******************************************************************************

static void
ilmstat_btuwi_pair_free(ilmstat_btuwi_pair_t* pair)
{
  if (!pair) return;
  bitree_uwi_free(0, pair->btuwi);

  // add pair to the front of the  global free list of ilmstat_btuwi_pair_t*:
  mcs_node_t me;
  mcs_lock(&GFL_lock, &me);
  push_free_pair(&GF_ilmstat_btuwi, pair);
  mcs_unlock(&GFL_lock, &me);
}

//---------------------------------------------------------------------
// local data
//---------------------------------------------------------------------

// The concrete representation of the abstract data type unwind recipe map.
static cskiplist_t *addr2recipe_map[NUM_UNWINDERS];

// memory allocator for creating addr2recipe_map
// and inserting entries into addr2recipe_map:
static mem_alloc my_alloc = hpcrun_malloc;

//******************************************************************************
// String output
//******************************************************************************


#define MAX_STAT_STR 14
#define LDMOD_NAME_LEN 128
#define MAX_ILDMODSTAT_STR MAX_INTERVAL_STR+LDMOD_NAME_LEN+MAX_STAT_STR

static void
load_module_tostr(void* lm, char str[])
{
  load_module_t* ldmod = (load_module_t*)lm;
  if (ldmod) {
	snprintf(str, LDMOD_NAME_LEN, "%s%s%d", ldmod->name, " ", ldmod->id);
  }
  else {
	snprintf(str, LDMOD_NAME_LEN, "%s", "nil");
  }
}

static void
treestat_tostr(tree_stat_t stat, char str[])
{
  switch (stat) {
  case NEVER: strcpy(str, "      NEVER"); break;
  case DEFERRED: strcpy(str, "   DEFERRED"); break;
  case FORTHCOMING: strcpy(str, "FORTHCOMING"); break;
  case READY: strcpy(str, "      READY"); break;
  default: strcpy(str, "STAT_ERROR");
  }
}

static void
ildmod_stat_tostr(void* ilms, char str[])
{
  ilmstat_btuwi_pair_t *pair = ilms;
  char intervalstr[MAX_INTERVAL_STR];
  interval_t_tostr(&pair->interval, intervalstr);
  char ldmodstr[LDMOD_NAME_LEN];
  load_module_tostr(pair->lm, ldmodstr);
  char statstr[MAX_STAT_STR];
  treestat_tostr(atomic_load_explicit(&pair->stat, memory_order_relaxed), statstr);
  sprintf(str, "(%s %s %s)", intervalstr, ldmodstr, statstr);
}

/*
 * Compute the string representation of ilmstat_btuwi_pair_t with appropriate
 * indentation of the second component which is a binary tree.
 * Return the result in the parameter str.
 */
static void
ilmstat_btuwi_pair_tostr_indent(void* itp, char* indents, char str[])
{
  ilmstat_btuwi_pair_t* it_pair = (ilmstat_btuwi_pair_t*)itp;
  bitree_uwi_t *tree = it_pair->btuwi;
  char firststr[MAX_ILDMODSTAT_STR];
  char secondstr[MAX_TREE_STR];
  ildmod_stat_tostr(it_pair, firststr);
  bitree_uwi_tostring_indent(tree, indents, secondstr);
  snprintf(str, strlen(firststr) + strlen(secondstr) + 6, "%s%s%s%s%s",
	  "(", firststr, ",  ", secondstr, ")");
}

static int
max_ilmstat_btuwi_pair_len()
{
  return MAX_ILDMODSTAT_STR + MAX_TREE_STR + 4;
}


static char
ILdMod_Stat_MaxSpaces[] = "                                                                              ";

/*
 * the max spaces occupied by "([start_address ... end_address), load module xx, status)
 */
static char*
ildmod_stat_maxspaces()
{
  return ILdMod_Stat_MaxSpaces;
}

//---------------------------------------------------------------------
// private operations
//---------------------------------------------------------------------

#if UW_RECIPE_MAP_DEBUG
static void
uw_recipe_map_report(const char *op, void *start, void *end)
{
  fprintf(stderr, "%s [start=%p, end=%p)\n", op, start, end);
}
#else
#define uw_recipe_map_report(op, start, end)
#endif

static void
uw_recipe_map_poison(uintptr_t start, uintptr_t end, unwinder_t uw)
{
  uw_recipe_map_report("uw_recipe_map_poison", (void *) start, (void *) end);

  ilmstat_btuwi_pair_t* itpair =
	  ilmstat_btuwi_pair_build(start, end, NULL, NEVER, my_alloc);
  csklnode_t *node = cskl_insert(addr2recipe_map[uw], itpair, my_alloc);
  if (itpair != (ilmstat_btuwi_pair_t*)node->val)
    ilmstat_btuwi_pair_free(itpair);
}


/*
 * if the given address, value, is in the range of a node in the cskiplist,
 * return that node, otherwise return NULL.
 */
static ilmstat_btuwi_pair_t*
uw_recipe_map_inrange_find(uintptr_t addr, unwinder_t uw)
{
  return (ilmstat_btuwi_pair_t*)cskl_inrange_find(addr2recipe_map[uw], (void*)addr);
}

static void
cskl_ilmstat_btuwi_free(void *anode)
{
#if CSKL_ILS_BTU
//  printf("DXN_DBG cskl_ilmstat_btuwi_free(%p)...\n", anode);
#endif

  csklnode_t *node = (csklnode_t*) anode;
  ilmstat_btuwi_pair_t *ilmstat_btuwi = (ilmstat_btuwi_pair_t*)node->val;
  ilmstat_btuwi_pair_free(ilmstat_btuwi);
  node->val = NULL;
  cskl_free(node);
}

static bool
uw_recipe_map_cmp_del_bulk_unsynch(
	ilmstat_btuwi_pair_t* lo,
	ilmstat_btuwi_pair_t* hi,
	unwinder_t uw)
{
  return cskl_cmp_del_bulk_unsynch(addr2recipe_map[uw], lo, hi, cskl_ilmstat_btuwi_free);
}

static void
uw_recipe_map_unpoison(uintptr_t start, uintptr_t end, unwinder_t uw)
{
  ilmstat_btuwi_pair_t* ilmstat_btuwi =	uw_recipe_map_inrange_find(start, uw);
  if (ilmstat_btuwi == NULL)
    return;

  uw_recipe_map_report("uw_recipe_map_unpoison", (void *) start, (void *) end);

#if UW_RECIPE_MAP_DEBUG
  assert(ilmstat_btuwi != NULL); // start should be in range of some poisoned interval
  assert(atomic_load_explicit(&ilmstat_btuwi->stat, memory_order_relaxed) == NEVER);  // should be a poisoned node
#endif

  uintptr_t s0 = ilmstat_btuwi->interval.start;
  uintptr_t e0 = ilmstat_btuwi->interval.end;
  uw_recipe_map_cmp_del_bulk_unsynch(ilmstat_btuwi, ilmstat_btuwi, uw);
  uw_recipe_map_poison(s0, start, uw);
  uw_recipe_map_poison(end, e0, uw);
}


static void
uw_recipe_map_repoison(uintptr_t start, uintptr_t end, unwinder_t uw)
{
  if (start > 0) {
    ilmstat_btuwi_pair_t* ileft = uw_recipe_map_inrange_find(start - 1, uw);
    if (ileft) { 
      if ((ileft->interval.end == start) &&
          (NEVER == atomic_load_explicit(&ileft->stat, memory_order_acquire))) {
        // poisoned interval adjacent on the left
        start = ileft->interval.start;
        uw_recipe_map_cmp_del_bulk_unsynch(ileft, ileft, uw);
      }
    }
  }
  if (end < UINTPTR_MAX) {
    ilmstat_btuwi_pair_t* iright = uw_recipe_map_inrange_find(end+1, uw);
    if (iright) { 
      if ((iright->interval.start == end) &&
          (NEVER == atomic_load_explicit(&iright->stat, memory_order_acquire))) {
        // poisoned interval adjacent on the right
        end = iright->interval.end;
        uw_recipe_map_cmp_del_bulk_unsynch(iright, iright, uw);
      }
    }
  }
  uw_recipe_map_poison(start, end, uw);
}

{'fraction_non_alphanumeric': 0.22508282716731087, 'fraction_numerical': 0.0027263942573163996, 'mean_word_length': 3.4890782339271884, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 98, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2659', 'n_tokens_mistral': 10121, 'n_tokens_neox': 9824, 'n_words': 2267}