Beispiel #1
0
/*
 * pmemalloc_coalesce_free -- find adjacent free blocks and coalesce them
 *
 * Scan the pmeme pool for recovery work:
 * 	- RESERVED clumps that need to be freed
 * 	- ACTIVATING clumps that need to be ACTIVE
 * 	- FREEING clumps that need to be freed
 *
 * Internal support routine, used during recovery.
 */
static void
pmemalloc_coalesce_free(void *pmp)
{
	struct clump *clp;
    struct pool_header  *phdr;
	struct clump *firstfree;
	struct clump *lastfree;
	size_t csize;

	DEBUG("pmp=0x%lx", pmp);

	firstfree = lastfree = NULL;
	csize = 0;
	clp = PMEM(pmp, (struct clump *)PMEM_CLUMP_OFFSET);
    phdr = PMEM(pmp, (struct pool_header *)PMEM_HDR_OFFSET);

    pthread_mutex_lock( &phdr->pool_lock );

	while (clp->size) {
		size_t sz = clp->size & ~PMEM_STATE_MASK;
		int state = clp->size & PMEM_STATE_MASK;

		DEBUG("[0x%lx]clump size %lx state %d",
				OFF(pmp, clp), sz, state);

		if (state == PMEM_STATE_FREE) {
			if (firstfree == NULL)
				firstfree = clp;
			else
				lastfree = clp;
			csize += sz;
		} else if (firstfree != NULL && lastfree != NULL) {
			DEBUG("coalesced size 0x%lx", csize);
			firstfree->size = csize | PMEM_STATE_FREE;
			pmem_persist(firstfree, sizeof(*firstfree), 0);
			firstfree = lastfree = NULL;
			csize = 0;
		} else {
			firstfree = lastfree = NULL;
			csize = 0;
		}

		clp = (struct clump *)((uintptr_t)clp + sz);
		DEBUG("next clp %lx, offset 0x%lx", clp, OFF(pmp, clp));
	}
	if (firstfree != NULL && lastfree != NULL) {
		DEBUG("coalesced size 0x%lx", csize);
		DEBUG("firstfree 0x%lx next clp after firstfree will be 0x%lx",
				firstfree, (uintptr_t)firstfree + csize);
		firstfree->size = csize | PMEM_STATE_FREE;
		pmem_persist(firstfree, sizeof(*firstfree), 0);
	}
    pthread_mutex_unlock( &phdr->pool_lock );
}
Beispiel #2
0
/*
 * pmemalloc_activate -- atomically persist memory, mark in-use, store pointers
 *
 * Inputs:
 *	pmp -- a pmp as returned by pmemalloc_init()
 *
 *	ptr_ -- memory to be persisted, as returned by pmemalloc_reserve()
 */
void
pmemalloc_activate(void *pmp, void *ptr_)
{
	struct clump *clp;
	size_t sz;
	int i;
    struct pool_header *phdr;

	DEBUG("pmp=%lx, ptr_=%lx", pmp, ptr_);

	clp = PMEM(pmp, (struct clump *)((uintptr_t)ptr_ - PMEM_CHUNK_SIZE));
    phdr = PMEM(pmp, (struct pool_header *)PMEM_HDR_OFFSET);

    pthread_mutex_lock(&phdr->activation_lock);

	ASSERTeq(clp->size & PMEM_STATE_MASK, PMEM_STATE_RESERVED);

	DEBUG("[0x%lx] clump on: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
			OFF(pmp, clp),
			clp->on[0].off, clp->on[0].ptr_,
			clp->on[1].off, clp->on[1].ptr_,
			clp->on[2].off, clp->on[2].ptr_);

	sz = clp->size & ~PMEM_STATE_MASK;

	/*
	 * order here is important:
	 * 1. persist *ptr_
	 * 2. set state to ACTIVATING
	 * 3. persist *clp (now we're committed to progressing to STATE_ACTIVE)
	 * 4. execute "on" list, persisting each one
	 * 5. clear out "on" list, last to first
	 * 5. set state to ACTIVE
	 * 6. persist *clp
	 */
	pmem_persist(PMEM(pmp, ptr_), clp->size - PMEM_CHUNK_SIZE, 0);
	clp->size = sz | PMEM_STATE_ACTIVATING;
	pmem_persist(clp, sizeof(*clp), 0);
	for (i = 0; i < PMEM_NUM_ON; i++)
		if (clp->on[i].off) {
			uintptr_t *dest =
				PMEM(pmp, (uintptr_t *)clp->on[i].off);
			*dest = (uintptr_t)clp->on[i].ptr_;
			pmem_persist(dest, sizeof(*dest), 0);
		} else
			break;
	for (i = PMEM_NUM_ON - 1; i >= 0; i--)
		clp->on[i].off = 0;
	pmem_persist(clp, sizeof(*clp), 0);
	clp->size = sz | PMEM_STATE_ACTIVE;
	pmem_persist(clp, sizeof(*clp), 0);
    pthread_mutex_unlock(&phdr->activation_lock);
}
Beispiel #3
0
/*
 * pmemalloc_static_area -- return a pointer to the static 4k area
 *
 * Outputs:
 * 	A pointer to a 4k static area is returned.  The caller may use
 * 	this area for anything -- no structure is imposed by this library.
 * 	This allows the caller to store pointers to roots of trees or
 * 	beginning of linked lists, etc. in the same file as the rest of
 * 	the memory pool.
 *
 * The pointer returned is a normal (absolute) pointer.  No need to use
 * the PMEM() macro with it.  Changes to this area are not guaranteed
 * persistent until pmem_persist() has been called, for example:
 *	pmem_persist(pmem_static_area(pmp), PMEM_STATIC_SIZE);
 */
