Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
f29b0d09
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
f29b0d09
编写于
9月 05, 2014
作者:
A
alanb
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8029516: (fs) WatchKey cancel unreliable on Windows
Reviewed-by: chegar
上级
e5b87d89
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
265 addition
and
43 deletion
+265
-43
src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
+30
-0
src/windows/classes/sun/nio/fs/WindowsWatchService.java
src/windows/classes/sun/nio/fs/WindowsWatchService.java
+79
-32
src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
+37
-11
test/java/nio/file/WatchService/LotsOfCancels.java
test/java/nio/file/WatchService/LotsOfCancels.java
+119
-0
未找到文件。
src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
浏览文件 @
f29b0d09
...
...
@@ -36,6 +36,17 @@ import sun.misc.Unsafe;
class
WindowsNativeDispatcher
{
private
WindowsNativeDispatcher
()
{
}
/**
* HANDLE CreateEvent(
* LPSECURITY_ATTRIBUTES lpEventAttributes,
* BOOL bManualReset,
* BOOL bInitialState,
* PCTSTR lpName
* );
*/
static
native
long
CreateEvent
(
boolean
bManualReset
,
boolean
bInitialState
)
throws
WindowsException
;
/**
* HANDLE CreateFile(
* LPCTSTR lpFileName,
...
...
@@ -1041,6 +1052,25 @@ class WindowsNativeDispatcher {
long
pOverlapped
)
throws
WindowsException
;
/**
* CancelIo(
* HANDLE hFile
* )
*/
static
native
void
CancelIo
(
long
hFile
)
throws
WindowsException
;
/**
* GetOverlappedResult(
* HANDLE hFile,
* LPOVERLAPPED lpOverlapped,
* LPDWORD lpNumberOfBytesTransferred,
* BOOL bWait
* );
*/
static
native
int
GetOverlappedResult
(
long
hFile
,
long
lpOverlapped
)
throws
WindowsException
;
/**
* BackupRead(
* HANDLE hFile,
...
...
src/windows/classes/sun/nio/fs/WindowsWatchService.java
浏览文件 @
f29b0d09
...
...
@@ -25,9 +25,16 @@
package
sun.nio.fs
;
import
java.nio.file.*
;
import
java.io.IOException
;
import
java.util.*
;
import
java.nio.file.NotDirectoryException
;
import
java.nio.file.Path
;
import
java.nio.file.StandardWatchEventKinds
;
import
java.nio.file.WatchEvent
;
import
java.nio.file.WatchKey
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Set
;
import
com.sun.nio.file.ExtendedWatchEventModifier
;
import
sun.misc.Unsafe
;
...
...
@@ -42,7 +49,6 @@ class WindowsWatchService
extends
AbstractWatchService
{
private
final
static
int
WAKEUP_COMPLETION_KEY
=
0
;
private
final
Unsafe
unsafe
=
Unsafe
.
getUnsafe
();
// background thread to service I/O completion port
private
final
Poller
poller
;
...
...
@@ -82,7 +88,7 @@ class WindowsWatchService
/**
* Windows implementation of WatchKey.
*/
private
class
WindowsWatchKey
extends
AbstractWatchKey
{
private
static
class
WindowsWatchKey
extends
AbstractWatchKey
{
// file key (used to detect existing registrations)
private
final
FileKey
fileKey
;
...
...
@@ -169,15 +175,9 @@ class WindowsWatchService
return
completionKey
;
}
// close directory and release buffer
void
releaseResources
()
{
CloseHandle
(
handle
);
buffer
.
cleaner
().
clean
();
}
// Invalidate key by closing directory and releasing buffer
// Invalidate the key, assumes that resources have been released
void
invalidate
()
{
releaseResources
(
);
((
WindowsWatchService
)
watcher
()).
poller
.
releaseResources
(
this
);
handle
=
INVALID_HANDLE_VALUE
;
buffer
=
null
;
countAddress
=
0
;
...
...
@@ -193,7 +193,7 @@ class WindowsWatchService
public
void
cancel
()
{
if
(
isValid
())
{
// delegate to poller
poller
.
cancel
(
this
);
((
WindowsWatchService
)
watcher
()).
poller
.
cancel
(
this
);
}
}
}
...
...
@@ -241,18 +241,25 @@ class WindowsWatchService
/**
* Background thread to service I/O completion port.
*/
private
class
Poller
extends
AbstractPoller
{
private
static
class
Poller
extends
AbstractPoller
{
private
final
static
Unsafe
UNSAFE
=
Unsafe
.
getUnsafe
();
/*
* typedef struct _OVERLAPPED {
* DWORD Internal;
* DWORD InternalHigh;
* DWORD Offset;
* DWORD OffsetHigh;
* HANDLE hEvent;
* ULONG_PTR Internal;
* ULONG_PTR InternalHigh;
* union {
* struct { DWORD Offset; DWORD OffsetHigh; };
* PVOID Pointer;
* };
* HANDLE hEvent;
* } OVERLAPPED;
*/
private
static
final
short
SIZEOF_DWORD
=
4
;
private
static
final
short
SIZEOF_OVERLAPPED
=
32
;
// 20 on 32-bit
private
static
final
short
OFFSETOF_HEVENT
=
(
UNSAFE
.
addressSize
()
==
4
)
?
(
short
)
16
:
24
;
/*
* typedef struct _FILE_NOTIFY_INFORMATION {
...
...
@@ -276,10 +283,10 @@ class WindowsWatchService
private
final
long
port
;
// maps completion key to WatchKey
private
final
Map
<
Integer
,
WindowsWatchKey
>
ck2key
;
private
final
Map
<
Integer
,
WindowsWatchKey
>
ck2key
;
// maps file key to WatchKey
private
final
Map
<
FileKey
,
WindowsWatchKey
>
fk2key
;
private
final
Map
<
FileKey
,
WindowsWatchKey
>
fk2key
;
// unique completion key for each directory
// native completion key capacity is 64 bits on Win64.
...
...
@@ -393,8 +400,13 @@ class WindowsWatchService
long
overlappedAddress
=
bufferAddress
+
size
-
SIZEOF_OVERLAPPED
;
long
countAddress
=
overlappedAddress
-
SIZEOF_DWORD
;
// zero the overlapped structure
UNSAFE
.
setMemory
(
overlappedAddress
,
SIZEOF_OVERLAPPED
,
(
byte
)
0
);
// start async read of changes to directory
try
{
createAndAttachEvent
(
overlappedAddress
);
ReadDirectoryChangesW
(
handle
,
bufferAddress
,
CHANGES_BUFFER_SIZE
,
...
...
@@ -403,6 +415,7 @@ class WindowsWatchService
countAddress
,
overlappedAddress
);
}
catch
(
WindowsException
x
)
{
closeAttachedEvent
(
overlappedAddress
);
buffer
.
release
();
return
new
IOException
(
x
.
getMessage
());
}
...
...
@@ -421,7 +434,7 @@ class WindowsWatchService
// 2. release existing key's resources (handle/buffer)
// 3. re-initialize key with new handle/buffer
ck2key
.
remove
(
existing
.
completionKey
());
existing
.
releaseResources
(
);
releaseResources
(
existing
);
watchKey
=
existing
.
init
(
handle
,
events
,
watchSubtree
,
buffer
,
countAddress
,
overlappedAddress
,
completionKey
);
}
...
...
@@ -436,6 +449,42 @@ class WindowsWatchService
}
}
/**
* Cancels the outstanding I/O operation on the directory
* associated with the given key and releases the associated
* resources.
*/
private
void
releaseResources
(
WindowsWatchKey
key
)
{
try
{
CancelIo
(
key
.
handle
());
GetOverlappedResult
(
key
.
handle
(),
key
.
overlappedAddress
());
}
catch
(
WindowsException
expected
)
{
// expected as I/O operation has been cancelled
}
CloseHandle
(
key
.
handle
());
closeAttachedEvent
(
key
.
overlappedAddress
());
key
.
buffer
().
cleaner
().
clean
();
}
/**
* Creates an unnamed event and set it as the hEvent field
* in the given OVERLAPPED structure
*/
private
void
createAndAttachEvent
(
long
ov
)
throws
WindowsException
{
long
hEvent
=
CreateEvent
(
false
,
false
);
UNSAFE
.
putAddress
(
ov
+
OFFSETOF_HEVENT
,
hEvent
);
}
/**
* Closes the event attached to the given OVERLAPPED structure. A
* no-op if there isn't an event attached.
*/
private
void
closeAttachedEvent
(
long
ov
)
{
long
hEvent
=
UNSAFE
.
getAddress
(
ov
+
OFFSETOF_HEVENT
);
if
(
hEvent
!=
0
&&
hEvent
!=
INVALID_HANDLE_VALUE
)
CloseHandle
(
hEvent
);
}
// cancel single key
@Override
void
implCancelKey
(
WatchKey
obj
)
{
...
...
@@ -451,9 +500,8 @@ class WindowsWatchService
@Override
void
implCloseAll
()
{
// cancel all keys
for
(
Map
.
Entry
<
Integer
,
WindowsWatchKey
>
entry:
ck2key
.
entrySet
())
{
entry
.
getValue
().
invalidate
();
}
ck2key
.
values
().
forEach
(
WindowsWatchKey:
:
invalidate
);
fk2key
.
clear
();
ck2key
.
clear
();
...
...
@@ -462,8 +510,7 @@ class WindowsWatchService
}
// Translate file change action into watch event
private
WatchEvent
.
Kind
<?>
translateActionToEvent
(
int
action
)
{
private
WatchEvent
.
Kind
<?>
translateActionToEvent
(
int
action
)
{
switch
(
action
)
{
case
FILE_ACTION_MODIFIED
:
return
StandardWatchEventKinds
.
ENTRY_MODIFY
;
...
...
@@ -487,18 +534,18 @@ class WindowsWatchService
int
nextOffset
;
do
{
int
action
=
unsafe
.
getInt
(
address
+
OFFSETOF_ACTION
);
int
action
=
UNSAFE
.
getInt
(
address
+
OFFSETOF_ACTION
);
// map action to event
WatchEvent
.
Kind
<?>
kind
=
translateActionToEvent
(
action
);
if
(
key
.
events
().
contains
(
kind
))
{
// copy the name
int
nameLengthInBytes
=
unsafe
.
getInt
(
address
+
OFFSETOF_FILENAMELENGTH
);
int
nameLengthInBytes
=
UNSAFE
.
getInt
(
address
+
OFFSETOF_FILENAMELENGTH
);
if
((
nameLengthInBytes
%
2
)
!=
0
)
{
throw
new
AssertionError
(
"FileNameLength
.FileNameLength
is not a multiple of 2"
);
throw
new
AssertionError
(
"FileNameLength is not a multiple of 2"
);
}
char
[]
nameAsArray
=
new
char
[
nameLengthInBytes
/
2
];
unsafe
.
copyMemory
(
null
,
address
+
OFFSETOF_FILENAME
,
nameAsArray
,
UNSAFE
.
copyMemory
(
null
,
address
+
OFFSETOF_FILENAME
,
nameAsArray
,
Unsafe
.
ARRAY_CHAR_BASE_OFFSET
,
nameLengthInBytes
);
// create FileName and queue event
...
...
@@ -508,7 +555,7 @@ class WindowsWatchService
}
// next event
nextOffset
=
unsafe
.
getInt
(
address
+
OFFSETOF_NEXTENTRYOFFSET
);
nextOffset
=
UNSAFE
.
getInt
(
address
+
OFFSETOF_NEXTENTRYOFFSET
);
address
+=
(
long
)
nextOffset
;
}
while
(
nextOffset
!=
0
);
}
...
...
src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
浏览文件 @
f29b0d09
...
...
@@ -195,6 +195,17 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
}
}
JNIEXPORT
jlong
JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_CreateEvent
(
JNIEnv
*
env
,
jclass
this
,
jboolean
bManualReset
,
jboolean
bInitialState
)
{
HANDLE
hEvent
=
CreateEventW
(
NULL
,
bManualReset
,
bInitialState
,
NULL
);
if
(
hEvent
==
NULL
)
{
throwWindowsException
(
env
,
GetLastError
());
}
return
ptr_to_jlong
(
hEvent
);
}
JNIEXPORT
jstring
JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_FormatMessage
(
JNIEnv
*
env
,
jclass
this
,
jint
errorCode
)
{
WCHAR
message
[
255
];
...
...
@@ -1229,6 +1240,31 @@ Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env,
}
}
JNIEXPORT
void
JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_CancelIo
(
JNIEnv
*
env
,
jclass
this
,
jlong
hFile
)
{
if
(
CancelIo
((
HANDLE
)
jlong_to_ptr
(
hFile
))
==
0
)
{
throwWindowsException
(
env
,
GetLastError
());
}
}
JNIEXPORT
jint
JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_GetOverlappedResult
(
JNIEnv
*
env
,
jclass
this
,
jlong
hFile
,
jlong
lpOverlapped
)
{
BOOL
res
;
DWORD
bytesTransferred
=
-
1
;
res
=
GetOverlappedResult
((
HANDLE
)
jlong_to_ptr
(
hFile
),
(
LPOVERLAPPED
)
jlong_to_ptr
(
lpOverlapped
),
&
bytesTransferred
,
TRUE
);
if
(
res
==
0
)
{
throwWindowsException
(
env
,
GetLastError
());
}
return
(
jint
)
bytesTransferred
;
}
JNIEXPORT
void
JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW
(
JNIEnv
*
env
,
jclass
this
,
jlong
hDirectory
,
jlong
bufferAddress
,
jint
bufferLength
,
jboolean
watchSubTree
,
jint
filter
,
...
...
@@ -1236,17 +1272,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclas
{
BOOL
res
;
BOOL
subtree
=
(
watchSubTree
==
JNI_TRUE
)
?
TRUE
:
FALSE
;
/* Any unused members of [OVERLAPPED] structure should always be initialized to zero
before the structure is used in a function call.
Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684342%28v=vs.85%29.aspx
The [Offset] and [OffsetHigh] members of this structure are not used.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
[hEvent] should be zero, other fields are the return values. */
ZeroMemory
((
LPOVERLAPPED
)
jlong_to_ptr
(
pOverlapped
),
sizeof
(
OVERLAPPED
));
LPOVERLAPPED
ov
=
(
LPOVERLAPPED
)
jlong_to_ptr
(
pOverlapped
);
res
=
ReadDirectoryChangesW
((
HANDLE
)
jlong_to_ptr
(
hDirectory
),
(
LPVOID
)
jlong_to_ptr
(
bufferAddress
),
...
...
test/java/nio/file/WatchService/LotsOfCancels.java
0 → 100644
浏览文件 @
f29b0d09
/*
* 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.
*/
/* @test
* @bug 8029516
* @summary Bash on WatchKey.cancel with a view to causing a crash when
* an outstanding I/O operation on directory completes after the
* directory has been closed
*/
import
java.nio.file.ClosedWatchServiceException
;
import
java.nio.file.FileSystems
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.WatchKey
;
import
java.nio.file.WatchService
;
import
static
java
.
nio
.
file
.
StandardWatchEventKinds
.*;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
public
class
LotsOfCancels
{
// set to true for any exceptions
static
volatile
boolean
failed
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
// create a bunch of directories. Create two tasks for each directory,
// one to bash on cancel, the other to poll the events
ExecutorService
pool
=
Executors
.
newCachedThreadPool
();
try
{
Path
top
=
Files
.
createTempDirectory
(
"work"
);
top
.
toFile
().
deleteOnExit
();
for
(
int
i
=
1
;
i
<=
16
;
i
++)
{
Path
dir
=
Files
.
createDirectory
(
top
.
resolve
(
"dir-"
+
i
));
WatchService
watcher
=
FileSystems
.
getDefault
().
newWatchService
();
pool
.
submit
(()
->
handle
(
dir
,
watcher
));
pool
.
submit
(()
->
poll
(
watcher
));
}
}
finally
{
pool
.
shutdown
();
}
// give thread pool lots of time to terminate
if
(!
pool
.
awaitTermination
(
5L
,
TimeUnit
.
MINUTES
))
throw
new
RuntimeException
(
"Thread pool did not terminate"
);
if
(
failed
)
throw
new
RuntimeException
(
"Test failed, see log for details"
);
}
/**
* Stress the given WatchService, specifically the cancel method, in
* the given directory. Closes the WatchService when done.
*/
static
void
handle
(
Path
dir
,
WatchService
watcher
)
{
try
{
try
{
Path
file
=
dir
.
resolve
(
"anyfile"
);
for
(
int
i
=
0
;
i
<
2000
;
i
++)
{
WatchKey
key
=
dir
.
register
(
watcher
,
ENTRY_CREATE
,
ENTRY_DELETE
);
Files
.
createFile
(
file
);
Files
.
delete
(
file
);
key
.
cancel
();
}
}
finally
{
watcher
.
close
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
failed
=
true
;
}
}
/**
* Polls the given WatchService in a tight loop. This keeps the event
* queue drained, it also hogs a CPU core which seems necessary to
* tickle the original bug.
*/
static
void
poll
(
WatchService
watcher
)
{
try
{
for
(;;)
{
WatchKey
key
=
watcher
.
take
();
if
(
key
!=
null
)
{
key
.
pollEvents
();
key
.
reset
();
}
}
}
catch
(
ClosedWatchServiceException
expected
)
{
// nothing to do
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
failed
=
true
;
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录