1/*
2 * Copyright (c) 2004, Bull S.A..  All rights reserved.
3 * Created by: Sebastien Decugis
4
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc., 59
15 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
16
17 */
18
19/*
20 * The purpose of this file is to provide a monitor process
21 * for the stress/threads/ * / *.c testcases in the OPTS.
22 *
23 * The goal is:
24 * -> if the testcase returns, the monitor returns the error code.
25 * -> after a specified timeout, the monitor let the stress test terminate
26
27 * This allows for the stress tests to be run in an automatic maneer
28 * with a script such as:
29#!/bin/sh
30
31#monitor the system
32vmstat -n 120 180 &> monitor.txt &
33
34#run the tests
35for TS in `ls -1 *.c`;
36do <compile $TS>;
37if [ $? -eq 0 ];
38then <run in background:>
39     helper 6 $TS.exe &
40fi
41done
42
43#wait for the end
44while [ "`ps -e | grep helper`" ];
45do sleep 30;
46done
47
48*/
49
50
51/* This utility should compile on any POSIX-conformant implementation. */
52#define _POSIX_C_SOURCE 200112L
53
54#include <pthread.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <unistd.h>
58#include <signal.h>
59#include <sys/wait.h>
60#include <assert.h>
61#include <time.h>
62
63pid_t child;
64int timeout;
65
66/* Note that there could be a race between
67the moment the stress test terminates and
68when the timeout expires. As this is highly
69improbable, we don't care... */
70
71void * timer(void * arg)
72{
73	int ret=0;
74
75	unsigned remaining = timeout  * 3600;
76	do {
77		remaining = sleep(remaining);
78	} while (remaining);
79	ret = kill(child, SIGUSR1);
80	if (ret != 0)
81	{
82		perror("Failed to kill the stress test");
83		exit(2);
84	}
85
86	return NULL;
87}
88
89
90int main (int argc, char * argv[])
91{
92	int ret;
93	pthread_t th;
94	pid_t chk;
95	int status;
96	char *ts="[??:??:??]";
97	struct tm * now;
98	time_t nw;
99
100	/* check args */
101	if (argc < 3)
102	{
103		printf("\nUsage: \n");
104		printf("  $ %s n exe arglist\n", argv[0]);
105		printf("\nWhere:\n");
106		printf("  n       is the timeout duration in hours,\n");
107		printf("  exe     is the stress test executable to monitor,\n");
108		printf("  arglist is the arguments to be passed to executable.\n\n");
109		return 2;
110	}
111
112	timeout = atoi(argv[1]);
113	if (timeout < 1)
114	{
115		fprintf(stderr, "Invalid timeout value \"%s\". Timeout must be a positive integer.\n", argv[1]);
116		return 2;
117	}
118
119	/* create the timer thread */
120	ret = pthread_create(&th, NULL, timer, NULL);
121	if (ret != 0)
122	{
123		perror("Failed to create the timeout thread\n");
124		return 2;
125	}
126
127	/* Create the new process for the stress test */
128	child = fork();
129
130	if (child == (pid_t)-1)
131	{
132		perror("Failed to create a new process");
133		exit(2);
134	}
135
136	/* The child process executes the test */
137	if (child == (pid_t)0)
138	{
139
140		/* Execute the command */
141		ret = execvp(argv[2], &argv[2]);
142		if (ret == -1)
143		{
144			/* Application was not launched */
145			perror("Unable to run child application");
146			return 2;
147		}
148		assert(0);
149		perror("Should not see me");
150		return 2;
151	}
152
153	/* The parent: */
154
155	/* wait for the child process to terminate */
156	chk = waitpid(child, &status, 0);
157	if (chk != child)
158	{
159		perror("Got the wrong process image status");
160		return 2;
161	}
162
163	/* Cancel the timer thread in case the process returned by itself */
164	(void) pthread_cancel(th);
165
166	ret = pthread_join(th, NULL);
167	if (ret != 0)
168	{
169		perror("Unable to join the timer thread");
170		return 2;
171	}
172
173	/* return */
174	nw = time(NULL);
175	now = localtime(&nw);
176	if (now == NULL)
177		printf(ts);
178	else
179		printf("[%2.2d:%2.2d:%2.2d]", now->tm_hour, now->tm_min, now->tm_sec);
180	if ( ! WIFEXITED(status))
181	{
182		printf("The stress sample did not exit\n");
183		if (WIFSIGNALED(status))
184		{
185			printf("It was killed with signal %i\n",  WTERMSIG(status));
186		}
187		else
188		{
189			printf("and it was not killed...\n");
190		}
191		exit(1);
192	}
193	if (WEXITSTATUS(status) == 0)
194	{
195		printf("Test %s PASSED\n", argv[2]);
196	}
197	else
198	{
199		printf("Test %s: returned %d\n", argv[2], WEXITSTATUS(status));
200	}
201	exit(WEXITSTATUS(status));
202}
203
204