/* * 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 ); }
/* * 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); }
/* * 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 }
/* * 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); }
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 */ }
/* * 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); } }
/* * 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); }
/* * 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; }
/* * 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); }
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); }