1 /* 2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <signal.h> 29 #include <pthread.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <sys/time.h> 33 #include <sys/resource.h> 34 #include <sys/uio.h> 35 #include <unistd.h> 36 #include <errno.h> 37 #include <sys/poll.h> 38 39 /* 40 * Stack allocated by thread when doing blocking operation 41 */ 42 typedef struct threadEntry { 43 pthread_t thr; /* this thread */ 44 struct threadEntry *next; /* next thread */ 45 int intr; /* interrupted */ 46 } threadEntry_t; 47 48 /* 49 * Heap allocated during initialized - one entry per fd 50 */ 51 typedef struct { 52 pthread_mutex_t lock; /* fd lock */ 53 threadEntry_t *threads; /* threads blocked on fd */ 54 } fdEntry_t; 55 56 /* 57 * Signal to unblock thread 58 */ 59 static int sigWakeup = (__SIGRTMAX - 2); 60 61 /* 62 * The fd table and the number of file descriptors 63 */ 64 static fdEntry_t *fdTable; 65 static int fdCount; 66 67 /* 68 * Null signal handler 69 */ 70 static void sig_wakeup(int sig) { 71 } 72 73 /* 74 * Initialization routine (executed when library is loaded) 75 * Allocate fd tables and sets up signal handler. 76 */ 77 static void __attribute((constructor)) init() { 78 struct rlimit nbr_files; 79 sigset_t sigset; 80 struct sigaction sa; 81 82 /* 83 * Allocate table based on the maximum number of 84 * file descriptors. 85 */ 86 getrlimit(RLIMIT_NOFILE, &nbr_files); 87 fdCount = nbr_files.rlim_max; 88 fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); 89 if (fdTable == NULL) { 90 fprintf(stderr, "library initialization failed - " 91 "unable to allocate file descriptor table - out of memory"); 92 abort(); 93 } 94 95 /* 96 * Setup the signal handler 97 */ 98 sa.sa_handler = sig_wakeup; 99 sa.sa_flags = 0; 100 sigemptyset(&sa.sa_mask); 101 sigaction(sigWakeup, &sa, NULL); 102 103 sigemptyset(&sigset); 104 sigaddset(&sigset, sigWakeup); 105 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 106 } 107 108 /* 109 * Return the fd table for this fd or NULL is fd out 110 * of range. 111 */ 112 static inline fdEntry_t *getFdEntry(int fd) 113 { 114 if (fd < 0 || fd >= fdCount) { 115 return NULL; 116 } 117 return &fdTable[fd]; 118 } 119 120 /* 121 * Start a blocking operation :- 122 * Insert thread onto thread list for the fd. 123 */ 124 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) 125 { 126 self->thr = pthread_self(); 127 self->intr = 0; 128 129 pthread_mutex_lock(&(fdEntry->lock)); 130 { 131 self->next = fdEntry->threads; 132 fdEntry->threads = self; 133 } 134 pthread_mutex_unlock(&(fdEntry->lock)); 135 } 136 137 /* 138 * End a blocking operation :- 139 * Remove thread from thread list for the fd 140 * If fd has been interrupted then set errno to EBADF 141 */ 142 static inline void endOp 143 (fdEntry_t *fdEntry, threadEntry_t *self) 144 { 145 int orig_errno = errno; 146 pthread_mutex_lock(&(fdEntry->lock)); 147 { 148 threadEntry_t *curr, *prev=NULL; 149 curr = fdEntry->threads; 150 while (curr != NULL) { 151 if (curr == self) { 152 if (curr->intr) { 153 orig_errno = EBADF; 154 } 155 if (prev == NULL) { 156 fdEntry->threads = curr->next; 157 } else { 158 prev->next = curr->next; 159 } 160 break; 161 } 162 prev = curr; 163 curr = curr->next; 164 } 165 } 166 pthread_mutex_unlock(&(fdEntry->lock)); 167 errno = orig_errno; 168 } 169 170 /* 171 * Close or dup2 a file descriptor ensuring that all threads blocked on 172 * the file descriptor are notified via a wakeup signal. 173 * 174 * fd1 < 0 => close(fd2) 175 * fd1 >= 0 => dup2(fd1, fd2) 176 * 177 * Returns -1 with errno set if operation fails. 178 */ 179 static int closefd(int fd1, int fd2) { 180 int rv, orig_errno; 181 fdEntry_t *fdEntry = getFdEntry(fd2); 182 if (fdEntry == NULL) { 183 errno = EBADF; 184 return -1; 185 } 186 187 /* 188 * Lock the fd to hold-off additional I/O on this fd. 189 */ 190 pthread_mutex_lock(&(fdEntry->lock)); 191 192 { 193 /* 194 * And close/dup the file descriptor 195 * (restart if interrupted by signal) 196 */ 197 do { 198 if (fd1 < 0) { 199 rv = close(fd2); 200 } else { 201 rv = dup2(fd1, fd2); 202 } 203 } while (rv == -1 && errno == EINTR); 204 205 /* 206 * Send a wakeup signal to all threads blocked on this 207 * file descriptor. 208 */ 209 threadEntry_t *curr = fdEntry->threads; 210 while (curr != NULL) { 211 curr->intr = 1; 212 pthread_kill( curr->thr, sigWakeup ); 213 curr = curr->next; 214 } 215 } 216 217 /* 218 * Unlock without destroying errno 219 */ 220 orig_errno = errno; 221 pthread_mutex_unlock(&(fdEntry->lock)); 222 errno = orig_errno; 223 224 return rv; 225 } 226 227 /* 228 * Wrapper for dup2 - same semantics as dup2 system call except 229 * that any threads blocked in an I/O system call on fd2 will be 230 * preempted and return -1/EBADF; 231 */ 232 int NET_Dup2(int fd, int fd2) { 233 if (fd < 0) { 234 errno = EBADF; 235 return -1; 236 } 237 return closefd(fd, fd2); 238 } 239 240 /* 241 * Wrapper for close - same semantics as close system call 242 * except that any threads blocked in an I/O on fd will be 243 * preempted and the I/O system call will return -1/EBADF. 244 */ 245 int NET_SocketClose(int fd) { 246 return closefd(-1, fd); 247 } 248 249 /************** Basic I/O operations here ***************/ 250 251 /* 252 * Macro to perform a blocking IO operation. Restarts 253 * automatically if interrupted by signal (other than 254 * our wakeup signal) 255 */ 256 #define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ 257 int ret; \ 258 threadEntry_t self; \ 259 fdEntry_t *fdEntry = getFdEntry(FD); \ 260 if (fdEntry == NULL) { \ 261 errno = EBADF; \ 262 return -1; \ 263 } \ 264 do { \ 265 startOp(fdEntry, &self); \ 266 ret = FUNC; \ 267 endOp(fdEntry, &self); \ 268 } while (ret == -1 && errno == EINTR); \ 269 return ret; \ 270 } 271 272 int NET_Read(int s, void* buf, size_t len) { 273 BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); 274 } 275 276 int NET_ReadV(int s, const struct iovec * vector, int count) { 277 BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); 278 } 279 280 int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, 281 struct sockaddr *from, socklen_t *fromlen) { 282 BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); 283 } 284 285 int NET_Send(int s, void *msg, int len, unsigned int flags) { 286 BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); 287 } 288 289 int NET_WriteV(int s, const struct iovec * vector, int count) { 290 BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); 291 } 292 293 int NET_SendTo(int s, const void *msg, int len, unsigned int 294 flags, const struct sockaddr *to, int tolen) { 295 BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); 296 } 297 298 int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { 299 BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); 300 } 301 302 int NET_Connect(int s, struct sockaddr *addr, int addrlen) { 303 BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); 304 } 305 306 int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { 307 BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); 308 } 309 310 /* 311 * Wrapper for poll(s, timeout). 312 * Auto restarts with adjusted timeout if interrupted by 313 * signal other than our wakeup signal. 314 */ 315 int NET_Timeout(int s, long timeout) { 316 long prevtime = 0, newtime; 317 struct timeval t; 318 fdEntry_t *fdEntry = getFdEntry(s); 319 320 /* 321 * Check that fd hasn't been closed. 322 */ 323 if (fdEntry == NULL) { 324 errno = EBADF; 325 return -1; 326 } 327 328 /* 329 * Pick up current time as may need to adjust timeout 330 */ 331 if (timeout > 0) { 332 gettimeofday(&t, NULL); 333 prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; 334 } 335 336 for(;;) { 337 struct pollfd pfd; 338 int rv; 339 threadEntry_t self; 340 341 /* 342 * Poll the fd. If interrupted by our wakeup signal 343 * errno will be set to EBADF. 344 */ 345 pfd.fd = s; 346 pfd.events = POLLIN | POLLERR; 347 348 startOp(fdEntry, &self); 349 rv = poll(&pfd, 1, timeout); 350 endOp(fdEntry, &self); 351 352 /* 353 * If interrupted then adjust timeout. If timeout 354 * has expired return 0 (indicating timeout expired). 355 */ 356 if (rv < 0 && errno == EINTR) { 357 if (timeout > 0) { 358 gettimeofday(&t, NULL); 359 newtime = t.tv_sec * 1000 + t.tv_usec / 1000; 360 timeout -= newtime - prevtime; 361 if (timeout <= 0) { 362 return 0; 363 } 364 prevtime = newtime; 365 } 366 } else { 367 return rv; 368 } 369 370 } 371 }