View Javadoc
1   /*
2    * Copyright 2024 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    *   https://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.channel.IoOps;
19  
20  /**
21   * Implementation of {@link IoOps} that is used by {@link EpollIoHandler} and so for epoll based transports.
22   */
23  public final class EpollIoOps implements IoOps {
24  
25      static {
26          // Need to ensure we load the native lib before trying to use the values in Native to construct the different
27          // instances.
28          Epoll.ensureAvailability();
29      }
30  
31      /**
32       * Interested in IO events which tell that the underlying channel is writable again or a connection
33       * attempt can be continued.
34       */
35      public static final EpollIoOps EPOLLOUT = new EpollIoOps(Native.EPOLLOUT);
36  
37      /**
38       * Interested in IO events which should be handled by finish pending connect operations
39       */
40      public static final EpollIoOps EPOLLIN = new EpollIoOps(Native.EPOLLIN);
41  
42      /**
43       * Error condition happened on the associated file descriptor.
44       */
45      public static final EpollIoOps EPOLLERR = new EpollIoOps(Native.EPOLLERR);
46  
47      /**
48       * Interested in IO events which should be handled by reading data.
49       */
50      public static final EpollIoOps EPOLLRDHUP = new EpollIoOps(Native.EPOLLRDHUP);
51  
52      public static final EpollIoOps EPOLLET = new EpollIoOps(Native.EPOLLET);
53  
54      /**
55       * Special {@link EpollIoOps} which basically means we are not interested in any event and so should remove the
56       * fd from underlying epoll fd.
57       */
58      public static final EpollIoOps NONE = new EpollIoOps(0);
59  
60      static final int EPOLL_ERR_OUT_MASK = EpollIoOps.EPOLLERR.value | EpollIoOps.EPOLLOUT.value;
61      static final int EPOLL_ERR_IN_MASK = EpollIoOps.EPOLLERR.value | EpollIoOps.EPOLLIN.value;
62      static final int EPOLL_RDHUP_MASK = EpollIoOps.EPOLLRDHUP.value;
63  
64      // Just use an array to store often used values.
65      private static final EpollIoEvent[] EVENTS;
66  
67      static {
68          EpollIoOps all = new EpollIoOps(EPOLLOUT.value | EPOLLIN.value | EPOLLERR.value | EPOLLRDHUP.value);
69          EVENTS = new EpollIoEvent[all.value + 2];
70          addToArray(EVENTS, NONE);
71          addToArray(EVENTS, EPOLLOUT);
72          addToArray(EVENTS, EPOLLIN);
73          addToArray(EVENTS, EPOLLERR);
74          addToArray(EVENTS, EPOLLRDHUP);
75          addToArray(EVENTS, all);
76      }
77  
78      private static void addToArray(EpollIoEvent[] array, EpollIoOps ops) {
79          array[ops.value] = new DefaultEpollIoEvent(ops);
80      }
81  
82      final int value;
83  
84      private EpollIoOps(int value) {
85          this.value = value;
86      }
87  
88      /**
89       * Returns {@code true} if this {@link EpollIoOps} is a combination of the given {@link EpollIoOps}.
90       * @param ops   the ops.
91       * @return      {@code true} if a combination of the given.
92       */
93      public boolean contains(EpollIoOps ops) {
94          return (value & ops.value) != 0;
95      }
96  
97      boolean contains(int value) {
98          return (this.value & value) != 0;
99      }
100 
101     /**
102      * Return a {@link EpollIoOps} which is a combination of the current and the given {@link EpollIoOps}.
103      *
104      * @param ops   the {@link EpollIoOps} that should be added to this one.
105      * @return      a {@link EpollIoOps}.
106      */
107     public EpollIoOps with(EpollIoOps ops) {
108         if (contains(ops)) {
109             return this;
110         }
111         return valueOf(value | ops.value());
112     }
113 
114     /**
115      * Return a {@link EpollIoOps} which is not a combination of the current and the given {@link EpollIoOps}.
116      *
117      * @param ops   the {@link EpollIoOps} that should be remove from this one.
118      * @return      a {@link EpollIoOps}.
119      */
120     public EpollIoOps without(EpollIoOps ops) {
121         if (!contains(ops)) {
122             return this;
123         }
124         return valueOf(value & ~ops.value());
125     }
126 
127     /**
128      * Returns the underlying value of the {@link EpollIoOps}.
129      *
130      * @return value.
131      */
132     public int value() {
133         return value;
134     }
135 
136     @Override
137     public boolean equals(Object o) {
138         if (this == o) {
139             return true;
140         }
141         if (o == null || getClass() != o.getClass()) {
142             return false;
143         }
144         EpollIoOps nioOps = (EpollIoOps) o;
145         return value == nioOps.value;
146     }
147 
148     @Override
149     public int hashCode() {
150         return value;
151     }
152 
153     /**
154      * Returns a {@link EpollIoOps} for the given value.
155      *
156      * @param   value the value
157      * @return  the {@link EpollIoOps}.
158      */
159     public static EpollIoOps valueOf(int value) {
160         return eventOf(value).ops();
161     }
162 
163     @Override
164     public String toString() {
165         return "EpollIoOps{" +
166                 "value=" + value +
167                 '}';
168     }
169 
170     static EpollIoEvent eventOf(int value) {
171         if (value > 0 && value < EVENTS.length) {
172             EpollIoEvent event = EVENTS[value];
173             if (event != null) {
174                 return event;
175             }
176         }
177         return new DefaultEpollIoEvent(new EpollIoOps(value));
178     }
179 
180     private static final class DefaultEpollIoEvent implements EpollIoEvent {
181         private final EpollIoOps ops;
182 
183         DefaultEpollIoEvent(EpollIoOps ops) {
184             this.ops = ops;
185         }
186 
187         @Override
188         public EpollIoOps ops() {
189             return ops;
190         }
191 
192         @Override
193         public boolean equals(Object o) {
194             if (this == o) {
195                 return true;
196             }
197             if (o == null || getClass() != o.getClass()) {
198                 return false;
199             }
200             EpollIoEvent event = (EpollIoEvent) o;
201             return event.ops().equals(ops());
202         }
203 
204         @Override
205         public int hashCode() {
206             return ops().hashCode();
207         }
208 
209         @Override
210         public String toString() {
211             return "DefaultEpollIoEvent{" +
212                     "ops=" + ops +
213                     '}';
214         }
215     }
216 }