1/*
2 * Copyright (c) 2000, 2013, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.nio.ch;
27
28import java.io.FileDescriptor;
29import java.io.IOException;
30import java.nio.ByteBuffer;
31
32
33/**
34 * File-descriptor based I/O utilities that are shared by NIO classes.
35 */
36
37public class IOUtil {
38
39    /**
40     * Max number of iovec structures that readv/writev supports
41     */
42    static final int IOV_MAX;
43
44    private IOUtil() { }                // No instantiation
45
46    static int write(FileDescriptor fd, ByteBuffer src, long position,
47                     NativeDispatcher nd)
48        throws IOException
49    {
50        if (src instanceof DirectBuffer)
51            return writeFromNativeBuffer(fd, src, position, nd);
52
53        // Substitute a native buffer
54        int pos = src.position();
55        int lim = src.limit();
56        assert (pos <= lim);
57        int rem = (pos <= lim ? lim - pos : 0);
58        ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
59        try {
60            bb.put(src);
61            bb.flip();
62            // Do not update src until we see how many bytes were written
63            src.position(pos);
64
65            int n = writeFromNativeBuffer(fd, bb, position, nd);
66            if (n > 0) {
67                // now update src
68                src.position(pos + n);
69            }
70            return n;
71        } finally {
72            Util.offerFirstTemporaryDirectBuffer(bb);
73        }
74    }
75
76    private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
77                                             long position, NativeDispatcher nd)
78        throws IOException
79    {
80        int pos = bb.position();
81        int lim = bb.limit();
82        assert (pos <= lim);
83        int rem = (pos <= lim ? lim - pos : 0);
84
85        int written = 0;
86        if (rem == 0)
87            return 0;
88        if (position != -1) {
89            written = nd.pwrite(fd,
90                                ((DirectBuffer)bb).address() + pos,
91                                rem, position);
92        } else {
93            written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem);
94        }
95        if (written > 0)
96            bb.position(pos + written);
97        return written;
98    }
99
100    static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
101        throws IOException
102    {
103        return write(fd, bufs, 0, bufs.length, nd);
104    }
105
106    static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
107                      NativeDispatcher nd)
108        throws IOException
109    {
110        IOVecWrapper vec = IOVecWrapper.get(length);
111
112        boolean completed = false;
113        int iov_len = 0;
114        try {
115
116            // Iterate over buffers to populate native iovec array.
117            int count = offset + length;
118            int i = offset;
119            while (i < count && iov_len < IOV_MAX) {
120                ByteBuffer buf = bufs[i];
121                int pos = buf.position();
122                int lim = buf.limit();
123                assert (pos <= lim);
124                int rem = (pos <= lim ? lim - pos : 0);
125                if (rem > 0) {
126                    vec.setBuffer(iov_len, buf, pos, rem);
127
128                    // allocate shadow buffer to ensure I/O is done with direct buffer
129                    if (!(buf instanceof DirectBuffer)) {
130                        ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
131                        shadow.put(buf);
132                        shadow.flip();
133                        vec.setShadow(iov_len, shadow);
134                        buf.position(pos);  // temporarily restore position in user buffer
135                        buf = shadow;
136                        pos = shadow.position();
137                    }
138
139                    vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
140                    vec.putLen(iov_len, rem);
141                    iov_len++;
142                }
143                i++;
144            }
145            if (iov_len == 0)
146                return 0L;
147
148            long bytesWritten = nd.writev(fd, vec.address, iov_len);
149
150            // Notify the buffers how many bytes were taken
151            long left = bytesWritten;
152            for (int j=0; j<iov_len; j++) {
153                if (left > 0) {
154                    ByteBuffer buf = vec.getBuffer(j);
155                    int pos = vec.getPosition(j);
156                    int rem = vec.getRemaining(j);
157                    int n = (left > rem) ? rem : (int)left;
158                    buf.position(pos + n);
159                    left -= n;
160                }
161                // return shadow buffers to buffer pool
162                ByteBuffer shadow = vec.getShadow(j);
163                if (shadow != null)
164                    Util.offerLastTemporaryDirectBuffer(shadow);
165                vec.clearRefs(j);
166            }
167
168            completed = true;
169            return bytesWritten;
170
171        } finally {
172            // if an error occurred then clear refs to buffers and return any shadow
173            // buffers to cache
174            if (!completed) {
175                for (int j=0; j<iov_len; j++) {
176                    ByteBuffer shadow = vec.getShadow(j);
177                    if (shadow != null)
178                        Util.offerLastTemporaryDirectBuffer(shadow);
179                    vec.clearRefs(j);
180                }
181            }
182        }
183    }
184
185    static int read(FileDescriptor fd, ByteBuffer dst, long position,
186                    NativeDispatcher nd)
187        throws IOException
188    {
189        if (dst.isReadOnly())
190            throw new IllegalArgumentException("Read-only buffer");
191        if (dst instanceof DirectBuffer)
192            return readIntoNativeBuffer(fd, dst, position, nd);
193
194        // Substitute a native buffer
195        ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
196        try {
197            int n = readIntoNativeBuffer(fd, bb, position, nd);
198            bb.flip();
199            if (n > 0)
200                dst.put(bb);
201            return n;
202        } finally {
203            Util.offerFirstTemporaryDirectBuffer(bb);
204        }
205    }
206
207    private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
208                                            long position, NativeDispatcher nd)
209        throws IOException
210    {
211        int pos = bb.position();
212        int lim = bb.limit();
213        assert (pos <= lim);
214        int rem = (pos <= lim ? lim - pos : 0);
215
216        if (rem == 0)
217            return 0;
218        int n = 0;
219        if (position != -1) {
220            n = nd.pread(fd, ((DirectBuffer)bb).address() + pos,
221                         rem, position);
222        } else {
223            n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);
224        }
225        if (n > 0)
226            bb.position(pos + n);
227        return n;
228    }
229
230    static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
231        throws IOException
232    {
233        return read(fd, bufs, 0, bufs.length, nd);
234    }
235
236    static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
237                     NativeDispatcher nd)
238        throws IOException
239    {
240        IOVecWrapper vec = IOVecWrapper.get(length);
241
242        boolean completed = false;
243        int iov_len = 0;
244        try {
245
246            // Iterate over buffers to populate native iovec array.
247            int count = offset + length;
248            int i = offset;
249            while (i < count && iov_len < IOV_MAX) {
250                ByteBuffer buf = bufs[i];
251                if (buf.isReadOnly())
252                    throw new IllegalArgumentException("Read-only buffer");
253                int pos = buf.position();
254                int lim = buf.limit();
255                assert (pos <= lim);
256                int rem = (pos <= lim ? lim - pos : 0);
257
258                if (rem > 0) {
259                    vec.setBuffer(iov_len, buf, pos, rem);
260
261                    // allocate shadow buffer to ensure I/O is done with direct buffer
262                    if (!(buf instanceof DirectBuffer)) {
263                        ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
264                        vec.setShadow(iov_len, shadow);
265                        buf = shadow;
266                        pos = shadow.position();
267                    }
268
269                    vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
270                    vec.putLen(iov_len, rem);
271                    iov_len++;
272                }
273                i++;
274            }
275            if (iov_len == 0)
276                return 0L;
277
278            long bytesRead = nd.readv(fd, vec.address, iov_len);
279
280            // Notify the buffers how many bytes were read
281            long left = bytesRead;
282            for (int j=0; j<iov_len; j++) {
283                ByteBuffer shadow = vec.getShadow(j);
284                if (left > 0) {
285                    ByteBuffer buf = vec.getBuffer(j);
286                    int rem = vec.getRemaining(j);
287                    int n = (left > rem) ? rem : (int)left;
288                    if (shadow == null) {
289                        int pos = vec.getPosition(j);
290                        buf.position(pos + n);
291                    } else {
292                        shadow.limit(shadow.position() + n);
293                        buf.put(shadow);
294                    }
295                    left -= n;
296                }
297                if (shadow != null)
298                    Util.offerLastTemporaryDirectBuffer(shadow);
299                vec.clearRefs(j);
300            }
301
302            completed = true;
303            return bytesRead;
304
305        } finally {
306            // if an error occurred then clear refs to buffers and return any shadow
307            // buffers to cache
308            if (!completed) {
309                for (int j=0; j<iov_len; j++) {
310                    ByteBuffer shadow = vec.getShadow(j);
311                    if (shadow != null)
312                        Util.offerLastTemporaryDirectBuffer(shadow);
313                    vec.clearRefs(j);
314                }
315            }
316        }
317    }
318
319    public static FileDescriptor newFD(int i) {
320        FileDescriptor fd = new FileDescriptor();
321        setfdVal(fd, i);
322        return fd;
323    }
324
325    static native boolean randomBytes(byte[] someBytes);
326
327    /**
328     * Returns two file descriptors for a pipe encoded in a long.
329     * The read end of the pipe is returned in the high 32 bits,
330     * while the write end is returned in the low 32 bits.
331     */
332    static native long makePipe(boolean blocking);
333
334    static native boolean drain(int fd) throws IOException;
335
336    public static native void configureBlocking(FileDescriptor fd,
337                                                boolean blocking)
338        throws IOException;
339
340    public static native int fdVal(FileDescriptor fd);
341
342    static native void setfdVal(FileDescriptor fd, int value);
343
344    static native int fdLimit();
345
346    static native int iovMax();
347
348    static native void initIDs();
349
350    /**
351     * Used to trigger loading of native libraries
352     */
353    public static void load() { }
354
355    static {
356        java.security.AccessController.doPrivileged(
357                new java.security.PrivilegedAction<Void>() {
358                    public Void run() {
359                        System.loadLibrary("net");
360                        System.loadLibrary("nio");
361                        return null;
362                    }
363                });
364
365        initIDs();
366
367        IOV_MAX = iovMax();
368    }
369
370}
371