static int mprAllocException(MPR_LOC_DEC(ctx, loc), uint size, bool granted) { MprApp *app; MprAlloc *alloc; int rc; mprAssert(VALID_BLK(ctx)); app = mprGetApp(ctx); alloc = &app->alloc; if (alloc->cback == 0) { return 0; } mprLock(app->allocLock); if (alloc->inAllocException == 0) { alloc->inAllocException = 1; mprUnlock(app->allocLock); rc = (alloc->cback)(app, size, alloc->stats.bytesAllocated, granted); mprLock(app->allocLock); app->alloc.inAllocException = 0; mprUnlock(app->allocLock); return rc; } return 0; }
bool mprStop(Mpr *mpr) { int stopped; stopped = 1; mprLock(mpr->mutex); if (! (mpr->flags & MPR_STARTED) || (mpr->flags & MPR_STOPPED)) { mprUnlock(mpr->mutex); return 0; } mpr->flags |= MPR_STOPPED; /* Trigger graceful termination. This will prevent further tasks and events being created. */ mprTerminate(mpr, 1); #if BLD_FEATURE_HTTP mprStopHttpService(mpr->httpService); #endif mprStopSocketService(mpr->socketService); #if BLD_FEATURE_MULTITHREAD if (!mprStopWorkerService(mpr->workerService, MPR_TIMEOUT_STOP_TASK)) { stopped = 0; } if (!mprStopThreadService(mpr->threadService, MPR_TIMEOUT_STOP_TASK)) { stopped = 0; } #endif mprStopModuleService(mpr->moduleService); mprStopOsService(mpr->osService); return stopped; }
MprCmd *mprCreateCmd(MprCtx ctx) { MprCmdService *cs; MprCmd *cmd; MprCmdFile *files; int i; cmd = mprAllocObjWithDestructorZeroed(ctx, MprCmd, cmdDestructor); if (cmd == 0) { return 0; } cmd->completeCond = mprCreateCond(cmd); cmd->timeoutPeriod = MPR_TIMEOUT_CMD; cmd->timestamp = mprGetTime(cmd); cmd->forkCallback = (MprForkCallback) closeFiles; #if VXWORKS cmd->startCond = semCCreate(SEM_Q_PRIORITY, SEM_EMPTY); cmd->exitCond = semCCreate(SEM_Q_PRIORITY, SEM_EMPTY); #endif files = cmd->files; for (i = 0; i < MPR_CMD_MAX_PIPE; i++) { files[i].clientFd = -1; files[i].fd = -1; } #if BLD_FEATURE_MULTITHREAD cmd->mutex = mprCreateLock(cmd); #endif cs = mprGetMpr(ctx)->cmdService; mprLock(cs->mutex); mprAddItem(cs->cmds, cmd); mprUnlock(cs->mutex); return cmd; }
static void sslDynLock(int mode, DynLock *dl, cchar *file, int line) { if (mode & CRYPTO_LOCK) { mprLock(dl->mutex); } else { mprUnlock(dl->mutex); } }
/* Timer callback */ static void timerCallback(void *data, MprEvent *event) { mprLock(app->mutex); if (--app->markCount == 0) { mprSignalCond(app->complete); } mprRemoveEvent(event); mprUnlock(app->mutex); }
/* * Timer callback */ static void timerCallback(void *data, MprEvent *event) { mprLock(mutex); if (--markCount == 0) { mprSignalCond(complete); } mprStopContinuousEvent(event); mprUnlock(mutex); }
static void waitForUser() { int c; mprLock(app->mutex); mprPrintf("Pause: "); if (read(0, (char*) &c, 1) < 0) {} mprUnlock(app->mutex); }
static int reportResponse(HttpConn *conn, cchar *url, MprTime elapsed) { HttpRx *rx; MprOff bytesRead; char *responseHeaders; int status; if (mprShouldAbortRequests(conn)) { return 0; } app->status = status = httpGetStatus(conn); bytesRead = httpGetContentLength(conn); if (bytesRead < 0 && conn->rx) { bytesRead = conn->rx->bytesRead; } mprLog(6, "Response status %d, elapsed %Ld", status, elapsed); if (conn->error) { app->success = 0; } if (conn->rx && bytesRead > 0) { if (!app->noout) { mprPrintf("\n"); } if (app->showHeaders) { responseHeaders = httpGetHeaders(conn); rx = conn->rx; mprPrintf("%s %d %s\n", conn->protocol, status, rx->statusMessage); if (responseHeaders) { mprPrintf("%s\n", responseHeaders); } } else if (app->showStatus) { mprPrintf("%d\n", status); } } if (status < 0) { mprError("Can't process request for \"%s\" %s", url, httpGetError(conn)); return MPR_ERR_CANT_READ; } else if (status == 0 && conn->protocol == 0) { /* Ignore */; } else if (!(200 <= status && status <= 206) && !(301 <= status && status <= 304)) { if (!app->zeroOnErrors) { app->success = 0; } if (!app->showStatus) { mprError("Can't process request for \"%s\" (%d) %s", url, status, httpGetError(conn)); return MPR_ERR_CANT_READ; } } mprLock(app->mutex); if (app->verbose && app->noout) { trace(conn, url, app->fetchCount, app->method, status, bytesRead); } mprUnlock(app->mutex); return 0; }
static void finishThread(MprThread *tp) { if (tp) { mprLock(app->mutex); if (--app->activeLoadThreads <= 0) { mprTerminate(MPR_EXIT_DEFAULT, -1); } mprUnlock(app->mutex); } }
static void finishThread(MprThread *tp) { if (tp) { mprLock(app->mutex); if (--app->activeLoadThreads <= 0) { mprShutdown(MPR_EXIT_NORMAL, 0, 0); } mprUnlock(app->mutex); } }
/* Event callback */ static void eventCallback(void *data, MprEvent *event) { // TODO - should have atomic Inc mprLock(app->mutex); if (--app->markCount == 0) { mprSignalCond(app->complete); } mprRemoveEvent(event); mprUnlock(app->mutex); }
/* * Full host name with domain. E.g. "server.domain.com" */ void mprSetHostName(MprCtx ctx, cchar *s) { Mpr *mpr; mpr = mprGetMpr(ctx); mprLock(mpr->mutex); mprFree(mpr->hostName); mpr->hostName = mprStrdup(mpr, s); mprUnlock(mpr->mutex); return; }
static bool iterationsComplete() { mprLock(app->mutex); if (app->verbose > 1) mprPrintf("."); if (++app->fetchCount >= app->iterations) { mprUnlock(app->mutex); return 1; } mprUnlock(app->mutex); return 0; }
/* Wait for the event to be triggered when there may be multiple waiters. This routine may return early due to other signals or events. The caller must verify if the signalled condition truly exists. If the event is already triggered, then it will return immediately. This call will not reset cp->triggered and must be reset manually. A timeout of -1 means wait forever. Timeout of 0 means no wait. Returns 0 if the event was signalled. Returns < 0 for a timeout. WARNING: On unix, the pthread_cond_timedwait uses an absolute time (Ugh!). So time-warps for daylight-savings may cause waits to prematurely return. */ PUBLIC int mprWaitForMultiCond(MprCond *cp, MprTicks timeout) { int rc; #if ME_UNIX_LIKE struct timespec waitTill; struct timeval current; int usec; #else MprTicks now, expire; #endif if (timeout < 0) { timeout = MAXINT; } #if ME_UNIX_LIKE gettimeofday(¤t, NULL); usec = current.tv_usec + ((int) (timeout % 1000)) * 1000; waitTill.tv_sec = current.tv_sec + ((int) (timeout / 1000)) + (usec / 1000000); waitTill.tv_nsec = (usec % 1000000) * 1000; #else now = mprGetTicks(); expire = now + timeout; #endif #if ME_WIN_LIKE rc = WaitForSingleObject(cp->cv, (int) (expire - now)); if (rc == WAIT_OBJECT_0) { rc = 0; } else if (rc == WAIT_TIMEOUT) { rc = MPR_ERR_TIMEOUT; } else { rc = MPR_ERR; } #elif VXWORKS rc = semTake(cp->cv, (int) (expire - now)); if (rc != 0) { if (errno == S_objLib_OBJ_UNAVAILABLE) { rc = MPR_ERR_TIMEOUT; } else { rc = MPR_ERR; } } #elif ME_UNIX_LIKE mprLock(cp->mutex); rc = pthread_cond_timedwait(&cp->cv, &cp->mutex->cs, &waitTill); if (rc == ETIMEDOUT) { rc = MPR_ERR_TIMEOUT; } else if (rc != 0) { rc = MPR_ERR; } mprUnlock(cp->mutex); #endif return rc; }
static void sslStaticLock(int mode, int n, cchar *file, int line) { assert(0 <= n && n < numLocks); if (olocks) { if (mode & CRYPTO_LOCK) { mprLock(olocks[n]); } else { mprUnlock(olocks[n]); } } }
static int cmdDestructor(MprCmd *cmd) { MprCmdService *cs; resetCmd(cmd); #if VXWORKS vxCmdDestructor(cmd); #endif cs = mprGetMpr(cmd)->cmdService; mprLock(cs->mutex); mprRemoveItem(cs->cmds, cmd); mprUnlock(cs->mutex); return 0; }
PUBLIC void mprStopModuleService() { MprModuleService *ms; MprModule *mp; int next; ms = MPR->moduleService; assert(ms); mprLock(ms->mutex); for (next = 0; (mp = mprGetNextItem(ms->modules, &next)) != 0; ) { mprStopModule(mp); } mprUnlock(ms->mutex); }
PUBLIC void mprResetCond(MprCond *cp) { mprLock(cp->mutex); cp->triggered = 0; #if ME_WIN_LIKE ResetEvent(cp->cv); #elif VXWORKS semDelete(cp->cv); cp->cv = semCCreate(SEM_Q_PRIORITY, SEM_EMPTY); #else pthread_cond_destroy(&cp->cv); pthread_cond_init(&cp->cv, NULL); #endif mprUnlock(cp->mutex); }
static void testCriticalSection(MprTestGroup *gp) { int i, size; mprLock(mutex); size = sizeof(critical) / sizeof(MprThread*); for (i = 0; i < size; i++) { critical[i] = mprGetCurrentOsThread(); } for (i = 0; i < size; i++) { assert(critical[i] == mprGetCurrentOsThread()); } mprUnlock(mutex); }
/* Signal a condition and wakeup the waiter. Note: this may be called prior to the waiter waiting. */ PUBLIC void mprSignalCond(MprCond *cp) { mprLock(cp->mutex); if (!cp->triggered) { cp->triggered = 1; #if ME_WIN_LIKE SetEvent(cp->cv); #elif VXWORKS semGive(cp->cv); #else pthread_cond_signal(&cp->cv); #endif } mprUnlock(cp->mutex); }
/* Signal a condition and wakeup the all the waiters. Note: this may be called before or after to the waiter waiting. */ PUBLIC void mprSignalMultiCond(MprCond *cp) { mprLock(cp->mutex); #if ME_WIN_LIKE /* Pulse event */ SetEvent(cp->cv); ResetEvent(cp->cv); #elif VXWORKS /* Reset sem count and then give once. Prevents accumulation */ while (semTake(cp->cv, 0) == OK) ; semGive(cp->cv); semFlush(cp->cv); #else pthread_cond_broadcast(&cp->cv); #endif mprUnlock(cp->mutex); }
static void slabFree(MprBlk *bp) { MprSlab *slab; MprApp *app; void *ptr; int slabIndex; mprAssert(VALID_HDR(bp)); slabIndex = GET_SLAB(bp->size); mprAssert(0 <= slabIndex && slabIndex < MPR_MAX_SLAB); if (0 <= slabIndex && slabIndex < MPR_MAX_SLAB) { mprLock(bp->app->allocLock); slab = &bp->app->alloc.slabs[slabIndex]; app = bp->app; #if BLD_DEBUG memset(bp, 0xfc, bp->size + HDR_SIZE); #endif ptr = GET_PTR(bp); ((MprSlabBlock*) ptr)->next = slab->next; slab->next = ((MprSlabBlock*) ptr); #if BLD_FEATURE_ALLOC_STATS { MprSlabStats *slabStats; slabStats = &slab->stats; slabStats->freeCount++; slabStats->allocCount--; if (slabStats->freeCount >= slabStats->peakFreeCount) { slabStats->peakFreeCount = slabStats->freeCount; } } #endif mprUnlock(app->allocLock); } }
/* Wait for the event to be triggered. Should only be used when there are single waiters. If the event is already triggered, then it will return immediately. Timeout of -1 means wait forever. Timeout of 0 means no wait. Returns 0 if the event was signalled. Returns < 0 for a timeout. WARNING: On unix, the pthread_cond_timedwait uses an absolute time (Ugh!). So time-warps for daylight-savings may cause waits to prematurely return. */ PUBLIC int mprWaitForCond(MprCond *cp, MprTicks timeout) { MprTicks now, expire; int rc; #if ME_UNIX_LIKE struct timespec waitTill; struct timeval current; int usec; #endif /* Avoid doing a mprGetTicks() if timeout is < 0 */ rc = 0; if (timeout >= 0) { if (timeout > MAXINT) { timeout = MAXINT; } now = mprGetTicks(); expire = now + timeout; if (expire < 0) { expire = MPR_MAX_TIMEOUT; } #if ME_UNIX_LIKE gettimeofday(¤t, NULL); usec = current.tv_usec + ((int) (timeout % 1000)) * 1000; waitTill.tv_sec = current.tv_sec + ((int) (timeout / 1000)) + (usec / 1000000); waitTill.tv_nsec = (usec % 1000000) * 1000; #endif } else { expire = -1; now = 0; } mprLock(cp->mutex); /* NOTE: The WaitForSingleObject and semTake APIs keeps state as to whether the object is signalled. WaitForSingleObject and semTake will not block if the object is already signalled. However, pthread_cond_ is different and does not keep such state. If it is signalled before pthread_cond_wait, the thread will still block. Consequently we need to keep our own state in cp->triggered. This also protects against spurious wakeups which can happen (on windows). */ do { #if ME_WIN_LIKE /* Regardless of the state of cp->triggered, we must call WaitForSingleObject to consume the signalled internal state of the object. */ mprUnlock(cp->mutex); rc = WaitForSingleObject(cp->cv, (int) (expire - now)); mprLock(cp->mutex); if (rc == WAIT_OBJECT_0) { rc = 0; ResetEvent(cp->cv); } else if (rc == WAIT_TIMEOUT) { rc = MPR_ERR_TIMEOUT; } else { rc = MPR_ERR; } #elif VXWORKS /* Regardless of the state of cp->triggered, we must call semTake to consume the semaphore signalled state */ mprUnlock(cp->mutex); rc = semTake(cp->cv, (int) (expire - now)); mprLock(cp->mutex); if (rc != 0) { if (errno == S_objLib_OBJ_UNAVAILABLE) { rc = MPR_ERR_TIMEOUT; } else { rc = MPR_ERR; } } #elif ME_UNIX_LIKE /* The pthread_cond_wait routines will atomically unlock the mutex before sleeping and will relock on awakening. WARNING: pthreads may do spurious wakeups without being triggered */ if (!cp->triggered) { do { if (now) { rc = pthread_cond_timedwait(&cp->cv, &cp->mutex->cs, &waitTill); } else { rc = pthread_cond_wait(&cp->cv, &cp->mutex->cs); } } while ((rc == 0 || rc == EAGAIN) && !cp->triggered); if (rc == ETIMEDOUT) { rc = MPR_ERR_TIMEOUT; } else if (rc == EAGAIN) { rc = 0; } else if (rc != 0) { mprLog("error mpr thread", 0, "pthread_cond_timedwait error rc %d", rc); rc = MPR_ERR; } } #endif } while (!cp->triggered && rc == 0 && (!now || (now = mprGetTicks()) < expire)); if (cp->triggered) { cp->triggered = 0; rc = 0; } else if (rc == 0) { rc = MPR_ERR_TIMEOUT; } mprUnlock(cp->mutex); return rc; }
void *mprReallocBlock(MPR_LOC_DEC(ctx, loc), void *ptr, uint size) { MprBlk *bp, *newbp, *firstChild, *cp; MprApp *app; void *newPtr; mprAssert(VALID_BLK(ctx)); mprAssert(size > 0); if (ptr == 0) { return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size); } mprAssert(VALID_BLK(ptr)); bp = GET_HDR(ptr); mprAssert(bp); mprAssert(VALID_HDR(bp)); CHECK_HDR(bp); if (size < bp->size) { return ptr; } newPtr = mprAllocBlock(MPR_LOC_PASS(ctx, loc), size); if (newPtr == 0) { bp->flags &= ~ALLOC_FLAGS_FREE; free(bp); return 0; } newbp = GET_HDR(newPtr); mprAssert(newbp->size >= size); memcpy((char*) newbp + HDR_SIZE, (char*) bp + HDR_SIZE, bp->size); mprAssert(newbp->size >= size); /* * Fix the next / prev pointers */ app = bp->app; mprLock(app->allocLock); newbp->next->prev = newbp; newbp->prev->next = newbp; /* * Need to fix the parent pointer of all children */ if ((firstChild = newbp->children) != 0) { cp = firstChild; do { cp->parent = newbp; cp = cp->next; } while (cp != firstChild); } /* * May need to set the children pointer of our parent */ if (newbp->parent->children == bp) { newbp->parent->children = newbp; } /* * Free the original block */ mprFree(ptr); mprUnlock(app->allocLock); return GET_PTR(newbp); }
void *mprSlabAllocBlock(MPR_LOC_DEC(ctx, loc), uint size, uint inc) { #if NO_SLAB return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size); #else MprBlk *parent, *bp; MprSlabBlock *sb; MprApp *app; MprSlab *slab; int slabIndex; if (ctx == 0) { mprAssert(ctx); return 0; } mprAssert(size > 0); mprAssert(VALID_BLK(ctx)); parent = GET_HDR(ctx); mprAssert(VALID_HDR(parent)); CHECK_HDR(parent); size = SLAB_ALIGN(size); app = parent->app; mprAssert(app); slabIndex = GET_SLAB(size); if (slabIndex < 0 || slabIndex >= MPR_MAX_SLAB) { return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size); } /* * Dequeue a block from the slab. "sb" will point to the user data * portion of the block (i.e. after the MprBlk header). Slabs must be * allocated off the "slabs" context to ensure they don't get freed * until after all other blocks are freed. */ mprLock(app->allocLock); slab = &app->alloc.slabs[slabIndex]; if ((sb = slab->next) == 0) { if (growSlab(MPR_LOC_ARGS(parent->app->alloc.slabs), slab, size, inc) < 0) { mprUnlock(app->allocLock); return 0; } sb = slab->next; } mprAssert(sb); /* * Dequeue the block */ slab->next = sb->next; #if BLD_FEATURE_ALLOC_STATS { MprSlabStats *slabStats; /* * Update the slab stats */ slabStats = &slab->stats; slabStats->totalAllocCount++; slabStats->freeCount--; slabStats->allocCount++; if (slabStats->allocCount > slabStats->peakAllocCount) { slabStats->peakAllocCount = slabStats->allocCount; } } #endif /* BLD_FEATURE_ALLOC_STATS */ bp = GET_HDR(sb); #if BLD_DEBUG && !BREW if (bp == stopAlloc) { mprBreakpoint(MPR_LOC, "breakOnAddr"); } #endif bp->size = size; bp->flags = ALLOC_MAGIC | ALLOC_FLAGS_SLAB_BLOCK; bp->destructor = 0; bp->parent = parent; if (parent->children == 0) { parent->children = bp; bp->next = bp->prev = bp; } else { /* * Append to the end of the list. Preserve alloc order */ bp->next = parent->children; bp->prev = parent->children->prev; parent->children->prev->next = bp; parent->children->prev = bp; } bp->children = 0; bp->app = app; #if BLD_FEATURE_ALLOC_LEAK_TRACK bp->location = loc; #endif mprUnlock(app->allocLock); return GET_PTR(bp); #endif }
// TODO - opt. Should be macro. static void lock(MaHost *host) { #if BLD_FEATURE_MULTITHREAD mprLock(host->mutex); #endif }
/* Big global lock. Avoid using this. */ PUBLIC void mprGlobalLock() { if (MPR && MPR->mutex) { mprLock(MPR->mutex); } }
/* * Do a performance benchmark */ static void doBenchmark(Mpr *mpr, void *thread) { MprTime start; MprList *list; void *mp; int count, i; #if BLD_FEATURE_MULTITHREAD MprMutex *lock; #endif complete = mprCreateCond(mpr); mprPrintf(mpr, "Group\t%-30s\t%13s\t%12s\n", "Benchmark", "Microsec", "Elapsed-sec"); /* * Alloc (1K) */ mprPrintf(mpr, "Alloc Benchmarks\n"); count = 2000000 * iterations; start = startMark(mpr); for (i = 0; i < count; i++) { mp = mprAlloc(mpr, 1024); memset(mp, 0, 1024); mprFree(mp); } endMark(mpr, start, count, "Alloc mprAlloc(1K)|mprFree"); start = startMark(mpr); #if BLD_FEATURE_MULTITHREAD /* * Locking primitives */ mprPrintf(mpr, "Lock Benchmarks\n"); lock = mprCreateLock(mpr); count = 5000000 * iterations; start = startMark(mpr); for (i = 0; i < count; i++) { mprLock(lock); mprUnlock(lock); } endMark(mpr, start, count, "Mutex lock|unlock"); mprFree(lock); /* * Condition signal / wait */ mprPrintf(mpr, "Cond Benchmarks\n"); count = 1000000 * iterations; start = startMark(mpr); mprResetCond(complete); for (i = 0; i < count; i++) { mprSignalCond(complete); mprWaitForCond(complete, -1); } endMark(mpr, start, count, "Cond signal|wait"); #endif /* * List */ mprPrintf(mpr, "List Benchmarks\n"); count = 500000 * iterations; list = mprCreateList(mpr); start = startMark(mpr); for (i = 0; i < count; i++) { mprAddItem(list, (void*) (long) i); mprRemoveItem(list, (void*) (long) i); } endMark(mpr, start, count, "Link insert|remove"); mprFree(list);; /* * Events */ mprPrintf(mpr, "Event Benchmarks\n"); mprResetCond(complete); count = 200000 * iterations; markCount = count; start = startMark(mpr); for (i = 0; i < count; i++) { mprCreateEvent(mprGetDispatcher(mpr), eventCallback, 0, 0, (void*) (long) i, 0); } endMark(mpr, start, count, "Event (create)"); mprWaitForCondWithService(complete, -1); endMark(mpr, start, count, "Event (run|delete)"); /* * Test timer creation, run and delete (make a million timers!) */ mprPrintf(mpr, "Timer\n"); mprResetCond(complete); count = 50000 * iterations; markCount = count; start = startMark(mpr); for (i = 0; i < count; i++) { mprCreateTimerEvent(mprGetDispatcher(mpr), timerCallback, 0, 0, (void*) (long) i, 0); } endMark(mpr, start, count, "Timer (create)"); mprWaitForCondWithService(complete, -1); endMark(mpr, start, count, "Timer (delete)"); testComplete = 1; }
int mprFree(void *ptr) { MprAllocStats *stats; MprBlk *bp, *parent, *cp, *firstChild, *prev; MprApp *app; if (ptr == 0) { return 0; } mprAssert(VALID_BLK(ptr)); VALIDATE_BLOCK(ptr); bp = GET_HDR(ptr); #if BLD_DEBUG && !BREW if (bp == stopAlloc) { mprBreakpoint(MPR_LOC, "breakOnAddr"); } #endif mprAssert(bp); mprAssert(VALID_HDR(bp)); CHECK_HDR(bp); /* * Test if already freed */ mprAssert(! (bp->flags & ALLOC_FLAGS_FREE)); if (bp->flags & ALLOC_FLAGS_FREE) { return 0; } /* * Return if recursive freeing or this is a permanent block */ app = bp->app; mprLock(app->allocLock); if (bp->flags & (ALLOC_FLAGS_FREEING | ALLOC_FLAGS_KEEP)) { mprUnlock(app->allocLock); return 0; } bp->flags |= ALLOC_FLAGS_FREEING; /* * Call any destructors */ if (bp->destructor) { mprUnlock(app->allocLock); if ((bp->destructor)(ptr) < 0) { return -1; } mprLock(app->allocLock); bp->destructor = 0; } /* * Free the children. Free in reverse order so firstChild is preserved * during the list scan as an end of list marker. */ if ((firstChild = bp->children) != 0) { cp = firstChild->prev; while (cp != firstChild) { mprAssert(VALID_HDR(cp)); VALIDATE_BLOCK(GET_PTR(cp)); prev = cp->prev; /* * FUTURE - OPT. Make this inline */ mprFree(GET_PTR(cp)); cp = prev; } mprFree(GET_PTR(firstChild)); /* * Just for clarity */ bp->children = 0; } parent = bp->parent; mprAssert(VALID_HDR(parent)); /* * Unlink from the parent */ if (parent->children == bp) { if (bp->next == bp) { parent->children = 0; } else { parent->children = bp->next; } } /* * Remove from the sibling chain */ bp->prev->next = bp->next; bp->next->prev = bp->prev; bp->flags |= ALLOC_FLAGS_FREE; /* * Release the memory. If from a slab, return to the slab. Otherwise, * return to the O/S. */ if (bp->flags & ALLOC_FLAGS_SLAB_BLOCK) { slabFree(bp); } else { mprAssert(bp); /* * Update the stats */ stats = &bp->app->alloc.stats; stats->bytesAllocated -= (bp->size + HDR_SIZE); mprAssert(stats->bytesAllocated >= 0); stats->allocCount--; mprAssert(stats->allocCount >= 0); #if BLD_DEBUG && !BREW if (bp == stopAlloc) { mprBreakpoint(MPR_LOC, "breakOnAddr"); } #endif /* * Return to the O/S */ if (! (bp->flags & ALLOC_FLAGS_DONT_OS_FREE)) { free(bp); } } /* OPT */ if (app != ptr) { mprUnlock(app->allocLock); } return 0; }
/* Do a performance benchmark */ static void doBenchmark(void *thread) { MprTime start; MprList *list; int count, i; MprMutex *lock; MprSpin *spin; mprPrintf("Group\t%-30s\t%13s\t%12s\n", "Benchmark", "Microsec", "Elapsed-sec"); testMalloc(); if (!app->testAllocOnly) { /* Locking primitives */ mprPrintf("Lock Benchmarks\n"); lock = mprCreateLock(); count = 5000000 * app->iterations; start = startMark(); for (i = 0; i < count; i++) { mprLock(lock); mprUnlock(lock); } endMark(start, count, "Mutex lock|unlock"); /* Locking primitives */ mprPrintf("Lock Benchmarks\n"); spin = mprCreateSpinLock(); count = 5000000 * app->iterations; start = startMark(); for (i = 0; i < count; i++) { mprSpinLock(spin); mprSpinUnlock(spin); } endMark(start, count, "Spin lock|unlock"); /* Condition signal / wait */ mprPrintf("Cond Benchmarks\n"); count = 1000000 * app->iterations; start = startMark(); mprResetCond(app->complete); for (i = 0; i < count; i++) { mprSignalCond(app->complete); mprWaitForCond(app->complete, -1); } endMark(start, count, "Cond signal|wait"); /* List */ mprPrintf("List Benchmarks\n"); count = 2000000 * app->iterations; list = mprCreateList(count, 0); start = startMark(); for (i = 0; i < count; i++) { mprAddItem(list, (void*) (long) i); mprRemoveItem(list, (void*) (long) i); } endMark(start, count, "Link insert|remove"); /* Events */ mprPrintf("Event Benchmarks\n"); mprResetCond(app->complete); count = 30000 * app->iterations; app->markCount = count; start = startMark(); for (i = 0; i < count; i++) { mprCreateEvent(NULL, "eventBenchmark", 0, eventCallback, ITOP(i), MPR_EVENT_QUICK); } mprWaitForCond(app->complete, -1); endMark(start, count, "Event (create|run|delete)"); /* Test timer creation, run and remove These create a new dispatcher and run a worker thread. */ mprPrintf("Timer\n"); mprResetCond(app->complete); count = 20000 * app->iterations; app->markCount = count; start = startMark(); for (i = 0; i < count; i++) { mprCreateTimerEvent(NULL, "timerBenchmark", 0, timerCallback, (void*) (long) i, 0); } mprWaitForCond(app->complete, -1); endMark(start, count, "Timer (create|delete)"); /* Alloc (1K) */ mprPrintf("Alloc 1K Benchmarks\n"); count = 2000000 * app->iterations; start = startMark(); for (i = 0; i < count; i++) { mprAlloc(1024); if ((i % 128) == 0) { mprGC(0); } } endMark(start, count, "Alloc mprAlloc(1K)"); } testComplete = 1; }