interim update for pio
- improved qse_pio_wait but not finished it yet
This commit is contained in:
		| @ -43,6 +43,12 @@ enum qse_pio_open_flag_t | |||||||
| 	QSE_PIO_SHELL      = (1 << 11) | 	QSE_PIO_SHELL      = (1 << 11) | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum qse_pio_wait_flag_t | ||||||
|  | { | ||||||
|  | 	QSE_PIO_NOWAIT     = (1 << 0), | ||||||
|  | 	QSE_PIO_IGNINTR    = (1 << 1) | ||||||
|  | }; | ||||||
|  |  | ||||||
| enum qse_pio_hid_t | enum qse_pio_hid_t | ||||||
| { | { | ||||||
| 	QSE_PIO_IN  = 0, | 	QSE_PIO_IN  = 0, | ||||||
| @ -55,11 +61,14 @@ typedef enum qse_pio_hid_t qse_pio_hid_t; | |||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	/* <winnt.h> => typedef PVOID HANDLE; */ | 	/* <winnt.h> => typedef PVOID HANDLE; */ | ||||||
| 	typedef void* qse_pio_hnd_t; | 	typedef void* qse_pio_hnd_t; | ||||||
| 	typedef int qse_pio_pid_t; /* TODO */ | 	typedef void* qse_pio_pid_t; | ||||||
|  | #	define  QSE_PIO_HND_NIL ((qse_pio_hnd_t)QSE_NULL) | ||||||
|  | #	define  QSE_PIO_PID_NIL ((qse_pio_pid_t)QSE_NULL) | ||||||
| #else | #else | ||||||
| 	typedef int qse_pio_hnd_t; | 	typedef int qse_pio_hnd_t; | ||||||
| 	typedef int qse_pio_pid_t; | 	typedef int qse_pio_pid_t; | ||||||
| #	define  QSE_PIO_HND_NIL ((qse_pio_hnd_t)-1) | #	define  QSE_PIO_HND_NIL ((qse_pio_hnd_t)-1) | ||||||
|  | #	define  QSE_PIO_PID_NIL ((qse_pio_hnd_t)-1) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| typedef struct qse_pio_t qse_pio_t; | typedef struct qse_pio_t qse_pio_t; | ||||||
| @ -73,6 +82,7 @@ struct qse_pio_t | |||||||
|  |  | ||||||
| #define QSE_PIO_MMGR(pio)       ((pio)->mmgr) | #define QSE_PIO_MMGR(pio)       ((pio)->mmgr) | ||||||
| #define QSE_PIO_HANDLE(pio,hid) ((pio)->handle[hid]) | #define QSE_PIO_HANDLE(pio,hid) ((pio)->handle[hid]) | ||||||
|  | #define QSE_PIO_CHILD(pio)      ((pio)->child) | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -80,7 +90,7 @@ extern "C" { | |||||||
|  |  | ||||||
| /****f* qse.cmn.pio/qse_pio_open | /****f* qse.cmn.pio/qse_pio_open | ||||||
|  * NAME |  * NAME | ||||||
|  *  qse_pio_open - open a pipe to a child process |  *  qse_pio_open - open pipes to a child process | ||||||
|  * |  * | ||||||
|  * DESCRIPTION |  * DESCRIPTION | ||||||
|  *  QSE_PIO_SHELL drives the function to execute the command via /bin/sh. |  *  QSE_PIO_SHELL drives the function to execute the command via /bin/sh. | ||||||
| @ -98,7 +108,7 @@ qse_pio_t* qse_pio_open ( | |||||||
|  |  | ||||||
| /****f* qse.cmn.pio/qse_pio_close | /****f* qse.cmn.pio/qse_pio_close | ||||||
|  * NAME |  * NAME | ||||||
|  *  qse_pio_close - close a pipe |  *  qse_pio_close - close pipes to a child process | ||||||
|  * |  * | ||||||
|  * SYNOPSIS |  * SYNOPSIS | ||||||
|  */ |  */ | ||||||
| @ -107,24 +117,27 @@ void qse_pio_close ( | |||||||
| ); | ); | ||||||
| /******/ | /******/ | ||||||
|  |  | ||||||
|  | /****f* qse.cmn/pio/qse_pio_init | ||||||
|  |  * NAME | ||||||
|  |  *  qse_pio_init - initialize pipes to a child process | ||||||
|  |  * | ||||||
|  |  * SYNOPSIS | ||||||
|  |  */ | ||||||
| qse_pio_t* qse_pio_init ( | qse_pio_t* qse_pio_init ( | ||||||
| 	qse_pio_t*        pio, | 	qse_pio_t*        pio, | ||||||
| 	qse_mmgr_t*       mmgr, | 	qse_mmgr_t*       mmgr, | ||||||
| 	const qse_char_t* path, | 	const qse_char_t* path, | ||||||
| 	int               flags | 	int               flags | ||||||
| ); | ); | ||||||
|  | /******/ | ||||||
|  |  | ||||||
| void qse_pio_fini ( | /****f* qse.cmn/pio/qse_pio_fini | ||||||
| 	qse_pio_t* pio |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /****f* qse.cmn.pio/qse_pio_wait |  | ||||||
|  * NAME |  * NAME | ||||||
|  *  qse_pio_wait - wait for a child process  |  *  qse_pio_fini - finalize pipes to a child process | ||||||
|  * |  * | ||||||
|  * SYNOPSIS |  * SYNOPSIS | ||||||
|  */ |  */ | ||||||
| int qse_pio_wait ( | void qse_pio_fini ( | ||||||
| 	qse_pio_t* pio | 	qse_pio_t* pio | ||||||
| ); | ); | ||||||
| /******/ | /******/ | ||||||
| @ -141,6 +154,17 @@ qse_pio_hnd_t qse_pio_gethandle ( | |||||||
| ); | ); | ||||||
| /******/ | /******/ | ||||||
|  |  | ||||||
|  | /****f* qse.cmn.pio/qse_pio_getchild | ||||||
|  |  * NAME | ||||||
|  |  *  qse_pio_getchild - get the PID of a child process | ||||||
|  |  * | ||||||
|  |  * SYNOPSIS | ||||||
|  |  */ | ||||||
|  | qse_pio_pid_t qse_pio_getchild ( | ||||||
|  | 	qse_pio_t*    pio | ||||||
|  | ); | ||||||
|  | /******/ | ||||||
|  |  | ||||||
| /****f* qse.cmn.pio/qse_pio_read | /****f* qse.cmn.pio/qse_pio_read | ||||||
|  * NAME |  * NAME | ||||||
|  *  qse_pio_read - read data |  *  qse_pio_read - read data | ||||||
| @ -185,6 +209,18 @@ void qse_pio_end ( | |||||||
| ); | ); | ||||||
| /******/ | /******/ | ||||||
|  |  | ||||||
|  | /****f* qse.cmn.pio/qse_pio_wait | ||||||
|  |  * NAME | ||||||
|  |  *  qse_pio_wait - wait for a child process  | ||||||
|  |  * | ||||||
|  |  * SYNOPSIS | ||||||
|  |  */ | ||||||
|  | int qse_pio_wait ( | ||||||
|  | 	qse_pio_t* pio, | ||||||
|  | 	int        flags | ||||||
|  | ); | ||||||
|  | /******/ | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -27,8 +27,11 @@ | |||||||
| #	include "syscall.h" | #	include "syscall.h" | ||||||
| #	include <fcntl.h> | #	include <fcntl.h> | ||||||
| #	include <errno.h> | #	include <errno.h> | ||||||
|  | #	include <sys/wait.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #define CHILD_EXIT_CODE 128 | ||||||
|  |  | ||||||
| qse_pio_t* qse_pio_open ( | qse_pio_t* qse_pio_open ( | ||||||
| 	qse_mmgr_t* mmgr, qse_size_t ext, | 	qse_mmgr_t* mmgr, qse_size_t ext, | ||||||
| 	const qse_char_t* path, int flags) | 	const qse_char_t* path, int flags) | ||||||
| @ -86,7 +89,9 @@ qse_pio_t* qse_pio_init ( | |||||||
|  |  | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	/* TODO: XXXXXXXXXXXXXXXXX */ | 	/* TODO: XXXXXXXXXXXXXXXXX */ | ||||||
|  | http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx | ||||||
| #else | #else | ||||||
|  |  | ||||||
| 	if (flags & QSE_PIO_WRITEIN) | 	if (flags & QSE_PIO_WRITEIN) | ||||||
| 	{ | 	{ | ||||||
| 		if (QSE_PIPE(&handle[0]) == -1) goto oops; | 		if (QSE_PIPE(&handle[0]) == -1) goto oops; | ||||||
| @ -298,7 +303,7 @@ qse_pio_t* qse_pio_init ( | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	child_oops: | 	child_oops: | ||||||
| 		QSE_EXIT(127); | 		QSE_EXIT (CHILD_EXIT_CODE); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* parent */ | 	/* parent */ | ||||||
| @ -352,44 +357,10 @@ oops: | |||||||
|  |  | ||||||
| void qse_pio_fini (qse_pio_t* pio) | void qse_pio_fini (qse_pio_t* pio) | ||||||
| { | { | ||||||
| #ifdef _WIN32 |  | ||||||
| 	CloseHandle (pio->handle); |  | ||||||
| #else |  | ||||||
| 	int i, status; |  | ||||||
|  |  | ||||||
| 	qse_pio_end (pio, QSE_PIO_IN); | 	qse_pio_end (pio, QSE_PIO_IN); | ||||||
| 	qse_pio_end (pio, QSE_PIO_OUT); | 	qse_pio_end (pio, QSE_PIO_OUT); | ||||||
| 	qse_pio_end (pio, QSE_PIO_ERR); | 	qse_pio_end (pio, QSE_PIO_ERR); | ||||||
|  | 	qse_pio_wait (pio, QSE_PIO_IGNINTR); | ||||||
| 	while (QSE_WAITPID (pio->child, &status, 0) == -1) |  | ||||||
| 	{ |  | ||||||
| 		if (errno != EINTR) break; |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int qse_pio_wait (qse_pio_t* pio) |  | ||||||
| { |  | ||||||
| 	int status; |  | ||||||
|  |  | ||||||
| #if 0 |  | ||||||
| 	if (opt & QSE_PIO_NOWAIT) |  | ||||||
| 	{ |  | ||||||
| 		opt |= WNOHANG; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	while (1) |  | ||||||
| 	{ |  | ||||||
| 		n = QSE_WAITPID (pio->child, &status, opt); |  | ||||||
| 		if (n == 0) break;  |  | ||||||
| 	/* TODO: .... */ |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	output => return code... |  | ||||||
| 	output => termination cause... |  | ||||||
| #endif |  | ||||||
| 	return -1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| qse_pio_hnd_t qse_pio_gethandle (qse_pio_t* pio, qse_pio_hid_t hid) | qse_pio_hnd_t qse_pio_gethandle (qse_pio_t* pio, qse_pio_hid_t hid) | ||||||
| @ -397,6 +368,11 @@ qse_pio_hnd_t qse_pio_gethandle (qse_pio_t* pio, qse_pio_hid_t hid) | |||||||
| 	return pio->handle[hid]; | 	return pio->handle[hid]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | qse_pio_pid_t qse_pio_getchild (qse_pio_t* pio) | ||||||
|  | { | ||||||
|  | 	return pio->child; | ||||||
|  | } | ||||||
|  |  | ||||||
| qse_ssize_t qse_pio_read ( | qse_ssize_t qse_pio_read ( | ||||||
| 	qse_pio_t* pio, void* buf, qse_size_t size, qse_pio_hid_t hid) | 	qse_pio_t* pio, void* buf, qse_size_t size, qse_pio_hid_t hid) | ||||||
| { | { | ||||||
| @ -445,3 +421,87 @@ void qse_pio_end (qse_pio_t* pio, qse_pio_hid_t hid) | |||||||
| 		pio->handle[hid] = QSE_PIO_HND_NIL; | 		pio->handle[hid] = QSE_PIO_HND_NIL; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  | 	WaitForSingleObject (pio->child, -1); | ||||||
|  | 	if (GetExitCodeProcess (pio->child, &ec) == -1) | ||||||
|  | 	/* close handle here to emulate waitpid() as much as possible. */ | ||||||
|  | 	CloseHandle (pio->child);  | ||||||
|  | 	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 (flags & QSE_PIO_NOWAIT) opt |= WNOHANG; | ||||||
|  |  | ||||||
|  | 	while (1) | ||||||
|  | 	{ | ||||||
|  | 		int n = QSE_WAITPID (pio->child, &status, opt); | ||||||
|  |  | ||||||
|  | qse_printf (QSE_T("n=%d,pio->child=%d,errno=%d,ECHILD=%d\n"), n, pio->child, errno, ECHILD); | ||||||
|  | 		if (n == -1) | ||||||
|  | 		{ | ||||||
|  | 			if (errno == ECHILD) | ||||||
|  | 			{ | ||||||
|  | 				/* 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; | ||||||
|  | 				ret = -1; /* OR ECHILD / QSE_PIO_ECHILD */ | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (errno != EINTR || !(flags & QSE_PIO_IGNINTR)) break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (n == 0)  | ||||||
|  | 		{ | ||||||
|  | 			/* when WNOHANG is not specified, 0 can't be returned */ | ||||||
|  | 			QSE_ASSERT (flags & QSE_PIO_NOWAIT); | ||||||
|  |  | ||||||
|  | 			ret = -2; | ||||||
|  | 			/* the child process is still alive */ | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (n == pio->child) | ||||||
|  | 		{ | ||||||
|  | 			if (WIFEXITED(status)) | ||||||
|  | 			{ | ||||||
|  | 				/* the child process ended normally */ | ||||||
|  | 				ret = WEXITSTATUS(status); | ||||||
|  | 			} | ||||||
|  | 			else if (WIFSIGNALED(status)) | ||||||
|  | 			{ | ||||||
|  | 				/* the child process was killed by a signal */ | ||||||
|  | 				ret = 255 + WTERMSIG (status); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			/* not interested in WIFSTOPPED & WIFCONTINUED  */ | ||||||
|  |  | ||||||
|  | 			pio->child = QSE_PIO_PID_NIL; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ret; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | |||||||
| @ -53,6 +53,7 @@ static int pio1 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static int test1 (void) | static int test1 (void) | ||||||
| { | { | ||||||
| 	return pio1 (QSE_T("ls -laF"), QSE_PIO_READOUT|QSE_PIO_WRITEIN|QSE_PIO_SHELL, QSE_PIO_OUT); | 	return pio1 (QSE_T("ls -laF"), QSE_PIO_READOUT|QSE_PIO_WRITEIN|QSE_PIO_SHELL, QSE_PIO_OUT); | ||||||
| @ -65,8 +66,32 @@ static int test2 (void) | |||||||
|  |  | ||||||
| static int test3 (void) | static int test3 (void) | ||||||
| { | { | ||||||
| 	//return pio1 (QSE_T("/bin/ls -laF"), QSE_PIO_READERR|QSE_PIO_OUTTOERR|QSE_PIO_WRITEIN, QSE_PIO_ERR); | 	return pio1 (QSE_T("/bin/ls -laF"), QSE_PIO_READERR|QSE_PIO_OUTTOERR|QSE_PIO_WRITEIN, QSE_PIO_ERR); | ||||||
| 	return pio1 (QSE_T("\"/bin/ls\" -laF"), QSE_PIO_READERR|QSE_PIO_OUTTOERR|QSE_PIO_WRITEIN, QSE_PIO_ERR); | } | ||||||
|  |  | ||||||
|  | static int test4 (void) | ||||||
|  | { | ||||||
|  | 	qse_pio_t* pio; | ||||||
|  |  | ||||||
|  | 	pio = qse_pio_open ( | ||||||
|  | 		QSE_NULL, | ||||||
|  | 		0, | ||||||
|  | 		"ls -laF", | ||||||
|  | 		QSE_PIO_READOUT|QSE_PIO_READERR|QSE_PIO_WRITEIN | ||||||
|  | 	); | ||||||
|  | 	if (pio == QSE_NULL) | ||||||
|  | 	{ | ||||||
|  | 		qse_printf (QSE_T("cannot open program through pipe\n")); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	{ | ||||||
|  | 		int status; | ||||||
|  | 		sleep (5); | ||||||
|  | 		qse_printf (QSE_T("waitpid...%d\n"),  (int)waitpid (-1, &status, 0)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	qse_pio_close (pio); | ||||||
| } | } | ||||||
|  |  | ||||||
| int main () | int main () | ||||||
| @ -80,6 +105,7 @@ int main () | |||||||
| 	R (test1); | 	R (test1); | ||||||
| 	R (test2); | 	R (test2); | ||||||
| 	R (test3); | 	R (test3); | ||||||
|  | 	R (test4); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user