PageRenderTime 61ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/fpm/fpm_process_ctl.c

http://github.com/dreamcat4/php-fpm
C | 354 lines | 246 code | 101 blank | 7 comment | 44 complexity | efbdb382432b86c4f0c34172b0600d32 MD5 | raw file
  1. /* $Id: fpm_process_ctl.c,v 1.19.2.2 2008/12/13 03:21:18 anight Exp $ */
  2. /* (c) 2007,2008 Andrei Nigmatulin */
  3. #include "fpm_config.h"
  4. #include <sys/types.h>
  5. #include <signal.h>
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include "fpm.h"
  9. #include "fpm_clock.h"
  10. #include "fpm_children.h"
  11. #include "fpm_signals.h"
  12. #include "fpm_events.h"
  13. #include "fpm_process_ctl.h"
  14. #include "fpm_cleanup.h"
  15. #include "fpm_request.h"
  16. #include "fpm_worker_pool.h"
  17. #include "zlog.h"
  18. static int fpm_state = FPM_PCTL_STATE_NORMAL;
  19. static int fpm_signal_sent = 0;
  20. static const char *fpm_state_names[] = {
  21. [FPM_PCTL_STATE_NORMAL] = "normal",
  22. [FPM_PCTL_STATE_RELOADING] = "reloading",
  23. [FPM_PCTL_STATE_TERMINATING] = "terminating",
  24. [FPM_PCTL_STATE_FINISHING] = "finishing"
  25. };
  26. static int saved_argc;
  27. static char **saved_argv;
  28. static void fpm_pctl_cleanup(int which, void *arg)
  29. {
  30. int i;
  31. if (which != FPM_CLEANUP_PARENT_EXEC) {
  32. for (i = 0; i < saved_argc; i++) {
  33. free(saved_argv[i]);
  34. }
  35. free(saved_argv);
  36. }
  37. }
  38. static struct event pctl_event;
  39. static void fpm_pctl_action(int fd, short which, void *arg)
  40. {
  41. evtimer_del(&pctl_event);
  42. memset(&pctl_event, 0, sizeof(pctl_event));
  43. fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT);
  44. }
  45. static int fpm_pctl_timeout_set(int sec)
  46. {
  47. struct timeval tv = { .tv_sec = sec, .tv_usec = 0 };
  48. if (evtimer_initialized(&pctl_event)) {
  49. evtimer_del(&pctl_event);
  50. }
  51. evtimer_set(&pctl_event, &fpm_pctl_action, 0);
  52. evtimer_add(&pctl_event, &tv);
  53. return 0;
  54. }
  55. static void fpm_pctl_exit()
  56. {
  57. zlog(ZLOG_STUFF, ZLOG_NOTICE, "exiting, bye-bye!");
  58. fpm_conf_unlink_pid();
  59. fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT_MAIN);
  60. exit(0);
  61. }
  62. #define optional_arg(c) (saved_argc > c ? ", \"" : ""), (saved_argc > c ? saved_argv[c] : ""), (saved_argc > c ? "\"" : "")
  63. static void fpm_pctl_exec()
  64. {
  65. zlog(ZLOG_STUFF, ZLOG_NOTICE, "reloading: execvp(\"%s\", {\"%s\""
  66. "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s"
  67. "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s"
  68. "})",
  69. saved_argv[0], saved_argv[0],
  70. optional_arg(1),
  71. optional_arg(2),
  72. optional_arg(3),
  73. optional_arg(4),
  74. optional_arg(5),
  75. optional_arg(6),
  76. optional_arg(7),
  77. optional_arg(8),
  78. optional_arg(9),
  79. optional_arg(10)
  80. );
  81. fpm_cleanups_run(FPM_CLEANUP_PARENT_EXEC);
  82. execvp(saved_argv[0], saved_argv);
  83. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "execvp() failed");
  84. exit(1);
  85. }
  86. static void fpm_pctl_action_last()
  87. {
  88. switch (fpm_state) {
  89. case FPM_PCTL_STATE_RELOADING :
  90. fpm_pctl_exec();
  91. break;
  92. case FPM_PCTL_STATE_FINISHING :
  93. case FPM_PCTL_STATE_TERMINATING :
  94. fpm_pctl_exit();
  95. break;
  96. }
  97. }
  98. int fpm_pctl_kill(pid_t pid, int how)
  99. {
  100. int s = 0;
  101. switch (how) {
  102. case FPM_PCTL_TERM :
  103. s = SIGTERM;
  104. break;
  105. case FPM_PCTL_STOP :
  106. s = SIGSTOP;
  107. break;
  108. case FPM_PCTL_CONT :
  109. s = SIGCONT;
  110. break;
  111. default :
  112. break;
  113. }
  114. return kill(pid, s);
  115. }
  116. static void fpm_pctl_kill_all(int signo)
  117. {
  118. struct fpm_worker_pool_s *wp;
  119. int alive_children = 0;
  120. for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
  121. struct fpm_child_s *child;
  122. for (child = wp->children; child; child = child->next) {
  123. int res = kill(child->pid, signo);
  124. zlog(ZLOG_STUFF, ZLOG_NOTICE, "sending signal %d %s to child %d (pool %s)", signo,
  125. fpm_signal_names[signo] ? fpm_signal_names[signo] : "",
  126. (int) child->pid, child->wp->config->name);
  127. if (res == 0) { ++alive_children; }
  128. }
  129. }
  130. if (alive_children) {
  131. zlog(ZLOG_STUFF, ZLOG_NOTICE, "%d %s still alive", alive_children, alive_children == 1 ? "child is" : "children are");
  132. }
  133. }
  134. static void fpm_pctl_action_next()
  135. {
  136. int sig, timeout;
  137. if (!fpm_globals.running_children) { fpm_pctl_action_last(); }
  138. if (fpm_signal_sent == 0) {
  139. if (fpm_state == FPM_PCTL_STATE_TERMINATING) {
  140. sig = SIGTERM;
  141. }
  142. else {
  143. sig = SIGQUIT;
  144. }
  145. timeout = fpm_global_config.process_control_timeout;
  146. }
  147. else {
  148. if (fpm_signal_sent == SIGQUIT) {
  149. sig = SIGTERM;
  150. }
  151. else {
  152. sig = SIGKILL;
  153. }
  154. timeout = 1;
  155. }
  156. fpm_pctl_kill_all(sig);
  157. fpm_signal_sent = sig;
  158. fpm_pctl_timeout_set(timeout);
  159. }
  160. void fpm_pctl(int new_state, int action)
  161. {
  162. switch (action) {
  163. case FPM_PCTL_ACTION_SET :
  164. if (fpm_state == new_state) { /* already in progress - just ignore duplicate signal */
  165. return;
  166. }
  167. switch (fpm_state) { /* check which states can be overridden */
  168. case FPM_PCTL_STATE_NORMAL :
  169. /* 'normal' can be overridden by any other state */
  170. break;
  171. case FPM_PCTL_STATE_RELOADING :
  172. /* 'reloading' can be overridden by 'finishing' */
  173. if (new_state == FPM_PCTL_STATE_FINISHING) { break; }
  174. case FPM_PCTL_STATE_FINISHING :
  175. /* 'reloading' and 'finishing' can be overridden by 'terminating' */
  176. if (new_state == FPM_PCTL_STATE_TERMINATING) { break; }
  177. case FPM_PCTL_STATE_TERMINATING :
  178. /* nothing can override 'terminating' state */
  179. zlog(ZLOG_STUFF, ZLOG_NOTICE, "not switching to '%s' state, because already in '%s' state",
  180. fpm_state_names[new_state], fpm_state_names[fpm_state]);
  181. return;
  182. }
  183. fpm_signal_sent = 0;
  184. fpm_state = new_state;
  185. zlog(ZLOG_STUFF, ZLOG_NOTICE, "switching to '%s' state", fpm_state_names[fpm_state]);
  186. /* fall down */
  187. case FPM_PCTL_ACTION_TIMEOUT :
  188. fpm_pctl_action_next();
  189. break;
  190. case FPM_PCTL_ACTION_LAST_CHILD_EXITED :
  191. fpm_pctl_action_last();
  192. break;
  193. }
  194. }
  195. int fpm_pctl_can_spawn_children()
  196. {
  197. return fpm_state == FPM_PCTL_STATE_NORMAL;
  198. }
  199. int fpm_pctl_child_exited()
  200. {
  201. if (fpm_state == FPM_PCTL_STATE_NORMAL) { return 0; }
  202. if (!fpm_globals.running_children) {
  203. fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED);
  204. }
  205. return 0;
  206. }
  207. int fpm_pctl_init_main()
  208. {
  209. int i;
  210. saved_argc = fpm_globals.argc;
  211. saved_argv = malloc(sizeof(char *) * (saved_argc + 1));
  212. if (!saved_argv) {
  213. return -1;
  214. }
  215. for (i = 0; i < saved_argc; i++) {
  216. saved_argv[i] = strdup(fpm_globals.argv[i]);
  217. if (!saved_argv[i]) {
  218. return -1;
  219. }
  220. }
  221. saved_argv[i] = 0;
  222. if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_pctl_cleanup, 0)) {
  223. return -1;
  224. }
  225. return 0;
  226. }
  227. static void fpm_pctl_check_request_timeout(struct timeval *now)
  228. {
  229. struct fpm_worker_pool_s *wp;
  230. for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
  231. int terminate_timeout = wp->config->request_terminate_timeout;
  232. int slowlog_timeout = wp->config->request_slowlog_timeout;
  233. struct fpm_child_s *child;
  234. if (terminate_timeout || slowlog_timeout) {
  235. for (child = wp->children; child; child = child->next) {
  236. fpm_request_check_timed_out(child, now, terminate_timeout, slowlog_timeout);
  237. }
  238. }
  239. }
  240. }
  241. void fpm_pctl_heartbeat(int fd, short which, void *arg)
  242. {
  243. static struct event heartbeat;
  244. struct timeval tv = { .tv_sec = 0, .tv_usec = 130000 };
  245. struct timeval now;
  246. if (which == EV_TIMEOUT) {
  247. evtimer_del(&heartbeat);
  248. fpm_clock_get(&now);
  249. fpm_pctl_check_request_timeout(&now);
  250. }
  251. evtimer_set(&heartbeat, &fpm_pctl_heartbeat, 0);
  252. evtimer_add(&heartbeat, &tv);
  253. }