00001
00002 #include <microfeed-common/microfeedmain.h>
00003 #include <microfeed-common/microfeedmisc.h>
00004 #include <microfeed-common/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_connection_set_exit_on_disconnect(connection, FALSE);
00076 dbus_error_free(&error);
00077
00078 return microfeed_main_new_with_dbus_connection(connection);
00079 }
00080
00096 MicrofeedMain* microfeed_main_new_with_dbus_connection(DBusConnection* connection) {
00097 MicrofeedMain* microfeed_main;
00098
00099 microfeed_main = microfeed_memory_allocate(MicrofeedMain);
00100 microfeed_main->mutex = microfeed_mutex_new();
00101 microfeed_main->connection = connection;
00102 microfeed_main->timeouts = NULL;
00103 microfeed_main->watches = NULL;
00104 microfeed_main->watches_count = 0;
00105 microfeed_main->poll_fds = NULL;
00106 microfeed_main->polling = 0;
00107 if (pipe(microfeed_main->wakeup_pipe)) {
00108 fprintf(stderr, "ERROR: Pipe failed.\n");
00109
00110 exit(126);
00111 }
00112
00113 dbus_connection_set_dispatch_status_function(connection, dispatch_status_changed, microfeed_main, NULL);
00114 dbus_connection_set_timeout_functions(connection, add_timeout, remove_timeout, toggle_timeout, microfeed_main, NULL);
00115 dbus_connection_set_watch_functions(connection, add_watch, remove_watch, toggle_watch, microfeed_main, NULL);
00116 dbus_connection_set_wakeup_main_function(connection, wakeup_main, microfeed_main, NULL);
00117
00118 return microfeed_main;
00119 }
00120
00129 void microfeed_main_free(MicrofeedMain* microfeed_main) {
00130 MicrofeedTimeout* timeout;
00131 MicrofeedTimeout* next_timeout;
00132 MicrofeedWatch* watch;
00133 MicrofeedWatch* next_watch;
00134
00135 microfeed_mutex_free(microfeed_main->mutex);
00136 microfeed_main->mutex = NULL;
00137 dbus_connection_close(microfeed_main->connection);
00138 microfeed_main->connection = NULL;
00139 for (timeout = microfeed_main->timeouts; timeout; timeout = next_timeout) {
00140 timeout->main = NULL;
00141 next_timeout = timeout->next;
00142 microfeed_memory_free(timeout);
00143 }
00144 microfeed_main->timeouts = NULL;
00145 for (watch = microfeed_main->watches; watch; watch = next_watch) {
00146 watch->main = NULL;
00147 next_watch = watch->next;
00148 microfeed_memory_free(watch);
00149 }
00150 microfeed_main->watches = NULL;
00151 microfeed_main->watches_count = 0;
00152 microfeed_memory_free(microfeed_main->poll_fds);
00153 microfeed_memory_free(microfeed_main);
00154 }
00155
00162 DBusConnection* microfeed_main_get_dbus_connection(MicrofeedMain* microfeed_main) {
00163
00164 return microfeed_main->connection;
00165 }
00166
00172 void microfeed_main_loop(MicrofeedMain* microfeed_main) {
00173 struct timeval timeval;
00174 int milliseconds;
00175 MicrofeedWatch* watch;
00176 struct pollfd* pollfd;
00177 MicrofeedTimeoutCallback timeout_callback;
00178 void* user_data;
00179 MicrofeedWatchType type;
00180 MicrofeedWatchCallback watch_callback;
00181 int fd;
00182 char buffer[1024];
00183 ssize_t dummy;
00184
00185 microfeed_mutex_lock(microfeed_main->mutex);
00186
00187 while (!microfeed_main->exit_requested) {
00188 microfeed_mutex_unlock(microfeed_main->mutex);
00189
00190 while (dbus_connection_get_dispatch_status(microfeed_main->connection) == DBUS_DISPATCH_DATA_REMAINS) {
00191 dbus_connection_dispatch(microfeed_main->connection);
00192 }
00193 if (dbus_connection_has_messages_to_send(microfeed_main->connection)) {
00194 dbus_connection_flush(microfeed_main->connection);
00195 }
00196
00197 microfeed_mutex_lock(microfeed_main->mutex);
00198
00199 if (microfeed_main->timeouts) {
00200 gettimeofday(&timeval, NULL);
00201 milliseconds = microfeed_main->timeouts->milliseconds - timeval.tv_sec * 1000 - timeval.tv_usec / 1000;
00202 if (milliseconds < 0) {
00203 milliseconds = 0;
00204 }
00205 } else {
00206 milliseconds = -1;
00207 }
00208
00209 if (!microfeed_main->poll_fds) {
00210 microfeed_main->poll_fds = pollfd = microfeed_memory_allocate_bytes((microfeed_main->watches_count + 1) * sizeof(struct pollfd));
00211 pollfd->fd = microfeed_main->wakeup_pipe[0];
00212 pollfd->events = POLLIN;
00213 for (watch = microfeed_main->watches, pollfd++; watch; watch = watch->next, pollfd++) {
00214 watch->pollfd = pollfd;
00215 pollfd->fd = watch->fd;
00216 if (watch->type == MICROFEED_WATCH_TYPE_READ_WRITE) {
00217 pollfd->events = POLLIN | POLLOUT;
00218 } else if (watch->type == MICROFEED_WATCH_TYPE_WRITE) {
00219 pollfd->events = POLLOUT;
00220 } else {
00221 pollfd->events = POLLIN;
00222 }
00223 }
00224 }
00225
00226 if (microfeed_main->exit_requested) {
00227 break;
00228 }
00229
00230 microfeed_main->polling = 1;
00231
00232 microfeed_mutex_unlock(microfeed_main->mutex);
00233
00234 poll(microfeed_main->poll_fds, microfeed_main->watches_count + 1, milliseconds);
00235
00236 microfeed_mutex_lock(microfeed_main->mutex);
00237
00238 microfeed_main->polling = 0;
00239
00240 gettimeofday(&timeval, NULL);
00241 milliseconds = timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
00242 if (microfeed_main->timeouts && microfeed_main->timeouts->milliseconds < milliseconds) {
00243 timeout_callback = microfeed_main->timeouts->callback;
00244 user_data = microfeed_main->timeouts->user_data;
00245
00246 microfeed_mutex_unlock(microfeed_main->mutex);
00247
00248 timeout_callback(microfeed_main, user_data);
00249 microfeed_main_remove_timeout(microfeed_main, microfeed_main->timeouts);
00250
00251 microfeed_mutex_lock(microfeed_main->mutex);
00252
00253 }
00254
00255 if (microfeed_main->poll_fds->revents & POLLIN) {
00256 dummy = read(microfeed_main->wakeup_pipe[0], buffer, 1024);
00257 }
00258
00259 if (microfeed_main->poll_fds) {
00260 for (watch = microfeed_main->watches; watch; watch = microfeed_main->watch_iterator) {
00261 microfeed_main->watch_iterator = watch->next;
00262 if ((pollfd = watch->pollfd)) {
00263 if (pollfd->revents & (POLLIN | POLLOUT)) {
00264 type = MICROFEED_WATCH_TYPE_READ_WRITE;
00265 } else if (pollfd->revents & POLLOUT) {
00266 type = MICROFEED_WATCH_TYPE_WRITE;
00267 } else if (pollfd->revents & POLLIN) {
00268 type = MICROFEED_WATCH_TYPE_READ;
00269 } else {
00270 type = MICROFEED_WATCH_TYPE_NONE;
00271 }
00272 if (type != MICROFEED_WATCH_TYPE_NONE) {
00273 watch_callback = watch->callback;
00274 fd = watch->fd;
00275 user_data = watch->user_data;
00276
00277 microfeed_mutex_unlock(microfeed_main->mutex);
00278
00279 watch_callback(microfeed_main, fd, type, user_data);
00280
00281 microfeed_mutex_unlock(microfeed_main->mutex);
00282 }
00283 }
00284 }
00285 }
00286 }
00287
00288 microfeed_mutex_unlock(microfeed_main->mutex);
00289 }
00290
00296 void microfeed_main_exit(MicrofeedMain* microfeed_main) {
00297 microfeed_mutex_lock(microfeed_main->mutex);
00298
00299 microfeed_main->exit_requested = 1;
00300 wakeup_poll(microfeed_main);
00301
00302 microfeed_mutex_unlock(microfeed_main->mutex);
00303 }
00304
00316 MicrofeedTimeout* microfeed_main_add_timeout(MicrofeedMain* microfeed_main, unsigned long int milliseconds, MicrofeedTimeoutCallback callback, void* user_data) {
00317 MicrofeedTimeout* timeout;
00318 struct timeval timeval;
00319 MicrofeedTimeout* current;
00320 MicrofeedTimeout* previous;
00321
00322 microfeed_mutex_lock(microfeed_main->mutex);
00323
00324 gettimeofday(&timeval, NULL);
00325 milliseconds += timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
00326
00327 timeout = microfeed_memory_allocate(MicrofeedTimeout);
00328 timeout->main = microfeed_main;
00329 timeout->milliseconds = milliseconds;
00330 timeout->callback = callback;
00331 timeout->user_data = user_data;
00332
00333 for (previous = NULL, current = microfeed_main->timeouts; current; previous = current, current = current->next) {
00334 if (milliseconds < current->milliseconds) {
00335 timeout->previous = current->previous;
00336 if (current->previous) {
00337 current->previous->next = timeout;
00338 } else {
00339 microfeed_main->timeouts = timeout;
00340 }
00341 current->previous = timeout;
00342 timeout->next = current;
00343 break;
00344 }
00345 }
00346 if (!current) {
00347 if (previous) {
00348 timeout->previous = previous;
00349 previous->next = timeout;
00350 } else {
00351 timeout->previous = NULL;
00352 microfeed_main->timeouts = timeout;
00353 }
00354 timeout->next = NULL;
00355 }
00356
00357 wakeup_poll(microfeed_main);
00358
00359 microfeed_mutex_unlock(microfeed_main->mutex);
00360
00361 return timeout;
00362 }
00363
00376 MicrofeedWatch* microfeed_main_add_watch(MicrofeedMain* microfeed_main, int fd, MicrofeedWatchType type, MicrofeedWatchCallback callback, void* user_data) {
00377 MicrofeedWatch* watch;
00378
00379 microfeed_mutex_lock(microfeed_main->mutex);
00380
00381 watch = microfeed_memory_allocate(MicrofeedWatch);
00382 watch->main = microfeed_main;
00383 watch->fd = fd;
00384 watch->type = type;
00385 watch->pollfd = NULL;
00386 watch->callback = callback;
00387 watch->user_data = user_data;
00388
00389 watch->next = microfeed_main->watches;
00390 if (watch->next) {
00391 watch->next->previous = watch;
00392 }
00393 microfeed_main->watches = watch;
00394 microfeed_main->watches_count++;
00395
00396 microfeed_memory_free(microfeed_main->poll_fds);
00397 microfeed_main->poll_fds = NULL;
00398 wakeup_poll(microfeed_main);
00399
00400 microfeed_mutex_unlock(microfeed_main->mutex);
00401
00402 return watch;
00403 }
00404
00414 void microfeed_main_remove_timeout(MicrofeedMain* microfeed_main, MicrofeedTimeout* timeout) {
00415 microfeed_mutex_lock(microfeed_main->mutex);
00416
00417 if (microfeed_main == timeout->main) {
00418 if (timeout->previous) {
00419 timeout->previous->next = timeout->next;
00420 } else if (timeout->main) {
00421 timeout->main->timeouts = timeout->next;
00422 }
00423 if (timeout->next) {
00424 timeout->next->previous = timeout->previous;
00425 }
00426 microfeed_memory_free(timeout);
00427 }
00428
00429 microfeed_mutex_unlock(microfeed_main->mutex);
00430 }
00431
00438 void microfeed_main_remove_watch(MicrofeedMain* microfeed_main, MicrofeedWatch* watch) {
00439 microfeed_mutex_lock(microfeed_main->mutex);
00440
00441 if (microfeed_main == watch->main) {
00442 if (microfeed_main->watch_iterator == watch) {
00443 microfeed_main->watch_iterator = watch->next;
00444 }
00445
00446 if (watch->previous) {
00447 watch->previous->next = watch->next;
00448 } else if (watch->main) {
00449 watch->main->watches = watch->next;
00450 }
00451 if (watch->next) {
00452 watch->next->previous = watch->previous;
00453 }
00454 microfeed_memory_free(watch);
00455 microfeed_main->watches_count--;
00456
00457 microfeed_memory_free(microfeed_main->poll_fds);
00458 microfeed_main->poll_fds = NULL;
00459 wakeup_poll(microfeed_main);
00460 }
00461
00462 microfeed_mutex_unlock(microfeed_main->mutex);
00463 }
00464
00465 static void dispatch_status_changed(DBusConnection* connection, DBusDispatchStatus new_status, void* data) {
00466 MicrofeedMain* microfeed_main;
00467
00468 if (new_status == DBUS_DISPATCH_DATA_REMAINS) {
00469 microfeed_main = (MicrofeedMain*)data;
00470 wakeup_poll(microfeed_main);
00471 }
00472 }
00473
00474 static dbus_bool_t add_timeout(DBusTimeout* timeout, void* data) {
00475 MicrofeedMain* microfeed_main;
00476 MicrofeedTimeout* microfeed_timeout;
00477
00478 if (dbus_timeout_get_enabled(timeout) && !dbus_timeout_get_data(timeout)) {
00479 microfeed_main = (MicrofeedMain*)data;
00480 microfeed_timeout = microfeed_main_add_timeout(microfeed_main, dbus_timeout_get_interval(timeout), handle_timeout, timeout);
00481 dbus_timeout_set_data(timeout, microfeed_timeout, NULL);
00482 }
00483
00484 return TRUE;
00485 }
00486
00487 static void remove_timeout(DBusTimeout* timeout, void* data) {
00488 MicrofeedMain* microfeed_main;
00489 MicrofeedTimeout* microfeed_timeout;
00490
00491 microfeed_main = (MicrofeedMain*)data;
00492 if ((microfeed_timeout = (MicrofeedTimeout*)dbus_timeout_get_data(timeout))) {
00493 microfeed_main_remove_timeout(microfeed_main, microfeed_timeout);
00494 dbus_timeout_set_data(timeout, NULL, NULL);
00495 }
00496 }
00497
00498 static void toggle_timeout(DBusTimeout* timeout, void* data) {
00499 if (dbus_timeout_get_enabled(timeout)) {
00500 add_timeout(timeout, data);
00501 } else {
00502 remove_timeout(timeout, data);
00503 }
00504 }
00505
00506 static void handle_timeout(MicrofeedMain* microfeed_main, void* user_data) {
00507 DBusTimeout* timeout;
00508
00509 timeout = (DBusTimeout*)user_data;
00510 if (dbus_timeout_get_enabled(timeout)) {
00511 dbus_timeout_handle(timeout);
00512 microfeed_main_add_timeout(microfeed_main, dbus_timeout_get_interval(timeout), handle_timeout, timeout);
00513 }
00514 }
00515
00516 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
00517 MicrofeedMain* microfeed_main;
00518 int fd;
00519 MicrofeedWatch* microfeed_watch;
00520 unsigned int flags;
00521 MicrofeedWatchType type;
00522
00523 if (dbus_watch_get_enabled(watch) && !dbus_watch_get_data(watch)) {
00524 microfeed_main = (MicrofeedMain*)data;
00525 flags = dbus_watch_get_flags(watch);
00526 if (flags & DBUS_WATCH_READABLE && flags & DBUS_WATCH_WRITABLE) {
00527 type = MICROFEED_WATCH_TYPE_READ_WRITE;
00528 } else if (flags & DBUS_WATCH_WRITABLE) {
00529 type = MICROFEED_WATCH_TYPE_WRITE;
00530 } else {
00531 type = MICROFEED_WATCH_TYPE_READ;
00532 }
00533 #if (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR == 1 && DBUS_VERSION_MICRO >= 1) || (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MAJOR > 1) || (DBUS_VERSION_MAJOR > 1)
00534 fd = dbus_watch_get_unix_fd(watch);
00535 #else
00536 fd = dbus_watch_get_fd(watch);
00537 #endif
00538 microfeed_watch = microfeed_main_add_watch(microfeed_main, fd, type, handle_watch, watch);
00539 dbus_watch_set_data(watch, microfeed_watch, NULL);
00540 }
00541
00542 return TRUE;
00543 }
00544
00545 static void remove_watch(DBusWatch *watch, void *data) {
00546 MicrofeedMain* microfeed_main;
00547 MicrofeedWatch* microfeed_watch;
00548
00549 microfeed_main = (MicrofeedMain*)data;
00550 if ((microfeed_watch = (MicrofeedWatch*)dbus_watch_get_data(watch))) {
00551 microfeed_main_remove_watch(microfeed_main, microfeed_watch);
00552 dbus_watch_set_data(watch, NULL, NULL);
00553 }
00554 }
00555
00556 static void toggle_watch(DBusWatch *watch, void *data) {
00557 if (dbus_watch_get_enabled(watch)) {
00558 add_watch(watch, data);
00559 } else {
00560 remove_watch(watch, data);
00561 }
00562 }
00563
00564 static void handle_watch(MicrofeedMain* main, int fd, MicrofeedWatchType type, void* user_data) {
00565 DBusWatch* watch;
00566 unsigned int flags;
00567
00568 watch = (DBusWatch*)user_data;
00569 if (dbus_watch_get_enabled(watch)) {
00570 if (type == MICROFEED_WATCH_TYPE_READ_WRITE) {
00571 flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
00572 } else if (type == MICROFEED_WATCH_TYPE_WRITE) {
00573 flags = DBUS_WATCH_WRITABLE;
00574 } else {
00575 flags = DBUS_WATCH_READABLE;
00576 }
00577 dbus_watch_handle(watch, flags);
00578 }
00579 }
00580
00581 static void wakeup_poll(MicrofeedMain* microfeed_main) {
00582 static char c = 0;
00583 ssize_t dummy;
00584
00585 if (microfeed_main->polling) {
00586 dummy = write(microfeed_main->wakeup_pipe[1], &c, 1);
00587 c++;
00588 }
00589 }
00590
00591 static void wakeup_main(void* data) {
00592 MicrofeedMain* microfeed_main;
00593
00594 microfeed_main = (MicrofeedMain*)data;
00595
00596 microfeed_mutex_lock(microfeed_main->mutex);
00597
00598 wakeup_poll(microfeed_main);
00599
00600 microfeed_mutex_unlock(microfeed_main->mutex);
00601 }