This assumes readers have some knowledge of Linux system calls — at least a simple understanding of the fork operation and simple inter-process communication.
A brief exploration of the master-slave communication mechanism and process.
Entering the Reload Logic
Normally I reload Nginx on servers with roughly these two operations:
1 | nginx -s reload |
Reloading Nginx means sending the SIGHUP signal to Nginx’s master process; the master then
creates new workers and removes old workers.
Signal sending and handling isn’t this blog’s focus; if you’re interested in that process, see here:
Understanding nginx -s reload from the nginx 1.17.9 source
I’ll start directly from where the reload is checked:
1 | // src/os/unix/ngx_process_cycle.c |
Creating New Worker Processes
1 | static void |
Nginx’s Process Startup
The process-starting function is fairly complex; I removed some logic unused during reload. Let me explain the parts I understand.
1 | // src/os/unix/ngx_process.c |
Worker Process Initialization and State Handling
1 | static void |
The Parent-Child Communication Process
In Nginx, process communication is based on socketpair, with parent and child each holding one socket.
For the Nginx process creation part, I’ll write brief pseudocode, hoping to help understanding:
1 | To create the i-th process |
Deleting Old Workers
1 | static void |
Summary
References
How nginx master-worker processes work nginx source analysis 1 — inter-process communication mechanisms (semaphores)
Appendix
Thoughts on Code Optimization After socketpair Initialization
The original code is like this:
1 | // src/os/unix/ngx_process.c |
You can see the return statement is used multiple times, and ngx_close_channel is also used multiple times. Having looked at Linux kernel code before, the code above can actually be simplified with goto statements. Below is my simplified version:
1 | // C syntax is quite detail-oriented; I'll just gloss over it with pseudocode — maybe submit a PR someday |
Adding goto statements here actually simplifies much of the logic, and you needn’t worry about forgetting close_channel after errors — this feels like an appropriate place to use goto.
How to Print Your Own Logs in Nginx
I couldn’t figure out why calling ngx_log_error myself printed no logs, so I just used the fprintf(stderr, "hello world"); form directly — it’s only debugging anyway.
https://stackoverflow.com/questions/20187630/nginx-logging-in-module