void *
pmemalloc_static_area(void *pmp)
{
	DEBUG("pmp=0x%lx", pmp);

	return PMEM(pmp, (void *)PMEM_STATIC_OFFSET);
}
inline void *pmemalloc_reserv_virtual(size_t size, void **tmp){
#ifdef INTEL_PMEM
	void *ptr = pmemalloc_reserve(Pmp, size);
	*tmp = ptr;
	return PMEM(Pmp, ptr);
#else
	return malloc(size);
#endif
}
Beispiel #5
0
/*
 * pmemalloc_onfree -- set assignments for when allocation gets freed
 *
 * Inputs:
 *	pmp -- The pmp as returned by pmemalloc_init() for the persistent
 *         Memory pool containing both the persistent memory chunk to
 *         be returned and the persistent data structure used by the
 *         calling program to track the allocated persistent memory.
 *
 *  ptr_ -- Relative pointer to the persistent memory to be returned
 *
 *	parentp -- Absolute pointer to the persistent relative pointer
 *             used by the calling program to track the chunk of
 *             persistent memory referenced by ptr_.  The persistent
 *             relative pointer must be within the same PM pool.
 *
 *	nptr_ -- The value to set in *parentp
 */
void
pmemalloc_onfree(void *pmp, void *ptr_, void **parentp, void *nptr_)
{
	struct clump *clp;
	int i;
    struct pool_header *phdr;

	DEBUG("pmp=0x%lx, ptr_=0x%lx, parentp_=0x%lx, nptr_=0x%lx",
			pmp, ptr_, parentp, nptr_);

	clp = PMEM(pmp, (struct clump *)((uintptr_t)ptr_ - PMEM_CHUNK_SIZE));
    phdr = PMEM(pmp, (struct pool_header *)PMEM_HDR_OFFSET);

    pthread_mutex_lock(&phdr->activation_lock);

	ASSERTeq(clp->size & PMEM_STATE_MASK, PMEM_STATE_ACTIVE);

	DEBUG("[0x%lx] clump on: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
			OFF(pmp, clp),
			clp->on[0].off, clp->on[0].ptr_,
			clp->on[1].off, clp->on[1].ptr_,
			clp->on[2].off, clp->on[2].ptr_);

	for (i = 0; i < PMEM_NUM_ON; i++)
		if (clp->on[i].off == 0) {
			DEBUG("using on[%d], off 0x%lx", i, OFF(pmp, parentp));
			/*
			 * order here is important:
			 * 1. set ptr_
			 * 2. make ptr_ persistent
			 * 3. set off
			 * 4. make off persistent
			 */
			clp->on[i].ptr_ = nptr_;
			pmem_persist(clp, sizeof(*clp), 0);
			clp->on[i].off = OFF(pmp, parentp);
			pmem_persist(clp, sizeof(*clp), 0);
            pthread_mutex_unlock(&phdr->activation_lock);
			return;
		}

	FATAL("exceeded onfree limit (%d)", PMEM_NUM_ON);
}
Beispiel #6
0
APIRET TestMemory(void)
{
  APIRET rc = NO_ERROR;                                   /* API Return Code */
  ULONG  ulMemorySize;                 /* size of one memory object in bytes */
  ULONG  ulMemoryNumber;                         /* number of memory objects */
  ULONG  ulMemoryFlags;             /* allocation attributes for the objects */

  struct
  {
    ULONG ulPageSize;                                    /* system page size */
    ULONG ulTotalPhysicalMemory;                    /* total physical memory */
    ULONG ulTotalResidentMemory;                    /* total resident memory */
    ULONG ulTotalAvailableMemory;                  /* total available memory */
    ULONG ulMaximumPrivateMemory;        /* maximum available private memory */
    ULONG ulMaximumSharedMemory;          /* maximum available shared memory */
  } sSystemValues;


  /***************************************************************************
   * Query information about memory manager from the system                  *
   * calculating all necessary parameters and values                         *
   ***************************************************************************/

  rc = DosQuerySysInfo (QSV_PAGE_SIZE,
                        QSV_PAGE_SIZE,
                        &sSystemValues.ulPageSize,
                        sizeof(sSystemValues.ulPageSize));
  if (rc != NO_ERROR)
    return (rc);                                         /* abort with error */

  rc = DosQuerySysInfo (QSV_TOTPHYSMEM,
                        QSV_MAXSHMEM,
                        &sSystemValues.ulTotalPhysicalMemory,
                        5 * sizeof(sSystemValues.ulTotalPhysicalMemory)
                       );
  if (rc != NO_ERROR)
    return (rc);                                         /* abort with error */

#define PMEM(a) sSystemValues.a, \
  (float)sSystemValues.a / 1024.0, \
  (float)sSystemValues.a / 1024.0 / 1024.0

  printf ("\nMemory Information:"
          "\n  System page size        (PAGE) : %10ub   %10.3fk   %10.3fM"
          "\n  Total physical memory   (PHYS) : %10ub   %10.3fk   %10.3fM",
          PMEM(ulPageSize),
          PMEM(ulTotalPhysicalMemory));

  printf ("\n  Total resident memory          : %10ub   %10.3fk   %10.3fM"
          "\n  Total available memory (AVAIL) : %10ub   %10.3fk   %10.3fM",
          PMEM(ulTotalResidentMemory),
          PMEM(ulTotalAvailableMemory));

  printf ("\n  Available private memory (MAX) : %10ub   %10.3fk   %10.3fM"
          "\n  Available shared  memory (SHR) : %10ub   %10.3fk   %10.3fM",
          PMEM(ulMaximumPrivateMemory),
          PMEM(ulMaximumSharedMemory));
#undef PMEM

  if (Options.fsMemSize)
  {
    if (stricmp(Options.pszMemSize,
                "MAX") == 0)
      ulMemorySize = sSystemValues.ulMaximumPrivateMemory;
    else
    {
      if (stricmp(Options.pszMemSize,
                  "PHYS") == 0)
        ulMemorySize = sSystemValues.ulTotalPhysicalMemory;
      else
      {
        if (stricmp(Options.pszMemSize,
                    "AVAIL") == 0)
          ulMemorySize = sSystemValues.ulTotalAvailableMemory;
        else
        {
          if (stricmp(Options.pszMemSize,
                      "SHR") == 0)
            ulMemorySize = sSystemValues.ulMaximumSharedMemory;
          else
          {
            if (stricmp(Options.pszMemSize,
                        "PAGE") == 0)
              ulMemorySize = sSystemValues.ulPageSize;
            else
              ulMemorySize = atoi(Options.pszMemSize);
          }
        }
      }
    }
  }
  else
    ulMemorySize = 1024 * 1024;                            /* 1MB is default */

  if (Options.fsMemNumber)
    ulMemoryNumber = Options.ulMemNumber;
  else
    ulMemoryNumber = 1;                             /* one object is default */

  printf ("\n\nAllocating %u objects at size of %u bytes each, %u in total.",
          ulMemoryNumber,
          ulMemorySize,
          ulMemoryNumber * ulMemorySize);

  ulMemoryFlags = 0;
  printf ("\nMemory object attributes:");
#define MEMA(a,b) {ulMemoryFlags |= a; printf (b);}
  if (Options.fsMemCommit ) MEMA(PAG_COMMIT, " PAG_COMMIT");
  if (Options.fsMemWrite  ) MEMA(PAG_WRITE,  " PAG_WRITE");
  if (Options.fsMemRead   ) MEMA(PAG_READ,   " PAG_READ");
  if (Options.fsMemExecute) MEMA(PAG_EXECUTE," PAG_EXECUTE");
  if (Options.fsMemTile   ) MEMA(OBJ_TILE,   " OBJ_TILE");
#undef MEMA


  /***************************************************************************
   * Now allocating the memory.                                              *
   ***************************************************************************/


  /***************************************************************************
   * Now performing certain operations on that memory.                       *
   ***************************************************************************/


#if 0
  ARGFLAG fsOpQuery;          /* Perform query operations on the objects.    */
  ARGFLAG fsOpWrite;          /* Perform write operations on the objects.    */
  ARGFLAG fsOpRead;           /* Perform read  operations on the objects.    */
  ARGFLAG fsOpCheck;          /* Perform memory r/w tests on the objects.    */
  ARGFLAG fsOpForward;        /* Operation direction is forward.             */
  ARGFLAG fsOpBackward;       /* Operation direction is backward.            */
  ARGFLAG fsOpMixed;          /* Operation direction is mixed.               */
  ARGFLAG fsOpRandom;         /* Operation uses random addresses.            */
#endif


  return (NO_ERROR);                     /* return value to the main routine */
}
Beispiel #7
0
/*
 * pmemalloc_check -- check the consistency of a pmem pool
 *
 * Inputs:
 *	path -- path to the file which contains the memory pool
 *
 * The current state of the pmem pool is printed.  This routine does
 * not make any changes to the pmem pool (maps it read-only, in fact).
 * It is not necessary to call pmemalloc_init() before calling this.
 */
