2020-08-28 14:02:51 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2020 The Netty Project
|
|
|
|
*
|
|
|
|
* The Netty Project licenses this file to you under the Apache License,
|
|
|
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
|
|
|
* with the License. You may obtain a copy of the License at:
|
|
|
|
*
|
2020-10-28 14:38:14 +01:00
|
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
2020-08-28 14:02:51 +02:00
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
|
|
|
*/
|
2020-08-24 16:34:32 +02:00
|
|
|
package io.netty.buffer.b2;
|
|
|
|
|
Update with support for shared segments
Motivation:
We wish to make as little use of Unsafe as possible, yet have a flexible buffer API.
With the proposed support for shared segments, we're able to clean up our buffer API and simplify the implementation.
Modification:
With shared segments, we are able to implement TransferSend using supported APIs.
This allows us to remove RendezvousSend, and also our hacks in Statics.
TransferSend now works by first creating a shared segment and using that for the handover.
On the receiving end, if the segment was originally thread-confined, it will once again become
confined, but this time to the receiver thread.
Shared segments are just passed directly to their new owners.
Pooled allocators always create shared memory segments for their buffers, so they can be
shared easily via the pool.
Result:
We now have buffer ownership transfer with nice, convenient, APIs, and we have buffer pooling,
all using supported APIs.
2020-09-07 16:51:43 +02:00
|
|
|
public abstract class RcSupport<I extends Rc<I>, T extends RcSupport<I, T>> implements Rc<I> {
|
2020-08-24 16:34:32 +02:00
|
|
|
private int acquires; // Closed if negative.
|
|
|
|
private final Drop<T> drop;
|
|
|
|
|
|
|
|
RcSupport(Drop<T> drop) {
|
|
|
|
this.drop = drop;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Increment the reference count.
|
|
|
|
* <p>
|
|
|
|
* Note, this method is not thread-safe because Rc's are meant to thread-confined.
|
|
|
|
*
|
|
|
|
* @return This Rc instance.
|
|
|
|
*/
|
|
|
|
@Override
|
Update with support for shared segments
Motivation:
We wish to make as little use of Unsafe as possible, yet have a flexible buffer API.
With the proposed support for shared segments, we're able to clean up our buffer API and simplify the implementation.
Modification:
With shared segments, we are able to implement TransferSend using supported APIs.
This allows us to remove RendezvousSend, and also our hacks in Statics.
TransferSend now works by first creating a shared segment and using that for the handover.
On the receiving end, if the segment was originally thread-confined, it will once again become
confined, but this time to the receiver thread.
Shared segments are just passed directly to their new owners.
Pooled allocators always create shared memory segments for their buffers, so they can be
shared easily via the pool.
Result:
We now have buffer ownership transfer with nice, convenient, APIs, and we have buffer pooling,
all using supported APIs.
2020-09-07 16:51:43 +02:00
|
|
|
public final I acquire() {
|
2020-08-24 16:34:32 +02:00
|
|
|
if (acquires < 0) {
|
|
|
|
throw new IllegalStateException("Resource is closed.");
|
|
|
|
}
|
2020-10-15 16:20:26 +02:00
|
|
|
if (acquires == Integer.MAX_VALUE) {
|
|
|
|
throw new IllegalStateException("Cannot acquire more references; counter would overflow.");
|
|
|
|
}
|
2020-08-24 16:34:32 +02:00
|
|
|
acquires++;
|
|
|
|
return self();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decrement the reference count, and despose of the resource if the last reference is closed.
|
|
|
|
* <p>
|
|
|
|
* Note, this method is not thread-safe because Rc's are meant to be thread-confined.
|
|
|
|
*
|
|
|
|
* @throws IllegalStateException If this Rc has already been closed.
|
|
|
|
*/
|
|
|
|
@Override
|
Update with support for shared segments
Motivation:
We wish to make as little use of Unsafe as possible, yet have a flexible buffer API.
With the proposed support for shared segments, we're able to clean up our buffer API and simplify the implementation.
Modification:
With shared segments, we are able to implement TransferSend using supported APIs.
This allows us to remove RendezvousSend, and also our hacks in Statics.
TransferSend now works by first creating a shared segment and using that for the handover.
On the receiving end, if the segment was originally thread-confined, it will once again become
confined, but this time to the receiver thread.
Shared segments are just passed directly to their new owners.
Pooled allocators always create shared memory segments for their buffers, so they can be
shared easily via the pool.
Result:
We now have buffer ownership transfer with nice, convenient, APIs, and we have buffer pooling,
all using supported APIs.
2020-09-07 16:51:43 +02:00
|
|
|
public final void close() {
|
2020-08-24 16:34:32 +02:00
|
|
|
if (acquires == -1) {
|
2020-10-15 16:20:26 +02:00
|
|
|
throw new IllegalStateException("Double-free: Resource already closed and dropped.");
|
2020-08-24 16:34:32 +02:00
|
|
|
}
|
|
|
|
if (acquires == 0) {
|
2020-08-28 12:17:41 +02:00
|
|
|
drop.drop(impl());
|
2020-08-24 16:34:32 +02:00
|
|
|
}
|
|
|
|
acquires--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send this Rc instance to another Thread, transferring the ownership to the recipient. This method can be used
|
|
|
|
* when the receiving thread is not known up front.
|
|
|
|
* <p>
|
|
|
|
* This instance immediately becomes inaccessible, and all attempts at accessing this Rc will throw. Calling {@link
|
|
|
|
* #close()} will have no effect, so this method is safe to call within a try-with-resources statement.
|
|
|
|
*
|
2020-10-15 16:20:26 +02:00
|
|
|
* @throws IllegalStateException if this object has any outstanding acquires; that is, if this object has been
|
|
|
|
* {@link #acquire() acquired} more times than it has been {@link #close() closed}.
|
2020-08-24 16:34:32 +02:00
|
|
|
*/
|
|
|
|
@Override
|
Update with support for shared segments
Motivation:
We wish to make as little use of Unsafe as possible, yet have a flexible buffer API.
With the proposed support for shared segments, we're able to clean up our buffer API and simplify the implementation.
Modification:
With shared segments, we are able to implement TransferSend using supported APIs.
This allows us to remove RendezvousSend, and also our hacks in Statics.
TransferSend now works by first creating a shared segment and using that for the handover.
On the receiving end, if the segment was originally thread-confined, it will once again become
confined, but this time to the receiver thread.
Shared segments are just passed directly to their new owners.
Pooled allocators always create shared memory segments for their buffers, so they can be
shared easily via the pool.
Result:
We now have buffer ownership transfer with nice, convenient, APIs, and we have buffer pooling,
all using supported APIs.
2020-09-07 16:51:43 +02:00
|
|
|
public final Send<I> send() {
|
2020-10-30 14:21:20 +01:00
|
|
|
if (!isSendable()) {
|
|
|
|
throw notSendableException();
|
2020-10-15 16:20:26 +02:00
|
|
|
}
|
|
|
|
var owned = prepareSend();
|
2020-11-10 14:36:39 +01:00
|
|
|
acquires = -2; // Close without dropping. This also ignore future double-free attempts.
|
2020-10-15 16:20:26 +02:00
|
|
|
return new TransferSend<I, T>(owned, drop);
|
2020-08-24 16:34:32 +02:00
|
|
|
}
|
|
|
|
|
2020-10-30 14:21:20 +01:00
|
|
|
protected IllegalStateException notSendableException() {
|
|
|
|
return new IllegalStateException(
|
2020-11-10 14:36:39 +01:00
|
|
|
"Cannot send() a reference counted object with " + acquires + " outstanding acquires: " + this + '.');
|
2020-10-30 14:21:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isSendable() {
|
|
|
|
return acquires == 0;
|
|
|
|
}
|
|
|
|
|
2020-11-12 14:55:42 +01:00
|
|
|
@Override
|
|
|
|
public int countBorrows() {
|
|
|
|
return acquires;
|
|
|
|
}
|
|
|
|
|
2020-08-24 16:34:32 +02:00
|
|
|
/**
|
|
|
|
* Prepare this instance for ownsership transfer. This method is called from {@link #send()} in the sending thread.
|
|
|
|
* This method should put this Rc in a deactivated state where it is no longer accessible from the currently owning
|
2020-10-28 14:38:14 +01:00
|
|
|
* thread. In this state, the Rc instance should only allow a call to {@link Owned#transferOwnership(Drop)} in
|
2020-08-24 16:34:32 +02:00
|
|
|
* the recipient thread.
|
|
|
|
*
|
|
|
|
* @return This Rc instance in a deactivated state.
|
|
|
|
*/
|
Update with support for shared segments
Motivation:
We wish to make as little use of Unsafe as possible, yet have a flexible buffer API.
With the proposed support for shared segments, we're able to clean up our buffer API and simplify the implementation.
Modification:
With shared segments, we are able to implement TransferSend using supported APIs.
This allows us to remove RendezvousSend, and also our hacks in Statics.
TransferSend now works by first creating a shared segment and using that for the handover.
On the receiving end, if the segment was originally thread-confined, it will once again become
confined, but this time to the receiver thread.
Shared segments are just passed directly to their new owners.
Pooled allocators always create shared memory segments for their buffers, so they can be
shared easily via the pool.
Result:
We now have buffer ownership transfer with nice, convenient, APIs, and we have buffer pooling,
all using supported APIs.
2020-09-07 16:51:43 +02:00
|
|
|
protected abstract Owned<T> prepareSend();
|
2020-08-28 12:17:41 +02:00
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
private I self() {
|
|
|
|
return (I) this;
|
2020-08-24 16:34:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
2020-08-28 12:17:41 +02:00
|
|
|
private T impl() {
|
2020-08-24 16:34:32 +02:00
|
|
|
return (T) this;
|
|
|
|
}
|
|
|
|
}
|