📄 mtask.c
字号:
/* * @(#)mtask.c 1.37 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <string.h>#include <sys/types.h>#include <fcntl.h>#include <signal.h>#include <unistd.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/wait.h>#include <sys/select.h>#include <errno.h>#include "javavm/export/jni.h"#include "javavm/export/cvm.h"#include "portlibs/ansi_c/java.h"#include "portlibs/posix/mtask.h"#include <jump_messaging.h>#include <dlfcn.h>#include "porting/JUMPMessageQueue.h"#include "porting/JUMPProcess.h"#include "zip_util.h"/* A non-blocking pipe that child() uses to notify the main loop. */static int child_pipe_write;static int child_pipe_read;/* Fd that main loop messages will arrive on. */static int message_fd;/* * Free (argc, argv[]) set */static voidfreeArgs(int argc, char** argv){ int i; for (i = 0; i < argc; i++) { if (argv[i] != NULL) { free(argv[i]); argv[i] = NULL; } } free(argv);}static voidsetupRequest(JNIEnv*env, int argc, char** argv, CVMInt32 clientId){ char* appclasspathStr = NULL; char* bootclasspathStr = NULL; JavaVMInitArgs* clientArgs; char* parse; int cpadd; clientArgs = ANSIargvToJinitArgs(argc - 1, argv + 1, &appclasspathStr, &bootclasspathStr); /* Now take this set of init args, and parse them */ parse = CVMparseCommandLineOptions(env, clientArgs, clientArgs->nOptions); if (parse != NULL) { /* If the parse failed for some reason, the parser must have already printed out the necessary message on the console. Exit with an error code. */ fprintf(stderr, "Exiting JVM\n"); exit(1); } /* The JVM state now reflects the arguments. Also amend the classpath setting with the value that we read from appclasspathStr and bootclasspathStr */ cpadd = CVMclassClassPathAppend(env, appclasspathStr, bootclasspathStr); if (!cpadd) { /* If the class path add failed for some reason, the system must have already printed out the necessary message on the console. Exit with an error code. */ fprintf(stderr, "Exiting JVM\n"); exit(1); } /* Initialize child VM */ CVMmtaskReinitializeChildVM(env, clientId); /* Free up the (argc,arv[]) and jInitArgs that we have built */ ANSIfreeJinitArgs(clientArgs); freeArgs(argc, argv); /* Now we are ready to execute code */#ifdef CVM_TIMESTAMPING if (clientId != 0) { CVMmtaskTimeStampRecord(env, "Child Created", -1); }#endif}static void child(int sig);/* * Task management */typedef enum _ProcType { PROCTYPE_JAVA = 1, PROCTYPE_NATIVE} ProcType;typedef struct _TaskRec { int pid; char* command; /* is it a native process or JVM? */ ProcType procType; /* testing mode specific snapshot of prefix */ char* testingModeFilePrefixSnapshot; struct _TaskRec* next; /* Any other task info? */} TaskRec;/* Single process for the mtask server, so these globals are OK */static int numTasks = 0;static TaskRec* taskList = NULL;static volatile int reapChildrenFlag = 0;static int executivePid = -1;static int amExecutive = 0;static char* executiveTestingModeFilePrefixSnapshot = NULL;/* * Handle exiting children so they don't hang around as zombies. */static void child(int sig){ int pid = getpid(); char buffer = 'A'; fprintf(stderr, "Received SIGCHLD in PID=%d\n", pid); reapChildrenFlag = 1; /* Non-blocking write, just ignore any error. */ write(child_pipe_write, &buffer, 1);}static void dumpTaskOneWithFp(TaskRec* task, FILE *fp, int verbose){ if (verbose) { fprintf(fp, "[Task pid=%d, command=\"%s\"(0x%x)]\n", task->pid, task->command, (unsigned int)task->command); } else { fprintf(fp, "PID=%d COMMAND=\"%s\"\n", task->pid, task->command); }}static void dumpTaskIntoMessage(JUMPOutgoingMessage m, TaskRec* task){ char str[256]; snprintf(str, 256, "PID=%d COMMAND=\"%s\"", task->pid, task->command); jumpMessageAddString(m, str);}static voiddumpTaskOne(TaskRec* task){ // Verbose printout on stderr dumpTaskOneWithFp(task, stderr, 1);}static voidfreeTask(TaskRec* task){ fprintf(stderr, "FREEING TASK: "); dumpTaskOne(task); free(task->command); if (task->testingModeFilePrefixSnapshot != NULL) { free(task->testingModeFilePrefixSnapshot); } free(task); numTasks--;}/* * Find TaskRec corresponding to given pid */static TaskRec* findTaskFromPid(int taskPid){ TaskRec* task; for (task = taskList; task != NULL; task = task->next) { if (task->pid == taskPid) { return task; } } return NULL;}/* * removeTask with a given pid * * Called after the SIGCHLD signal handler signaled that there are * children exiting */static voidremoveTask(int taskPid){ TaskRec* task; TaskRec* taskPrev = NULL; for (task = taskList; task != NULL; taskPrev = task, task = task->next) { if (task->pid == taskPid) { if (taskPrev == NULL) { /* The first item in the list */ taskList = task->next; } else { taskPrev->next = task->next; } freeTask(task); return; } }}/* * Create log file off of 'prefix', named 'kind' for 'pid' * Return fd */static intcreateLogFile(char* prefix, char* kind, int pid){ /* We want to open files for stdout, stderr, and exit codes. */ int prefixLen = strlen(prefix) + 1; const int maxPidLen = 6; const int kindLength = strlen(kind) + 1; const int maxFileLen = prefixLen + maxPidLen + kindLength; char* fileName = calloc(1, maxFileLen); int fd; if (fileName == NULL) { fprintf(stderr, "Out of memory trying to open log file %s\n", fileName); return -1; } sprintf(fileName, "%s/%s.%d", prefix, kind, pid); /*fprintf(stderr, "%s fileName = %s\n", kind, fileName);*/ fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd == -1) { perror(fileName); } return fd;}static FILE*makeLineBufferedStream(int socket){ FILE* stream; stream = fdopen(socket, "w"); if (stream != NULL) { setvbuf(stream, NULL, _IOLBF, BUFSIZ); } return stream;} static voidprintExitStatusString(FILE* out, int status){ if (WIFEXITED(status)) { fprintf(out, "<exit code %d>\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { fprintf(out, "<uncaught signal %d>\n", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { fprintf(out, "<stopped with signal %d>\n", WSTOPSIG(status)); } } /* * Send executive a lifecycle message indicating that a child has terminated. */static voidnotifyTermination(int cpid) { JUMPOutgoingMessage message; JUMPAddress executiveAddr; JUMPMessageStatusCode statusCode; message = jumpMessageNewOutgoingByType("mvm/lifecycle", &statusCode); jumpMessageAddString(message, "IsolateDestroyed"); /* ID_ISOLATE_DESTROYED */ jumpMessageAddInt(message, 0); /* String[] data length */ jumpMessageAddInt(message, cpid); /* isolateId */ jumpMessageAddInt(message, 0); /* appID */ executiveAddr.processId = executivePid; jumpMessageSendAsync(executiveAddr, message, &statusCode); jumpMessageFreeOutgoing(message);}/* * The signal handler indicated there are children to reap. Do it. * Return last status reaped. */static intdoReapChildren(ServerState* state, int options){ int cpid, status; struct rusage ru; /* Reset the flag early. If the signal handler re-raises this, we will discover this in the next iteration of reapChildren() */ reapChildrenFlag = 0; while ((cpid = wait3(&status, options, &ru)) > 0) { int exitcodefd; /* Notify the executive about the isolate termination */ if (cpid != executivePid) { notifyTermination(cpid); } /* This had better be one of ours */ assert((executivePid == cpid) || (findTaskFromPid(cpid) != NULL)); fprintf(stderr, "Reaping child process %d\n", cpid); jumpMessageQueueCleanQueuesOf(cpid); printExitStatusString(stderr, status); fprintf(stderr, "\t user time %ld.%02d sec\n", ru.ru_utime.tv_sec, (int)(ru.ru_utime.tv_usec / 1000 / 10)); fprintf(stderr, "\t sys time %ld.%02d sec\n", ru.ru_stime.tv_sec, (int)(ru.ru_stime.tv_usec / 1000 / 10)); fprintf(stderr, "\t max res set %ld\n", ru.ru_maxrss);#if 0 fprintf(stderr, "\t integral shared mem size %ld\n", ru.ru_ixrss); fprintf(stderr, "\t integral unshared data size %ld\n", ru.ru_idrss); fprintf(stderr, "\t integral unshared stack size %ld\n", ru.ru_isrss);#endif fprintf(stderr, "\t page reclaims (minor faults) %ld\n", ru.ru_minflt); fprintf(stderr, "\t page faults (major) %ld\n", ru.ru_majflt); fprintf(stderr, "\t swaps %ld\n", ru.ru_nswap);#if 0 fprintf(stderr, "\t block input operations %ld\n", ru.ru_inblock); fprintf(stderr, "\t block output operations %ld\n", ru.ru_oublock);#endif if (state->isTestingMode) { TaskRec* task = findTaskFromPid(cpid); char* testingModeFilePrefixSnapshot; /* Now make a record, but only if TESTING_MODE was executed _prior_ to launching this currently reaped task. We can't apply current testing mode to an app that did not know about it */ if (executivePid == cpid) { testingModeFilePrefixSnapshot = executiveTestingModeFilePrefixSnapshot; } else { testingModeFilePrefixSnapshot = task->testingModeFilePrefixSnapshot; } if (testingModeFilePrefixSnapshot != NULL) { /* Use the snapshot of the file prefix created at launch */ exitcodefd = createLogFile(testingModeFilePrefixSnapshot, "exitcode", cpid); if (exitcodefd == -1) { perror("exitcodefile"); } else { FILE* exitcodefile = makeLineBufferedStream(exitcodefd); printExitStatusString(exitcodefile, status); fclose(exitcodefile); close(exitcodefd); } } } if (executivePid == cpid) { /* Get rid of all traces */ executivePid = -1; if (executiveTestingModeFilePrefixSnapshot != NULL) { free(executiveTestingModeFilePrefixSnapshot); executiveTestingModeFilePrefixSnapshot = NULL; } } else { removeTask(cpid); } } return status;}static voidreapChildren(ServerState* state){ doReapChildren(state, WNOHANG);}/* * A new task has been created */static intaddTask(JNIEnv* env, ServerState* state, int taskPid, char* command, ProcType type){ TaskRec* task; task = (TaskRec*)calloc(1, sizeof(TaskRec)); if (task == NULL) { return JNI_FALSE; } task->pid = taskPid; task->command = command; task->procType = type; /* Take a snapshot of the testing mode prefix here */ if (state->isTestingMode) { task->testingModeFilePrefixSnapshot = strdup(state->testingModeFilePrefix); if (task->testingModeFilePrefixSnapshot == NULL) { fprintf(stderr, "Could not allocate file prefix snapshot\n"); free(task->command); free(task); return JNI_FALSE; } } else { task->testingModeFilePrefixSnapshot = NULL; }#if 0 fprintf(stderr, "Added task=0x%x: [pid=%d, \"%s\"(0x%x)]\n", task, taskPid, task->command, (unsigned int)task->command);#endif numTasks++; /* Insert at the head */ task->next = taskList; taskList = task; return JNI_TRUE;}static CVMBoolkillTaskFromTaskRec(TaskRec* task){#if 0 /* * Message based exit * Not so robust, so commenting out for now. */ return sendMessageToTask(task, "EXIT");#else if (kill(task->pid, SIGKILL) == -1) { perror("kill"); return CVM_FALSE; } /* Killing is "best effort" and needs to be verified via Java, preferably using Xlet.getState() api's */ return CVM_TRUE;#endif}static CVMBoolkillTask(int taskPid){ TaskRec* task; task = findTaskFromPid(taskPid); if (task == NULL) { return CVM_FALSE; } return killTaskFromTaskRec(task);}static CVMBoolkillAllTasks(){ TaskRec* task; CVMBool result = CVM_TRUE; for (task = taskList; task != NULL; task = task->next) { if (!killTaskFromTaskRec(task)) { result = CVM_FALSE; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -