/*
 * Copyright (c) 2013, 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 8012019
 * @summary Tests interruption of threads doing position-based read methods in
 *   an attempt to provoke a deadlock between position sensitive and position
 *   insensitive methods
 */
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.*;
import static java.nio.file.StandardOpenOption.*;

public class InterruptDeadlock {

    /**
     * A thread that continuously reads from a FileChannel with
     * read(ByteBuffer,long). The thread terminates when interrupted and/or
     * the FileChannel is closed.
     */
    static class Reader extends Thread {
        final FileChannel fc;
        volatile Exception exception;

        Reader(FileChannel fc) {
            this.fc = fc;
        }

        @Override
        public void run() {
            ByteBuffer bb = ByteBuffer.allocate(1024);
            try {
                long pos = 0L;
                for (;;) {
                    bb.clear();
                    int n = fc.read(bb, pos);
                    if (n > 0)
                        pos += n;
                    // fc.size is important here as it is position sensitive
                    if (pos > fc.size())
                        pos = 0L;
                }
            } catch (ClosedChannelException x) {
                System.out.println(x.getClass() + " (expected)");
            } catch (Exception unexpected) {
                this.exception = unexpected;
            }
        }

        Exception exception() {
            return exception;
        }

        static Reader startReader(FileChannel fc) {
            Reader r = new Reader(fc);
            r.start();
            return r;
        }
    }

    // the number of reader threads to start
    private static final int READER_COUNT = 4;

    public static void main(String[] args) throws Exception {
        Path file = Paths.get("data.txt");
        try (FileChannel fc = FileChannel.open(file, CREATE, TRUNCATE_EXISTING, WRITE)) {
            fc.position(1024L * 1024L);
            fc.write(ByteBuffer.wrap(new byte[1]));
        }

        Reader[] readers = new Reader[READER_COUNT];

        for (int i=1; i<=20; i++) {
            System.out.format("Iteration: %s%n", i);

            try (FileChannel fc = FileChannel.open(file)) {
                boolean failed = false;

                // start reader threads
                for (int j=0; j<READER_COUNT; j++) {
                    readers[j] = Reader.startReader(fc);
                }

                // give readers a bit of time to get started (not strictly required)
                Thread.sleep(100);

                // interrupt and wait for the readers to terminate
                for (Reader r: readers) {
                    r.interrupt();
                }
                for (Reader r: readers) {
                    try {
                        r.join(10000);
                        Exception e = r.exception();
                        if (e != null) {
                            System.err.println("Reader thread failed with: " + e);
                            failed = true;
                        }
                    } catch (InterruptedException x) {
                        System.err.println("Reader thread did not terminte");
                        failed = true;
                    }
                }

                // the channel should not be open at this point
                if (fc.isOpen()) {
                    System.err.println("FileChannel was not closed");
                    failed = true;
                }

                if (failed)
                    throw new RuntimeException("Test failed - see log for details");
            }
        }
    }
}
