摘要:在創(chuàng)建進(jìn)程和線程之間,主線程開始進(jìn)行信號處理函數(shù)的設(shè)置。事件循環(huán)結(jié)束前會調(diào)用函數(shù),該函數(shù)會檢查并執(zhí)行相應(yīng)的信號處理函數(shù)。
前言
信號處理是網(wǎng)絡(luò)庫不可或缺的一部分,不論是 ALARM、SIGTERM、SIGUSR1、SIGUSR2、SIGPIPE 等信號對程序的控制,還是 reactor、read、write 等操作被信號中斷的處理,都關(guān)系著整個框架程序的正常運(yùn)行。
Signal 數(shù)據(jù)結(jié)構(gòu)Signal 模塊的數(shù)據(jù)結(jié)構(gòu)很簡單,就是一個 swSignal 類型的數(shù)組,數(shù)組大小是 128。swSignal 中存放著信號的回調(diào)函數(shù) callback,信號 signo,是否啟用 active。
typedef void (*swSignalHander)(int); #define SW_SIGNO_MAX 128 typedef struct { swSignalHander callback; uint16_t signo; uint16_t active; } swSignal; static swSignal signals[SW_SIGNO_MAX];Signal 函數(shù) swSignal_none 屏蔽所有信號
如果當(dāng)前的線程不想要被信號中斷,那么就可以使用 swSignal_none 函數(shù)屏蔽所有的信號,這樣該進(jìn)程所有的函數(shù)都不會被信號中斷,編寫函數(shù)的時候就不用考慮被信號打斷的情況。
值得注意的是處理的信號 SIGKILL 和 SIGSTOP 無法被阻塞。
void swSignal_none(void) { sigset_t mask; sigfillset(&mask); int ret = pthread_sigmask(SIG_BLOCK, &mask, NULL); if (ret < 0) { swWarn("pthread_sigmask() failed. Error: %s[%d]", strerror(ret), ret); } }swSignal_add 添加信號
添加信號就是向 signals 數(shù)組添加一個新的信號元素,然后調(diào)用 swSignal_set 函數(shù)進(jìn)行信號處理函數(shù)的注冊。如果使用的是 signalfd,那么使用的是 swSignalfd_set 函數(shù)。
void swSignal_add(int signo, swSignalHander func) { #ifdef HAVE_SIGNALFD if (SwooleG.use_signalfd) { swSignalfd_set(signo, func); } else #endif { { signals[signo].callback = func; signals[signo].active = 1; signals[signo].signo = signo; swSignal_set(signo, swSignal_async_handler, 1, 0); } } }swSignal_set 設(shè)置信號處理函數(shù)
swSignal_set 函數(shù)主要是調(diào)用 sigaction 為整個進(jìn)程設(shè)置信號處理函數(shù)。如果設(shè)置 func 為 -1,信號處理函數(shù)是系統(tǒng)默認(rèn),如果 func 是 null,就會忽略該信號。如果 mask 為 1,那么在處理該信號的時候會阻塞所有信號,如果 mask 為 0,那么在處理該信號的時候就不會阻塞任何信號。
swSignalHander swSignal_set(int sig, swSignalHander func, int restart, int mask) { //ignore if (func == NULL) { func = SIG_IGN; } //clear else if ((long) func == -1) { func = SIG_DFL; } struct sigaction act, oact; act.sa_handler = func; if (mask) { sigfillset(&act.sa_mask); } else { sigemptyset(&act.sa_mask); } act.sa_flags = 0; if (sigaction(sig, &act, &oact) < 0) { return NULL; } return oact.sa_handler; }swSignal_async_handler 信號處理函數(shù)
Signal 模塊所有的信號處理函數(shù)都是 swSignal_async_handler,該函數(shù)會調(diào)用 signals 數(shù)組中信號元素的回調(diào)函數(shù)。對于進(jìn)程中存在 reactor(例如主線程或者 worker 進(jìn)程),只需設(shè)置 main_reactor->singal_no,等待 reactor 回調(diào)即可(一般是 swReactor_error 函數(shù)和 swReactor_onFinish 函數(shù))。對于沒有 reactor 的進(jìn)程,例如 manager 進(jìn)程,會直接調(diào)用回調(diào)函數(shù)。
值得注意的是,這種異步信號處理函數(shù)代碼一定要簡單,一定要是信號安全函數(shù),例如本例中只設(shè)置 SwooleG.main_reactor->singal_no,等待著返回主流程后再具體執(zhí)行回調(diào)函數(shù);而沒有 main_reactor 的進(jìn)程,就要著重注意回調(diào)函數(shù)是否是信號安全函數(shù)。因此從這方面來說,signalfd 有著天然的優(yōu)勢,它是文件描述符,由 epoll 統(tǒng)一管理,回調(diào)函數(shù)并不需要異步信號安全。
static void swSignal_async_handler(int signo) { if (SwooleG.main_reactor) { SwooleG.main_reactor->singal_no = signo; } else { //discard signal if (_lock) { return; } _lock = 1; swSignal_callback(signo); _lock = 0; } } void swSignal_callback(int signo) { if (signo >= SW_SIGNO_MAX) { swWarn("signal[%d] numberis invalid.", signo); return; } swSignalHander callback = signals[signo].callback; if (!callback) { swWarn("signal[%d] callback is null.", signo); return; } callback(signo); }swSignal_clear 清除所有信號
清除信號就是遍歷 signals 數(shù)組,將所有的有效信號元素的信號處理函數(shù)設(shè)置為系統(tǒng)默認(rèn)。如果使用的是 signalfd,那么調(diào)用 swSignalfd_clear 函數(shù)。
void swSignal_clear(void) { #ifdef HAVE_SIGNALFD if (SwooleG.use_signalfd) { swSignalfd_clear(); } else #endif { int i; for (i = 0; i < SW_SIGNO_MAX; i++) { if (signals[i].active) { { swSignal_set(signals[i].signo, (swSignalHander) -1, 1, 0); } } } } bzero(&signals, sizeof(signals)); }swSignalfd_init—signalfd 信號初始化
使用 signalfd 之前需要將 signalfd_mask、signals 重置。
static sigset_t signalfd_mask; static int signal_fd = 0; void swSignalfd_init() { sigemptyset(&signalfd_mask); bzero(&signals, sizeof(signals)); }swSignalfd_setup——signalfd 信號啟用
signalfd 信號啟用需要兩個步驟,調(diào)用 signalfd 函數(shù)創(chuàng)建信號描述符,reactor->add 添加到 reactor 事件循環(huán)中。
int swSignalfd_setup(swReactor *reactor) { if (signal_fd == 0) { signal_fd = signalfd(-1, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC); if (signal_fd < 0) { swWarn("signalfd() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } SwooleG.signal_fd = signal_fd; if (sigprocmask(SIG_BLOCK, &signalfd_mask, NULL) == -1) { swWarn("sigprocmask() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } reactor->setHandle(reactor, SW_FD_SIGNAL, swSignalfd_onSignal); reactor->add(reactor, signal_fd, SW_FD_SIGNAL); return SW_OK; } else { swWarn("signalfd has been created"); return SW_ERR; } }swSignalfd_set——signalfd 信號處理函數(shù)的設(shè)置
使用 signalfd 函數(shù)對 signal_fd 設(shè)置信號處理函數(shù)的時候,要先將對應(yīng)的信號進(jìn)行屏蔽 sigprocmask,否則很可能會額外執(zhí)行系統(tǒng)的默認(rèn)信號處理函數(shù)。
static void swSignalfd_set(int signo, swSignalHander callback) { if (callback == NULL && signals[signo].active) { sigdelset(&signalfd_mask, signo); bzero(&signals[signo], sizeof(swSignal)); } else { sigaddset(&signalfd_mask, signo); signals[signo].callback = callback; signals[signo].signo = signo; signals[signo].active = 1; } if (signal_fd > 0) { sigprocmask(SIG_BLOCK, &signalfd_mask, NULL); signalfd(signal_fd, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC); } }swSignalfd_onSignal——signalfd 信號處理函數(shù)
swSignalfd_onSignal 函數(shù)由 reactor 事件循環(huán)直接調(diào)用。
static int swSignalfd_onSignal(swReactor *reactor, swEvent *event) { int n; struct signalfd_siginfo siginfo; n = read(event->fd, &siginfo, sizeof(siginfo)); if (n < 0) { swWarn("read from signalfd failed. Error: %s[%d]", strerror(errno), errno); return SW_OK; } if (siginfo.ssi_signo >= SW_SIGNO_MAX) { swWarn("unknown signal[%d].", siginfo.ssi_signo); return SW_OK; } if (signals[siginfo.ssi_signo].active) { if (signals[siginfo.ssi_signo].callback) { signals[siginfo.ssi_signo].callback(siginfo.ssi_signo); } else { swWarn("signal[%d] callback is null.", siginfo.ssi_signo); } } return SW_OK; }swSignalfd_clear——signalfd 信號處理函數(shù)的清除
static void swSignalfd_clear() { if (signal_fd) { if (sigprocmask(SIG_UNBLOCK, &signalfd_mask, NULL) < 0) { swSysError("sigprocmask(SIG_UNBLOCK) failed."); } close(signal_fd); bzero(&signalfd_mask, sizeof(signalfd_mask)); } signal_fd = 0; }Signal 信號的應(yīng)用 master 線程信號
在調(diào)用 swoole_server->start 函數(shù)之后,master 主進(jìn)程開始創(chuàng)建 manager 進(jìn)程與 reactor 線程。在創(chuàng)建 manager 進(jìn)程和 reactor 線程之間,master 主線程開始進(jìn)行信號處理函數(shù)的設(shè)置。
可以看到,master 進(jìn)程的信號處理函數(shù)是 swServer_signal_hanlder,并設(shè)置忽略了 SIGPIPE、SIGHUP 函數(shù)。
SIGPIPE 一般發(fā)生于對端連接已關(guān)閉,服務(wù)端仍然在發(fā)送數(shù)據(jù)的情況,如果沒有忽略該信號,很可能主進(jìn)程會異常終止。
SIGHUP 信號一般發(fā)生于終端關(guān)閉時,該信號被發(fā)送到 session 首進(jìn)程,也就是 master 主進(jìn)程。如果不忽略該信號,關(guān)閉終端的時候,主進(jìn)程會默認(rèn)異常退出。
SIGHUP會在以下3種情況下被發(fā)送給相應(yīng)的進(jìn)程:1、終端關(guān)閉時,該信號被發(fā)送到session首進(jìn)程以及作為job提交的進(jìn)程(即用 & 符號提交的進(jìn)程)
2、session首進(jìn)程退出時,該信號被發(fā)送到該session中的前臺進(jìn)程組中的每一個進(jìn)程
3、若父進(jìn)程退出導(dǎo)致進(jìn)程組成為孤兒進(jìn)程組,且該進(jìn)程組中有進(jìn)程處于停止?fàn)顟B(tài)(收到SIGSTOP或SIGTSTP信號),該信號會被發(fā)送到該進(jìn)程組中的每一個進(jìn)程。
int swServer_start(swServer *serv) { ... if (factory->start(factory) < 0)//創(chuàng)建 manager 進(jìn)程 { return SW_ERR; } //signal Init swServer_signal_init(serv); ret = swServer_start_proxy(serv); ... } void swServer_signal_init(swServer *serv) { swSignal_add(SIGPIPE, NULL); swSignal_add(SIGHUP, NULL); if (serv->factory_mode != SW_MODE_BASE) { swSignal_add(SIGCHLD, swServer_signal_hanlder); } swSignal_add(SIGUSR1, swServer_signal_hanlder); swSignal_add(SIGUSR2, swServer_signal_hanlder); swSignal_add(SIGTERM, swServer_signal_hanlder); #ifdef SIGRTMIN swSignal_add(SIGRTMIN, swServer_signal_hanlder); #endif swSignal_add(SIGALRM, swSystemTimer_signal_handler); //for test swSignal_add(SIGVTALRM, swServer_signal_hanlder); swServer_set_minfd(SwooleG.serv, SwooleG.signal_fd); }
swServer_signal_hanlder 函數(shù)中是對其他信號函數(shù)的處理,
SIGTERM 是終止信號,用于終止 master 線程的 reactor 線程。
SIGALRM 是鬧鐘信號,我們在上一篇中已經(jīng)詳細(xì)介紹過。
SIGCHLD 是子進(jìn)程退出信號,如果調(diào)用 waitpid 之后,得到的是 manager 進(jìn)程的進(jìn)程 id,說明 manager 進(jìn)程無故退出。
SIGVTALRM 信號也是鬧鐘信號,是 setitimer 函數(shù)以 ITIMER_VIRTUAL 進(jìn)程在用戶態(tài)下花費(fèi)的時間進(jìn)行鬧鐘設(shè)置的時候觸發(fā),swoole 里均以 ITIMER_REAL 系統(tǒng)真實(shí)的時間來計(jì)算,因此理論上并不會有此信號,
SIGUSR1、SIGUSR2 是 manager 進(jìn)程默認(rèn)重啟 worker 進(jìn)程的信號,只重啟 task 進(jìn)程使用 SIGUSR2 信號,重啟所有 worker 進(jìn)程使用 SIGUSR1,該信號也是 swoole_server->reload 函數(shù)發(fā)送給 manager 的信號。
SIGRTMIN 信號被用于實(shí)現(xiàn)重新打開日志文件。在服務(wù)器程序運(yùn)行期間日志文件被 mv 移動或 unlink 刪除后,日志信息將無法正常寫入,這時可以向 Server 發(fā)送 SIGRTMIN 信號
static void swServer_signal_hanlder(int sig) { swTraceLog(SW_TRACE_SERVER, "signal[%d] triggered.", sig); swServer *serv = SwooleG.serv; int status; pid_t pid; switch (sig) { case SIGTERM: if (SwooleG.main_reactor) { SwooleG.main_reactor->running = 0; } else { SwooleG.running = 0; } swNotice("Server is shutdown now."); break; case SIGALRM: swSystemTimer_signal_handler(SIGALRM); break; case SIGCHLD: if (!SwooleG.running) { break; } if (SwooleG.serv->factory_mode == SW_MODE_SINGLE) { break; } pid = waitpid(-1, &status, WNOHANG); if (pid > 0 && pid == serv->gs->manager_pid) { swWarn("Fatal Error: manager process exit. status=%d, signal=%d.", WEXITSTATUS(status), WTERMSIG(status)); } break; /** * for test */ case SIGVTALRM: swWarn("SIGVTALRM coming"); break; /** * proxy the restart signal */ case SIGUSR1: case SIGUSR2: if (SwooleG.serv->factory_mode == SW_MODE_SINGLE) { if (serv->gs->event_workers.reloading) { break; } serv->gs->event_workers.reloading = 1; serv->gs->event_workers.reload_init = 0; } else { kill(serv->gs->manager_pid, sig); } break; default: #ifdef SIGRTMIN if (sig == SIGRTMIN) { int i; swWorker *worker; for (i = 0; i < SwooleG.serv->worker_num + serv->task_worker_num + SwooleG.serv->user_worker_num; i++) { worker = swServer_get_worker(SwooleG.serv, i); kill(worker->pid, SIGRTMIN); } if (SwooleG.serv->factory_mode == SW_MODE_PROCESS) { kill(serv->gs->manager_pid, SIGRTMIN); } swServer_reopen_log_file(SwooleG.serv); } #endif break; } }
master 線程在 reactor 事件循環(huán)中負(fù)責(zé)接受客戶端的請求,在 reactor 事件循環(huán)中 epoll_wait 函數(shù)可能會被信號中斷,這時程序會首先調(diào)用 swSignal_async_handler 設(shè)置 reactor->singal_no,然后返回 n < 0,執(zhí)行 swSignal_callback 對應(yīng)的信號處理函數(shù)。
static int swServer_start_proxy(swServer *serv) { main_reactor->setHandle(main_reactor, SW_FD_LISTEN, swServer_master_onAccept); ... return main_reactor->wait(main_reactor, NULL); } static int swReactorEpoll_wait(swReactor *reactor, struct timeval *timeo) { ... while (reactor->running > 0) { n = epoll_wait(epoll_fd, events, max_event_num, msec); if (n < 0) { if (swReactor_error(reactor) < 0) { swWarn("[Reactor#%d] epoll_wait failed. Error: %s[%d]", reactor_id, strerror(errno), errno); return SW_ERR; } else { continue; } } ... handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type); ret = handle(reactor, &event); ... if (reactor->onFinish != NULL) { reactor->onFinish(reactor); } } ... } static sw_inline int swReactor_error(swReactor *reactor) { switch (errno) { case EINTR: if (reactor->singal_no) { swSignal_callback(reactor->singal_no); reactor->singal_no = 0; } return SW_OK; } return SW_ERR; }
而在 reactor 事件循環(huán)中,reactor 中讀寫就緒的回調(diào)函數(shù)中仍然可能被信號中斷,例如 accept 函數(shù),即使 采用非阻塞也有可能被信號中斷,這個時候需要忽略這種錯誤,繼續(xù)進(jìn)行 accept 直到 EAGAIN 錯誤。事件循環(huán)結(jié)束前會調(diào)用 onFinish 函數(shù),該函數(shù)會檢查 reactor->singal_no 并執(zhí)行相應(yīng)的信號處理函數(shù)。
int swServer_master_onAccept(swReactor *reactor, swEvent *event) { ... for (i = 0; i < SW_ACCEPT_MAX_COUNT; i++) { new_fd = accept(event->fd, (struct sockaddr *) &client_addr, &client_addrlen); if (new_fd < 0) { switch (errno) { case EAGAIN: return SW_OK; case EINTR: continue; ... } } ... } static void swReactor_onFinish(swReactor *reactor) { //check signal if (reactor-singal_no) { swSignal_callback(reactor->singal_no); reactor->singal_no = 0; } swReactor_onTimeout_and_Finish(reactor); }reactor 線程信號
對于 reactor 線程來說,承擔(dān)了大量 socket 流量消息的收發(fā),因此 reactor 不應(yīng)該頻繁的被信號中斷影響 reactor 事件循環(huán)的效率。因此,在初始化截?cái)啵绦蚓驼{(diào)用 swSignal_none 阻塞了所有的信號,所有的信號處理都由 master 主線程來處理。當(dāng)然 SIGTERM、SIGSTOP 等信號無法屏蔽。
static int swReactorThread_loop(swThreadParam *param) { ... swSignal_none(); ... }manager 進(jìn)程中信號的應(yīng)用
manager 進(jìn)程大部分信號的處理與 master 線程類似,唯一不同的是多了 SIGID 信號的處理,該信號是由 worker 進(jìn)程發(fā)送給 manager 進(jìn)程通知重啟服務(wù)時使用的。
當(dāng)發(fā)生信號時,wait 函數(shù)將會被中斷,返回的 pid 小于 0,此時檢查被中斷的信號并相應(yīng)進(jìn)行操作,
static int swManager_loop(swFactory *factory) { ... swSignal_add(SIGHUP, NULL); swSignal_add(SIGTERM, swManager_signal_handle); swSignal_add(SIGUSR1, swManager_signal_handle); swSignal_add(SIGUSR2, swManager_signal_handle); swSignal_add(SIGIO, swManager_signal_handle); #ifdef SIGRTMIN swSignal_add(SIGRTMIN, swManager_signal_handle); if (serv->manager_alarm > 0) { alarm(serv->manager_alarm); swSignal_add(SIGALRM, swManager_signal_handle); } SwooleG.main_reactor = NULL; ... while (SwooleG.running > 0) { _wait: pid = wait(&status); if (ManagerProcess.read_message) {...} if (pid < 0) { if (ManagerProcess.alarm == 1) {} if (ManagerProcess.reloading == 0) { error: if (errno != EINTR) { swSysError("wait() failed."); } continue; } else if (ManagerProcess.reload_all_worker == 1) {...} else if (ManagerProcess.reload_task_worker == 1) {...} else { goto error; } } } swSignal_none(); } static void swManager_signal_handle(int sig) { switch (sig) { case SIGTERM: SwooleG.running = 0; break; /** * reload all workers */ case SIGUSR1: if (ManagerProcess.reloading == 0) { ManagerProcess.reloading = 1; ManagerProcess.reload_all_worker = 1; } break; /** * only reload task workers */ case SIGUSR2: if (ManagerProcess.reloading == 0) { ManagerProcess.reloading = 1; ManagerProcess.reload_task_worker = 1; } break; case SIGIO: ManagerProcess.read_message = 1; break; case SIGALRM: ManagerProcess.alarm = 1; break; default: #ifdef SIGRTMIN if (sig == SIGRTMIN) { swServer_reopen_log_file(SwooleG.serv); } #endif break; } }worker 進(jìn)程信號
與 master 進(jìn)程類似,也要忽略 SIGHUP、SIGPIPE 信號,不同的是忽略了 SIGUSR1、SIGUSR2 信號。對于 SIGTERM 信號,worker 進(jìn)程采取了異步關(guān)閉的措施,并不會強(qiáng)硬終止進(jìn)程,而是要等到 reactor 事件循環(huán)完畢。
void swWorker_signal_init(void) { swSignal_clear(); /** * use user settings */ SwooleG.use_signalfd = SwooleG.enable_signalfd; swSignal_add(SIGHUP, NULL); swSignal_add(SIGPIPE, NULL); swSignal_add(SIGUSR1, NULL); swSignal_add(SIGUSR2, NULL); //swSignal_add(SIGINT, swWorker_signal_handler); swSignal_add(SIGTERM, swWorker_signal_handler); swSignal_add(SIGALRM, swSystemTimer_signal_handler); //for test swSignal_add(SIGVTALRM, swWorker_signal_handler); #ifdef SIGRTMIN swSignal_add(SIGRTMIN, swWorker_signal_handler); #endif } void swWorker_signal_handler(int signo) { switch (signo) { case SIGTERM: /** * Event worker */ if (SwooleG.main_reactor) { swWorker_stop(); } /** * Task worker */ else { SwooleG.running = 0; } break; case SIGALRM: swSystemTimer_signal_handler(SIGALRM); break; /** * for test */ case SIGVTALRM: swWarn("SIGVTALRM coming"); break; case SIGUSR1: break; case SIGUSR2: break; default: #ifdef SIGRTMIN if (signo == SIGRTMIN) { swServer_reopen_log_file(SwooleG.serv); } #endif break; } }task 進(jìn)程信號
task 進(jìn)程不同于 worker 進(jìn)程,使用的并不是 reactor + 非阻塞文件描述符,而是阻塞式描述符,并沒有 reactor 來告知消息的到來。因此 task 進(jìn)程的循環(huán)是阻塞在各個函數(shù)當(dāng)中的。只有文件描述符可讀,或者信號到來,才會從阻塞中返回。
當(dāng) swMsgQueue_pop、accept、read 等函數(shù)被信號中斷后,信號處理函數(shù)會被執(zhí)行,之后會返回 n < 0,這個時候由于信號處理函數(shù)已經(jīng)被執(zhí)行,因此只需要 continue 即可。對于鬧鐘信號,信號到來,還需要調(diào)用 swTimer_select 來篩選已經(jīng)到時間的任務(wù)。
static void swTaskWorker_signal_init(void) { swSignal_set(SIGHUP, NULL, 1, 0); swSignal_set(SIGPIPE, NULL, 1, 0); swSignal_set(SIGUSR1, swWorker_signal_handler, 1, 0); swSignal_set(SIGUSR2, NULL, 1, 0); swSignal_set(SIGTERM, swWorker_signal_handler, 1, 0); swSignal_set(SIGALRM, swSystemTimer_signal_handler, 1, 0); #ifdef SIGRTMIN swSignal_set(SIGRTMIN, swWorker_signal_handler, 1, 0); #endif } static int swProcessPool_worker_loop(swProcessPool *pool, swWorker *worker) { ... while (SwooleG.running > 0 && task_n > 0) { if (pool->use_msgqueue) { n = swMsgQueue_pop(pool->queue, (swQueue_data *) &out, sizeof(out.buf)); if (n < 0 && errno != EINTR) { swSysError("[Worker#%d] msgrcv() failed.", worker->id); break; } } else if (pool->use_socket) { int fd = accept(pool->stream->socket, NULL, NULL); if (fd < 0) { if (errno == EAGAIN || errno == EINTR) { continue; } else { swSysError("accept(%d) failed.", pool->stream->socket); break; } } n = swStream_recv_blocking(fd, (void*) &out.buf, sizeof(out.buf)); if (n == SW_CLOSE) { close(fd); continue; } pool->stream->last_connection = fd; } else { n = read(worker->pipe_worker, &out.buf, sizeof(out.buf)); if (n < 0 && errno != EINTR) { swSysError("[Worker#%d] read(%d) failed.", worker->id, worker->pipe_worker); } } /** * timer */ if (n < 0) { if (errno == EINTR && SwooleG.signal_alarm) { alarm_handler: SwooleG.signal_alarm = 0; swTimer_select(&SwooleG.timer); } continue; } /** * do task */ worker->status = SW_WORKER_BUSY; worker->request_time = time(NULL); ret = pool->onTask(pool, &out.buf); worker->status = SW_WORKER_IDLE; worker->request_time = 0; worker->traced = 0; if (pool->use_socket && pool->stream->last_connection > 0) { int _end = 0; swSocket_write_blocking(pool->stream->last_connection, (void *) &_end, sizeof(_end)); close(pool->stream->last_connection); pool->stream->last_connection = 0; } /** * timer */ if (SwooleG.signal_alarm) { goto alarm_handler; } if (ret >= 0 && !worker_task_always) { task_n--; } } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/29380.html
摘要:當(dāng)其就緒時,會調(diào)用執(zhí)行定時函數(shù)。進(jìn)程超時停止進(jìn)程將要停止時,并不會立刻停止,而是會等待事件循環(huán)結(jié)束后停止,這時為了防止進(jìn)程不退出,還設(shè)置了的延遲,超過就會停止該進(jìn)程。當(dāng)允許空閑時間小于時,統(tǒng)一每隔檢測空閑連接。 前言 swoole 的 timer 模塊功能有三個:用戶定時任務(wù)、剔除空閑連接、更新 server 時間。timer 模塊的底層有兩種,一種是基于 alarm 信號,一種是基于...
摘要:如果為,就不斷循環(huán),殺死或者啟動相應(yīng)的進(jìn)程,如果為,那么就關(guān)閉所有的進(jìn)程,調(diào)用函數(shù)退出程序。調(diào)用函數(shù),監(jiān)控已結(jié)束的進(jìn)程如果函數(shù)返回異常,很有可能是被信號打斷。函數(shù)主要用于調(diào)用函數(shù),進(jìn)而調(diào)用函數(shù) swManager_loop 函數(shù) manager 進(jìn)程管理 manager 進(jìn)程開啟的時候,首先要調(diào)用 onManagerStart 回調(diào) 添加信號處理函數(shù) swSignal_add,S...
摘要:清空主進(jìn)程殘留的定時器與信號。設(shè)定為執(zhí)行回調(diào)函數(shù)如果在回調(diào)函數(shù)中調(diào)用了異步系統(tǒng),啟動函數(shù)進(jìn)行事件循環(huán)。因此為了區(qū)分兩者,規(guī)定并不允許兩者同時存在。 前言 swoole-1.7.2 增加了一個進(jìn)程管理模塊,用來替代 PHP 的 pcntl 擴(kuò)展。 PHP自帶的pcntl,存在很多不足,如 pcntl 沒有提供進(jìn)程間通信的功能 pcntl 不支持重定向標(biāo)準(zhǔn)輸入和輸出 pcntl 只...
前言 作為一個網(wǎng)絡(luò)框架,最為核心的就是消息的接受與發(fā)送。高效的 reactor 模式一直是眾多網(wǎng)絡(luò)框架的首要選擇,本節(jié)主要講解 swoole 中的 reactor 模塊。 UNP 學(xué)習(xí)筆記——IO 復(fù)用 Reactor 的數(shù)據(jù)結(jié)構(gòu) Reactor 的數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜,首先 object 是具體 Reactor 對象的首地址,ptr 是擁有 Reactor 對象的類的指針, event_nu...
摘要:函數(shù)事件循環(huán)在事件循環(huán)時,如果使用的是消息隊(duì)列,那么就不斷的調(diào)用從消息隊(duì)列中取出數(shù)據(jù)。獲取后的數(shù)據(jù)調(diào)用回調(diào)函數(shù)消費(fèi)消息之后,向中發(fā)送空數(shù)據(jù),告知進(jìn)程已消費(fèi),并且關(guān)閉新連接。 swManager_start 創(chuàng)建進(jìn)程流程 task_worker 進(jìn)程的創(chuàng)建可以分為三個步驟:swServer_create_task_worker 申請所需的內(nèi)存、swTaskWorker_init 初始化...
閱讀 2907·2021-11-15 18:02
閱讀 3801·2021-10-14 09:43
閱讀 3733·2021-09-08 10:41
閱讀 2522·2019-08-30 15:53
閱讀 1804·2019-08-30 14:14
閱讀 1943·2019-08-29 16:12
閱讀 3139·2019-08-29 14:03
閱讀 1280·2019-08-29 13:46