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