@@ -238,3 +238,144 @@ split(char *line, int *pargc)
238238
239239 return argv ;
240240}
241+
242+
243+ #include <poll.h>
244+
245+ struct FDmsg
246+ {
247+ int msg ;
248+ FD * fd ;
249+ };
250+
251+ static FD * fds [100 ];
252+ static struct pollfd pfds [100 ];
253+ static int nfds ;
254+ static int pollpipe [2 ] = { -1 , -1 };
255+
256+ static void
257+ removeslot (int i )
258+ {
259+ pfds [i ].revents = 0 ;
260+ pfds [i ].events = 0 ;
261+ pfds [i ].fd = -1 ;
262+ fds [i ]-> fd = -1 ;
263+ fds [i ]-> id = -1 ;
264+ fds [i ]-> ready = 0 ;
265+ fds [i ] = nil ;
266+ }
267+
268+ static void
269+ pollfds (void )
270+ {
271+ struct FDmsg msg ;
272+ FD * fd ;
273+ int i , n ;
274+
275+ pipe (pollpipe );
276+ pfds [0 ].fd = pollpipe [0 ];
277+ pfds [0 ].events = POLLIN ;
278+ nfds = 1 ;
279+ for (;;) {
280+ n = poll (pfds , nfds , -1 );
281+ if (n < 0 ) {
282+ perror ("error poll" );
283+ return ;
284+ }
285+
286+ /* someone wants us to watch their fd or has closed it */
287+ if (pfds [0 ].revents & POLLIN ) {
288+ read (pfds [0 ].fd , & msg , sizeof (msg ));
289+ fd = msg .fd ;
290+ switch (msg .msg ) {
291+ // wait
292+ case 1 :
293+ if (fd -> id >= 0 ) {
294+ /* already in list */
295+ assert (fds [fd -> id ] == fd );
296+ //printf("polling fd %d in slot %d\n", fd->fd, fd->id);
297+ } else {
298+ /* add to list */
299+ for (i = 1 ; i < nfds ; i ++ )
300+ if (fds [i ] == nil )
301+ break ;
302+ assert (i < nelem (pfds ));
303+ if (i == nfds ) nfds ++ ;
304+ fd -> id = i ;
305+ fds [fd -> id ] = fd ;
306+ //printf("adding fd %d in slot %d\n", fd->fd, fd->id);
307+ }
308+ pfds [fd -> id ].fd = fd -> fd ;
309+ pfds [fd -> id ].events = POLLIN ;
310+ pfds [fd -> id ].revents = 0 ;
311+ fd -> ready = 0 ;
312+ break ;
313+
314+ // close
315+ case 2 :
316+ /* fd was closed */
317+ //printf("received close for fd %d slot %d\n", pfds[fd->id].fd, fd->id);
318+ assert (fd -> id >= 0 );
319+ close (pfds [fd -> id ].fd );
320+ removeslot (fd -> id );
321+ break ;
322+ }
323+ }
324+
325+ for (i = 1 ; i < nfds ; i ++ ) {
326+ /* fd was closed on other side */
327+ if (pfds [i ].revents & POLLHUP ) {
328+ //printf("fd %d hung up\n", pfds[i].fd);
329+ close (fds [i ]-> fd );
330+ removeslot (i );
331+ }
332+ if (pfds [i ].revents & POLLIN ) {
333+ //printf("fd %d became ready\n", pfds[i].fd);
334+ /* ignore this fd for now */
335+ pfds [i ].fd = -1 ;
336+ pfds [i ].events = 0 ;
337+ pfds [i ].revents = 0 ;
338+ fds [i ]-> ready = 1 ;
339+ }
340+ if (pfds [i ].revents )
341+ printf ("more events on fd %d: %d\n" , pfds [i ].fd , pfds [i ].revents );
342+ }
343+ }
344+ }
345+
346+ static void * pollthread (void * arg ) { pollfds (); return nil ; }
347+
348+ void
349+ startpolling (void )
350+ {
351+ pthread_t th ;
352+ pthread_create (& th , nil , pollthread , nil );
353+
354+ // wait for thread to start so waitfd can do its thing
355+ while (((volatile int * )pollpipe )[0 ] < 0 ) usleep (1000 );
356+ }
357+
358+ void
359+ waitfd (FD * fd )
360+ {
361+ struct FDmsg msg ;
362+ if (fd -> fd < 0 )
363+ return ;
364+ fd -> ready = 0 ;
365+ msg .msg = 1 ;
366+ msg .fd = fd ;
367+ write (pollpipe [1 ], & msg , sizeof (msg ));
368+ }
369+
370+ void
371+ closefd (FD * fd )
372+ {
373+ struct FDmsg msg ;
374+ printf ("closing fd %d\n" , fd -> fd );
375+ int i = fd -> id ;
376+ msg .msg = 2 ;
377+ msg .fd = fd ;
378+ write (pollpipe [1 ], & msg , sizeof (msg ));
379+ // wait for thread to notice
380+ while (((volatile FD * * )fds )[i ] != nil ) usleep (1 );
381+ }
0 commit comments