/** * Polling loop * * @param re Poll state. * * @return 0 if success, otherwise errorcode */ static int fd_poll(struct re *re) { const uint64_t to = tmr_next_timeout(&re->tmrl); int i, n; #ifdef HAVE_SELECT fd_set rfds, wfds, efds; #endif DEBUG_INFO("next timer: %llu ms\n", to); /* Wait for I/O */ switch (re->method) { #ifdef HAVE_POLL case METHOD_POLL: re_unlock(re); n = poll(re->fds, re->nfds, to ? (int)to : -1); re_lock(re); break; #endif #ifdef HAVE_SELECT case METHOD_SELECT: { struct timeval tv; /* Clear and update fd sets */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); for (i=0; i<re->nfds; i++) { if (!re->fhs[i].fh) continue; if (re->fhs[i].flags & FD_READ) FD_SET(i, &rfds); if (re->fhs[i].flags & FD_WRITE) FD_SET(i, &wfds); if (re->fhs[i].flags & FD_EXCEPT) FD_SET(i, &efds); } #ifdef WIN32 tv.tv_sec = (long) to / 1000; #else tv.tv_sec = (time_t) to / 1000; #endif tv.tv_usec = (uint32_t) (to % 1000) * 1000; re_unlock(re); n = select(re->nfds, &rfds, &wfds, &efds, to ? &tv : NULL); re_lock(re); } break; #endif #ifdef HAVE_EPOLL case METHOD_EPOLL: re_unlock(re); n = epoll_wait(re->epfd, re->events, re->maxfds, to ? (int)to : -1); re_lock(re); break; #endif default: (void)to; DEBUG_WARNING("no polling method set\n"); return EINVAL; } if (n < 0) return errno; /* Check for events */ for (i=0; (n > 0) && (i < re->nfds); i++) { int fd, flags = 0; switch (re->method) { #ifdef HAVE_POLL case METHOD_POLL: fd = i; if (re->fds[fd].revents & POLLIN) flags |= FD_READ; if (re->fds[fd].revents & POLLOUT) flags |= FD_WRITE; if (re->fds[fd].revents & (POLLERR|POLLHUP|POLLNVAL)) flags |= FD_EXCEPT; if (re->fds[fd].revents & POLLNVAL) { DEBUG_WARNING("event: fd=%d POLLNVAL" " (fds.fd=%d," " fds.events=0x%02x)\n", fd, re->fds[fd].fd, re->fds[fd].events); } /* Clear events */ re->fds[fd].revents = 0; break; #endif #ifdef HAVE_SELECT case METHOD_SELECT: fd = i; if (FD_ISSET(fd, &rfds)) flags |= FD_READ; if (FD_ISSET(fd, &wfds)) flags |= FD_WRITE; if (FD_ISSET(fd, &efds)) flags |= FD_EXCEPT; break; #endif #ifdef HAVE_EPOLL case METHOD_EPOLL: fd = re->events[i].data.fd; if (re->events[i].events & EPOLLIN) flags |= FD_READ; if (re->events[i].events & EPOLLOUT) flags |= FD_WRITE; if (re->events[i].events & EPOLLERR) flags |= FD_EXCEPT; if (!flags) { DEBUG_WARNING("epoll: no flags fd=%d\n", fd); } break; #endif default: return EINVAL; } if (!flags) continue; if (re->fhs[fd].fh) { #if MAIN_DEBUG fd_handler(re, fd, flags); #else re->fhs[fd].fh(flags, re->fhs[fd].arg); #endif } /* Check if polling method was changed */ if (re->update) { re->update = false; return 0; } --n; } return 0; }
//! Main loop int loop_exec() { /*! * This is the main loop function. * * Based on code written by Kimmo.Hamalainen at nokia.com * http://lists.freedesktop.org/archives/dbus/2007-October/008859.html * * @return 0 on success, -1 on error */ DBusError bus_error; dbus_error_init(&bus_error); // Connect to D-Bus bus_conn = dbus_connection_open_private(config_server_address, &bus_error); if (dbus_error_is_set(&bus_error)) { log_error("Error while connecting to the bus: %s\n", bus_error.message); dbus_error_free(&bus_error); return -1; } if (!dbus_bus_register(bus_conn, &bus_error)) { log_error("Error while registering to the bus: %s\n", bus_error.message); dbus_error_free(&bus_error); return -1; } config_unique_address = dbus_bus_get_unique_name(bus_conn); log_debug("Connected to D-Bus, unique id is %s\n", dbus_bus_get_unique_name(bus_conn)); // Request a name (example: com.server.test) dbus_bus_request_name(bus_conn, config_service_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &bus_error); if (dbus_error_is_set(&bus_error)) { log_error("Name Error (%s)\n", bus_error.message); dbus_error_free(&bus_error); return -1; } log_debug("Registered name '%s'\n", config_service_name); // Register watch callback functions if (!dbus_connection_set_watch_functions(bus_conn, add_watch, remove_watch, NULL, NULL, NULL)) { log_error("dbus_connection_set_watch_functions failed\n"); return -1; } // Register function that handles D-Bus events (calls, signals, ...) if (!dbus_connection_add_filter(bus_conn, filter_func, NULL, NULL)) { log_error("Failed to register signal handler callback\n"); return -1; } // Catch all method calls dbus_bus_add_match(bus_conn, "type='method_call'", NULL); log_info("Listening for connections...\n"); /* This clears any pending messages avoiding weird timeouts on some systems * with dbus >= 1.2.22 */ while (dbus_connection_dispatch(bus_conn) == DBUS_DISPATCH_DATA_REMAINS); while (1) { struct pollfd fds[MAX_FDS]; DBusWatch *watches[MAX_WATCHES]; int i, j; int nr_fds = 0; int nr_watches = 0; int poll_result; // Add D-Bus watch descriptors to the list nr_fds = 0; for (i = 0; i < bus_nr_watches; i++) { if (bus_fds[i].fd == 0 || !dbus_watch_get_enabled(bus_watches[i])) { continue; } fds[nr_fds].fd = bus_fds[i].fd; fds[nr_fds].events = bus_fds[i].events; fds[nr_fds].revents = 0; watches[nr_fds] = bus_watches[i]; nr_fds++; if (i > MAX_WATCHES) { log_error("ERR: %d watches reached\n", MAX_WATCHES); break; } } nr_watches = nr_fds; // Add subprocess descriptors to the list for (i = 0; i < my_proc.nr_children; i++) { fds[nr_fds].fd = my_proc.children[i].from; fds[nr_fds].events = 0; fds[nr_fds].revents = 0; nr_fds++; } // Poll descriptors poll_result = 0; if (config_timeout == 0) { // If no timeout defined, wait forever. poll_result = poll(fds, nr_fds, -1); } else { // wait <timeout> seconds poll_result = poll(fds, nr_fds, config_timeout * 1000); } if (poll_result == 0) { if (config_timeout != 0 && my_proc.nr_children == 0) { log_info("Service was idle for more than %d second(s), closing daemon...\n", config_timeout); break; } continue; } else if (poll_result < 0) { perror("poll"); return -1; } // Iterate over all descriptors for (i = 0; i < nr_fds; i++) { if (i < nr_watches) { // D-Bus watch event if (fds[i].revents) { // Handle D-Bus watch event fd_handler(fds[i].revents, watches[i]); } } else { // Subprocess event for (j = 0; j < my_proc.nr_children; j++) { if (my_proc.children[j].from == fds[i].fd) { if (fds[i].revents) { // Subprocess exited, remove it rem_child(j); } break; } } } } } return 0; }