interim commit for qse_pio_t
- added QSE_KILL() - added qse_pio_kill() - enhanced qse_pio_wait()
This commit is contained in:
		@ -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]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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]);
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,9 @@
 | 
			
		||||
#ifdef HAVE_SYS_WAIT_H
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef HAVE_SIGNAL_H
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(QSE_USE_SYSCALL) && defined(HAVE_SYS_SYSCALL_H)
 | 
			
		||||
#include <sys/syscall.h>
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user