changeset 940:dddc404783c9

added basic Windows support to crashRun.c NOTE: crashRun.c takes now the arguments "<timeOut> <maxMemory> <command> [command args]" instead of "<command> [command args]"
author thomask
date Sat, 01 Apr 2006 20:22:12 +0000
parents 38e8bc3a9a50
children 60f9aece9c62
files crashRun.c dstress.c
diffstat 2 files changed, 137 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/crashRun.c	Sat Apr 01 20:22:02 2006 +0000
+++ b/crashRun.c	Sat Apr 01 20:22:12 2006 +0000
@@ -2,8 +2,9 @@
  * crashRun - execute command with restricted CPU time and memory usage
  *
  * Copyright (C)
- *		2005 Thomas Kuehne <thomas@kuehne.cn>
- *		2005 Anders F Björrklund <afb@algonet.se>
+ *		2005, 2006 Thomas Kuehne <thomas@kuehne.cn>
+ *		2005 Anders F Björrklund <afb@algonet.se> (BSD)
+ *		2005 Stewart Gordon <smjg_1998@yahoo.com> (Windows)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,25 +32,39 @@
 #include <stdio.h>
 #include <signal.h>
 
-const int TIME_OUT= 30; /* time-out in seconds (might be cpu or system time)*/
-const int MEM_LIMIT = 1024;  /* mem megabytes */
+#undef WAIT_GUARD
+#define WAIT_GUARD 3
+
+/* time-out in seconds
+ * Posix: cpu time(timeOut) and system time(timeOut * WAIT_GUARD)
+ * Windows: system time(timeOut)
+ */
+long int timeOut;
+
+/* max memory usage in megabytes (Posix only) */
+long int memoryLimit;
 
 /* identify system API */
-#if defined(__GNU_LIBRARY__) || defined(__GLIBC__) || defined(__USE_POSIX)
-#define USE_POSIX
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
+#define USE_POSIX 1
+#endif
+
+#if defined(__GNU_LIBRARY__) || defined(__GLIBC__)
+#define USE_POSIX 1
 #endif
 
 #if defined(linux) || defined(__FreeBsd__) || defined(__OpenBSD__)
-#define USE_POSIX
+#define USE_POSIX 1
 #endif
 
 #if defined(__APPLE__) && defined(__MACH__)
-#define USE_POSIX
+#define USE_POSIX 1
 #endif
 
 #if !defined(USE_POSIX) && \
-	(defined(WINDOWS) || defined(WIN) || defined(WINVER) || defined(WIN32))
-#define USE_WINDOWS
+	(defined(WINDOWS) || defined(WIN) || defined(WINVER) || defined(WIN32) \
+	|| defined(WIN64))
+#define USE_WINDOWS 1
 #endif
 
 
@@ -80,82 +95,73 @@
 #include <sys/types.h>
 #endif
 
+#ifdef USE_WINDOWS
+#include <windows.h>
+#define snprintf _snprintf
+#endif
 
-char* cmd;
+
 
