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 
26 package sun.nio.ch;
27 
28 import java.io.FileDescriptor;
29 import java.io.IOException;
30 import java.nio.ByteBuffer;
31 
32 
33 /**
34  * File-descriptor based I/O utilities that are shared by NIO classes.
35  */
36 
37 public class IOUtil {
38 
39     /**
40      * Max number of iovec structures that readv/writev supports
41      */
42     static final int IOV_MAX;
43 
IOUtil()44     private IOUtil() { }                // No instantiation
45 
write(FileDescriptor fd, ByteBuffer src, long position, NativeDispatcher nd)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 
writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb, long position, NativeDispatcher nd)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 
write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)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 
write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, NativeDispatcher nd)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 
read(FileDescriptor fd, ByteBuffer dst, long position, NativeDispatcher nd)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 
readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb, long position, NativeDispatcher nd)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 
read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)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 
read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, NativeDispatcher nd)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 
newFD(int i)319     public static FileDescriptor newFD(int i) {
320         FileDescriptor fd = new FileDescriptor();
321         setfdVal(fd, i);
322         return fd;
323     }
324 
randomBytes(byte[] someBytes)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      */
makePipe(boolean blocking)332     static native long makePipe(boolean blocking);
333 
drain(int fd)334     static native boolean drain(int fd) throws IOException;
335 
configureBlocking(FileDescriptor fd, boolean blocking)336     public static native void configureBlocking(FileDescriptor fd,
337                                                 boolean blocking)
338         throws IOException;
339 
fdVal(FileDescriptor fd)340     public static native int fdVal(FileDescriptor fd);
341 
setfdVal(FileDescriptor fd, int value)342     static native void setfdVal(FileDescriptor fd, int value);
343 
fdLimit()344     static native int fdLimit();
345 
iovMax()346     static native int iovMax();
347 
348     static {
349         IOV_MAX = iovMax();
350     }
351 
352 }
353