Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
fix MC on FreeBSD
[simgrid.git] / src / xbt / mmalloc / mm_module.c
index cd4ef27..9f96095 100644 (file)
@@ -1,5 +1,12 @@
-/* Initialization for access to a mmap'd malloc managed region.
-   Copyright 1992, 2000 Free Software Foundation, Inc.
+/* Initialization for acces s to a mmap'd malloc managed region. */
+
+/* Copyright (c) 2012-2019. The SimGrid Team.
+ * All rights reserved.                                                     */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* Copyright 1992, 2000 Free Software Foundation, Inc.
 
    Contributed by Fred Fish at Cygnus Support.   fnf@cygnus.com
 
    not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include "src/internal_config.h"
 #include <sys/types.h>
 #include <fcntl.h>              /* After sys/types.h, at least for dpx/2.  */
 #include <sys/stat.h>
 #include <string.h>
-#ifdef HAVE_UNISTD_H
+#if HAVE_UNISTD_H
 #include <unistd.h>             /* Prototypes for lseek */
 #endif
 #include "mmprivate.h"
 #include "xbt/ex.h"
-#include "xbt_modinter.h" /* declarations of mmalloc_preinit and friends that live here */
+#include "src/xbt_modinter.h" /* declarations of mmalloc_preinit and friends that live here */
 
 #ifndef SEEK_SET
 #define SEEK_SET 0
@@ -40,7 +48,7 @@
    If FD is a valid file descriptor for an open file then data for the
    mmalloc managed region is mapped to that file, otherwise an anonymous
    map is used if supported by the underlying OS. In case of running in
-   an OS without support of anonymous mappings then "/dev/zero" is used 
+   an OS without support of anonymous mappings then "/dev/zero" is used
    and in both cases the data will not exist in any filesystem object.
 
    If the open file corresponding to FD is from a previous use of
@@ -50,8 +58,8 @@
    the current process as the process that created the file (ignoring
    the BASEADDR parameter).
 
-   For non valid FDs or empty files ones the mapping is established 
-   starting at the specified address BASEADDR in the process address 
+   For non valid FDs or empty files ones the mapping is established
+   starting at the specified address BASEADDR in the process address
    space.
 
    The provided BASEADDR should be choosed carefully in order to avoid
    On failure returns NULL. */
 
 xbt_mheap_t xbt_mheap_new(int fd, void *baseaddr)
+{
+  return xbt_mheap_new_options(fd, baseaddr, 0);
+}
+
+xbt_mheap_t xbt_mheap_new_options(int fd, void *baseaddr, int options)
 {
   struct mdesc mtemp;
   xbt_mheap_t mdp;
@@ -107,7 +120,8 @@ xbt_mheap_t xbt_mheap_new(int fd, void *baseaddr)
          unsuccessful for some reason. */
 
       struct mdesc newmd;
-      struct mdesc *mdptr = NULL, *mdptemp = NULL;
+      struct mdesc* mdptr   = NULL;
+      struct mdesc* mdptemp = NULL;
 
       if (lseek(fd, 0L, SEEK_SET) != 0)
         return NULL;
@@ -125,7 +139,7 @@ xbt_mheap_t xbt_mheap_new(int fd, void *baseaddr)
         mdptr = (struct mdesc *) newmd.base;
         mdptr->fd = fd;
         if(!mdptr->refcount){
-          sem_init(&mdptr->sem, 0, 1);
+          pthread_mutex_init(&mdptr->mutex, NULL);
           mdptr->refcount++;
         }
       }
@@ -143,15 +157,13 @@ xbt_mheap_t xbt_mheap_new(int fd, void *baseaddr)
     }
   }
 
-  /* NULL is not a valid baseaddr as we cannot map anything there.
-     C'mon, user. Think! */
+  /* NULL is not a valid baseaddr as we cannot map anything there. C'mon, user. Think! */
   if (baseaddr == NULL)
     return (NULL);
 
-  /* We start off with the malloc descriptor allocated on the stack, until
-     we build it up enough to call _mmalloc_mmap_morecore() to allocate the
-     first page of the region and copy it there.  Ensure that it is zero'd and
-     then initialize the fields that we know values for. */
+  /* We start off with the malloc descriptor allocated on the stack, until we build it up enough to
+   * call _mmalloc_mmap_morecore() to allocate the first page of the region and copy it there.  Ensure that it is
+   * zero'd and then initialize the fields that we know values for. */
 
   mdp = &mtemp;
   memset((char *) mdp, 0, sizeof(mtemp));
