1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.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.netty5.channel.unix.Errors.ioResult;
25 import static io.netty5.channel.unix.Errors.newIOException;
26 import static io.netty5.channel.unix.Limits.IOV_MAX;
27 import static io.netty5.util.internal.ObjectUtil.checkPositiveOrZero;
28 import static java.lang.Math.min;
29 import static java.util.Objects.requireNonNull;
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 requireNonNull(path, "path");
180 int res = open(path);
181 if (res < 0) {
182 throw newIOException("open", res);
183 }
184 return new FileDescriptor(res);
185 }
186
187
188
189
190 public static FileDescriptor from(File file) throws IOException {
191 return from(requireNonNull(file, "file").getPath());
192 }
193
194
195
196
197 public static FileDescriptor[] pipe() throws IOException {
198 long res = newPipe();
199 if (res < 0) {
200 throw newIOException("newPipe", (int) res);
201 }
202 return new FileDescriptor[]{new FileDescriptor((int) (res >>> 32)), new FileDescriptor((int) res)};
203 }
204
205 final boolean casState(int expected, int update) {
206 return stateUpdater.compareAndSet(this, expected, update);
207 }
208
209 static boolean isClosed(int state) {
210 return (state & STATE_CLOSED_MASK) != 0;
211 }
212
213 static boolean isInputShutdown(int state) {
214 return (state & STATE_INPUT_SHUTDOWN_MASK) != 0;
215 }
216
217 static boolean isOutputShutdown(int state) {
218 return (state & STATE_OUTPUT_SHUTDOWN_MASK) != 0;
219 }
220
221 static int inputShutdown(int state) {
222 return state | STATE_INPUT_SHUTDOWN_MASK;
223 }
224
225 static int outputShutdown(int state) {
226 return state | STATE_OUTPUT_SHUTDOWN_MASK;
227 }
228
229 private static native int open(String path);
230 private static native int close(int fd);
231
232 private static native int write(int fd, ByteBuffer buf, int pos, int limit);
233 private static native int writeAddress(int fd, long address, int pos, int limit);
234 private static native long writev(int fd, ByteBuffer[] buffers, int offset, int length, long maxBytesToWrite);
235 private static native long writevAddresses(int fd, long memoryAddress, int length);
236
237 private static native int read(int fd, ByteBuffer buf, int pos, int limit);
238 private static native int readAddress(int fd, long address, int pos, int limit);
239
240 private static native long newPipe();
241 }