2 * Server main select() loop
4 * Copyright (C) 1998 Alexandre Julliard
15 #include <sys/types.h>
18 #include "server/object.h"
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 */
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 */
40 int add_select_user( int fd
, int events
, const struct select_ops
*ops
, void *private )
43 struct user
*user
= malloc( sizeof(*user
) );
48 user
->when
.tv_sec
= 0;
49 user
->when
.tv_usec
= 0;
51 user
->private = private;
53 flags
= fcntl( fd
, F_GETFL
, 0 );
54 fcntl( fd
, F_SETFL
, flags
| O_NONBLOCK
);
57 set_select_events( fd
, events
);
58 if (fd
> max_fd
) max_fd
= fd
;
64 void remove_select_user( int fd
)
66 struct user
*user
= users
[fd
];
69 set_select_timeout( fd
, 0 );
70 set_select_events( fd
, 0 );
72 if (max_fd
== fd
) while (max_fd
&& !users
[max_fd
]) max_fd
--;
77 /* set a user timeout */
78 void set_select_timeout( int fd
, struct timeval
*when
)
80 struct user
*user
= users
[fd
];
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 */
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
;
112 else /* insert it at the tail */
115 if (timeout_tail
) timeout_tail
->next
= user
;
116 else timeout_head
= user
;
117 user
->prev
= timeout_tail
;
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
];
136 assert( user
->ops
== ops
);
137 return user
->private;
140 /* server main loop */
141 void select_loop(void)
146 signal( SIGPIPE
, SIG_IGN
);
150 fd_set read
= read_set
, write
= write_set
;
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' : '-') );
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 );
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;
174 ret
= select( max_fd
+ 1, &read
, &write
, NULL
, &tv
);
176 else /* no timeout */
178 ret
= select( max_fd
+ 1, &read
, &write
, NULL
, NULL
);
182 if (ret
== -1) perror("select");
184 for (i
= 0; i
<= max_fd
; i
++)
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 );