1
16 package io.netty.channel.unix;
17
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.ByteBuffer;
22 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
23
24 import static io.netty.channel.unix.Errors.ioResult;
25 import static io.netty.channel.unix.Errors.newIOException;
26 import static io.netty.channel.unix.Limits.IOV_MAX;
27 import static io.netty.util.internal.ObjectUtil.checkNotNull;
28 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
29 import static java.lang.Math.min;
30
31
35 public class FileDescriptor {
36
37 private static final AtomicIntegerFieldUpdater<FileDescriptor> stateUpdater =
38 AtomicIntegerFieldUpdater.newUpdater(FileDescriptor.class, "state");
39
40 private static final int STATE_CLOSED_MASK = 1;
41 private static final int STATE_INPUT_SHUTDOWN_MASK = 1 << 1;
42 private static final int STATE_OUTPUT_SHUTDOWN_MASK = 1 << 2;
43 private static final int STATE_ALL_MASK = STATE_CLOSED_MASK |
44 STATE_INPUT_SHUTDOWN_MASK |
45 STATE_OUTPUT_SHUTDOWN_MASK;
46
47
50 volatile int state;
51 final int fd;
52
53 public FileDescriptor(int fd) {
54 checkPositiveOrZero(fd, "fd");
55 this.fd = fd;
56 }
57
58
61 public final int intValue() {
62 return fd;
63 }
64
65
68 public void close() throws IOException {
69 for (;;) {
70 int state = this.state;
71 if (isClosed(state)) {
72 return;
73 }
74
75 if (casState(state, state | STATE_ALL_MASK)) {
76 break;
77 }
78 }
79 int res = close(fd);
80 if (res < 0) {
81 throw newIOException("close", res);
82 }
83 }
84
85
88 public boolean isOpen() {
89 return !isClosed(state);
90 }
91
92 public final int write(ByteBuffer buf, int pos, int limit) throws IOException {
93 int res = write(fd, buf, pos, limit);
94 if (res >= 0) {
95 return res;
96 }
97 return ioResult("write", res);
98 }
99
100 public final int writeAddress(long address, int pos, int limit) throws IOException {
101 int res = writeAddress(fd, address, pos, limit);
102 if (res >= 0) {
103 return res;
104 }
105 return ioResult("writeAddress", res);
106 }
107
108 public final long writev(ByteBuffer[] buffers, int offset, int length, long maxBytesToWrite) throws IOException {
109 long res = writev(fd, buffers, offset, min(IOV_MAX, length), maxBytesToWrite);
110 if (res >= 0) {
111 return res;
112 }
113 return ioResult("writev", (int) res);
114 }
115
116 public final long writevAddresses(long memoryAddress, int length) throws IOException {
117 long res = writevAddresses(fd, memoryAddress, length);
118 if (res >= 0) {
119 return res;
120 }
121 return ioResult("writevAddresses", (int) res);
122 }
123
124 public final int read(ByteBuffer buf, int pos, int limit) throws IOException {
125 int res = read(fd, buf, pos, limit);
126 if (res > 0) {
127 return res;
128 }
129 if (res == 0) {
130 return -1;
131 }
132 return ioResult("read", res);
133 }
134
135 public final int readAddress(long address, int pos, int limit) throws IOException {
136 int res = readAddress(fd, address, pos, limit);
137 if (res > 0) {
138 return res;
139 }
140 if (res == 0) {
141 return -1;
142 }
143 return ioResult("readAddress", res);
144 }
145
146 @Override
147 public String toString() {
148 return "FileDescriptor{" +
149 "fd=" + fd +
150 '}';
151 }
152
153 @Override
154 public boolean equals(Object o) {
155 if (this == o) {
156 return true;
157 }
158 if (!(o instanceof FileDescriptor)) {
159 return false;
160 }
161
162 return fd == ((FileDescriptor) o).fd;
163 }
164
165 @Override
166 public int hashCode() {
167 return fd;
168 }
169
170
173 public static FileDescriptor from(String path) throws IOException {
174 int res = open(checkNotNull(path, "path"));
175 if (res < 0) {
176 throw newIOException("open", res);
177 }
178 return new FileDescriptor(res);
179 }
180
181
184 public static FileDescriptor from(File file) throws IOException {
185 return from(checkNotNull(file, "file").getPath());
186 }
187
188
191 public static FileDescriptor[] pipe() throws IOException {
192 long res = newPipe();
193 if (res < 0) {
194 throw newIOException("newPipe", (int) res);
195 }
196 return new FileDescriptor[]{new FileDescriptor((int) (res >>> 32)), new FileDescriptor((int) res)};
197 }
198
199 final boolean casState(int expected, int update) {
200 return stateUpdater.compareAndSet(this, expected, update);
201 }
202
203 static boolean isClosed(int state) {
204 return (state & STATE_CLOSED_MASK) != 0;
205 }
206
207 static boolean isInputShutdown(int state) {
208 return (state & STATE_INPUT_SHUTDOWN_MASK) != 0;
209 }
210
211 static boolean isOutputShutdown(int state) {
212 return (state & STATE_OUTPUT_SHUTDOWN_MASK) != 0;
213 }
214
215 static int inputShutdown(int state) {
216 return state | STATE_INPUT_SHUTDOWN_MASK;
217 }
218
219 static int outputShutdown(int state) {
220 return state | STATE_OUTPUT_SHUTDOWN_MASK;
221 }
222
223 private static native int open(String path);
224 private static native int close(int fd);
225
226 private static native int write(int fd, ByteBuffer buf, int pos, int limit);
227 private static native int writeAddress(int fd, long address, int pos, int limit);
228 private static native long writev(int fd, ByteBuffer[] buffers, int offset, int length, long maxBytesToWrite);
229 private static native long writevAddresses(int fd, long memoryAddress, int length);
230
231 private static native int read(int fd, ByteBuffer buf, int pos, int limit);
232 private static native int readAddress(int fd, long address, int pos, int limit);
233
234 private static native long newPipe();
235 }
236