1 /*
2  * Copyright 2015 The Netty Project
3  *
4  * The Netty Project licenses this file to you under the Apache License,
5  * version 2.0 (the "License"); you may not use this file except in compliance
6  * with the License. You may obtain a copy of the License at:
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */

16 package io.netty.channel.epoll;
17
18 import io.netty.buffer.ByteBufAllocator;
19 import io.netty.channel.ChannelException;
20 import io.netty.channel.ChannelOption;
21 import io.netty.channel.DefaultChannelConfig;
22 import io.netty.channel.MessageSizeEstimator;
23 import io.netty.channel.RecvByteBufAllocator;
24 import io.netty.channel.WriteBufferWaterMark;
25 import io.netty.util.internal.ObjectUtil;
26
27 import java.io.IOException;
28 import java.util.Map;
29
30 import static io.netty.channel.unix.Limits.SSIZE_MAX;
31
32 public class EpollChannelConfig extends DefaultChannelConfig {
33     private volatile long maxBytesPerGatheringWrite = SSIZE_MAX;
34
35     EpollChannelConfig(AbstractEpollChannel channel) {
36         super(channel);
37     }
38
39     @Override
40     public Map<ChannelOption<?>, Object> getOptions() {
41         return getOptions(super.getOptions(), EpollChannelOption.EPOLL_MODE);
42     }
43
44     @SuppressWarnings("unchecked")
45     @Override
46     public <T> T getOption(ChannelOption<T> option) {
47         if (option == EpollChannelOption.EPOLL_MODE) {
48             return (T) getEpollMode();
49         }
50         return super.getOption(option);
51     }
52
53     @Override
54     public <T> boolean setOption(ChannelOption<T> option, T value) {
55         validate(option, value);
56         if (option == EpollChannelOption.EPOLL_MODE) {
57             setEpollMode((EpollMode) value);
58         } else {
59             return super.setOption(option, value);
60         }
61         return true;
62     }
63
64     @Override
65     public EpollChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
66         super.setConnectTimeoutMillis(connectTimeoutMillis);
67         return this;
68     }
69
70     @Override
71     @Deprecated
72     public EpollChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
73         super.setMaxMessagesPerRead(maxMessagesPerRead);
74         return this;
75     }
76
77     @Override
78     public EpollChannelConfig setWriteSpinCount(int writeSpinCount) {
79         super.setWriteSpinCount(writeSpinCount);
80         return this;
81     }
82
83     @Override
84     public EpollChannelConfig setAllocator(ByteBufAllocator allocator) {
85         super.setAllocator(allocator);
86         return this;
87     }
88
89     @Override
90     public EpollChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
91         if (!(allocator.newHandle() instanceof RecvByteBufAllocator.ExtendedHandle)) {
92             throw new IllegalArgumentException("allocator.newHandle() must return an object of type: " +
93                     RecvByteBufAllocator.ExtendedHandle.class);
94         }
95         super.setRecvByteBufAllocator(allocator);
96         return this;
97     }
98
99     @Override
100     public EpollChannelConfig setAutoRead(boolean autoRead) {
101         super.setAutoRead(autoRead);
102         return this;
103     }
104
105     @Override
106     @Deprecated
107     public EpollChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
108         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
109         return this;
110     }
111
112     @Override
113     @Deprecated
114     public EpollChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
115         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
116         return this;
117     }
118
119     @Override
120     public EpollChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) {
121         super.setWriteBufferWaterMark(writeBufferWaterMark);
122         return this;
123     }
124
125     @Override
126     public EpollChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
127         super.setMessageSizeEstimator(estimator);
128         return this;
129     }
130
131     /**
132      * Return the {@link EpollMode} used. Default is
133      * {@link EpollMode#EDGE_TRIGGERED}. If you want to use {@link #isAutoRead()} {@code false} or
134      * {@link #getMaxMessagesPerRead()} and have an accurate behaviour you should use
135      * {@link EpollMode#LEVEL_TRIGGERED}.
136      */

137     public EpollMode getEpollMode() {
138         return ((AbstractEpollChannel) channel).isFlagSet(Native.EPOLLET)
139                 ? EpollMode.EDGE_TRIGGERED : EpollMode.LEVEL_TRIGGERED;
140     }
141
142     /**
143      * Set the {@link EpollMode} used. Default is
144      * {@link EpollMode#EDGE_TRIGGERED}. If you want to use {@link #isAutoRead()} {@code false} or
145      * {@link #getMaxMessagesPerRead()} and have an accurate behaviour you should use
146      * {@link EpollMode#LEVEL_TRIGGERED}.
147      *
148      * <strong>Be aware this config setting can only be adjusted before the channel was registered.</strong>
149      */

150     public EpollChannelConfig setEpollMode(EpollMode mode) {
151         ObjectUtil.checkNotNull(mode, "mode");
152
153         try {
154             switch (mode) {
155             case EDGE_TRIGGERED:
156                 checkChannelNotRegistered();
157                 ((AbstractEpollChannel) channel).setFlag(Native.EPOLLET);
158                 break;
159             case LEVEL_TRIGGERED:
160                 checkChannelNotRegistered();
161                 ((AbstractEpollChannel) channel).clearFlag(Native.EPOLLET);
162                 break;
163             default:
164                 throw new Error();
165             }
166         } catch (IOException e) {
167             throw new ChannelException(e);
168         }
169         return this;
170     }
171
172     private void checkChannelNotRegistered() {
173         if (channel.isRegistered()) {
174             throw new IllegalStateException("EpollMode can only be changed before channel is registered");
175         }
176     }
177
178     @Override
179     protected final void autoReadCleared() {
180         ((AbstractEpollChannel) channel).clearEpollIn();
181     }
182
183     final void setMaxBytesPerGatheringWrite(long maxBytesPerGatheringWrite) {
184         this.maxBytesPerGatheringWrite = maxBytesPerGatheringWrite;
185     }
186
187     final long getMaxBytesPerGatheringWrite() {
188         return maxBytesPerGatheringWrite;
189     }
190 }
191