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 }
121