61
61
#define chdir _chdir
62
62
#else
63
63
#include <sys/ioctl.h>
64
+ #include <poll.h>
64
65
#if !defined(__wasi__ )
65
66
#include <dlfcn.h>
66
67
#include <termios.h>
@@ -2633,11 +2634,10 @@ static int js_os_poll(JSContext *ctx)
2633
2634
{
2634
2635
JSRuntime * rt = JS_GetRuntime (ctx );
2635
2636
JSThreadState * ts = js_get_thread_state (rt );
2636
- int ret , fd_max , min_delay ;
2637
- fd_set rfds , wfds ;
2637
+ int r , w , ret , nfds , min_delay ;
2638
2638
JSOSRWHandler * rh ;
2639
2639
struct list_head * el ;
2640
- struct timeval tv , * tvp ;
2640
+ struct pollfd * pfd , * pfds , pfds_local [ 64 ] ;
2641
2641
2642
2642
/* only check signals in the main thread */
2643
2643
if (!ts -> recv_pipe &&
@@ -2663,67 +2663,83 @@ static int js_os_poll(JSContext *ctx)
2663
2663
if (list_empty (& ts -> os_rw_handlers ) && list_empty (& ts -> port_list ))
2664
2664
return -1 ; /* no more events */
2665
2665
2666
- tvp = NULL ;
2667
- if (min_delay >= 0 ) {
2668
- tv .tv_sec = min_delay / 1000 ;
2669
- tv .tv_usec = (min_delay % 1000 ) * 1000 ;
2670
- tvp = & tv ;
2666
+ nfds = 0 ;
2667
+ list_for_each (el , & ts -> os_rw_handlers ) {
2668
+ rh = list_entry (el , JSOSRWHandler , link );
2669
+ nfds += (!JS_IsNull (rh -> rw_func [0 ]) || !JS_IsNull (rh -> rw_func [1 ]));
2670
+ }
2671
+
2672
+ #ifdef USE_WORKER
2673
+ list_for_each (el , & ts -> port_list ) {
2674
+ JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
2675
+ nfds += !JS_IsNull (port -> on_message_func );
2676
+ }
2677
+ #endif // USE_WORKER
2678
+
2679
+ pfd = pfds = pfds_local ;
2680
+ if (nfds > (int )countof (pfds_local )) {
2681
+ pfd = pfds = js_malloc (ctx , nfds * sizeof (* pfd ));
2682
+ if (!pfd )
2683
+ return -1 ;
2671
2684
}
2672
2685
2673
- FD_ZERO (& rfds );
2674
- FD_ZERO (& wfds );
2675
- fd_max = -1 ;
2676
2686
list_for_each (el , & ts -> os_rw_handlers ) {
2677
2687
rh = list_entry (el , JSOSRWHandler , link );
2678
- fd_max = max_int (fd_max , rh -> fd );
2679
- if (!JS_IsNull (rh -> rw_func [0 ]))
2680
- FD_SET (rh -> fd , & rfds );
2681
- if (!JS_IsNull (rh -> rw_func [1 ]))
2682
- FD_SET (rh -> fd , & wfds );
2688
+ r = POLLIN * !JS_IsNull (rh -> rw_func [0 ]);
2689
+ w = POLLOUT * !JS_IsNull (rh -> rw_func [1 ]);
2690
+ if (r || w )
2691
+ * pfd ++ = (struct pollfd ){rh -> fd , r |w , 0 };
2683
2692
}
2684
2693
2685
2694
#ifdef USE_WORKER
2686
2695
list_for_each (el , & ts -> port_list ) {
2687
2696
JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
2688
2697
if (!JS_IsNull (port -> on_message_func )) {
2689
2698
JSWorkerMessagePipe * ps = port -> recv_pipe ;
2690
- fd_max = max_int (fd_max , ps -> waker .read_fd );
2691
- FD_SET (ps -> waker .read_fd , & rfds );
2699
+ * pfd ++ = (struct pollfd ){ps -> waker .read_fd , POLLIN , 0 };
2692
2700
}
2693
2701
}
2694
2702
#endif // USE_WORKER
2695
2703
2696
- ret = select (fd_max + 1 , & rfds , & wfds , NULL , tvp );
2697
- if (ret > 0 ) {
2698
- list_for_each (el , & ts -> os_rw_handlers ) {
2699
- rh = list_entry (el , JSOSRWHandler , link );
2700
- if (!JS_IsNull (rh -> rw_func [0 ]) &&
2701
- FD_ISSET (rh -> fd , & rfds )) {
2702
- return call_handler (ctx , rh -> rw_func [0 ]);
2704
+ // FIXME(bnoordhuis) the loop below is quadratic in theory but
2705
+ // linear-ish in practice because we bail out on the first hit,
2706
+ // i.e., it's probably good enough for now
2707
+ ret = 0 ;
2708
+ nfds = poll (pfds , nfds , min_delay );
2709
+ for (pfd = pfds ; nfds -- > 0 ; pfd ++ ) {
2710
+ rh = find_rh (ts , pfd -> fd );
2711
+ if (rh ) {
2712
+ r = (POLLERR |POLLHUP |POLLNVAL |POLLIN ) * !JS_IsNull (rh -> rw_func [0 ]);
2713
+ w = (POLLERR |POLLHUP |POLLNVAL |POLLOUT ) * !JS_IsNull (rh -> rw_func [1 ]);
2714
+ if (r & pfd -> revents ) {
2715
+ ret = call_handler (ctx , rh -> rw_func [0 ]);
2716
+ goto done ;
2703
2717
/* must stop because the list may have been modified */
2704
2718
}
2705
- if (! JS_IsNull ( rh -> rw_func [ 1 ]) &&
2706
- FD_ISSET ( rh -> fd , & wfds )) {
2707
- return call_handler ( ctx , rh -> rw_func [ 1 ]) ;
2719
+ if (w & pfd -> revents ) {
2720
+ ret = call_handler ( ctx , rh -> rw_func [ 1 ]);
2721
+ goto done ;
2708
2722
/* must stop because the list may have been modified */
2709
2723
}
2710
- }
2724
+ } else {
2711
2725
#ifdef USE_WORKER
2712
- list_for_each (el , & ts -> port_list ) {
2713
- JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
2714
- if (!JS_IsNull (port -> on_message_func )) {
2715
- JSWorkerMessagePipe * ps = port -> recv_pipe ;
2716
- if (FD_ISSET (ps -> waker .read_fd , & rfds )) {
2717
- if (handle_posted_message (rt , ctx , port ))
2718
- goto done ;
2726
+ list_for_each (el , & ts -> port_list ) {
2727
+ JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
2728
+ if (!JS_IsNull (port -> on_message_func )) {
2729
+ JSWorkerMessagePipe * ps = port -> recv_pipe ;
2730
+ if (pfd -> fd == ps -> waker .read_fd ) {
2731
+ if (handle_posted_message (rt , ctx , port ))
2732
+ goto done ;
2733
+ }
2719
2734
}
2720
2735
}
2721
- }
2722
2736
#endif // USE_WORKER
2737
+ }
2723
2738
}
2724
- goto done ; // silence unused label warning
2725
2739
done :
2726
- return 0 ;
2740
+ if (pfds != pfds_local )
2741
+ js_free (ctx , pfds );
2742
+ return ret ;
2727
2743
}
2728
2744
#endif // defined(_WIN32)
2729
2745
0 commit comments