//version 1:以下代码仅演示nginx多进程模型
[test@vm c]$ cat mynginx.c
#include <stdio.h>
#include <string.h>
#include <unistd.h> char **os_argv;
char *os_argv_last;
init_setproctitle(void)
{
char *p;
size_t size;
int i; size = ; os_argv_last = os_argv[]; for (i = ; os_argv[i]; i++) {
if (os_argv_last == os_argv[i]) {
os_argv_last = os_argv[i] + strlen(os_argv[i]) + ;
}
}
os_argv_last += strlen(os_argv_last);
} void setproctitle(char *title)
{
char *p;
os_argv[] = NULL; p = strncpy((char *) os_argv[], (char *) title,
strlen(title));
p += strlen(title); if (os_argv_last - (char *) p > ) {
memset(p, ' ', os_argv_last - (char *) p);
} } void start_woker_processes()
{
setproctitle("mynginx:worker process");
for(;;)
{
sleep();
printf("worker pid=%d\n",getpid());
}
} void start_dispatcher_process()
{
setproctitle("mynginx:dispatcher process");
for(;;)
{
sleep();
printf("\tdispatcher pid=%d\n",getpid());
}
} void save_argv(int argc, char *const *argv)
{
os_argv = (char **) argv;
} int main(int argc, char **argv)
{
int fd;
int i;
pid_t pid;
save_argv(argc, argv);
init_setproctitle();
printf("father pid1=%d\n",getpid());
for (i = ; i <; i++)
{
pid = fork();
if (pid == )
{
start_woker_processes();
}
}
pid = fork();
if (pid == )
{
start_dispatcher_process();
}
printf("father pid2=%d\n",getpid());
while()
sleep();
return ;
}
make mynginx
./mynginx
ps -ef |grep mynginx 即可看到
test 20553 20463 0 23:54 pts/0 00:00:00 ./mynginx
test 20554 20553 0 23:54 pts/0 00:00:00 mynginx:worker process
test 20555 20553 0 23:54 pts/0 00:00:00 mynginx:worker process
test 20556 20553 0 23:54 pts/0 00:00:00 mynginx:worker process
test 20557 20553 0 23:54 pts/0 00:00:00 mynginx:dispatcher process
root 20574 20560 0 23:54 pts/2 00:00:00 grep mynginx
version 2:
改进:支持父进程重启被异常中断的子进程。
一个master,一个dispatcher,三个worker
[root@vm---- nginx-1.7.]# ps -ef | grep getslice
liubin : pts/ :: ./getslice
liubin : pts/ :: getslice:worker process
liubin : pts/ :: getslice:worker process
liubin : pts/ :: getslice:dispatcher process
liubin : pts/ :: getslice:worker process
[root@vm-10-154-252-59 nginx-1.7.10]# kill -9 745
[root@vm-10-154-252-59 nginx-1.7.10]# ps -ef | grep getslice
liubin 726 3469 0 20:00 pts/4 00:00:00 ./getslice
liubin 727 726 0 20:00 pts/4 00:00:00 getslice:worker process
liubin 728 726 0 20:00 pts/4 00:00:00 getslice:worker process
liubin 740 726 0 20:00 pts/4 00:00:00 getslice:dispatcher process
liubin 2714 726 0 20:30 pts/4 00:00:00 getslice:worker process
//可以看到,杀掉745后,马上又起来新的2714进程
下面是代码,可以直接编译
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> #define DefaultConfigFile "/opt/project/getslice/conf/getslice_lunbo.conf"
#define PID_FILENAME "/var/run/getslice_lunbo.pid"
#define VERSION "1.0.0" #define MAX_PROCESSES 128
#define PROCESS_NORESPAWN -1
#define PROCESS_JUST_SPAWN -2
#define PROCESS_RESPAWN -3
#define PROCESS_JUST_RESPAWN -4
#define PROCESS_DETACHED -5 const char *appname="getslice_lunbo";
char *ConfigFile = NULL; typedef void (*spawn_proc_pt) (void *data);
typedef struct {
pid_t pid;
int status;
//int channel[2]; spawn_proc_pt proc;
void *data;
char *name; unsigned respawn:;
unsigned just_spawn:;
unsigned detached:;
unsigned exiting:;
unsigned exited:;
} process_t;
process_t processes[MAX_PROCESSES];
int process_slot; /* getopt args*/
int opt_no_daemon = ;
int opt_debug_stderr = -;
int opt_parse_cfg_only = ;
int opt_send_signal = -; sig_atomic_t reap;
sig_atomic_t terminate;
sig_atomic_t quit;
int last_process;
int exiting; char **os_argv;
char *os_argv_last;
init_setproctitle(void)
{
char *p;
size_t size;
int i; size = ; os_argv_last = os_argv[]; for (i = ; os_argv[i]; i++) {
if (os_argv_last == os_argv[i]) {
os_argv_last = os_argv[i] + strlen(os_argv[i]) + ;
}
}
os_argv_last += strlen(os_argv_last);
} void setproctitle(char *title)
{
char *p;
os_argv[] = NULL; p = strncpy((char *) os_argv[], (char *) title,
strlen(title));
p += strlen(title); if (os_argv_last - (char *) p > ) {
memset(p, ' ', os_argv_last - (char *) p);
} } void worker_process_init(int worker)
{ } void worker_process_exit(void)
{ } void
worker_process_cycle(void *data)
{
int worker = (intptr_t) data; worker_process_init(worker); setproctitle("getslice:worker process"); for ( ;; ) {
if (exiting) {
fprintf(stderr, "exiting");
worker_process_exit();
}
sleep();
fprintf(stderr, "\tworker cycle pid: %d\n", getpid()); if (terminate) {
fprintf(stderr, "exiting");
worker_process_exit();
} if (quit) {
quit = ;
fprintf(stderr, "gracefully shutting down");
setproctitle("worker process is shutting down"); if (!exiting) {
exiting = ;
}
}
}
} void dispatcher_process_init(int worker)
{ } void dispatcher_process_exit()
{ } void
dispatcher_process_cycle(void *data)
{
int worker = (intptr_t) data; dispatcher_process_init(worker); setproctitle("getslice:dispatcher process"); for ( ;; ) {
if (exiting) {
fprintf(stderr, "exiting\n");
dispatcher_process_exit();
} sleep();
fprintf(stderr, "\tdispatcher cycle pid: %d\n", getpid()); if (terminate) {
fprintf(stderr, "exiting\n");
dispatcher_process_exit();
} if (quit) {
quit = ;
fprintf(stderr, "gracefully shutting down\n");
setproctitle("worker process is shutting down"); if (!exiting) {
exiting = ;
}
}
}
} void
start_worker_processes(int n, int type)
{
int i;
fprintf(stderr, "start worker processes\n"); for (i = ; i < n; i++) {
spawn_process(worker_process_cycle, (void *) (intptr_t) i, "worker process", type);
}
} void start_dispatcher_process(int type)
{
fprintf(stderr, "start dispatcher processes\n");
spawn_process(dispatcher_process_cycle, (void *) (intptr_t) , "dispatcher process", type);
} void save_argv(int argc, char *const *argv)
{
os_argv = (char **) argv;
} void
sig_child(int sig)
{
reap = ; int status;
int i;
pid_t pid; do {
pid = waitpid(-, &status, WNOHANG);
for (i = ; i < last_process; i++) {
if (processes[i].pid == pid) {
processes[i].status = status;
processes[i].exited = ;
//process = processes[i].name;
break;
}
}
} while (pid > );
signal(sig, sig_child);
} typedef void SIGHDLR(int sig);
void signal_set(int sig, SIGHDLR * func, int flags)
{
struct sigaction sa;
sa.sa_handler = func;
sa.sa_flags = flags;
sigemptyset(&sa.sa_mask);
if (sigaction(sig, &sa, NULL) < )
fprintf(stderr, "sigaction: sig=%d func=%p: %s\n", sig, func, strerror(errno));
} void init_signals(void)
{
signal_set(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
} static pid_t readPidFile(void)
{
FILE *pid_fp = NULL;
const char *f = PID_FILENAME;
pid_t pid = -;
int i; if (f == NULL) {
fprintf(stderr, "%s: error: no pid file name defined\n", appname);
exit();
} pid_fp = fopen(f, "r");
if (pid_fp != NULL) {
pid = ;
if (fscanf(pid_fp, "%d", &i) == )
pid = (pid_t) i;
fclose(pid_fp);
} else {
if (errno != ENOENT) {
fprintf(stderr, "%s: error: could not read pid file\n", appname);
fprintf(stderr, "\t%s: %s\n", f, strerror(errno));
exit();
}
}
return pid;
} int checkRunningPid(void)
{
pid_t pid;
pid = readPidFile();
if (pid < )
return ;
if (kill(pid, ) < )
return ;
fprintf(stderr, "getslice_master is already running! process id %ld\n", (long int) pid);
return ;
} void writePidFile(void)
{
FILE *fp;
const char *f = PID_FILENAME;
fp = fopen(f, "w+");
if (!fp) {
fprintf(stderr, "could not write pid file '%s': %s\n", f, strerror(errno));
return;
}
fprintf(fp, "%d\n", (int) getpid());
fclose(fp);
} void usage(void)
{
fprintf(stderr,
"Usage: %s [-?hvVN] [-d level] [-c config-file] [-k signal]\n"
" -h Print help message.\n"
" -v Show Version and exit.\n"
" -N No daemon mode.\n"
" -c file Use given config-file instead of\n"
" %s\n"
" -k reload|rotate|kill|parse\n"
" kill is fast shutdown\n"
" Parse configuration file, then send signal to \n"
" running copy (except -k parse) and exit.\n",
appname, DefaultConfigFile);
exit();
} static void show_version(void)
{
fprintf(stderr, "%s version: %s\n", appname,VERSION);
exit();
} void mainParseOptions(int argc, char *argv[])
{
extern char *optarg;
int c; while ((c = getopt(argc, argv, "hvNc:k:?")) != -) {
switch (c) {
case 'h':
usage();
break;
case 'v':
show_version();
break;
case 'N':
opt_no_daemon = ;
break;
case 'c':
ConfigFile = strdup(optarg);
break;
case 'k':
if ((int) strlen(optarg) < )
usage();
if (!strncmp(optarg, "reload", strlen(optarg)))
opt_send_signal = SIGHUP;
else if (!strncmp(optarg, "rotate", strlen(optarg)))
opt_send_signal = SIGUSR1;
else if (!strncmp(optarg, "shutdown", strlen(optarg)))
opt_send_signal = SIGTERM;
else if (!strncmp(optarg, "kill", strlen(optarg)))
opt_send_signal = SIGKILL;
else if (!strncmp(optarg, "parse", strlen(optarg)))
opt_parse_cfg_only = ; /* parse cfg file only */
else
usage();
break;
case '?':
default:
usage();
break;
}
}
} void enableCoredumps(void)
{
/* Set Linux DUMPABLE flag */
if (prctl(PR_SET_DUMPABLE, , , , ) != )
fprintf(stderr, "prctl: %s\n", strerror(errno)); /* Make sure coredumps are not limited */
struct rlimit rlim; if (getrlimit(RLIMIT_CORE, &rlim) == ) {
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_CORE, &rlim) == ) {
fprintf(stderr, "Enable Core Dumps OK!\n");
return;
}
}
fprintf(stderr, "Enable Core Dump failed: %s\n",strerror(errno));
} int
reap_children(void)
{
int i, n;
int live; live = ;
for (i = ; i < last_process; i++) {
//child[0] 26718 e:0 t:0 d:0 r:1 j:0
fprintf(stderr,"child[%d] %d e:%d t:%d d:%d r:%d j:%d\n",
i,
processes[i].pid,
processes[i].exiting,
processes[i].exited,
processes[i].detached,
processes[i].respawn,
processes[i].just_spawn); if (processes[i].pid == -) {
continue;
} if (processes[i].exited) {
if (!processes[i].detached) {
for (n = ; n < last_process; n++) {
if (processes[n].exited
|| processes[n].pid == -)
{
continue;
} fprintf(stderr,"detached:%d\n", processes[n].pid);
}
} if (processes[i].respawn
&& !processes[i].exiting
&& !terminate
&& !quit)
{
if (spawn_process(processes[i].proc, processes[i].data, processes[i].name, i) == -)
{
fprintf(stderr, "could not respawn %s\n", processes[i].name);
continue;
} live = ; continue;
} if (i == last_process - ) {
last_process--; } else {
processes[i].pid = -;
} } else if (processes[i].exiting || !processes[i].detached) {
live = ;
}
} return live;
} pid_t
spawn_process(spawn_proc_pt proc, void *data, char *name, int respawn)
{
long on;
pid_t pid;
int s; if (respawn >= ) {
s = respawn; } else {
for (s = ; s < last_process; s++) {
if (processes[s].pid == -) {
break;
}
} if (s == MAX_PROCESSES) {
fprintf(stderr, "no more than %d processes can be spawned",
MAX_PROCESSES);
return -;
}
} process_slot = s; pid = fork(); switch (pid) { case -:
fprintf(stderr, "fork() failed while spawning \"%s\" :%s", name, errno);
return -; case :
pid = getpid();
proc(data);
break; default:
break;
} fprintf(stderr, "start %s %d\n", name, pid); processes[s].pid = pid;
processes[s].exited = ; if (respawn >= ) {
return pid;
} processes[s].proc = proc;
processes[s].data = data;
processes[s].name = name;
processes[s].exiting = ; switch (respawn) { case PROCESS_NORESPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_JUST_SPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_RESPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_JUST_RESPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_DETACHED:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break;
} if (s == last_process) {
last_process++;
} return pid;
} int main(int argc, char **argv)
{
int fd;
int i;
pid_t pid;
sigset_t set; mainParseOptions(argc, argv);
if (- == opt_send_signal)
if (checkRunningPid())
exit(); enableCoredumps();
writePidFile();
save_argv(argc, argv);
init_setproctitle();
init_signals();
sigemptyset(&set); printf("father pid1=%d\n",getpid());
int worker_processes = ;
start_worker_processes(worker_processes, PROCESS_RESPAWN); start_dispatcher_process(PROCESS_RESPAWN);
printf("father pid2=%d\n",getpid()); int live = ;
for (;;) {
printf("father before suspend\n");
sigsuspend(&set);
printf("father after suspend\n");
if (reap) {
reap = ;
fprintf(stderr, "reap children\n");
live = reap_children();
}
}
return ;
}