void pmemalloc_check(const char *path)
{
	void *pmp;
	int fd;
	struct stat stbuf;
	struct clump *clp;
	struct clump *lastclp;
	struct pool_header *hdrp;
	size_t clumptotal;
	/*
	 * stats we keep for each type of memory:
	 * 	stats[PMEM_STATE_FREE] for free clumps
	 * 	stats[PMEM_STATE_RESERVED] for reserved clumps
	 * 	stats[PMEM_STATE_ACTIVATING] for activating clumps
	 * 	stats[PMEM_STATE_ACTIVE] for active clumps
	 * 	stats[PMEM_STATE_FREEING] for freeing clumps
	 * 	stats[PMEM_STATE_UNUSED] for overall totals
	 */
	struct {
		size_t largest;
		size_t smallest;
		size_t bytes;
		unsigned count;
	} stats[PMEM_STATE_UNUSED + 1] = { 0 };
	const char *names[] = {
		"Free",
		"Reserved",
		"Activating",
		"Active",
		"Freeing",
		"TOTAL",
	};
	int i;

	DEBUG("path=%s", path);

	if ((fd = open(path, O_RDONLY)) < 0)
		FATALSYS("%s", path);

	if (fstat(fd, &stbuf) < 0)
		FATALSYS("fstat");

	DEBUG("file size 0x%lx", stbuf.st_size);

	if (stbuf.st_size < PMEM_MIN_POOL_SIZE)
		FATAL("size %lu too small (must be at least %lu)",
					stbuf.st_size, PMEM_MIN_POOL_SIZE);

	if ((pmp = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
					fd, 0)) == MAP_FAILED)
		FATALSYS("mmap");
	DEBUG("pmp %lx", pmp);

	close(fd);

	hdrp = PMEM(pmp, (struct pool_header *)PMEM_HDR_OFFSET);
	DEBUG("   hdrp 0x%lx (off 0x%lx)", hdrp, OFF(pmp, hdrp));

	if (strcmp(hdrp->signature, PMEM_SIGNATURE))
		FATAL("failed signature check");
	DEBUG("signature check passed");

	clp = PMEM(pmp, (struct clump *)PMEM_CLUMP_OFFSET);
	/*
	 * location of last clump is calculated by rounding the file
	 * size down to a multiple of 64, and then subtracting off
	 * another 64 to hold the struct clump.  the last clump is
	 * indicated by a size of zero.
	 */
	lastclp = PMEM(pmp, (struct clump *)
		(stbuf.st_size & ~(PMEM_CHUNK_SIZE - 1)) - PMEM_CHUNK_SIZE);
	DEBUG("    clp 0x%lx (off 0x%lx)", clp, OFF(pmp, clp));
	DEBUG("lastclp 0x%lx (off 0x%lx)", lastclp, OFF(pmp, lastclp));

	clumptotal = (uintptr_t)lastclp - (uintptr_t)clp;

	DEBUG("expected clumptotal: %lu", clumptotal);

	/*
	 * check that:
	 *
	 *   the overhead size (stuff up to CLUMP_OFFSET)
	 * + clumptotal
	 * + last clump marker (CHUNK_SIZE)
	 * + any bytes we rounded off the end
	 * = file size
	 */
	if (PMEM_CLUMP_OFFSET + clumptotal + 
		(stbuf.st_size & (PMEM_CHUNK_SIZE - 1)) + PMEM_CHUNK_SIZE
		== stbuf.st_size) {
		DEBUG("section sizes correctly add up to file size");
	} else {
		FATAL("CLUMP_OFFSET %d + clumptotal %lu + rounded %d + "
				"CHUNK_SIZE %d = %lu, (not st_size %lu)",
				PMEM_CLUMP_OFFSET, clumptotal,
				(stbuf.st_size & (PMEM_CHUNK_SIZE - 1)),
				PMEM_CHUNK_SIZE,
				PMEM_CLUMP_OFFSET + clumptotal +
				(stbuf.st_size & (PMEM_CHUNK_SIZE - 1)) +
				PMEM_CHUNK_SIZE,
				stbuf.st_size);
	}

	if (clp->size == 0)
		FATAL("no clumps found");

	while (clp->size) {
		size_t sz = clp->size & ~PMEM_STATE_MASK;
		int state = clp->size & PMEM_STATE_MASK;

		DEBUG("[%u]clump size 0x%lx state %d",
				OFF(pmp, clp), sz, state);
		DEBUG("on: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
			clp->on[0].off, clp->on[0].ptr_,
			clp->on[1].off, clp->on[1].ptr_,
			clp->on[2].off, clp->on[2].ptr_);

		if (sz > stats[PMEM_STATE_UNUSED].largest)
			stats[PMEM_STATE_UNUSED].largest = sz;
		if (stats[PMEM_STATE_UNUSED].smallest == 0 ||
		    sz < stats[PMEM_STATE_UNUSED].smallest)
			stats[PMEM_STATE_UNUSED].smallest = sz;
		stats[PMEM_STATE_UNUSED].bytes += sz;
		stats[PMEM_STATE_UNUSED].count++;

		switch (state) {
		case PMEM_STATE_FREE:
			DEBUG("clump state: free");
			ASSERTeq(clp->on[0].off, 0);
			ASSERTeq(clp->on[1].off, 0);
			ASSERTeq(clp->on[2].off, 0);
			break;

		case PMEM_STATE_RESERVED:
			DEBUG("clump state: reserved");
			break;

		case PMEM_STATE_ACTIVATING:
			DEBUG("clump state: activating");
			break;

		case PMEM_STATE_ACTIVE:
			DEBUG("clump state: active");
			ASSERTeq(clp->on[0].off, 0);
			ASSERTeq(clp->on[1].off, 0);
			ASSERTeq(clp->on[2].off, 0);
			break;

		case PMEM_STATE_FREEING:
			DEBUG("clump state: freeing");
			break;

		default:
			FATAL("unknown clump state: %d", state);
		}

		if (sz > stats[state].largest)
			stats[state].largest = sz;
		if (stats[state].smallest == 0 ||
		    sz < stats[state].smallest)
			stats[state].smallest = sz;
		stats[state].bytes += sz;
		stats[state].count++;

		clp = (struct clump *)((uintptr_t)clp + sz);
		DEBUG("next clp 0x%lx, offset 0x%lx", clp, OFF(pmp, clp));
	}

	if (clp == lastclp)
		DEBUG("all clump space accounted for");
	else
		FATAL("clump list stopped at %lx instead of %lx", clp, lastclp);

	if (munmap(pmp, stbuf.st_size) < 0)
		FATALSYS("munmap");

	/*
	 * print the report
	 */
	printf("Summary of pmem pool:\n");
	printf("File size: %lu, %d allocatable bytes in pool\n\n",
			stbuf.st_size, clumptotal);
	printf("     State      Bytes     Clumps    Largest   Smallest\n");
	for (i = 0; i < PMEM_STATE_UNUSED + 1; i++) {
		printf("%10s %10d %10d %10d %10d\n",
				names[i],
				stats[i].bytes,
				stats[i].count,
				stats[i].largest,
				stats[i].smallest);
	}
}
Beispiel #8
0
/*
 * pmemalloc_free -- free memory
 *
 * Inputs:
 *	pmp -- a pmp as returned by pmemalloc_init()
 *
 *	ptr_ -- memory to be freed, as returned by pmemalloc_reserve()
 */
