Merge branch 'contrib_goto_focus'
[notion.git] / libmainloop / select.c
blob591fe3331566c6b839ec0301a5896130b8c25665
1 /*
2 * libmainloop/select.c
3 *
4 * Partly based on a contributed code.
6 * See the included file LICENSE for details.
7 */
9 #include <signal.h>
10 #include <sys/select.h>
11 #include <errno.h>
12 #include <string.h>
14 #include <libtu/types.h>
15 #include <libtu/misc.h>
16 #include <libtu/dlist.h>
18 #include "select.h"
19 #include "signal.h"
22 /*{{{ File descriptor management */
25 static WInputFd *input_fds=NULL;
27 static WInputFd *find_input_fd(int fd)
29 WInputFd *tmp=input_fds;
31 while(tmp){
32 if(tmp->fd==fd)
33 break;
34 tmp=tmp->next;
36 return tmp;
39 bool mainloop_register_input_fd(int fd, void *data,
40 void (*callback)(int fd, void *d))
42 WInputFd *tmp;
44 if(find_input_fd(fd)!=NULL)
45 return FALSE;
47 tmp=ALLOC(WInputFd);
48 if(tmp==NULL)
49 return FALSE;
51 tmp->fd=fd;
52 tmp->data=data;
53 tmp->process_input_fn=callback;
55 LINK_ITEM(input_fds, tmp, next, prev);
57 return TRUE;
60 void mainloop_unregister_input_fd(int fd)
62 WInputFd *tmp=find_input_fd(fd);
64 if(tmp!=NULL){
65 UNLINK_ITEM(input_fds, tmp, next, prev);
66 free(tmp);
70 static void set_input_fds(fd_set *rfds, int *nfds)
72 WInputFd *tmp=input_fds;
74 while(tmp){
75 FD_SET(tmp->fd, rfds);
76 if(tmp->fd>*nfds)
77 *nfds=tmp->fd;
78 tmp=tmp->next;
82 static void check_input_fds(fd_set *rfds)
84 WInputFd *tmp=input_fds, *next=NULL;
86 while(tmp){
87 next=tmp->next;
88 if(FD_ISSET(tmp->fd, rfds))
89 tmp->process_input_fn(tmp->fd, tmp->data);
90 tmp=next;
94 /*}}}*/
97 /*{{{ Select */
99 void mainloop_select()
101 fd_set rfds;
102 int nfds=0;
103 int ret=0;
106 #if _POSIX_SELECT || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
108 sigset_t oldmask;
110 FD_ZERO(&rfds);
111 set_input_fds(&rfds, &nfds);
113 mainloop_block_signals(&oldmask);
115 if(!mainloop_unhandled_signals())
116 ret=pselect(nfds+1, &rfds, NULL, NULL, NULL, &oldmask);
118 sigprocmask(SIG_SETMASK, &oldmask, NULL);
120 #else
121 #warning "pselect() unavailable -- using dirty hacks"
123 struct timeval tv={0, 0};
124 bool to;
126 /* If there are timers, make sure we return from select with
127 * some delay, if the timer signal happens right before
128 * entering select(). Race conditions with other signals
129 * we'll just have to ignore without pselect().
132 bool to;
133 FD_ZERO(&rfds);
134 set_input_fds(&rfds, &nfds);
136 to=libmainloop_get_timeout(&tv);
138 if(mainloop_unhandled_signals()){
139 ret=0;
140 break;
143 ret=select(nfds+1, &rfds, NULL, NULL, to ? &tv : NULL);
144 }while(ret<0 && errno==EINTR && !mainloop_unhandled_signals());
146 #endif
147 if(ret>0)
148 check_input_fds(&rfds);
152 /*}}}*/