View Javadoc
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    *   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.unix.Buffer;
19  import io.netty.util.internal.PlatformDependent;
20  import io.netty.util.internal.UnstableApi;
21  
22  import java.nio.ByteBuffer;
23  
24  /**
25   * This is an internal datastructure which can be directly passed to epoll_wait to reduce the overhead.
26   *
27   * typedef union epoll_data {
28   *     void        *ptr;
29   *     int          fd;
30   *     uint32_t     u32;
31   *     uint64_t     u64;
32   * } epoll_data_t;
33   *
34   * struct epoll_event {
35   *     uint32_t     events;      // Epoll events
36   *     epoll_data_t data;        // User data variable
37   * };
38   *
39   * We use {@code fd} if the {@code epoll_data union} to store the actual file descriptor of an
40   * {@link AbstractEpollChannel} and so be able to map it later.
41   */
42  @UnstableApi
43  public final class EpollEventArray {
44      // Size of the epoll_event struct
45      private static final int EPOLL_EVENT_SIZE = Native.sizeofEpollEvent();
46      // The offset of the data union in the epoll_event struct
47      private static final int EPOLL_DATA_OFFSET = Native.offsetofEpollData();
48  
49      private ByteBuffer memory;
50      private long memoryAddress;
51      private int length;
52  
53      EpollEventArray(int length) {
54          if (length < 1) {
55              throw new IllegalArgumentException("length must be >= 1 but was " + length);
56          }
57          this.length = length;
58          memory = Buffer.allocateDirectWithNativeOrder(calculateBufferCapacity(length));
59          memoryAddress = Buffer.memoryAddress(memory);
60      }
61  
62      /**
63       * Return the {@code memoryAddress} which points to the start of this {@link EpollEventArray}.
64       */
65      long memoryAddress() {
66          return memoryAddress;
67      }
68  
69      /**
70       * Return the length of the {@link EpollEventArray} which represent the maximum number of {@code epoll_events}
71       * that can be stored in it.
72       */
73      int length() {
74          return length;
75      }
76  
77      /**
78       * Increase the storage of this {@link EpollEventArray}.
79       */
80      void increase() {
81          // double the size
82          length <<= 1;
83          // There is no need to preserve what was in the memory before.
84          ByteBuffer buffer = Buffer.allocateDirectWithNativeOrder(calculateBufferCapacity(length));
85          Buffer.free(memory);
86          memory = buffer;
87          memoryAddress = Buffer.memoryAddress(buffer);
88      }
89  
90      /**
91       * Free this {@link EpollEventArray}. Any usage after calling this method may segfault the JVM!
92       */
93      void free() {
94          Buffer.free(memory);
95          memoryAddress = 0;
96      }
97  
98      /**
99       * Return the events for the {@code epoll_event} on this index.
100      */
101     int events(int index) {
102         return getInt(index, 0);
103     }
104 
105     /**
106      * Return the file descriptor for the {@code epoll_event} on this index.
107      */
108     int fd(int index) {
109         return getInt(index, EPOLL_DATA_OFFSET);
110     }
111 
112     private int getInt(int index, int offset) {
113         if (PlatformDependent.hasUnsafe()) {
114             long n = (long) index * EPOLL_EVENT_SIZE;
115             return PlatformDependent.getInt(memoryAddress + n + offset);
116         }
117         return memory.getInt(index * EPOLL_EVENT_SIZE + offset);
118     }
119 
120     private static int calculateBufferCapacity(int capacity) {
121         return capacity * EPOLL_EVENT_SIZE;
122     }
123 }