diff --git a/qse/README b/qse/README index b01247d6..9031afcd 100644 --- a/qse/README +++ b/qse/README @@ -1,5 +1,5 @@ -QSE is a script engine library designed to be embedded into an application. +QSE provides a script engine for various scripting languages. It aims to produce a script engine framework that can be embedded into an application. A hosting application can access various aspects of the embedded script engine and vice versa. [INSTALL] diff --git a/qse/include/qse/cmn/pio.h b/qse/include/qse/cmn/pio.h index 4ec34722..97dab303 100644 --- a/qse/include/qse/cmn/pio.h +++ b/qse/include/qse/cmn/pio.h @@ -63,7 +63,10 @@ enum qse_pio_err_t { QSE_PIO_ENOERR = 0, QSE_PIO_ENOMEM, /* out of memory */ - QSE_PIO_ECHILD /* the child is not valid */ + QSE_PIO_ENOHND, /* no handle available */ + QSE_PIO_ECHILD, /* the child is not valid */ + QSE_PIO_EINTR, /* interrupted */ + QSE_PIO_ESYSCALL /* system call error */ }; typedef enum qse_pio_hid_t qse_pio_hid_t; @@ -269,6 +272,18 @@ void qse_pio_end ( * NAME * qse_pio_wait - wait for a child process * + * DESCRIPTION + * QSE_PIO_IGNINTR causes the function to retry when the underlying system + * call is interrupted. + * When you specify QSE_PIO_NOHANG, the return value of 256 indicates that the + * child process has not terminated. If the flag is not specified, 256 will + * never be returned. + * + * RETURN + * -1 on error, 256 if the child is still alive and QSE_PIO_NOHANG is specified, + * a number between 0 and 255 inclusive if the child process terminates normally, + * 256 + signal number if the child process is terminated by a signal. + * * SYNOPSIS */ int qse_pio_wait ( @@ -277,6 +292,22 @@ int qse_pio_wait ( ); /******/ +/****f* qse.cmn.pio/qse_pio_kill + * NAME + * qse_pio_kill - terminate the child process + * + * NOTES + * You should know the danger of calling this function as the function can + * kill a process that is not your child process if it has terminated but + * there is a new process with the same process handle. + * + * SYNOPSIS + */ +int qse_pio_kill ( + qse_pio_t* pio +); +/******/ + #ifdef __cplusplus } #endif diff --git a/qse/lib/cmn/fio.c b/qse/lib/cmn/fio.c index 2b6d6be9..8d4fdac5 100644 --- a/qse/lib/cmn/fio.c +++ b/qse/lib/cmn/fio.c @@ -275,7 +275,7 @@ qse_fio_off_t qse_fio_seek ( return (qse_fio_off_t)tmp; -#elif defined(HAVE_LSEEK64) +#elif defined(QSE_LSEEK64) return QSE_LSEEK64 (fio->handle, offset, seek_map[origin]); #else return QSE_LSEEK (fio->handle, offset, seek_map[origin]); diff --git a/qse/lib/cmn/pio.c b/qse/lib/cmn/pio.c index 829f51fe..f0711efe 100644 --- a/qse/lib/cmn/pio.c +++ b/qse/lib/cmn/pio.c @@ -378,18 +378,31 @@ qse_ssize_t qse_pio_read ( { #ifdef _WIN32 DWORD count; +#else + qse_ssize_t n; +#endif + + if (pio->handle[hid] == QSE_PIO_HND_NIL) + { + /* the stream is already closed */ + pio->errnum = QSE_PIO_ENOHND; + return (qse_ssize_t)-1; + } + +#ifdef _WIN32 if (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); if (ReadFile(pio->handle, buf, size, &count, QSE_NULL) == FALSE) return -1; return (qse_ssize_t)count; #else - if (pio->handle[hid] == QSE_PIO_HND_NIL) - { - /* the stream is already closed */ - return (qse_ssize_t)-1; - } if (size > QSE_TYPE_MAX(size_t)) size = QSE_TYPE_MAX(size_t); - return QSE_READ (pio->handle[hid], buf, size); + n = QSE_READ (pio->handle[hid], buf, size); + if (n == -1) + { + pio->errnum = (errno == EINTR)? + QSE_PIO_EINTR: QSE_PIO_ESYSCALL; + } + return n; #endif } @@ -398,6 +411,18 @@ qse_ssize_t qse_pio_write ( { #ifdef _WIN32 DWORD count; +#else + qse_ssize_t n; +#endif + + if (pio->handle[hid] == QSE_PIO_HND_NIL) + { + /* the stream is already closed */ + pio->errnum = QSE_PIO_ENOHND; + return (qse_ssize_t)-1; + } + +#ifdef _WIN32 if (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); if (WriteFile(pio->handle, data, size, &count, QSE_NULL) == FALSE) return -1; return (qse_ssize_t)count; @@ -409,7 +434,13 @@ qse_ssize_t qse_pio_write ( } if (size > QSE_TYPE_MAX(size_t)) size = QSE_TYPE_MAX(size_t); - return QSE_WRITE (pio->handle[hid], data, size); + n = QSE_WRITE (pio->handle[hid], data, size); + if (n == -1) + { + pio->errnum = (errno == EINTR)? + QSE_PIO_EINTR: QSE_PIO_ESYSCALL; + } + return n; #endif } @@ -422,19 +453,17 @@ void qse_pio_end (qse_pio_t* pio, qse_pio_hid_t hid) } } -/* -return -1 on error -return -2 on no change -return retcode on normal exit -return 255+signal on kill. -*/ - int qse_pio_wait (qse_pio_t* pio, int flags) { #ifdef _WIN32 DWORD ec; - if (pio->child == QSE_PIO_PID_NIL) return -1; + if (pio->child == QSE_PIO_PID_NIL) + { + + pio->errnum = QSE_PIO_ECHILD; + return -1; + } WaitForSingleObject (pio->child, -1); if (GetExitCodeProcess (pio->child, &ec) == -1) @@ -443,17 +472,22 @@ int qse_pio_wait (qse_pio_t* pio, int flags) pio->child = QSE_PIO_PID_NIL; #else - int status; int opt = 0; int ret = -1; - if (pio->child == QSE_PIO_PID_NIL) return -1; + if (pio->child == QSE_PIO_PID_NIL) + { + pio->errnum = QSE_PIO_ECHILD; + return -1; + } if (flags & QSE_PIO_NOHANG) opt |= WNOHANG; while (1) { - int n = QSE_WAITPID (pio->child, &status, opt); + int status, n; + + n = QSE_WAITPID (pio->child, &status, opt); if (n == -1) { @@ -461,17 +495,17 @@ int qse_pio_wait (qse_pio_t* pio, int flags) { /* most likely, the process has already been * waitpid()ed on. */ - - /* TODO: what should we do... ? */ - /* ??? TREAT AS NORMAL??? => cannot know exit code => TREAT AS ERROR but reset pio->child */ - pio->child = QSE_PIO_PID_NIL; pio->errnum = QSE_PIO_ECHILD; - ret = -1; - break; } + else if (errno == EINTR) + { + if (flags & QSE_PIO_IGNINTR) continue; + pio->errnum = QSE_PIO_EINTR; + } + else pio->errnum = QSE_PIO_ESYSCALL; - if (errno != EINTR || !(flags & QSE_PIO_IGNINTR)) break; + break; } if (n == 0) @@ -479,7 +513,7 @@ int qse_pio_wait (qse_pio_t* pio, int flags) /* when WNOHANG is not specified, 0 can't be returned */ QSE_ASSERT (flags & QSE_PIO_NOHANG); - ret = -2; + ret = 255 + 1; /* the child process is still alive */ break; } @@ -494,10 +528,16 @@ int qse_pio_wait (qse_pio_t* pio, int flags) else if (WIFSIGNALED(status)) { /* the child process was killed by a signal */ - ret = 255 + WTERMSIG (status); + ret = 255 + 1 + WTERMSIG (status); + } + else + { + /* not interested in WIFSTOPPED & WIFCONTINUED. + * in fact, this else block should not be reached + * as WIFEXITED or WIFSIGNALED must be true. + * anyhow, just set the return value to 0. */ + ret = 0; } - - /* not interested in WIFSTOPPED & WIFCONTINUED */ pio->child = QSE_PIO_PID_NIL; break; @@ -507,3 +547,33 @@ int qse_pio_wait (qse_pio_t* pio, int flags) return ret; #endif } + +int qse_pio_kill (qse_pio_t* pio) +{ +#ifdef _WIN32 + DWORD n; +#else + int n; +#endif + + if (pio->child == QSE_PIO_PID_NIL) + { + pio->errnum = QSE_PIO_ECHILD; + return -1; + } + +#ifdef _WIN32 + /* 9 was chosen below to treat TerminateProcess as kill -KILL. */ + n = TerminateProcess (pio->child, 255 + 1 + 9); + if (n == FALSE) + { + pio->errnum = QSE_PIO_SYSCALL; + return -1; + } + return 0; +#else + n = QSE_KILL (pio->child, SIGKILL); + if (n == -1) pio->errnum = QSE_PIO_ESYSCALL; + return n; +#endif +} diff --git a/qse/lib/cmn/syscall.h b/qse/lib/cmn/syscall.h index 16ceb166..81cd6f52 100644 --- a/qse/lib/cmn/syscall.h +++ b/qse/lib/cmn/syscall.h @@ -12,6 +12,9 @@ #ifdef HAVE_SYS_WAIT_H #include #endif +#ifdef HAVE_SIGNAL_H +#include +#endif #if defined(QSE_USE_SYSCALL) && defined(HAVE_SYS_SYSCALL_H) #include @@ -117,6 +120,12 @@ #define QSE_WAITPID(pid,status,options) waitpid(pid,status,options) #endif +#ifdef SYS_kill + #define QSE_KILL(pid,sig) syscall(SYS_kill,pid,sig) +#else + #define QSE_KILL(pid,sig) kill(pid,sig) +#endif + #ifdef SYS_getpid #define QSE_GETPID() syscall(SYS_getpid) #else