Beispiel #1
0
/**
 * 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;
}
Beispiel #2
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;
}