All pastes #136268 Raw Edit

hughsie

public text v1 · immutable
#136268 ·published 2006-08-17 15:51 UTC
rendered paste body
http://www.mail-archive.com/powersave-devel@forge.novell.com/msg00599.html

GpmInhibit, add g_return_if_fail stuff. Search for FIXME and TODO.

--------------------------------------------------------
to hal: + dsd@gentoo.org

Multicore laptops and turning off cores

Now we are playing with cpu frequency scaling, it would make sense in my opinion to expose a OS neutral API to offline and online CPU's.

I think it was Daniel Drake who showed me how to do this at GUADEC by just echoing a value somewhere in sysfs for his new shiny dual-core laptop.
He also showed me this *dramatically* reduced the power usage of the laptop.

I think it went something like this:
echo 0 > /sys/devices/system/cpu/cpuX/online

This is Linux specific, but we can add Solaris and *BSD support easily. Artem, Joe, what are the commands?

I'm guessing that a dual core laptop appears as two processor objects in HAL, in which case it makes it trivial to add methods:

void org.freedesktop.Hal.Device.ProcessorHotplug.SetOnline(bool)
bool org.freedesktop.Hal.Device.ProcessorHotplug.GetOnline(void)

This scheme wouldn't be possible if the processor object disappears from the HAL device tree which I don't think it does. Daniel can you confirm please?

Note: we can see if a CPU is "offlineable" by the presence of the file /sys/devices/system/cpu/cpuX/online - if it does not exist then you can't offline it, and we shouldn't add the methods or the capability 'processor_hotplug'.

Better interface, capability and method names welcome. :-)

Now, I'm imagining this being used on dual core laptops, but the interface shouldn't rule out other machines, such as insanely big SMP servers with x CPU's.

Sound sane / insane? Imagine a checkbox in a typical policy agent preferences program (heh):

When on battery power:

[x] Turn off additional processors

Now, that would ROCK.
--------------------------------------------------------

GpmProxy *proxy_processor;
DBusGProxy *proxy;

proxy = gpm_proxy_assign (proxy_processor, GPM_PROXY_SESSION, "org.freedesktop.Hal", "org.freedesktop.Hal.Device.ProcessorHotplug", "/org/freedesktop/moo");
If (proxy == NULL) {
	g_warning ("could not get initial proxy");
	has_hardware = FALSE; /* not a new enough HAL */
}

proxy = gpm_proxy_get_proxy (proxy_processor);
If (proxy == NULL) {
	g_warning ("not connected");
	return;
}	

Then GpmProxy class can monitor changes in dbus session and system busses, and keep the state in a non-singleton object:

Then work on a gpm-cpu-hotplug.[c|h]

MAKE SURE WE HAVE UNIX LINE ENDINGS!

--------------------------------------------------------
private:
	int number_cpus
	gboolean has_hardware;

int gpm_cpu_hotplug_get_number_cpus (GpmCpuHotplug *cpuhotplug)
int gpm_cpu_hotplug_set_number_cpus (GpmCpuHotplug *cpuhotplug, int cpus)
gboolean gpm_cpu_hotplug_has_hardware (GpmCpuHotplug *cpuhotplug)
--------------------------------------------------------
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2006 Richard Hughes <richard@hughsie.com>
 *
 * Licensed under the GNU General Public License Version 2
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <dbus/dbus-glib.h>

#include "gpm-proxy.h"
#include "gpm-debug.h"

static void     gpm_proxy_class_init (GpmProxyClass *klass);
static void     gpm_proxy_init       (GpmProxy      *proxy);
static void     gpm_proxy_finalize   (GObject		*object);

#define GPM_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_PROXY, GpmProxyPrivate))

/* this is a managed proxy, i.e. a proxy that handles messagebus and DBUS service restarts. */

/* convert:
trivial:
 gpm-polkit
 gpm-brightness

complex:
 gpm-screensaver
 gpm-hal

then, rm gpm-dbus-x-monitor.*

*/

