Mercurial > hg > nginx-vendor-current
comparison src/os/unix/ngx_process.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | cc9f381affaa |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_channel.h> | |
11 | |
12 | |
13 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data); | |
14 | |
15 ngx_int_t ngx_process_slot; | |
16 ngx_socket_t ngx_channel; | |
17 ngx_int_t ngx_last_process; | |
18 ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; | |
19 | |
20 | |
21 ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, | |
22 ngx_spawn_proc_pt proc, void *data, | |
23 char *name, ngx_int_t respawn) | |
24 { | |
25 u_long on; | |
26 ngx_pid_t pid; | |
27 ngx_int_t s; | |
28 | |
29 if (respawn >= 0) { | |
30 s = respawn; | |
31 | |
32 } else { | |
33 for (s = 0; s < ngx_last_process; s++) { | |
34 if (ngx_processes[s].pid == -1) { | |
35 break; | |
36 } | |
37 } | |
38 | |
39 if (s == NGX_MAX_PROCESSES) { | |
40 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
41 "no more than %d processes can be spawned", | |
42 NGX_MAX_PROCESSES); | |
43 return NGX_ERROR; | |
44 } | |
45 } | |
46 | |
47 | |
48 if (respawn != NGX_PROCESS_DETACHED) { | |
49 | |
50 /* Solaris 9 still has no AF_LOCAL */ | |
51 | |
52 if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1) | |
53 { | |
54 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
55 "socketpair() failed while spawning \"%s\"", name); | |
56 return NGX_ERROR; | |
57 } | |
58 | |
59 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
60 "channel %d:%d", | |
61 ngx_processes[s].channel[0], | |
62 ngx_processes[s].channel[1]); | |
63 | |
64 if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) { | |
65 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
66 ngx_nonblocking_n " failed while spawning \"%s\"", | |
67 name); | |
68 ngx_close_channel(ngx_processes[s].channel, cycle->log); | |
69 return NGX_ERROR; | |
70 } | |
71 | |
72 if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) { | |
73 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
74 ngx_nonblocking_n " failed while spawning \"%s\"", | |
75 name); | |
76 ngx_close_channel(ngx_processes[s].channel, cycle->log); | |
77 return NGX_ERROR; | |
78 } | |
79 | |
80 on = 1; | |
81 if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { | |
82 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
83 "ioctl(FIOASYNC) failed while spawning \"%s\"", name); | |
84 ngx_close_channel(ngx_processes[s].channel, cycle->log); | |
85 return NGX_ERROR; | |
86 } | |
87 | |
88 if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { | |
89 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
90 "fcntl(F_SETOWN) failed while spawning \"%s\"", name); | |
91 ngx_close_channel(ngx_processes[s].channel, cycle->log); | |
92 return NGX_ERROR; | |
93 } | |
94 | |
95 if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) { | |
96 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
97 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", | |
98 name); | |
99 ngx_close_channel(ngx_processes[s].channel, cycle->log); | |
100 return NGX_ERROR; | |
101 } | |
102 | |
103 if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) { | |
104 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
105 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", | |
106 name); | |
107 ngx_close_channel(ngx_processes[s].channel, cycle->log); | |
108 return NGX_ERROR; | |
109 } | |
110 | |
111 ngx_channel = ngx_processes[s].channel[1]; | |
112 | |
113 } else { | |
114 ngx_processes[s].channel[0] = -1; | |
115 ngx_processes[s].channel[1] = -1; | |
116 } | |
117 | |
118 ngx_process_slot = s; | |
119 | |
120 | |
121 pid = fork(); | |
122 | |
123 switch (pid) { | |
124 | |
125 case -1: | |
126 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
127 "fork() failed while spawning \"%s\"", name); | |
128 ngx_close_channel(ngx_processes[s].channel, cycle->log); | |
129 return NGX_ERROR; | |
130 | |
131 case 0: | |
132 ngx_pid = ngx_getpid(); | |
133 proc(cycle, data); | |
134 break; | |
135 | |
136 default: | |
137 break; | |
138 } | |
139 | |
140 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
141 "spawn %s: " PID_T_FMT, name, pid); | |
142 | |
143 ngx_processes[s].pid = pid; | |
144 ngx_processes[s].exited = 0; | |
145 | |
146 if (respawn >= 0) { | |
147 return pid; | |
148 } | |
149 | |
150 ngx_processes[s].proc = proc; | |
151 ngx_processes[s].data = data; | |
152 ngx_processes[s].name = name; | |
153 ngx_processes[s].exiting = 0; | |
154 | |
155 switch (respawn) { | |
156 | |
157 case NGX_PROCESS_RESPAWN: | |
158 ngx_processes[s].respawn = 1; | |
159 ngx_processes[s].just_respawn = 0; | |
160 ngx_processes[s].detached = 0; | |
161 break; | |
162 | |
163 case NGX_PROCESS_JUST_RESPAWN: | |
164 ngx_processes[s].respawn = 1; | |
165 ngx_processes[s].just_respawn = 1; | |
166 ngx_processes[s].detached = 0; | |
167 break; | |
168 | |
169 case NGX_PROCESS_DETACHED: | |
170 ngx_processes[s].respawn = 0; | |
171 ngx_processes[s].just_respawn = 0; | |
172 ngx_processes[s].detached = 1; | |
173 break; | |
174 } | |
175 | |
176 if (s == ngx_last_process) { | |
177 ngx_last_process++; | |
178 } | |
179 | |
180 return pid; | |
181 } | |
182 | |
183 | |
184 ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) | |
185 { | |
186 return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name, | |
187 NGX_PROCESS_DETACHED); | |
188 } | |
189 | |
190 | |
191 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data) | |
192 { | |
193 ngx_exec_ctx_t *ctx = data; | |
194 | |
195 if (execve(ctx->path, ctx->argv, ctx->envp) == -1) { | |
196 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
197 "execve() failed while executing %s \"%s\"", | |
198 ctx->name, ctx->path); | |
199 } | |
200 | |
201 exit(1); | |
202 } | |
203 | |
204 | |
205 void ngx_process_get_status() | |
206 { | |
207 int status; | |
208 char *process; | |
209 ngx_pid_t pid; | |
210 ngx_err_t err; | |
211 ngx_int_t i; | |
212 ngx_uint_t one; | |
213 struct timeval tv; | |
214 one = 0; | |
215 | |
216 for ( ;; ) { | |
217 pid = waitpid(-1, &status, WNOHANG); | |
218 | |
219 if (pid == 0) { | |
220 return; | |
221 } | |
222 | |
223 if (pid == -1) { | |
224 err = ngx_errno; | |
225 | |
226 if (err == NGX_EINTR) { | |
227 continue; | |
228 } | |
229 | |
230 if (err == NGX_ECHILD && one) { | |
231 return; | |
232 } | |
233 | |
234 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno, | |
235 "waitpid() failed"); | |
236 return; | |
237 } | |
238 | |
239 | |
240 if (ngx_accept_mutex_ptr) { | |
241 | |
242 /* | |
243 * unlock the accept mutex if the abnormally exited process | |
244 * held it | |
245 */ | |
246 | |
247 ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0); | |
248 } | |
249 | |
250 | |
251 one = 1; | |
252 process = "unknown process"; | |
253 | |
254 for (i = 0; i < ngx_last_process; i++) { | |
255 if (ngx_processes[i].pid == pid) { | |
256 ngx_processes[i].status = status; | |
257 ngx_processes[i].exited = 1; | |
258 process = ngx_processes[i].name; | |
259 break; | |
260 } | |
261 } | |
262 | |
263 if (WTERMSIG(status)) { | |
264 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
265 "%s " PID_T_FMT " exited on signal %d%s", | |
266 process, pid, WTERMSIG(status), | |
267 WCOREDUMP(status) ? " (core dumped)" : ""); | |
268 | |
269 } else { | |
270 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, | |
271 "%s " PID_T_FMT " exited with code %d", | |
272 process, pid, WEXITSTATUS(status)); | |
273 } | |
274 | |
275 if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) { | |
276 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
277 "%s " PID_T_FMT | |
278 " exited with fatal code %d and could not respawn", | |
279 process, pid, WEXITSTATUS(status)); | |
280 ngx_processes[i].respawn = 0; | |
281 } | |
282 } | |
283 } |