47 // The file descriptor associated with this channel
48 private final FileDescriptor fd;
49 private final int fdVal;
50
51 // Lock held by current writing thread
52 private final ReentrantLock writeLock = new ReentrantLock();
53
54 // Lock held by any thread that modifies the state fields declared below
55 // DO NOT invoke a blocking I/O operation while holding this lock!
56 private final Object stateLock = new Object();
57
58 // -- The following fields are protected by stateLock
59
60 // Channel state
61 private static final int ST_INUSE = 0;
62 private static final int ST_CLOSING = 1;
63 private static final int ST_CLOSED = 2;
64 private int state;
65
66 // ID of native thread doing write, for signalling
67 private long thread;
68
69 // True if the channel's socket has been forced into non-blocking mode
70 // by a virtual thread. It cannot be reset. When the channel is in
71 // blocking mode and the channel's socket is in non-blocking mode then
72 // operations that don't complete immediately will poll the socket and
73 // preserve the semantics of blocking operations.
74 private volatile boolean forcedNonBlocking;
75
76 // -- End of fields protected by stateLock
77
78
79 public FileDescriptor getFD() {
80 return fd;
81 }
82
83 public int getFDVal() {
84 return fdVal;
85 }
86
87 SinkChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException {
103 /**
104 * Ensures that the socket is configured non-blocking when on a virtual thread.
105 */
106 private void configureSocketNonBlockingIfVirtualThread() throws IOException {
107 assert writeLock.isHeldByCurrentThread();
108 if (!forcedNonBlocking && Thread.currentThread().isVirtual()) {
109 synchronized (stateLock) {
110 ensureOpen();
111 IOUtil.configureBlocking(fd, false);
112 forcedNonBlocking = true;
113 }
114 }
115 }
116
117 /**
118 * Closes the write end of the pipe if there are no write operation in
119 * progress and the channel is not registered with a Selector.
120 */
121 private boolean tryClose() throws IOException {
122 assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
123 if (thread == 0 && !isRegistered()) {
124 state = ST_CLOSED;
125 nd.close(fd);
126 return true;
127 } else {
128 return false;
129 }
130 }
131
132 /**
133 * Invokes tryClose to attempt to close the write end of the pipe.
134 *
135 * This method is used for deferred closing by I/O and Selector operations.
136 */
137 private void tryFinishClose() {
138 try {
139 tryClose();
140 } catch (IOException ignore) { }
141 }
142
143 /**
144 * Closes this channel when configured in blocking mode.
145 *
146 * If there is a write operation in progress then the write-end of the pipe
147 * is pre-closed and the writer is signalled, in which case the final close
148 * is deferred until the writer aborts.
149 */
150 private void implCloseBlockingMode() throws IOException {
151 synchronized (stateLock) {
152 assert state < ST_CLOSING;
153 state = ST_CLOSING;
154 if (!tryClose()) {
155 nd.preClose(fd, thread, 0);
156 }
157 }
158 }
159
160 /**
161 * Closes this channel when configured in non-blocking mode.
162 *
163 * If the channel is registered with a Selector then the close is deferred
164 * until the channel is flushed from all Selectors.
165 */
166 private void implCloseNonBlockingMode() throws IOException {
167 synchronized (stateLock) {
168 assert state < ST_CLOSING;
169 state = ST_CLOSING;
170 }
171 // wait for any write operation to complete before trying to close
172 writeLock.lock();
173 writeLock.unlock();
174 synchronized (stateLock) {
175 if (state == ST_CLOSING) {
253 int newOps = 0;
254 if (ops == SelectionKey.OP_WRITE)
255 newOps |= Net.POLLOUT;
256 return newOps;
257 }
258
259 /**
260 * Marks the beginning of a write operation that might block.
261 *
262 * @throws ClosedChannelException if the channel is closed
263 * @throws NotYetConnectedException if the channel is not yet connected
264 */
265 private void beginWrite(boolean blocking) throws ClosedChannelException {
266 if (blocking) {
267 // set hook for Thread.interrupt
268 begin();
269 }
270 synchronized (stateLock) {
271 ensureOpen();
272 if (blocking)
273 thread = NativeThread.current();
274 }
275 }
276
277 /**
278 * Marks the end of a write operation that may have blocked.
279 *
280 * @throws AsynchronousCloseException if the channel was closed due to this
281 * thread being interrupted on a blocking write operation.
282 */
283 private void endWrite(boolean blocking, boolean completed)
284 throws AsynchronousCloseException
285 {
286 if (blocking) {
287 synchronized (stateLock) {
288 thread = 0;
289 if (state == ST_CLOSING) {
290 tryFinishClose();
291 }
292 }
293 // remove hook for Thread.interrupt
294 end(completed);
295 }
296 }
297
298 @Override
299 public int write(ByteBuffer src) throws IOException {
300 Objects.requireNonNull(src);
301
302 writeLock.lock();
303 try {
304 ensureOpen();
305 boolean blocking = isBlocking();
306 int n = 0;
307 try {
308 beginWrite(blocking);
|
47 // The file descriptor associated with this channel
48 private final FileDescriptor fd;
49 private final int fdVal;
50
51 // Lock held by current writing thread
52 private final ReentrantLock writeLock = new ReentrantLock();
53
54 // Lock held by any thread that modifies the state fields declared below
55 // DO NOT invoke a blocking I/O operation while holding this lock!
56 private final Object stateLock = new Object();
57
58 // -- The following fields are protected by stateLock
59
60 // Channel state
61 private static final int ST_INUSE = 0;
62 private static final int ST_CLOSING = 1;
63 private static final int ST_CLOSED = 2;
64 private int state;
65
66 // ID of native thread doing write, for signalling
67 private NativeThread writer;
68
69 // True if the channel's socket has been forced into non-blocking mode
70 // by a virtual thread. It cannot be reset. When the channel is in
71 // blocking mode and the channel's socket is in non-blocking mode then
72 // operations that don't complete immediately will poll the socket and
73 // preserve the semantics of blocking operations.
74 private volatile boolean forcedNonBlocking;
75
76 // -- End of fields protected by stateLock
77
78
79 public FileDescriptor getFD() {
80 return fd;
81 }
82
83 public int getFDVal() {
84 return fdVal;
85 }
86
87 SinkChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException {
103 /**
104 * Ensures that the socket is configured non-blocking when on a virtual thread.
105 */
106 private void configureSocketNonBlockingIfVirtualThread() throws IOException {
107 assert writeLock.isHeldByCurrentThread();
108 if (!forcedNonBlocking && Thread.currentThread().isVirtual()) {
109 synchronized (stateLock) {
110 ensureOpen();
111 IOUtil.configureBlocking(fd, false);
112 forcedNonBlocking = true;
113 }
114 }
115 }
116
117 /**
118 * Closes the write end of the pipe if there are no write operation in
119 * progress and the channel is not registered with a Selector.
120 */
121 private boolean tryClose() throws IOException {
122 assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
123 if (writer == null && !isRegistered()) {
124 state = ST_CLOSED;
125 nd.close(fd);
126 return true;
127 } else {
128 return false;
129 }
130 }
131
132 /**
133 * Invokes tryClose to attempt to close the write end of the pipe.
134 *
135 * This method is used for deferred closing by I/O and Selector operations.
136 */
137 private void tryFinishClose() {
138 try {
139 tryClose();
140 } catch (IOException ignore) { }
141 }
142
143 /**
144 * Closes this channel when configured in blocking mode.
145 *
146 * If there is a write operation in progress then the write-end of the pipe
147 * is pre-closed and the writer is signalled, in which case the final close
148 * is deferred until the writer aborts.
149 */
150 private void implCloseBlockingMode() throws IOException {
151 synchronized (stateLock) {
152 assert state < ST_CLOSING;
153 state = ST_CLOSING;
154 if (!tryClose()) {
155 nd.preClose(fd, null, writer);
156 }
157 }
158 }
159
160 /**
161 * Closes this channel when configured in non-blocking mode.
162 *
163 * If the channel is registered with a Selector then the close is deferred
164 * until the channel is flushed from all Selectors.
165 */
166 private void implCloseNonBlockingMode() throws IOException {
167 synchronized (stateLock) {
168 assert state < ST_CLOSING;
169 state = ST_CLOSING;
170 }
171 // wait for any write operation to complete before trying to close
172 writeLock.lock();
173 writeLock.unlock();
174 synchronized (stateLock) {
175 if (state == ST_CLOSING) {
253 int newOps = 0;
254 if (ops == SelectionKey.OP_WRITE)
255 newOps |= Net.POLLOUT;
256 return newOps;
257 }
258
259 /**
260 * Marks the beginning of a write operation that might block.
261 *
262 * @throws ClosedChannelException if the channel is closed
263 * @throws NotYetConnectedException if the channel is not yet connected
264 */
265 private void beginWrite(boolean blocking) throws ClosedChannelException {
266 if (blocking) {
267 // set hook for Thread.interrupt
268 begin();
269 }
270 synchronized (stateLock) {
271 ensureOpen();
272 if (blocking)
273 writer = NativeThread.current();
274 }
275 }
276
277 /**
278 * Marks the end of a write operation that may have blocked.
279 *
280 * @throws AsynchronousCloseException if the channel was closed due to this
281 * thread being interrupted on a blocking write operation.
282 */
283 private void endWrite(boolean blocking, boolean completed)
284 throws AsynchronousCloseException
285 {
286 if (blocking) {
287 synchronized (stateLock) {
288 writer = null;
289 if (state == ST_CLOSING) {
290 tryFinishClose();
291 }
292 }
293 // remove hook for Thread.interrupt
294 end(completed);
295 }
296 }
297
298 @Override
299 public int write(ByteBuffer src) throws IOException {
300 Objects.requireNonNull(src);
301
302 writeLock.lock();
303 try {
304 ensureOpen();
305 boolean blocking = isBlocking();
306 int n = 0;
307 try {
308 beginWrite(blocking);
|