void
pmemalloc_free(void *pmp, void *ptr_)
{
	struct clump *clp;
	size_t sz;
	int state;
	int i;
    struct pool_header *phdr;

	DEBUG("pmp=%lx, ptr_=%lx", pmp, ptr_);

	clp = PMEM(pmp, (struct clump *)((uintptr_t)ptr_ - PMEM_CHUNK_SIZE));
    phdr = PMEM(pmp, (struct pool_header *)PMEM_HDR_OFFSET);

	DEBUG("[0x%lx] clump on: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
			OFF(pmp, clp),
			clp->on[0].off, clp->on[0].ptr_,
			clp->on[1].off, clp->on[1].ptr_,
			clp->on[2].off, clp->on[2].ptr_);

    pthread_mutex_lock(&phdr->activation_lock);
	sz = clp->size & ~PMEM_STATE_MASK;
	state = clp->size & PMEM_STATE_MASK;

	if (state != PMEM_STATE_RESERVED && state != PMEM_STATE_ACTIVE)
		FATAL("freeing clump in bad state: %d", state);

	if (state == PMEM_STATE_ACTIVE) {
		/*
		 * order here is important:
		 * 1. set state to FREEING
		 * 2. persist *clp (now we're committed towards STATE_FREE)
		 * 3. execute onfree stores, persisting each one
		 * 4. set state to FREE
		 * 5. persist *clp
		 */
		clp->size = sz | PMEM_STATE_FREEING;
		pmem_persist(clp, sizeof(*clp), 0);
		for (i = 0; i < PMEM_NUM_ON; i++)
			if (clp->on[i].off) {
				uintptr_t *dest =
					PMEM(pmp, (uintptr_t *)clp->on[i].off);
				*dest = (uintptr_t)clp->on[i].ptr_;
				pmem_persist(dest, sizeof(*dest), 0);
			} else
				break;
		for (i = PMEM_NUM_ON - 1; i >= 0; i--)
			clp->on[i].off = 0;
		pmem_persist(clp, sizeof(*clp), 0);
	}
	clp->size = sz | PMEM_STATE_FREE;
	pmem_persist(clp, sizeof(*clp), 0);
    pthread_mutex_unlock(&phdr->activation_lock);

	/*
	 * at this point we may have adjacent free clumps that need
	 * to be coalesced.  there are three interesting cases:
	 * 	case 1: the clump below us is free (need to combine two clumps)
	 * 	case 2: the clump above us is free (need to combine two clumps)
	 * 	case 3: both are free (need to combining three clumps)
	 * XXX this can be much more optimal by using clp->prevsize to
	 *     get back to the clump below us.  for now, we just invoke
	 *     the recovery code for coalescing.
	 */
	pmemalloc_coalesce_free(pmp);
}
Beispiel #9
0
/*
 * pmemalloc_reserve -- allocate memory, volatile until pmemalloc_activate()
 *
 * Inputs:
 *	pmp -- a pmp as returned by pmemalloc_init()
 *
 *	size -- number of bytes to allocate
 *
 * Outputs:
 *	On success, this function returns memory allocated from the
 *	memory-mapped file associated with pmp.  The memory is suitably
 *	aligned for any kind of variable.  The memory is not initialized.
 *
 *	On failure, this function returns NULL and errno is set.
 *
 * The memory returned is initially *volatile* meaning that if the
 * program exits (or system crashes) before pmemalloc_activate() is called
 * with the return value, it is considered incompletely allocated
 * and the memory is returned to the free pool in the memory-mapped
 * file.  It works this way to prevent memory leaks when the system
 * crashes between a successful return from pmemalloc_reserve() and when
 * the caller actually links something to point at the new memory.
 * The basic pattern for using pmemalloc_reserve() is this:
 *
 *	np_ = pmemalloc_reserve(pmp, sizeof(*np_));
 *	...fill in fields in *np_...
 *	pmemalloc_onactive(pmp, np_, &parent->next_, np_);
 *	pmemalloc_activate(pmp, np_);
 *
 * In addition to flushing the data at *np_ to persistence, the
 * pmemalloc_activate() call above also atomically marks that memory
 * as in-use and stores the pointer to the persistent-memory-
 * based pointer parent->next_ in this example).  So any crash that
 * happens before parent->next_ is set to point at the new memory will
 * result in the memory being returned back to the free list.
 */
