00001
00002 #include <microfeed/microfeedmain.h>
00003 #include <microfeed/microfeedmisc.h>
00004 #include <microfeed/microfeedthread.h>
00005
00006 #include <sys/time.h>
00007 #include <time.h>
00008 #include <stdio.h>
00009 #include <poll.h>
00010 #include <string.h>
00011 #include <unistd.h>
00012
00013 struct _MicrofeedTimeout {
00014 MicrofeedMain* main;
00015 MicrofeedTimeout* next;
00016 MicrofeedTimeout* previous;
00017 unsigned long int milliseconds;
00018 MicrofeedTimeoutCallback callback;
00019 void* user_data;
00020 };
00021
00022 struct _MicrofeedWatch {
00023 MicrofeedMain* main;
00024 MicrofeedWatch* next;
00025 MicrofeedWatch* previous;
00026 int fd;
00027 MicrofeedWatchType type;
00028 struct pollfd* pollfd;
00029 MicrofeedWatchCallback callback;
00030 void* user_data;
00031 };
00032
00033 struct _MicrofeedMain {
00034 MicrofeedMutex* mutex;
00035 DBusConnection* connection;
00036 MicrofeedTimeout* timeouts;
00037 MicrofeedWatch* watches;
00038 unsigned int watches_count;
00039 MicrofeedWatch* watch_iterator;
00040 struct pollfd* poll_fds;
00041 int polling;
00042 int wakeup_pipe[2];
00043 int exit_requested : 1;
00044 };
00045
00046 static void dispatch_status_changed(DBusConnection* connection, DBusDispatchStatus new_status, void* data);
00047 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data);
00048 static void remove_timeout(DBusTimeout *timeout, void *data);
00049 static void toggle_timeout(DBusTimeout *timeout, void *data);
00050 static void handle_timeout(MicrofeedMain* main, void* user_data);
00051 static dbus_bool_t add_watch(DBusWatch *timeout, void *data);
00052 static void remove_watch(DBusWatch *timeout, void *data);
00053 static void toggle_watch(DBusWatch *timeout, void *data);
00054 static void handle_watch(MicrofeedMain* main, int fd, MicrofeedWatchType type, void* user_data);
00055 static void wakeup_poll(MicrofeedMain* microfeed_main);
00056 static void wakeup_main(void* data);
00057
00068 MicrofeedMain* microfeed_main_new() {
00069 DBusError error;
00070 DBusConnection* connection;
00071
00072 dbus_threads_init_default();
00073 dbus_error_init(&error);
00074 connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
00075 dbus_error_free(&error);
00076
00077 return microfeed_main_new_with_dbus_connection(connection);
00078 }
00079
00095 MicrofeedMain* microfeed_main_new_with_dbus_connection(DBusConnection* connection) {
00096 MicrofeedMain* microfeed_main;
00097
00098 microfeed_main = microfeed_memory_allocate(MicrofeedMain);
00099 microfeed_main->mutex = microfeed_mutex_new();
00100 microfeed_main->connection = connection;
00101 microfeed_main->timeouts = NULL;
00102 microfeed_main->watches = NULL;
00103 microfeed_main->watches_count = 0;
00104 microfeed_main->poll_fds = NULL;
00105 microfeed_main->polling = 0;
00106 if (pipe(microfeed_main->wakeup_pipe)) {
00107 fprintf(stderr, "pipe failed\n");
00108
00109 exit(1);
00110 }
00111
00112 dbus_connection_set_dispatch_status_function(connection, dispatch_status_changed, microfeed_main, NULL);
00113 dbus_connection_set_timeout_functions(connection, add_timeout, remove_timeout, toggle_timeout, microfeed_main, NULL);
00114 dbus_connection_set_watch_functions(connection, add_watch, remove_watch, toggle_watch, microfeed_main, NULL);
00115 dbus_connection_set_wakeup_main_function(connection, wakeup_main, microfeed_main, NULL);
00116
00117 return microfeed_main;
00118 }
00119
00128 void microfeed_main_free(MicrofeedMain* microfeed_main) {
00129 MicrofeedTimeout* timeout;
00130 MicrofeedTimeout* next_timeout;
00131 MicrofeedWatch* watch;
00132 MicrofeedWatch* next_watch;
00133
00134 microfeed_mutex_free(microfeed_main->mutex);
00135 microfeed_main->mutex = NULL;
00136 dbus_connection_close(microfeed_main->connection);
00137 microfeed_main->connection = NULL;
00138 for (timeout = microfeed_main->timeouts; timeout; timeout = next_timeout) {
00139 timeout->main = NULL;
00140 next_timeout = timeout->next;
00141 microfeed_memory_free(timeout);
00142 }
00143 microfeed_main->timeouts = NULL;
00144 for (watch = microfeed_main->watches; watch; watch = next_watch) {
00145 watch->main = NULL;
00146 next_watch = watch->next;
00147 microfeed_memory_free(watch);
00148 }
00149 microfeed_main->watches = NULL;
00150 microfeed_main->watches_count = 0;
00151 microfeed_memory_free(microfeed_main->poll_fds);
00152 microfeed_memory_free(microfeed_main);
00153 }
00154
00161 DBusConnection* microfeed_main_get_dbus_connection(MicrofeedMain* microfeed_main) {
00162
00163 return microfeed_main->connection;
00164 }
00165
00171 void microfeed_main_loop(MicrofeedMain* microfeed_main) {
00172 struct timeval timeval;
00173 int milliseconds;
00174 MicrofeedWatch* watch;
00175 struct pollfd* pollfd;
00176 MicrofeedTimeoutCallback timeout_callback;
00177 void* user_data;
00178 MicrofeedWatchType type;
00179 MicrofeedWatchCallback watch_callback;
00180 int fd;
00181 char buffer[1024];
00182
00183 microfeed_mutex_lock(microfeed_main->mutex);
00184
00185 while (!microfeed_main->exit_requested) {
00186 microfeed_mutex_unlock(microfeed_main->mutex);
00187
00188 while (dbus_connection_get_dispatch_status(microfeed_main->connection) == DBUS_DISPATCH_DATA_REMAINS) {
00189 dbus_connection_dispatch(microfeed_main->connection);
00190 }
00191 if (dbus_connection_has_messages_to_send(microfeed_main->connection)) {
00192 dbus_connection_flush(microfeed_main->connection);
00193 }
00194
00195 microfeed_mutex_lock(microfeed_main->mutex);
00196
00197 if (microfeed_main->timeouts) {
00198 gettimeofday(&timeval, NULL);
00199 milliseconds = microfeed_main->timeouts->milliseconds - timeval.tv_sec * 1000 - timeval.tv_usec / 1000;
00200 if (milliseconds < 0) {
00201 milliseconds = 0;
00202 }
00203 } else {
00204 milliseconds = -1;
00205 }
00206
00207 if (!microfeed_main->poll_fds) {
00208 microfeed_main->poll_fds = pollfd = microfeed_memory_allocate_bytes((microfeed_main->watches_count + 1) * sizeof(struct pollfd));
00209 pollfd->fd = microfeed_main->wakeup_pipe[0];
00210 pollfd->events = POLLIN;
00211 for (watch = microfeed_main->watches, pollfd++; watch; watch = watch->next, pollfd++) {
00212 watch->pollfd = pollfd;
00213 pollfd->fd = watch->fd;
00214 if (watch->type == MICROFEED_WATCH_TYPE_READ_WRITE) {
00215 pollfd->events = POLLIN | POLLOUT;
00216 } else if (watch->type == MICROFEED_WATCH_TYPE_WRITE) {
00217 pollfd->events = POLLOUT;
00218 } else {
00219 pollfd->events = POLLIN;
00220 }
00221 }
00222 }
00223
00224 if (microfeed_main->exit_requested) {
00225 break;
00226 }
00227
00228 microfeed_main->polling = 1;
00229
00230 microfeed_mutex_unlock(microfeed_main->mutex);
00231
00232 poll(microfeed_main->poll_fds, microfeed_main->watches_count + 1, milliseconds);
00233
00234 microfeed_mutex_lock(microfeed_main->mutex);
00235
00236 microfeed_main->polling = 0;
00237
00238 gettimeofday(&timeval, NULL);
00239 milliseconds = timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
00240 if (microfeed_main->timeouts && microfeed_main->timeouts->milliseconds < milliseconds) {
00241 timeout_callback = microfeed_main->timeouts->callback;
00242 user_data = microfeed_main->timeouts->user_data;
00243
00244 microfeed_mutex_unlock(microfeed_main->mutex);
00245
00246 timeout_callback(microfeed_main, user_data);
00247 microfeed_main_remove_timeout(microfeed_main, microfeed_main->timeouts);
00248
00249 microfeed_mutex_lock(microfeed_main->mutex);
00250
00251 }
00252
00253 if (microfeed_main->poll_fds->revents & POLLIN) {
00254 read(microfeed_main->wakeup_pipe[0], buffer, 1024);
00255 }
00256
00257 if (microfeed_main->poll_fds) {
00258 for (watch = microfeed_main->watches; watch; watch = microfeed_main->watch_iterator) {
00259 microfeed_main->watch_iterator = watch->next;
00260 if ((pollfd = watch->pollfd)) {
00261 if (pollfd->revents & (POLLIN | POLLOUT)) {
00262 type = MICROFEED_WATCH_TYPE_READ_WRITE;
00263 } else if (pollfd->revents & POLLOUT) {
00264 type = MICROFEED_WATCH_TYPE_WRITE;
00265 } else if (pollfd->revents & POLLIN) {
00266 type = MICROFEED_WATCH_TYPE_READ;
00267 } else {
00268 type = MICROFEED_WATCH_TYPE_NONE;
00269 }
00270 if (type != MICROFEED_WATCH_TYPE_NONE) {
00271 watch_callback = watch->callback;
00272 fd = watch->fd;
00273 user_data = watch->user_data;
00274
00275 microfeed_mutex_unlock(microfeed_main->mutex);
00276
00277 watch_callback(microfeed_main, fd, type, user_data);
00278
00279 microfeed_mutex_unlock(microfeed_main->mutex);
00280 }
00281 }
00282 }
00283 }
00284 }
00285
00286 microfeed_mutex_unlock(microfeed_main->mutex);
00287 }
00288
00289 void microfeed_main_exit(MicrofeedMain* microfeed_main) {
00290 microfeed_mutex_lock(microfeed_main->mutex);
00291
00292 microfeed_main->exit_requested = 1;
00293 wakeup_poll(microfeed_main);
00294
00295 microfeed_mutex_unlock(microfeed_main->mutex);
00296 }
00297
00309 MicrofeedTimeout* microfeed_main_add_timeout(MicrofeedMain* microfeed_main, unsigned long int milliseconds, MicrofeedTimeoutCallback callback, void* user_data) {
00310 MicrofeedTimeout* timeout;
00311 struct timeval timeval;
00312 MicrofeedTimeout* current;
00313 MicrofeedTimeout* previous;
00314
00315 microfeed_mutex_lock(microfeed_main->mutex);
00316
00317 gettimeofday(&timeval, NULL);
00318 milliseconds += timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
00319
00320 timeout = microfeed_memory_allocate(MicrofeedTimeout);
00321 timeout->main = microfeed_main;
00322 timeout->milliseconds = milliseconds;
00323 timeout->callback = callback;
00324 timeout->user_data = user_data;
00325
00326 for (previous = NULL, current = microfeed_main->timeouts; current; previous = current, current = current->next) {
00327 if (milliseconds < current->milliseconds) {
00328 timeout->previous = current->previous;
00329 if (current->previous) {
00330 current->previous->next = timeout;
00331 } else {
00332 microfeed_main->timeouts = timeout;
00333 }
00334 timeout->next = current;
00335 break;
00336 }
00337 }
00338 if (!current) {
00339 if (previous) {
00340 timeout->previous = previous;
00341 previous->next = timeout;
00342 } else {
00343 timeout->previous = NULL;
00344 microfeed_main->timeouts = timeout;
00345 }
00346 timeout->next = NULL;
00347 }
00348
00349 wakeup_poll(microfeed_main);
00350
00351 microfeed_mutex_unlock(microfeed_main->mutex);
00352
00353 return timeout;
00354 }
00355
00368 MicrofeedWatch* microfeed_main_add_watch(MicrofeedMain* microfeed_main, int fd, MicrofeedWatchType type, MicrofeedWatchCallback callback, void* user_data) {
00369 MicrofeedWatch* watch;
00370
00371 microfeed_mutex_lock(microfeed_main->mutex);
00372
00373 watch = microfeed_memory_allocate(MicrofeedWatch);
00374 watch->main = microfeed_main;
00375 watch->fd = fd;
00376 watch->type = type;
00377 watch->pollfd = NULL;
00378 watch->callback = callback;
00379 watch->user_data = user_data;
00380
00381 watch->next = microfeed_main->watches;
00382 if (watch->next) {
00383 watch->next->previous = watch;
00384 }
00385 microfeed_main->watches = watch;
00386 microfeed_main->watches_count++;
00387
00388 microfeed_memory_free(microfeed_main->poll_fds);
00389 microfeed_main->poll_fds = NULL;
00390 wakeup_poll(microfeed_main);
00391
00392 microfeed_mutex_unlock(microfeed_main->mutex);
00393
00394 return watch;
00395 }
00396
00406 void microfeed_main_remove_timeout(MicrofeedMain* microfeed_main, MicrofeedTimeout* timeout) {
00407 microfeed_mutex_lock(microfeed_main->mutex);
00408
00409 if (microfeed_main == timeout->main) {
00410 if (timeout->previous) {
00411 timeout->previous = timeout->next;
00412 } else if (timeout->main) {
00413 timeout->main->timeouts = timeout->next;
00414 }
00415 if (timeout->next) {
00416 timeout->next->previous = timeout->previous;
00417 }
00418 microfeed_memory_free(timeout);
00419 }
00420
00421 microfeed_mutex_unlock(microfeed_main->mutex);
00422 }
00423
00430 void microfeed_main_remove_watch(MicrofeedMain* microfeed_main, MicrofeedWatch* watch) {
00431 microfeed_mutex_lock(microfeed_main->mutex);
00432
00433 if (microfeed_main == watch->main) {
00434 if (microfeed_main->watch_iterator == watch) {
00435 microfeed_main->watch_iterator = watch->next;
00436 }
00437
00438 if (watch->previous) {
00439 watch->previous = watch->next;
00440 } else if (watch->main) {
00441 watch->main->watches = watch->next;
00442 }
00443 if (watch->next) {
00444 watch->next->previous = watch->previous;
00445 }
00446 microfeed_memory_free(watch);
00447 microfeed_main->watches_count--;
00448
00449 microfeed_memory_free(microfeed_main->poll_fds);
00450 microfeed_main->poll_fds = NULL;
00451 wakeup_poll(microfeed_main);
00452 }
00453
00454 microfeed_mutex_unlock(microfeed_main->mutex);
00455 }
00456
00457 static void dispatch_status_changed(DBusConnection* connection, DBusDispatchStatus new_status, void* data) {
00458 MicrofeedMain* microfeed_main;
00459
00460 if (new_status == DBUS_DISPATCH_DATA_REMAINS) {
00461 microfeed_main = (MicrofeedMain*)data;
00462 wakeup_poll(microfeed_main);
00463 }
00464 }
00465
00466 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
00467 MicrofeedMain* microfeed_main;
00468 MicrofeedTimeout* microfeed_timeout;
00469
00470 if (dbus_timeout_get_enabled(timeout) && !dbus_timeout_get_data(timeout)) {
00471 microfeed_main = (MicrofeedMain*)data;
00472 microfeed_timeout = microfeed_main_add_timeout(microfeed_main, dbus_timeout_get_interval(timeout), handle_timeout, timeout);
00473 dbus_timeout_set_data(timeout, microfeed_timeout, NULL);
00474 }
00475
00476 return TRUE;
00477 }
00478
00479 static void remove_timeout(DBusTimeout *timeout, void *data) {
00480 MicrofeedMain* microfeed_main;
00481 MicrofeedTimeout* microfeed_timeout;
00482
00483 microfeed_main = (MicrofeedMain*)data;
00484 if ((microfeed_timeout = (MicrofeedTimeout*)dbus_timeout_get_data(timeout))) {
00485 microfeed_main_remove_timeout(microfeed_main, microfeed_timeout);
00486 dbus_timeout_set_data(timeout, NULL, NULL);
00487 }
00488 }
00489
00490 static void toggle_timeout(DBusTimeout *timeout, void *data) {
00491 if (dbus_timeout_get_enabled(timeout)) {
00492 add_timeout(timeout, data);
00493 } else {
00494 remove_timeout(timeout, data);
00495 }
00496 }
00497
00498 static void handle_timeout(MicrofeedMain* microfeed_main, void* user_data) {
00499 DBusTimeout* timeout;
00500
00501 timeout = (DBusTimeout*)user_data;
00502 if (dbus_timeout_get_enabled(timeout)) {
00503 dbus_timeout_handle(timeout);
00504 microfeed_main_add_timeout(microfeed_main, dbus_timeout_get_interval(timeout), handle_timeout, timeout);
00505 }
00506 }
00507
00508 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
00509 MicrofeedMain* microfeed_main;
00510 MicrofeedWatch* microfeed_watch;
00511 unsigned int flags;
00512 MicrofeedWatchType type;
00513
00514 if (dbus_watch_get_enabled(watch) && !dbus_watch_get_data(watch)) {
00515 microfeed_main = (MicrofeedMain*)data;
00516 flags = dbus_watch_get_flags(watch);
00517 if (flags & DBUS_WATCH_READABLE && flags & DBUS_WATCH_WRITABLE) {
00518 type = MICROFEED_WATCH_TYPE_READ_WRITE;
00519 } else if (flags & DBUS_WATCH_WRITABLE) {
00520 type = MICROFEED_WATCH_TYPE_WRITE;
00521 } else {
00522 type = MICROFEED_WATCH_TYPE_READ;
00523 }
00524 microfeed_watch = microfeed_main_add_watch(microfeed_main, dbus_watch_get_unix_fd(watch), type, handle_watch, watch);
00525 dbus_watch_set_data(watch, microfeed_watch, NULL);
00526 }
00527
00528 return TRUE;
00529 }
00530
00531 static void remove_watch(DBusWatch *watch, void *data) {
00532 MicrofeedMain* microfeed_main;
00533 MicrofeedWatch* microfeed_watch;
00534
00535 microfeed_main = (MicrofeedMain*)data;
00536 if ((microfeed_watch = (MicrofeedWatch*)dbus_watch_get_data(watch))) {
00537 microfeed_main_remove_watch(microfeed_main, microfeed_watch);
00538 dbus_watch_set_data(watch, NULL, NULL);
00539 }
00540 }
00541
00542 static void toggle_watch(DBusWatch *watch, void *data) {
00543 if (dbus_watch_get_enabled(watch)) {
00544 add_watch(watch, data);
00545 } else {
00546 remove_watch(watch, data);
00547 }
00548 }
00549
00550 static void handle_watch(MicrofeedMain* main, int fd, MicrofeedWatchType type, void* user_data) {
00551 DBusWatch* watch;
00552 unsigned int flags;
00553
00554 watch = (DBusWatch*)user_data;
00555 if (dbus_watch_get_enabled(watch)) {
00556 if (type == MICROFEED_WATCH_TYPE_READ_WRITE) {
00557 flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
00558 } else if (type == MICROFEED_WATCH_TYPE_WRITE) {
00559 flags = DBUS_WATCH_WRITABLE;
00560 } else {
00561 flags = DBUS_WATCH_READABLE;
00562 }
00563 dbus_watch_handle(watch, flags);
00564 }
00565 }
00566
00567 static void wakeup_poll(MicrofeedMain* microfeed_main) {
00568 static char c = 0;
00569
00570 if (microfeed_main->polling) {
00571 write(microfeed_main->wakeup_pipe[1], &c, 1);
00572 c++;
00573 }
00574 }
00575
00576 static void wakeup_main(void* data) {
00577 MicrofeedMain* microfeed_main;
00578
00579 microfeed_main = (MicrofeedMain*)data;
00580
00581 microfeed_mutex_lock(microfeed_main->mutex);
00582
00583 wakeup_poll(microfeed_main);
00584
00585 microfeed_mutex_unlock(microfeed_main->mutex);
00586 }