aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/gui/alarm-notify/alarm.c
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@ximian.com>2001-09-18 04:04:42 +0800
committerFederico Mena Quintero <federico@src.gnome.org>2001-09-18 04:04:42 +0800
commita6d5818f66df9ecf6c96c700fdf32a514c134ce3 (patch)
tree357eb0a4a492c6cc5c45536632887e06212b55f1 /calendar/gui/alarm-notify/alarm.c
parent9772d692a2b717b7978008d2426aec71aa3fe33f (diff)
downloadgsoc2013-evolution-a6d5818f66df9ecf6c96c700fdf32a514c134ce3.tar
gsoc2013-evolution-a6d5818f66df9ecf6c96c700fdf32a514c134ce3.tar.gz
gsoc2013-evolution-a6d5818f66df9ecf6c96c700fdf32a514c134ce3.tar.bz2
gsoc2013-evolution-a6d5818f66df9ecf6c96c700fdf32a514c134ce3.tar.lz
gsoc2013-evolution-a6d5818f66df9ecf6c96c700fdf32a514c134ce3.tar.xz
gsoc2013-evolution-a6d5818f66df9ecf6c96c700fdf32a514c134ce3.tar.zst
gsoc2013-evolution-a6d5818f66df9ecf6c96c700fdf32a514c134ce3.zip
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
Diffstat (limited to 'calendar/gui/alarm-notify/alarm.c')
-rw-r--r--calendar/gui/alarm-notify/alarm.c255
1 files changed, 95 insertions, 160 deletions
diff --git a/calendar/gui/alarm-notify/alarm.c b/calendar/gui/alarm-notify/alarm.c
index 8f6ba013a4..7f1a2eaa5f 100644
--- a/calendar/gui/alarm-notify/alarm.c
+++ b/calendar/gui/alarm-notify/alarm.c
@@ -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,108 +46,90 @@ typedef struct {
AlarmDestroyNotify destroy_notify_fn;
} AlarmRecord;
+static void setup_timeout (time_t now);
+
-/* SIGALRM handler. Notifies the callback about the alarm. */
+/* Removes the head alarm from the queue. Does not touch the timeout_id. */
static void
-alarm_signal (int arg)
+pop_alarm (void)
{
- char c = 0;
+ AlarmRecord *ar;
+ GList *l;
+
+ if (!alarms)
+ return;
+
+ ar = alarms->data;
+
+ l = alarms;
+ alarms = g_list_remove_link (alarms, l);
+ g_list_free_1 (l);
- write (alarm_pipes [1], &c, 1);
+ g_free (ar);
}
-/* Sets up an itimer and returns a success code */
+/* Callback from the alarm timeout */
static gboolean
-setup_itimer (time_t diff)
+alarm_ready_cb (gpointer data)
{
- struct itimerval itimer;
- int v;
+ time_t now;
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = 0;
- itimer.it_value.tv_sec = diff;
- itimer.it_value.tv_usec = 0;
+ g_assert (alarms != NULL);
+ timeout_id = 0;
- v = setitimer (ITIMER_REAL, &itimer, NULL);
+ now = time (NULL);
- return (v == 0) ? TRUE : FALSE;
-}
+ while (alarms) {
+ AlarmRecord *ar;
+ AlarmRecord ar_copy;
-/* Clears the itimer we have pending */
-static gboolean
-clear_itimer (void)
-{
- return setup_itimer (0);
-}
+ ar = alarms->data;
-/* Removes the head alarm, returns it, and schedules the next alarm in the
- * queue.
- */
-static AlarmRecord *
-pop_alarm (void)
-{
- AlarmRecord *ar;
- GList *l;
+ if (ar->trigger > now)
+ break;
- if (!alarms)
- return NULL;
+ ar_copy = *ar;
+ ar = &ar_copy;
- ar = alarms->data;
+ pop_alarm (); /* This will free the original AlarmRecord; that's why we copy it */
- l = alarms;
- alarms = g_list_remove_link (alarms, l);
- g_list_free_1 (l);
+ (* ar->alarm_fn) (ar, ar->trigger, ar->data);
- if (alarms) {
- time_t now;
- AlarmRecord *new_ar;
-
- 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.");
-
- /* FIXME: should we free the alarm list? What
- * about further alarm removal requests that
- * will fail?
- */
- }
- } else
- if (!clear_itimer ())
- g_message ("pop_alarm(): Could not clear the timer! "
- "Weird things may happen.");
+ if (ar->destroy_notify_fn)
+ (* ar->destroy_notify_fn) (ar, ar->data);
+ }
- 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,41 +142,35 @@ 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);
-
- alarms = g_list_remove_link (alarms, l);
- g_list_free_1 (l);
- return FALSE;
- }
-
- return TRUE;
+ now = time (NULL);
+ setup_timeout (now);
}
+
+
/**
* alarm_add:
* @trigger: Time at which alarm will trigger.
@@ -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;
}