blob: 090c77e6774d300a080f69485f742b076f958629 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#include "jni.h"
27#include "jni_util.h"
28#include "jvm.h"
29#include "jlong.h"
30#include "sun_nio_ch_DevPollArrayWrapper.h"
31#include <sys/poll.h>
32#include <sys/resource.h>
33#include <unistd.h>
34#include <sys/time.h>
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40typedef uint32_t caddr32_t;
41
42/* /dev/poll ioctl */
43#define DPIOC (0xD0 << 8)
44#define DP_POLL (DPIOC | 1) /* poll on fds in cached in /dev/poll */
45#define DP_ISPOLLED (DPIOC | 2) /* is this fd cached in /dev/poll */
46#define DEVPOLLSIZE 1000 /* /dev/poll table size increment */
47#define POLLREMOVE 0x0800 /* Removes fd from monitored set */
48
49/*
50 * /dev/poll DP_POLL ioctl format
51 */
52typedef struct dvpoll {
53 pollfd_t *dp_fds; /* pollfd array */
54 nfds_t dp_nfds; /* num of pollfd's in dp_fds[] */
55 int dp_timeout; /* time out in millisec */
56} dvpoll_t;
57
58typedef struct dvpoll32 {
59 caddr32_t dp_fds; /* pollfd array */
60 uint32_t dp_nfds; /* num of pollfd's in dp_fds[] */
61 int32_t dp_timeout; /* time out in millisec */
62} dvpoll32_t;
63
64#ifdef __cplusplus
65}
66#endif
67
68#define RESTARTABLE(_cmd, _result) do { \
69 do { \
70 _result = _cmd; \
71 } while((_result == -1) && (errno == EINTR)); \
72} while(0)
73
74static int
75idevpoll(jint wfd, int dpctl, struct dvpoll a)
76{
77 jlong start, now;
78 int remaining = a.dp_timeout;
79 struct timeval t;
80 int diff;
81
82 gettimeofday(&t, NULL);
83 start = t.tv_sec * 1000 + t.tv_usec / 1000;
84
85 for (;;) {
86 /* poll(7d) ioctl does not return remaining count */
87 int res = ioctl(wfd, dpctl, &a);
88 if (res < 0 && errno == EINTR) {
89 if (remaining >= 0) {
90 gettimeofday(&t, NULL);
91 now = t.tv_sec * 1000 + t.tv_usec / 1000;
92 diff = now - start;
93 remaining -= diff;
94 if (diff < 0 || remaining <= 0) {
95 return 0;
96 }
97 start = now;
98 }
99 } else {
100 return res;
101 }
102 }
103}
104
105JNIEXPORT jint JNICALL
106Java_sun_nio_ch_DevPollArrayWrapper_init(JNIEnv *env, jobject this)
107{
108 int wfd = open("/dev/poll", O_RDWR);
109 if (wfd < 0) {
110 JNU_ThrowIOExceptionWithLastError(env, "Error opening driver");
111 return -1;
112 }
113 return wfd;
114}
115
116JNIEXPORT void JNICALL
117Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this,
118 jint wfd, jint fd, jint mask)
119{
120 struct pollfd a[2];
121 unsigned char *pollBytes = (unsigned char *)&a[0];
122 unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * 2;
123
124 /* We clear it first, otherwise any entries between poll invocations
125 get OR'd together */
126 a[0].fd = fd;
127 a[0].events = POLLREMOVE;
128 a[0].revents = 0;
129
130 a[1].fd = fd;
131 a[1].events = mask;
132 a[1].revents = 0;
133
134 while (pollBytes < pollEnd) {
135 int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes));
136 if (bytesWritten < 0) {
137 JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
138 return;
139 }
140 pollBytes += bytesWritten;
141 }
142}
143
144JNIEXPORT void JNICALL
145Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple(JNIEnv *env, jobject this,
146 jint wfd, jlong address,
147 jint len)
148{
149 unsigned char *pollBytes = (unsigned char *)jlong_to_ptr(address);
150 unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * len;
151 while (pollBytes < pollEnd) {
152 int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes));
153 if (bytesWritten < 0) {
154 JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
155 return;
156 }
157 pollBytes += bytesWritten;
158 }
159}
160
161JNIEXPORT jint JNICALL
162Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this,
163 jlong address, jint numfds,
164 jlong timeout, jint wfd)
165{
166 struct dvpoll a;
167 void *pfd = (void *) jlong_to_ptr(address);
168 int result = 0;
169
170 a.dp_fds = pfd;
171 a.dp_nfds = numfds;
172 a.dp_timeout = (int)timeout;
173
174 if (timeout <= 0) { /* Indefinite or no wait */
175 RESTARTABLE (ioctl(wfd, DP_POLL, &a), result);
176 } else { /* Bounded wait; bounded restarts */
177 result = idevpoll(wfd, DP_POLL, a);
178 }
179
180 if (result < 0) {
181 JNU_ThrowIOExceptionWithLastError(env, "Error reading driver");
182 return -1;
183 }
184 return result;
185}
186
187JNIEXPORT jint JNICALL
188Java_sun_nio_ch_DevPollArrayWrapper_fdLimit(JNIEnv *env, jclass this)
189{
190 struct rlimit rlp;
191 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) {
192 JNU_ThrowIOExceptionWithLastError(env,
193 "getrlimit failed");
194 }
195 return (jint)rlp.rlim_max;
196}
197
198JNIEXPORT void JNICALL
199Java_sun_nio_ch_DevPollArrayWrapper_interrupt(JNIEnv *env, jclass this, jint fd)
200{
201 int fakebuf[1];
202 fakebuf[0] = 1;
203 if (write(fd, fakebuf, 1) < 0) {
204 JNU_ThrowIOExceptionWithLastError(env,
205 "Write to interrupt fd failed");
206 }
207}