6161#define chdir _chdir
6262#else
6363#include <sys/ioctl.h>
64+ #include <poll.h>
6465#if !defined(__wasi__ )
6566#include <dlfcn.h>
6667#include <termios.h>
@@ -2633,11 +2634,10 @@ static int js_os_poll(JSContext *ctx)
26332634{
26342635 JSRuntime * rt = JS_GetRuntime (ctx );
26352636 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 ;
26382638 JSOSRWHandler * rh ;
26392639 struct list_head * el ;
2640- struct timeval tv , * tvp ;
2640+ struct pollfd * pfd , * pfds , pfds_local [ 64 ] ;
26412641
26422642 /* only check signals in the main thread */
26432643 if (!ts -> recv_pipe &&
@@ -2663,67 +2663,83 @@ static int js_os_poll(JSContext *ctx)
26632663 if (list_empty (& ts -> os_rw_handlers ) && list_empty (& ts -> port_list ))
26642664 return -1 ; /* no more events */
26652665
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 ;
26712684 }
26722685
2673- FD_ZERO (& rfds );
2674- FD_ZERO (& wfds );
2675- fd_max = -1 ;
26762686 list_for_each (el , & ts -> os_rw_handlers ) {
26772687 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 };
26832692 }
26842693
26852694#ifdef USE_WORKER
26862695 list_for_each (el , & ts -> port_list ) {
26872696 JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
26882697 if (!JS_IsNull (port -> on_message_func )) {
26892698 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 };
26922700 }
26932701 }
26942702#endif // USE_WORKER
26952703
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 ;
27032717 /* must stop because the list may have been modified */
27042718 }
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 ;
27082722 /* must stop because the list may have been modified */
27092723 }
2710- }
2724+ } else {
27112725#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+ }
27192734 }
27202735 }
2721- }
27222736#endif // USE_WORKER
2737+ }
27232738 }
2724- goto done ; // silence unused label warning
27252739done :
2726- return 0 ;
2740+ if (pfds != pfds_local )
2741+ js_free (ctx , pfds );
2742+ return ret ;
27272743}
27282744#endif // defined(_WIN32)
27292745
0 commit comments