/*
    <schema>
      <key>/schemas/apps/gnome-power-manager/processor_offline_ac</key>
      <applyto>/apps/gnome-power-manager/processor_offline_ac</applyto>
      <owner>gnome-power-manager</owner>
      <type>bool</type>
      <default>true</default>
      <locale name="C">
        <short>Whether or not we should turn off additional processors when on AC power</short>
        <long>Whether or not we should turn off any additional processors to save power when on AC power. This setting only affects multiprocessor servers and dual core laptops.</long>
      </locale>
    </schema>

    <schema>
      <key>/schemas/apps/gnome-power-manager/processor_offline_battery</key>
      <applyto>/apps/gnome-power-manager/processor_offline_battery</applyto>
      <owner>gnome-power-manager</owner>
      <type>bool</type>
      <default>true</default>
      <locale name="C">
        <short>Whether or not we should turn off additional processors when on battery power</short>
        <long>Whether or not we should turn off any additional processors to save power when on battery power. This setting only affects multiprocessor servers and dual core laptops.</long>
      </locale>
    </schema>

#define GPM_PREF_AC_OFFLINE_CPU		GPM_PREF_DIR "/processor_offline_ac"
#define GPM_PREF_BATTERY_OFFLINE_CPU	GPM_PREF_DIR "/processor_offline_battery"
*/

struct GpmProxyPrivate
{
	GpmProxyBusType  bus_type;
	char			*service;
	char			*interface;
	char			*path;
	DBusGProxy		*proxy;
	DBusGProxy		*proxy_dbus;
	gboolean		*assigned;
	DBusGConnection	*connection;
};

enum {
	DAEMON_START,
	DAEMON_STOP,
	LAST_SIGNAL
};

static guint	     signals [LAST_SIGNAL] = { 0, };

G_DEFINE_TYPE (GpmProxy, gpm_proxy, G_TYPE_OBJECT)

/**
 * gpm_proxy_connect:
 * @gproxy: This class instance
 * Return value: success
 **/
static gboolean
gpm_proxy_connect (GpmProxy *gproxy)
{
	g_return_val_if_fail (GPM_IS_PROXY (gproxy), FALSE);

	/* are already connected? */
	if (gproxy->priv->proxy != NULL) {
		gpm_debug ("already connected to %s", gproxy->priv->service);
		return FALSE;
	}

	gproxy->priv->proxy = dbus_g_proxy_new_for_name (gproxy->priv->connection,
							 gproxy->priv->service,
							 gproxy->priv->path,
							 gproxy->priv->interface);
	/* shouldn't be, but make sure proxy valid */
	if (gproxy->priv->proxy == NULL) {
		gpm_debug ("proxy is NULL, maybe the daemon responsible for %s is not running?", gproxy->priv->service,);
		return FALSE;
	}

	g_debug ("emitting daemon-start: %s", gproxy->priv->service);
	g_signal_emit (screensaver, signals [DAEMON_START], 0);
	return TRUE;
}

/**
 * gpm_proxy_disconnect:
 * @gproxy: This class instance
 * Return value: success
 **/
static gboolean
gpm_proxy_disconnect (GpmProxy *gproxy)
{
	g_return_val_if_fail (GPM_IS_PROXY (gproxy), FALSE);

	/* are already disconnected? */
	if (gproxy->priv->proxy == NULL) {
		gpm_debug ("already disconnected from %s", gproxy->priv->service);
		return FALSE;
	}
	g_object_unref (gproxy->priv->proxy);
	g_debug ("emitting daemon-stop: %s", gproxy->priv->service);
	g_signal_emit (screensaver, signals [DAEMON_STOP], 0);
	return TRUE;
}

/**
 * gpm_proxy_dbus_name_owner_changed:
 * @proxy: The DBUS_SERVICE_DBUS proxy
 * @name: The DBUS name, e.g. org.freedesktop.Hal
 * @prev: The previous name, e.g. :0.13
 * @new: The new name, e.g. :0.14
 * @gproxy: This class instance
 *
 * The name-owner-changed session DBUS callback.
 **/
static void
gpm_proxy_dbus_name_owner_changed (DBusGProxy	*proxy,
				 const char	*name,
				 const char	*prev,
				 const char	*new,
				 GpmProxy *gproxy)
{
	g_return_if_fail (GPM_IS_PROXY (gproxy));

	gpm_debug ("emitting name-owner-changed : %s (%s->%s)", name, prev, new);

	if (strcmp (name, gproxy->priv->service) == 0) {
		if (strlen (prev) != 0 && strlen (new) == 0 ) {
			gpm_proxy_disconnect (gproxy);
		}
		if (strlen (prev) == 0 && strlen (new) != 0 ) {
			gpm_proxy_connect (gproxy);
		}
	}
}

