C言語への感謝の正拳突き 今日は21日目、です
今回はJVM編です。。JDKがマルチプラットフォーム周りの吸収をほとんど自前でやっていることが前回で分かりましたので、
JVMのマルチプラットフォームを抽象化したAPIって何を指しているんでしょうね。
fallout4をプレイする傍ら土日にこんなの書いてましたが、わたしの進捗良くない、勘違いしないでよね!
OpenJDKの取得方法とかはこちらを参照ください。
http://qiita.com/nothingcosmos/items/935cd0b9d62ef01ddddc
libjvm.soの中身
JVMがどういうglibcのAPIを叩いているのか、JVMがjdkに提供しているAPIにはどんなものがあるのか調べてみました。
まずはglibcの呼び出し一覧です。
_IO_getc@@GLIBC_2.2.5
__assert_fail@@GLIBC_2.2.5
__cxa_atexit@@GLIBC_2.2.5
__cxa_finalize@@GLIBC_2.2.5
__environ@@GLIBC_2.2.5
__errno_location@@GLIBC_2.2.5
__fxstat64@@GLIBC_2.2.5
__fxstat@@GLIBC_2.2.5
__isnan@@GLIBC_2.2.5
__libc_current_sigrtmax@@GLIBC_2.2.5
__libc_current_sigrtmin@@GLIBC_2.2.5
__lxstat@@GLIBC_2.2.5
__sigsetjmp@@GLIBC_2.2.5
__stack_chk_fail@@GLIBC_2.4
__timezone@@GLIBC_2.2.5
__tls_get_addr@@GLIBC_2.3
__xstat64@@GLIBC_2.2.5
__xstat@@GLIBC_2.2.5
_exit@@GLIBC_2.2.5
abort@@GLIBC_2.2.5
accept@@GLIBC_2.2.5
access@@GLIBC_2.2.5
bind@@GLIBC_2.2.5
ceil@@GLIBC_2.2.5
chmod@@GLIBC_2.2.5
close@@GLIBC_2.2.5
closedir@@GLIBC_2.2.5
confstr@@GLIBC_2.2.5
connect@@GLIBC_2.2.5
ctime@@GLIBC_2.2.5
dirfd@@GLIBC_2.2.5
dl_iterate_phdr@@GLIBC_2.2.5
dladdr@@GLIBC_2.2.5
dlclose@@GLIBC_2.2.5
dlerror@@GLIBC_2.2.5
dlopen@@GLIBC_2.2.5
dlsym@@GLIBC_2.2.5
dlvsym@@GLIBC_2.2.5
environ@@GLIBC_2.2.5
execve@@GLIBC_2.2.5
exit@@GLIBC_2.2.5
exp@@GLIBC_2.2.5
fchdir@@GLIBC_2.2.5
fclose@@GLIBC_2.2.5
fcntl@@GLIBC_2.2.5
fdopen@@GLIBC_2.2.5
feof@@GLIBC_2.2.5
fflush@@GLIBC_2.2.5
fgetc@@GLIBC_2.2.5
fgets@@GLIBC_2.2.5
fileno@@GLIBC_2.2.5
floor@@GLIBC_2.2.5
fmod@@GLIBC_2.2.5
fopen64@@GLIBC_2.2.5
fopen@@GLIBC_2.2.5
fork@@GLIBC_2.2.5
fprintf@@GLIBC_2.2.5
fputc@@GLIBC_2.2.5
fputs@@GLIBC_2.2.5
fread@@GLIBC_2.2.5
free@@GLIBC_2.2.5
frexp@@GLIBC_2.2.5
fscanf@@GLIBC_2.2.5
fseek@@GLIBC_2.2.5
fsync@@GLIBC_2.2.5
ftell@@GLIBC_2.2.5
ftruncate64@@GLIBC_2.2.5
ftruncate@@GLIBC_2.2.5
fwrite@@GLIBC_2.2.5
getcwd@@GLIBC_2.2.5
getegid@@GLIBC_2.2.5
getenv@@GLIBC_2.2.5
geteuid@@GLIBC_2.2.5
getgid@@GLIBC_2.2.5
gethostname@@GLIBC_2.2.5
getloadavg@@GLIBC_2.2.5
getpagesize@@GLIBC_2.2.5
getpid@@GLIBC_2.2.5
getpriority@@GLIBC_2.2.5
getpwuid_r@@GLIBC_2.2.5
getrlimit@@GLIBC_2.2.5
getrusage@@GLIBC_2.2.5
getsockname@@GLIBC_2.2.5
getsockopt@@GLIBC_2.2.5
gettimeofday@@GLIBC_2.2.5
getuid@@GLIBC_2.2.5
gnu_get_libc_release@@GLIBC_2.2.5
gnu_get_libc_version@@GLIBC_2.2.5
ioctl@@GLIBC_2.2.5
isalnum@@GLIBC_2.2.5
isatty@@GLIBC_2.2.5
isspace@@GLIBC_2.2.5
kill@@GLIBC_2.2.5
listen@@GLIBC_2.2.5
localtime_r@@GLIBC_2.2.5
log10@@GLIBC_2.2.5
lseek64@@GLIBC_2.2.5
lseek@@GLIBC_2.2.5
madvise@@GLIBC_2.2.5
malloc@@GLIBC_2.2.5
memchr@@GLIBC_2.2.5
memcpy@@GLIBC_2.2.5
memmove@@GLIBC_2.2.5
memset@@GLIBC_2.2.5
mincore@@GLIBC_2.2.5
mkdir@@GLIBC_2.2.5
mmap@@GLIBC_2.2.5
mprotect@@GLIBC_2.2.5
munmap@@GLIBC_2.2.5
nanosleep@@GLIBC_2.2.5
open64@@GLIBC_2.2.5
open@@GLIBC_2.2.5
opendir@@GLIBC_2.2.5
perror@@GLIBC_2.2.5
poll@@GLIBC_2.2.5
pread64@@GLIBC_2.2.5
printf@@GLIBC_2.2.5
pthread_attr_destroy@@GLIBC_2.2.5
pthread_attr_getstack@@GLIBC_2.2.5
pthread_attr_init@@GLIBC_2.2.5
pthread_attr_setdetachstate@@GLIBC_2.2.5
pthread_attr_setguardsize@@GLIBC_2.2.5
pthread_attr_setstacksize@@GLIBC_2.2.5
pthread_cancel@@GLIBC_2.2.5
pthread_cond_destroy@@GLIBC_2.3.2
pthread_cond_init@@GLIBC_2.3.2
pthread_cond_signal@@GLIBC_2.3.2
pthread_cond_timedwait@@GLIBC_2.3.2
pthread_cond_wait@@GLIBC_2.3.2
pthread_condattr_init@@GLIBC_2.2.5
pthread_condattr_setclock@@GLIBC_2.3.3
pthread_create@@GLIBC_2.2.5
pthread_getattr_np@@GLIBC_2.2.5
pthread_getspecific@@GLIBC_2.2.5
pthread_key_create@@GLIBC_2.2.5
pthread_key_delete@@GLIBC_2.2.5
pthread_kill@@GLIBC_2.2.5
pthread_mutex_init@@GLIBC_2.2.5
pthread_mutex_lock@@GLIBC_2.2.5
pthread_mutex_trylock@@GLIBC_2.2.5
pthread_mutex_unlock@@GLIBC_2.2.5
pthread_once@@GLIBC_2.2.5
pthread_self@@GLIBC_2.2.5
pthread_setspecific@@GLIBC_2.2.5
pthread_sigmask@@GLIBC_2.2.5
putchar@@GLIBC_2.2.5
puts@@GLIBC_2.2.5
pwrite64@@GLIBC_2.2.5
qsort@@GLIBC_2.2.5
raise@@GLIBC_2.2.5
read@@GLIBC_2.2.5
readdir@@GLIBC_2.2.5
readdir_r@@GLIBC_2.2.5
realloc@@GLIBC_2.2.5
realpath@@GLIBC_2.3
recv@@GLIBC_2.2.5
recvfrom@@GLIBC_2.2.5
remove@@GLIBC_2.2.5
rename@@GLIBC_2.2.5
rewind@@GLIBC_2.2.5
sched_yield@@GLIBC_2.2.5
sem_destroy@@GLIBC_2.2.5
sem_init@@GLIBC_2.2.5
sem_post@@GLIBC_2.2.5
sem_timedwait@@GLIBC_2.2.5
sem_trywait@@GLIBC_2.2.5
sem_wait@@GLIBC_2.2.5
send@@GLIBC_2.2.5
sendto@@GLIBC_2.2.5
setpriority@@GLIBC_2.2.5
setrlimit@@GLIBC_2.2.5
setsockopt@@GLIBC_2.2.5
shmat@@GLIBC_2.2.5
shmctl@@GLIBC_2.2.5
shmdt@@GLIBC_2.2.5
shmget@@GLIBC_2.2.5
shutdown@@GLIBC_2.2.5
sigaction@@GLIBC_2.2.5
sigaddset@@GLIBC_2.2.5
sigdelset@@GLIBC_2.2.5
sigemptyset@@GLIBC_2.2.5
sigfillset@@GLIBC_2.2.5
sigismember@@GLIBC_2.2.5
siglongjmp@@GLIBC_2.2.5
sigprocmask@@GLIBC_2.2.5
sigsuspend@@GLIBC_2.2.5
sleep@@GLIBC_2.2.5
snprintf@@GLIBC_2.2.5
socket@@GLIBC_2.2.5
sprintf@@GLIBC_2.2.5
sqrt@@GLIBC_2.2.5
sscanf@@GLIBC_2.2.5
stderr@@GLIBC_2.2.5
stdin@@GLIBC_2.2.5
stdout@@GLIBC_2.2.5
strcasecmp@@GLIBC_2.2.5
strcat@@GLIBC_2.2.5
strchr@@GLIBC_2.2.5
strcmp@@GLIBC_2.2.5
strcpy@@GLIBC_2.2.5
strcspn@@GLIBC_2.2.5
strdup@@GLIBC_2.2.5
strerror@@GLIBC_2.2.5
strlen@@GLIBC_2.2.5
strncasecmp@@GLIBC_2.2.5
strncat@@GLIBC_2.2.5
strncmp@@GLIBC_2.2.5
strncpy@@GLIBC_2.2.5
strpbrk@@GLIBC_2.2.5
strrchr@@GLIBC_2.2.5
strstr@@GLIBC_2.2.5
strtod@@GLIBC_2.2.5
strtol@@GLIBC_2.2.5
strtoul@@GLIBC_2.2.5
syscall@@GLIBC_2.2.5
sysconf@@GLIBC_2.2.5
sysinfo@@GLIBC_2.2.5
time@@GLIBC_2.2.5
times@@GLIBC_2.2.5
timezone@@GLIBC_2.2.5
tolower@@GLIBC_2.2.5
uname@@GLIBC_2.2.5
unlink@@GLIBC_2.2.5
unsetenv@@GLIBC_2.2.5
vfprintf@@GLIBC_2.2.5
vsnprintf@@GLIBC_2.2.5
vsscanf@@GLIBC_2.2.5
waitpid@@GLIBC_2.2.5
write@@GLIBC_2.2.5
pthread系が多いのは、JVM内部でスレッドを管理してJava側に提供するから。
file io系があるのは、たぶんclass file読むんでしょう。
net系があるのは、、JDWPで使うんでしょう。
JVMが外部に公開しているインターフェースはヘッダファイルに纏められていました。
http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/6ea3aea950d1/src/share/javavm/export
こちらのdoxygenでも見れます。
http://cr.openjdk.java.net/~ngmr/vmi.00/html/jvm_8h.html
prefixごとに分かれているみたいで、多いのはJVM系、JVMTI系でしょうかね。
概要
JVMが外部に公開しているインターフェースを見ていて気づいたのですが、こういうのが定義されている。
PART 1: Functions for Native Libraries
これらはjdkに実装が用意されているのではなく、vm側が専用のAPIを用意しているものですね。
PART 3: I/O and Network Support
すごく怪しいAPIが続々とあって、open() close() read() write() socket() send() recv()とか
これこそがJVMのプラットフォームを抽象化したC APIに違いない!
実装
JVMの実装は、jdk8u/hotspotの下に定義されており、JVM_系のAPIの実装を探してみます。
hotspot (VMのソースコード C++主体)
src
cpu
os
os_cpu
share
vm
まずはヘッダの宣言から
JNIEXPORT jint JNICALL
JVM_Open(const char *fname, jint flags, jint mode);
JNIEXPORT jint JNICALL
JVM_Close(jint fd);
JNIEXPORT jint JNICALL
JVM_Read(jint fd, char *buf, jint nbytes);
JNIEXPORT jint JNICALL
JVM_Write(jint fd, char *buf, jint nbytes);
JNIEXPORT jint JNICALL
JVM_Socket(jint domain, jint type, jint protocol);
JNIEXPORT jint JNICALL
JVM_SocketClose(jint fd);
JNIEXPORT jint JNICALL
JVM_Recv(jint fd, char *buf, jint nBytes, jint flags);
JNIEXPORT jint JNICALL
JVM_Send(jint fd, char *buf, jint nBytes, jint flags);
JNIEXPORT jint JNICALL
JVM_RecvFrom(jint fd, char *buf, int nBytes,
int flags, struct sockaddr *from, int *fromlen);
JNIEXPORT jint JNICALL
JVM_SendTo(jint fd, char *buf, int len,
int flags, struct sockaddr *to, int tolen);
代表的なものを選出してみましたが、すごく素朴で、実装が透けてみえそうです。
実装はどうなっているのか。
まずはファイルIOのほう
JVM_LEAF(jint, JVM_Open(const char *fname, jint flags, jint mode))
JVMWrapper2("JVM_Open (%s)", fname);
//%note jvm_r6
int result = os::open(fname, flags, mode);
if (result >= 0) {
return result;
} else {
switch(errno) {
case EEXIST:
return JVM_EEXIST;
default:
return -1;
}
}
JVM_END
JVM_LEAF(jint, JVM_Close(jint fd))
JVMWrapper2("JVM_Close (0x%x)", fd);
//%note jvm_r6
return os::close(fd);
JVM_END
JVM_LEAF(jint, JVM_Read(jint fd, char *buf, jint nbytes))
JVMWrapper2("JVM_Read (0x%x)", fd);
//%note jvm_r6
return (jint)os::restartable_read(fd, buf, nbytes);
JVM_END
JVM_LEAF(jint, JVM_Write(jint fd, char *buf, jint nbytes))
JVMWrapper2("JVM_Write (0x%x)", fd);
//%note jvm_r6
return (jint)os::write(fd, buf, nbytes);
JVM_END
突然のマクロ!apiの先頭にhook仕込みたいようですね。
#define JVM_LEAF(result_type, header) \
extern "C" { \
result_type JNICALL header { \
VM_Exit::block_if_vm_exited(); \
VM_LEAF_BASE(result_type, header)
#define JVM_END } }
// LEAF routines do not lock, GC or throw exceptions
#define VM_LEAF_BASE(result_type, header) \
TRACE_CALL(result_type, header) \
debug_only(NoHandleMark __hm;) \
os::verify_stack_alignment(); \
/* begin of body */
APIの呼び出しはos::XXXで抽象化しているようですね。
os::XXXの実体がどこにあるのかというと、OSごとにディレクトリが分かれているようでした。
inline size_t os::read(int fd, void *buf, unsigned int nBytes) {
return ::read(fd, buf, nBytes);
}
inline size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) {
return ::read(fd, buf, nBytes);
}
inline size_t os::write(int fd, const void *buf, unsigned int nBytes) {
return ::write(fd, buf, nBytes);
}
inline int os::close(int fd) {
return ::close(fd);
}
socket系の実装はこちら
int os::recvfrom(int fd, char *buf, size_t nBytes, uint flags,
sockaddr* from, socklen_t* fromlen) {
return ::recvfrom(fd, buf, (int)nBytes, flags, from, fromlen);
}
int os::recv(int fd, char* buf, size_t nBytes, uint flags) {
return ::recv(fd, buf, (int)nBytes, flags);
}
int os::send(int fd, char* buf, size_t nBytes, uint flags) {
return ::send(fd, buf, (int)nBytes, flags);
}
お次はlinux
// macros for restartable system calls
#define RESTARTABLE(_cmd, _result) do { \
_result = _cmd; \
} while(((int)_result == OS_ERR) && (errno == EINTR))
#define RESTARTABLE_RETURN_INT(_cmd) do { \
int _result; \
RESTARTABLE(_cmd, _result); \
return _result; \
} while(false)
inline size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) {
size_t res;
RESTARTABLE( (size_t) ::read(fd, buf, (size_t) nBytes), res);
return res;
}
inline size_t os::write(int fd, const void *buf, unsigned int nBytes) {
size_t res;
RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res);
return res;
}
inline int os::close(int fd) {
return ::close(fd);
}
inline int os::socket_close(int fd) {
return ::close(fd);
}
inline int os::socket(int domain, int type, int protocol) {
return ::socket(domain, type, protocol);
}
inline int os::recv(int fd, char* buf, size_t nBytes, uint flags) {
RESTARTABLE_RETURN_INT(::recv(fd, buf, nBytes, flags));
}
inline int os::send(int fd, char* buf, size_t nBytes, uint flags) {
RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, flags));
}
linuxのほうは微妙にrepeatableマクロを使っていて微妙に異なりますね。
シンプルにfdを引数に取るAPIに纏められていますが、どのようなところで使うのでしょうか。jdk側を調べてみました。
使用例
share/native/java/util/zip/zip_util.c: return JVM_Open(fname, flags, 0);
share/native/java/util/zip/ZipFile.c: zfd = JVM_Open(path, flag, 0);
share/javavm/export/jvm.h:JVM_Open(const char *fname, jint flags, jint mode);
solaris/native/sun/management/OperatingSystemImpl.c: fd = JVM_Open("/proc/self/psinfo", O_RDONLY, 0);
JVM_Open使ってるところほんと少ない。。
static ZFILE
ZFILE_Open(const char *fname, int flags) {
#ifdef WIN32
const DWORD access =
(flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
(flags & O_WRONLY) ? GENERIC_WRITE :
GENERIC_READ;
const DWORD sharing =
FILE_SHARE_READ | FILE_SHARE_WRITE;
const DWORD disposition =
/* Note: O_TRUNC overrides O_CREAT */
(flags & O_TRUNC) ? CREATE_ALWAYS :
(flags & O_CREAT) ? OPEN_ALWAYS :
OPEN_EXISTING;
const DWORD maybeWriteThrough =
(flags & (O_SYNC | O_DSYNC)) ?
FILE_FLAG_WRITE_THROUGH :
FILE_ATTRIBUTE_NORMAL;
const DWORD maybeDeleteOnClose =
(flags & O_TEMPORARY) ?
FILE_FLAG_DELETE_ON_CLOSE :
FILE_ATTRIBUTE_NORMAL;
const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
return (jlong) CreateFile(
fname, /* Wide char path name */
access, /* Read and/or write permission */
sharing, /* File sharing flags */
NULL, /* Security attributes */
disposition, /* creation disposition */
flagsAndAttributes, /* flags and attributes */
NULL);
#else
return JVM_Open(fname, flags, 0);
#endif
}
Windowsでは呼ばれない、、だと、、、!?
solaris/nativeもwindowsでは通らないパスだろうし、
Socketのほうも探してみました。
share/javavm/export/jvm.h:JVM_Socket(jint domain, jint type, jint protocol);
share/javavm/export/jvm.h:JVM_SocketClose(jint fd);
share/javavm/export/jvm.h:JVM_SocketShutdown(jint fd, jint howto);
share/javavm/export/jvm.h:JVM_SocketAvailable(jint fd, jint *result);
solaris/native/java/net/net_util_md.h:#define NET_SocketClose JVM_SocketClose
solaris/native/java/net/Inet4AddressImpl.c: fd = JVM_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
solaris/native/java/net/Inet4AddressImpl.c: fd = JVM_Socket(AF_INET, SOCK_STREAM, 0);
solaris/native/java/net/NetworkInterface.c: if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {
solaris/native/java/net/NetworkInterface.c: if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
solaris/native/java/net/NetworkInterface.c: if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
solaris/native/java/net/NetworkInterface.c: if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
solaris/native/java/net/NetworkInterface.c: if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
solaris/native/java/net/NetworkInterface.c: if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
solaris/native/java/net/NetworkInterface.c: if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
solaris/native/java/net/NetworkInterface.c: if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
solaris/native/java/net/net_util_md.c: fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0) ;
solaris/native/java/net/PlainDatagramSocketImpl.c: if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) {
solaris/native/java/net/Inet6AddressImpl.c: fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
solaris/native/java/net/Inet6AddressImpl.c: fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
solaris/native/java/net/PlainSocketImpl.c: JVM_SocketShutdown(sv[0], 2);
solaris/native/java/net/PlainSocketImpl.c: JVM_SocketClose(sv[1]);
solaris/native/java/net/PlainSocketImpl.c: if ((fd = JVM_Socket(domain, type, 0)) == JVM_IO_ERR) {
solaris/native/java/net/PlainSocketImpl.c: JVM_SocketShutdown(fd, 2);
solaris/native/java/net/PlainSocketImpl.c: /* JVM_SocketAvailable returns 0 for failure, 1 for success */
solaris/native/java/net/PlainSocketImpl.c: if (!JVM_SocketAvailable(fd, &ret)){
solaris/native/java/net/PlainSocketImpl.c: JVM_SocketShutdown(fd, howto);
solaris/nativeからの呼び出しは結構あるようですが、
jdkのsocketとして呼び出しているのではなく、突発的にJVM_Socketを呼び出しているように見えます。
Javaの初期のころは、VMが提供するI/O and Network Supportで定義されたAPIを呼び出していたのかもしれませんが、
マルチプラットフォーム対応(特にWindows)したころに、ほとんど呼び出されなくなってしまったのかもしれませんね。
もしくは、socketやfileioを使いたいけど、自分(たとえばlibXXX.soで定義されているAPI)は、
socketやfileioを定義しているlibjava.soやlibnio.soへの依存を作りたくないといった場合に、
libjvm.soに定義されたI/O and Network SupportのAPIを呼び出すのかもしれません。。
※特にzipの中ではifdef切ってfileopenしていた。
たぶん後者かな。
まとめ
(1) JVMにはI/O and Network Supportというプラットフォーム抽象化されたサポート用のAPIを用意していたが、呼び出されることは少なく、ライブラリ間の依存を回避したい場合に呼び出し可能な補助的なAPIぽい。
※io/netの本体はjdk/src/solaris/native/java/netや、jdk/src/windows/native/java/netに定義されている。
(2) JVMよくわからん。
おまけ
JVM自体はThreadを抽象化してJavaに提供しており、シンプルなAPIに纏められていますが、実装はすべてJVM側でされています。
C++11で提供されるthreadとAPIを比較してみたり、どんな実装になっているのか比べてみるのも面白いかもしれませんね。
JVMに実装されている、Threadのインターフェース一覧はこちらです。
static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread},
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread},
{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
{"yield", "()V", (void *)&JVM_Yield},
{"sleep", "(J)V", (void *)&JVM_Sleep},
{"currentThread", "()" THD, (void *)&JVM_CurrentThread},
{"countStackFrames", "()I", (void *)&JVM_CountStackFrames},
{"interrupt0", "()V", (void *)&JVM_Interrupt},
{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},
{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};