2828struct delayed_write_args {
2929 int fd ;
3030 int delay_ms ;
31+ int close_after_write ;
3132};
3233
3334struct delayed_connect_args {
3435 int port ;
3536 int delay_ms ;
3637};
3738
39+ enum native_block_kind {
40+ NATIVE_BLOCK_ACCEPT = 3 ,
41+ NATIVE_BLOCK_POLL = 5 ,
42+ NATIVE_BLOCK_SELECT = 6 ,
43+ NATIVE_BLOCK_EPOLL_WAIT = 7
44+ };
45+
46+ static jlong native_blocker (enum native_block_kind kind , int blocker_id ) {
47+ return (jlong )(((uint64_t )kind << 32 ) | (uint32_t )blocker_id );
48+ }
49+
3850static void sleep_ms (int delay_ms ) {
3951 if (delay_ms <= 0 ) {
4052 return ;
@@ -63,13 +75,24 @@ static void throw_out_of_memory(JNIEnv* env) {
6375 }
6476}
6577
78+ static void throw_timeout (JNIEnv * env , const char * operation ) {
79+ jclass exception_class = (* env )-> FindClass (env , "java/io/IOException" );
80+ if (exception_class != NULL ) {
81+ char message [256 ];
82+ snprintf (message , sizeof (message ), "%s timed out" , operation );
83+ (* env )-> ThrowNew (env , exception_class , message );
84+ }
85+ }
86+
6687static void * delayed_write (void * arg ) {
6788 struct delayed_write_args * args = (struct delayed_write_args * )arg ;
6889 sleep_ms (args -> delay_ms );
6990 uint64_t value = 1 ;
7091 while (write (args -> fd , & value , sizeof (value )) < 0 && errno == EINTR ) {
7192 }
72- close (args -> fd );
93+ if (args -> close_after_write ) {
94+ close (args -> fd );
95+ }
7396 free (args );
7497 return NULL ;
7598}
@@ -91,7 +114,7 @@ static void* delayed_connect(void* arg) {
91114 return NULL ;
92115}
93116
94- static int start_delayed_write (JNIEnv * env , int fd , int delay_ms ) {
117+ static int start_delayed_write (JNIEnv * env , int fd , int delay_ms , int close_after_write ) {
95118 struct delayed_write_args * args =
96119 (struct delayed_write_args * )malloc (sizeof (struct delayed_write_args ));
97120 if (args == NULL ) {
@@ -100,6 +123,7 @@ static int start_delayed_write(JNIEnv* env, int fd, int delay_ms) {
100123 }
101124 args -> fd = fd ;
102125 args -> delay_ms = delay_ms ;
126+ args -> close_after_write = close_after_write ;
103127 pthread_t thread ;
104128 int rc = pthread_create (& thread , NULL , delayed_write , args );
105129 if (rc != 0 ) {
@@ -133,77 +157,94 @@ static int start_delayed_connect(JNIEnv* env, int port, int delay_ms) {
133157 return 0 ;
134158}
135159
136- static void block_with_poll_like (JNIEnv * env , jint delay_ms , int use_ppoll ) {
160+ static jlong block_with_poll_like (JNIEnv * env , jint delay_ms , int use_ppoll ) {
137161 int fds [2 ];
138162 if (pipe (fds ) != 0 ) {
139163 throw_io_exception (env , "pipe" );
140- return ;
164+ return 0 ;
141165 }
142- if (start_delayed_write (env , fds [1 ], delay_ms ) != 0 ) {
166+ if (start_delayed_write (env , fds [1 ], delay_ms , 1 ) != 0 ) {
143167 close (fds [0 ]);
144168 close (fds [1 ]);
145- return ;
169+ return 0 ;
146170 }
147171
148172 struct pollfd pfd ;
149173 pfd .fd = fds [0 ];
150174 pfd .events = POLLIN ;
151175 pfd .revents = 0 ;
152176 int rc ;
153- if (use_ppoll ) {
154- rc = ppoll (& pfd , 1 , NULL , NULL );
155- } else {
156- rc = poll (& pfd , 1 , -1 );
157- }
177+ do {
178+ if (use_ppoll ) {
179+ struct timespec timeout_ts = {5 , 0 };
180+ rc = ppoll (& pfd , 1 , & timeout_ts , NULL );
181+ } else {
182+ rc = poll (& pfd , 1 , 5000 );
183+ }
184+ } while (rc < 0 && errno == EINTR );
158185 close (fds [0 ]);
159186 if (rc < 0 ) {
160187 throw_io_exception (env , use_ppoll ? "ppoll" : "poll" );
188+ return 0 ;
189+ } else if (rc == 0 ) {
190+ throw_timeout (env , use_ppoll ? "ppoll" : "poll" );
191+ return 0 ;
161192 }
193+ return native_blocker (NATIVE_BLOCK_POLL , 0 );
162194}
163195
164- JNIEXPORT void JNICALL
196+ JNIEXPORT jlong JNICALL
165197Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingPpoll (
166198 JNIEnv * env , jclass clazz , jint delay_ms ) {
167199 (void )clazz ;
168- block_with_poll_like (env , delay_ms , 1 );
200+ return block_with_poll_like (env , delay_ms , 1 );
169201}
170202
171- JNIEXPORT void JNICALL
203+ JNIEXPORT jlong JNICALL
172204Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingPselect (
173205 JNIEnv * env , jclass clazz , jint delay_ms ) {
174206 (void )clazz ;
175207 int fds [2 ];
176208 if (pipe (fds ) != 0 ) {
177209 throw_io_exception (env , "pipe" );
178- return ;
210+ return 0 ;
179211 }
180- if (start_delayed_write (env , fds [1 ], delay_ms ) != 0 ) {
212+ if (start_delayed_write (env , fds [1 ], delay_ms , 1 ) != 0 ) {
181213 close (fds [0 ]);
182214 close (fds [1 ]);
183- return ;
215+ return 0 ;
184216 }
185217
186- fd_set readfds ;
187- FD_ZERO (& readfds );
188- FD_SET (fds [0 ], & readfds );
189- int rc = pselect (fds [0 ] + 1 , & readfds , NULL , NULL , NULL , NULL );
218+ int rc ;
219+ do {
220+ fd_set readfds ;
221+ FD_ZERO (& readfds );
222+ FD_SET (fds [0 ], & readfds );
223+ struct timespec timeout = {5 , 0 };
224+ rc = pselect (fds [0 ] + 1 , & readfds , NULL , NULL , & timeout , NULL );
225+ } while (rc < 0 && errno == EINTR );
190226 close (fds [0 ]);
191227 if (rc < 0 ) {
192228 throw_io_exception (env , "pselect" );
229+ return 0 ;
230+ } else if (rc == 0 ) {
231+ throw_timeout (env , "pselect" );
232+ return 0 ;
193233 }
234+ return native_blocker (NATIVE_BLOCK_SELECT , 0 );
194235}
195236
196- static void block_with_epoll (JNIEnv * env , jint delay_ms , int use_pwait ) {
237+ static jlong block_with_epoll (JNIEnv * env , jint delay_ms , int use_pwait ) {
197238 int event_fd = eventfd (0 , EFD_CLOEXEC );
198239 if (event_fd < 0 ) {
199240 throw_io_exception (env , "eventfd" );
200- return ;
241+ return 0 ;
201242 }
202243 int epfd = epoll_create1 (EPOLL_CLOEXEC );
203244 if (epfd < 0 ) {
204245 close (event_fd );
205246 throw_io_exception (env , "epoll_create1" );
206- return ;
247+ return 0 ;
207248 }
208249 struct epoll_event event ;
209250 memset (& event , 0 , sizeof (event ));
@@ -213,49 +254,58 @@ static void block_with_epoll(JNIEnv* env, jint delay_ms, int use_pwait) {
213254 close (epfd );
214255 close (event_fd );
215256 throw_io_exception (env , "epoll_ctl" );
216- return ;
257+ return 0 ;
217258 }
218- if (start_delayed_write (env , event_fd , delay_ms ) != 0 ) {
259+ if (start_delayed_write (env , event_fd , delay_ms , 0 ) != 0 ) {
219260 close (epfd );
220261 close (event_fd );
221- return ;
262+ return 0 ;
222263 }
223264
224265 struct epoll_event out_event ;
225266 int rc ;
226- if (use_pwait ) {
227- rc = epoll_pwait (epfd , & out_event , 1 , -1 , NULL );
228- } else {
229- rc = epoll_wait (epfd , & out_event , 1 , -1 );
230- }
267+ do {
268+ if (use_pwait ) {
269+ rc = epoll_pwait (epfd , & out_event , 1 , 5000 , NULL );
270+ } else {
271+ rc = epoll_wait (epfd , & out_event , 1 , 5000 );
272+ }
273+ } while (rc < 0 && errno == EINTR );
274+ jlong blocker = native_blocker (NATIVE_BLOCK_EPOLL_WAIT , epfd );
231275 close (epfd );
276+ close (event_fd );
232277 if (rc < 0 ) {
233278 throw_io_exception (env , use_pwait ? "epoll_pwait" : "epoll_wait" );
279+ return 0 ;
280+ } else if (rc == 0 ) {
281+ throw_timeout (env , use_pwait ? "epoll_pwait" : "epoll_wait" );
282+ return 0 ;
234283 }
284+ return blocker ;
235285}
236286
237- JNIEXPORT void JNICALL
287+ JNIEXPORT jlong JNICALL
238288Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingEpollWait (
239289 JNIEnv * env , jclass clazz , jint delay_ms ) {
240290 (void )clazz ;
241- block_with_epoll (env , delay_ms , 0 );
291+ return block_with_epoll (env , delay_ms , 0 );
242292}
243293
244- JNIEXPORT void JNICALL
294+ JNIEXPORT jlong JNICALL
245295Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingEpollPwait (
246296 JNIEnv * env , jclass clazz , jint delay_ms ) {
247297 (void )clazz ;
248- block_with_epoll (env , delay_ms , 1 );
298+ return block_with_epoll (env , delay_ms , 1 );
249299}
250300
251- JNIEXPORT void JNICALL
301+ JNIEXPORT jlong JNICALL
252302Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingAccept4 (
253303 JNIEnv * env , jclass clazz , jint delay_ms ) {
254304 (void )clazz ;
255305 int server_fd = socket (AF_INET , SOCK_STREAM , 0 );
256306 if (server_fd < 0 ) {
257307 throw_io_exception (env , "socket" );
258- return ;
308+ return 0 ;
259309 }
260310 int one = 1 ;
261311 setsockopt (server_fd , SOL_SOCKET , SO_REUSEADDR , & one , sizeof (one ));
@@ -269,28 +319,31 @@ Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingAccept4(
269319 listen (server_fd , 1 ) != 0 ) {
270320 close (server_fd );
271321 throw_io_exception (env , "bind/listen" );
272- return ;
322+ return 0 ;
273323 }
274324
275325 socklen_t addr_len = sizeof (addr );
276326 if (getsockname (server_fd , (struct sockaddr * )& addr , & addr_len ) != 0 ) {
277327 close (server_fd );
278328 throw_io_exception (env , "getsockname" );
279- return ;
329+ return 0 ;
280330 }
281331 if (start_delayed_connect (env , ntohs (addr .sin_port ), delay_ms ) != 0 ) {
282332 close (server_fd );
283- return ;
333+ return 0 ;
284334 }
285335
336+ jlong blocker = native_blocker (NATIVE_BLOCK_ACCEPT , server_fd );
286337 int accepted_fd = accept4 (server_fd , NULL , NULL , SOCK_CLOEXEC );
287338 if (accepted_fd >= 0 ) {
288339 close (accepted_fd );
289340 }
290341 close (server_fd );
291342 if (accepted_fd < 0 ) {
292343 throw_io_exception (env , "accept4" );
344+ return 0 ;
293345 }
346+ return blocker ;
294347}
295348
296349#else
@@ -302,44 +355,49 @@ static void unsupported(JNIEnv* env) {
302355 }
303356}
304357
305- JNIEXPORT void JNICALL
358+ JNIEXPORT jlong JNICALL
306359Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingAccept4 (
307360 JNIEnv * env , jclass clazz , jint delay_ms ) {
308361 (void )clazz ;
309362 (void )delay_ms ;
310363 unsupported (env );
364+ return 0 ;
311365}
312366
313- JNIEXPORT void JNICALL
367+ JNIEXPORT jlong JNICALL
314368Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingPpoll (
315369 JNIEnv * env , jclass clazz , jint delay_ms ) {
316370 (void )clazz ;
317371 (void )delay_ms ;
318372 unsupported (env );
373+ return 0 ;
319374}
320375
321- JNIEXPORT void JNICALL
376+ JNIEXPORT jlong JNICALL
322377Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingPselect (
323378 JNIEnv * env , jclass clazz , jint delay_ms ) {
324379 (void )clazz ;
325380 (void )delay_ms ;
326381 unsupported (env );
382+ return 0 ;
327383}
328384
329- JNIEXPORT void JNICALL
385+ JNIEXPORT jlong JNICALL
330386Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingEpollWait (
331387 JNIEnv * env , jclass clazz , jint delay_ms ) {
332388 (void )clazz ;
333389 (void )delay_ms ;
334390 unsupported (env );
391+ return 0 ;
335392}
336393
337- JNIEXPORT void JNICALL
394+ JNIEXPORT jlong JNICALL
338395Java_com_datadoghq_profiler_wallclock_NativeIoBlockHelper_blockingEpollPwait (
339396 JNIEnv * env , jclass clazz , jint delay_ms ) {
340397 (void )clazz ;
341398 (void )delay_ms ;
342399 unsupported (env );
400+ return 0 ;
343401}
344402
345403#endif
0 commit comments