Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_hotspot
提交
5071c50f
D
dragonwell8_hotspot
项目概览
openanolis
/
dragonwell8_hotspot
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_hotspot
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
5071c50f
编写于
9月 04, 2014
作者:
S
sla
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8057535: add a thread extension class
Reviewed-by: mgerdin, bdelsart, jcoomes
上级
41c1b635
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
219 addition
and
132 deletion
+219
-132
src/share/vm/runtime/thread.cpp
src/share/vm/runtime/thread.cpp
+21
-0
src/share/vm/runtime/thread.hpp
src/share/vm/runtime/thread.hpp
+9
-0
src/share/vm/runtime/thread_ext.cpp
src/share/vm/runtime/thread_ext.cpp
+31
-0
src/share/vm/runtime/thread_ext.hpp
src/share/vm/runtime/thread_ext.hpp
+35
-0
src/share/vm/services/management.cpp
src/share/vm/services/management.cpp
+123
-132
未找到文件。
src/share/vm/runtime/thread.cpp
浏览文件 @
5071c50f
...
...
@@ -860,6 +860,7 @@ void Thread::print_on(outputStream* st) const {
st
->
print
(
"os_prio=%d "
,
os_prio
);
}
st
->
print
(
"tid="
INTPTR_FORMAT
" "
,
this
);
ext
().
print_on
(
st
);
osthread
()
->
print_on
(
st
);
}
debug_only
(
if
(
WizardMode
)
print_owned_locks_on
(
st
);)
...
...
@@ -3021,6 +3022,8 @@ void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) {
// Push the Java priority down to the native thread; needs Threads_lock
Thread
::
set_priority
(
this
,
prio
);
prepare_ext
();
// Add the new thread to the Threads list and set it in motion.
// We must have threads lock in order to call Threads::add.
// It is crucial that we do not block before the thread is
...
...
@@ -3875,6 +3878,24 @@ void Threads::create_vm_init_libraries() {
}
}
JavaThread
*
Threads
::
find_java_thread_from_java_tid
(
jlong
java_tid
)
{
assert
(
Threads_lock
->
owned_by_self
(),
"Must hold Threads_lock"
);
JavaThread
*
java_thread
=
NULL
;
// Sequential search for now. Need to do better optimization later.
for
(
JavaThread
*
thread
=
Threads
::
first
();
thread
!=
NULL
;
thread
=
thread
->
next
())
{
oop
tobj
=
thread
->
threadObj
();
if
(
!
thread
->
is_exiting
()
&&
tobj
!=
NULL
&&
java_tid
==
java_lang_Thread
::
thread_id
(
tobj
))
{
java_thread
=
thread
;
break
;
}
}
return
java_thread
;
}
// Last thread running calls java.lang.Shutdown.shutdown()
void
JavaThread
::
invoke_shutdown_hooks
()
{
HandleMark
hm
(
this
);
...
...
src/share/vm/runtime/thread.hpp
浏览文件 @
5071c50f
...
...
@@ -40,6 +40,7 @@
#include "runtime/safepoint.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/threadLocalStorage.hpp"
#include "runtime/thread_ext.hpp"
#include "runtime/unhandledOops.hpp"
#include "utilities/macros.hpp"
...
...
@@ -257,6 +258,8 @@ class Thread: public ThreadShadow {
TRACE_DATA
_trace_data
;
// Thread-local data for tracing
ThreadExt
_ext
;
int
_vm_operation_started_count
;
// VM_Operation support
int
_vm_operation_completed_count
;
// VM_Operation support
...
...
@@ -436,6 +439,9 @@ class Thread: public ThreadShadow {
TRACE_DATA
*
trace_data
()
{
return
&
_trace_data
;
}
const
ThreadExt
&
ext
()
const
{
return
_ext
;
}
ThreadExt
&
ext
()
{
return
_ext
;
}
// VM operation support
int
vm_operation_ticket
()
{
return
++
_vm_operation_started_count
;
}
int
vm_operation_completed_count
()
{
return
_vm_operation_completed_count
;
}
...
...
@@ -1002,6 +1008,7 @@ class JavaThread: public Thread {
// not specified, use the priority of the thread object. Threads_lock
// must be held while this function is called.
void
prepare
(
jobject
jni_thread
,
ThreadPriority
prio
=
NoPriority
);
void
prepare_ext
();
void
set_saved_exception_pc
(
address
pc
)
{
_saved_exception_pc
=
pc
;
}
address
saved_exception_pc
()
{
return
_saved_exception_pc
;
}
...
...
@@ -1956,6 +1963,8 @@ class Threads: AllStatic {
// Deoptimizes all frames tied to marked nmethods
static
void
deoptimized_wrt_marked_nmethods
();
static
JavaThread
*
find_java_thread_from_java_tid
(
jlong
java_tid
);
};
...
...
src/share/vm/runtime/thread_ext.cpp
0 → 100644
浏览文件 @
5071c50f
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code 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 code 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 in the LICENSE file that
* accompanied this code).
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "runtime/thread.hpp"
#include "runtime/thread_ext.hpp"
void
JavaThread
::
prepare_ext
()
{
}
src/share/vm/runtime/thread_ext.hpp
0 → 100644
浏览文件 @
5071c50f
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code 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 code 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 in the LICENSE file that
* accompanied this code).
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_RUNTIME_THREAD_EXT_HPP
#define SHARE_VM_RUNTIME_THREAD_EXT_HPP
#include "memory/allocation.hpp"
class
ThreadExt
VALUE_OBJ_CLASS_SPEC
{
public:
void
print_on
(
outputStream
*
st
)
const
{};
};
#endif // SHARE_VM_RUNTIME_THREAD_EXT_HPP
src/share/vm/services/management.cpp
浏览文件 @
5071c50f
...
...
@@ -389,23 +389,6 @@ instanceOop Management::create_thread_info_instance(ThreadSnapshot* snapshot,
return
(
instanceOop
)
element
();
}
// Helper functions
static
JavaThread
*
find_java_thread_from_id
(
jlong
thread_id
)
{
assert
(
Threads_lock
->
owned_by_self
(),
"Must hold Threads_lock"
);
JavaThread
*
java_thread
=
NULL
;
// Sequential search for now. Need to do better optimization later.
for
(
JavaThread
*
thread
=
Threads
::
first
();
thread
!=
NULL
;
thread
=
thread
->
next
())
{
oop
tobj
=
thread
->
threadObj
();
if
(
!
thread
->
is_exiting
()
&&
tobj
!=
NULL
&&
thread_id
==
java_lang_Thread
::
thread_id
(
tobj
))
{
java_thread
=
thread
;
break
;
}
}
return
java_thread
;
}
static
GCMemoryManager
*
get_gc_memory_manager_from_jobject
(
jobject
mgr
,
TRAPS
)
{
if
(
mgr
==
NULL
)
{
...
...
@@ -442,6 +425,8 @@ static MemoryPool* get_memory_pool_from_jobject(jobject obj, TRAPS) {
return
MemoryService
::
get_memory_pool
(
ph
);
}
#endif // INCLUDE_MANAGEMENT
static
void
validate_thread_id_array
(
typeArrayHandle
ids_ah
,
TRAPS
)
{
int
num_threads
=
ids_ah
->
length
();
...
...
@@ -457,6 +442,8 @@ static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) {
}
}
#if INCLUDE_MANAGEMENT
static
void
validate_thread_info_array
(
objArrayHandle
infoArray_h
,
TRAPS
)
{
// check if the element of infoArray is of type ThreadInfo class
Klass
*
threadinfo_klass
=
Management
::
java_lang_management_ThreadInfo_klass
(
CHECK
);
...
...
@@ -820,45 +807,6 @@ JVM_ENTRY(jlong, jmm_SetPoolThreshold(JNIEnv* env, jobject obj, jmmThresholdType
return
prev
;
JVM_END
// Gets an array containing the amount of memory allocated on the Java
// heap for a set of threads (in bytes). Each element of the array is
// the amount of memory allocated for the thread ID specified in the
// corresponding entry in the given array of thread IDs; or -1 if the
// thread does not exist or has terminated.
JVM_ENTRY
(
void
,
jmm_GetThreadAllocatedMemory
(
JNIEnv
*
env
,
jlongArray
ids
,
jlongArray
sizeArray
))
// Check if threads is null
if
(
ids
==
NULL
||
sizeArray
==
NULL
)
{
THROW
(
vmSymbols
::
java_lang_NullPointerException
());
}
ResourceMark
rm
(
THREAD
);
typeArrayOop
ta
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
ids
));
typeArrayHandle
ids_ah
(
THREAD
,
ta
);
typeArrayOop
sa
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
sizeArray
));
typeArrayHandle
sizeArray_h
(
THREAD
,
sa
);
// validate the thread id array
validate_thread_id_array
(
ids_ah
,
CHECK
);
// sizeArray must be of the same length as the given array of thread IDs
int
num_threads
=
ids_ah
->
length
();
if
(
num_threads
!=
sizeArray_h
->
length
())
{
THROW_MSG
(
vmSymbols
::
java_lang_IllegalArgumentException
(),
"The length of the given long array does not match the length of "
"the given array of thread IDs"
);
}
MutexLockerEx
ml
(
Threads_lock
);
for
(
int
i
=
0
;
i
<
num_threads
;
i
++
)
{
JavaThread
*
java_thread
=
find_java_thread_from_id
(
ids_ah
->
long_at
(
i
));
if
(
java_thread
!=
NULL
)
{
sizeArray_h
->
long_at_put
(
i
,
java_thread
->
cooked_allocated_bytes
());
}
}
JVM_END
// Returns a java/lang/management/MemoryUsage object representing
// the memory usage for the heap or non-heap memory.
JVM_ENTRY
(
jobject
,
jmm_GetMemoryUsage
(
JNIEnv
*
env
,
jboolean
heap
))
...
...
@@ -1164,7 +1112,7 @@ static void do_thread_dump(ThreadDumpResult* dump_result,
MutexLockerEx
ml
(
Threads_lock
);
for
(
int
i
=
0
;
i
<
num_threads
;
i
++
)
{
jlong
tid
=
ids_ah
->
long_at
(
i
);
JavaThread
*
jt
=
find_java_thread_from_
id
(
tid
);
JavaThread
*
jt
=
Threads
::
find_java_thread_from_java_t
id
(
tid
);
oop
thread_obj
=
(
jt
!=
NULL
?
jt
->
threadObj
()
:
(
oop
)
NULL
);
instanceHandle
threadObj_h
(
THREAD
,
(
instanceOop
)
thread_obj
);
thread_handle_array
->
append
(
threadObj_h
);
...
...
@@ -1243,7 +1191,7 @@ JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jo
MutexLockerEx
ml
(
Threads_lock
);
for
(
int
i
=
0
;
i
<
num_threads
;
i
++
)
{
jlong
tid
=
ids_ah
->
long_at
(
i
);
JavaThread
*
jt
=
find_java_thread_from_
id
(
tid
);
JavaThread
*
jt
=
Threads
::
find_java_thread_from_java_t
id
(
tid
);
ThreadSnapshot
*
ts
;
if
(
jt
==
NULL
)
{
// if the thread does not exist or now it is terminated,
...
...
@@ -1489,7 +1437,7 @@ JVM_ENTRY(jboolean, jmm_ResetStatistic(JNIEnv *env, jvalue obj, jmmStatisticType
}
}
else
{
// reset contention statistics for a given thread
JavaThread
*
java_thread
=
find_java_thread_from_
id
(
tid
);
JavaThread
*
java_thread
=
Threads
::
find_java_thread_from_java_t
id
(
tid
);
if
(
java_thread
==
NULL
)
{
return
false
;
}
...
...
@@ -1558,7 +1506,7 @@ JVM_ENTRY(jlong, jmm_GetThreadCpuTime(JNIEnv *env, jlong thread_id))
return
os
::
current_thread_cpu_time
();
}
else
{
MutexLockerEx
ml
(
Threads_lock
);
java_thread
=
find_java_thread_from_
id
(
thread_id
);
java_thread
=
Threads
::
find_java_thread_from_java_t
id
(
thread_id
);
if
(
java_thread
!=
NULL
)
{
return
os
::
thread_cpu_time
((
Thread
*
)
java_thread
);
}
...
...
@@ -1566,78 +1514,6 @@ JVM_ENTRY(jlong, jmm_GetThreadCpuTime(JNIEnv *env, jlong thread_id))
return
-
1
;
JVM_END
// Returns the CPU time consumed by a given thread (in nanoseconds).
// If thread_id == 0, CPU time for the current thread is returned.
// If user_sys_cpu_time = true, user level and system CPU time of
// a given thread is returned; otherwise, only user level CPU time
// is returned.
JVM_ENTRY
(
jlong
,
jmm_GetThreadCpuTimeWithKind
(
JNIEnv
*
env
,
jlong
thread_id
,
jboolean
user_sys_cpu_time
))
if
(
!
os
::
is_thread_cpu_time_supported
())
{
return
-
1
;
}
if
(
thread_id
<
0
)
{
THROW_MSG_
(
vmSymbols
::
java_lang_IllegalArgumentException
(),
"Invalid thread ID"
,
-
1
);
}
JavaThread
*
java_thread
=
NULL
;
if
(
thread_id
==
0
)
{
// current thread
return
os
::
current_thread_cpu_time
(
user_sys_cpu_time
!=
0
);
}
else
{
MutexLockerEx
ml
(
Threads_lock
);
java_thread
=
find_java_thread_from_id
(
thread_id
);
if
(
java_thread
!=
NULL
)
{
return
os
::
thread_cpu_time
((
Thread
*
)
java_thread
,
user_sys_cpu_time
!=
0
);
}
}
return
-
1
;
JVM_END
// Gets an array containing the CPU times consumed by a set of threads
// (in nanoseconds). Each element of the array is the CPU time for the
// thread ID specified in the corresponding entry in the given array
// of thread IDs; or -1 if the thread does not exist or has terminated.
// If user_sys_cpu_time = true, the sum of user level and system CPU time
// for the given thread is returned; otherwise, only user level CPU time
// is returned.
JVM_ENTRY
(
void
,
jmm_GetThreadCpuTimesWithKind
(
JNIEnv
*
env
,
jlongArray
ids
,
jlongArray
timeArray
,
jboolean
user_sys_cpu_time
))
// Check if threads is null
if
(
ids
==
NULL
||
timeArray
==
NULL
)
{
THROW
(
vmSymbols
::
java_lang_NullPointerException
());
}
ResourceMark
rm
(
THREAD
);
typeArrayOop
ta
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
ids
));
typeArrayHandle
ids_ah
(
THREAD
,
ta
);
typeArrayOop
tia
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
timeArray
));
typeArrayHandle
timeArray_h
(
THREAD
,
tia
);
// validate the thread id array
validate_thread_id_array
(
ids_ah
,
CHECK
);
// timeArray must be of the same length as the given array of thread IDs
int
num_threads
=
ids_ah
->
length
();
if
(
num_threads
!=
timeArray_h
->
length
())
{
THROW_MSG
(
vmSymbols
::
java_lang_IllegalArgumentException
(),
"The length of the given long array does not match the length of "
"the given array of thread IDs"
);
}
MutexLockerEx
ml
(
Threads_lock
);
for
(
int
i
=
0
;
i
<
num_threads
;
i
++
)
{
JavaThread
*
java_thread
=
find_java_thread_from_id
(
ids_ah
->
long_at
(
i
));
if
(
java_thread
!=
NULL
)
{
timeArray_h
->
long_at_put
(
i
,
os
::
thread_cpu_time
((
Thread
*
)
java_thread
,
user_sys_cpu_time
!=
0
));
}
}
JVM_END
// Returns a String array of all VM global flag names
JVM_ENTRY
(
jobjectArray
,
jmm_GetVMGlobalNames
(
JNIEnv
*
env
))
// last flag entry is always NULL, so subtract 1
...
...
@@ -2323,7 +2199,122 @@ jlong Management::ticks_to_ms(jlong ticks) {
return
(
jlong
)(((
double
)
ticks
/
(
double
)
os
::
elapsed_frequency
())
*
(
double
)
1000.0
);
}
#endif // INCLUDE_MANAGEMENT
// Gets an array containing the amount of memory allocated on the Java
// heap for a set of threads (in bytes). Each element of the array is
// the amount of memory allocated for the thread ID specified in the
// corresponding entry in the given array of thread IDs; or -1 if the
// thread does not exist or has terminated.
JVM_ENTRY
(
void
,
jmm_GetThreadAllocatedMemory
(
JNIEnv
*
env
,
jlongArray
ids
,
jlongArray
sizeArray
))
// Check if threads is null
if
(
ids
==
NULL
||
sizeArray
==
NULL
)
{
THROW
(
vmSymbols
::
java_lang_NullPointerException
());
}
ResourceMark
rm
(
THREAD
);
typeArrayOop
ta
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
ids
));
typeArrayHandle
ids_ah
(
THREAD
,
ta
);
typeArrayOop
sa
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
sizeArray
));
typeArrayHandle
sizeArray_h
(
THREAD
,
sa
);
// validate the thread id array
validate_thread_id_array
(
ids_ah
,
CHECK
);
// sizeArray must be of the same length as the given array of thread IDs
int
num_threads
=
ids_ah
->
length
();
if
(
num_threads
!=
sizeArray_h
->
length
())
{
THROW_MSG
(
vmSymbols
::
java_lang_IllegalArgumentException
(),
"The length of the given long array does not match the length of "
"the given array of thread IDs"
);
}
MutexLockerEx
ml
(
Threads_lock
);
for
(
int
i
=
0
;
i
<
num_threads
;
i
++
)
{
JavaThread
*
java_thread
=
Threads
::
find_java_thread_from_java_tid
(
ids_ah
->
long_at
(
i
));
if
(
java_thread
!=
NULL
)
{
sizeArray_h
->
long_at_put
(
i
,
java_thread
->
cooked_allocated_bytes
());
}
}
JVM_END
// Returns the CPU time consumed by a given thread (in nanoseconds).
// If thread_id == 0, CPU time for the current thread is returned.
// If user_sys_cpu_time = true, user level and system CPU time of
// a given thread is returned; otherwise, only user level CPU time
// is returned.
JVM_ENTRY
(
jlong
,
jmm_GetThreadCpuTimeWithKind
(
JNIEnv
*
env
,
jlong
thread_id
,
jboolean
user_sys_cpu_time
))
if
(
!
os
::
is_thread_cpu_time_supported
())
{
return
-
1
;
}
if
(
thread_id
<
0
)
{
THROW_MSG_
(
vmSymbols
::
java_lang_IllegalArgumentException
(),
"Invalid thread ID"
,
-
1
);
}
JavaThread
*
java_thread
=
NULL
;
if
(
thread_id
==
0
)
{
// current thread
return
os
::
current_thread_cpu_time
(
user_sys_cpu_time
!=
0
);
}
else
{
MutexLockerEx
ml
(
Threads_lock
);
java_thread
=
Threads
::
find_java_thread_from_java_tid
(
thread_id
);
if
(
java_thread
!=
NULL
)
{
return
os
::
thread_cpu_time
((
Thread
*
)
java_thread
,
user_sys_cpu_time
!=
0
);
}
}
return
-
1
;
JVM_END
// Gets an array containing the CPU times consumed by a set of threads
// (in nanoseconds). Each element of the array is the CPU time for the
// thread ID specified in the corresponding entry in the given array
// of thread IDs; or -1 if the thread does not exist or has terminated.
// If user_sys_cpu_time = true, the sum of user level and system CPU time
// for the given thread is returned; otherwise, only user level CPU time
// is returned.
JVM_ENTRY
(
void
,
jmm_GetThreadCpuTimesWithKind
(
JNIEnv
*
env
,
jlongArray
ids
,
jlongArray
timeArray
,
jboolean
user_sys_cpu_time
))
// Check if threads is null
if
(
ids
==
NULL
||
timeArray
==
NULL
)
{
THROW
(
vmSymbols
::
java_lang_NullPointerException
());
}
ResourceMark
rm
(
THREAD
);
typeArrayOop
ta
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
ids
));
typeArrayHandle
ids_ah
(
THREAD
,
ta
);
typeArrayOop
tia
=
typeArrayOop
(
JNIHandles
::
resolve_non_null
(
timeArray
));
typeArrayHandle
timeArray_h
(
THREAD
,
tia
);
// validate the thread id array
validate_thread_id_array
(
ids_ah
,
CHECK
);
// timeArray must be of the same length as the given array of thread IDs
int
num_threads
=
ids_ah
->
length
();
if
(
num_threads
!=
timeArray_h
->
length
())
{
THROW_MSG
(
vmSymbols
::
java_lang_IllegalArgumentException
(),
"The length of the given long array does not match the length of "
"the given array of thread IDs"
);
}
MutexLockerEx
ml
(
Threads_lock
);
for
(
int
i
=
0
;
i
<
num_threads
;
i
++
)
{
JavaThread
*
java_thread
=
Threads
::
find_java_thread_from_java_tid
(
ids_ah
->
long_at
(
i
));
if
(
java_thread
!=
NULL
)
{
timeArray_h
->
long_at_put
(
i
,
os
::
thread_cpu_time
((
Thread
*
)
java_thread
,
user_sys_cpu_time
!=
0
));
}
}
JVM_END
#if INCLUDE_MANAGEMENT
const
struct
jmmInterface_1_
jmm_interface
=
{
NULL
,
NULL
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录