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 }