1/*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/* @test
25 * @bug 4938372 6541641
26 * @summary Flushing dirty pages prior to unmap can cause Cleaner thread to
27 *          abort VM if memory system has pages locked
28 * @run main/othervm ExpandingMap
29 */
30import java.io.File;
31import java.io.RandomAccessFile;
32import java.io.IOException;
33import java.nio.ByteBuffer;
34import java.nio.channels.FileChannel;
35import java.util.ArrayList;
36
37/**
38 * Test case provided by submitter of 4938372.
39 */
40
41public class ExpandingMap {
42
43    public static void main(String[] args) throws Exception {
44
45        int initialSize = 20480*1024;
46        int maximumMapSize = 16*1024*1024;
47        int maximumFileSize = 300000000;
48
49        File file = File.createTempFile("exp", "tmp");
50        file.deleteOnExit();
51        RandomAccessFile f = new RandomAccessFile(file, "rw");
52        f.setLength(initialSize);
53
54        FileChannel fc = f.getChannel();
55
56        ByteBuffer[] buffers = new ByteBuffer[128];
57
58        System.out.format("map %d -> %d\n", 0, initialSize);
59        buffers[0] = fc.map(FileChannel.MapMode.READ_WRITE, 0, initialSize);
60
61        int currentBuffer = 0;
62        int currentSize = initialSize;
63        int currentPosition = 0;
64
65        ArrayList<String> junk = new ArrayList<String>();
66
67        while (currentPosition+currentSize < maximumFileSize) {
68            int inc = Math.max(1000*1024, (currentPosition+currentSize)/8);
69
70            int size = currentPosition+currentSize+inc;
71            f.setLength(size);
72
73            while (currentSize+inc > maximumMapSize) {
74                if (currentSize < maximumMapSize) {
75                    System.out.format("map %d -> %d\n", currentPosition,
76                        (currentPosition + maximumMapSize));
77                    buffers[currentBuffer] = fc.map(FileChannel.MapMode.READ_WRITE,
78                        currentPosition, maximumMapSize);
79                    fillBuffer(buffers[currentBuffer], currentSize);
80                }
81                currentPosition += maximumMapSize;
82                inc = currentSize+inc-maximumMapSize;
83                currentSize = 0;
84                currentBuffer++;
85                if (currentBuffer == buffers.length) {
86                    ByteBuffer[] old = buffers;
87                    buffers = new ByteBuffer[currentBuffer+currentBuffer/2];
88                    System.arraycopy(old, 0, buffers, 0, currentBuffer);                                        }
89            }
90            currentSize += inc;
91            if (currentSize > 0) {
92                System.out.format("map %d -> %d\n", currentPosition,
93                    (currentPosition + currentSize));
94                buffers[currentBuffer] = fc.map(FileChannel.MapMode.READ_WRITE,
95                     currentPosition, currentSize);
96                fillBuffer(buffers[currentBuffer], currentSize-inc);
97            }
98
99            // busy loop needed to reproduce issue
100            long t = System.currentTimeMillis();
101            while (System.currentTimeMillis() < t+500) {
102                junk.add(String.valueOf(t));
103                if (junk.size() > 100000) junk.clear();
104            }
105        }
106
107        fc.close();
108        // cleanup the ref to mapped buffers so they can be GCed
109        for (int i = 0; i < buffers.length; i++)
110            buffers[i] = null;
111        System.gc();
112        // Take a nap to wait for the Cleaner to cleanup those unrefed maps
113        Thread.sleep(1000);
114        System.out.println("TEST PASSED");
115    }
116
117    static void fillBuffer(ByteBuffer buf, int from) {
118        int limit = buf.limit();
119        for (int i=from; i<limit; i++) {
120            buf.put(i, (byte)i);
121        }
122    }
123}
124