]> granicus.if.org Git - fcron/commitdiff
On Linux, use specific system APIs to detect suspend/resume and measure suspend duration
authorThibault Godouet <fcron@free.fr>
Sun, 12 Jun 2016 20:28:28 +0000 (21:28 +0100)
committerThibault Godouet <fcron@free.fr>
Sun, 12 Jun 2016 20:28:28 +0000 (21:28 +0100)
12 files changed:
config.h.in
configure.in
database.c
doc/en/changes.sgml
doc/en/faq.sgml
doc/en/fcron.8.sgml
doc/en/fcron.conf.5.sgml
doc/en/todo.sgml
fcron.c
script/boot-install
suspend.c
suspend.h

index 97b56d7292c42ed3935b3fcac0b482264677e069..d0dc8d7eac03192cd332230242715a73c8cdf6a8 100644 (file)
 /* Define if you have the <sys/time.h> header file.  */
 #undef HAVE_SYS_TIME_H
 
+/* Define if you have the <sys/timerfd.h> header file.  */
+#undef HAVE_SYS_TIMERFD_H
+
 /* Define if you have the <sys/types.h> header file.  */
 #undef HAVE_SYS_TYPES_H
 
index 56694efbff179b40cb456512c18f440b4f7db318..0e80c616db15866785d6a61cb117b43109a12a34 100644 (file)
@@ -10,7 +10,7 @@ AC_CONFIG_HEADER(config.h)
 AC_PREREQ(2.57)
 m4_include([m4/ax_lib_readline.m4])
 
-vers="3.2.1"
+vers="3.3.0"
 vers_quoted="\"$vers\""
 AC_DEFINE_UNQUOTED(VERSION, $vers)
 AC_DEFINE_UNQUOTED(VERSION_QUOTED, $vers_quoted)
@@ -54,7 +54,7 @@ AC_CHECK_HEADERS(errno.h sys/fcntl.h getopt.h limits.h)
 AC_CHECK_HEADERS(stdarg.h)
 AC_CHECK_HEADERS(termios.h)
 AC_CHECK_HEADERS(strings.h)
-AC_CHECK_HEADERS(sys/select.h sys/types.h sys/socket.h sys/un.h)
+AC_CHECK_HEADERS(sys/select.h sys/timerfd.h sys/types.h sys/socket.h sys/un.h)
 AC_CHECK_HEADERS(security/pam_appl.h pam/pam_appl.h crypt.h shadow.h libaudit.h)
 AC_CHECK_HEADERS(sys/resource.h)
 AC_CHECK_HEADERS(grp.h)
