src/share/bin/java.c::ReadKnownVMs
/*
* Read the jvm.cfg file and fill the knownJVMs[] array.
*
* The functionality of the jvm.cfg file is subject to change without
* notice and the mechanism will be removed in the future.
*
* The lexical structure of the jvm.cfg file is as follows:
*
* jvmcfg := { vmLine }
* vmLine := knownLine
* | aliasLine
* | warnLine
* | ignoreLine
* | errorLine
* | predicateLine
* | commentLine
* knownLine := flag "KNOWN" EOL
* warnLine := flag "WARN" EOL
* ignoreLine := flag "IGNORE" EOL
* errorLine := flag "ERROR" EOL
* aliasLine := flag "ALIASED_TO" flag EOL
* predicateLine := flag "IF_SERVER_CLASS" flag EOL
* commentLine := "#" text EOL
* flag := "-" identifier
*
* The semantics are that when someone specifies a flag on the command line:
* - if the flag appears on a knownLine, then the identifier is used as
* the name of the directory holding the JVM library (the name of the JVM).
* - if the flag appears as the first flag on an aliasLine, the identifier
* of the second flag is used as the name of the JVM.
* - if the flag appears on a warnLine, the identifier is used as the
* name of the JVM, but a warning is generated.
* - if the flag appears on an ignoreLine, the identifier is recognized as the
* name of a JVM, but the identifier is ignored and the default vm used
* - if the flag appears on an errorLine, an error is generated.
* - if the flag appears as the first flag on a predicateLine, and
* the machine on which you are running passes the predicate indicated,
* then the identifier of the second flag is used as the name of the JVM,
* otherwise the identifier of the first flag is used as the name of the JVM.
* If no flag is given on the command line, the first vmLine of the jvm.cfg
* file determines the name of the JVM.
* PredicateLines are only interpreted on first vmLine of a jvm.cfg file,
* since they only make sense if someone hasn't specified the name of the
* JVM on the command line.
*
* The intent of the jvm.cfg file is to allow several JVM libraries to
* be installed in different subdirectories of a single JRE installation,
* for space-savings and convenience in testing.
* The intent is explicitly not to provide a full aliasing or predicate
* mechanism.
*/
jint
ReadKnownVMs(const char *jvmCfgName, jboolean speculative)
{
FILE *jvmCfg;
char line[MAXPATHLEN+20];
int cnt = 0;
int lineno = 0;
jlong start, end;
int vmType;
char *tmpPtr;
char *altVMName = NULL;
char *serverClassVMName = NULL;
static char *whiteSpace = " \t";
if (JLI_IsTraceLauncher()) {
//获取定时器开始计数值
start = CounterGet();
}
//打开%JRE_HOME%\lib\${arch}\jvm.cfg
jvmCfg = fopen(jvmCfgName, "r");
if (jvmCfg == NULL) {
if (!speculative) {
//"Error: could not open `%s'"
JLI_ReportErrorMessage(CFG_ERROR6, jvmCfgName);
exit(1);
} else {
return -1;
}
}
//遍历jvm.cfg每一行的内容
while (fgets(line, sizeof(line), jvmCfg) != NULL) {
vmType = VM_UNKNOWN;
lineno++;
//'#'号开始的注释过滤掉
if (line[0] == '#')
continue;
//除去注释,所有有效配置行都应该以符号'-'开始,否则打印错误信息
if (line[0] != '-') {
//"Warning: No leading - on line %d of `%s'"
JLI_ReportErrorMessage(CFG_WARN2, lineno, jvmCfgName);
}
//knowVMs数组长度超过knownVMsLimit,扩容
if (cnt >= knownVMsLimit) {
GrowKnownVMs(cnt);
}
//移除行末换行符
line[JLI_StrLen(line)-1] = '\0'; /* remove trailing newline */
//字符指针移动指向第一个空白字符,line保留空格前的字符串:-server,tempPtr:' 'KNOWN
//-server KNOWN
// ↑
tmpPtr = line + JLI_StrCSpn(line, whiteSpace);
//如果移动后的指针内容为0,打印异常信息
if (*tmpPtr == 0) {
//"Warning: Missing VM type on line %d of `%s'"
JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName);
} else {
/* Null-terminate this string for JLI_StringDup below */
*tmpPtr++ = 0;
//字符指针移动到第一个非空白字符出,即tmpPtr内容就为参数值:KNOWN
//-server KNOWN
// ↑
tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace);
if (*tmpPtr == 0) {
//"Warning: Missing VM type on line %d of `%s'"
JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName);
} else {
//设置vmType
if (!JLI_StrCCmp(tmpPtr, "KNOWN")) {
vmType = VM_KNOWN;
} else if (!JLI_StrCCmp(tmpPtr, "ALIASED_TO")) {
//获取别名
tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);
if (*tmpPtr != 0) {
tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace);
}
if (*tmpPtr == 0) {
//"Warning: Missing VM type on line %d of `%s'"
JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName);
} else {
/* Null terminate altVMName */
altVMName = tmpPtr;
tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);
*tmpPtr = 0;
vmType = VM_ALIASED_TO;
}
} else if (!JLI_StrCCmp(tmpPtr, "WARN")) {
vmType = VM_WARN;
} else if (!JLI_StrCCmp(tmpPtr, "IGNORE")) {
vmType = VM_IGNORE;
} else if (!JLI_StrCCmp(tmpPtr, "ERROR")) {
vmType = VM_ERROR;
} else if (!JLI_StrCCmp(tmpPtr, "IF_SERVER_CLASS")) {
tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);
if (*tmpPtr != 0) {
tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace);
}
if (*tmpPtr == 0) {
//"Warning: Missing server class VM on line %d of `%s'"
JLI_ReportErrorMessage(CFG_WARN4, lineno, jvmCfgName);
} else {
/* Null terminate server class VM name */
serverClassVMName = tmpPtr;
tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);
*tmpPtr = 0;
vmType = VM_IF_SERVER_CLASS;
}
} else {
//"Warning: Unknown VM type on line %d of `%s'"
JLI_ReportErrorMessage(CFG_WARN5, lineno, &jvmCfgName[0]);
vmType = VM_KNOWN;
}
}
}
//jvm.cfg[0] = ->-server<-
//jvm.cfg[1] = ->-client<-
JLI_TraceLauncher("jvm.cfg[%d] = ->%s<-\n", cnt, line);
if (vmType != VM_UNKNOWN) {
knownVMs[cnt].name = JLI_StringDup(line);//-server
knownVMs[cnt].flag = vmType;//KNOWN
switch (vmType) {
default:
break;
case VM_ALIASED_TO:
knownVMs[cnt].alias = JLI_StringDup(altVMName);
JLI_TraceLauncher(" name: %s vmType: %s alias: %s\n",
knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias);
break;
case VM_IF_SERVER_CLASS:
knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName);
JLI_TraceLauncher(" name: %s vmType: %s server_class: %s\n",
knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class);
break;
}
cnt++;
}
}
fclose(jvmCfg);
knownVMsCount = cnt;
if (JLI_IsTraceLauncher()) {
//获取定时器结束计数值
end = CounterGet();
//2326 micro seconds to parse jvm.cfg
printf("%ld micro seconds to parse jvm.cfg\n",
(long)(jint)Counter2Micros(end-start));
}
return cnt;
}
src/windows/bin/java_md.c::CounterGet
//获取定时器的计数值,用来计算时间差
jlong CounterGet()
{
LARGE_INTEGER count;
if (!counterInitialized) {
//获得机器内部计时器的时钟频率
counterAvailable = QueryPerformanceFrequency(&counterFrequency);
counterInitialized = JNI_TRUE;
}
if (!counterAvailable) {
return 0;
}
//查询定时器的计数值,如果硬件里有定时器,它就会启动这个定时器,
//并且不断获取定时器的值,这样的定时器精度,就跟硬件时钟的晶振一样精确的。
QueryPerformanceCounter(&count);
return (jlong)(count.QuadPart);
}
src/share/bin/java.c::GrowKnownVMs
static void
GrowKnownVMs(int minimum)
{
struct vmdesc* newKnownVMs;
int newMax;
//knownVMs扩容
//1.如果knownVMsLimit为0,扩容为:INIT_MAX_KNOWN_VMS
//2.如果knownVMsLimit不为0,扩容为:2 * knownVMsLimit
newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit));
//如果扩容后的容量不能满足要求,则将传入的值设为容量最大值
if (newMax <= minimum) {
newMax = minimum;
}
//为新的数组分配内存,将原有数据拷贝到新的数组中,并交换数组,重设knownVMsLimit
newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc));
if (knownVMs != NULL) {
memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc));
}
JLI_MemFree(knownVMs);
knownVMs = newKnownVMs;
k = newMax;
}
src/share/bin/java.c
/* Maximum supported entries from jvm.cfg. */
#define INIT_MAX_KNOWN_VMS 10
/* Values for vmdesc.flag */
enum vmdesc_flag {
VM_UNKNOWN = -1,
VM_KNOWN,
VM_ALIASED_TO,
VM_WARN,
VM_ERROR,
VM_IF_SERVER_CLASS,
VM_IGNORE
};