@@ -162,22 +174,21 @@ xbt_mheap_t xbt_mheap_new(int fd, void *baseaddr)
   mdp->base = mdp->breakval = mdp->top = baseaddr;
   mdp->next_mdesc = NULL;
   mdp->refcount = 1;
-  
+  mdp->options = options;
+
   /* If we have not been passed a valid open file descriptor for the file
      to map to, then we go for an anonymous map */
 
   if (mdp->fd < 0){
     mdp->flags |= MMALLOC_ANONYMOUS;
   }
-  sem_init(&mdp->sem, 0, 1);
-  
+  pthread_mutex_init(&mdp->mutex, NULL);
   /* If we have not been passed a valid open file descriptor for the file
      to map to, then open /dev/zero and use that to map to. */
 
-  /* Now try to map in the first page, copy the malloc descriptor structure
-     there, and arrange to return a pointer to this new copy.  If the mapping
-     fails, then close the file descriptor if it was opened by us, and arrange
-     to return a NULL. */
+  /* Now try to map in the first page, copy the malloc descriptor structure there, and arrange to return a pointer to
+   * this new copy.  If the mapping fails, then close the file descriptor if it was opened by us, and arrange to return
+   * a NULL. */
 
   if ((mbase = mmorecore(mdp, sizeof(mtemp))) != NULL) {
     memcpy(mbase, mdp, sizeof(mtemp));
@@ -186,7 +197,7 @@ xbt_mheap_t xbt_mheap_new(int fd, void *baseaddr)
     abort();
   }
 
-  /* Add the new heap to the linked list of heaps attached by mmalloc */  
+  /* Add the new heap to the linked list of heaps attached by mmalloc */
   if(__mmalloc_default_mdp){
     mdp = __mmalloc_default_mdp;
     while(mdp->next_mdesc)
@@ -212,46 +223,39 @@ void xbt_mheap_destroy_no_free(xbt_mheap_t md)
   struct mdesc *mdp = md;
 
   if(--mdp->refcount == 0){
-    LOCK(mdp) ;
-    sem_destroy(&mdp->sem);
+    pthread_mutex_destroy(&mdp->mutex);
   }
 }
 
