1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
32
33
34
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
48
49
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
59
60
61 public final int intValue() {
62 return fd;
63 }
64
65 protected boolean markClosed() {
66 for (;;) {
67 int state = this.state;
68 if (isClosed(state)) {
69 return false;
70 }
71
72 if (casState(state, state | STATE_ALL_MASK)) {
73 return true;
74 }
75 }
76 }
77
78
79
80
81 public void close() throws IOException {
82 if (markClosed()) {
83 int res = close(fd);
84 if (res < 0) {
85 throw newIOException("close", res);
86 }
87 }
88 }
89
90
91
92
93 public boolean isOpen() {
94 return !isClosed(state);
95 }
96
97 public final int write(ByteBuffer buf, int pos, int limit) throws IOException {
98 int res = write(fd, buf, pos, limit);
99 if (res >= 0) {
100 return res;
101 }
102 return ioResult("write", res);
103 }
104
105 public final int writeAddress(long address, int pos, int limit) throws IOException {
106 int res = writeAddress(fd, address, pos, limit);
107 if (res >= 0) {
108 return res;
109 }
110 return ioResult("writeAddress", res);
111 }
112
113 public final long writev(ByteBuffer[] buffers, int offset, int length, long maxBytesToWrite) throws IOException {
114 long res = writev(fd, buffers, offset, min(IOV_MAX, length), maxBytesToWrite);
115 if (res >= 0) {
116 return res;
117 }
118 return ioResult("writev", (int) res);
119 }
120
121 public final long writevAddresses(long memoryAddress, int length) throws IOException {
122 long res = writevAddresses(fd, memoryAddress, length);
123 if (res >= 0) {
124 return res;
125 }
126 return ioResult("writevAddresses", (int) res);
127 }
128
129 public final int read(ByteBuffer buf, int pos, int limit) throws IOException {
130 int res = read(fd, buf, pos, limit);
131 if (res > 0) {
132 return res;
133 }
134 if (res == 0) {
135 return -1;
136 }
137 return ioResult("read", res);
138 }
139
140 public final int readAddress(long address, int pos, int limit) throws IOException {
141 int res = readAddress(fd, address, pos, limit);
142 if (res > 0) {
143 return res;
144 }
145 if (res == 0) {
146 return -1;
147 }
148 return ioResult("readAddress", res);
149 }
150
151 @Override
152 public String toString() {
153 return "FileDescriptor{" +
154 "fd=" + fd +
155 '}';
156 }
157
158 @Override
159 public boolean equals(Object o) {
160 if (this == o) {
161 return true;
162 }
163 if (!(o instanceof FileDescriptor)) {
164 return false;
165 }
166
167 return fd == ((FileDescriptor) o).fd;
168 }
169
170 @Override
171 public int hashCode() {
172 return fd;
173 }
174
175
176
177
178 public static FileDescriptor from(String path) throws IOException {
179 int res = open(checkNotNull(path, "path"));
180 if (res < 0) {
181 throw newIOException("open", res);
182 }
183 return new FileDescriptor(res);
184 }
185
186
187
188
189 public static FileDescriptor from(File file) throws IOException {
190 return from(checkNotNull(file, "file").getPath());
191 }
192
193
194
195
196 public static FileDescriptor[] pipe() throws IOException {
197 long res = newPipe();
198 if (res < 0) {
199 throw newIOException("newPipe", (int) res);
200 }
201 return new FileDescriptor[]{new FileDescriptor((int) (res >>> 32)), new FileDescriptor((int) res)};
202 }
203
204 final boolean casState(int expected, int update) {
205 return stateUpdater.compareAndSet(this, expected, update);
206 }
207
208 static boolean isClosed(int state) {
209 return (state & STATE_CLOSED_MASK) != 0;
210 }
211
212 static boolean isInputShutdown(int state) {
213 return (state & STATE_INPUT_SHUTDOWN_MASK) != 0;
214 }
215
216 static boolean isOutputShutdown(int state) {
217 return (state & STATE_OUTPUT_SHUTDOWN_MASK) != 0;
218 }
219
220 static int inputShutdown(int state) {
221 return state | STATE_INPUT_SHUTDOWN_MASK;
222 }
223
224 static int outputShutdown(int state) {
225 return state | STATE_OUTPUT_SHUTDOWN_MASK;
226 }
227
228 private static native int open(String path);
229 private static native int close(int fd);
230
231 private static native int write(int fd, ByteBuffer buf, int pos, int limit);
232 private static native int writeAddress(int fd, long address, int pos, int limit);
233 private static native long writev(int fd, ByteBuffer[] buffers, int offset, int length, long maxBytesToWrite);
234 private static native long writevAddresses(int fd, long memoryAddress, int length);
235
236 private static native int read(int fd, ByteBuffer buf, int pos, int limit);
237 private static native int readAddress(int fd, long address, int pos, int limit);
238
239 private static native long newPipe();
240 }