Commit a6d5818f authored by Federico Mena Quintero's avatar Federico Mena Quintero Committed by Federico Mena Quintero

Switch the alarm system from using SIGALRM to normal glib timers. Also,

2001-09-17  Federico Mena Quintero  <federico@ximian.com>

	Switch the alarm system from using SIGALRM to normal glib timers.
	Also, use a more robust de-queueing mechanism.

	* gui/alarm-notify/alarm.c (alarm_init): Removed.
	(alarm_done): Remove the glib timeout instead of closing the pipes
	and the signal handler.
	(alarm_add): Allow adding alarms that happen before right now.
	(queue_alarm): Use a glib timer instead of a signal.
	(alarm_remove): Adjust the timeout as appropriate.

	* gui/alarm-notify/notify-main.c (main): There is no need to
	initialize the alarm system now.

	* gui/main.c (main): Likewise.

svn path=/trunk/; revision=12904
parent 9772d692
2001-09-17 Federico Mena Quintero <federico@ximian.com>
Switch the alarm system from using SIGALRM to normal glib timers.
Also, use a more robust de-queueing mechanism.
* gui/alarm-notify/alarm.c (alarm_init): Removed.
(alarm_done): Remove the glib timeout instead of closing the pipes
and the signal handler.
(alarm_add): Allow adding alarms that happen before right now.
(queue_alarm): Use a glib timer instead of a signal.
(alarm_remove): Adjust the timeout as appropriate.
* gui/alarm-notify/notify-main.c (main): There is no need to
initialize the alarm system now.
* gui/main.c (main): Likewise.
2001-09-17 JP Rosevear <jpr@ximian.com>
* gui/calendar-model.c (calendar_model_init): get itip addresses
......
......@@ -32,14 +32,11 @@
/* Whether the timer system has been initialized */
static gboolean alarm_inited;
/* The pipes used to notify about an alarm */
static int alarm_pipes [2];
/* Our glib timeout */
static guint timeout_id;
/* The list of pending alarms */
static GList *alarms;
static GList *alarms = NULL;
/* A queued alarm structure */
typedef struct {
......@@ -49,52 +46,19 @@ typedef struct {
AlarmDestroyNotify destroy_notify_fn;
} AlarmRecord;
static void setup_timeout (time_t now);
/* SIGALRM handler. Notifies the callback about the alarm. */
static void
alarm_signal (int arg)
{
char c = 0;
write (alarm_pipes [1], &c, 1);
}
/* Sets up an itimer and returns a success code */
static gboolean
setup_itimer (time_t diff)
{
struct itimerval itimer;
int v;
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = diff;
itimer.it_value.tv_usec = 0;
v = setitimer (ITIMER_REAL, &itimer, NULL);
return (v == 0) ? TRUE : FALSE;
}
/* Clears the itimer we have pending */
static gboolean
clear_itimer (void)
{
return setup_itimer (0);
}
/* Removes the head alarm, returns it, and schedules the next alarm in the
* queue.
*/
static AlarmRecord *
/* Removes the head alarm from the queue. Does not touch the timeout_id. */
static void
pop_alarm (void)
{
AlarmRecord *ar;
GList *l;
if (!alarms)
return NULL;
return;
ar = alarms->data;
......@@ -102,55 +66,70 @@ pop_alarm (void)
alarms = g_list_remove_link (alarms, l);
g_list_free_1 (l);
if (alarms) {
g_free (ar);
}
/* Callback from the alarm timeout */
static gboolean
alarm_ready_cb (gpointer data)
{
time_t now;
AlarmRecord *new_ar;
g_assert (alarms != NULL);
timeout_id = 0;
now = time (NULL);
new_ar = alarms->data;
if (!setup_itimer (new_ar->trigger - now)) {
g_message ("pop_alarm(): Could not reset the timer! "
"Weird things will happen.");
while (alarms) {
AlarmRecord *ar;
AlarmRecord ar_copy;
/* FIXME: should we free the alarm list? What
* about further alarm removal requests that
* will fail?
*/
ar = alarms->data;
if (ar->trigger > now)
break;
ar_copy = *ar;
ar = &ar_copy;
pop_alarm (); /* This will free the original AlarmRecord; that's why we copy it */
(* ar->alarm_fn) (ar, ar->trigger, ar->data);
if (ar->destroy_notify_fn)
(* ar->destroy_notify_fn) (ar, ar->data);
}
} else
if (!clear_itimer ())
g_message ("pop_alarm(): Could not clear the timer! "
"Weird things may happen.");
return ar;
if (alarms)
setup_timeout (now);
return FALSE;
}
/* Input handler for our own alarm notification pipe */
/* Sets up a timeout for the next minute */
static void
alarm_ready (gpointer data, gint fd, GdkInputCondition cond)
setup_timeout (time_t now)
{
AlarmRecord *ar;
char c;
if (read (alarm_pipes [0], &c, 1) != 1) {
g_message ("alarm_ready(): Uh? Could not read from notification pipe.");
return;
}
time_t next, diff;
struct tm tm;
g_assert (timeout_id == 0);
g_assert (alarms != NULL);
ar = pop_alarm ();
g_print ("alarm_ready(): Notifying about alarm on %s\n", ctime (&ar->trigger));
tm = *localtime (&now);
tm.tm_sec = 0;
tm.tm_min++; /* next minute */
(* ar->alarm_fn) (ar, ar->trigger, ar->data);
next = mktime (&tm);
g_assert (next != -1);
if (ar->destroy_notify_fn)
(* ar->destroy_notify_fn) (ar, ar->data);
diff = next - now;
g_free (ar);
g_assert (diff >= 0);
timeout_id = g_timeout_add (diff * 1000, alarm_ready_cb, NULL);
}
/* Used from g_list_insert_sorted(); compares the trigger times of two AlarmRecord structures. */
static int
compare_alarm_by_time (gconstpointer a, gconstpointer b)
{
......@@ -163,40 +142,34 @@ compare_alarm_by_time (gconstpointer a, gconstpointer b)
}
/* Adds an alarm to the queue and sets up the timer */
static gboolean
queue_alarm (time_t now, AlarmRecord *ar)
static void
queue_alarm (AlarmRecord *ar)
{
time_t diff;
time_t now;
AlarmRecord *old_head;
if (alarms)
if (alarms) {
g_assert (timeout_id != 0);
old_head = alarms->data;
else
} else {
g_assert (timeout_id == 0);
old_head = NULL;
}
alarms = g_list_insert_sorted (alarms, ar, compare_alarm_by_time);
if (old_head == alarms->data)
return TRUE;
return;
/* Set the timer for removal upon activation */
diff = ar->trigger - now;
if (!setup_itimer (diff)) {
GList *l;
g_message ("queue_alarm(): Could not set up timer! Not queueing alarm.");
l = g_list_find (alarms, ar);
g_assert (l != NULL);
now = time (NULL);
setup_timeout (now);
}
alarms = g_list_remove_link (alarms, l);
g_list_free_1 (l);
return FALSE;
}
return TRUE;
}
/**
* alarm_add:
......@@ -215,29 +188,18 @@ gpointer
alarm_add (time_t trigger, AlarmFunction alarm_fn, gpointer data,
AlarmDestroyNotify destroy_notify_fn)
{
time_t now;
AlarmRecord *ar;
g_return_val_if_fail (alarm_inited, NULL);
g_return_val_if_fail (trigger != -1, NULL);
g_return_val_if_fail (alarm_fn != NULL, NULL);
now = time (NULL);
if (trigger < now)
return NULL;
ar = g_new (AlarmRecord, 1);
ar->trigger = trigger;
ar->alarm_fn = alarm_fn;
ar->data = data;
ar->destroy_notify_fn = destroy_notify_fn;
g_print ("alarm_add(): Adding alarm for %s\n", ctime (&trigger));
if (!queue_alarm (now, ar)) {
g_free (ar);
ar = NULL;
}
queue_alarm (ar);
return ar;
}
......@@ -252,10 +214,10 @@ void
alarm_remove (gpointer alarm)
{
AlarmRecord *ar;
AlarmRecord ar_copy;
AlarmRecord *old_head;
GList *l;
g_return_if_fail (alarm_inited);
g_return_if_fail (alarm != NULL);
ar = alarm;
......@@ -268,48 +230,29 @@ alarm_remove (gpointer alarm)
old_head = alarms->data;
if (old_head == ar)
pop_alarm ();
else {
if (old_head == ar) {
ar_copy = *ar;
ar = &ar_copy;
pop_alarm (); /* This will free the original AlarmRecord; that's why we copy it */
} else {
alarms = g_list_remove_link (alarms, l);
g_list_free_1 (l);
}
if (ar->destroy_notify_fn)
(* ar->destroy_notify_fn) (ar, ar->data);
g_free (ar);
}
/**
* alarm_init:
*
* Initializes the alarm timer mechanism. This must be called near the
* beginning of the program.
**/
void
alarm_init (void)
{
struct sigaction sa;
int flags;
/* Reset the timeout */
g_return_if_fail (alarm_inited == FALSE);
g_assert (timeout_id != 0);
pipe (alarm_pipes);
if (!alarms) {
g_source_remove (timeout_id);
timeout_id = 0;
}
/* set non blocking mode */
flags = 0;
fcntl (alarm_pipes [0], F_GETFL, &flags);
fcntl (alarm_pipes [0], F_SETFL, flags | O_NONBLOCK);
gdk_input_add (alarm_pipes [0], GDK_INPUT_READ, alarm_ready, NULL);
/* Notify about destructiono of the alarm */
/* Setup the signal handler */
sa.sa_handler = alarm_signal;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction (SIGALRM, &sa, NULL);
if (ar->destroy_notify_fn)
(* ar->destroy_notify_fn) (ar, ar->data);
alarm_inited = TRUE;
}
/**
......@@ -323,11 +266,15 @@ alarm_done (void)
{
GList *l;
g_return_if_fail (alarm_inited);
if (timeout_id == 0) {
g_assert (alarms == NULL);
return;
}
g_assert (alarms != NULL);
if (!clear_itimer ())
g_message ("alarm_done(): Could not clear the timer! "
"Weird things may happen.");
g_source_remove (timeout_id);
timeout_id = 0;
for (l = alarms; l; l = l->next) {
AlarmRecord *ar;
......@@ -342,16 +289,4 @@ alarm_done (void)
g_list_free (alarms);
alarms = NULL;
if (close (alarm_pipes[0]) != 0)
g_message ("alarm_done(): Could not close the input pipe for notification");
alarm_pipes[0] = -1;
if (close (alarm_pipes[1]) != 0)
g_message ("alarm_done(): Could not close the output pipe for notification");
alarm_pipes[1] = -1;
alarm_inited = FALSE;
}
......@@ -44,30 +44,6 @@ static BonoboGenericFactory *factory;
static AlarmNotify *alarm_notify_service;
/* La de da */
static void
funny_trigger_cb (gpointer alarm_id, time_t trigger, gpointer data)
{
char *msg;
char str[256];
struct tm *tm;
tm = localtime (&trigger);
strftime (str, sizeof (str), "%Y/%m/%d %H:%M:%S", tm);
msg = g_strdup_printf (_("It is %s. The Unix time is %ld right now. We just thought "
"you may like to know."), str, (long) trigger);
gnome_ok_dialog (msg);
g_free (msg);
}
/* Dum de dum */
static void
funny_times_init (void)
{
alarm_add ((time_t) 999999999L, funny_trigger_cb, NULL, NULL); /* Sep 9 01:46:39 2001 UTC */
}
/* Factory function for the alarm notify service; just creates and references a
* singleton service object.
*/
......@@ -106,11 +82,8 @@ main (int argc, char **argv)
glade_gnome_init ();
alarm_init ();
alarm_queue_init ();
funny_times_init ();
factory = bonobo_generic_factory_new ("OAFIID:GNOME_Evolution_Calendar_AlarmNotify_Factory",
alarm_notify_factory_fn, NULL);
if (!factory)
......
......@@ -106,7 +106,6 @@ main (int argc, char **argv)
g_error (_("Could not initialize gnome-vfs"));
glade_gnome_init ();
alarm_init ();
e_cursors_init ();
#if 0
......
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