static void testInsertAndRemove(MprTestGroup *gp) { MprList *lp; int index; lp = mprCreateList(0, 0); tassert(lp != 0); /* Do one insert and remove */ index = mprAddItem(lp, (void*) 1); tassert(index >= 0); tassert(mprGetListLength(lp) == 1); mprRemoveItem(lp, (void*) 1); tassert(mprGetListLength(lp) == 0); /* Test remove will compact */ mprAddItem(lp, (void*) 1); mprAddItem(lp, (void*) 2); mprAddItem(lp, (void*) 3); mprRemoveItem(lp, (void*) 2); tassert(mprGetListLength(lp) == 2); mprRemoveItem(lp, (void*) 3); tassert(mprGetListLength(lp) == 1); }
int maInsertDir(MaHost *host, MaDir *newDir) { MaDir *dir; int rc, next; mprAssert(newDir); mprAssert(newDir->path); if (mprGetParent(host->dirs) == host->parent) { host->dirs = mprDupList(host, host->parent->dirs); } /* * Sort in reverse collating sequence. Must make sure that /abc/def sorts before /abc */ for (next = 0; (dir = mprGetNextItem(host->dirs, &next)) != 0; ) { mprAssert(dir->path); rc = strcmp(newDir->path, dir->path); if (rc == 0) { mprRemoveItem(host->dirs, dir); mprInsertItemAtPos(host->dirs, next, newDir); return 0; } else if (rc > 0) { mprInsertItemAtPos(host->dirs, next - 1, newDir); return 0; } } mprAddItem(host->dirs, newDir); return 0; }
int maInsertAlias(MaHost *host, MaAlias *newAlias) { MaAlias *alias, *old; int rc, next, index; if (mprGetParent(host->aliases) == host->parent) { host->aliases = mprDupList(host, host->parent->aliases); } /* * Sort in reverse collating sequence. Must make sure that /abc/def sorts before /abc. But we sort redirects with * status codes first. */ for (next = 0; (alias = mprGetNextItem(host->aliases, &next)) != 0; ) { rc = strcmp(newAlias->prefix, alias->prefix); if (rc == 0) { index = mprLookupItem(host->aliases, alias); old = (MaAlias*) mprGetItem(host->aliases, index); mprRemoveItem(host->aliases, alias); mprInsertItemAtPos(host->aliases, next - 1, newAlias); return 0; } else if (rc > 0) { if (newAlias->redirectCode >= alias->redirectCode) { mprInsertItemAtPos(host->aliases, next - 1, newAlias); return 0; } } } mprAddItem(host->aliases, newAlias); return 0; }
static void removeWorker(EjsWorker *worker) { Ejs *ejs; assert(!worker->inside); assert(worker); ejs = worker->ejs; if (ejs) { lock(ejs); if (ejs->workers) { mprRemoveItem(ejs->workers, worker); } if (ejs->joining) { mprSignalDispatcher(ejs->dispatcher); } /* Accelerate GC */ if (worker->pair) { worker->pair->ejs = 0; worker->pair->pair = 0; worker->pair = 0; } worker->ejs = 0; unlock(ejs); } }
static int deleteXmlListPropertyByName(Ejs *ejs, EjsXML *list, EjsName qname) { EjsXML *elt; int index, next; if (isdigit((uchar) qname.name->value[0]) && allDigitsForXmlList(qname.name)) { index = ejsAtoi(ejs, qname.name, 10); elt = (EjsXML*) mprGetItem(list->elements, index); if (elt) { if (elt->parent) { if (elt->kind == EJS_XML_ATTRIBUTE) { ejsDeletePropertyByName(ejs, (EjsObj*) elt->parent, elt->qname); } else { // TODO - let q be the property of parent where parent[q] == x[i] mprRemoveItem(elt->parent->elements, elt); elt->parent = 0; } } } // Spec says return true even if index is out of range. We return 0 for true and < 0 for false. // TODO - should ejs throw? return 0; } for (next = 0; (elt = mprGetNextItem(list->elements, &next)) != 0; ) { if (elt->kind == EJS_XML_ELEMENT /* && elt->parent */) { ejsDeletePropertyByName(ejs, (EjsObj*) elt /* TODO was elt->parent */, qname); } } return 0; }
int maAddLocation(MaHost *host, MaLocation *newLocation) { MaLocation *location; int next, rc; mprAssert(newLocation); mprAssert(newLocation->prefix); if (mprGetParent(host->locations) == host->parent) { host->locations = mprDupList(host, host->parent->locations); } /* * Sort in reverse collating sequence. Must make sure that /abc/def sorts before /abc */ for (next = 0; (location = mprGetNextItem(host->locations, &next)) != 0; ) { rc = strcmp(newLocation->prefix, location->prefix); if (rc == 0) { mprRemoveItem(host->locations, location); mprInsertItemAtPos(host->locations, next - 1, newLocation); return 0; } if (strcmp(newLocation->prefix, location->prefix) > 0) { mprInsertItemAtPos(host->locations, next - 1, newLocation); return 0; } } mprAddItem(host->locations, newLocation); return 0; }
void ejsDestroyVM(Ejs *ejs) { EjsService *sp; EjsState *state; EjsModule *mp; ejs->destroying = 1; sp = ejs->service; if (sp) { while ((mp = mprGetFirstItem(ejs->modules)) != 0) { ejsRemoveModule(ejs, mp); } assure(ejs->modules->length == 0); ejsRemoveWorkers(ejs); state = ejs->state; if (state && state->stackBase) { mprVirtFree(state->stackBase, state->stackSize); state->stackBase = 0; ejs->state = 0; } mprRemoveItem(sp->vmlist, ejs); ejs->service = 0; ejs->result = 0; if (ejs->dispatcher) { mprDisableDispatcher(ejs->dispatcher); } } mprLog(6, "ejs: destroy VM"); }
static void completeCommand(MprCmd *cmd) { /* After removing the command from the cmds list, it can be garbage collected if no other reference is retained */ cmd->complete = 1; mprDisconnectCmd(cmd); mprRemoveItem(MPR->cmdService->cmds, cmd); }
void mprUnloadModule(MprModule *mp) { mprAssert(mp->handle); mprStopModule(mp); mprRemoveItem(mprGetMpr(mp)->moduleService->modules, mp); if (mp->handle) { FreeLibrary((HINSTANCE) mp->handle); mp->handle = 0; } }
static void removeWorker(Ejs *ejs, EjsWorker *worker) { mprAssert(ejs == worker->ejs); mprAssert(!worker->inside); mprAssert(worker); lock(ejs); mprRemoveItem(ejs->workers, worker); if (ejs->joining) { mprWakeDispatcher(ejs->dispatcher); } unlock(ejs); }
int maRemoveUserFromGroup(MaGroup *gp, cchar *user) { char *name; int next; for (next = 0; (name = mprGetNextItem(gp->users, &next)) != 0; ) { if (strcmp(name, user) == 0) { mprRemoveItem(gp->users, name); return 0; } } return MPR_ERR_CANT_ACCESS; }
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; }
void ejsRemoveModuleFromAll(EjsModule *mp) { Ejs *ejs; EjsService *sp; int next; if ((sp = MPR->ejsService) == 0) { return; } lock(sp); for (ITERATE_ITEMS(sp->vmlist, ejs, next)) { mprRemoveItem(ejs->modules, mp); } unlock(sp); }
PUBLIC void mprRemoveWaitHandler(MprWaitHandler *wp) { if (wp && wp->service) { if (!mprIsStopped()) { /* It needs special handling for the shutdown case when the locks have been removed */ if (wp->fd >= 0 && wp->desiredMask) { mprNotifyOn(wp, 0); } mprRemoveItem(wp->service->handlers, wp); } wp->fd = INVALID_SOCKET; } }
PUBLIC int mprUnloadModule(MprModule *mp) { mprDebug("mpr", 5, "Unloading native module %s from %s", mp->name, mp->path); if (mprStopModule(mp) < 0) { return MPR_ERR_NOT_READY; } #if ME_COMPILER_HAS_DYN_LOAD if (mp->flags & MPR_MODULE_LOADED) { if (mprUnloadNativeModule(mp) != 0) { mprLog("error mpr", 0, "Cannot unload module %s", mp->name); } } #endif mprRemoveItem(MPR->moduleService->modules, mp); return 0; }
int mprUnloadModule(MprModule *mp) { mprLog(6, "Unloading native module %s from %s", mp->name, mp->path); if (mprStopModule(mp) < 0) { return MPR_ERR_NOT_READY; } #if BIT_HAS_DYN_LOAD if (mp->handle) { if (mprUnloadNativeModule(mp) != 0) { mprError("Can't unload module %s", mp->name); } mp->handle = 0; } #endif mprRemoveItem(MPR->moduleService->modules, mp); return 0; }
static void filterDirList(HttpConn *conn, MprList *list) { Dir *dir; MprDirEntry *dp; int next; dir = conn->data; /* Do pattern matching. Entries that don't match, free the name to mark */ for (next = 0; (dp = mprGetNextItem(list, &next)) != 0; ) { if (! match(dir->pattern, dp->name)) { mprRemoveItem(list, dp); next--; } } }
static void filterDirList(HttpConn *conn, MprList *list) { Dir *dir; MprDirEntry *dp; int next; dir = conn->data; /* Do pattern matching. Entries that don't match, free the name to mark */ for (ITERATE_ITEMS(list, dp, next)) { if (!matchDirPattern(dir->pattern, dp->name)) { mprRemoveItem(list, dp); next--; } } }
static void testLotsOfInserts(MprTestGroup *gp) { MprList *lp; int i; lp = mprCreateList(LIST_MAX_ITEMS, 0); tassert(lp != 0); /* Do lots insertions */ for (i = 0; i < LIST_MAX_ITEMS; i++) { mprAddItem(lp, (void*) (long) i); tassert(mprGetListLength(lp) == (i + 1)); } /* Now remove */ for (i = LIST_MAX_ITEMS - 1; i >= 0; i--) { mprRemoveItem(lp, (void*) (long) i); tassert(mprGetListLength(lp) == i); } }
PUBLIC void httpRemoveConn(HttpConn *conn) { mprRemoveItem(HTTP->connections, conn); }
/* This routine runs a command and waits for its completion. Stdoutput and Stderr are returned in *out and *err respectively. The command returns the exit status of the command. Valid flags are: MPR_CMD_NEW_SESSION Create a new session on Unix MPR_CMD_SHOW Show the commands window on Windows MPR_CMD_IN Connect to stdin */ PUBLIC int mprRunCmdV(MprCmd *cmd, int argc, cchar **argv, cchar **envp, cchar *in, char **out, char **err, MprTicks timeout, int flags) { ssize len; int rc, status; assert(cmd); if (in) { flags |= MPR_CMD_IN; } if (err) { *err = 0; flags |= MPR_CMD_ERR; } else { flags &= ~MPR_CMD_ERR; } if (out) { *out = 0; flags |= MPR_CMD_OUT; } else { flags &= ~MPR_CMD_OUT; } if (flags & MPR_CMD_OUT) { cmd->stdoutBuf = mprCreateBuf(ME_BUFSIZE, -1); } if (flags & MPR_CMD_ERR) { cmd->stderrBuf = mprCreateBuf(ME_BUFSIZE, -1); } mprSetCmdCallback(cmd, defaultCmdCallback, NULL); rc = mprStartCmd(cmd, argc, argv, envp, flags); if (in) { len = slen(in); if (mprWriteCmdBlock(cmd, MPR_CMD_STDIN, in, len) != len) { *err = sfmt("Cannot write to command %s", cmd->program); return MPR_ERR_CANT_WRITE; } } if (cmd->files[MPR_CMD_STDIN].fd >= 0) { mprFinalizeCmd(cmd); } if (rc < 0) { if (err) { if (rc == MPR_ERR_CANT_ACCESS) { *err = sfmt("Cannot access command %s", cmd->program); } else if (rc == MPR_ERR_CANT_OPEN) { *err = sfmt("Cannot open standard I/O for command %s", cmd->program); } else if (rc == MPR_ERR_CANT_CREATE) { *err = sfmt("Cannot create process for %s", cmd->program); } } return rc; } if (cmd->flags & MPR_CMD_DETACH) { return 0; } if (mprWaitForCmd(cmd, timeout) < 0) { mprRemoveItem(MPR->cmdService->cmds, cmd); return MPR_ERR_NOT_READY; } if ((status = mprGetCmdExitStatus(cmd)) < 0) { mprRemoveItem(MPR->cmdService->cmds, cmd); return MPR_ERR; } if (err && flags & MPR_CMD_ERR) { *err = mprGetBufStart(cmd->stderrBuf); } if (out && flags & MPR_CMD_OUT) { *out = mprGetBufStart(cmd->stdoutBuf); } return status; }
/* * 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; }
PUBLIC void mprDestroyCmd(MprCmd *cmd) { assert(cmd); resetCmd(cmd, 0); mprRemoveItem(MPR->cmdService->cmds, cmd); }
static EjsWorker *initWorker(Ejs *ejs, EjsWorker *worker, Ejs *baseVM, cchar *name, EjsArray *search, cchar *scriptFile) { Ejs *wejs; EjsWorker *self; EjsName sname; static int workerSeqno = 0; ejsBlockGC(ejs); if (worker == 0) { worker = ejsCreateWorker(ejs); } worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; if (name) { worker->name = sclone(name); } else { lock(ejs); worker->name = sfmt("worker-%d", workerSeqno++); unlock(ejs); } /* Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. The worker interpreter gets a new dispatcher */ if (baseVM) { if ((wejs = ejsCloneVM(baseVM)) == 0) { ejsThrowMemoryError(ejs); return 0; } } else { if ((wejs = ejsCreateVM(0, 0, ejs->flags)) == 0) { ejsThrowMemoryError(ejs); return 0; } if (ejsLoadModules(wejs, 0, 0) < 0) { return 0; } } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = sjoin("inside-", worker->name, NULL); #if MOB mprEnableDispatcher(wejs->dispatcher); #endif if (search) { ejsSetSearchPath(ejs, (EjsArray*) search); } // TODO - these should be don't delete ejsSetProperty(ejs, worker, ES_Worker_name, ejsCreateStringFromAsc(ejs, self->name)); ejsSetProperty(wejs, self, ES_Worker_name, ejsCreateStringFromAsc(wejs, self->name)); sname = ejsName(wejs, EJS_WORKER_NAMESPACE, "self"); ejsSetPropertyByName(wejs, wejs->global, sname, self); /* Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->global, NULL, EJS_WORKER_NAMESPACE); addWorker(ejs, worker); if (scriptFile) { worker->scriptFile = sclone(scriptFile); worker->state = EJS_WORKER_STARTED; if (mprCreateEvent(wejs->dispatcher, "workerMain", 0, (MprEventProc) workerMain, self, 0) < 0) { mprRemoveItem(ejs->workers, worker); ejsThrowStateError(ejs, "Cannot create worker event"); return 0; } } return worker; }
void ejsRemoveModule(Ejs *ejs, EjsModule *mp) { mprRemoveItem(ejs->modules, mp); }
PUBLIC void httpRemoveEndpoint(HttpEndpoint *endpoint) { mprRemoveItem(HTTP->endpoints, endpoint); }
PUBLIC void httpRemoveHost(HttpHost *host) { mprRemoveItem(HTTP->hosts, host); }
void maRemoveEndpoint(MaServer *server, HttpEndpoint *endpoint) { mprRemoveItem(server->endpoints, endpoint); }
/* function listen(endpoint): Void An endpoint can be either a "port" or "ip:port", or null. If hosted, this call does little -- just add to the ejs->httpServers list. */ static EjsVoid *hs_listen(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv) { HttpEndpoint *endpoint; HttpHost *host; HttpRoute *route; EjsString *address; EjsObj *loc; EjsPath *documents; if (!sp->hosted) { loc = (argc >= 1) ? argv[0] : ESV(null); if (loc != ESV(null)) { address = ejsToString(ejs, loc); // TODO should permit https://IP:PORT mprParseSocketAddress(address->value, &sp->ip, &sp->port, NULL, 0); } else { address = 0; } if (address == 0) { ejsThrowArgError(ejs, "Missing listen endpoint"); return 0; } if (sp->endpoint) { httpDestroyEndpoint(sp->endpoint); sp->endpoint = 0; } /* The endpoint uses the ejsDispatcher. This is VERY important. All connections will inherit this also. This serializes all activity on one dispatcher. */ if ((endpoint = httpCreateEndpoint(sp->ip, sp->port, ejs->dispatcher)) == 0) { ejsThrowIOError(ejs, "Cannot create Http endpoint object"); return 0; } sp->endpoint = endpoint; host = httpCreateHost(NULL); httpSetHostName(host, sfmt("%s:%d", sp->ip, sp->port)); route = httpCreateConfiguredRoute(host, 1); httpAddRouteMethods(route, "DELETE, HEAD, OPTIONS, PUT"); httpAddRouteHandler(route, "ejsHandler", ""); httpSetRouteTarget(route, "run", 0); httpFinalizeRoute(route); httpSetHostDefaultRoute(host, route); httpAddHostToEndpoint(endpoint, host); if (sp->limits) { ejsSetHttpLimits(ejs, endpoint->limits, sp->limits, 1); } if (sp->incomingStages || sp->outgoingStages || sp->connector) { setHttpPipeline(ejs, sp); } if (sp->ssl) { httpSecureEndpoint(endpoint, sp->ssl); } if (sp->name) { httpSetHostName(host, sp->name); } httpSetSoftware(EJS_HTTPSERVER_NAME); httpSetEndpointAsync(endpoint, sp->async); httpSetEndpointContext(endpoint, sp); httpSetEndpointNotifier(endpoint, stateChangeNotifier); /* This is only required when http is using non-ejs handlers and/or filters */ documents = ejsGetProperty(ejs, sp, ES_ejs_web_HttpServer_documents); if (ejsIs(ejs, documents, Path)) { httpSetRouteDocuments(route, documents->value); } #if KEEP // TODO -- what to do with home? // TODO - if removed, then the "home" property should be removed? home = ejsGetProperty(ejs, sp, ES_ejs_web_HttpServer_home); if (ejsIs(ejs, home, Path)) { httpSetRoutDir(host, home->value); } #endif if (httpStartEndpoint(endpoint) < 0) { httpDestroyEndpoint(sp->endpoint); sp->endpoint = 0; ejsThrowIOError(ejs, "Cannot listen on %s", address->value); } } if (ejs->httpServers == 0) { ejs->httpServers = mprCreateList(-1, MPR_LIST_STATIC_VALUES); } /* Remove to make sure old listening() registrations are removed */ mprRemoveItem(ejs->httpServers, sp); mprAddItem(ejs->httpServers, sp); 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; }