1/**************************************************************************** 2 * fs/vfs/fs_select.c 3 * 4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved. 5 * Based on NuttX originally from nuttx source (nuttx/fs/ and nuttx/drivers/) 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 ****************************************************************************/ 20 21/**************************************************************************** 22 * Included Files 23 ****************************************************************************/ 24 25#include "vfs_config.h" 26 27#include "sys/select.h" 28 29#include "string.h" 30#include "unistd.h" 31#include "poll.h" 32#include "assert.h" 33#include "errno.h" 34 35#include "stdlib.h" 36 37#include "los_signal.h" 38#include "los_syscall.h" 39 40#ifndef CONFIG_DISABLE_POLL 41 42 43/**************************************************************************** 44 * Pre-processor Definitions 45 ****************************************************************************/ 46 47#define POLL_IN_SET (POLLIN | POLLRDNORM | POLLRDBAND | POLLHUP | POLLERR) 48#define POLL_OUT_SET (POLLOUT | POLLWRBAND | POLLWRNORM | POLLERR) 49#define POLL_EX_SET (POLLPRI) 50 51/* pollfd count in stack, optimization in order to avoid small memory allocation */ 52 53#define POLL_STACK_CNT 5 54 55/**************************************************************************** 56 * Private Functions 57 ****************************************************************************/ 58 59/**************************************************************************** 60 * Public Functions 61 ****************************************************************************/ 62extern unsigned int sleep(unsigned int seconds); 63 64/**************************************************************************** 65 * Name: select 66 * 67 * Description: 68 * select() allows a program to monitor multiple file descriptors, waiting 69 * until one or more of the file descriptors become "ready" for some class 70 * of I/O operation (e.g., input possible). A file descriptor is 71 * considered ready if it is possible to perform the corresponding I/O 72 * operation (e.g., read(2)) without blocking. 73 * 74 * NOTE: poll() is the fundamental API for performing such monitoring 75 * operation under NuttX. select() is provided for compatibility and 76 * is simply a layer of added logic on top of poll(). As such, select() 77 * is more wasteful of resources and poll() is the recommended API to be 78 * used. 79 * 80 * Input Parameters: 81 * nfds - the maximum fd number (+1) of any descriptor in any of the 82 * three sets. 83 * readfds - the set of descriptions to monitor for read-ready events 84 * writefds - the set of descriptions to monitor for write-ready events 85 * exceptfds - the set of descriptions to monitor for error events 86 * timeout - Return at this time if none of these events of interest 87 * occur. 88 * 89 * Returned Value: 90 * 0: Timer expired 91 * >0: The number of bits set in the three sets of descriptors 92 * -1: An error occurred (errno will be set appropriately) 93 * 94 ****************************************************************************/ 95 96int do_select(int nfds, fd_set *readfds, fd_set *writefds, 97 fd_set *exceptfds, struct timeval *timeout, PollFun poll) 98{ 99 struct pollfd *pollset = NULL; 100 struct pollfd pfd[POLL_STACK_CNT]; 101 int pfd_alloc_flag = 0; 102 int fd; 103 int npfds; 104 int msec; 105 int ndx; 106 int ret; 107 108 if (nfds < 0 || nfds >= FD_SETSIZE) 109 { 110 set_errno(EINVAL); 111 return VFS_ERROR; 112 } 113 114 /* How many pollfd structures do we need to allocate? */ 115 116 /* Initialize the descriptor list for poll() */ 117 118 for (fd = 0, npfds = 0; fd < nfds; fd++) 119 { 120 /* Check if any monitor operation is requested on this fd */ 121 122 if ((readfds && FD_ISSET(fd, readfds)) || 123 (writefds && FD_ISSET(fd, writefds)) || 124 (exceptfds && FD_ISSET(fd, exceptfds))) 125 { 126 /* Yes.. increment the count of pollfds structures needed */ 127 128 npfds++; 129 } 130 } 131 132 /* Allocate the descriptor list for poll() */ 133 134 if (npfds != 0) 135 { 136 /* use stack variable in order to avoid small memory allocation. */ 137 138 if (npfds <= POLL_STACK_CNT) 139 { 140 pollset = pfd; 141 (void)memset_s(pollset, npfds * sizeof(struct pollfd), 0, npfds * sizeof(struct pollfd)); 142 } 143 else 144 { 145 pollset = (struct pollfd *)zalloc(npfds * sizeof(struct pollfd)); 146 if (pollset == NULL) 147 { 148 set_errno(ENOMEM); 149 return VFS_ERROR; 150 } 151 pfd_alloc_flag = 1; 152 } 153 } 154 else 155 { 156 /* If the readfds, writefds, and exceptfds arguments are all null pointers and 157 * the timeout argument is not a null pointer, the select() function shall block for 158 * the time specified. If the readfds, writefds, and exceptfds arguments are all 159 * null pointers and the timeout argument is a null pointer, this is NOT permitted 160 * as LiteOS doesn't support Signal machanism, so select() can't come back anymore. 161 */ 162 163 if (timeout != NULL) 164 { 165 /* 1000000 : Convert seconds to microseconds. */ 166 167 if ((long long)timeout->tv_sec * 1000000 > 0xffffffff) 168 { 169 (void)sleep(timeout->tv_sec); 170 } 171 else 172 { 173 (void)usleep(timeout->tv_sec * 1000000 + timeout->tv_usec); 174 } 175 return OK; 176 } 177 else 178 { 179 set_errno(EINVAL); 180 return VFS_ERROR; 181 } 182 } 183 184 /* Initialize the descriptor list for poll() */ 185 186 for (fd = 0, ndx = 0; fd < nfds; fd++) 187 { 188 int incr = 0; 189 190 /* The readfs set holds the set of FDs that the caller can be assured 191 * of reading from without blocking. Note that POLLHUP is included as 192 * a read-able condition. POLLHUP will be reported at the end-of-file 193 * or when a connection is lost. In either case, the read() can then 194 * be performed without blocking. 195 */ 196 197 if (readfds && FD_ISSET(fd, readfds)) 198 { 199 pollset[ndx].fd = fd; 200 pollset[ndx].events |= (POLLIN | POLLRDNORM); 201 incr = 1; 202 } 203 204 /* The writefds set holds the set of FDs that the caller can be assured 205 * of writing to without blocking. 206 */ 207 208 if (writefds && FD_ISSET(fd, writefds)) 209 { 210 pollset[ndx].fd = fd; 211 pollset[ndx].events |= (POLLOUT | POLLWRNORM); 212 incr = 1; 213 } 214 215 /* The exceptfds set holds the set of FDs that are watched for exceptions */ 216 217 if (exceptfds && FD_ISSET(fd, exceptfds)) 218 { 219 pollset[ndx].fd = fd; 220 incr = 1; 221 } 222 223 ndx += incr; 224 } 225 226 DEBUGASSERT(ndx == npfds); 227 228 /* Convert the timeout to milliseconds */ 229 230 if (timeout) 231 { 232 /* Calculate the timeout in milliseconds */ 233 234 msec = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; 235 } 236 else 237 { 238 /* Any negative value of msec means no timeout */ 239 240 msec = -1; 241 } 242 243 /* Then let poll do all of the real work. */ 244 245 ret = poll(pollset, npfds, msec); 246 247 /* Now set up the return values */ 248 249 if (readfds) 250 { 251 (void)memset_s(readfds, sizeof(fd_set), 0, sizeof(fd_set)); 252 } 253 254 if (writefds) 255 { 256 (void)memset_s(writefds, sizeof(fd_set), 0, sizeof(fd_set)); 257 } 258 259 if (exceptfds) 260 { 261 (void)memset_s(exceptfds, sizeof(fd_set), 0, sizeof(fd_set)); 262 } 263 264 /* Convert the poll descriptor list back into selects 3 bitsets */ 265 266 if (ret > 0) 267 { 268 ret = 0; 269 for (ndx = 0; ndx < npfds; ndx++) 270 { 271 /* Check for read conditions. Note that POLLHUP is included as a 272 * read condition. POLLHUP will be reported when no more data will 273 * be available (such as when a connection is lost). In either 274 * case, the read() can then be performed without blocking. 275 */ 276 277 if (readfds) 278 { 279 if (pollset[ndx].revents & POLL_IN_SET) 280 { 281 FD_SET(pollset[ndx].fd, readfds); 282 ret++; 283 } 284 } 285 286 /* Check for write conditions */ 287 288 if (writefds) 289 { 290 if (pollset[ndx].revents & POLL_OUT_SET) 291 { 292 FD_SET(pollset[ndx].fd, writefds); 293 ret++; 294 } 295 } 296 297 /* Check for exceptions */ 298 299 if (exceptfds) 300 { 301 if (pollset[ndx].revents & POLL_EX_SET) 302 { 303 FD_SET(pollset[ndx].fd, exceptfds); 304 ret++; 305 } 306 } 307 } 308 } 309 310 if (pfd_alloc_flag) 311 { 312 free(pollset); 313 } 314 return ret; 315} 316 317int select(int nfds, fd_set *readfds, fd_set *writefds, 318 fd_set *exceptfds, struct timeval *timeout) 319{ 320 return do_select(nfds, readfds, writefds, exceptfds, timeout, poll); 321} 322 323#endif /* CONFIG_DISABLE_POLL */ 324