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 }