static int createEndpoints(int argc, char **argv) { cchar *endpoint; char *ip; int argind, port, secure; ip = 0; port = -1; endpoint = 0; argind = 0; if ((app->appweb = maCreateAppweb()) == 0) { mprLog("error appweb", 0, "Cannot create HTTP service"); return MPR_ERR_CANT_CREATE; } if ((app->server = maCreateServer(app->appweb, "default")) == 0) { mprLog("error appweb", 0, "Cannot create HTTP server"); return MPR_ERR_CANT_CREATE; } loadStaticModules(); mprGC(MPR_GC_FORCE | MPR_GC_COMPLETE); if (argind == argc) { if (maParseConfig(app->server, app->configFile, 0) < 0) { return MPR_ERR_CANT_CREATE; } } else { app->documents = sclone(argv[argind++]); if (argind == argc) { if (maConfigureServer(app->server, NULL, app->home, app->documents, NULL, ME_HTTP_PORT, 0) < 0) { return MPR_ERR_CANT_CREATE; } } else while (argind < argc) { endpoint = argv[argind++]; mprParseSocketAddress(endpoint, &ip, &port, &secure, 80); if (maConfigureServer(app->server, NULL, app->home, app->documents, ip, port, 0) < 0) { return MPR_ERR_CANT_CREATE; } } } if (app->workers >= 0) { mprSetMaxWorkers(app->workers); } /* Call any ESP initializers from slink.c */ appwebStaticInitialize(); #if ME_WIN_LIKE writePort(app->server); #elif ME_UNIX_LIKE addSignals(); #endif mprGC(MPR_GC_FORCE | MPR_GC_COMPLETE); return 0; }
static void endMark(MprTime start, int count, char *msg) { MprTime elapsed; elapsed = mprGetElapsedTime(start); mprPrintf("\t%-30s\t%13.2f\t%12.2f\n", msg, elapsed * 1000.0 / count, elapsed / 1000.0); mprGC(MPR_GC_FORCE | MPR_GC_COMPLETE); }
static int createEndpoints(int argc, char **argv) { HttpHost *host; HttpRoute *route; host = httpCreateHost(); httpSetDefaultHost(host); route = httpCreateRoute(host); httpSetHostDefaultRoute(host, route); httpFinalizeRoute(route); httpInitConfig(route); if (httpLoadConfig(route, app->configFile) < 0) { return MPR_ERR_CANT_CREATE; } mprGC(MPR_GC_FORCE | MPR_GC_COMPLETE); return 0; }
MAIN(ejsMain, int argc, char **argv, char **envp) { Mpr *mpr; EcCompiler *cp; Ejs *ejs; cchar *cmd, *className, *method, *homeDir, *logSpec, *traceSpec; char *argp, *searchPath, *modules, *name, *tok, *extraFiles; int nextArg, err, ecFlags, stats, merge, bind, noout, debug, optimizeLevel, warnLevel, strict, i, next; /* Initialize Multithreaded Portable Runtime (MPR) */ mpr = mprCreate(argc, argv, 0); app = mprAllocObj(App, manageApp); mprAddRoot(app); mprAddStandardSignals(); if (mprStart(mpr) < 0) { mprLog("ejs", 0, "Cannot start mpr services"); return EJS_ERR; } err = 0; className = 0; cmd = 0; method = 0; searchPath = 0; stats = 0; merge = 0; bind = 1; noout = 1; debug = 1; warnLevel = 1; optimizeLevel = 9; strict = 0; logSpec = 0; traceSpec = 0; app->files = mprCreateList(-1, 0); app->iterations = 1; argc = mpr->argc; argv = (char**) mpr->argv; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--bind")) { bind = 1; } else if (smatch(argp, "--class")) { if (nextArg >= argc) { err++; } else { className = argv[++nextArg]; } } else if (smatch(argp, "--chdir") || smatch(argp, "--home") || smatch(argp, "-C")) { if (nextArg >= argc) { err++; } else { homeDir = argv[++nextArg]; if (chdir((char*) homeDir) < 0) { mprLog("ejs", 0, "Cannot change directory to %s", homeDir); } } #if ME_UNIX_LIKE } else if (smatch(argp, "--chroot")) { /* Not documented or supported */ if (nextArg >= argc) { err++; } else { homeDir = mprGetAbsPath(argv[++nextArg]); if (chroot(homeDir) < 0) { if (errno == EPERM) { mprEprintf("%s: Must be super user to use the --chroot option", mprGetAppName(mpr)); } else { mprEprintf("%s: Cannot change change root directory to %s, errno %d", mprGetAppName(), homeDir, errno); } return 4; } } #endif } else if (smatch(argp, "--cmd") || smatch(argp, "-c")) { if (nextArg >= argc) { err++; } else { cmd = argv[++nextArg]; } #if ME_WIN_LIKE } else if (smatch(argp, "--cygroot")) { if (nextArg >= argc) { err++; } else { app->cygroot = sclone(argv[++nextArg]); } #endif } else if (smatch(argp, "--debug")) { debug = 1; } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); } else if (smatch(argp, "--files") || smatch(argp, "-f")) { /* Compatibility with mozilla shell */ if (nextArg >= argc) { err++; } else { extraFiles = sclone(argv[++nextArg]); name = stok(extraFiles, " \t", &tok); while (name != NULL) { mprAddItem(app->files, sclone(name)); name = stok(NULL, " \t", &tok); } } } else if (smatch(argp, "--iterations") || smatch(argp, "-i")) { if (nextArg >= argc) { err++; } else { app->iterations = atoi(argv[++nextArg]); } } else if (smatch(argp, "--log")) { if (nextArg >= argc) { err++; } else { logSpec = argv[++nextArg]; } } else if (smatch(argp, "--method")) { if (nextArg >= argc) { err++; } else { method = argv[++nextArg]; } } else if (smatch(argp, "--name")) { /* Just ignore. Used to tag commands with a unique command line */ nextArg++; } else if (smatch(argp, "--nobind")) { bind = 0; } else if (smatch(argp, "--nodebug")) { debug = 0; } else if (smatch(argp, "--optimize")) { if (nextArg >= argc) { err++; } else { optimizeLevel = atoi(argv[++nextArg]); } } else if (smatch(argp, "--require")) { if (nextArg >= argc) { err++; } else { if (app->modules == 0) { app->modules = mprCreateList(-1, 0); } modules = sclone(argv[++nextArg]); name = stok(modules, " \t", &tok); while (name != NULL) { require(name); name = stok(NULL, " \t", &tok); } } } else if (smatch(argp, "-s")) { /* Compatibility with mozilla shell. Just ignore */ } else if (smatch(argp, "--search") || smatch(argp, "--searchpath")) { if (nextArg >= argc) { err++; } else { searchPath = argv[++nextArg]; } } else if (smatch(argp, "--standard")) { strict = 0; } else if (smatch(argp, "--stats")) { stats = 1; } else if (smatch(argp, "--strict")) { strict = 1; } else if (smatch(argp, "--trace") || smatch(argp, "-t")) { if (nextArg >= argc) { err++; } else { traceSpec = argv[++nextArg]; } } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { logSpec = "stderr:2"; } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprPrintf("%s\n", EJS_VERSION); return 0; } else if (smatch(argp, "--warn")) { if (nextArg >= argc) { err++; } else { warnLevel = atoi(argv[++nextArg]); } } else if (*argp == '-' && isdigit((uchar) argp[1])) { if (!logSpec) { logSpec = sfmt("stderr:%d", (int) stoi(&argp[1])); } if (!traceSpec) { traceSpec = sfmt("stderr:%d", (int) stoi(&argp[1])); } } else { err++; break; } } if (err) { /* If --method or --class is specified, then the named class.method will be run (method defaults to "main", class defaults to first class with a "main"). Examples: ejs ejs script.es arg1 arg2 arg3 ejs --class "Customer" --method "start" --files "script1.es script2.es" main.es */ mprEprintf("Usage: %s [options] script.es [arguments] ...\n" " Ejscript shell program options:\n" " --class className # Name of class containing method to run\n" " --cmd ejscriptCode # Literal ejscript statements to execute\n" " --cygroot path # Set cygwin root for resolving script paths\n" " --debug # Use symbolic debugging information (default)\n" " --debugger # Disable timeouts to make using a debugger easier\n" " --files \"files..\" # Extra source to compile\n" " --log logSpec # Internal compiler diagnostics logging\n" " --method methodName # Name of method to run. Defaults to main\n" " --nodebug # Omit symbolic debugging information\n" " --optimize level # Set the optimization level (0-9 default is 9)\n" " --require 'module,...' # Required list of modules to pre-load\n" " --search ejsPath # Module search path\n" " --standard # Default compilation mode to standard (default)\n" " --stats # Print memory stats on exit\n" " --strict # Default compilation mode to strict\n" " --trace traceSpec # HTTP request tracing\n" " --verbose | -v # Same as --log stderr:2 \n" " --version # Emit the compiler version information\n" " --warn level # Set the warning message level (0-9 default is 0)\n\n", mpr->name); return -1; } if (logSpec) { mprStartLogging(logSpec, MPR_LOG_CMDLINE); } if (traceSpec) { httpCreate(HTTP_CLIENT_SIDE | HTTP_SERVER_SIDE); httpStartTracing(traceSpec); } if ((ejs = ejsCreateVM(argc - nextArg, (cchar **) &argv[nextArg], 0)) == 0) { return MPR_ERR_MEMORY; } mprStartDispatcher(ejs->dispatcher); app->ejs = ejs; if (ejsLoadModules(ejs, searchPath, app->modules) < 0) { return MPR_ERR_CANT_READ; } mprGC(MPR_GC_FORCE); ecFlags = 0; ecFlags |= (merge) ? EC_FLAGS_MERGE: 0; ecFlags |= (bind) ? EC_FLAGS_BIND: 0; ecFlags |= (noout) ? EC_FLAGS_NO_OUT: 0; ecFlags |= (debug) ? EC_FLAGS_DEBUG: 0; cp = app->compiler = ecCreateCompiler(ejs, ecFlags); if (cp == 0) { return MPR_ERR_MEMORY; } ecSetRequire(cp, app->modules); ecSetOptimizeLevel(cp, optimizeLevel); ecSetWarnLevel(cp, warnLevel); ecSetStrictMode(cp, strict); if (nextArg < argc) { mprAddItem(app->files, sclone(argv[nextArg])); } if (app->cygroot) { /* When cygwin invokes a script with shebang, it passes a cygwin path to the script The ejs --cygroot option permits ejscript to conver this to a native path */ for (next = 0; (name = mprGetNextItem(app->files, &next)) != 0; ) { if (*name == '/' || *name == '\\') { mprSetItem(app->files, next - 1, sjoin(app->cygroot, name, NULL)); } } } for (i = 0; !err && i < app->iterations; i++) { if (cmd) { if (interpretCommands(cp, cmd) < 0) { err++; } } else if (mprGetListLength(app->files) > 0) { if (interpretFiles(cp, app->files, argc - nextArg, &argv[nextArg], className, method) < 0) { err++; } } else { /* No args - run as an interactive shell */ if (interpretCommands(cp, NULL) < 0) { err++; } } } if (stats) { #if ME_DEBUG mprSetLogLevel(1); mprPrintMem("Memory Usage", 1); #endif } if (err) { mprSetExitStatus(err); } app->ejs = 0; app->compiler = 0; ejsDestroy(ejs); mprDestroy(); return mprGetExitStatus(); }
static void testMalloc() { MprTime start; char *ptr; int count, i, pin; #if KEEP ssize base; #endif mprPrintf("Alloc/Malloc overhead\n"); count = 2000000 * app->iterations; pin = 0; mprGC(MPR_GC_FORCE); #if MALLOC /* malloc(1) */ base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = malloc(1); if (pin) memset(ptr, 0, 1); } endMark(start, count, "Alloc malloc(1)"); mprPrintf("\tMalloc overhead per block %d\n\n", ((mprGetMem() - base) / count) - 1); /* malloc(8) */ base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = malloc(8); if (pin) memset(ptr, 0, 8); } endMark(start, count, "Alloc malloc(8)"); mprPrintf("\tMalloc overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 8); /* malloc(16) */ base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = malloc(16); if (pin) memset(ptr, 0, 16); } endMark(start, count, "Alloc malloc(16)"); mprPrintf("\tMalloc overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 16); /* malloc(32) */ base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = malloc(32); if (pin) memset(ptr, 0, 32); } endMark(start, count, "Alloc malloc(32)"); mprPrintf("\tMalloc overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 32); /* malloc+free(8) */ start = startMark(); for (i = 0; i < count; i++) { ptr = malloc(8); if (pin) memset(ptr, 0, 8); mprNop(ptr); free(ptr); } endMark(start, count, "Alloc malloc+free(8)"); mprPrintf("\n"); #endif /* mprAlloc(1) */ // base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = mprAlloc(1); if (pin) memset(ptr, 0, 1); } endMark(start, count, "Alloc mprAlloc(1)"); // mprPrintf("\tMpr overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 1); /* mprAlloc(8) */ // base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = mprAlloc(8); if (pin) memset(ptr, 0, 8); } endMark(start, count, "Alloc mprAlloc(8)"); // mprPrintf("\tMpr overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 8); /* mprAlloc(16) */ // base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = mprAlloc(16); if (pin) memset(ptr, 0, 16); } endMark(start, count, "Alloc mprAlloc(16)"); // mprPrintf("\tMpr overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 16); /* mprAlloc(32) */ // base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = mprAlloc(32); if (pin) memset(ptr, 0, 32); } endMark(start, count, "Alloc mprAlloc(32)"); // mprPrintf("\tMpr overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 32); /* mprAlloc(64) */ // base = mprGetMem(); start = startMark(); for (i = 0; i < count; i++) { ptr = mprAlloc(64); if (pin) memset(ptr, 0, 64); } endMark(start, count, "Alloc mprAlloc(32)"); // mprPrintf("\tMpr overhead per block %d (approx)\n\n", ((mprGetMem() - base) / count) - 64); mprPrintf("\n"); }
/* 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; }
/* The http timer does maintenance activities and will fire per second while there are active requests. This routine will also be called by httpTerminate with event == 0 to signify a shutdown. NOTE: Because we lock the http here, connections cannot be deleted while we are modifying the list. */ static void httpTimer(Http *http, MprEvent *event) { HttpConn *conn; HttpStage *stage; HttpLimits *limits; MprModule *module; int next, active, abort; updateCurrentDate(); /* Check for any inactive connections or expired requests (inactivityTimeout and requestTimeout) OPT - could check for expired connections every 10 seconds. */ lock(http->connections); for (active = 0, next = 0; (conn = mprGetNextItem(http->connections, &next)) != 0; active++) { limits = conn->limits; if (!conn->timeoutEvent) { abort = mprIsStopping(); if (httpServerConn(conn) && (HTTP_STATE_CONNECTED < conn->state && conn->state < HTTP_STATE_PARSED) && (http->now - conn->started) > limits->requestParseTimeout) { conn->timeout = HTTP_PARSE_TIMEOUT; abort = 1; } else if ((http->now - conn->lastActivity) > limits->inactivityTimeout) { conn->timeout = HTTP_INACTIVITY_TIMEOUT; abort = 1; } else if ((http->now - conn->started) > limits->requestTimeout) { conn->timeout = HTTP_REQUEST_TIMEOUT; abort = 1; } else if (!event) { /* Called directly from httpStop to stop connections */ if (MPR->exitTimeout > 0) { if (conn->state == HTTP_STATE_COMPLETE || (HTTP_STATE_CONNECTED < conn->state && conn->state < HTTP_STATE_PARSED)) { abort = 1; } } else { abort = 1; } } if (abort && !mprGetDebugMode()) { httpScheduleConnTimeout(conn); } } } /* Check for unloadable modules OPT - could check for modules every minute */ if (mprGetListLength(http->connections) == 0) { for (next = 0; (module = mprGetNextItem(MPR->moduleService->modules, &next)) != 0; ) { if (module->timeout) { if (module->lastActivity + module->timeout < http->now) { mprLog("info http", 2, "Unloading inactive module %s", module->name); if ((stage = httpLookupStage(module->name)) != 0) { if (mprUnloadModule(module) < 0) { active++; } else { stage->flags |= HTTP_STAGE_UNLOADED; } } else { mprUnloadModule(module); } } else { active++; } } } } httpPruneMonitors(); if (active == 0 || mprIsStopping()) { if (event) { mprRemoveEvent(event); } http->timer = 0; /* Going to sleep now, so schedule a GC to free as much as possible. */ mprGC(MPR_GC_FORCE | MPR_GC_NO_BLOCK); } else { mprGC(MPR_GC_NO_BLOCK); } unlock(http->connections); }