2
Copyright (C) 2003-2004 Douglas Thain and the University of Wisconsin
3
Copyright (C) 2005- The University of Notre Dame
4
This software is distributed under the GNU General Public License.
5
See the file COPYING for details.
8
#include "multi_fork.h"
9
#include "ftsh_error.h"
10
#include "stringtools.h"
22
int multi_fork_kill_timeout = 30;
23
int multi_fork_kill_mode = MULTI_FORK_KILL_MODE_STRONG;
26
Fork off n processes without any fault-tolerance.
29
static int multi_start( int n, struct multi_fork_status *p, time_t stoptime, int line )
35
if(cancel_pending()) return MULTI_FORK_FAILURE;
36
if(stoptime && (time(0)>stoptime)) return MULTI_FORK_TIMEOUT;
41
ftsh_error(FTSH_ERROR_PROCESS,line,"started new process %d",pid);
43
p[i].state = MULTI_FORK_STATE_RUNNING;
45
ftsh_error(FTSH_ERROR_FAILURE,line,"couldn't create new process: %s\n",strerror(errno));
46
return MULTI_FORK_FAILURE;
50
return MULTI_FORK_SUCCESS;
54
Wait for these n processes to complete,
55
allowing for a timeout or an incoming cancel signal, if requested.
58
static int multi_wait( int n, struct multi_fork_status *p, time_t stoptime, int line, int stop_on_failure )
70
if( p[i].state==MULTI_FORK_STATE_GRAVE ) {
75
if(total>=n) return MULTI_FORK_SUCCESS;
76
if(stop_on_failure && cancel_pending()) return MULTI_FORK_FAILURE;
79
interval = stoptime-time(0);
81
return MULTI_FORK_TIMEOUT;
86
/* Although we hope that this algorithm is correct, there are many ways to get it wrong, so regardless, bail out every 10 seconds and reconsider. */
90
pid = waitpid(-1,&status,0);
92
ftsh_error(FTSH_ERROR_PROCESS,line,"process %d has completed",pid);
94
if( p[i].state==MULTI_FORK_STATE_RUNNING && p[i].pid==pid ) {
96
p[i].state = MULTI_FORK_STATE_GRAVE;
97
if(WIFEXITED(status)&&(WEXITSTATUS(status)==0)) {
99
} else if(stop_on_failure) {
100
return MULTI_FORK_FAILURE;
111
Attempt to kill a set of running processes.
112
First, send a gentle signal to all, then wait
113
to see if they exit voluntarily. After that,
114
start killing forcibly. If the kill mode is
115
strong, then keep killing every five seconds
116
until they exit. If not, assume they are dead.
119
static void multi_kill( int n, struct multi_fork_status *p, time_t stoptime, int line )
123
for( i=0; i<n; i++ ) {
124
if(p[i].state==MULTI_FORK_STATE_CRADLE) {
125
p[i].state = MULTI_FORK_STATE_GRAVE;
126
} else if(p[i].state==MULTI_FORK_STATE_RUNNING) {
127
ftsh_error(FTSH_ERROR_PROCESS,line,"sending SIGTERM to process %d",p[i].pid);
128
kill(p[i].pid,SIGTERM);
129
kill(-p[i].pid,SIGTERM);
133
multi_wait(n,p,time(0)+multi_fork_kill_timeout,line,0);
137
for( i=0; i<n; i++ ) {
138
if(p[i].state==MULTI_FORK_STATE_RUNNING) {
139
ftsh_error(FTSH_ERROR_PROCESS,line,"%d: sending SIGKILL to process %d",i,p[i].pid);
140
kill(p[i].pid,SIGKILL);
141
kill(-p[i].pid,SIGKILL);
145
if( total==0 ) break;
146
if( multi_fork_kill_mode==MULTI_FORK_KILL_MODE_WEAK ) break;
147
multi_wait(n,p,time(0)+5,line,0);
151
int multi_fork( int n, struct multi_fork_status *p, time_t stoptime, int line )
155
for( i=0; i<n; i++ ) {
156
p[i].state = MULTI_FORK_STATE_CRADLE;
161
result = multi_start(n,p,stoptime,line);
162
if(result==MULTI_FORK_SUCCESS) {
163
result = multi_wait(n,p,stoptime,line,1);
164
if(result!=MULTI_FORK_SUCCESS) {
165
multi_kill(n,p,stoptime,line);