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