Blame libdw/libdw_alloc.c

Packit Service 97d2fb
/* Memory handling for libdw.
Packit Service 97d2fb
   Copyright (C) 2003, 2004, 2006 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include "libdwP.h"
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
#include "atomics.h"
Packit Service 97d2fb
#if USE_VG_ANNOTATIONS == 1
Packit Service 97d2fb
#include <helgrind.h>
Packit Service 97d2fb
#else
Packit Service 97d2fb
#define ANNOTATE_HAPPENS_BEFORE(X)
Packit Service 97d2fb
#define ANNOTATE_HAPPENS_AFTER(X)
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#define THREAD_ID_UNSET ((size_t) -1)
Packit Service 97d2fb
static __thread size_t thread_id = THREAD_ID_UNSET;
Packit Service 97d2fb
static atomic_size_t next_id = ATOMIC_VAR_INIT(0);
Packit Service 97d2fb
Packit Service 97d2fb
struct libdw_memblock *
Packit Service 97d2fb
__libdw_alloc_tail (Dwarf *dbg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (thread_id == THREAD_ID_UNSET)
Packit Service 97d2fb
    thread_id = atomic_fetch_add (&next_id, 1);
Packit Service 97d2fb
Packit Service 97d2fb
  pthread_rwlock_rdlock (&dbg->mem_rwl);
Packit Service 97d2fb
  if (thread_id >= dbg->mem_stacks)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      pthread_rwlock_unlock (&dbg->mem_rwl);
Packit Service 97d2fb
      pthread_rwlock_wrlock (&dbg->mem_rwl);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Another thread may have already reallocated. In theory using an
Packit Service 97d2fb
         atomic would be faster, but given that this only happens once per
Packit Service 97d2fb
         thread per Dwarf, some minor slowdown should be fine.  */
Packit Service 97d2fb
      if (thread_id >= dbg->mem_stacks)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          dbg->mem_tails = realloc (dbg->mem_tails, (thread_id+1)
Packit Service 97d2fb
                                    * sizeof (struct libdw_memblock *));
Packit Service 97d2fb
          if (dbg->mem_tails == NULL)
Packit Service 97d2fb
            {
Packit Service 97d2fb
              pthread_rwlock_unlock (&dbg->mem_rwl);
Packit Service 97d2fb
              dbg->oom_handler();
Packit Service 97d2fb
            }
Packit Service 97d2fb
          for (size_t i = dbg->mem_stacks; i <= thread_id; i++)
Packit Service 97d2fb
            dbg->mem_tails[i] = NULL;
Packit Service 97d2fb
          dbg->mem_stacks = thread_id + 1;
Packit Service 97d2fb
          ANNOTATE_HAPPENS_BEFORE (&dbg->mem_tails);
Packit Service 97d2fb
        }
Packit Service 97d2fb
Packit Service 97d2fb
      pthread_rwlock_unlock (&dbg->mem_rwl);
Packit Service 97d2fb
      pthread_rwlock_rdlock (&dbg->mem_rwl);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* At this point, we have an entry in the tail array.  */
Packit Service 97d2fb
  ANNOTATE_HAPPENS_AFTER (&dbg->mem_tails);
Packit Service 97d2fb
  struct libdw_memblock *result = dbg->mem_tails[thread_id];
Packit Service 97d2fb
  if (result == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      result = malloc (dbg->mem_default_size);
Packit Service 97d2fb
      if (result == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  pthread_rwlock_unlock (&dbg->mem_rwl);
Packit Service 97d2fb
	  dbg->oom_handler();
Packit Service 97d2fb
	}
Packit Service 97d2fb
      result->size = dbg->mem_default_size
Packit Service 97d2fb
                     - offsetof (struct libdw_memblock, mem);
Packit Service 97d2fb
      result->remaining = result->size;
Packit Service 97d2fb
      result->prev = NULL;
Packit Service 97d2fb
      dbg->mem_tails[thread_id] = result;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  pthread_rwlock_unlock (&dbg->mem_rwl);
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Can only be called after a allocation for this thread has already
Packit Service 97d2fb
   been done, to possibly undo it.  */
Packit Service 97d2fb
struct libdw_memblock *
Packit Service 97d2fb
__libdw_thread_tail (Dwarf *dbg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct libdw_memblock *result;
Packit Service 97d2fb
  pthread_rwlock_rdlock (&dbg->mem_rwl);
Packit Service 97d2fb
  result = dbg->mem_tails[thread_id];
Packit Service 97d2fb
  pthread_rwlock_unlock (&dbg->mem_rwl);
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
void *
Packit Service 97d2fb
__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t size = MAX (dbg->mem_default_size,
Packit Service 97d2fb
		     (align - 1 +
Packit Service 97d2fb
		      2 * minsize + offsetof (struct libdw_memblock, mem)));
Packit Service 97d2fb
  struct libdw_memblock *newp = malloc (size);
Packit Service 97d2fb
  if (newp == NULL)
Packit Service 97d2fb
    dbg->oom_handler ();
Packit Service 97d2fb
Packit Service 97d2fb
  uintptr_t result = ((uintptr_t) newp->mem + align - 1) & ~(align - 1);
Packit Service 97d2fb
Packit Service 97d2fb
  newp->size = size - offsetof (struct libdw_memblock, mem);
Packit Service 97d2fb
  newp->remaining = (uintptr_t) newp + size - (result + minsize);
Packit Service 97d2fb
Packit Service 97d2fb
  pthread_rwlock_rdlock (&dbg->mem_rwl);
Packit Service 97d2fb
  newp->prev = dbg->mem_tails[thread_id];
Packit Service 97d2fb
  dbg->mem_tails[thread_id] = newp;
Packit Service 97d2fb
  pthread_rwlock_unlock (&dbg->mem_rwl);
Packit Service 97d2fb
Packit Service 97d2fb
  return (void *) result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
Dwarf_OOM
Packit Service 97d2fb
dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_OOM old = dbg->oom_handler;
Packit Service 97d2fb
  dbg->oom_handler = handler;
Packit Service 97d2fb
  return old;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
__attribute ((noreturn)) attribute_hidden
Packit Service 97d2fb
__libdw_oom (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  while (1)
Packit Service 97d2fb
    error (EXIT_FAILURE, ENOMEM, "libdw");
Packit Service 97d2fb
}