Subject: Re: signal stuff...
To: Christos Zoulas <christos@zoulas.com>
From: Ignatios Souvatzis <ignatios@cs.uni-bonn.de>
List: tech-kern
Date: 01/08/1999 12:35:00
--pAwQNkOnpTn9IO2O
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=mutta00834
On Fri, Jan 08, 1999 at 11:10:40AM +0000, Christos Zoulas wrote:
> In article <19990108115308.D834@cs.uni-bonn.de> ignatios@cs.uni-bonn.de (Ignatios Souvatzis) writes:
>
> > act.sa_handler = (void (*)(int)) &chkpt_restore;
> > act.sa_flags |= SA_ONSTACK;
>
> add:
> sigemptyset(&act.sa_mask);
Uhm, I forgot the comment:
/* We use the same mask as above */
also flags are already initialized (to SA_RESTART, if I looked right).
Maybe I should have cited more... but you better look at the complete
original.
-is
--pAwQNkOnpTn9IO2O
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="chkpt.c"
/*
* Copyright (c) 1998 Alexandre Wennmacher (wennmach@geo.Uni-Koeln.DE)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Alexandre Wennmacher.
* 4. The name of Alexandre Wennmacher may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY ALEXANDRE WENNMACHER AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL ALEXANDRE WENNMACHER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The Chkpt Library is not an official product of the University of Cologne
* (Universitaet zu Koeln).
*/
#include <machine/vmparam.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <sys/uio.h>
#include <stddef.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <setjmp.h>
#include <time.h>
#include "machine.h"
#include "fpu.h"
#include "chkpt_lib.h"
#include "chkpt.h"
#if defined(OS_DIGITAL_UNIX)
#include <alloca.h>
#endif
#if defined(HAVE_MD5)
#include <md5.h>
#endif
#if defined(OS_NETBSD)
extern caddr_t etext;
#endif
#if defined(OS_DIGITAL_UNIX)
extern unsigned long _ftext;
extern unsigned long _etext;
extern unsigned long _fdata;
#endif
static char chkpt_file[MAXPATHLEN];
static char chkpt_file_tmp[MAXPATHLEN];
static char chkpt_file_lock[MAXPATHLEN];
static jmp_buf procenv;
static int handler_installed = 0;
static struct header chkpt_hdr;
static size_t s_header = sizeof(chkpt_hdr);
static struct iovec iov[2];
static int sglen;
static int fd;
static int f_lock;
#if defined(SAVE_FPU)
static fpu_regs fpu;
#endif
static void
#if defined(OS_NETBSD)
chkpt_save(sig, code, scp)
int sig;
int code;
struct sigcontext *scp;
#endif
#if defined(OS_DIGITAL_UNIX)
chkpt_save(sig)
int sig;
#endif
{
struct sigaction act;
int f_chkpt;
void *data_top;
#if defined(EBUG)
switch(sig) {
case SIGALRM:
debug("chkpt_save(): info: Received SIGALRM.\n");
break;
case SIGVTALRM:
debug("chkpt_save(): info: Received SIGVTALRM.\n");
break;
}
#endif
/* Save the process environment.
* If setjmp(procenv) != 0 then we returned just from a restarted program ... */
if (setjmp(procenv) != 0) {
#if defined(EBUG)
debug("chkpt_save(): info: Longjmp succeeded.\n");
#endif
/* We clean up. First, We deinstall the restore signal handler (SIGUSR1). */
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
if (sigaction(SIGUSR1, &act, (struct sigaction *) NULL) == 0) {
#if defined(EBUG)
debug("chkpt_save(): info: Handler for SIGUSR1 deinstalled.\n");
#endif
} else {
#if defined(IAGNOSTIC)
debug("chkpt_save(): warning: Deinstallation of handler SIGUSR1 failed.\n");
#endif
}
/* Reopen files */
if (files_restore() != E_CHKPT_SUCCESS) {
debug("chkpt_save(): error: files_restore() failed.\n");
abort();
}
/* Restore signals */
if (signals_restore() != E_CHKPT_SUCCESS) {
debug("chkpt_save(): error: signals_restore() failed.\n");
abort();
}
/* Restore itimers */
if (itimers_restore() != E_CHKPT_SUCCESS) {
debug("chkpt_save(): error: itimers_restore() failed.\n");
abort();
}
/* Restore the fpu */
#if defined(SAVE_FPU)
#if defined(EBUG)
debug("chkpt_save(): info: Restoring FPU state.\n");
#endif
fpu_restore(&fpu);
#endif
/* Finally, we free the additionally sbrk()'d memory.
* What comes below is really wierd and may give raise to lots of
* compiler or lint complaints. We use the variable `data_top' before
* it is initialized. These are the wonders of checkpointing! */
if (brk(data_top) != 0)
#if defined(IAGNOSTIC)
debug("chkpt_save(): warning: Could not brk memory at %p\n", data_top);
/* If the brk fails, do nothing. We can live with it. */
#endif
#if defined(EBUG)
debug("chkpt_save(): info: Checkpointed state restored; continuing...\n");
#endif
return;
}
/* First, on OSes where neither the kernel saves the FPU when building the
* new context for the signal handler, nor setjmp() saving the FPU registers,
* we have to do that ourselves. */
#if defined(SAVE_FPU)
#if defined(EBUG)
debug("chkpt_save(): info: Saving FPU state.\n");
#endif
fpu_save(&fpu);
#endif
/* Error checking: if one of the save calls fails, return from the
* chkpt_save handler. We don't like to write corrupt checkpoint files */
if (itimers_save() != E_CHKPT_SUCCESS) {
#if defined(IAGNOSTIC)
debug("chkpt_save(): error: itimers_save() failed.\n");
#endif
return;
}
if (signals_save() != E_CHKPT_SUCCESS) {
#if defined(IAGNOSTIC)
debug("chkpt_save(): error: signals_save() failed.\n");
#endif
return;
}
if (files_save() != E_CHKPT_SUCCESS) {
#if defined(IAGNOSTIC)
debug("chkpt_save(): error: files_save() failed.\n");
#endif
return;
}
/* The `ptr' of struct segment points to the first valid address of the text
* or the data segment. In the case of the stack segment, it points to the
* first address after the end. The `top'-variables are always the first
* addresses after the end of a segment (see etext(3), sbrk(2)). Thus,
* `top - base' is always the size (we don't need to add 1).
* Is this also true for USRSTACK ???
*/
data_top = (void *) sbrk(0);
chkpt_hdr.stack.ptr = (void *) alloca(0);
#if defined(OS_DIGITAL_UNIX) && !defined(__gcc2__)
/* We have to do the casts to ptrdiff_t to make the
* Digital Unix C compiler happy */
chkpt_hdr.data.len = (ptrdiff_t) data_top - (ptrdiff_t) chkpt_hdr.data.ptr;
chkpt_hdr.stack.len = USRSTACK - (ptrdiff_t) chkpt_hdr.stack.ptr;
#else
chkpt_hdr.data.len = data_top - chkpt_hdr.data.ptr;
chkpt_hdr.stack.len = (void *) USRSTACK - chkpt_hdr.stack.ptr;
#endif
#if defined(EBUG)
debug("chkpt_save(): info: text.ptr = %p\n", chkpt_hdr.text.ptr);
debug("chkpt_save(): info: text.len = %d\n", chkpt_hdr.text.len);
debug("chkpt_save(): info: data.ptr = %p\n", chkpt_hdr.data.ptr);
debug("chkpt_save(): info: data.len = %d\n", chkpt_hdr.data.len);
debug("chkpt_save(): info: stack.ptr = %p\n", chkpt_hdr.stack.ptr);
debug("chkpt_save(): info: stack.len = %d\n", chkpt_hdr.stack.len);
#endif
iov[0].iov_base = chkpt_hdr.data.ptr;
iov[0].iov_len = chkpt_hdr.data.len;
iov[1].iov_base = chkpt_hdr.stack.ptr;
iov[1].iov_len = chkpt_hdr.stack.len;
sglen = iov[0].iov_len + iov[1].iov_len;
f_chkpt = syscall(SYS_open, chkpt_file_tmp, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (f_chkpt == -1) {
#if defined(IAGNOSTIC)
debug("chkpt_save(): error: Could not open %s.\n", chkpt_file_tmp);
#endif
return;
}
if (write(f_chkpt, &chkpt_hdr, s_header) != s_header) {
#if defined(IAGNOSTIC)
debug("chkpt_save(): error: Could not write struct chkpt_hdr to %s.\n", chkpt_file_tmp);
#endif
(void) syscall(SYS_close, f_chkpt);
return;
}
if (writev(f_chkpt, &iov[0], 2) != sglen) {
#if defined(IAGNOSTIC)
debug("chkpt_save(): error: Could not write data/stack to %s.\n", chkpt_file_tmp);
#endif
(void) syscall(SYS_close, f_chkpt);
return;
}
#if defined(EBUG)
debug("chkpt_save(): info: Wrote %d bytes of data/stack to %s.\n", sglen, chkpt_file_tmp);
#endif
(void) syscall(SYS_close, f_chkpt);
(void) rename(chkpt_file_tmp, chkpt_file);
return;
}
static void
#if defined(OS_NETBSD)
chkpt_restore(sig, code, scp)
int sig;
int code;
struct sigcontext *scp;
#endif /* OS_NETBSD */
#if defined(OS_DIGITAL_UNIX)
chkpt_restore(sig)
int sig;
#endif /* OS_DIGITAL_UNIX */
{
int read_len;
int fd_on_stack;
#if defined(EBUG)
debug("chkpt_restore(): info: received SIGUSR1.\n");
#endif
/* Read in the data and stack using scatter/gather IO. The pointer to our save
* area will be overwritten. We make a local copy (on the stack) and restore
* save immediately after the read.
*/
fd_on_stack = fd;
read_len = readv(fd, &iov[0], 2);
if (read_len != sglen) {
#if defined(IAGNOSTIC)
debug("chkpt_restore(): error: Could not read data/stack from %s.\n", chkpt_file);
if (read_len == -1)
debug("errno = %d\n", errno);
else
debug("chkpt_restore(): error: ... only got %d bytes.\n", read_len);
#endif
abort();
}
#if defined(EBUG)
debug("chkpt_restore(): info: Read %d bytes of data/stack from %s.\n", read_len, chkpt_file);
#endif
(void) syscall(SYS_close, fd_on_stack);
longjmp(procenv, 1);
/* Not reached */
abort();
}
void
chkpt()
{
(void) kill(getpid(), SIGALRM);
return;
}
/* Fortran-C-Interface */
void
#if defined(OS_DIGITAL_UNIX)
chkpt_(void)
#endif /* OS_DIGITAL_UNIX */
#if defined(OS_NETBSD)
chkpt_()
#endif /* OS_NETBSD */
{
chkpt();
}
int
chkpt_init(filename)
char *filename;
{
int pagesize;
struct sigaction act;
struct header lchkpt_hdr;
int f_chkpt;
int allocate;
void *text_top;
void *data_top;
void *ldata_top;
void *stack_base;
void *lstack_base;
#if defined(OS_NETBSD)
struct sigaltstack sigstack;
#endif
#if defined(OS_DIGITAL_UNIX)
stack_t sigstack;
#endif
(void) strncpy(chkpt_file, filename, MAXPATHLEN);
(void) strncpy(chkpt_file_tmp, filename, MAXPATHLEN);
(void) strncat(chkpt_file_tmp, ".tmp", MAXPATHLEN);
(void) strncpy(chkpt_file_lock, filename, MAXPATHLEN);
(void) strncat(chkpt_file_lock, ".lock", MAXPATHLEN);
/* We create a lock file to prevent multiple instances of a process
* to write to the same checkpoint */
#if defined(OS_NETBSD)
f_lock = syscall(SYS_open, chkpt_file_lock, O_WRONLY | O_CREAT | O_EXLOCK, S_IRUSR | S_IWUSR);
if (f_lock == -1) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Lock file %s can not be created.\n", chkpt_file_lock);
#endif
return E_CHKPT_LOCK;
}
#endif /* defined(OS_NETBSD) */
#if defined(OS_DIGITAL_UNIX)
f_lock = syscall(SYS_open, chkpt_file_lock, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (f_lock == -1) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Lock file %s can not be created.\n", chkpt_file_lock);
#endif
return E_CHKPT_LOCK;
}
if (syscall(SYS_flock, f_lock, LOCK_EX) != 0) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Could not obtain lock on lock file %s.\n", chkpt_file_lock);
#endif
return E_CHKPT_LOCK;
}
#endif /* defined(OS_DIGITAL_UNIX) */
/* We fill in as much as possible in chkpt_hdr */
(void) strncpy(chkpt_hdr.version, VERSION, VERSIONLEN);
pagesize = getpagesize();
#if defined(EBUG)
debug("chkpt_init(): info: Pagesize = %d\n", pagesize);
#endif
#if defined(OS_NETBSD)
chkpt_hdr.text.ptr = (void *) USRTEXT;
chkpt_hdr.data.ptr = (void *) roundup((unsigned long) &etext, pagesize);
text_top = (void *) &etext;
#endif /* OS_NETBSD */
#if defined(OS_DIGITAL_UNIX)
chkpt_hdr.text.ptr = (void *) &_ftext;
chkpt_hdr.data.ptr = (void *) &_fdata;
text_top = (void *) &_etext;
#endif /* OS_DIGITAL_UNIX */
#if defined(OS_DIGITAL_UNIX) && !defined(__gcc2__)
chkpt_hdr.text.len = (ptrdiff_t) text_top - (ptrdiff_t) chkpt_hdr.text.ptr;
#else
chkpt_hdr.text.len = text_top - chkpt_hdr.text.ptr;
#endif
#if defined(HAVE_MD5)
(void) MD5Data((unsigned char *) chkpt_hdr.text.ptr, chkpt_hdr.text.len, chkpt_hdr.md5);
#if defined(EBUG)
debug("chkpt_init(): info: MD5 = %s\n", chkpt_hdr.md5);
#endif
#endif
f_chkpt = syscall(SYS_open, chkpt_file, O_RDONLY, 0);
if (f_chkpt == -1) {
/* Checkpoint file does not exist. We already test here if we can open
* chkpt_file for write. If this fails, we signal this to the user. */
f_chkpt = syscall(SYS_open, chkpt_file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (f_chkpt == -1) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Checkpoint file %s can not be created.\n", chkpt_file);
#endif
return E_CHKPT_CREAT;
} else {
(void) syscall(SYS_close, f_chkpt);
(void) unlink(chkpt_file);
/* Install signal Handlers */
act.sa_handler = (void (*)(int)) &chkpt_save;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGALRM);
sigaddset(&act.sa_mask, SIGVTALRM);
sigaddset(&act.sa_mask, SIGUSR1);
act.sa_flags = SA_RESTART;
if (sigaction(SIGALRM, &act, (struct sigaction *) NULL) == 0) {
#if defined(EBUG)
debug("chkpt_init(): info: Handler for SIGALRM installed.\n");
#endif
} else {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Installation of handler for SIGALRM failed.\n");
#endif
return E_CHKPT_SYS;
}
if (sigaction(SIGVTALRM, &act, (struct sigaction *) NULL) == 0) {
#if defined(EBUG)
debug("chkpt_init(): info: Handler for SIGVTALRM installed.\n");
#endif
} else {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Installation of handler for SIGVTALRM failed.\n");
#endif
return E_CHKPT_SYS;
}
handler_installed = 1;
return E_CHKPT_SUCCESS;
}
}
#if defined(EBUG)
debug("chkpt_init(): info: Checkpoint file detected; preparing for restart.\n");
#endif
/*
* O.k., so we have detected a checkpoint file and want to restart the
* process. We can't simply call chkpt_restore() because this routine then
* will overwrite its own stack. Instead, we install chkpt_restore() as a
* signal handler and specify a specific (signal) stack for this handler.
* This way chkpt_restore() can safely restore the saved stack.
*
* However, before we do so, we perform some simple checks to verify that
* the detected checkpoint file corresponds to this process.
*/
if (read(f_chkpt, &lchkpt_hdr, s_header) != s_header) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Could not read struct lchkpt_hdr from %s.\n", chkpt_file);
#endif
(void) syscall(SYS_close, f_chkpt);
return E_CHKPT_READ;
}
if (strncmp(lchkpt_hdr.version, chkpt_hdr.version, VERSIONLEN) != 0) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Checkpoint library version mismatch.\n");
#endif
return E_CHKPT_INCOMPAT;
}
if (lchkpt_hdr.text.ptr != chkpt_hdr.text.ptr) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Start of text segment in checkpoint file does not match with that of the program.\n");
#endif
return E_CHKPT_INCOMPAT;
}
if (lchkpt_hdr.text.len != chkpt_hdr.text.len) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Length of text segment in checkpoint file does not match with that of the program.\n");
#endif
return E_CHKPT_INCOMPAT;
}
#if defined(HAVE_MD5)
if (strncmp(lchkpt_hdr.md5, chkpt_hdr.md5, MD5LEN) != 0) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: MD5 checksum of checkpoint file does not match with that of the program.\n");
#endif
return E_CHKPT_INCOMPAT;
}
#endif
if (lchkpt_hdr.data.ptr != chkpt_hdr.data.ptr) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Start of data segment in checkpoint file does not match with that of the program.\n");
#endif
return E_CHKPT_INCOMPAT;
}
#if defined(EBUG)
debug("chkpt_init(): info: Checkpoint file successfully verified.\n");
debug("chkpt_init(): info: text.ptr = %p\n", lchkpt_hdr.text.ptr);
debug("chkpt_init(): info: text.len = %d\n", lchkpt_hdr.text.len);
debug("chkpt_init(): info: data.ptr = %p\n", lchkpt_hdr.data.ptr);
debug("chkpt_init(): info: data.len = %d\n", lchkpt_hdr.data.len);
debug("chkpt_init(): info: stack.ptr = %p\n", lchkpt_hdr.stack.ptr);
debug("chkpt_init(): info: stack.len = %d\n", lchkpt_hdr.stack.len);
#endif
data_top = (void *) sbrk(0);
#if defined(EBUG)
debug("chkpt_init(): info: Current data_top = %p\n", data_top);
#endif
#if defined(OS_DIGITAL_UNIX) && !defined(__gcc2__)
ldata_top = (void *) ((ptrdiff_t) lchkpt_hdr.data.ptr + lchkpt_hdr.data.len);
#else
ldata_top = lchkpt_hdr.data.ptr + lchkpt_hdr.data.len;
#endif
if (ldata_top > data_top) {
if (brk(ldata_top) != 0) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Could not brk memory at %p\n", ldata_top);
#endif
(void) syscall(SYS_close, f_chkpt);
return E_CHKPT_NOMEM;
}
#if defined(EBUG)
debug("chkpt_init(): info: Successfully set new brk at %p\n", ldata_top);
#endif
}
/* Now that we have set the program brk, we can sbrk() space for the signal
* stack (here) and for the save structure (further down). */
sigstack.ss_sp = sbrk(SIGSTACKSIZE);
if (sigstack.ss_sp == (char *) -1) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Couldn't sbrk() for sigaltstack().\n");
#endif
return E_CHKPT_NOMEM;
}
sigstack.ss_size = SIGSTACKSIZE;
sigstack.ss_flags = 0;
if (sigaltstack(&sigstack, 0) < 0) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Sigaltstack() failed.\n");
#endif
return E_CHKPT_SYS;
}
#if defined(OS_NETBSD)
act.sa_handler = (void (*)(int)) &chkpt_restore;
#endif
#if defined(OS_DIGITAL_UNIX)
act.sa_handler = &chkpt_restore;
#endif
act.sa_flags |= SA_ONSTACK;
/* We use the same mask as above */
if (sigaction(SIGUSR1, &act, (struct sigaction *) NULL) == 0) {
#if defined(EBUG)
debug("chkpt_init(): info: Handler for SIGUSR1 installed.\n");
#endif
} else {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Installation of handler SIGUSR1 failed.\n");
#endif
return E_CHKPT_SYS;
}
/* prepare iov[] for readv() : */
iov[0].iov_base = lchkpt_hdr.data.ptr;
iov[0].iov_len = lchkpt_hdr.data.len;
iov[1].iov_base = lchkpt_hdr.stack.ptr;
iov[1].iov_len = lchkpt_hdr.stack.len;
fd = f_chkpt;
/* Grow the stack to the old size */
stack_base = alloca(0);
#if defined(EBUG)
debug("chkpt_init(): info: Current stack_base = %p\n", stack_base);
#endif
#if defined(OS_DIGITAL_UNIX) && !defined(__gcc2__)
lstack_base = (void *) ((ptrdiff_t) lchkpt_hdr.stack.ptr - lchkpt_hdr.stack.len);
allocate = (ptrdiff_t) stack_base - (ptrdiff_t) lstack_base;
#else
lstack_base = lchkpt_hdr.stack.ptr - lchkpt_hdr.stack.len;
allocate = stack_base - lstack_base;
#endif
if (allocate > 0) {
#if defined(EBUG)
debug("chkpt_init(): info: Allocating %d bytes of stack frame.\n", allocate);
#endif
if (alloca(allocate) == NULL) {
#if defined(IAGNOSTIC)
debug("chkpt_init(): error: Could not alloca() %d bytes of stack frame.\n", allocate);
#endif
(void) syscall(SYS_close, f_chkpt);
return E_CHKPT_NOMEM;
}
}
/* Restore data segment and stack by calling the signal handler chkpt_restore
* on the signal stack */
(void) kill(getpid(), SIGUSR1);
/* We don't return from the kill().
* Not reached, guard against fatal (compiler? OS?) errors */
abort();
}
/* Fortran-C-Interface */
void
#if defined(OS_DIGITAL_UNIX)
chkpt_init_(fcharptr, fstatus, flength)
#endif
#if defined(OS_NETBSD)
chkpt_init__(fcharptr, fstatus, flength)
#endif
/* Fortran programs do: call chkpt_init(filename, status) */
char *fcharptr;
int *fstatus;
int flength;
{
char *buf;
int ii;
buf = (char *) malloc(flength);
if (buf == NULL) {
#if defined(DIAGNOSTIC)
debug("chkpt_init_(): Error: Could not malloc() for buf.\n");
#endif
*fstatus = E_CHKPT_NOMEM;
return;
}
(void) strncpy(buf, fcharptr, flength);
/* Make shure, that the filename in buf is properly terminated */
for (ii = 0; ii <= flength; ii++) {
if (*(buf + ii) == ' ') {
*(buf + ii) = '\0';
break;
}
if (ii == flength) *(buf + ii) = '\0';
}
*fstatus = chkpt_init(buf);
/* do NOT free buf here! */
}
int
chkpt_timer(which, seconds)
int which;
int seconds;
{
struct itimerval itimer;
int iwhich;
if (which != TIMER_REAL && which != TIMER_VIRTUAL) {
#if defined(IAGNOSTIC)
debug("chkpt_timer(): error: No such timer %d\n", which);
#endif
return E_CHKPT_INVAL;
}
if (handler_installed == 0) {
#if defined(IAGNOSTIC)
debug("chkpt_timer(): error: Signal handlers not installed, call chkpt_init() first!\n");
#endif
return E_CHKPT_NOHANDLER;
}
if (seconds <= 0) {
#if defined(IAGNOSTIC)
debug("chkpt_timer(): error: Invalid value for seconds (must be > 0).\n");
#endif
return E_CHKPT_INVAL;
}
itimer.it_interval.tv_sec = itimer.it_value.tv_sec = seconds;
itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
/* Map our timers to the OS timers */
iwhich = -1;
if (which == TIMER_REAL) iwhich = ITIMER_REAL;
else if (which == TIMER_VIRTUAL) iwhich = ITIMER_VIRTUAL;
if (setitimer(iwhich, &itimer, (struct itimerval *) NULL) == 0) {
#if defined(EBUG)
debug("chkpt_timer(): info: Timer %d set to %d s.\n", which, seconds);
#endif
return E_CHKPT_SUCCESS;
} else {
#if defined(IAGNOSTIC)
debug("chkpt_timer(): error: Failed to set timer %d\n", which);
#endif
return E_CHKPT_SYS;
}
/* not reached */
}
/* Fortran-C-Interface */
void
#if defined(OS_DIGITAL_UNIX)
chkpt_timer_(fwhich, fseconds, fstatus)
#endif /* OS_DIGITAL_UNIX */
#if defined(OS_NETBSD)
chkpt_timer__(fwhich, fseconds, fstatus)
#endif /* OS_NETBSD */
int *fwhich;
int *fseconds;
int *fstatus;
{
*fstatus = chkpt_timer(*fwhich, *fseconds);
}
void
chkpt_exit(status)
int status;
{
struct stat sb;
if (stat(chkpt_file, &sb) == 0) {
#if defined(EBUG)
debug("chkpt_exit: info: Checkpoint file detected; unlinking.\n");
#endif
(void) unlink(chkpt_file);
}
/* release lock */
#if defined(OS_NETBSD)
(void) unlink(chkpt_file_lock);
(void) syscall(SYS_close, f_lock);
#endif /* defined(OS_NETBSD) */
#if defined(OS_DIGITAL_ALPHA)
(void) syscall(SYS_flock, f_lock, LOCK_UN);
(void) unlink(chkpt_file_lock);
(void) syscall(SYS_close, f_lock);
#endif /* defined(OS_DIGITAL_ALPHA) */
exit(status);
}
/* Fortran-C-Interface */
void
#if defined(OS_DIGITAL_UNIX)
chkpt_exit_(fstatus)
#endif /* OS_DIGITAL_UNIX */
#if defined(OS_NETBSD)
chkpt_exit__(fstatus)
#endif /* OS_NETBSD */
int *fstatus;
{
chkpt_exit(*fstatus);
}
--pAwQNkOnpTn9IO2O--