00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <microfeed-common/microfeedmain.h>
00021 #include <microfeed-common/microfeedmisc.h>
00022 #include <microfeed-common/microfeedthread.h>
00023
00024 #include <sys/time.h>
00025 #include <time.h>
00026 #include <stdio.h>
00027 #include <poll.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030
00031 struct _MicrofeedTimeout {
00032 MicrofeedMain* main;
00033 MicrofeedTimeout* next;
00034 MicrofeedTimeout* previous;
00035 unsigned long int milliseconds;
00036 MicrofeedTimeoutCallback callback;
00037 void* user_data;
00038 };
00039
00040 struct _MicrofeedWatch {
00041 MicrofeedMain* main;
00042 MicrofeedWatch* next;
00043 MicrofeedWatch* previous;
00044 int fd;
00045 MicrofeedWatchType type;
00046 struct pollfd* pollfd;
00047 MicrofeedWatchCallback callback;
00048 void* user_data;
00049 };
00050
00051 struct _MicrofeedMain {
00052 MicrofeedMutex* mutex;
00053 DBusConnection* connection;
00054 MicrofeedTimeout* timeouts;
00055 MicrofeedWatch* watches;
00056 unsigned int watches_count;
00057 MicrofeedWatch* watch_iterator;
00058 struct pollfd* poll_fds;
00059 int polling;
00060 int wakeup_pipe[2];
00061 int exit_requested : 1;
00062 };
00063
00064 static void dispatch_status_changed(DBusConnection* connection, DBusDispatchStatus new_status, void* data);
00065 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data);
00066 static void remove_timeout(DBusTimeout *timeout, void *data);
00067 static void toggle_timeout(DBusTimeout *timeout, void *data);
00068 static void handle_timeout(MicrofeedMain* main, void* user_data);
00069 static dbus_bool_t add_watch(DBusWatch *timeout, void *data);
00070 static void remove_watch(DBusWatch *timeout, void *data);
00071 static void toggle_watch(DBusWatch *timeout, void *data);
00072 static void handle_watch(MicrofeedMain* main, int fd, MicrofeedWatchType type, void* user_data);
00073 static void wakeup_poll(MicrofeedMain* microfeed_main);
00074 static void wakeup_main(void* data);
00075
00086 MicrofeedMain* microfeed_main_new() {
00087 DBusError error;
00088 DBusConnection* connection;
00089
00090 dbus_threads_init_default();
00091 dbus_error_init(&error);
00092 connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
00093 dbus_connection_set_exit_on_disconnect(connection, FALSE);
00094 dbus_error_free(&error);
00095
00096 return microfeed_main_new_with_dbus_connection(connection);
00097 }
00098
00114 MicrofeedMain* microfeed_main_new_with_dbus_connection(DBusConnection* connection) {
00115 MicrofeedMain* microfeed_main;
00116
00117 microfeed_main = microfeed_memory_allocate(MicrofeedMain);
00118 microfeed_main->mutex = microfeed_mutex_new();
00119 microfeed_main->connection = connection;
00120 microfeed_main->timeouts = NULL;
00121 microfeed_main->watches = NULL;
00122 microfeed_main->watches_count = 0;
00123 microfeed_main->poll_fds = NULL;
00124 microfeed_main->polling = 0;
00125 if (pipe(microfeed_main->wakeup_pipe)) {
00126 fprintf(stderr, "ERROR: Pipe failed.\n");
00127
00128 exit(126);
00129 }
00130
00131 dbus_connection_set_dispatch_status_function(connection, dispatch_status_changed, microfeed_main, NULL);
00132 dbus_connection_set_timeout_functions(connection, add_timeout, remove_timeout, toggle_timeout, microfeed_main, NULL);
00133 dbus_connection_set_watch_functions(connection, add_watch, remove_watch, toggle_watch, microfeed_main, NULL);
00134 dbus_connection_set_wakeup_main_function(connection, wakeup_main, microfeed_main, NULL);
00135
00136 return microfeed_main;
00137 }
00138
00147 void microfeed_main_free(MicrofeedMain* microfeed_main) {
00148 MicrofeedTimeout* timeout;
00149 MicrofeedTimeout* next_timeout;
00150 MicrofeedWatch* watch;
00151 MicrofeedWatch* next_watch;
00152
00153 microfeed_mutex_free(microfeed_main->mutex);
00154 microfeed_main->mutex = NULL;
00155 dbus_connection_close(microfeed_main->connection);
00156 microfeed_main->connection = NULL;
00157 for (timeout = microfeed_main->timeouts; timeout; timeout = next_timeout) {
00158 timeout->main = NULL;
00159 next_timeout = timeout->next;
00160 microfeed_memory_free(timeout);
00161 }
00162 microfeed_main->timeouts = NULL;
00163 for (watch = microfeed_main->watches; watch; watch = next_watch) {
00164 watch->main = NULL;
00165 next_watch = watch->next;
00166 microfeed_memory_free(watch);
00167 }
00168 microfeed_main->watches = NULL;
00169 microfeed_main->watches_count = 0;
00170 microfeed_memory_free(microfeed_main->poll_fds);
00171 microfeed_memory_free(microfeed_main);
00172 }
00173
00180 DBusConnection* microfeed_main_get_dbus_connection(MicrofeedMain* microfeed_main) {
00181
00182 return microfeed_main->connection;
00183 }
00184
00190 void microfeed_main_loop(MicrofeedMain* microfeed_main) {
00191 struct timeval timeval;
00192 int milliseconds;
00193 MicrofeedWatch* watch;
00194 struct pollfd* pollfd;
00195 MicrofeedTimeoutCallback timeout_callback;
00196 void* user_data;
00197 MicrofeedWatchType type;
00198 MicrofeedWatchCallback watch_callback;
00199 int fd;
00200 char buffer[1024];
00201 ssize_t dummy;
00202
00203 microfeed_mutex_lock(microfeed_main->mutex);
00204
00205 while (!microfeed_main->exit_requested) {
00206 microfeed_mutex_unlock(microfeed_main->mutex);
00207
00208 while (dbus_connection_get_dispatch_status(microfeed_main->connection) == DBUS_DISPATCH_DATA_REMAINS) {
00209 dbus_connection_dispatch(microfeed_main->connection);
00210 }
00211 if (dbus_connection_has_messages_to_send(microfeed_main->connection)) {
00212 dbus_connection_flush(microfeed_main->connection);
00213 }
00214
00215 microfeed_mutex_lock(microfeed_main->mutex);
00216
00217 if (microfeed_main->timeouts) {
00218 gettimeofday(&timeval, NULL);
00219 milliseconds = microfeed_main->timeouts->milliseconds - timeval.tv_sec * 1000 - timeval.tv_usec / 1000;
00220 if (milliseconds < 0) {
00221 milliseconds = 0;
00222 }
00223 } else {
00224 milliseconds = -1;
00225 }
00226
00227 if (!microfeed_main->poll_fds) {
00228 microfeed_main->poll_fds = pollfd = microfeed_memory_allocate_bytes((microfeed_main->watches_count + 1) * sizeof(struct pollfd));
00229 pollfd->fd = microfeed_main->wakeup_pipe[0];
00230 pollfd->events = POLLIN;
00231 for (watch = microfeed_main->watches, pollfd++; watch; watch = watch->next, pollfd++) {
00232 watch->pollfd = pollfd;
00233 pollfd->fd = watch->fd;
00234 if (watch->type == MICROFEED_WATCH_TYPE_READ_WRITE) {
00235 pollfd->events = POLLIN | POLLOUT;
00236 } else if (watch->type == MICROFEED_WATCH_TYPE_WRITE) {
00237 pollfd->events = POLLOUT;
00238 } else {
00239 pollfd->events = POLLIN;
00240 }
00241 }
00242 }
00243
00244 if (microfeed_main->exit_requested) {
00245 break;
00246 }
00247
00248 microfeed_main->polling = 1;
00249
00250 microfeed_mutex_unlock(microfeed_main->mutex);
00251
00252 poll(microfeed_main->poll_fds, microfeed_main->watches_count + 1, milliseconds);
00253
00254 microfeed_mutex_lock(microfeed_main->mutex);
00255
00256 microfeed_main->polling = 0;
00257
00258 gettimeofday(&timeval, NULL);
00259 milliseconds = timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
00260 if (microfeed_main->timeouts && microfeed_main->timeouts->milliseconds < milliseconds) {
00261 timeout_callback = microfeed_main->timeouts->callback;
00262 user_data = microfeed_main->timeouts->user_data;
00263
00264 microfeed_mutex_unlock(microfeed_main->mutex);
00265
00266 timeout_callback(microfeed_main, user_data);
00267 microfeed_main_remove_timeout(microfeed_main, microfeed_main->timeouts);
00268
00269 microfeed_mutex_lock(microfeed_main->mutex);
00270
00271 }
00272
00273 if (microfeed_main->poll_fds->revents & POLLIN) {
00274 dummy = read(microfeed_main->wakeup_pipe[0], buffer, 1024);
00275 }
00276
00277 if (microfeed_main->poll_fds) {
00278 for (watch = microfeed_main->watches; watch; watch = microfeed_main->watch_iterator) {
00279 microfeed_main->watch_iterator = watch->next;
00280 if ((pollfd = watch->pollfd)) {
00281 if (pollfd->revents & (POLLIN | POLLOUT)) {
00282 type = MICROFEED_WATCH_TYPE_READ_WRITE;
00283 } else if (pollfd->revents & POLLOUT) {
00284 type = MICROFEED_WATCH_TYPE_WRITE;
00285 } else if (pollfd->revents & POLLIN) {
00286 type = MICROFEED_WATCH_TYPE_READ;
00287 } else {
00288 type = MICROFEED_WATCH_TYPE_NONE;
00289 }
00290 if (type != MICROFEED_WATCH_TYPE_NONE) {
00291 watch_callback = watch->callback;
00292 fd = watch->fd;
00293 user_data = watch->user_data;
00294
00295 microfeed_mutex_unlock(microfeed_main->mutex);
00296
00297 watch_callback(microfeed_main, fd, type, user_data);
00298
00299 microfeed_mutex_unlock(microfeed_main->mutex);
00300 }
00301 }
00302 }
00303 }
00304 }
00305
00306 microfeed_mutex_unlock(microfeed_main->mutex);
00307 }
00308
00314 void microfeed_main_exit(MicrofeedMain* microfeed_main) {
00315 microfeed_mutex_lock(microfeed_main->mutex);
00316
00317 microfeed_main->exit_requested = 1;
00318 wakeup_poll(microfeed_main);
00319
00320 microfeed_mutex_unlock(microfeed_main->mutex);
00321 }
00322
00334 MicrofeedTimeout* microfeed_main_add_timeout(MicrofeedMain* microfeed_main, unsigned long int milliseconds, MicrofeedTimeoutCallback callback, void* user_data) {
00335 MicrofeedTimeout* timeout;
00336 struct timeval timeval;
00337 MicrofeedTimeout* current;
00338 MicrofeedTimeout* previous;
00339
00340 microfeed_mutex_lock(microfeed_main->mutex);
00341
00342 gettimeofday(&timeval, NULL);
00343 milliseconds += timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
00344
00345 timeout = microfeed_memory_allocate(MicrofeedTimeout);
00346 timeout->main = microfeed_main;
00347 timeout->milliseconds = milliseconds;
00348 timeout->callback = callback;
00349 timeout->user_data = user_data;
00350
00351 for (previous = NULL, current = microfeed_main->timeouts; current; previous = current, current = current->next) {
00352 if (milliseconds < current->milliseconds) {
00353 timeout->previous = current->previous;
00354 if (current->previous) {
00355 current->previous->next = timeout;
00356 } else {
00357 microfeed_main->timeouts = timeout;
00358 }
00359 current->previous = timeout;
00360 timeout->next = current;
00361 break;
00362 }
00363 }
00364 if (!current) {
00365 if (previous) {
00366 timeout->previous = previous;
00367 previous->next = timeout;
00368 } else {
00369 timeout->previous = NULL;
00370 microfeed_main->timeouts = timeout;
00371 }
00372 timeout->next = NULL;
00373 }
00374
00375 wakeup_poll(microfeed_main);
00376
00377 microfeed_mutex_unlock(microfeed_main->mutex);
00378
00379 return timeout;
00380 }
00381
00394 MicrofeedWatch* microfeed_main_add_watch(MicrofeedMain* microfeed_main, int fd, MicrofeedWatchType type, MicrofeedWatchCallback callback, void* user_data) {
00395 MicrofeedWatch* watch;
00396
00397 microfeed_mutex_lock(microfeed_main->mutex);
00398
00399 watch = microfeed_memory_allocate(MicrofeedWatch);
00400 watch->main = microfeed_main;
00401 watch->fd = fd;
00402 watch->type = type;
00403 watch->pollfd = NULL;
00404 watch->callback = callback;
00405 watch->user_data = user_data;
00406
00407 watch->next = microfeed_main->watches;
00408 if (watch->next) {
00409 watch->next->previous = watch;
00410 }
00411 microfeed_main->watches = watch;
00412 microfeed_main->watches_count++;
00413
00414 microfeed_memory_free(microfeed_main->poll_fds);
00415 microfeed_main->poll_fds = NULL;
00416 wakeup_poll(microfeed_main);
00417
00418 microfeed_mutex_unlock(microfeed_main->mutex);
00419
00420 return watch;
00421 }
00422
00432 void microfeed_main_remove_timeout(MicrofeedMain* microfeed_main, MicrofeedTimeout* timeout) {
00433 microfeed_mutex_lock(microfeed_main->mutex);
00434
00435 if (microfeed_main == timeout->main) {
00436 if (timeout->previous) {
00437 timeout->previous->next = timeout->next;
00438 } else if (timeout->main) {
00439 timeout->main->timeouts = timeout->next;
00440 }
00441 if (timeout->next) {
00442 timeout->next->previous = timeout->previous;
00443 }
00444 microfeed_memory_free(timeout);
00445 }
00446
00447 microfeed_mutex_unlock(microfeed_main->mutex);
00448 }
00449
00456 void microfeed_main_remove_watch(MicrofeedMain* microfeed_main, MicrofeedWatch* watch) {
00457 microfeed_mutex_lock(microfeed_main->mutex);
00458
00459 if (microfeed_main == watch->main) {
00460 if (microfeed_main->watch_iterator == watch) {
00461 microfeed_main->watch_iterator = watch->next;
00462 }
00463
00464 if (watch->previous) {
00465 watch->previous->next = watch->next;
00466 } else if (watch->main) {
00467 watch->main->watches = watch->next;
00468 }
00469 if (watch->next) {
00470 watch->next->previous = watch->previous;
00471 }
00472 microfeed_memory_free(watch);
00473 microfeed_main->watches_count--;
00474
00475 microfeed_memory_free(microfeed_main->poll_fds);
00476 microfeed_main->poll_fds = NULL;
00477 wakeup_poll(microfeed_main);
00478 }
00479
00480 microfeed_mutex_unlock(microfeed_main->mutex);
00481 }
00482
00483 static void dispatch_status_changed(DBusConnection* connection, DBusDispatchStatus new_status, void* data) {
00484 MicrofeedMain* microfeed_main;
00485
00486 if (new_status == DBUS_DISPATCH_DATA_REMAINS) {
00487 microfeed_main = (MicrofeedMain*)data;
00488 wakeup_poll(microfeed_main);
00489 }
00490 }
00491
00492 static dbus_bool_t add_timeout(DBusTimeout* timeout, void* data) {
00493 MicrofeedMain* microfeed_main;
00494 MicrofeedTimeout* microfeed_timeout;
00495
00496 if (dbus_timeout_get_enabled(timeout) && !dbus_timeout_get_data(timeout)) {
00497 microfeed_main = (MicrofeedMain*)data;
00498 microfeed_timeout = microfeed_main_add_timeout(microfeed_main, dbus_timeout_get_interval(timeout), handle_timeout, timeout);
00499 dbus_timeout_set_data(timeout, microfeed_timeout, NULL);
00500 }
00501
00502 return TRUE;
00503 }
00504
00505 static void remove_timeout(DBusTimeout* timeout, void* data) {
00506 MicrofeedMain* microfeed_main;
00507 MicrofeedTimeout* microfeed_timeout;
00508
00509 microfeed_main = (MicrofeedMain*)data;
00510 if ((microfeed_timeout = (MicrofeedTimeout*)dbus_timeout_get_data(timeout))) {
00511 microfeed_main_remove_timeout(microfeed_main, microfeed_timeout);
00512 dbus_timeout_set_data(timeout, NULL, NULL);
00513 }
00514 }
00515
00516 static void toggle_timeout(DBusTimeout* timeout, void* data) {
00517 if (dbus_timeout_get_enabled(timeout)) {
00518 add_timeout(timeout, data);
00519 } else {
00520 remove_timeout(timeout, data);
00521 }
00522 }
00523
00524 static void handle_timeout(MicrofeedMain* microfeed_main, void* user_data) {
00525 DBusTimeout* timeout;
00526
00527 timeout = (DBusTimeout*)user_data;
00528 if (dbus_timeout_get_enabled(timeout)) {
00529 dbus_timeout_handle(timeout);
00530 microfeed_main_add_timeout(microfeed_main, dbus_timeout_get_interval(timeout), handle_timeout, timeout);
00531 }
00532 }
00533
00534 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
00535 MicrofeedMain* microfeed_main;
00536 int fd;
00537 MicrofeedWatch* microfeed_watch;
00538 unsigned int flags;
00539 MicrofeedWatchType type;
00540
00541 if (dbus_watch_get_enabled(watch) && !dbus_watch_get_data(watch)) {
00542 microfeed_main = (MicrofeedMain*)data;
00543 flags = dbus_watch_get_flags(watch);
00544 if (flags & DBUS_WATCH_READABLE && flags & DBUS_WATCH_WRITABLE) {
00545 type = MICROFEED_WATCH_TYPE_READ_WRITE;
00546 } else if (flags & DBUS_WATCH_WRITABLE) {
00547 type = MICROFEED_WATCH_TYPE_WRITE;
00548 } else {
00549 type = MICROFEED_WATCH_TYPE_READ;
00550 }
00551 #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)
00552 fd = dbus_watch_get_unix_fd(watch);
00553 #else
00554 fd = dbus_watch_get_fd(watch);
00555 #endif
00556 microfeed_watch = microfeed_main_add_watch(microfeed_main, fd, type, handle_watch, watch);
00557 dbus_watch_set_data(watch, microfeed_watch, NULL);
00558 }
00559
00560 return TRUE;
00561 }
00562
00563 static void remove_watch(DBusWatch *watch, void *data) {
00564 MicrofeedMain* microfeed_main;
00565 MicrofeedWatch* microfeed_watch;
00566
00567 microfeed_main = (MicrofeedMain*)data;
00568 if ((microfeed_watch = (MicrofeedWatch*)dbus_watch_get_data(watch))) {
00569 microfeed_main_remove_watch(microfeed_main, microfeed_watch);
00570 dbus_watch_set_data(watch, NULL, NULL);
00571 }
00572 }
00573
00574 static void toggle_watch(DBusWatch *watch, void *data) {
00575 if (dbus_watch_get_enabled(watch)) {
00576 add_watch(watch, data);
00577 } else {
00578 remove_watch(watch, data);
00579 }
00580 }
00581
00582 static void handle_watch(MicrofeedMain* main, int fd, MicrofeedWatchType type, void* user_data) {
00583 DBusWatch* watch;
00584 unsigned int flags;
00585
00586 watch = (DBusWatch*)user_data;
00587 if (dbus_watch_get_enabled(watch)) {
00588 if (type == MICROFEED_WATCH_TYPE_READ_WRITE) {
00589 flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
00590 } else if (type == MICROFEED_WATCH_TYPE_WRITE) {
00591 flags = DBUS_WATCH_WRITABLE;
00592 } else {
00593 flags = DBUS_WATCH_READABLE;
00594 }
00595 dbus_watch_handle(watch, flags);
00596 }
00597 }
00598
00599 static void wakeup_poll(MicrofeedMain* microfeed_main) {
00600 static char c = 0;
00601 ssize_t dummy;
00602
00603 if (microfeed_main->polling) {
00604 dummy = write(microfeed_main->wakeup_pipe[1], &c, 1);
00605 c++;
00606 }
00607 }
00608
00609 static void wakeup_main(void* data) {
00610 MicrofeedMain* microfeed_main;
00611
00612 microfeed_main = (MicrofeedMain*)data;
00613
00614 microfeed_mutex_lock(microfeed_main->mutex);
00615
00616 wakeup_poll(microfeed_main);
00617
00618 microfeed_mutex_unlock(microfeed_main->mutex);
00619 }