Commit 5fa62aad authored by Stefan Walter's avatar Stefan Walter

Stop copious polling in the background Fixes bug #354432

    * agent/seahorse-agent-cache.c:
    * agent/seahorse-agent-main.c:
    * daemon/seahorse-daemon.c:
    * libseahorse/Makefile.am:
    * libseahorse/seahorse-unix-signal.c:
    * libseahorse/seahorse-unix-signal.h: Stop copious polling in the background
    Fixes bug #354432
parent 3814ef15
......@@ -5,7 +5,8 @@
* daemon/seahorse-daemon.c:
* libseahorse/Makefile.am:
* libseahorse/seahorse-unix-signal.c:
* libseahorse/seahorse-unix-signal.h:
* libseahorse/seahorse-unix-signal.h: Stop copious polling in the background
Fixes bug #354432
2006-12-21 Nate Nielsen <nielsen@memberwebs.com>
......
......@@ -52,6 +52,23 @@
* if their TTL expires.
*/
/* Override the DEBUG_CACHE switch here */
/* #define DEBUG_CACHE_ENABLE 0 */
#ifndef DEBUG_CACHE_ENABLE
#if _DEBUG
#define DEBUG_CACHE_ENABLE 1
#else
#define DEBUG_CACHE_ENABLE 0
#endif
#endif
#if DEBUG_CACHE_ENABLE
#define DEBUG_CACHE(x) g_printerr x
#else
#define DEBUG_CACHE(x)
#endif
#define UNPARSEABLE_KEY _("Unparseable Key ID")
#define UNKNOWN_KEY _("Unknown/Invalid Key")
#define TRANSIENT_ID "TRANSIENTTRANSIENT"
......@@ -67,10 +84,72 @@ typedef struct sa_cache_t {
static GHashTable *g_cache = NULL; /* Hash of ids to sa_cache_t */
static GMemChunk *g_memory = NULL; /* Memory for sa_cache_t's */
static guint g_notify_id = 0; /* gconf notify id */
static guint g_timeout_id = 0; /* timeout of next expire */
gboolean seahorse_agent_cache_check (gpointer);
/* -----------------------------------------------------------------------------
*/
static gint
calc_ttl ()
{
if (!seahorse_gconf_get_boolean (SETTING_CACHE)) {
/* No caching */
return 0;
}
if (seahorse_gconf_get_boolean (SETTING_EXPIRE)) {
/* How long to cache. gconf has in minutes, we want seconds */
return seahorse_gconf_get_integer (SETTING_TTL) * 60;
}
return -1;
};
static void
find_next_expiry (gpointer key, gpointer value, gpointer user_data)
{
sa_cache_t *it = (sa_cache_t *) value;
time_t *next = (time_t*)user_data;
if (*next < it->stamp)
*next = it->stamp;
}
/* Called to calculate and setup next expiry timeout */
static void
setup_next_expiry (gboolean nextonly)
{
time_t now, first = 0;
gint ms, ttl;
if (g_hash_table_size (g_cache) == 0)
return;
ttl = calc_ttl ();
if (ttl == -1) /* cache indefinitely */
return;
g_hash_table_foreach (g_cache, find_next_expiry, &first);
if (!first)
return;
if (g_timeout_id)
g_source_remove (g_timeout_id);
now = time (NULL);
first += ttl;
/* Already expired, so clear in a second */
if (!nextonly && first <= now)
first = now;
ms = ((first - now) + 1) * 1000;
g_timeout_id = g_timeout_add (ms, seahorse_agent_cache_check, NULL);
DEBUG_CACHE (("[cache] next expiry in %d seconds\n", ms / 1000));
}
/* Check each cache item for expiry */
static gboolean
cache_enumerator (gpointer key, gpointer value, gpointer user_data)
......@@ -100,30 +179,24 @@ cache_enumerator (gpointer key, gpointer value, gpointer user_data)
gboolean
seahorse_agent_cache_check (gpointer unused)
{
gint ttl = -1;
g_timeout_id = 0;
if (!g_cache)
return FALSE;
if (g_hash_table_size (g_cache) > 0) {
if (!seahorse_gconf_get_boolean (SETTING_CACHE)) {
/* No caching */
ttl = 0;
}
else if (seahorse_gconf_get_boolean (SETTING_EXPIRE)) {
/* How long to cache. gconf has in minutes, we want seconds */
ttl = seahorse_gconf_get_integer (SETTING_TTL) * 60;
}
gint ttl = calc_ttl ();
/* negative means cache indefinitely */
if (ttl != -1) {
if (g_hash_table_foreach_remove (g_cache, cache_enumerator, &ttl) > 0)
if (g_hash_table_foreach_remove (g_cache, cache_enumerator, &ttl) > 0) {
DEBUG_CACHE (("[cache] expired cached secrets\n"));
seahorse_agent_status_update ();
setup_next_expiry (TRUE);
}
}
}
return TRUE;
return FALSE;
}
/* Callback to free a cache item */
......@@ -154,8 +227,10 @@ gconf_notify (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
if (!gconf_value_get_bool (gconf_entry_get_value (entry)))
seahorse_agent_cache_clearall (NULL);
}
}
/* TTL setting may have changed, so... */
setup_next_expiry (FALSE);
}
/* Initialize the cache */
void
......@@ -171,9 +246,6 @@ seahorse_agent_cache_init ()
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, destroy_cache_item);
g_memory = g_mem_chunk_create (SeahorseAgentPassReq, 128, G_ALLOC_AND_FREE);
/* Handle the cache timeouts */
g_timeout_add (1000, seahorse_agent_cache_check, g_cache);
err = gpgme_engine_check_version (proto);
g_return_if_fail (GPG_IS_OK (err));
......@@ -201,6 +273,11 @@ seahorse_agent_cache_uninit ()
seahorse_gconf_unnotify (g_notify_id);
g_notify_id = 0;
}
if (g_timeout_id) {
g_source_remove (g_timeout_id);
g_timeout_id = 0;
}
}
/* Retrieve a password from the cache */
......@@ -270,6 +347,7 @@ seahorse_agent_internal_clear (const gchar *id)
/* UI hooks */
seahorse_agent_status_update ();
setup_next_expiry (FALSE);
}
/* Callback for clearing all items */
......@@ -291,8 +369,10 @@ seahorse_agent_cache_clearall ()
{
g_assert (g_cache != NULL);
if (g_hash_table_foreach_remove (g_cache, remove_cache_item, NULL) > 0)
if (g_hash_table_foreach_remove (g_cache, remove_cache_item, NULL) > 0) {
seahorse_agent_status_update ();
setup_next_expiry (FALSE);
}
}
......@@ -342,6 +422,7 @@ seahorse_agent_internal_set (const gchar *id, const gchar *pass, gboolean lock)
/* UI hooks */
seahorse_agent_status_update ();
setup_next_expiry (FALSE);
}
/* Returns number of passwords in the cache */
......
......@@ -37,13 +37,15 @@
#include "seahorse-gtkstock.h"
#include "seahorse-gconf.h"
#include "seahorse-agent.h"
#include "seahorse-unix-signal.h"
#include "seahorse-secure-memory.h"
static gboolean g_daemonize = TRUE;
static gboolean g_quit = FALSE;
static gboolean agent_daemonize = TRUE;
static gboolean agent_running = FALSE;
static gboolean agent_quit = FALSE;
static const struct poptOption options[] = {
{ "no-daemonize", 'd', POPT_ARG_NONE | POPT_ARG_VAL, &g_daemonize, FALSE,
{ "no-daemonize", 'd', POPT_ARG_NONE | POPT_ARG_VAL, &agent_daemonize, FALSE,
N_("Do not daemonize seahorse-agent"), NULL },
{ "cshell", 'c', POPT_ARG_NONE | POPT_ARG_VAL, &seahorse_agent_cshell, TRUE,
......@@ -74,7 +76,7 @@ daemonize (const gchar **exec)
pid_t pid;
int i;
if (g_daemonize) {
if (agent_daemonize) {
switch ((pid = fork ())) {
case -1:
err (1, _("couldn't fork process"));
......@@ -110,7 +112,7 @@ daemonize (const gchar **exec)
seahorse_agent_postfork (pid);
seahorse_agent_ssh_postfork (pid);
if (g_daemonize) {
if (agent_daemonize) {
/* If we were asked to exec another program, do that here */
if (!exec || !exec[0])
......@@ -130,20 +132,11 @@ daemonize (const gchar **exec)
}
static void
on_quit (int signal)
unix_signal (int signal)
{
g_quit = 1;
}
static gboolean
check_quit (gpointer data)
{
if (g_quit) {
agent_quit = TRUE;
if (agent_running)
gtk_main_quit ();
return FALSE;
}
return TRUE;
}
static void
......@@ -260,11 +253,11 @@ int main(int argc, char* argv[])
daemonize (args);
/* Handle some signals */
signal (SIGINT, on_quit);
signal (SIGTERM, on_quit);
seahorse_unix_signal_register (SIGINT, unix_signal);
seahorse_unix_signal_register (SIGTERM, unix_signal);
/* Force gconf to reconnect after daemonizing */
if (g_daemonize)
if (agent_daemonize)
seahorse_gconf_disconnect ();
client = gnome_master_client();
......@@ -289,8 +282,8 @@ int main(int argc, char* argv[])
#endif
/* Sometimes we've already gotten a quit signal */
if(!g_quit) {
g_timeout_add (100, check_quit, NULL);
if(!agent_quit) {
agent_running = TRUE;
gtk_main ();
g_message ("left gtk_main\n");
}
......
......@@ -38,9 +38,11 @@
#include "seahorse-gconf.h"
#include "seahorse-gtkstock.h"
#include "seahorse-context.h"
#include "seahorse-unix-signal.h"
static gboolean g_daemonize = TRUE;
static gboolean g_quit = FALSE;
static gboolean daemon_daemonize = TRUE;
static gboolean daemon_running = FALSE;
static gboolean daemon_quit = FALSE;
static const gchar *daemon_icons[] = {
SEAHORSE_ICON_SHARING,
......@@ -49,7 +51,7 @@ static const gchar *daemon_icons[] = {
static const struct poptOption options[] = {
{ "no-daemonize", 'd', POPT_ARG_NONE | POPT_ARG_VAL, &g_daemonize, FALSE,
{ "no-daemonize", 'd', POPT_ARG_NONE | POPT_ARG_VAL, &daemon_daemonize, FALSE,
N_("Do not daemonize seahorse-daemon"), NULL },
POPT_AUTOHELP
......@@ -68,7 +70,7 @@ daemonize (const gchar **exec)
pid_t pid;
int i;
if (g_daemonize) {
if (daemon_daemonize) {
switch ((pid = fork ())) {
case -1:
err (1, _("couldn't fork process"));
......@@ -100,7 +102,7 @@ daemonize (const gchar **exec)
/* The parent process or not daemonizing ... */
if (g_daemonize) {
if (daemon_daemonize) {
/* If we were asked to exec another program, do that here */
if (!exec || !exec[0])
......@@ -120,20 +122,11 @@ daemonize (const gchar **exec)
}
static void
on_quit (int signal)
unix_signal (int signal)
{
g_quit = 1;
}
static gboolean
check_quit (gpointer data)
{
if (g_quit) {
daemon_quit = TRUE;
if (daemon_running)
gtk_main_quit ();
return FALSE;
}
return TRUE;
}
static void
......@@ -234,11 +227,11 @@ int main(int argc, char* argv[])
daemonize (args);
/* Handle some signals */
signal (SIGINT, on_quit);
signal (SIGTERM, on_quit);
seahorse_unix_signal_register (SIGINT, unix_signal);
seahorse_unix_signal_register (SIGTERM, unix_signal);
/* Force gconf to reconnect after daemonizing */
if (g_daemonize)
if (daemon_daemonize)
seahorse_gconf_disconnect ();
client = gnome_master_client();
......@@ -264,8 +257,8 @@ int main(int argc, char* argv[])
#endif
/* Sometimes we've already gotten a quit signal */
if(!g_quit) {
g_timeout_add (100, check_quit, NULL);
if(!daemon_quit) {
daemon_running = TRUE;
gtk_main ();
g_message ("left gtk_main\n");
}
......
......@@ -89,6 +89,7 @@ libseahorse_a_SOURCES = \
seahorse-secure-memory.c seahorse-secure-memory.h \
seahorse-secure-entry.c seahorse-secure-entry.h \
seahorse-algo.c seahorse-algo.h \
seahorse-unix-signal.c seahorse-unix-signal.h \
$(BUILT_SOURCES) \
$(AGENT_SRCS) \
$(KEYSERVER_SRCS) \
......
/*
* Seahorse
*
* Copyright (C) 2006 Nate Nielsen
*
* 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 <sys/types.h>
#include <sys/signal.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <gnome.h>
#include "seahorse-unix-signal.h"
#define MAX_SIGNAL 32
static signal_handler signal_handlers[MAX_SIGNAL] = { NULL, };
static int signal_pipe[2] = { -1, -1 };
static GIOChannel *signal_channel = NULL;
static gint signal_watch_id = 0;
/* The unix signal handler. */
static void
pipe_signals (int signal)
{
gchar sig;
if (signal > MAX_SIGNAL) {
g_warning ("unix signal number too large: %d", signal);
return;
}
sig = (char)signal;
if (write (signal_pipe[1], &sig, sizeof (gchar)) != sizeof (gchar))
g_critical ("unix signal %d lost", signal);
}
/* The event loop callback that handles the unix signals. Must be a GIOFunc. */
static gboolean
deliver_signal (GIOChannel *source, GIOCondition cond, gpointer d)
{
GError *err = NULL;
GIOStatus st;
gsize read;
gchar sig;
while ((st = g_io_channel_read_chars (source, &sig, sizeof (gchar),
&read, &err)) == G_IO_STATUS_NORMAL) {
g_assert (err == NULL);
if (read != 1)
break;
if (sig < MAX_SIGNAL) {
if (signal_handlers[(int)sig])
(signal_handlers[(int)sig]) (sig);
}
}
if (err != NULL)
g_warning ("reading signal pipe failed: %s", err->message);
if (st == G_IO_STATUS_EOF)
g_critical ("signal pipe has been closed");
return TRUE;
}
static void
cleanup_signals ()
{
if (signal_watch_id)
g_source_remove (signal_watch_id);
signal_watch_id = 0;
if (signal_channel)
g_io_channel_unref (signal_channel);
signal_channel = NULL;
if (signal_pipe[0] != -1) {
close (signal_pipe[0]);
close (signal_pipe[1]);
signal_pipe[0] = signal_pipe[1] = -1;
}
}
void
seahorse_unix_signal_register (int sig, signal_handler handler)
{
g_return_if_fail (sig < MAX_SIGNAL);
g_return_if_fail (handler != NULL);
/* Setup the signal channel */
if (signal_channel == NULL) {
memset (&signal_handlers, 0, sizeof (signal_handlers));
if (pipe (signal_pipe)) {
g_critical ("can't create signal pipe: %s", strerror (errno));
return;
}
/* Non blocking to prevent deadlock */
fcntl (signal_pipe[1], F_SETFL, fcntl (signal_pipe[1], F_GETFL) | O_NONBLOCK);
/* convert the reading end of the pipe into a GIOChannel */
signal_channel = g_io_channel_unix_new (signal_pipe[0]);
g_io_channel_set_encoding (signal_channel, NULL, NULL);
g_io_channel_set_flags (signal_channel, g_io_channel_get_flags (signal_channel) | G_IO_FLAG_NONBLOCK, NULL);
/* register the reading end with the event loop */
signal_watch_id = g_io_add_watch (signal_channel, G_IO_IN | G_IO_PRI | G_IO_HUP, deliver_signal, NULL);
g_atexit (cleanup_signals);
}
/* Handle some signals */
signal (sig, pipe_signals);
signal_handlers[sig] = handler;
}
/*
* Seahorse
*
* Copyright (C) 2006 Nate Nielsen
*
* 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.
*/
/**
* For handling unix signal from within main loop.
*/
#ifndef __SEAHORSE_UNIX_SIGNAL_H__
#define __SEAHORSE_UNIX_SIGNAL_H__
#include <glib.h>
typedef void (*signal_handler) (int sig);
void seahorse_unix_signal_register (int sig, signal_handler handler);
#endif /* __SEAHORSE_UNIX_SIGNAL_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment