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      static final int EPOLL_ERR_OUT_MASK = EpollIoOps.EPOLLERR.value | EpollIoOps.EPOLLOUT.value;
55      static final int EPOLL_ERR_IN_MASK = EpollIoOps.EPOLLERR.value | EpollIoOps.EPOLLIN.value;
56      static final int EPOLL_RDHUP_MASK = EpollIoOps.EPOLLRDHUP.value;
57  
58      // Just use an array to store often used values.
59      private static final EpollIoEvent[] EVENTS;
60  
61      static {
62          EpollIoOps all = new EpollIoOps(EPOLLOUT.value | EPOLLIN.value | EPOLLERR.value | EPOLLRDHUP.value);
63          EVENTS = new EpollIoEvent[all.value + 1];
64          addToArray(EVENTS, EPOLLOUT);
65          addToArray(EVENTS, EPOLLIN);
66          addToArray(EVENTS, EPOLLERR);
67          addToArray(EVENTS, EPOLLRDHUP);
68          addToArray(EVENTS, all);
69      }
70  
71      private static void addToArray(EpollIoEvent[] array, EpollIoOps ops) {
72          array[ops.value] = new DefaultEpollIoEvent(ops);
73      }
74  
75      final int value;
76  
77      private EpollIoOps(int value) {
78          this.value = value;
79      }
80  
81      /**
82       * Returns {@code true} if this {@link EpollIoOps} is a combination of the given {@link EpollIoOps}.
83       * @param ops   the ops.
84       * @return      {@code true} if a combination of the given.
85       */
86      public boolean contains(EpollIoOps ops) {
87          return (value & ops.value) != 0;
88      }
89  
90      boolean contains(int value) {
91          return (this.value & value) != 0;
92      }
93  
94      /**
95       * Return a {@link EpollIoOps} which is a combination of the current and the given {@link EpollIoOps}.
96       *
97       * @param ops   the {@link EpollIoOps} that should be added to this one.
98       * @return      a {@link EpollIoOps}.
99       */
100     public EpollIoOps with(EpollIoOps ops) {
101         if (contains(ops)) {
102             return this;
103         }
104         return valueOf(value | ops.value());
105     }
106 
107     /**
108      * Return a {@link EpollIoOps} which is not a combination of the current and the given {@link EpollIoOps}.
109      *
110      * @param ops   the {@link EpollIoOps} that should be remove from this one.
111      * @return      a {@link EpollIoOps}.
112      */
113     public EpollIoOps without(EpollIoOps ops) {
114         if (!contains(ops)) {
115             return this;
116         }
117         return valueOf(value & ~ops.value());
118     }
119 
120     /**
121      * Returns the underlying value of the {@link EpollIoOps}.
122      *
123      * @return value.
124      */
125     public int value() {
126         return value;
127     }
128 
129     @Override
130     public boolean equals(Object o) {
131         if (this == o) {
132             return true;
133         }
134         if (o == null || getClass() != o.getClass()) {
135             return false;
136         }
137         EpollIoOps nioOps = (EpollIoOps) o;
138         return value == nioOps.value;
139     }
140 
141     @Override
142     public int hashCode() {
143         return value;
144     }
145 
146     /**
147      * Returns a {@link EpollIoOps} for the given value.
148      *
149      * @param   value the value
150      * @return  the {@link EpollIoOps}.
151      */
152     public static EpollIoOps valueOf(int value) {
153         return eventOf(value).ops();
154     }
155 
156     @Override
157     public String toString() {
158         return "EpollIoOps{" +
159                 "value=" + value +
160                 '}';
161     }
162 
163     static EpollIoEvent eventOf(int value) {
164         if (value > 0 && value < EVENTS.length) {
165             EpollIoEvent event = EVENTS[value];
166             if (event != null) {
167                 return event;
168             }
169         }
170         return new DefaultEpollIoEvent(new EpollIoOps(value));
171     }
172 
173     private static final class DefaultEpollIoEvent implements EpollIoEvent {
174         private final EpollIoOps ops;
175 
176         DefaultEpollIoEvent(EpollIoOps ops) {
177             this.ops = ops;
178         }
179 
180         @Override
181         public EpollIoOps ops() {
182             return ops;
183         }
184 
185         @Override
186         public boolean equals(Object o) {
187             if (this == o) {
188                 return true;
189             }
190             if (o == null || getClass() != o.getClass()) {
191                 return false;
192             }
193             EpollIoEvent event = (EpollIoEvent) o;
194             return event.ops().equals(ops());
195         }
196 
197         @Override
198         public int hashCode() {
199             return ops().hashCode();
200         }
201 
202         @Override
203         public String toString() {
204             return "DefaultEpollIoEvent{" +
205                     "ops=" + ops +
206                     '}';
207         }
208     }
209 }