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