elk/lib/unix/wait.c

177 lines
4.9 KiB
C

/* wait.c
*
* $Id$
*
* Copyright 1990, 1991, 1992, 1993, 1994, 1995, Oliver Laumann, Berlin
* Copyright 2002, 2003 Sam Hocevar <sam@hocevar.net>, Paris
*
* This software was derived from Elk 1.2, which was Copyright 1987, 1988,
* 1989, Nixdorf Computer AG and TELES GmbH, Berlin (Elk 1.2 has been written
* by Oliver Laumann for TELES Telematic Services, Berlin, in a joint project
* between TELES and Nixdorf Microprocessor Engineering, Berlin).
*
* Oliver Laumann, TELES GmbH, Nixdorf Computer AG and Sam Hocevar, as co-
* owners or individual owners of copyright in this software, grant to any
* person or company a worldwide, royalty free, license to
*
* i) copy this software,
* ii) prepare derivative works based on this software,
* iii) distribute copies of this software or derivative works,
* iv) perform this software, or
* v) display this software,
*
* provided that this notice is not removed and that neither Oliver Laumann
* nor Teles nor Nixdorf are deemed to have made any representations as to
* the suitability of this software for any purpose nor are held responsible
* for any defects of this software.
*
* THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#ifdef __MACH__
# define _POSIX_SOURCE
#endif
#include "unix.h"
#include <string.h>
#if defined(HAVE_WAITPID) || defined(HAVE_WAIT4)
# define WAIT_PROCESS
#endif
#if defined(HAVE_WAITPID) || defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
# define WAIT_OPTIONS
#endif
#if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
# define WAIT_RUSAGE
# include <sys/time.h>
# include <sys/resource.h>
#endif
#ifdef WAIT_OPTIONS
static SYMDESCR Wait_Flags[] = {
{ "nohang", WNOHANG },
{ "untraced", WUNTRACED },
{ 0, 0 }
};
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(stat) ((int)((stat >> 8) & 0xFF))
#endif
#ifndef WTERMSIG
# define WTERMSIG(stat) ((int)(stat & 0x7F))
#endif
#ifndef WSTOPSIG
# define WSTOPSIG(stat) ((int)((stat >> 8) & 0xFF))
#endif
#ifndef WIFSIGNALED
# define WIFSIGNALED(stat) ((int)(stat & 0x7F))
#endif
#ifndef WIFSTOPPED
# define WIFSTOPPED(stat) ((int)(stat & 0x7F) == 0x7F)
#endif
static Object General_Wait(Object ret, Object ruret,
int haspid, int pid, int options) {
#ifndef WIN32
int retpid, st, code;
char *status;
#ifdef WAIT_RUSAGE
struct rusage ru;
Object sec;
#endif
Object x;
GC_Node3;
x = Null;
Check_Result_Vector(ret, 5);
Check_Result_Vector(ruret, 2);
if (haspid) {
#ifdef HAVE_WAIT4
retpid = wait4(pid, &st, options, &ru);
#else
#ifdef HAVE_WAITPID
retpid = waitpid(pid, &st, options);
#endif
#endif
} else {
#ifdef HAVE_WAIT3
retpid = wait3(&st, options, &ru);
#else
retpid = wait(&st);
#endif
}
if (retpid == -1 && errno != ECHILD)
Raise_System_Error("~E");
GC_Link3(ret, ruret, x);
x = Make_Integer(retpid); VECTOR(ret)->data[0] = x;
if (retpid == 0 || retpid == -1) {
status = "none";
st = code = 0;
#ifdef WAIT_RUSAGE
memset((char *)&ru, 0, sizeof(ru));
#endif
} else if (WIFSTOPPED(st)) {
status = "stopped"; code = WSTOPSIG(st);
} else if (WIFSIGNALED(st)) {
status = "signaled"; code = WTERMSIG(st);
} else {
status = "exited"; code = WEXITSTATUS(st);
}
x = Intern(status); VECTOR(ret)->data[1] = x;
x = Make_Integer(code); VECTOR(ret)->data[2] = x;
VECTOR(ret)->data[3] = st & 0200 ? True : False;
#ifdef WAIT_RUSAGE
x = Cons(Null, Make_Unsigned_Long((unsigned long)ru.ru_utime.tv_usec
* 1000));
sec = Make_Unsigned_Long((unsigned long)ru.ru_utime.tv_sec);
Car(x) = sec;
VECTOR(ruret)->data[0] = x;
x = Cons(Null, Make_Unsigned_Long((unsigned long)ru.ru_stime.tv_usec
* 1000));
sec = Make_Unsigned_Long((unsigned long)ru.ru_stime.tv_sec);
Car(x) = sec;
VECTOR(ruret)->data[1] = x;
#endif
GC_Unlink;
#endif
return Void;
}
static Object P_Wait(int argc, Object *argv) {
int flags = 0;
if (argc == 3)
#ifdef WAIT_OPTIONS
flags = (int)Symbols_To_Bits(argv[2], 1, Wait_Flags);
#else
Primitive_Error("wait options not supported");
#endif
return General_Wait(argv[0], argv[1], 0, 0, flags);
}
#ifdef WAIT_PROCESS
/* If WAIT_PROCESS is supported, then WAIT_OPTIONS is supported as well,
* because both waitpid() and wait4() accept options.
*/
static Object P_Wait_Process(int argc, Object *argv) {
return General_Wait(argv[0], argv[1], 1, Get_Integer(argv[2]),
argc == 4 ? (int)Symbols_To_Bits(argv[3], 1, Wait_Flags) : 0);
}
#endif
void elk_init_unix_wait() {
Def_Prim(P_Wait, "unix-wait-vector-fill!", 2, 3, VARARGS);
#ifdef WAIT_PROCESS
Def_Prim(P_Wait_Process, "unix-wait-process-vector-fill!", 3, 4, VARARGS);
P_Provide(Intern("unix:wait-process"));
#endif
#ifdef WAIT_OPTIONS
P_Provide(Intern("unix:wait-options"));
#endif
}