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 }