index 6c6d05146776fdd1c4b3bca005f8a691dfb2654c..91a90a82c80fa5da70a22a75ad27c808f79fad30 100644 (file)
@@ -1509,7 +1509,14 @@ set_next_exe_startup(struct cl_t *cl, const int context,
         else {
             if (cl->cl_nextexe != LONG_MAX) {
                 cl->cl_nextexe += sleep_duration;
-                if (cl->cl_nextexe < now || cl->cl_nextexe > TIME_T_MAX) {
+
+                if (cl->cl_nextexe < now && context == CONTEXT_RESUME) {
+                    /* userland processes including fcron may not run for a short
+                     * time before suspend, or after resume, so we can end up in this situation.
+                     * it's not really an error though, and it's best to simply run that job now */
+                    cl->cl_nextexe = now;
+                }
+                else if (cl->cl_nextexe < now || cl->cl_nextexe > TIME_T_MAX) {
                     /* either there was an integer overflow, or the sleep_duration time is incorrect
                      * (e.g. fcron didn't shut down cleanly and the fcrontab wasn't saved correctly) */
                     error
index ca8e4365e3a437db3ee9c79e1857eb07bc555f40..b03073b976ea48db1656c15b0d288c1fd214e7fa 100644 (file)
@@ -12,6 +12,17 @@ A copy of the license is included in gfdl.sgml.
    <sect1 id="changes">
       <title>Changes</title>
 
+      <itemizedlist>
+        <title>From version 3.2.1 to 3.3.0</title>
+            <listitem>
+               <para>fcron now handles computer suspend/resume.  On Linux systems, fcron can detect resumes and measure the suspend time.  On other OSes, a script must be run at suspend and resume via system hooks.</para>
+            </listitem>
+            <listitem>
+               <para>Refactored the socket (for fcrondyn), suspend and select code.</para>
+            </listitem>
+      </itemizedlist>
+
+
       <itemizedlist>
         <title>From version 3.2.0 to 3.2.1</title>
            <listitem>
index c92313d0e28cc161b6f7a205af4713a7738dc77a..b03a3b6f51a7026e49b1a9603236dcdee6044599 100644 (file)
@@ -96,9 +96,10 @@ every day at 2:30, it will run at 3:30 the day of this kind of DST change.
            <answer>
               <para>fcron now fully supports suspend (to memory or disk).
                On resume it will adjust the task schedules accordingly, run runatreboot tasks if appropriate, and report non-execution of noticenotrun tasks.</para>
-               <para>fcron will try to notice suspends by itself without external help,
-               by checking if it wakes up later than it expected after a sleep.
-               However this is far from bullet-proof, as fcron may not notice
+               <para>fcron will try to notice suspends by itself without external help.
+              On Linux it can do so reliably via system APIs, but on other OSes it will instead
+               check if it wakes up later than it expected after a sleep.
+               This is far from bullet-proof, as fcron may not notice
                the computer was suspended or under-estimate the suspend duration.
                This is because fcron can be woken up by external events such
                as receiving a signal or fcrondyn interation. There is also a risk
@@ -106,7 +107,7 @@ every day at 2:30, it will run at 3:30 the day of this kind of DST change.
                clock correctly after resume. If so, it may compute an incorrect
                the time and date of the execution of a job (please see the entry
                about system clock adjustment in the present FAQ).</para>
-               <para>Because of this, it is recommended to explicitly 'tell' fcron
+               <para>Because of this, on non-Linux systems it is recommended to explicitly 'tell' fcron
                about suspends and the precise suspend duration:
                <orderedlist>
                    <listitem>
@@ -122,6 +123,9 @@ every day at 2:30, it will run at 3:30 the day of this kind of DST change.
                         <para>Wake up fcron and tell it to process the suspend file and reschedule tasks accordingly:
                         <programlisting>$ kill -CONT $(cat &fcron.pid;)</programlisting></para>
                </orderedlist>
+              <para>An example script implementing this for pm-utils and systemd is included: fcron.suspend.sh.
+               Note that it is however not needed on Linux.  Contribution of equivalent scripts for other
+               systems is welcome.</para>
               <para>Alternatively you could have fcron stop on suspend and restart on resume.
                However the main drawback would then be that tasks running at the time of suspend
                would be run again at resume, even though they may not have been stopped and finish on resume
index c2562c461dacdaffe3b3fd5c7cb8f6ae89c137a8..9ce5b6723223931a56f4bde38956c3420c325f2c 100644 (file)
@@ -263,7 +263,7 @@ update (this signal is used by &fcrontab;(5))</para>
            <varlistentry>
                <term><constant>SIGCONT</constant></term>
                <listitem>
-                   <para>Notify &fcron; that the system was just resumed from suspend (to memory or disk). This will trigger &fcron; to read the &suspendfile; and update the task schedules accordingly.</para>
+                   <para>Notify &fcron; that the system was just resumed from suspend (to memory or disk). This will trigger &fcron; to read the &suspendfile; and update the task schedules accordingly.  Note that fcron doesn't need this to detect suspend/resume on Linux.</para>
                </listitem>
            </varlistentry>
        </variablelist>
@@ -311,7 +311,7 @@ name per line, special name "all" acts for everyone)</para>
            <varlistentry>
                <term><filename>&suspendfile;</filename></term>
                <listitem>
-                   <para>Location of &fcron; suspend file. This should be used to let &fcron; know how long the system was suspended (to memory or disk), so as task schedules can be updated accordingly. The file must be owned by &rootname;:&rootgroup;, and not writable by others. When the system resumes, write the number of seconds (as a string) the system was suspended into this file, and then send a <constant>SIGCONT</constant> signal to make fcron process (and then delete) that file.</para>
+                   <para>Location of &fcron; suspend file, for non-Linux systems. This should be used to let &fcron; know how long the system was suspended (to memory or disk), so as task schedules can be updated accordingly. The file must be owned by &rootname;:&rootgroup;, and not writable by others. When the system resumes, write the number of seconds (as a string) the system was suspended into this file, and then send a <constant>SIGCONT</constant> signal to make fcron process (and then delete) that file.  This is not needed on Linux as fcron uses Linux-specific APIs to detect the resume and measure the suspend duration.</para>
                </listitem>
            </varlistentry>
        </variablelist>
index 590cd380e905942b8cc4f999940b05eef7fc9176..324074863686b2ae228990ef26a6f8c6535b5f60 100644 (file)
@@ -59,7 +59,7 @@ to work properly).</para>
                    <term><varname>suspendfile</varname>=<replaceable>file-path</replaceable>
 (<filename>&suspendfile;</filename>)</term>
                    <listitem>
-                       <para>Location of &fcron; suspend file. This should be used to let fcron know how long the system was suspended (to memory or disk), so as task schedules can be updated accordingly.</para>
+                       <para>Location of &fcron; suspend file. On non-Linux systems, this should be used to let fcron know how long the system was suspended (to memory or disk), so as task schedules can be updated accordingly.</para>
                    </listitem>
                </varlistentry>
                <varlistentry>
index a1341c7fa8bd9aef59f7e5da61ec80a539b838a7..fbe26ec183fefbdeeb85f6895af6d7a2fdfcfb2a 100644 (file)
@@ -27,16 +27,7 @@ A copy of the license is included in gfdl.sgml.
               <para>Option to compile and install from git sources without generating the doc</para>
            </listitem>
            <listitem>
-              <para>On Linux systems, replace suspendfile by clock_gettime() calls: CLOCK_BOOTTIME - CLOCK_MONOTONIC will give us the total suspend duration.  Should be simpler, more elegant and accurate.</para>
-           </listitem>
-           <listitem>
-              <para>On Linux systems, use timerfd_create()/timerfd_settime(TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET) to get notified of time jumps.  On other systems, keep SIGCONT with a hook in systemd/pm-utils.</para>
-           </listitem>
-           <listitem>
-              <para>add systemd suspend hooks for fcron (contribution welcome)</para>
-           </listitem>
-           <listitem>
-              <para>add a 'runatresume' (or 'runonclockchanges'?) option, to run when the computer resumes? (similar to runatreboot)</para>
+              <para>split bootrun into bootrun vs. resumerun, to run when the computer resumes? (similar to bootrun)</para>
            </listitem>
            <listitem>
               <para>use ask_user() in boot-install</para>
diff --git a/fcron.c b/fcron.c
index e476340d14972b8cc7c82d934af9912974c78eb8..f54d96ffc693bb3e742b8d0f29af152367670157 100644 (file)
--- a/fcron.c
+++ b/fcron.c
@@ -829,6 +829,7 @@ main_loop()
 #ifdef FCRONDYN
     fcrondyn_socket_init(&main_select);
 #endif
+    init_suspend(&main_select);
 #endif
 
     now = my_time();
@@ -893,17 +894,17 @@ main_loop()
 
         debug("\n");
         now = my_time();
-        debug_print_tstamp("just woke up")
+        debug_print_tstamp("just woke up");
 
-            check_signal();
-        check_suspend(slept_from, nwt, &sig_cont);
+        check_signal();
+        check_suspend(slept_from, nwt, &sig_cont, &main_select);
         reset_sig_cont();
-        debug_print_tstamp("after check_signal and suspend")
+        debug_print_tstamp("after check_signal and suspend");
 
-            test_jobs();
-        debug_print_tstamp("after test_jobs")
+        test_jobs();
+        debug_print_tstamp("after test_jobs");
 
-            while (serial_num > 0 && serial_running < serial_max_running) {
+        while (serial_num > 0 && serial_running < serial_max_running) {
             run_serial_job();
         }
 
@@ -917,16 +918,16 @@ main_loop()
             /* save all files */
             save_file(NULL);
         }
-        debug_print_tstamp("after save")
+        debug_print_tstamp("after save");
 #if defined(FCRONDYN) && defined(HAVE_GETTIMEOFDAY)
-            /* check if there's a new connection, a new command to answer, etc ... */
-            /* we do that *after* other checks, to avoid Denial Of Service attacks */
-            fcrondyn_socket_check(&main_select);
+        /* check if there's a new connection, a new command to answer, etc ... */
+        /* we do that *after* other checks, to avoid Denial Of Service attacks */
+        fcrondyn_socket_check(&main_select);
 #endif
 
         nwt = check_lavg(save);
-        debug_print_tstamp("after check_lavg")
-            debug("next wake time : %s", ctime(&nwt));
+        debug_print_tstamp("after check_lavg");
+        debug("next wake time : %s", ctime(&nwt));
 
         check_signal();
 
index 37bb34ed119b875cd03b90cc821a08294e0e99d0..35d66a6694417903b2a7a86f97289607669205e8 100755 (executable)
@@ -289,28 +289,36 @@ fi
 
 #
 # Now install the suspend script under the appropriate suspend framework
+# Note that we don't need this on Linux as fcron works this out
+# by itself using systems API.
 #
+if test `uname` != Linux ; then
 echo
-if test -d /usr/lib/systemd/system-sleep ; then
-    # systemd
-    SUSPEND_DEST=/usr/lib/systemd/system-sleep/fcron.sh
-    echo "This system appears to run systemd. Would you like to install the systemd"
-    echo "suspend script under $SUSPEND_DEST?"
-    if test "`ask_user`" = y; then
-        $INSPROG -c -m 754 script/fcron.suspend.sh $SUSPEND_DEST
-    fi
-elif test -d /etc/pm/sleep.d ; then
-    # pm-utils
-    SUSPEND_DEST=/etc/pm/sleep.d/74_fcron
-    echo "This system appears to run pm-utils. Would you like to install the pm-utils"
-    echo "suspend script under $SUSPEND_DEST?"
-    if test "`ask_user`" = y; then
-        $INSPROG -c -m 754 script/fcron.suspend.sh $SUSPEND_DEST
+    if test -d /usr/lib/systemd/system-sleep -o -d /lib/systemd/system-sleep  ; then
+        # systemd
+       if test -d /usr/lib/systemd/system-sleep ; then
+               SUSPEND_DEST=/usr/lib/systemd/system-sleep/fcron.sh
+       else
+               SUSPEND_DEST=/lib/systemd/system-sleep/fcron.sh
+       fi
+        echo "This system appears to run systemd. Would you like to install the systemd"
+        echo "suspend script under $SUSPEND_DEST?"
+        if test "`ask_user`" = y; then
+            $INSPROG -c -m 754 script/fcron.suspend.sh $SUSPEND_DEST
+        fi
+    elif test -d /etc/pm/sleep.d ; then
+        # pm-utils
+        SUSPEND_DEST=/etc/pm/sleep.d/74_fcron
+        echo "This system appears to run pm-utils. Would you like to install the pm-utils"
+        echo "suspend script under $SUSPEND_DEST?"
+        if test "`ask_user`" = y; then
+            $INSPROG -c -m 754 script/fcron.suspend.sh $SUSPEND_DEST
+        fi
+    else
+        echo "This script didn't find any suspend system it supports."
+        echo "Please install an appropriate suspend script manually."
     fi
-else
-    echo "This script didn't find any suspend system it supports."
-    echo "Please install an appropriate suspend script manually."
-fi
+fi # uname != Linux
 
 if PID=`pidof fcron`; then
   KILL="kill -TERM $PID"
index 1aedcb1dbef0b81f0cd82932d2e800c331f59602..c41e23b5f3967807103225ecfb30e007b4244569 100644 (file)
--- a/suspend.c
+++ b/suspend.c
@@ -1,5 +1,5 @@
 /*
- * FCRON - periodic command scheduler 
+ * FCRON - periodic command scheduler
  *
  *  Copyright 2000-2014 Thibault Godouet <fcron@free.fr>
  *
  *  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
- * 
+ *
  *  The GNU General Public License can also be found in the file
  *  `LICENSE' that comes with the fcron source distribution.
  */
 #include "fcronconf.h"
 #include "fcron.h"
 #include "database.h"
+#ifdef HAVE_SYS_TIMERFD_H
+#include <sys/select.h>
+#include <sys/timerfd.h>
+#include <stdint.h>             /* for uint64_t */
+#ifdef __linux__
+/* Not too sure how to get that from the Linux header, so we redefine here instead */
+#ifndef TFD_TIMER_CANCEL_ON_SET
+#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#endif                          /* TFD_TIMER_CANCEL_ON_SET */
+#endif                          /* __linux__ */
+#endif                          /* HAVE_SYS_TIMERFD_H */
+
+/* types */
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+struct linux_timeref {
+    struct timespec monotonic;
+    struct timespec boottime;
+};
+#endif                          /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
+
+/* variables */
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+struct linux_timeref linux_suspend_ref;
+#endif                          /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
+#ifdef TFD_TIMER_CANCEL_ON_SET
+int timer_cancel_on_set_fd = -1;
+#endif                          /* TFD_TIMER_CANCEL_ON_SET */
+
+
+/* internal functions */
+long int read_suspend_duration(time_t slept_from);
+double timespec_diff(struct timespec *from, struct timespec *to);
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+void linux_init_timeref(struct linux_timeref *tr);
+double linux_get_suspend_time(struct linux_timeref *tr);
+#endif                          /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
+
+double
+timespec_diff(struct timespec *from, struct timespec *to)
+{
+    return ((to->tv_sec - from->tv_sec) * 1000000000.0 +
+            (to->tv_nsec - from->tv_nsec)) / 1000000000.0;
+}
+
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+void
+linux_init_timeref(struct linux_timeref *tr)
+    /* Initialize the time reference */
+{
+    clock_gettime(CLOCK_MONOTONIC, &tr->monotonic);
+    clock_gettime(CLOCK_BOOTTIME, &tr->boottime);
+}
+
+double
+linux_get_suspend_time(struct linux_timeref *tr)
+    /* return the suspend time, using Linux-specific APIs */
+{
+    struct timespec tpm, tpb;
+    double tpm_diff, tpb_diff;
+
+    debug("Calculating suspend duration from CLOCK_BOOTTIME-CLOCK_MONOTONIC");
+
+    clock_gettime(CLOCK_MONOTONIC, &tpm);
+    clock_gettime(CLOCK_BOOTTIME, &tpb);
+
+    tpm_diff = timespec_diff(&tr->monotonic, &tpm);
+    tpb_diff = timespec_diff(&tr->boottime, &tpb);
+
+    linux_init_timeref(tr);
+
+    return (tpb_diff - tpm_diff);
+}
+#endif                          /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
 
 long int
 read_suspend_duration(time_t slept_from)
@@ -50,6 +123,7 @@ read_suspend_duration(time_t slept_from)
     long int suspend_duration = 0;      /* default value to return on error */
     struct stat s;
 
+    debug("Attempting to read suspend duration from %s", suspendfile);
     fd = open(suspendfile, O_RDONLY | O_NONBLOCK);
     if (fd == -1) {
         /* If the file doesn't exist, then we assume the user/system
@@ -137,18 +211,78 @@ read_suspend_duration(time_t slept_from)
 }
 
 void
-check_suspend(time_t slept_from, time_t nwt, char *sig_cont)
+init_suspend(select_instance * si)
+{
+
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+    linux_init_timeref(&linux_suspend_ref);
+#endif                          /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
+
+#ifdef TFD_TIMER_CANCEL_ON_SET
+    {
+        struct itimerspec expiration = {
+            .it_value.tv_sec = TIME_T_MAX,
+        };
+
+
+        timer_cancel_on_set_fd = timerfd_create(CLOCK_REALTIME, 0);
+        if (timer_cancel_on_set_fd == -1) {
+            die_e("timerfd_create");
+        }
+        if (timerfd_settime
+            (timer_cancel_on_set_fd,
+             TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &expiration,
+             NULL) == -1) {
+            die_e("timerfd_settime");
+        }
+
+    }
+    select_add_read(si, timer_cancel_on_set_fd);
+#endif                          /* TFD_TIMER_CANCEL_ON_SET */
+
+}
+
+
+void
+check_suspend(time_t slept_from, time_t nwt, char *sig_cont,
+              select_instance * si)
     /* Check if the machine was suspended (to mem or disk), and if so
      * reschedule jobs accordingly */
 {
-    long int suspend_duration;  /* amount of time the system was suspended */
+    long int suspend_duration = 0;      /* amount of time the system was suspended */
     long int time_diff;         /* estimate of suspend_duration (as fallback) */
 
+    time_diff = now - nwt;
+
+#ifdef TFD_TIMER_CANCEL_ON_SET
+    if (si->retcode > 0 && FD_ISSET(timer_cancel_on_set_fd, &si->readfds)) {
+        /* we don't need the data from that fd, but we must read it
+         * or select() would return immediately again */
+        uint64_t exp;
+        read(timer_cancel_on_set_fd, &exp, sizeof(uint64_t));
+
+        debug
+            ("We were notified of a change of time, find out suspend duration");
+#ifdef JUST_FOR_FORMATTING
+    }
+#endif
+
+#else                           /* TFD_TIMER_CANCEL_ON_SET */
+
     if (*sig_cont > 0) {
-        /* the signal CONT was raised, check the suspendfile */
+        debug("We received a SIGCONT, find out the suspend duration");
+
+#endif                          /* TFD_TIMER_CANCEL_ON_SET */
+
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+        suspend_duration = linux_get_suspend_time(&linux_suspend_ref);
+#else                           /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
         suspend_duration = read_suspend_duration(slept_from);
+#endif                          /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
     }
 
+
+
     /* Also check if there was an unaccounted sleep duration, in case
      * the OS is not configured to let fcron properly know about suspends
      * via suspendfile.
@@ -158,14 +292,18 @@ check_suspend(time_t slept_from, time_t nwt, char *sig_cont)
      * NOTE: the +5 second is arbitrary -- just a way to make sure
      * we don't get any false positive.  If the suspend or hibernate
      * is very short it seems fine to simply ignore it anyway */
-    time_diff = now - nwt;
     if (suspend_duration <= 0 && time_diff > 5) {
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+        suspend_duration = linux_get_suspend_time(&linux_suspend_ref);
+#else                           /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
         suspend_duration = time_diff;
+#endif                          /* defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) */
     }
 
     if (suspend_duration > 0) {
         long int actual_sleep = now - slept_from;
         long int scheduled_sleep = nwt - slept_from;
+
         explain("suspend/hibernate detected: we woke up after %lus"
                 " instead of %lus. The system was suspended for %lus.",
                 actual_sleep, scheduled_sleep, suspend_duration);
index 247a6575b46cac9cc68d09d65361aa9f1887c949..e0651a5d6846b50c8582e5cc88697f17c24e0eb0 100644 (file)
--- a/suspend.h
+++ b/suspend.h
 
 #include "config.h"
 #include "global.h"
+#include "select.h"
 
 /* functions prototypes */
-extern long int read_suspend_duration(time_t slept_from);
-extern void check_suspend(time_t slept_from, time_t nwt, char *sig_cont);
+extern void init_suspend(select_instance * si);
+extern void check_suspend(time_t slept_from, time_t nwt, char *sig_cont,
+                          select_instance * si);
 
 #endif                          /* __SUSPEND_H__ */