1 /* 2 * Copyright 2025 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.uring; 17 18 import io.netty.util.internal.ObjectUtil; 19 20 import java.util.ArrayList; 21 import java.util.HashSet; 22 import java.util.List; 23 import java.util.Objects; 24 import java.util.Set; 25 26 /** 27 * Configuration class for an {@link IoUringIoHandler}, 28 * managing the settings for a {@link RingBuffer} and its io_uring file descriptor. 29 * 30 * <h3>Option Map</h3> 31 * These options are used exclusively during the initialization of the {@link IoUringIoHandler} 32 * to configure the associated io_uring instance. 33 * 34 * <p> 35 * The {@link IoUringIoHandlerConfig} class provides the following configurable options: 36 * </p> 37 * 38 * <table border="1" cellspacing="0" cellpadding="6"> 39 * <caption>Available Configuration Options</caption> 40 * <thead> 41 * <tr> 42 * <th>Setter Method</th> 43 * <th>Description</th> 44 * </tr> 45 * </thead> 46 * <tbody> 47 * <tr> 48 * <td>{@link IoUringIoHandlerConfig#setRingSize}</td> 49 * <td>Sets the size of the submission queue for the io_uring instance.</td> 50 * </tr> 51 * <tr> 52 * <td>{@link IoUringIoHandlerConfig#setMaxBoundedWorker}</td> 53 * <td>Defines the maximum number of bounded io_uring worker threads.</td> 54 * </tr> 55 * <tr> 56 * <td>{@link IoUringIoHandlerConfig#setMaxUnboundedWorker}</td> 57 * <td>Defines the maximum number of unbounded io_uring worker threads.</td> 58 * </tr> 59 * <tr> 60 * <td>{@link IoUringIoHandlerConfig#setBufferRingConfig}</td> 61 * <td> 62 * Adds a buffer ring configuration to the list of buffer ring configurations. 63 * It will be used to register the buffer ring for the io_uring instance. 64 * </td> 65 * </tr> 66 * </tbody> 67 * </table> 68 */ 69 70 public final class IoUringIoHandlerConfig { 71 private static final int DISABLE_SETUP_CQ_SIZE = -1; 72 73 private int ringSize = Native.DEFAULT_RING_SIZE; 74 private int cqSize = DISABLE_SETUP_CQ_SIZE; 75 76 private int maxBoundedWorker; 77 78 private int maxUnboundedWorker; 79 80 private Set<IoUringBufferRingConfig> bufferRingConfigs; 81 82 /** 83 * Return the ring size of the io_uring instance. 84 * @return the ring size of the io_uring instance. 85 */ 86 public int getRingSize() { 87 return ringSize; 88 } 89 90 /** 91 * Return the size of the io_uring cqe. 92 * @return the cq size of the io_uring. 93 */ 94 public int getCqSize() { 95 return cqSize; 96 } 97 98 /** 99 * Return the maximum number of bounded iowq worker threads. 100 * @return the maximum number of bounded iowq worker threads. 101 */ 102 public int getMaxBoundedWorker() { 103 return maxBoundedWorker; 104 } 105 106 /** 107 * Return the maximum number of unbounded iowq worker threads. 108 * @return the maximum number of unbounded iowq worker threads. 109 */ 110 public int getMaxUnboundedWorker() { 111 return maxUnboundedWorker; 112 } 113 114 /** 115 * Set the ring size of the io_uring instance. 116 * @param ringSize the ring size of the io_uring instance. 117 * @return reference to this, so the API can be used fluently 118 */ 119 public IoUringIoHandlerConfig setRingSize(int ringSize) { 120 this.ringSize = ObjectUtil.checkPositive(ringSize, "ringSize"); 121 return this; 122 } 123 124 /** 125 * Set the size of the io_uring cqe. 126 * @param cqSize the size of the io_uring cqe. 127 * @throws IllegalArgumentException if cqSize is less than ringSize, or not a power of 2 128 * @return reference to this, so the API can be used fluently 129 */ 130 public IoUringIoHandlerConfig setCqSize(int cqSize) { 131 ObjectUtil.checkPositive(cqSize, "cqSize"); 132 this.cqSize = checkCqSize(cqSize); 133 return this; 134 } 135 136 int checkCqSize(int cqSize) { 137 if (cqSize < ringSize) { 138 throw new IllegalArgumentException("cqSize must be greater than or equal to ringSize"); 139 } 140 141 boolean isPowerOfTwo = Integer.bitCount(cqSize) == 1; 142 if (!isPowerOfTwo) { 143 throw new IllegalArgumentException("cqSize: " + cqSize + " (expected: power of 2)"); 144 } 145 return cqSize; 146 } 147 148 /** 149 * Set the maximum number of bounded iowq worker threads. 150 * @param maxBoundedWorker the maximum number of bounded iowq worker threads, 151 * or 0 for the Linux kernel default 152 * @return reference to this, so the API can be used fluently 153 */ 154 public IoUringIoHandlerConfig setMaxBoundedWorker(int maxBoundedWorker) { 155 this.maxBoundedWorker = ObjectUtil.checkPositiveOrZero(maxBoundedWorker, "maxBoundedWorker"); 156 return this; 157 } 158 159 /** 160 * Set the maximum number of unbounded iowq worker threads. 161 * @param maxUnboundedWorker the maximum number of unbounded iowq worker threads, 162 * of 0 for the Linux kernel default 163 * @return reference to this, so the API can be used fluently 164 */ 165 public IoUringIoHandlerConfig setMaxUnboundedWorker(int maxUnboundedWorker) { 166 this.maxUnboundedWorker = ObjectUtil.checkPositiveOrZero(maxUnboundedWorker, "maxUnboundedWorker"); 167 return this; 168 } 169 170 /** 171 * Add a buffer ring configuration to the list of buffer ring configurations. 172 * Each {@link IoUringBufferRingConfig} must have a different {@link IoUringBufferRingConfig#bufferGroupId()}. 173 * 174 * @param ringConfig the buffer ring configuration to append. 175 * @return reference to this, so the API can be used fluently 176 */ 177 public IoUringIoHandlerConfig setBufferRingConfig(IoUringBufferRingConfig... ringConfig) { 178 Set<IoUringBufferRingConfig> configSet = new HashSet<>(ringConfig.length); 179 for (IoUringBufferRingConfig bufferRingConfig : ringConfig) { 180 if (!configSet.add(bufferRingConfig)) { 181 throw new IllegalArgumentException("Duplicated buffer group id: " + bufferRingConfig.bufferGroupId()); 182 } 183 } 184 bufferRingConfigs = configSet; 185 return this; 186 } 187 188 /** 189 * Get the list of buffer ring configurations. 190 * @return the copy of buffer ring configurations. 191 */ 192 public List<IoUringBufferRingConfig> getBufferRingConfigs() { 193 return new ArrayList<>(bufferRingConfigs); 194 } 195 196 boolean needRegisterIowqMaxWorker() { 197 return maxBoundedWorker > 0 || maxUnboundedWorker > 0; 198 } 199 200 boolean needSetupCqeSize() { 201 return cqSize != DISABLE_SETUP_CQ_SIZE; 202 } 203 204 Set<IoUringBufferRingConfig> getInternBufferRingConfigs() { 205 return bufferRingConfigs; 206 } 207 }