/**
 * gpm_proxy_assign:
 * @gproxy: This class instance
 * @bus_type: The bus type, either GPM_PROXY_SESSION or GPM_PROXY_SYSTEM
 * @service: The DBUS service name
 * @interface: The DBUS interface
 * @path: The DBUS path
 * Return value: The DBUS proxy, or NULL if we haven't connected yet.
 **/
DBusGProxy *
gpm_proxy_assign (GpmProxy *gproxy, GpmProxyBusType bus_type, char *service, char *interface, char *path)
{
	GError *error = NULL;

	g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
	g_return_val_if_fail (service != NULL, NULL);
	g_return_val_if_fail (interface != NULL, NULL);
	g_return_val_if_fail (path != NULL, NULL);

	if (gproxy->priv->assigned == TRUE) {
		gpm_warning ("already assigned proxy!");
		return NULL;
	}

	gproxy->priv->service = g_strdup (service);
	gproxy->priv->interface = g_strdup (interface);
	gproxy->priv->path = g_strdup (path);
	gproxy->priv->bus_type = bus_type;
	gproxy->priv->assigned == TRUE;

	/* get the DBUS connection */
	if (bus_type == GPM_PROXY_SESSION) {
		gproxy->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
	} else {
		gproxy->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
	}
	if (error) {
		gpm_warning ("Cannot connect to DBUS daemon: %s", error->message);
		g_error_free (error);
		return NULL;
	}

	/* set up dbus callbacks to monitor the service */
	gproxy->priv->proxy_dbus = dbus_g_proxy_new_for_name_owner (monitor->priv->connection,
								DBUS_SERVICE_DBUS,
								DBUS_PATH_DBUS,
						 		DBUS_INTERFACE_DBUS,
								&error);
	if (error) {
		gpm_warning ("Cannot connect to DBUS manager: %s", error->message);
		g_error_free (error);
		return NULL;
	}

	dbus_g_proxy_add_signal (gproxy->priv->proxy, "NameOwnerChanged",
				 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
	dbus_g_proxy_connect_signal (gproxy->priv->proxy, "NameOwnerChanged",
				    G_CALLBACK (dbus_name_owner_changed),
				    gproxy, NULL);

	/* try to connect and return proxy (or NULL if invalid) */
	gpm_proxy_connect (gproxy);
	return gproxy->priv->proxy;
}

/**
 * gpm_proxy_get_service:
 * @gproxy: This class instance
 * Return value: The DBUS proxy, or NULL if we are not connected
 **/
DBusGProxy *
gpm_proxy_get_proxy (GpmProxy *gproxy)
{
	g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
	g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
	return gproxy->priv->proxy;
}

/**
 * gpm_proxy_get_service:
 * @gproxy: This class instance
 * Return value: The DBUS service name
 **/
char *
gpm_proxy_get_service (GpmProxy *gproxy)
{
	g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
	g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
	return gproxy->priv->service;
}

/**
 * gpm_proxy_get_interface:
 * @gproxy: This class instance
 * Return value: The DBUS interface
 **/
char *
gpm_proxy_get_interface (GpmProxy *gproxy)
{
	g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
	g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
	return gproxy->priv->interface;
}

/**
 * gpm_proxy_get_path:
 * @gproxy: This class instance
 * Return value: The DBUS path
 **/
char *
gpm_proxy_get_path (GpmProxy *gproxy)
{
	g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
	g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
	return gproxy->priv->path;
}

/**
 * gpm_proxy_get_bus_type:
 * @gproxy: This class instance
 * Return value: The bus type, either GPM_PROXY_SESSION or GPM_PROXY_SYSTEM
 **/
GpmProxyBusType
gpm_proxy_get_bus_type (GpmProxy *gproxy)
{
	g_return_val_if_fail (GPM_IS_PROXY (gproxy), GPM_PROXY_UNKNOWN);
	g_return_val_if_fail (gproxy->priv->assigned == TRUE, GPM_PROXY_UNKNOWN);
	return gproxy->priv->bus_type;
}

/**
 * gpm_proxy_class_init:
 * @gproxy: This class instance
 **/
static void
gpm_proxy_class_init (GpmProxyClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	object_class->finalize = gpm_proxy_finalize;
	g_type_class_add_private (klass, sizeof (GpmProxyPrivate));

	signals [DAEMON_START] =
		g_signal_new ("daemon-start",
			      G_TYPE_FROM_CLASS (object_class),
			      G_SIGNAL_RUN_LAST,
			      G_STRUCT_OFFSET (GpmProxyClass, daemon_start),
			      NULL,
			      NULL,
			      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);

	signals [DAEMON_STOP] =
		g_signal_new ("daemon-stop",
			      G_TYPE_FROM_CLASS (object_class),
			      G_SIGNAL_RUN_LAST,
			      G_STRUCT_OFFSET (GpmProxyClass, daemon_stop),
			      NULL,
			      NULL,
			      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

/**
 * gpm_proxy_init:
 * @gproxy: This class instance
 **/
static void
gpm_proxy_init (GpmProxy *gproxy)
{
	gproxy->priv = GPM_PROXY_GET_PRIVATE (proxy);
	gproxy->priv->proxy = NULL;
	gproxy->priv->proxy_dbus = NULL;
	gproxy->priv->service = NULL;
	gproxy->priv->interface = NULL;
	gproxy->priv->path = NULL;
	gproxy->priv->bus_type = GPM_PROXY_UNKOWN;
	gproxy->priv->assigned = FALSE;
}

/**
 * gpm_proxy_finalize:
 * @object: This class instance
 **/
static void
gpm_proxy_finalize (GObject *object)
{
	GpmProxy *gproxy;
	g_return_if_fail (object != NULL);
	g_return_if_fail (GPM_IS_PROXY (object));

	gproxy = GPM_PROXY (object);
	gproxy->priv = GPM_PROXY_GET_PRIVATE (proxy);

	gpm_proxy_disconnect (gproxy);
	g_object_unref (gproxy->priv->proxy_dbus);
	g_object_unref (gproxy->priv->proxy);
	g_free (gproxy->priv->service);
	g_free (gproxy->priv->interface;
	g_free (gproxy->priv->path);
}

/**
 * gpm_proxy_new:
 * Return value: new class instance.
 **/
GpmProxy *
gpm_proxy_new (void)
{
	GpmProxy *proxy;
	proxy = g_object_new (GPM_TYPE_PROXY, NULL);
	return GPM_PROXY (proxy);
}
--------------------------------------------------------
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2006 Richard Hughes <richard@hughsie.com>
 *
 * Licensed under the GNU General Public License Version 2
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef __GPMPROXY_H
#define __GPMPROXY_H

#include <glib-object.h>

G_BEGIN_DECLS

#define GPM_TYPE_PROXY		(gpm_proxy_get_type ())
#define GPM_PROXY(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_TYPE_PROXY, GpmProxy))
#define GPM_PROXY_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPM_TYPE_PROXY, GpmProxyClass))
#define GPM_IS_PROXY(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_TYPE_PROXY))
#define GPM_IS_PROXY_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPM_TYPE_PROXY))
#define GPM_PROXY_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPM_TYPE_PROXY, GpmProxyClass))

typedef struct GpmProxyPrivate GpmProxyPrivate;

typedef struct
{
	GObject		       parent;
	GpmProxyPrivate *priv;
} GpmProxy;

typedef struct
{
	GObjectClass	parent_class;
	void		(* daemon_start)		(GpmProxy	*proxy);
	void		(* daemon_stop)			(GpmProxy	*proxy);
} GpmProxyClass;

typedef emum {
        GPM_PROXY_SESSION,
        GPM_PROXY_SYSTEM,
        GPM_PROXY_UNKNOWN
} GpmProxyBusType;

GType		 gpm_proxy_get_type		(void);
GpmProxy	*gpm_proxy_new			(void);

DBusGProxy	*gpm_proxy_assign		(GpmProxy	*gproxy,
					GpmProxyBusType	bus_type,
					char	*service,
					char	*interface,
					char	*path);
DBusGProxy	*gpm_proxy_get_proxy		(GpmProxy *gproxy);
char		*gpm_proxy_get_service		(GpmProxy *gproxy);
char		*gpm_proxy_get_interface	(GpmProxy *gproxy);
char		*gpm_proxy_get_path		(GpmProxy *gproxy);
GpmProxyBusType	 gpm_proxy_get_bus_type		(GpmProxy *gproxy);

G_END_DECLS

#endif	/* __GPMPROXY_H */
---------------------------------------------------



-------------------------------------------------------------