-/** Terminate access to a mmalloc managed region by unmapping all memory pages
-    associated with the region, and closing the file descriptor if it is one
-    that we opened.
+/** Terminate access to a mmalloc managed region by unmapping all memory pages associated with the region, and closing
+ *  the file descriptor if it is one that we opened.
 
     Returns NULL on success.
 
-    Returns the malloc descriptor on failure, which can subsequently be used
-    for further action, such as obtaining more information about the nature of
-    the failure.
+    Returns the malloc descriptor on failure, which can subsequently be used for further action, such as obtaining more
+    information about the nature of the failure.
 
-    Note that the malloc descriptor that we are using is currently located in
-    region we are about to unmap, so we first make a local copy of it on the
-    stack and use the copy. */
+    Note that the malloc descriptor that we are using is currently located in region we are about to unmap, so we first
+    make a local copy of it on the stack and use the copy. */
 
 void *xbt_mheap_destroy(xbt_mheap_t mdp)
 {
-  struct mdesc mtemp, *mdptemp;
-
   if (mdp != NULL) {
     /* Remove the heap from the linked list of heaps attached by mmalloc */
-    mdptemp = __mmalloc_default_mdp;
+    struct mdesc* mdptemp = __mmalloc_default_mdp;
     while(mdptemp->next_mdesc != mdp )
       mdptemp = mdptemp->next_mdesc;
 
     mdptemp->next_mdesc = mdp->next_mdesc;
 
     xbt_mheap_destroy_no_free(mdp);
-    mtemp = *mdp;
+    struct mdesc mtemp = *mdp;
 
     /* Now unmap all the pages associated with this region by asking for a
        negative increment equal to the current size of the region. */
 
     if (mmorecore(&mtemp, (char *)mtemp.base - (char *)mtemp.breakval) == NULL) {
-      /* Deallocating failed.  Update the original malloc descriptor
-         with any changes */
+      /* Deallocating failed.  Update the original malloc descriptor with any changes */
       *mdp = mtemp;
     } else {
       if (mtemp.flags & MMALLOC_DEVZERO) {
@@ -265,8 +269,7 @@ void *xbt_mheap_destroy(xbt_mheap_t mdp)
 }
 
 /* Safety gap from the heap's break address.
- * Try to increase this first if you experience strange errors under
- * valgrind. */
+ * Try to increase this first if you experience strange errors under valgrind. */
 #define HEAP_OFFSET   (128UL<<20)
 
 xbt_mheap_t mmalloc_get_default_md(void)
@@ -315,18 +318,16 @@ static void mmalloc_fork_child(void)
 /* Initialize the default malloc descriptor. */
 void *mmalloc_preinit(void)
 {
-  int res;
   if (__mmalloc_default_mdp == NULL) {
-    unsigned long mask = ~((unsigned long)getpagesize() - 1);
+    if(!xbt_pagesize)
+      xbt_pagesize = getpagesize();
+    unsigned long mask = ~((unsigned long)xbt_pagesize - 1);
     void *addr = (void*)(((unsigned long)sbrk(0) + HEAP_OFFSET) & mask);
-    __mmalloc_default_mdp = xbt_mheap_new(-1, addr);
-    /* Fixme? only the default mdp in protected against forks */
-    // This is mandated to protect the mmalloced areas through forks. Think of tesh.
-    // Nah, removing the mutex isn't a good idea either for tesh
-    res = xbt_os_thread_atfork(mmalloc_fork_prepare,  
-                               mmalloc_fork_parent, mmalloc_fork_child);
-    if (res != 0)
-      THROWF(system_error,0,"xbt_os_thread_atfork() failed: return value %d",res);
+    __mmalloc_default_mdp = xbt_mheap_new_options(-1, addr, XBT_MHEAP_OPTION_MEMSET);
+
+    // atfork mandated at least on FreeBSD, or simgrid-mc will fail to fork the verified app
+    int res = pthread_atfork(mmalloc_fork_prepare, mmalloc_fork_parent, mmalloc_fork_child);
+    xbt_assert(res == 0, "pthread_atfork() failed: return value %d", res);
   }
   xbt_assert(__mmalloc_default_mdp != NULL);
 
@@ -335,7 +336,46 @@ void *mmalloc_preinit(void)
 
 void mmalloc_postexit(void)
 {
-  /* Do not detach the default mdp or ldl won't be able to free the memory it allocated since we're in memory */
-  //  mmalloc_detach(__mmalloc_default_mdp);
-  xbt_mheap_destroy_no_free(__mmalloc_default_mdp);
+  /* Do not destroy the default mdp or ldl won't be able to free the memory it
+   * allocated since we're in memory */
+  // xbt_mheap_destroy_no_free(__mmalloc_default_mdp);
+}
+
+// This is the underlying implementation of mmalloc_get_bytes_used_remote.
+// Is it used directly in order to evaluate the bytes used from a different
+// process.
+size_t mmalloc_get_bytes_used_remote(size_t heaplimit, const malloc_info* heapinfo)
+{
+  int bytes = 0;
+  for (size_t i=0; i < heaplimit; ++i){
+    if (heapinfo[i].type == MMALLOC_TYPE_UNFRAGMENTED){
+      if (heapinfo[i].busy_block.busy_size > 0)
+        bytes += heapinfo[i].busy_block.busy_size;
+    } else if (heapinfo[i].type > 0) {
+      for (size_t j=0; j < (size_t) (BLOCKSIZE >> heapinfo[i].type); j++){
+        if(heapinfo[i].busy_frag.frag_size[j] > 0)
+          bytes += heapinfo[i].busy_frag.frag_size[j];
+      }
+    }
+  }
+  return bytes;
+}
+
+size_t mmalloc_get_bytes_used(const xbt_mheap_t heap){
+  const struct mdesc* heap_data = (const struct mdesc *) heap;
+  return mmalloc_get_bytes_used_remote(heap_data->heaplimit, heap_data->heapinfo);
+}
+
+ssize_t mmalloc_get_busy_size(xbt_mheap_t heap, void *ptr){
+
+  ssize_t block = ((char*)ptr - (char*)(heap->heapbase)) / BLOCKSIZE + 1;
+  if(heap->heapinfo[block].type < 0)
+    return -1;
+  else if(heap->heapinfo[block].type == MMALLOC_TYPE_UNFRAGMENTED)
+    return heap->heapinfo[block].busy_block.busy_size;
+  else{
+    ssize_t frag = ((uintptr_t) (ADDR2UINT (ptr) % (BLOCKSIZE))) >> heap->heapinfo[block].type;
+    return heap->heapinfo[block].busy_frag.frag_size[frag];
+  }
+
 }