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