void *
pmemalloc_reserve(void *pmp, size_t size)
{
	size_t nsize = roundup(size + PMEM_CHUNK_SIZE, PMEM_CHUNK_SIZE);
	struct clump *clp;
    struct pool_header  *phdr;

	DEBUG("pmp=0x%lx, size=0x%lx -> 0x%lx", pmp, size, nsize);

	clp = PMEM(pmp, (struct clump *)PMEM_CLUMP_OFFSET);
    phdr = PMEM(pmp, (struct pool_header *)PMEM_HDR_OFFSET);

	if (clp->size == 0)
		FATAL("no clumps found");

    pthread_mutex_lock( &phdr->pool_lock );
	/* first fit */
	while (clp->size) {
		size_t sz = clp->size & ~PMEM_STATE_MASK;
		int state = clp->size & PMEM_STATE_MASK;

		DEBUG("[0x%lx] clump size 0x%lx state %d",
				OFF(pmp, clp), sz, state);

		if (state == PMEM_STATE_FREE && nsize <= sz) {
			void *ptr = (void *)
				(uintptr_t)clp + PMEM_CHUNK_SIZE -
				(uintptr_t)pmp;
			size_t leftover = sz - nsize;

			DEBUG("fit found ptr 0x%lx, leftover 0x%lx bytes",
					ptr, leftover);
			if (leftover >= PMEM_CHUNK_SIZE * 2) {
				struct clump *newclp;
				int i;

				newclp = (struct clump *)
					((uintptr_t)clp + nsize);

				DEBUG("splitting: [0x%lx] new clump",
						OFF(pmp, newclp));
				/*
				 * can go ahead and start fiddling with
				 * this freely since it is in the middle
				 * of a free clump until we change fields
				 * in *clp.  order here is important:
				 * 	1. initialize new clump
				 * 	2. persist new clump
				 * 	3. initialize existing clump do list
				 * 	4. persist existing clump
				 * 	5. set new clump size, RESERVED
				 * 	6. persist existing clump
				 */
				memset(newclp, '\0', sizeof(*newclp));
				newclp->size = leftover | PMEM_STATE_FREE;
				pmem_persist(newclp, sizeof(*newclp), 0);
				for (i = 0; i < PMEM_NUM_ON; i++) {
					clp->on[i].off = 0;
					clp->on[i].ptr_ = 0;
				}
				pmem_persist(clp, sizeof(*clp), 0);
				clp->size = nsize | PMEM_STATE_RESERVED;
				pmem_persist(clp, sizeof(*clp), 0);
			} else {
				int i;

				DEBUG("no split required");

				for (i = 0; i < PMEM_NUM_ON; i++) {
					clp->on[i].off = 0;
					clp->on[i].ptr_ = 0;
				}
				pmem_persist(clp, sizeof(*clp), 0);
				clp->size = sz | PMEM_STATE_RESERVED;
				pmem_persist(clp, sizeof(*clp), 0);
			}

            pthread_mutex_unlock( &phdr->pool_lock );
			return ptr;
		}

		clp = (struct clump *)((uintptr_t)clp + sz);
		DEBUG("[0x%lx] next clump", OFF(pmp, clp));
	}

    pthread_mutex_unlock( &phdr->pool_lock );
	DEBUG("no free memory of size %lu available", nsize);
	errno = ENOMEM;
	return NULL;
}
Beispiel #10
0
/*
 * pmemalloc_recover -- recover after a possible crash
 *
 * Internal support routine, used during recovery.
 */
