Thread-safe implementation of profile functions (Windows and Wine).
[wine.git] / server / select.c
blob5d3092e3bdf00e1972a539cd297de73de8f19388
1 /*
2 * Server main select() loop
4 * Copyright (C) 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <unistd.h>
18 #include "server/object.h"
20 /* select user fd */
21 struct user
23 struct timeval when; /* timeout expiry (absolute time) */
24 struct user *next; /* next in sorted timeout list */
25 struct user *prev; /* prev in sorted timeout list */
26 const struct select_ops *ops; /* user operations list */
27 int fd; /* user fd */
28 void *private; /* user private data */
31 static struct user *users[FD_SETSIZE]; /* users array */
32 static fd_set read_set, write_set; /* current select sets */
33 static int nb_users; /* current number of users */
34 static int max_fd; /* max fd in use */
35 static struct user *timeout_head; /* sorted timeouts list head */
36 static struct user *timeout_tail; /* sorted timeouts list tail */
39 /* add a user */
40 int add_select_user( int fd, int events, const struct select_ops *ops, void *private )
42 int flags;
43 struct user *user = malloc( sizeof(*user) );
44 if (!user) return -1;
45 assert( !users[fd] );
47 user->ops = ops;
48 user->when.tv_sec = 0;
49 user->when.tv_usec = 0;
50 user->fd = fd;
51 user->private = private;
53 flags = fcntl( fd, F_GETFL, 0 );
54 fcntl( fd, F_SETFL, flags | O_NONBLOCK );
56 users[fd] = user;
57 set_select_events( fd, events );
58 if (fd > max_fd) max_fd = fd;
59 nb_users++;
60 return fd;
63 /* remove a user */
64 void remove_select_user( int fd )
66 struct user *user = users[fd];
67 assert( user );
69 set_select_timeout( fd, 0 );
70 set_select_events( fd, 0 );
71 users[fd] = NULL;
72 if (max_fd == fd) while (max_fd && !users[max_fd]) max_fd--;
73 nb_users--;
74 free( user );
77 /* set a user timeout */
78 void set_select_timeout( int fd, struct timeval *when )
80 struct user *user = users[fd];
81 struct user *pos;
82 assert( user );
84 if (user->when.tv_sec || user->when.tv_usec)
86 /* there is already a timeout */
87 if (user->next) user->next->prev = user->prev;
88 else timeout_tail = user->prev;
89 if (user->prev) user->prev->next = user->next;
90 else timeout_head = user->next;
91 user->when.tv_sec = user->when.tv_usec = 0;
93 if (!when) return; /* no timeout */
94 user->when = *when;
96 /* Now insert it in the linked list */
98 for (pos = timeout_head; pos; pos = pos->next)
100 if (pos->when.tv_sec > user->when.tv_sec) break;
101 if ((pos->when.tv_sec == user->when.tv_sec) &&
102 (pos->when.tv_usec > user->when.tv_usec)) break;
105 if (pos) /* insert it before 'pos' */
107 if ((user->prev = pos->prev)) user->prev->next = user;
108 else timeout_head = user;
109 user->next = pos;
110 pos->prev = user;
112 else /* insert it at the tail */
114 user->next = NULL;
115 if (timeout_tail) timeout_tail->next = user;
116 else timeout_head = user;
117 user->prev = timeout_tail;
118 timeout_tail = user;
122 /* set the events that select waits for on this fd */
123 void set_select_events( int fd, int events )
125 if (events & READ_EVENT) FD_SET( fd, &read_set );
126 else FD_CLR( fd, &read_set );
127 if (events & WRITE_EVENT) FD_SET( fd, &write_set );
128 else FD_CLR( fd, &write_set );
131 /* get a user private data, checking the type */
132 void *get_select_private_data( const struct select_ops *ops, int fd )
134 struct user *user = users[fd];
135 assert( user );
136 assert( user->ops == ops );
137 return user->private;
140 /* server main loop */
141 void select_loop(void)
143 int i, ret;
145 setsid();
146 signal( SIGPIPE, SIG_IGN );
148 while (nb_users)
150 fd_set read = read_set, write = write_set;
151 #if 0
152 printf( "select: " );
153 for (i = 0; i <= max_fd; i++) printf( "%c", FD_ISSET( i, &read_set ) ? 'r' :
154 (FD_ISSET( i, &write_set ) ? 'w' : '-') );
155 printf( "\n" );
156 #endif
157 if (timeout_head)
159 struct timeval tv, now;
160 gettimeofday( &now, NULL );
161 if ((timeout_head->when.tv_sec < now.tv_sec) ||
162 ((timeout_head->when.tv_sec == now.tv_sec) &&
163 (timeout_head->when.tv_usec < now.tv_usec)))
165 timeout_head->ops->timeout( timeout_head->fd, timeout_head->private );
166 continue;
168 tv.tv_sec = timeout_head->when.tv_sec - now.tv_sec;
169 if ((tv.tv_usec = timeout_head->when.tv_usec - now.tv_usec) < 0)
171 tv.tv_usec += 1000000;
172 tv.tv_sec--;
174 ret = select( max_fd + 1, &read, &write, NULL, &tv );
176 else /* no timeout */
178 ret = select( max_fd + 1, &read, &write, NULL, NULL );
181 if (!ret) continue;
182 if (ret == -1) perror("select");
184 for (i = 0; i <= max_fd; i++)
186 int event = 0;
187 if (FD_ISSET( i, &write )) event |= WRITE_EVENT;
188 if (FD_ISSET( i, &read )) event |= READ_EVENT;
189 if (event) users[i]->ops->event( i, event, users[i]->private );