1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2016-12-28 Bernard first version 9 */ 10 #include <dfs.h> 11 #include <dfs_fs.h> 12 #include <dfs_posix.h> 13 14 #include <dfs_poll.h> 15 #include <dfs_select.h> 16 17 static void fdszero(fd_set *set, int nfds) 18 { 19 fd_mask *m; 20 int n; 21 22 /* 23 The 'sizeof(fd_set)' of the system space may differ from user space, 24 so the actual size of the 'fd_set' is determined here with the parameter 'nfds' 25 */ 26 m = (fd_mask*)set; 27 for (n = 0; n < nfds; n += (sizeof(fd_mask) * 8)) 28 { 29 rt_memset(m, 0, sizeof(fd_mask)); 30 m ++; 31 } 32 } 33 34 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) 35 { 36 int fd; 37 int npfds; 38 int msec; 39 int ndx; 40 int ret; 41 struct pollfd *pollset = RT_NULL; 42 43 /* How many pollfd structures do we need to allocate? */ 44 for (fd = 0, npfds = 0; fd < nfds; fd++) 45 { 46 /* Check if any monitor operation is requested on this fd */ 47 if ((readfds && FD_ISSET(fd, readfds)) || 48 (writefds && FD_ISSET(fd, writefds)) || 49 (exceptfds && FD_ISSET(fd, exceptfds))) 50 { 51 npfds++; 52 } 53 } 54 55 /* Allocate the descriptor list for poll() */ 56 if (npfds > 0) 57 { 58 pollset = (struct pollfd *)rt_calloc(npfds, sizeof(struct pollfd)); 59 if (!pollset) 60 { 61 return -1; 62 } 63 } 64 65 /* Initialize the descriptor list for poll() */ 66 for (fd = 0, ndx = 0; fd < nfds; fd++) 67 { 68 int incr = 0; 69 70 /* The readfs set holds the set of FDs that the caller can be assured 71 * of reading from without blocking. Note that POLLHUP is included as 72 * a read-able condition. POLLHUP will be reported at the end-of-file 73 * or when a connection is lost. In either case, the read() can then 74 * be performed without blocking. 75 */ 76 77 if (readfds && FD_ISSET(fd, readfds)) 78 { 79 pollset[ndx].fd = fd; 80 pollset[ndx].events |= POLLIN; 81 incr = 1; 82 } 83 84 if (writefds && FD_ISSET(fd, writefds)) 85 { 86 pollset[ndx].fd = fd; 87 pollset[ndx].events |= POLLOUT; 88 incr = 1; 89 } 90 91 if (exceptfds && FD_ISSET(fd, exceptfds)) 92 { 93 pollset[ndx].fd = fd; 94 incr = 1; 95 } 96 97 ndx += incr; 98 } 99 100 RT_ASSERT(ndx == npfds); 101 102 /* Convert the timeout to milliseconds */ 103 if (timeout) 104 { 105 msec = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; 106 } 107 else 108 { 109 msec = -1; 110 } 111 112 /* Then let poll do all of the real work. */ 113 114 ret = poll(pollset, npfds, msec); 115 116 /* Now set up the return values */ 117 if (readfds) 118 { 119 fdszero(readfds, nfds); 120 } 121 122 if (writefds) 123 { 124 fdszero(writefds, nfds); 125 } 126 127 if (exceptfds) 128 { 129 fdszero(exceptfds, nfds); 130 } 131 132 /* Convert the poll descriptor list back into selects 3 bitsets */ 133 134 if (ret > 0) 135 { 136 ret = 0; 137 for (ndx = 0; ndx < npfds; ndx++) 138 { 139 /* Check for read conditions. Note that POLLHUP is included as a 140 * read condition. POLLHUP will be reported when no more data will 141 * be available (such as when a connection is lost). In either 142 * case, the read() can then be performed without blocking. 143 */ 144 145 if (readfds) 146 { 147 if (pollset[ndx].revents & (POLLIN | POLLHUP)) 148 { 149 FD_SET(pollset[ndx].fd, readfds); 150 ret++; 151 } 152 } 153 154 /* Check for write conditions */ 155 if (writefds) 156 { 157 if (pollset[ndx].revents & POLLOUT) 158 { 159 FD_SET(pollset[ndx].fd, writefds); 160 ret++; 161 } 162 } 163 164 /* Check for exceptions */ 165 if (exceptfds) 166 { 167 if (pollset[ndx].revents & POLLERR) 168 { 169 FD_SET(pollset[ndx].fd, exceptfds); 170 ret++; 171 } 172 } 173 } 174 } 175 176 if (pollset) rt_free(pollset); 177 178 return ret; 179 } 180 181