~ubuntu-branches/ubuntu/vivid/cctools/vivid

« back to all changes in this revision

Viewing changes to ftsh/src/multi_fork.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Hanke
  • Date: 2011-05-07 09:05:00 UTC
  • Revision ID: james.westby@ubuntu.com-20110507090500-lqpmdtwndor6e7os
Tags: upstream-3.3.2
ImportĀ upstreamĀ versionĀ 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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.
 
6
*/
 
7
 
 
8
#include "multi_fork.h"
 
9
#include "ftsh_error.h"
 
10
#include "stringtools.h"
 
11
#include "cancel.h"
 
12
#include "macros.h"
 
13
 
 
14
#include <unistd.h>
 
15
#include <stdio.h>
 
16
#include <stdlib.h>
 
17
#include <errno.h>
 
18
#include <string.h>
 
19
#include <sys/wait.h>
 
20
#include <signal.h>
 
21
 
 
22
int multi_fork_kill_timeout = 30;
 
23
int multi_fork_kill_mode = MULTI_FORK_KILL_MODE_STRONG;
 
24
 
 
25
/*
 
26
Fork off n processes without any fault-tolerance.
 
27
*/
 
28
 
 
29
static int multi_start( int n, struct multi_fork_status *p, time_t stoptime, int line )
 
30
{
 
31
        int i;
 
32
        pid_t pid;
 
33
 
 
34
        for(i=0;i<n;i++) {
 
35
                if(cancel_pending()) return MULTI_FORK_FAILURE;
 
36
                if(stoptime && (time(0)>stoptime)) return MULTI_FORK_TIMEOUT;
 
37
                pid = fork();
 
38
                if(pid==0) {
 
39
                        return i;
 
40
                } else if(pid>0) {
 
41
                        ftsh_error(FTSH_ERROR_PROCESS,line,"started new process %d",pid);
 
42
                        p[i].pid = pid;
 
43
                        p[i].state = MULTI_FORK_STATE_RUNNING;
 
44
                } else {
 
45
                        ftsh_error(FTSH_ERROR_FAILURE,line,"couldn't create new process: %s\n",strerror(errno));
 
46
                        return MULTI_FORK_FAILURE;
 
47
                }
 
48
        }
 
49
 
 
50
        return MULTI_FORK_SUCCESS;
 
51
}
 
52
 
 
53
/*
 
54
Wait for these n processes to complete,
 
55
allowing for a timeout or an incoming cancel signal, if requested.
 
56
*/
 
57
 
 
58
static int multi_wait( int n, struct multi_fork_status *p, time_t stoptime, int line, int stop_on_failure )
 
59
{
 
60
        int status;
 
61
        int interval;
 
62
        int i;
 
63
        pid_t pid;
 
64
        int total;
 
65
 
 
66
        while(1) {
 
67
                total=0;
 
68
 
 
69
                for(i=0;i<n;i++) {
 
70
                        if( p[i].state==MULTI_FORK_STATE_GRAVE ) {
 
71
                                total++;
 
72
                        }
 
73
                }
 
74
 
 
75
                if(total>=n) return MULTI_FORK_SUCCESS;
 
76
                if(stop_on_failure && cancel_pending()) return MULTI_FORK_FAILURE;
 
77
 
 
78
                if(stoptime) {
 
79
                        interval = stoptime-time(0);
 
80
                        if(interval<=0) {
 
81
                                return MULTI_FORK_TIMEOUT;
 
82
                        } else {
 
83
                                alarm(interval);
 
84
                        }
 
85
                } else {
 
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. */
 
87
                        alarm(10);
 
88
                }
 
89
 
 
90
                pid = waitpid(-1,&status,0);
 
91
                if(pid>0) {
 
92
                        ftsh_error(FTSH_ERROR_PROCESS,line,"process %d has completed",pid);
 
93
                        for(i=0;i<n;i++) {
 
94
                                if( p[i].state==MULTI_FORK_STATE_RUNNING && p[i].pid==pid ) {
 
95
                                        p[i].status = status;
 
96
                                        p[i].state = MULTI_FORK_STATE_GRAVE;
 
97
                                        if(WIFEXITED(status)&&(WEXITSTATUS(status)==0)) {
 
98
                                                break;
 
99
                                        } else if(stop_on_failure) {
 
100
                                                return MULTI_FORK_FAILURE;
 
101
                                        } else {
 
102
                                                break;
 
103
                                        }
 
104
                                }
 
105
                        }
 
106
                }
 
107
        }
 
108
}
 
109
 
 
110
/*
 
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.
 
117
*/
 
118
 
 
119
static void multi_kill( int n, struct multi_fork_status *p, time_t stoptime, int line )
 
120
{
 
121
        int i;
 
122
 
 
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);
 
130
                }
 
131
        }
 
132
 
 
133
        multi_wait(n,p,time(0)+multi_fork_kill_timeout,line,0);
 
134
 
 
135
        while(1) {
 
136
                int total=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);
 
142
                                total++;
 
143
                        }
 
144
                }
 
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);
 
148
        }
 
149
}
 
150
 
 
151
int multi_fork( int n, struct multi_fork_status *p, time_t stoptime, int line )
 
152
{
 
153
        int i, result;
 
154
 
 
155
        for( i=0; i<n; i++ ) {
 
156
                p[i].state = MULTI_FORK_STATE_CRADLE;
 
157
        }
 
158
 
 
159
        cancel_hold();
 
160
 
 
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);
 
166
                }
 
167
        }
 
168
 
 
169
        cancel_release();
 
170
 
 
171
        return result;
 
172
}
 
173