[D-BUS] How handle D-BUS messages without GLib main loop?

Claudio Takahasi cktakahasi at gmail.com
Mon Jun 13 13:24:55 PDT 2005


The function dbus_connection_setup_with_g_main sets the watch 
and timeout functions of a DBusConnection to integrate the 
connection with the GLib main loop.

However, I need remove glib dependency. I developed
a workaround writing my own main loop and handling
D-Bus messages. The skeleton is below.

Is there another way to implement it?
Comments and suggestions are welcome!

Claudio.

... Start function:
	dbus_connection_set_watch_functions(dbus_conn,
			     add_dbus_watch, 
			     remove_dbus_watch, 
			     watch_dbus_toggled, 
			     NULL, 
			     NULL);
	
	
	poll_main_loop_run(main_loop);
...


/**
 *  Add D-Bus watch function
 *  @param watch D-Bus watch
 *  @return TRUE
 **/
uint32_t add_dbus_watch(DBusWatch *watch, void *data)
{
	uint32_t ret_val = 0;
	uint32_t  cond   =  POLLHUP | POLLERR;
	int32_t *fd, flags;
	
	if (!dbus_watch_get_enabled(watch))
		return TRUE;
	
	fd = (int32_t*)malloc(sizeof(int32_t));
	if(!fd) {
		syslog(LOG_ERR, "Can't allocate memory\n");
		return TRUE;
	}
	
	(*fd) = dbus_watch_get_fd(watch);
	
	
	flags = dbus_watch_get_flags(watch);
	
	if (flags & DBUS_WATCH_READABLE) 
		cond |= POLLIN;
	if (flags & DBUS_WATCH_WRITABLE) 
		cond |= POLLOUT;
	
	fd_poll_add(*fd, cond, dbus_fd_handler , NULL, watch);
	
	dbus_watch_set_data(watch, fd ,(DBusFreeFunction)free);
	
	return ret_val;
}

/**
 *  D-Bus file descriptor handler
 *  @param fd D-Bus file descriptor
 *  @param cond socket condition
 *  @param udata watch
 *  @return TRUE
 **/
static uint8_t dbus_fd_handler(int32_t fd, uint32_t cond, void *udata)
{
	DBusWatch *watch = (DBusWatch *) udata;
	uint32_t flags   = 0;

	if (cond & POLLIN)  
		flags |= DBUS_WATCH_READABLE;
	if (cond & POLLOUT) 
		flags |= DBUS_WATCH_WRITABLE;
	if (cond & POLLHUP) 
		flags |= DBUS_WATCH_HANGUP;
	if (cond & POLLERR) 
		flags |= DBUS_WATCH_ERROR;
	
	
	dbus_watch_handle(watch, flags);
	
	dbus_connection_ref(dbus_conn);

	/* Dispatch messages */
	while (dbus_connection_dispatch(dbus_conn) == DBUS_DISPATCH_DATA_REMAINS);

	dbus_connection_unref(dbus_conn);
	
	return TRUE;
}

/**
 *  Creates a main loop
 *  @return returns the main loop
 **/
static pand_main_loop_t * poll_main_loop_new()
{
	pand_main_loop_t * loop = NULL;
	
	loop = (pand_main_loop_t *) malloc(sizeof(pand_main_loop_t));
	if(!loop) {
		syslog(LOG_ERR, "Can't allocate memory\n");
		return NULL;
	}
		
	memset(loop, 0, sizeof(pand_main_loop_t));
	loop->run = 1;
	return  loop;
}

/**
 *  Exit from main loop
 *  @param loop the main loop
 *  @return (0) success (-1)fail
 **/
static uint8_t poll_main_loop_exit(pand_main_loop_t * loop)
{
	uint8_t  ret_val = -1;
	
	if (loop) {
		loop->run = 0;
		ret_val   = 0;
	}
	
	return ret_val;
	
}

/**
 *  Free the main loop data
 *  @param loop the main loop
 **/
static void poll_main_loop_free(pand_main_loop_t * loop)
{
	//free all fds
	fd_poll_free(loop->fd_poll_head.next);

	if (loop) {
		free(loop);
		loop = NULL;
	}
	
}

/**
 *  The main loop of the daemon
 *  @param loop the main loop pointer
 **/
static void poll_main_loop_run(pand_main_loop_t * loop)
{
	struct pollfd *fds;
	struct fd_poll *p, *w;
	int nfds, res, i;
	uint8_t keep;
	
	fds = malloc(WATCH_MAX * sizeof(struct pollfd));
	
	if (!fds) {
		syslog(LOG_ERR, "Can't allocate memory\n");
		return;
	}
	
	while (loop->run) {
		nfds = 0;
		for (w = (main_loop->fd_poll_head.next); w != NULL; w = w->next) {
			fds[nfds].fd      = w->fd;
			fds[nfds].events  = w->flags;
			fds[nfds].revents = 0;
			nfds++;
		}
		
		res = poll(fds, nfds, -1);
		
		if (res <= 0)
			continue;
		
		p = &(main_loop->fd_poll_head);
		w = main_loop->fd_poll_head.next;
		i = 0;
		
		while (w) {
			if (fds[i].revents) {
				keep = w->func(w->fd, fds[i].revents, w->udata);
				if (!keep) {
					p->next = w->next;
					memset(w, 0, sizeof(*w));
					w = p->next;
					i++;
					continue;
				}
			}
			p = w;
			w = w->next;
			i++;
		}

	}
	
	free(fds);
}


More information about the dbus mailing list