Install the wine server in $(bindir) and exec it from there.
[wine] / server / select.c
1 /*
2  * Server main select() loop
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include "object.h"
18
19 struct timeout_user
20 {
21     struct timeout_user  *next;       /* next in sorted timeout list */
22     struct timeout_user  *prev;       /* prev in sorted timeout list */
23     struct timeval        when;       /* timeout expiry (absolute time) */
24     timeout_callback      callback;   /* callback function */
25     void                 *private;    /* callback private data */
26 };
27
28 static struct select_user *users[FD_SETSIZE];  /* users array */
29 static fd_set read_set, write_set, except_set; /* current select sets */
30 static int nb_users;                        /* current number of users */
31 static int max_fd;                          /* max fd in use */
32 static struct timeout_user *timeout_head;   /* sorted timeouts list head */
33 static struct timeout_user *timeout_tail;   /* sorted timeouts list tail */
34
35
36 /* register a user */
37 void register_select_user( struct select_user *user )
38 {
39     assert( !users[user->fd] );
40
41     users[user->fd] = user;
42     if (user->fd > max_fd) max_fd = user->fd;
43     nb_users++;
44 }
45
46 /* remove a user */
47 void unregister_select_user( struct select_user *user )
48 {
49     assert( users[user->fd] == user );
50
51     FD_CLR( user->fd, &read_set );
52     FD_CLR( user->fd, &write_set );
53     FD_CLR( user->fd, &except_set );
54     users[user->fd] = NULL;
55     if (max_fd == user->fd) while (max_fd && !users[max_fd]) max_fd--;
56     nb_users--;
57 }
58
59 /* set the events that select waits for on this fd */
60 void set_select_events( struct select_user *user, int events )
61 {
62     assert( users[user->fd] == user );
63     if (events & READ_EVENT) FD_SET( user->fd, &read_set );
64     else FD_CLR( user->fd, &read_set );
65     if (events & WRITE_EVENT) FD_SET( user->fd, &write_set );
66     else FD_CLR( user->fd, &write_set );
67     if (events & EXCEPT_EVENT) FD_SET( user->fd, &except_set );
68     else FD_CLR( user->fd, &except_set );
69 }
70
71 /* check if events are pending */
72 int check_select_events( struct select_user *user, int events )
73 {
74     fd_set read_fds, write_fds, except_fds;
75     struct timeval tv = { 0, 0 };
76
77     FD_ZERO( &read_fds );
78     FD_ZERO( &write_fds );
79     FD_ZERO( &except_fds );
80     if (events & READ_EVENT) FD_SET( user->fd, &read_fds );
81     if (events & WRITE_EVENT) FD_SET( user->fd, &write_fds );
82     if (events & EXCEPT_EVENT) FD_SET( user->fd, &except_fds );
83     return select( user->fd + 1, &read_fds, &write_fds, &except_fds, &tv ) > 0;
84 }
85
86 /* add a timeout user */
87 struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
88 {
89     struct timeout_user *user;
90     struct timeout_user *pos;
91
92     if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
93     user->when     = *when;
94     user->callback = func;
95     user->private  = private;
96
97     /* Now insert it in the linked list */
98
99     for (pos = timeout_head; pos; pos = pos->next)
100     {
101         if (pos->when.tv_sec > user->when.tv_sec) break;
102         if ((pos->when.tv_sec == user->when.tv_sec) &&
103             (pos->when.tv_usec > user->when.tv_usec)) break;
104     }
105
106     if (pos)  /* insert it before 'pos' */
107     {
108         if ((user->prev = pos->prev)) user->prev->next = user;
109         else timeout_head = user;
110         user->next = pos;
111         pos->prev = user;
112     }
113     else  /* insert it at the tail */
114     {
115         user->next = NULL;
116         if (timeout_tail) timeout_tail->next = user;
117         else timeout_head = user;
118         user->prev = timeout_tail;
119         timeout_tail = user;
120     }
121     return user;
122 }
123
124 /* remove a timeout user */
125 void remove_timeout_user( struct timeout_user *user )
126 {
127     if (user->next) user->next->prev = user->prev;
128     else timeout_tail = user->prev;
129     if (user->prev) user->prev->next = user->next;
130     else timeout_head = user->next;
131     free( user );
132 }
133
134 /* make an absolute timeout value from a relative timeout in milliseconds */
135 void make_timeout( struct timeval *when, int timeout )
136 {
137     gettimeofday( when, 0 );
138     if (!timeout) return;
139     if ((when->tv_usec += (timeout % 1000) * 1000) >= 1000000)
140     {
141         when->tv_usec -= 1000000;
142         when->tv_sec++;
143     }
144     when->tv_sec += timeout / 1000;
145 }
146
147 /* handle an expired timeout */
148 static void handle_timeout( struct timeout_user *user )
149 {
150     if (user->next) user->next->prev = user->prev;
151     else timeout_tail = user->prev;
152     if (user->prev) user->prev->next = user->next;
153     else timeout_head = user->next;
154     user->callback( user->private );
155     free( user );
156 }
157
158 #ifdef DEBUG_OBJECTS
159 static int do_dump_objects;
160
161 /* SIGHUP handler */
162 static void sighup()
163 {
164     do_dump_objects = 1;
165 }
166 #endif
167
168 /* server main loop */
169 void select_loop(void)
170 {
171     int i, ret;
172
173     setsid();
174     signal( SIGPIPE, SIG_IGN );
175 #ifdef DEBUG_OBJECTS
176     signal( SIGHUP, sighup );
177 #endif
178
179     while (nb_users)
180     {
181         fd_set read = read_set, write = write_set, except = except_set;
182         if (timeout_head)
183         {
184             struct timeval tv, now;
185             gettimeofday( &now, NULL );
186             if ((timeout_head->when.tv_sec < now.tv_sec) ||
187                 ((timeout_head->when.tv_sec == now.tv_sec) &&
188                  (timeout_head->when.tv_usec < now.tv_usec)))
189             {
190                 handle_timeout( timeout_head );
191                 continue;
192             }
193             tv.tv_sec = timeout_head->when.tv_sec - now.tv_sec;
194             if ((tv.tv_usec = timeout_head->when.tv_usec - now.tv_usec) < 0)
195             {
196                 tv.tv_usec += 1000000;
197                 tv.tv_sec--;
198             }
199 #if 0
200             printf( "select: " );
201             for (i = 0; i <= max_fd; i++) printf( "%c", FD_ISSET( i, &read_set ) ? 'r' :
202                                                   (FD_ISSET( i, &write_set ) ? 'w' : '-') );
203             printf( " timeout %d.%06d\n", tv.tv_sec, tv.tv_usec );
204 #endif
205             ret = select( max_fd + 1, &read, &write, &except, &tv );
206         }
207         else  /* no timeout */
208         {
209 #if 0
210             printf( "select: " );
211             for (i = 0; i <= max_fd; i++) printf( "%c", FD_ISSET( i, &read_set ) ? 'r' :
212                                                   (FD_ISSET( i, &write_set ) ? 'w' : '-') );
213             printf( " no timeout\n" );
214 #endif
215             ret = select( max_fd + 1, &read, &write, &except, NULL );
216         }
217
218         if (!ret) continue;
219         if (ret == -1) {
220             if (errno == EINTR)
221             {
222 #ifdef DEBUG_OBJECTS
223                 if (do_dump_objects) dump_objects();
224                 do_dump_objects = 0;
225 #endif
226                 continue;
227             }
228             perror("select");
229         }
230
231         for (i = 0; i <= max_fd; i++)
232         {
233             int event = 0;
234             if (FD_ISSET( i, &except )) event |= EXCEPT_EVENT;
235             if (FD_ISSET( i, &write ))  event |= WRITE_EVENT;
236             if (FD_ISSET( i, &read ))   event |= READ_EVENT;
237
238             /* Note: users[i] might be NULL here, because an event routine
239                called in an earlier pass of this loop might have removed 
240                the current user ... */
241             if (event && users[i]) 
242                 users[i]->func( event, users[i]->private );
243         }
244     }
245 }