-/* let's start implementing :) */
+#ifdef USE_POSIX
 
 void handleSignal(int signalID){
-#ifdef SIGALARM
 	if( signalID==SIGALRM
 #ifdef SIGXCPU
 		|| signalID==SIGXCPU
 #endif
 	)
-		printf("EXIT CODE: signal %d (time-out after %d seconds)", signalID, TIME_OUT);
+		printf("EXIT CODE: signal %d (time-out after CPU/total %li/%li seconds)\n",
+				signalID, timeOut, timeOut * WAIT_GUARD);
 	else
-#endif
-	printf("EXIT CODE: signal %d, errno %d\n", signalID, errno);
+		printf("EXIT CODE: signal %d, errno %d\n", signalID, errno);
 
 	fflush(stdout);
 	fflush(stderr);
 
-#ifdef USE_POSIX
 	kill(-pID, SIGTERM);
 	sleep(1);
 	kill(-pID, SIGKILL);
-#else
-#error sub processes have to be killed
-#endif
 
-#ifdef SIGUSR1
-	if(signalID==SIGUSR1 || signalID==SIGUSR2)
-		exit(EXIT_SUCCESS);
-	else
-#endif
 	exit(EXIT_FAILURE);
 }
 
 void setupLimits(){
-#ifdef USE_POSIX_LIMITS
 	struct rlimit limit;
 
-	limit.rlim_cur = TIME_OUT;
-	limit.rlim_max = TIME_OUT;
+	limit.rlim_cur = timeOut;
+	limit.rlim_max = timeOut;
 	if(0!=setrlimit(RLIMIT_CPU, &limit)){
 		fprintf(stderr, "failed to set cpu limit [%d]\n", errno);
 		exit(EXIT_FAILURE);
 	}
 
-	limit.rlim_cur = MEM_LIMIT * 1024L * 1024L;
-	limit.rlim_max = MEM_LIMIT * 1024L * 1024L;
+	limit.rlim_cur = memoryLimit * 1024L * 1024L;
+	limit.rlim_max = memoryLimit * 1024L * 1024L;
 #ifdef RLIMIT_AS
 	if(0!=setrlimit(RLIMIT_AS, &limit)){
-		fprintf(stderr, "failed to set mem limit (AS) [%d]\n", errno);
+		fprintf(stderr, "failed to set mem limit (AS) %s [%d]\n", strerror(errno), errno);
 		exit(EXIT_FAILURE);
 	}
 #endif
 
 	if(0!=setrlimit(RLIMIT_DATA, &limit)){
-		fprintf(stderr, "failed to set mem limit (DATA) [%d]\n", errno);
+		fprintf(stderr, "failed to set mem limit (DATA) %s [%d]\n", strerror(errno), errno);
 		exit(EXIT_FAILURE);
 	}
 
 	if(0!=setrlimit(RLIMIT_RSS, &limit)){
-		fprintf(stderr, "failed to set mem limit (RSS) [%d]\n", errno);
+		fprintf(stderr, "failed to set mem limit (RSS) %s [%d]\n", strerror(errno), errno);
 		exit(EXIT_FAILURE);
 	}
 #if defined(RLIMIT_MEMLOCK) && !defined(linux)
 	if(0!=setrlimit(RLIMIT_MEMLOCK, &limit)){
-		fprintf(stderr, "failed to set mem limit (MEMLOCK) [%d]\n", errno);
+		fprintf(stderr, "failed to set mem limit (MEMLOCK): %s [%d]\n", strerror(errno), errno);
 		exit(EXIT_FAILURE);
 	}
 #endif
-#endif /* USE_POSIX_LIMITS */
 }
 
 void setupHandlers(){
-#ifdef USE_POSIX
 #ifdef SIGHUP
 	signal(SIGHUP, &handleSignal);
 #endif
@@ -185,9 +191,7 @@
 #ifdef SIGPIPE
 	signal(SIGPIPE, &handleSignal);
 #endif
-#ifdef SIGALRM
 	signal(SIGALRM, &handleSignal);
-#endif
 	signal(SIGTERM, &handleSignal);
 #ifdef SIGSTKFLT
 	signal(SIGSTKFLT, &handleSignal);
@@ -207,26 +211,26 @@
 #ifdef SIGSYS
 	signal(SIGSYS, &handleSignal);
 #endif
+}
 #endif /* USE_POSIX */
