JDK-6209658 : (fc) FileChannel.lock() does not wakeup when file asynchronously closed (win)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 5.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-12-16
  • Updated: 2025-02-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
If a thread is interrupted while it is blocked in FileChannel.lock() that method might return null instead of a valid FileLock object or throwing a exception.

  From the JDK source it seems this can happen because begin() in AbstractInterruptibleChannel sets open to false if the thread is interrupted. In FileChannelImpl.lock() (line 781) null is returned if isOpen() returns false.

According to the JDK docs FileChannel.lock() should throw a FileLockInterruptionException in this case and not return null.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Since this bug involves interrupting a thread at exactly the right time it is not easy to reproduce. It sometimes is reproducable on my machine by executing the attached sample code. If the bug was reproduced it will output  "Lock is null!".

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
FileChannel.lock() should throw a FileLockInterruptionException.
ACTUAL -
FileChannel.lock() returns null.

REPRODUCIBILITY :
This bug can be reproduced occasionally.

---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.channels.*;

public class FileChannelTest
{
    private static Thread createLockThread(final File file)
    {
        return new Thread() {
            public void run() {
                try {
                    FileOutputStream out = new FileOutputStream(file);
                    FileChannel channel = out.getChannel();
                    FileLock lock = channel.lock();
                    
                    if(lock == null) {
                        System.out.println("Lock is null!");
                    }
                    
                    Thread.sleep(5000);
                    lock.release();
                    channel.close();
                }
                catch(InterruptedException ex) {
                }
                catch(Throwable t) {
                    t.printStackTrace();
                }
            }
        };
    }
    
    public static void main(String args[])
        throws Exception
    {
        File file = File.createTempFile("test", "");
        file.deleteOnExit();
        
        Thread t1 = createLockThread(file);
        Thread t2 = createLockThread(file);

        t1.start();
        Thread.sleep(100);
        t2.start();


        t2.interrupt();
    }
}

---------- END SOURCE ----------
###@###.### 2004-12-16 19:19:51 GMT

Comments
The version of FileChannelTest provided in the description fails with OverlappingFileLockException. A version with non-overlapping lock ranges is attached.
11-02-2025

File locking is a case where async close may not be feasible on all platforms and that the spec need to set expectations on that.
20-07-2023

Thread.intrerrupt causes sun.nio.ch.FileChannelImpl.implCloseChannel to be invoked so that might be the place to consider attempting to cancel the I/O. Some experiments may be required to see if this is feasible solution or not. Note that this issue has existed forever so we do not need to attempt this for jdk8.
07-08-2013

Seems that [hotspot\src\os\windows\vm\os_windows.cpp], os::interrupt(Thread* thread) is the right place for the call. Or we need to re-implement the [interrupt0] entry in [jdk\src\share\native\java\lang\Thread.c]
07-08-2013

The [CancelSynchronousIo] call inside [Thread.interrupt] is our choice.
07-08-2013

Here the process is described in the details: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363789%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683%28v=vs.85%29.aspx An answer for the case is the [CancelSynchronousIo] call: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363794%28v=vs.85%29.aspx , or the sequence of the [CancelIoEx] calls from earlier prepared thread-key map http://msdn.microsoft.com/en-us/library/windows/desktop/aa363792%28v=vs.85%29.aspx There are limitations that are described in the first article. http://msdn.microsoft.com/en-us/library/windows/desktop/aa365203%28v=vs.85%29.aspx: 1] "If the file handle was not opened for asynchronous I/O and the lock is not available, this call waits until the lock is granted or an error occurs, unless the LOCKFILE_FAIL_IMMEDIATELY flag is specified." Lets suggest that the LOCKFILE_FAIL_IMMEDIATELY flag is not installed, so the thread is locked, we are in sync operation. http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683%28v=vs.85%29.aspx 2] "If a file or device is opened for synchronous I/O (that is, FILE_FLAG_OVERLAPPED is not specified), subsequent calls to functions such as WriteFile can block execution of the calling thread until one of the following events occurs: - The I/O operation completes (in this example, a data write). - An I/O error occurs. (For example, the pipe is closed from the other end.) - An error was made in the call itself (for example, one or more parameters are not valid). - !!!! Another thread in the process calls the CancelSynchronousIo function using the blocked thread's thread handle, which terminates I/O for that thread, failing the I/O operation. !!!! <-- our case is here - The blocked thread is terminated by the system; for example, the process itself is terminated, or another thread calls the TerminateThread function using the blocked thread's handle. (This is generally considered a last resort and not good application design.) http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683%28v=vs.85%29.aspx 3] "To cancel all pending asynchronous I/O operations, use either: - CancelIo—this function only cancels operations issued by the calling thread for the specified file handle. - CancelIoEx—this function cancels all operations issued by the threads for the specified file handle. Use CancelSynchronousIo to cancel pending synchronous I/O operations."
07-08-2013

Alexey - you might have ideas but it doesn't seem to be possible to wakeup a thread blocked in LockFileEx.
23-05-2013

EVALUATION This original issue, with lock returning null, has been fixed by 6979009. However, we need to keep the bug open as there is a second issue whereby the close does not cause the thread blocked in the lock operation to wakeup. I've changed the synopsis accordiningly.
13-11-2010

EVALUATION The issue described in this bug report is not easy to reproduce. However, the conditions as to how this can arise are clear. However, while investigating this I see that closing the file channel does not always preempt a thread blocked acquiring a lock on Windows. This may not be an easy issue to resolve.
07-12-2006