struct PP_Var nspawn_send_request(struct PP_Var req_var) { /* * naclprocess.js is required in order send requests to JavaScript. * If NACL_PROCESS is not set in the environment then we assume it is * not present and exit early. Without this check we would block forever * waiting for a response for the JavaScript side. * * Only check this once per process, as some programs (emacs) * engage in manipulation of the environment that may not be safely * read at all times. */ static int checked_for_nacl_process = 0; if (!checked_for_nacl_process) { const char* naclprocess = getenv("NACL_PROCESS"); if (naclprocess == NULL) { fprintf(stderr, "nspawn_send_request called without NACL_PROCESS set\n"); return PP_MakeNull(); } checked_for_nacl_process = 1; } int64_t id = get_request_id(); char req_id[64]; sprintf(req_id, "%lld", id); nspawn_dict_setstring(req_var, "id", req_id); struct NaClSpawnReply reply; pthread_mutex_init(&reply.mu, NULL); pthread_cond_init(&reply.cond, NULL); PSEventRegisterMessageHandler(req_id, &handle_reply, &reply); PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), req_var); nspawn_var_release(req_var); pthread_mutex_lock(&reply.mu); /* * Wait for response for JavaScript. This can block for an unbounded amount * of time (e.g. waiting for a response to waitpid). */ int error = pthread_cond_wait(&reply.cond, &reply.mu); pthread_mutex_unlock(&reply.mu); pthread_cond_destroy(&reply.cond); pthread_mutex_destroy(&reply.mu); PSEventRegisterMessageHandler(req_id, NULL, &reply); if (error != 0) { fprintf(stderr, "nspawn_send_request: pthread_cond_timedwait: %s\n", strerror(error)); return PP_MakeNull(); } return reply.result_var; }
void ExitHandshake(int status, void* user_data) { if (s_exit_message == NULL) return; PSEventRegisterMessageHandler(s_exit_message, MessageHandlerExit, NULL); /* exit message + ':' + num + \0 */ size_t message_len = strlen(s_exit_message) + 1 + 11 + 1; char* message = alloca(message_len); snprintf(message, message_len, "%s:%d", s_exit_message, status); pthread_mutex_lock(&s_exit_lock); PostMessageString(message); pthread_cond_wait(&s_exit_cond, &s_exit_lock); pthread_mutex_unlock(&s_exit_lock); }
int ProcessProperties(void) { /* Reset verbosity if passed in */ const char* verbosity = getenv("PS_VERBOSITY"); if (verbosity) PSInstanceSetVerbosity(atoi(verbosity)); /* Enable NaCl IO to map STDIN, STDOUT, and STDERR */ nacl_io_init_ppapi(PSGetInstanceId(), PSGetInterface); s_tty_prefix = getenv("PS_TTY_PREFIX"); if (s_tty_prefix) { s_tty_fd = open("/dev/tty", O_WRONLY); if (s_tty_fd >= 0) { PSEventRegisterMessageHandler(s_tty_prefix, MessageHandlerInput, NULL); const char* tty_resize = getenv("PS_TTY_RESIZE"); if (tty_resize) PSEventRegisterMessageHandler(tty_resize, MessageHandlerResize, NULL); char* tty_rows = getenv("PS_TTY_ROWS"); char* tty_cols = getenv("PS_TTY_COLS"); if (tty_rows && tty_cols) { char* end = tty_rows; int rows = strtol(tty_rows, &end, 10); if (*end != '\0' || rows < 0) { PSInstanceError("Invalid value for PS_TTY_ROWS: %s\n", tty_rows); } else { end = tty_cols; int cols = strtol(tty_cols, &end, 10); if (*end != '\0' || cols < 0) PSInstanceError("Invalid value for PS_TTY_COLS: %s\n", tty_cols); else HandleResize(cols, rows); } } else if (tty_rows || tty_cols) { PSInstanceError("PS_TTY_ROWS and PS_TTY_COLS must be set together\n"); } struct tioc_nacl_output handler; handler.handler = TtyOutputHandler; handler.user_data = NULL; ioctl(s_tty_fd, TIOCNACLOUTPUT, &handler); } else { PSInstanceError("Failed to open /dev/tty.\n"); } } /* Set default values */ setenv("PS_STDIN", "/dev/stdin", 0); setenv("PS_STDOUT", "/dev/stdout", 0); setenv("PS_STDERR", "/dev/console3", 0); int fd0 = open(getenv("PS_STDIN"), O_RDONLY); dup2(fd0, 0); int fd1 = open(getenv("PS_STDOUT"), O_WRONLY); dup2(fd1, 1); int fd2 = open(getenv("PS_STDERR"), O_WRONLY); dup2(fd2, 2); PSEventRegisterMessageHandler("jspipe1", MessageHandlerInput, NULL); PSEventRegisterMessageHandler("jspipe2", MessageHandlerInput, NULL); PSEventRegisterMessageHandler("jspipe3", MessageHandlerInput, NULL); s_exit_message = getenv("PS_EXIT_MESSAGE"); /* If PS_EXIT_MESSAGE is set in the environment then we perform a handshake * with JavaScript when program exits. */ if (s_exit_message != NULL) nacl_io_set_exit_callback(ExitHandshake, NULL); /* Set line buffering on stdout and stderr */ #if !defined(WIN32) setvbuf(stderr, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0); #endif return 1; }