Introduction
代码基本上是抄袭自nginx。在此表示感谢。The code here owns much to nginx. With thanks to author for such greate contribution.
Code
process_test.cc
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <memory.h>
#include <chrono>
#include <errno.h>
#include <signal.h>
#include <sys/types.h> //pid_t
#include <sys/wait.h>
inline int64_t WallTimeNowInUsec(){
std::chrono::system_clock::duration d = std::chrono::system_clock::now().time_since_epoch();
std::chrono::microseconds mic = std::chrono::duration_cast<std::chrono::microseconds>(d);
return mic.count();
}
inline int64_t TimeMillis(){
return WallTimeNowInUsec()/1000;
}
#define abc_signal_helper(n) SIG##n
#define abc_signal_value(n) abc_signal_helper(n)
#define abc_str_value_helper(n) #n
#define abc_str_value(n) abc_str_value_helper(n)
#define ABC_SHUTDOWN_SIGNAL QUIT
#define ABC_TERMINATE_SIGNAL TERM
typedef struct {
int signo;
char *signame;
char *name;
void (*handler)(int signo, siginfo_t *siginfo, void *ucontext);
}abc_signal_t;
static volatile bool g_running=true;
static void abc_signal_handler(int signo, siginfo_t *siginfo, void *ucontext){
switch(signo){
case abc_signal_value(ABC_SHUTDOWN_SIGNAL):
case abc_signal_value(ABC_TERMINATE_SIGNAL):
case SIGINT:
case SIGHUP:
case SIGTSTP:
g_running=false;
std::cout<<"signal "<<signo<<std::endl;
break;
default:
break;
}
}
abc_signal_t signals[] ={
{ abc_signal_value(ABC_TERMINATE_SIGNAL),
(char*)"SIG" abc_str_value(ABC_TERMINATE_SIGNAL),
(char*)"stop",
abc_signal_handler},
{abc_signal_value(ABC_SHUTDOWN_SIGNAL),
(char*)"SIG" abc_str_value(ABC_SHUTDOWN_SIGNAL),
(char*)"quit",
abc_signal_handler},
{ SIGINT, (char*)"SIGINT", (char*)"", abc_signal_handler },
{ SIGHUP, (char*)"SIGHUP", (char*)"", abc_signal_handler },
{ SIGTSTP, (char*)"SIGTSTP",(char*)"", abc_signal_handler },
{ 0, NULL, (char*)"", NULL}
};
int abc_init_signals()
{
abc_signal_t *sig;
struct sigaction sa;
for (sig = signals; sig->signo != 0; sig++) {
memset(&sa, 0,sizeof(struct sigaction));
if (sig->handler) {
sa.sa_sigaction = sig->handler;
sa.sa_flags = SA_SIGINFO;
} else {
sa.sa_handler = SIG_IGN;
}
sigemptyset(&sa.sa_mask);
if (sigaction(sig->signo, &sa, NULL) == -1) {
std::cout<<"error init signal "<<sig->name<<std::endl;
}
}
return 0;
}
#define ABC_PRIV_SZ 64
#define ABC_MAX_PROCESSES 4
#define ABC_INVALID_PID -1
#define abc_errno errno
#define abc_getpid getpid
#define abc_getppid getppid
typedef pid_t abc_pid_t;
typedef struct{
abc_pid_t pid;
char priv[ABC_PRIV_SZ];
}abc_process_t;
abc_process_t abc_processes[ABC_MAX_PROCESSES];
int abc_process_slot;
int abc_last_process;
abc_pid_t abc_pid;
abc_pid_t abc_parent;
typedef void (*abc_task_fun_t)(void *user_data);
abc_task_fun_t user_task_fun=nullptr;
void abc_worker_process(){
abc_init_signals();
abc_process_t *ptr=&abc_processes[abc_process_slot];
if(user_task_fun){
user_task_fun((void*)ptr->priv);
}
}
abc_pid_t abc_spawn_process(const char*priv,int sz){
abc_pid_t pid;
if(sz<0||sz>ABC_PRIV_SZ){
return ABC_INVALID_PID;
}
int s=0;
for(s=0;s<abc_last_process;s++){
if(-1==abc_processes[s].pid){
break;
}
}
abc_process_slot=s;
if(priv&&sz>0){
memcpy(abc_processes[s].priv,priv,sz);
}
pid = fork();
switch(pid){
case -1:{
std::cout<<"fork failed"<<std::endl;
return ABC_INVALID_PID;
}
case 0:{
abc_parent=abc_pid;
abc_pid=abc_getpid();
abc_worker_process();
break;
}
default:
break;
}
if(0==pid){
exit(0);
}else{
abc_processes[s].pid=pid;
abc_last_process++;
}
return pid;
}
void abc_signal_workers(int signo){
for(int i=0;i<abc_last_process;i++){
abc_pid_t pid=abc_processes[i].pid;
if(pid>0){
if(-1==kill(pid,signo)){
std::cout<<"kill erorr"<<strerror(abc_errno)<<std::endl;
}
int status=0;
if(-1==waitpid(pid,&status,0)){
std::cout<<"waitpid erorr"<<strerror(abc_errno)<<" "<<status<<std::endl;
}
abc_processes[i].pid=-1;
}
}
abc_last_process=0;
}
int abc_worker_status(abc_pid_t pid){
int status;
int ret=waitpid(pid,&status,WNOHANG);
if(-1==ret){
std::cout<<pid<<strerror(abc_errno)<<std::endl;
}
return ret;
}
int abc_alive_workers(){
int counter=abc_last_process;
int sig_term=abc_signal_value(ABC_TERMINATE_SIGNAL);
int n=counter;
for(int i=n-1;i>=0;i--){
abc_pid_t pid=abc_processes[i].pid;
int alive=1;
if(pid>0){
if(pid==abc_worker_status(pid)){
kill(pid,sig_term);
abc_processes[i].pid=-1;
counter--;
alive=0;
}
}else{
counter--;
alive=0;
}
if(0==alive&&i==abc_last_process-1){
abc_last_process--;
}
}
return counter;
}
typedef struct{
int data1;
int data2;
}abc_user_t;
void test_task(void *priv){
abc_user_t *user=(abc_user_t*)priv;
int count=0;
int32_t last=TimeMillis();
while(g_running){
int32_t now=TimeMillis();
int32_t delta=now-last;
last=now;
std::cout<<abc_pid<<" "<<user->data1<<" "<<count<<" "<<delta<<std::endl;
if(count>10){
break;
}
usleep(30000);
count++;
}
}
int main(){
abc_init_signals();
abc_process_slot=0;
abc_last_process=0;
memset((void*)abc_processes,0,sizeof(abc_processes));
abc_parent=abc_getppid();
abc_pid=abc_getpid();
int n=2;
int alive=0;
abc_user_t user[2];
user[0].data1=1;
user[0].data2=2;
user[1].data1=3;
user[1].data2=4;
user_task_fun=test_task;
for(int i=0;i<n;i++){
if(abc_spawn_process((const char*)&user[i],sizeof(abc_user_t))>0){
alive++;
}
}
for(int i=0;i<ABC_MAX_PROCESSES;i++){
abc_pid_t pid=abc_processes[i].pid;
if(pid>0){
int ret=abc_worker_status(pid);
std::cout<<"check "<<pid<<" "<<ret<<std::endl;
}
}
while(g_running){
if(0==abc_alive_workers()){
break;
}
}
for(int i=0;i<abc_last_process;i++){
abc_pid_t pid=abc_processes[i].pid;
if(pid>0){
int ret=abc_worker_status(pid);
std::cout<<"check "<<pid<<" "<<ret<<std::endl;
}
}
return 0;
}
Build
g++ -o t_pro process_test.cc
网友评论