static void
pmemalloc_recover(void *pmp)
{
	struct clump *clp;
    struct pool_header *phdr;
	int i;

	DEBUG("pmp=0x%lx", pmp);

	clp = PMEM(pmp, (struct clump *)PMEM_CLUMP_OFFSET);
    phdr = PMEM(pmp, (struct pool_header *)PMEM_HDR_OFFSET);

	while (clp->size) {
		size_t sz = clp->size & ~PMEM_STATE_MASK;
		int state = clp->size & PMEM_STATE_MASK;

		DEBUG("[0x%lx]clump size %lx state %d",
				OFF(pmp, clp), sz, state);

		switch (state) {
		case PMEM_STATE_RESERVED:
			/* return the clump to the FREE pool */
			for (i = PMEM_NUM_ON - 1; i >= 0; i--)
				clp->on[i].off = 0;
			pmem_persist(clp, sizeof(*clp), 0);
			clp->size = sz | PMEM_STATE_FREE;
			pmem_persist(clp, sizeof(*clp), 0);
			break;

		case PMEM_STATE_ACTIVATING:
			/* finish progressing the clump to ACTIVE */
			for (i = 0; i < PMEM_NUM_ON; i++)
				if (clp->on[i].off) {
					uintptr_t *dest =
						PMEM(pmp,
						(uintptr_t *)clp->on[i].off);
					*dest = (uintptr_t)clp->on[i].ptr_;
					pmem_persist(dest, sizeof(*dest), 0);
				} else
					break;
			for (i = PMEM_NUM_ON - 1; i >= 0; i--)
				clp->on[i].off = 0;
			pmem_persist(clp, sizeof(*clp), 0);
			clp->size = sz | PMEM_STATE_ACTIVE;
			pmem_persist(clp, sizeof(*clp), 0);
			break;

		case PMEM_STATE_FREEING:
			/* finish progressing the clump to FREE */
			for (i = 0; i < PMEM_NUM_ON; i++)
				if (clp->on[i].off) {
					uintptr_t *dest =
						PMEM(pmp,
						(uintptr_t *)clp->on[i].off);
					*dest = (uintptr_t)clp->on[i].ptr_;
					pmem_persist(dest, sizeof(*dest), 0);
				} else
					break;
			for (i = PMEM_NUM_ON - 1; i >= 0; i--)
				clp->on[i].off = 0;
			pmem_persist(clp, sizeof(*clp), 0);
			clp->size = sz | PMEM_STATE_FREE;
			pmem_persist(clp, sizeof(*clp), 0);
			break;
		}

		clp = (struct clump *)((uintptr_t)clp + sz);
		DEBUG("next clp %lx, offset 0x%lx", clp, OFF(pmp, clp));
	}
    pthread_mutex_init(&phdr->pool_lock, NULL);
    pthread_mutex_init(&phdr->activation_lock, NULL);
    pmem_persist(phdr, sizeof(*phdr), 0);
}
int
main(int argc, char *argv[])
{
    const char *path;
    int opt;
    int retval;
    unsigned long thrd;
    int mbx;
    void **sa_ptr;
    mailbox_array_t *mbx_offset_; 

    Myname = argv[0];

    while ((opt = getopt(argc, argv, "t:r:s:d")) != -1) {
        switch (opt) {
        case 't':
            if (sscanf(optarg, "%u", &num_threads) == EOF) {
                USAGE( "-t option error");
            }
            if (num_threads > MAX_THREADS) {
                fprintf( stderr, "using max threads %d\n", MAX_THREADS );
                num_threads = MAX_THREADS;
            }
            break;

        case 'r':
            if (sscanf(optarg, "%u", &runtime)==EOF) {
                USAGE("-r option error");
            }
            break;

        case 's':
            if (sscanf(optarg, "%u", &max_malloc)==EOF) 
                USAGE("-s option error");
            break;

        case 'd':
            Debug=TRUE;
            break;

        default:
            USAGE(NULL);
        } 
    } /* end while opt */

    if (optind >= argc)
        USAGE("No path given");
    path = argv[optind++];

    if (optind < argc)
        USAGE(NULL);

    /*
     * Use the alloc_init lib function to open the pool
     * via pmfs, and map it into our address space.
     * This returns a regular (absolute) pointer.
     */
    if ((pmp = pmemalloc_init(path, POOL_SIZE)) == NULL)
        FATALSYS("pmemalloc_init on %s", path);

	/*
     * Fetch our static info.
     * The first word is used to store a relative pointer to
     * the mailbox array.  The library function converts this
     * to an absolute pointer.
     */
    sa_ptr = (void**)pmemalloc_static_area(pmp);

    /* The static area for a new pmem pool is zero'd */
    if (*sa_ptr == NULL) {
        /*
         * Create and initialize the mailbox array in PM
         */
        if ((mbx_offset_=pmemalloc_reserve(pmp,
                            sizeof(mailbox_array_t))) == NULL )
            FATALSYS("pmemalloc mailbox array");
        /*
         * Place a pointer to this array in the first word of the
         * static area on activation
         */
        pmemalloc_onactive( pmp, mbx_offset_, (void**)sa_ptr, mbx_offset_ );
        pmemalloc_activate( pmp, mbx_offset_ );
        
        /* Set the static, regular pointer to be used in the program */
        mbx_array_ptr = PMEM( pmp, mbx_offset_ );

        for (thrd=0; thrd<MAX_THREADS; ++thrd) {
            for (mbx=0; mbx<MAILBOXES; ++mbx) {
                (*mbx_array_ptr)[thrd][mbx] = NULL;
            }
        }
     } else {
         /*
          * This region already exists from a previous run.
          * Free any pmem spaces still in the mailbox.
          */
         mbx_array_ptr = PMEM( pmp, (mailbox_array_t*)*sa_ptr );
         for (thrd=0; thrd<MAX_THREADS; ++thrd) {
             for (mbx=0; mbx<MAILBOXES; ++mbx) {
                 if ((*mbx_array_ptr)[thrd][mbx] != NULL) {
                     pmemalloc_onfree( pmp,
                                    (*mbx_array_ptr)[thrd][mbx],
                                    &(*mbx_array_ptr)[thrd][mbx],
                                    NULL );
                     pmemalloc_free( pmp, (*mbx_array_ptr)[thrd][mbx] );
                 }
             }
         }
    }
    /* Commit the initialized mailbox to persistent media */
    pmem_persist( mbx_array_ptr, sizeof(mailbox_array_t), 0 );

    DEBUG( "Number of threads = %d", num_threads);
    DEBUG( "Runtime: %d seconds", runtime );
    DEBUG( "Max alloc size %d bytes", max_malloc );

    /*
     * Create each allocating thread.  Each allocating thread
     * will create its corresponding freeing thread.
     * Once each each thread is created, signal the start condition
     * so they all start running around the same time.
     */
    for (thrd=0; thrd<num_threads; ++thrd) {
        retval = pthread_create( &alloc_threads[thrd],
                    NULL,
                    alloc_main,
                    (void *) thrd );
        if (retval) {
            errno = retval;
            FATALSYS( "alloc thread create %d\n", thrd );
        }
    }

    /* Give the new threads a chance to start */
    sleep(0);

    pthread_mutex_lock( &start_lock );
    b_start_flag = TRUE;
    pthread_cond_broadcast( &start_cv );
    pthread_mutex_unlock( &start_lock );

    /* Let run for the desired seconds then tell all threads to stop */
    sleep( runtime );
    b_all_stop = TRUE;

    /* Wait for each alloating thread to complete. */
    for (thrd=0; thrd<num_threads; ++thrd) {
        retval = pthread_join( alloc_threads[thrd], NULL );
        if (retval) {
            errno = retval;
            FATALSYS( "Allocating thread JOIN %d", thrd );
        }
    }

    /* Commit the final mailbox array to persistent media */
    pmem_persist( mbx_array_ptr, sizeof(mailbox_array_t), 0 );

    DEBUG("Done.");
	exit(0);
}
Beispiel #12
0
int main(int argc, char *argv[]) {
  const char *path;
  int opt;
  int fflag = 0;
  int iflag = 0;
  unsigned long icount;
  void *pmp;
  struct static_info *sp;
  struct node *parent_;
  struct node *np_;

  Myname = argv[0];
  while ((opt = getopt(argc, argv, "FMdfi:")) != -1) {
    switch (opt) {
      case 'F':
        pmem_fit_mode();
        break;

      case 'M':
        pmem_msync_mode();
        break;

      case 'd':
        Debug++;
        break;

      case 'f':
        fflag++;
        break;

      case 'i':
        iflag++;
        icount = strtoul(optarg, NULL, 10);
        break;

      default:
        USAGE(NULL);
    }
  }

  if (optind >= argc)
    USAGE("No path given");
  path = argv[optind++];

  if ((pmp = pmemalloc_init(path, MY_POOL_SIZE)) == NULL)
    FATALSYS("pmemalloc_init on %s", path);

  /* fetch our static info */
  sp = (struct static_info *) pmemalloc_static_area(pmp);

  if (optind < argc) { /* numbers supplied as arguments? */
    int i;

    if (fflag)
      USAGE("unexpected extra arguments given with -f flag");

    if (iflag)
      icount_start(icount); /* start instruction count */

    for (i = optind; i < argc; i++) {
      int value = atoi(argv[i]);

      if ((np_ = pmemalloc_reserve(pmp, sizeof(*np_))) == NULL)
        FATALSYS("pmemalloc_reserve");

      /* link it in at the beginning of the list */
      PMEM(pmp, np_)->next_ = sp->rootnp_;
      PMEM(pmp, np_)->value = value;
      pmemalloc_onactive(pmp, np_, (void **) &sp->rootnp_, np_);
      pmemalloc_activate(pmp, np_);
    }

    if (iflag) {
      icount_stop(); /* end instruction count */

      printf("Total instruction count: %lu\n", icount_total());
    }
  } else if (fflag) {
    /*
     * remove first item from list
     */
    if (sp->rootnp_ == NULL)
      FATAL("the list is empty");

    if (iflag)
      icount_start(icount); /* start instruction count */

    np_ = sp->rootnp_;
    pmemalloc_onfree(pmp, np_, (void **) &sp->rootnp_, PMEM(pmp, np_)->next_);
    pmemalloc_free(pmp, np_);

    if (iflag) {
      icount_stop(); /* end instruction count */

      printf("Total instruction count: %lu\n", icount_total());
    }
  } else {
    char *sep = "";

    /*
     * traverse the list, printing the numbers found
     */
    np_ = sp->rootnp_;
    while (np_) {
      printf("%s%d", sep, PMEM(pmp, np_)->value);
      sep = " ";
      np_ = PMEM(pmp, np_)->next_;
    }
    printf("\n");
  }

  DEBUG("Done.");
  exit(0);
}