]> git.decadent.org.uk Git - ion3.git/blob - libmainloop/select.c
f8410a5b846c46b318deb3d1a039576c0b0b6618
[ion3.git] / libmainloop / select.c
1 /*
2  * libmainloop/select.c
3  * 
4  * Partly based on a contributed code.
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <signal.h>
10 #include <sys/select.h>
11
12 #include <libtu/types.h>
13 #include <libtu/misc.h>
14 #include <libtu/dlist.h>
15
16 #include "select.h"
17 #include "signal.h"
18
19
20 /*{{{ File descriptor management */
21
22
23 static WInputFd *input_fds=NULL;
24
25 static WInputFd *find_input_fd(int fd)
26 {
27     WInputFd *tmp=input_fds;
28     
29     while(tmp){
30         if(tmp->fd==fd)
31             break;
32         tmp=tmp->next;
33     }
34     return tmp;
35 }
36
37 bool mainloop_register_input_fd(int fd, void *data,
38                                 void (*callback)(int fd, void *d))
39 {
40     WInputFd *tmp;
41     
42     if(find_input_fd(fd)!=NULL)
43         return FALSE;
44     
45     tmp=ALLOC(WInputFd);
46     if(tmp==NULL)
47         return FALSE;
48     
49     tmp->fd=fd;
50     tmp->data=data;
51     tmp->process_input_fn=callback;
52     
53     LINK_ITEM(input_fds, tmp, next, prev);
54     
55     return TRUE;
56 }
57
58 void mainloop_unregister_input_fd(int fd)
59 {
60     WInputFd *tmp=find_input_fd(fd);
61     
62     if(tmp!=NULL){
63         UNLINK_ITEM(input_fds, tmp, next, prev);
64         free(tmp);
65     }
66 }
67
68 static void set_input_fds(fd_set *rfds, int *nfds)
69 {
70     WInputFd *tmp=input_fds;
71     
72     while(tmp){
73         FD_SET(tmp->fd, rfds);
74         if(tmp->fd>*nfds)
75             *nfds=tmp->fd;
76         tmp=tmp->next;
77     }
78 }
79
80 static void check_input_fds(fd_set *rfds)
81 {
82     WInputFd *tmp=input_fds, *next=NULL;
83     
84     while(tmp){
85         next=tmp->next;
86         if(FD_ISSET(tmp->fd, rfds))
87             tmp->process_input_fn(tmp->fd, tmp->data);
88         tmp=next;
89     }
90 }
91
92 /*}}}*/
93
94
95 /*{{{ Select */
96
97 void mainloop_select()
98 {
99     fd_set rfds;
100     int nfds=0;
101     int ret=0;
102     
103     FD_ZERO(&rfds);
104     
105     set_input_fds(&rfds, &nfds);
106     
107 #ifdef _POSIX_SELECT
108     {
109         sigset_t oldmask;
110         
111         mainloop_block_signals(&oldmask);
112         
113         if(!mainloop_unhandled_signals())
114             ret=pselect(nfds+1, &rfds, NULL, NULL, NULL, &oldmask);
115         
116         sigprocmask(SIG_SETMASK, &oldmask, NULL);
117     }
118 #else
119     #warning "pselect() unavailable -- using dirty hacks"
120     {
121         struct timeval tv_={0, 0}, *tv=&tv_;
122         
123         /* If there are timers, make sure we return from select with 
124          * some delay, if the timer signal happens right before
125          * entering select(). Race conditions with other signals
126          * we'll just have to ignore without pselect().
127          */
128         if(!libmainloop_get_timeout(tv))
129             tv=NULL;
130             
131         if(!mainloop_unhandled_signals())
132             ret=select(nfds+1, &rfds, NULL, NULL, tv);
133     }
134 #endif
135     if(ret>0)
136         check_input_fds(&rfds);
137 }
138
139
140 /*}}}*/