static void standardSignalHandler(void *ignored, MprSignal *sp) { mprLog(6, "standardSignalHandler signo %d, flags %x", sp->signo, sp->flags); if (sp->signo == SIGTERM) { mprTerminate(MPR_EXIT_GRACEFUL, -1); } else if (sp->signo == SIGINT) { #if BIT_UNIX_LIKE /* Ensure shell input goes to a new line */ if (isatty(1)) { if (write(1, "\n", 1) < 0) {} } #endif mprTerminate(MPR_EXIT_IMMEDIATE, -1); } else if (sp->signo == SIGUSR1) { mprTerminate(MPR_EXIT_GRACEFUL | MPR_EXIT_RESTART, 0); } else if (sp->signo == SIGPIPE || sp->signo == SIGXFSZ) { /* Ignore */ #if MACOSX && BIT_DEBUG } else if (sp->signo == SIGSEGV || sp->signo == SIGBUS) { printf("PAUSED for watson to debug\n"); sleep(120); #endif } else { mprTerminate(MPR_EXIT_DEFAULT, -1); } }
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; }
/* Exit the application static function exit(status: Number, how: String = "default"): void MOB - status is not implemented */ static EjsObj *app_exit(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { cchar *how; int status, mode; if (ejs->dontExit) { ejsThrowStateError(ejs, "App.exit has been disabled"); return 0; } status = argc >= 1 ? ejsGetInt(ejs, argv[0]) : 0; how = ejsToMulti(ejs, argc >= 2 ? ejsToString(ejs, argv[1]): ESV(empty)); if (scmp(how, "default") == 0) { mode = MPR_EXIT_DEFAULT; } else if (scmp(how, "immediate") == 0) { mode = MPR_EXIT_IMMEDIATE; } else if (scmp(how, "graceful") == 0) { mode = MPR_EXIT_GRACEFUL; } else { mode = MPR_EXIT_NORMAL; } mprTerminate(mode, status); ejsAttention(ejs); return 0; }
/* Wait for I/O on all registered descriptors. Timeout is in milliseconds. Return the number of events serviced. Should only be called by the thread that calls mprServiceEvents */ PUBLIC void mprWaitForIO(MprWaitService *ws, MprTicks timeout) { MSG msg; assert(ws->hwnd); if (timeout < 0 || timeout > MAXINT) { timeout = MAXINT; } #if BIT_DEBUG if (mprGetDebugMode() && timeout > 30000) { timeout = 30000; } #endif if (ws->needRecall) { mprDoWaitRecall(ws); return; } SetTimer(ws->hwnd, 0, (UINT) timeout, NULL); mprYield(MPR_YIELD_STICKY); if (GetMessage(&msg, NULL, 0, 0) == 0) { mprResetYield(); mprTerminate(MPR_EXIT_DEFAULT, -1); } else { mprClearWaiting(); mprResetYield(); TranslateMessage(&msg); DispatchMessage(&msg); } ws->wakeRequested = 0; }
static long msgProc(HWND hwnd, UINT msg, UINT wp, LPARAM lp) { MprThread *tp; char buf[MPR_MAX_FNAME]; switch (msg) { case WM_DESTROY: case WM_QUIT: mprTerminate(MPR_EXIT_GRACEFUL, -1); break; case APPWEB_MONITOR_MESSAGE: return monitorEvent(hwnd, wp, lp); case WM_COMMAND: switch (LOWORD(wp)) { case MA_MENU_STATUS: break; case MA_MENU_DOC: runBrowser("/doc/index.html"); break; case MA_MENU_MANAGE: runBrowser("/index.html"); break; case MA_MENU_START: tp = mprCreateThread("startService", startService, 0, 0); mprStartThread(tp); break; case MA_MENU_STOP: tp = mprCreateThread("stopService", stopService, 0, 0); mprStartThread(tp); break; case MA_MENU_ABOUT: /* Single-threaded users beware. This blocks !! */ mprSprintf(buf, sizeof(buf), "%s %s-%s", BIT_TITLE, BIT_VERSION, BIT_BUILD_NUMBER); MessageBoxEx(hwnd, buf, mprGetAppTitle(), MB_OK, 0); break; case MA_MENU_EXIT: PostMessage(hwnd, WM_QUIT, 0, 0L); break; default: return (long) DefWindowProc(hwnd, msg, wp, lp); } break; default: return (long) DefWindowProc(hwnd, msg, wp, lp); } return 0; }
/* Catch signals. Do a graceful shutdown. */ static void catchSignal(int signo, siginfo_t *info, void *arg) { Mpr *mpr; mpr = mprGetMpr(); if (mpr) { #if DEBUG_IDE if (signo == SIGINT) return; #endif mprLog(mpr, 2, "Received signal %d", signo); if (signo == SIGTERM) { mprLog(mpr, 1, "Executing a graceful exit. Waiting for all requests to complete."); mprTerminate(mpr, 1); } else { mprLog(mpr, 1, "Exiting immediately ..."); mprTerminate(mpr, 0); } } }
static void finishThread(MprThread *tp) { if (tp) { mprLock(app->mutex); if (--app->activeLoadThreads <= 0) { mprTerminate(MPR_EXIT_DEFAULT, -1); } mprUnlock(app->mutex); } }
/** * Exit the application * * static function exit(status: Number): void */ static EjsVar *exitApp(Ejs *ejs, EjsVar *unused, int argc, EjsVar **argv) { int status; status = argc == 0 ? 0 : ejsGetInt(argv[0]); mprBreakpoint(); if (!ejs->dontExit) { if (status != 0) { exit(status); } else { mprTerminate(mprGetMpr(ejs), 1); } } return 0; }
/* Windows message processing loop for wakeup and socket messages */ static LRESULT msgProc(HWND hwnd, UINT msg, UINT wp, LPARAM lp) { MprWaitService *ws; int sock, winMask; ws = MPR->waitService; if (msg == WM_DESTROY || msg == WM_QUIT) { mprTerminate(MPR_EXIT_DEFAULT, -1); } else if (msg && msg == ws->socketMessage) { sock = wp; winMask = LOWORD(lp); mprServiceWinIO(MPR->waitService, sock, winMask); } else if (ws->msgCallback) { return ws->msgCallback(hwnd, msg, wp, lp); } else { return DefWindowProc(hwnd, msg, wp, lp); } return 0; }
MAIN(ejsMain, int argc, char **argv, char **envp) { Mpr *mpr; EcCompiler *cp; Ejs *ejs; cchar *cmd, *className, *method, *homeDir; 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) { mprError("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; 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) { mprError("Cannot change directory to %s", homeDir); } } #if BIT_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) { mprPrintfError("%s: Must be super user to use the --chroot option", mprGetAppName(mpr)); } else { mprPrintfError("%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 BIT_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 { mprStartLogging(argv[++nextArg], 0); mprSetCmdlineLogging(1); } } 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, "-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, "--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, "--verbose") || smatch(argp, "-v")) { mprStartLogging("stderr:2", 0); mprSetCmdlineLogging(1); } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprPrintf("%s-%s\n", BIT_VERSION, BIT_BUILD_NUMBER); return 0; } else if (smatch(argp, "--warn")) { if (nextArg >= argc) { err++; } else { warnLevel = atoi(argv[++nextArg]); } } 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 */ mprPrintfError("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" " --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 ((ejs = ejsCreateVM(argc - nextArg, (cchar **) &argv[nextArg], 0)) == 0) { return MPR_ERR_MEMORY; } app->ejs = ejs; if (ejsLoadModules(ejs, searchPath, app->modules) < 0) { return MPR_ERR_CANT_READ; } 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 BIT_DEBUG mprSetLogLevel(1); mprPrintMem("Memory Usage", 1); #endif } if (!err) { err = mpr->exitStatus; } app->ejs = 0; mprTerminate(MPR_EXIT_DEFAULT, err); ejsDestroyVM(ejs); mprDestroy(MPR_EXIT_DEFAULT); return err; }
MAIN(ejsMain, int argc, char **argv, char **envp) { Mpr *mpr; Ejs *ejs; EcCompiler *ec; char *argp, *searchPath, *path, *homeDir; int nextArg, err, flags; /* Initialize Multithreaded Portable Runtime (MPR) */ mpr = mprCreate(argc, argv, 0); app = mprAllocObj(App, manageApp); mprAddRoot(app); mprAddStandardSignals(); if (mprStart(mpr) < 0) { mprError("Cannot start mpr services"); return EJS_ERR; } err = 0; searchPath = 0; argc = mpr->argc; argv = (char**) mpr->argv; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--chdir") || smatch(argp, "--home") || smatch(argp, "-C")) { if (nextArg >= argc) { err++; } else { homeDir = argv[++nextArg]; if (chdir((char*) homeDir) < 0) { mprError("Cannot change directory to %s", homeDir); } } } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); } else if (smatch(argp, "--log")) { if (nextArg >= argc) { err++; } else { mprStartLogging(argv[++nextArg], 0); mprSetCmdlineLogging(1); } } else if (smatch(argp, "--name")) { /* Just ignore. Used to tag commands with a unique command line */ nextArg++; } else if (smatch(argp, "--search") || smatch(argp, "--searchpath")) { if (nextArg >= argc) { err++; } else { searchPath = argv[++nextArg]; } } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { mprStartLogging("stderr:1", 0); mprSetCmdlineLogging(1); } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprPrintf("%s-%s\n", BIT_VERSION, BIT_BUILD_NUMBER); return 0; } else { /* Ignore */ } } path = mprJoinPath(mprGetAppDir(), mprGetPathBase(argv[0])); path = mprReplacePathExt(path, ".es"); mprAddRoot(path); argv[0] = path; if ((ejs = ejsCreateVM(argc, (cchar **) &argv[0], 0)) == 0) { return MPR_ERR_MEMORY; } app->ejs = ejs; if (ejsLoadModules(ejs, searchPath, NULL) < 0) { return MPR_ERR_CANT_READ; } mprLog(2, "Load script \"%s\"", path); flags = EC_FLAGS_BIND | EC_FLAGS_DEBUG | EC_FLAGS_NO_OUT | EC_FLAGS_THROW; if ((ec = ecCreateCompiler(ejs, flags)) == 0) { return MPR_ERR_MEMORY; } mprAddRoot(ec); ecSetOptimizeLevel(ec, 9); ecSetWarnLevel(ec, 1); if (ecCompile(ec, 1, (char**) &path) < 0) { if (flags & EC_FLAGS_THROW) { ejsThrowSyntaxError(ejs, "%s", ec->errorMsg ? ec->errorMsg : "Cannot parse script"); ejsReportError(ejs, "Error in script"); } err = MPR_ERR; } else { mprRemoveRoot(ec); if (ejsRunProgram(ejs, NULL, NULL) < 0) { ejsReportError(ejs, "Error in script"); err = MPR_ERR; } } if (!err) { err = mpr->exitStatus; } app->ejs = 0; mprTerminate(MPR_EXIT_DEFAULT, err); ejsDestroyVM(ejs); mprDestroy(MPR_EXIT_DEFAULT); return err; }