-}
-
-void cleanCommand(){
-	free(cmd);
-}
 
 char* reconstructCmd(int argc, char** argv){
 	size_t cmdLen=1;
 	size_t tmpLen;
 	size_t i;
 	char* tmp;
+	char* cmd;
 
 	for(i=0; i<argc; i++){
 		cmdLen+=strlen(argv[i]);
 		cmdLen+=3;
 	}
 
-	cmd = (char*)malloc(cmdLen);
-	atexit(&cleanCommand);
+	cmd = malloc(cmdLen);
+	if(!cmd){
+		fprintf(stderr, "failed to allocate enough memory");
+		exit(EXIT_FAILURE);
+	}
 
 	*cmd = '\x00';
 	tmp = cmd;
@@ -240,11 +244,35 @@
 }
 
 int main(int argc, char** argv){
-	if(argc<2){
-		fprintf(stderr, "name of command to call required\n");
+	char* cmd;
+	char* end;
+
+	if(argc<4){
+		fprintf(stderr, "crashRun <timeOut (s)> <maxMemory (MB)> <command> [<command arg> ...]\n");
+		return EXIT_FAILURE;
+	}
+	timeOut = strtol(argv[1], &end, 10);
+	if(*end){
+		fprintf(stderr, "the timeOut argument contains the illegal character: %c (0x%X)", *end, *end);
+		return EXIT_FAILURE;
+	}else if(timeOut < 1){
+		fprintf(stderr, "minimum timeOut is 1 second, got %li seconds\n", timeOut);
 		return EXIT_FAILURE;
 	}
-	cmd = reconstructCmd(argc-1, argv+1);
+
+	memoryLimit = strtol(argv[2], &end, 10);
+	if(*end){
+		fprintf(stderr, "the maxMemory argument contains the illegal character: %c (0x%X)", *end, *end);
+		return EXIT_FAILURE;
+	}else if(memoryLimit < 1){
+		fprintf(stderr, "minimum memoryLimit is 1MB second, got %li MB\n", memoryLimit);
+		return EXIT_FAILURE;
+	}
+	cmd = reconstructCmd(argc-3, argv+3);
+
+#ifdef DEBUG
+		printf("cmd[%li sec, %li MB]: %s \n", timeOut, memoryLimit, cmd);
+#endif
 
 #ifdef USE_POSIX
 	setupLimits();
@@ -252,9 +280,6 @@
 	if(pID == 0){
 		/* child */
 		pID=setsid();
-#ifdef DEBUG
-		printf("cmd[%i sec]: %s \n", TIME_OUT, cmd);
-#endif
 		printf("EXIT CODE: %d\n", system(cmd));
 	}else if(pID < 0){
 		fprintf(stderr, "failed to fork\n");
@@ -263,14 +288,66 @@
 		/* parent */
 		setupHandlers();
 #if !(defined(USE_POSIX_LIMITS) && defined(SIGXCPU))
-		alarm(TIME_OUT);
+		alarm(timeOut);
+#else
+		/* safe guard against childs without CPU usage */
+		alarm(timeOut * WAIT_GUARD);
 #endif
 		wait(NULL);
 	}
 	return EXIT_SUCCESS;
-#else /* USE_POSIX */
+#elif USE_WINDOWS
+	/* BUG: maxMemory not implemented */
+
+	PROCESS_INFORMATION processInfo;
+	STARTUPINFO startupInfo;
+	SECURITY_ATTRIBUTES sa = {
+		sizeof(SECURITY_ATTRIBUTES), NULL, TRUE
+	};
+	unsigned long exitCode;
+	long int timeLeft = timeOut;	/* time limit in iterations of WFX loop */
+
+	memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
+	memset(&startupInfo, 0, sizeof(STARTUPINFO));
+	startupInfo.cb = sizeof(STARTUPINFO);
+
+	if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL,
+		  &startupInfo, &processInfo)) {
+		void *message;
+
+		FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
+		  | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
+		   (char*) &message, 0, NULL);
 
-#error no test run implmentation present for your system
+		/* this should never happen */
+		fprintf(stderr, "ERROR running %s:\n", cmd);
+		fprintf(stderr, "%s\n", message);
+		LocalFree((HLOCAL) message);
+		return RAND_MAX;
+	}
+
+	/* wait for exit */
+	while (TRUE) {
+		Sleep(1000);
+		GetExitCodeProcess(processInfo.hProcess, &exitCode);
+		if (exitCode == 0x103) {
+			if (--timeLeft == 0) {
+				TerminateProcess(processInfo.hProcess, EXIT_FAILURE);
+				printf("EXIT CODE: timeout after %li seconds\n", timeOut);
+				Sleep(100);
+				return EXIT_SUCCESS;
+			}
+		} else {
+			printf("EXIT CODE: %i\n", exitCode);
+			return EXIT_SUCCESS;
+		}
+	}
+
+	fprintf(stderr, "crashRun: BUG\n");
+	return EXIT_FAILURE;
+#else
+
+#error no implmentation for your system found (supported: Posix, Windows)
 
 #endif /* USE_POSIX else */
 }
--- a/dstress.c	Sat Apr 01 20:22:02 2006 +0000
+++ b/dstress.c	Sat Apr 01 20:22:12 2006 +0000
@@ -2,7 +2,10 @@
  * core test tool for the DStress test suite
  * http://dstress.kuehne.cn
  *
- * Copyright (C) 2005, 2006 Thomas Kuehne <thomas@kuehne.cn>
+ * Copyright (C)
+ * 	2005, 2006 Thomas Kuehne <thomas@kuehne.cn>
+ * 	2005 Carlos Santander (Window files)
+ * 	2005 Stewart Gordon <smjg_1998@yahoo.com> (Window crashRun)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -151,7 +154,7 @@
 #define TORTURE_PREFIX		"torture-"
 
 #ifdef USE_POSIX
-#define		CRASH_RUN	"./crashRun"
+#define		CRASH_RUN	"./crashRun 30 1024"
 #define		TMP_DIR		"./obj"
 #else
 #ifdef USE_WINDOWS
@@ -653,7 +656,7 @@
 	len = 20 + strlen(CRASH_RUN) + strlen(cmd) + strlen(*logFile);
 	buffer = malloc(len);
 
-	snprintf(buffer, len, "\"%s\" %s > %s 2>&1", CRASH_RUN, cmd, *logFile);
+	snprintf(buffer, len, "%s %s > %s 2>&1", CRASH_RUN, cmd, *logFile);
 
 	system(buffer);
 	free(buffer);