FastCGI Process Manager Architecture and Implementation in PHP7

FastCGI Process Manager (FPM) is a process manager for PHP's FastCGI execution mode. Its core functionality involves managing worker processes that handle FastCGI requests.

FastCGI Protocol Fundamentals

FastCGI is a application-layer communication protocol between web servers (like Nginx or Apache) and application processors. PHP implements the FastCGI protocol for request parsing but delegates network handling to the web server.

Process Management Models

PHP-FPM employs a multi-process model where a master process manages worker pools. Each worker pool listens on a designated socket and contains multiple worker processes. Unlike event-driven models (like Nginx's), an FPM worker process handles one request at a time in a blocking manner before accepting the next.

Configuration and Process Structure

Worker pools are defined in php-fpm.conf using [pool] sections:

[web1]
listen = 127.0.0.1:9000

[web2]
listen = 127.0.0.1:9001

The internal structure for a worker pool:

struct worker_pool {
    struct worker_pool *next_pool;
    struct pool_config *settings;
    int socket_descriptor;
    struct worker_process *worker_list;
    int active_workers;
    struct scoreboard *performance_data;
    // ... additional fields
}

Initialization Process

The FPM startup sequence in fpm_main.c:

int main(int argc, char *argv[]) {
    sapi_startup(&cgi_sapi_module);
    
    if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {
        return FPM_EXIT_SOFTWARE;
    }
    
    fpm_init();
    fpm_is_running = 1;
    
    int fastcgi_socket = fpm_run(&max_requests);
    
    // Worker process execution continues here
    return process_requests(fastcgi_socket);
}

The fpm_init() function performs critical setup:

  1. Configuration parsing
  2. Shared memory allocation for scoreboarding
  3. Signal handler registration
  4. Socket creation for each pool
  5. Event system initialization

Request Processing Lifecycle

Worker processes follow this sequence:

  1. Request Acceptance: Block on fcgi_accept_request()
  2. Request Parsing: Parse FastCGI protocol headers and content
  3. Request Initialization: Execute php_request_startup(), triggering extension PHP_RINIT_FUNCTION() calls
  4. Script Execution: Compile and execute PHP code via php_execute_script()
  5. Request Completion: Execute php_request_shutdown(), triggering extension PHP_RSHUTDOWN_FUNCTION() calls

Processing stages are tracked in the scoreboard:

  • FPM_REQUEST_ACCEPTING: Waiting for request
  • FPM_REQUEST_READING_HEADERS: Reading FastCGI headers
  • FPM_REQUEST_INFO: Processing request metadata
  • FPM_REQUEST_EXECUTING: Executing PHP script
  • FPM_REQUEST_FINISHED: Request comlpeted

Process Management Strategies

FPM supports three process management approaches:

Static Pool Management

Worker count remains fixed at pm.max_children. No dynamic scaling occurs.

Dynamic Pool Management

Workers scale between pm.min_spare_servers and pm.max_spare_servers boundaries, with total not exceeding pm.max_children.

On-Demand Pool Management

Workers spawn only when requests arrive, up to pm.max_children. Idle workers terminate after pm.process_idle_timeout.

Master Process Event Loop

The master process enters an event loop after initialization:

void fpm_event_loop(int error_code) {
    // Setup signal handling via pipe
    fpm_event_set(&signal_event, signal_pipe[0], 
                  FPM_EV_READ, &handle_signal, NULL);
    fpm_event_add(&signal_event, 0);
    
    // Configure heartbeat for request timeout monitoring
    if (fpm_globals.heartbeat_interval > 0) {
        setup_heartbeat_timer();
    }
    
    // Regular process maintenance
    schedule_process_maintenance();
    
    while (1) {
        process_events();
    }
}

Signal Handling Mechanism

Master process handles several signals through a pipe notification system:

  • SIGTERM/SIGINT/SIGQUIT: Graceful shutdown
  • SIGUSR1: Log file rotation
  • SIGUSR2: Process restart
  • SIGCHLD: Worker process termination cleanup

Process Maintenance Timer

A periodic timer (approximately 1 second) manages dynamic and on-demand pools:

static void maintain_worker_pools(struct timeval *current_time) {
    for (pool = all_pools; pool; pool = pool->next_pool) {
        int idle_count = 0;
        int active_count = 0;
        struct worker *oldest_idle = NULL;
        
        // Count idle and active workers
        for (worker = pool->worker_list; worker; worker = worker->next) {
            if (worker_is_idle(worker)) {
                idle_count++;
                if (!oldest_idle || worker->idle_start < oldest_idle->idle_start) {
                    oldest_idle = worker;
                }
            } else {
                active_count++;
            }
        }
        
        // On-demand pool management
        if (pool->config->management_mode == ON_DEMAND && oldest_idle) {
            if (oldest_idle->idle_duration > pool->config->idle_timeout) {
                terminate_worker(oldest_idle->process_id);
            }
            continue;
        }
        
        // Dynamic pool management
        if (pool->config->management_mode == DYNAMIC) {
            if (idle_count > pool->config->max_spare_workers && oldest_idle) {
                terminate_worker(oldest_idle->process_id);
            }
            if (idle_count < pool->config->min_spare_workers && 
                pool->total_workers < pool->config->max_workers) {
                spawn_new_worker(pool);
            }
        }
    }
}

Request Timeout Enforcement

When request_terminate_timeout is configured, the master monitors request duration:

static void check_request_timeouts(struct timeval *current_time) {
    for (pool = all_pools; pool; pool = pool->next_pool) {
        int terminate_limit = pool->config->request_terminate_timeout;
        int slow_log_limit = pool->config->request_slowlog_timeout;
        
        if (terminate_limit || slow_log_limit) {
            for (worker = pool->worker_list; worker; worker = worker->next) {
                monitor_worker_timeout(worker, current_time, 
                                      terminate_limit, slow_log_limit);
            }
        }
    }
}

Worker processes exceeding the timeout receive termination signals, and slow requests are logged when exceeding request_slowlog_timeout.

Inter-Process Communication

The master process monitors worker status through shared scoreboard memory rather than direct communication. Worker termination commands are sent via signals.

Tags: PHP-FPM FastCGI Process Management Web Server Architecture PHP Internals

Posted on Wed, 13 May 2026 18:06:13 +0000 by tomkure