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