1 /* based on code from OpenBSC */
14 static int unregistered;
15 static struct lcr_fd *fd_first = NULL;
16 static struct timeval *nearest_timer(struct timeval *select_timer, int *work);
17 static int next_work(void);
19 int _register_fd(struct lcr_fd *fd, int when, int (*cb)(struct lcr_fd *fd, unsigned int what, void *instance, int index), void *instance, int index, const char *func)
24 FATAL("FD that is registered in function %s is already in use\n", func);
25 // printf("registering fd %d %s\n", fd->fd, func);
27 /* make FD nonblocking */
28 flags = fcntl(fd->fd, F_GETFL);
30 FATAL("Failed to F_GETFL\n");
32 flags = fcntl(fd->fd, F_SETFL, flags);
34 FATAL("Failed to F_SETFL O_NONBLOCK\n");
44 fd->cb_instance = instance;
52 void _unregister_fd(struct lcr_fd *fd, const char *func)
54 struct lcr_fd **lcr_fdp;
56 /* find pointer to fd */
61 lcr_fdp = &((*lcr_fdp)->next);
64 FATAL("FD unregistered in function %s not in list\n", func);
67 /* remove fd from list */
74 int select_main(int polling, int *global_change, void (*lock)(void), void (*unlock)(void))
76 struct lcr_fd *lcr_fd;
77 fd_set readset, writeset, exceptset;
78 int work = 0, temp, rc;
79 struct timeval no_time = {0, 0};
80 struct timeval select_timer, *timer;
84 * this ensures that select is only called until:
85 * - no work event exists
86 * - and no timeout occurred
88 * if no future timeout exists, select will wait infinit.
91 printf("-"); fflush(stdout);
93 printf("1"); fflush(stdout);
94 /* process all work events */
96 printf("2"); fflush(stdout);
101 /* process timer events and get timeout for next timer event */
103 timer = nearest_timer(&select_timer, &temp);
104 printf("3"); fflush(stdout);
106 printf("4"); fflush(stdout);
114 // printf("wait till infinity ..."); fflush(stdout);
120 printf("5"); fflush(stdout);
121 /* prepare read and write fdsets */
124 if (lcr_fd->when & LCR_FD_READ)
125 FD_SET(lcr_fd->fd, &readset);
126 if (lcr_fd->when & LCR_FD_WRITE)
127 FD_SET(lcr_fd->fd, &writeset);
128 if (lcr_fd->when & LCR_FD_EXCEPT)
129 FD_SET(lcr_fd->fd, &exceptset);
130 lcr_fd = lcr_fd->next;
132 printf("6"); fflush(stdout);
136 rc = select(maxfd+1, &readset, &writeset, &exceptset, timer);
141 // printf("interrupted.\n");
144 if (global_change && *global_change) {
148 printf("7"); fflush(stdout);
155 /* call registered callback functions */
157 printf("8"); fflush(stdout);
163 if (FD_ISSET(lcr_fd->fd, &readset)) {
164 flags |= LCR_FD_READ;
165 FD_CLR(lcr_fd->fd, &readset);
167 if (FD_ISSET(lcr_fd->fd, &writeset)) {
168 flags |= LCR_FD_WRITE;
169 FD_CLR(lcr_fd->fd, &writeset);
171 if (FD_ISSET(lcr_fd->fd, &exceptset)) {
172 flags |= LCR_FD_EXCEPT;
173 FD_CLR(lcr_fd->fd, &exceptset);
176 printf("9"); fflush(stdout);
178 lcr_fd->cb(lcr_fd, flags, lcr_fd->cb_instance, lcr_fd->cb_index);
179 printf("0"); fflush(stdout);
182 printf("-"); fflush(stdout);
185 lcr_fd = lcr_fd->next;
191 static struct lcr_timer *timer_first = NULL;
193 int _add_timer(struct lcr_timer *timer, int (*cb)(struct lcr_timer *timer, void *instance, int index), void *instance, int index, const char *func)
196 FATAL("timer that is registered in function %s is already in use\n", func);
200 struct lcr_timer *test = timer_first;
203 FATAL("Timer already in list %s\n", func);
210 timer->timeout.tv_sec = 0;
211 timer->timeout.tv_usec = 0;
213 timer->cb_instance = instance;
214 timer->cb_index = index;
215 timer->next = timer_first;
221 void _del_timer(struct lcr_timer *timer, const char *func)
223 struct lcr_timer **lcr_timerp;
225 /* find pointer to timer */
226 lcr_timerp = &timer_first;
228 if (*lcr_timerp == timer)
230 lcr_timerp = &((*lcr_timerp)->next);
233 FATAL("timer deleted in function %s not in list\n", func);
236 /* remove timer from list */
238 *lcr_timerp = timer->next;
241 void schedule_timer(struct lcr_timer *timer, int seconds, int microseconds)
243 struct timeval current_time;
246 FATAL("Timer not added\n");
249 gettimeofday(¤t_time, NULL);
250 unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
251 currentTime += seconds * MICRO_SECONDS + microseconds;
252 timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
253 timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
257 void unsched_timer(struct lcr_timer *timer)
262 /* if a timeout is reached, process timer, if not, return timer value for select */
263 static struct timeval *nearest_timer(struct timeval *select_timer, int *work)
265 struct timeval current;
266 struct timeval *nearest = NULL;
267 struct lcr_timer *lcr_timer, *lcr_nearest = NULL;
269 /* find nearest timer, or NULL, if no timer active */
270 lcr_timer = timer_first;
272 if (lcr_timer->active && (!nearest || TIME_SMALLER(&lcr_timer->timeout, nearest))) {
273 nearest = &lcr_timer->timeout;
274 lcr_nearest = lcr_timer;
276 lcr_timer = lcr_timer->next;
279 select_timer->tv_sec = 0;
280 select_timer->tv_usec = 0;
283 return NULL; /* wait until infinity */
285 gettimeofday(¤t, NULL);
286 unsigned long long nearestTime = nearest->tv_sec * MICRO_SECONDS + nearest->tv_usec;
287 unsigned long long currentTime = current.tv_sec * MICRO_SECONDS + current.tv_usec;
289 if (nearestTime > currentTime) {
290 select_timer->tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
291 select_timer->tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
294 lcr_nearest->active = 0;
295 (*lcr_nearest->cb)(lcr_nearest, lcr_nearest->cb_instance, lcr_nearest->cb_index);
296 /* don't wait so we can process the queues, indicate "work=1" */
297 select_timer->tv_sec = 0;
298 select_timer->tv_usec = 0;
305 static struct lcr_work *work_first = NULL; /* chain of work */
306 static struct lcr_work *first_event = NULL, *last_event = NULL; /* chain of active events */
309 void show_chain(const char *func)
311 struct lcr_work *work = first_event;
312 printf("chain:%s\n", func);
314 printf("%p - %p - %p\n", work->prev_event, work, work->next_event);
315 work = work->next_event;
320 int _add_work(struct lcr_work *work, int (*cb)(struct lcr_work *work, void *instance, int index), void *instance, int index, const char *func)
323 FATAL("work that is registered in function %s is already in use\n", func);
327 printf("add work %p from function %s\n", work, func);
328 show_chain("before add");
333 work->cb_instance = instance;
334 work->cb_index = index;
335 work->next = work_first;
338 show_chain("after add");
344 void _del_work(struct lcr_work *work, const char *func)
346 struct lcr_work **lcr_workp;
349 show_chain("before detach");
352 /* first event removed */
353 if (!work->prev_event)
354 first_event = work->next_event;
356 work->prev_event->next_event = work->next_event;
357 /* last event removed */
358 if (!work->next_event)
359 last_event = work->prev_event;
361 work->next_event->prev_event = work->prev_event;
364 show_chain("after detach");
367 /* find pointer to work */
368 lcr_workp = &work_first;
370 if (*lcr_workp == work)
372 lcr_workp = &((*lcr_workp)->next);
375 FATAL("work deleted by '%s' not in list\n", func);
378 /* remove work from list */
380 *lcr_workp = work->next;
382 show_chain("after delete");
386 void trigger_work(struct lcr_work *work)
389 FATAL("Work not added\n");
392 /* event already triggered */
397 show_chain("before trigger");
399 /* append to tail of chain */
401 last_event->next_event = work;
402 work->prev_event = last_event;
403 work->next_event = NULL;
408 show_chain("after trigger");
414 /* get first work and remove from event chain */
415 static int next_work(void)
417 struct lcr_work *lcr_work;
423 show_chain("before next_work");
425 if (!first_event->inuse) {
426 FATAL("Work not added\n");
429 /* detach from event chain */
430 lcr_work = first_event;
431 first_event = lcr_work->next_event;
435 first_event->prev_event = NULL;
438 show_chain("after next_work");
440 lcr_work->active = 0;
442 (*lcr_work->cb)(lcr_work, lcr_work->cb_instance, lcr_work->cb_index);