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] | [INSTALL] | ||||||
|  |  | ||||||
|  | |||||||
| @ -63,7 +63,10 @@ enum qse_pio_err_t | |||||||
| { | { | ||||||
| 	QSE_PIO_ENOERR = 0, | 	QSE_PIO_ENOERR = 0, | ||||||
| 	QSE_PIO_ENOMEM,     /* out of memory */ | 	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; | typedef enum qse_pio_hid_t qse_pio_hid_t; | ||||||
| @ -269,6 +272,18 @@ void qse_pio_end ( | |||||||
|  * NAME |  * NAME | ||||||
|  *  qse_pio_wait - wait for a child process  |  *  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 |  * SYNOPSIS | ||||||
|  */ |  */ | ||||||
| int qse_pio_wait ( | 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -275,7 +275,7 @@ qse_fio_off_t qse_fio_seek ( | |||||||
|  |  | ||||||
| 	return (qse_fio_off_t)tmp; | 	return (qse_fio_off_t)tmp; | ||||||
|  |  | ||||||
| #elif defined(HAVE_LSEEK64) | #elif defined(QSE_LSEEK64) | ||||||
| 	return QSE_LSEEK64 (fio->handle, offset, seek_map[origin]); | 	return QSE_LSEEK64 (fio->handle, offset, seek_map[origin]); | ||||||
| #else | #else | ||||||
| 	return QSE_LSEEK (fio->handle, offset, seek_map[origin]); | 	return QSE_LSEEK (fio->handle, offset, seek_map[origin]); | ||||||
|  | |||||||
| @ -378,18 +378,31 @@ qse_ssize_t qse_pio_read ( | |||||||
| { | { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	DWORD count; | 	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 (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); | ||||||
| 	if (ReadFile(pio->handle, buf, size, &count, QSE_NULL) == FALSE) return -1; | 	if (ReadFile(pio->handle, buf, size, &count, QSE_NULL) == FALSE) return -1; | ||||||
| 	return (qse_ssize_t)count; | 	return (qse_ssize_t)count; | ||||||
| #else | #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); | 	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 | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -398,6 +411,18 @@ qse_ssize_t qse_pio_write ( | |||||||
| { | { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	DWORD count; | 	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 (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); | ||||||
| 	if (WriteFile(pio->handle, data, size, &count, QSE_NULL) == FALSE) return -1; | 	if (WriteFile(pio->handle, data, size, &count, QSE_NULL) == FALSE) return -1; | ||||||
| 	return (qse_ssize_t)count; | 	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); | 	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 | #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) | int qse_pio_wait (qse_pio_t* pio, int flags) | ||||||
| { | { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	DWORD ec; | 	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); | 	WaitForSingleObject (pio->child, -1); | ||||||
| 	if (GetExitCodeProcess (pio->child, &ec) == -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; | 	pio->child = QSE_PIO_PID_NIL; | ||||||
|  |  | ||||||
| #else | #else | ||||||
| 	int status; |  | ||||||
| 	int opt = 0; | 	int opt = 0; | ||||||
| 	int ret = -1; | 	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; | 	if (flags & QSE_PIO_NOHANG) opt |= WNOHANG; | ||||||
|  |  | ||||||
| 	while (1) | 	while (1) | ||||||
| 	{ | 	{ | ||||||
| 		int n = QSE_WAITPID (pio->child, &status, opt); | 		int status, n; | ||||||
|  |  | ||||||
|  | 		n = QSE_WAITPID (pio->child, &status, opt); | ||||||
|  |  | ||||||
| 		if (n == -1) | 		if (n == -1) | ||||||
| 		{ | 		{ | ||||||
| @ -461,17 +495,17 @@ int qse_pio_wait (qse_pio_t* pio, int flags) | |||||||
| 			{ | 			{ | ||||||
| 				/* most likely, the process has already been  | 				/* most likely, the process has already been  | ||||||
| 				 * waitpid()ed on. */ | 				 * 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->child = QSE_PIO_PID_NIL; | ||||||
| 				pio->errnum = QSE_PIO_ECHILD; | 				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)  | 		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 */ | 			/* when WNOHANG is not specified, 0 can't be returned */ | ||||||
| 			QSE_ASSERT (flags & QSE_PIO_NOHANG); | 			QSE_ASSERT (flags & QSE_PIO_NOHANG); | ||||||
|  |  | ||||||
| 			ret = -2; | 			ret = 255 + 1; | ||||||
| 			/* the child process is still alive */ | 			/* the child process is still alive */ | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| @ -494,10 +528,16 @@ int qse_pio_wait (qse_pio_t* pio, int flags) | |||||||
| 			else if (WIFSIGNALED(status)) | 			else if (WIFSIGNALED(status)) | ||||||
| 			{ | 			{ | ||||||
| 				/* the child process was killed by a signal */ | 				/* 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; | 			pio->child = QSE_PIO_PID_NIL; | ||||||
| 			break; | 			break; | ||||||
| @ -507,3 +547,33 @@ int qse_pio_wait (qse_pio_t* pio, int flags) | |||||||
| 	return ret; | 	return ret; | ||||||
| #endif | #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 | #ifdef HAVE_SYS_WAIT_H | ||||||
| #include <sys/wait.h> | #include <sys/wait.h> | ||||||
| #endif | #endif | ||||||
|  | #ifdef HAVE_SIGNAL_H | ||||||
|  | #include <signal.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if defined(QSE_USE_SYSCALL) && defined(HAVE_SYS_SYSCALL_H) | #if defined(QSE_USE_SYSCALL) && defined(HAVE_SYS_SYSCALL_H) | ||||||
| #include <sys/syscall.h> | #include <sys/syscall.h> | ||||||
| @ -117,6 +120,12 @@ | |||||||
| 	#define QSE_WAITPID(pid,status,options) waitpid(pid,status,options) | 	#define QSE_WAITPID(pid,status,options) waitpid(pid,status,options) | ||||||
| #endif | #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 | #ifdef SYS_getpid | ||||||
| 	#define QSE_GETPID() syscall(SYS_getpid) | 	#define QSE_GETPID() syscall(SYS_getpid) | ||||||
| #else | #else | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user