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