/* * Copyright (C) 2019 Weber Yann * * This file is part of PyFCGI. * * PyFCGI is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * PyFCGI is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with PyFCGI. If not, see . */ /**@defgroup worker_process Worker processes * @brief Processus handling python execution with @ref work() function * * This kind of process are @ref spawn() by a @ref work_master_proc * @section Running Python * Running embed python in FCGI mean serving multiple requests with a single * python process, meaning : * - environnement variable of the living Python process need to be updated * - we need a way to communicate with python code * * @subsection worker_proc_ipc Communicating with python * sys.stdout & sys.stderr will be used to communicate in python. Shortly * after python initialize @ref update_python_fd() update these two file * objects with freshly created pipes. * * @subsubsection worker_proc_ipc_piper The piper process * * When a request arrive, the worker process fork again in a @ref worker_piper() child * process that will read the two pipes. Sending stdout to FCGI using printf * and stderr to syslog. * * @subsection worker_proc_environ Updating os.environ * os.environ is a special kind of dictionnary, automatically calling * os.putenv() function. This function will attempt (and succeed) to update * the real process environnement, making a nasty conflict with libfcgi (trying * to free an environnement it did not create anymore...). * * The os.environ is replaced by a simple python dict by @ref update_pyenv() * once a request. * * @see update_python_path() * * @ingroup processes * @ingroup work_master_proc */ /**@file pyworker.h * @ingroup worker_process */ #ifndef _PYWORKER__H___ #define _PYWORKER__H___ #include "config.h" #include #include /* fcgi library; put it first*/ #define PY_SSIZE_T_CLEAN #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logger.h" #include "pyutils.h" #include "python_pyfcgi.h" #define WPIPER_SIG 30 #define PIPER_STACK_SZ (1024 * 1024 * 4) //extern char **environ; typedef unsigned long int pywrkid_t; typedef struct piper_args_s piper_args_t; struct piper_args_s { int wrk_id, pystdout, pystderr, ctl_pipe; //int req_id; FCGX_Stream *out; struct sigaction *act; }; extern PyObject* response_status; extern PyObject* response_headers; /**@brief The function that initialize the alternate python worker * @ingroup worker_process * * This function handles python worker by running a PEP333 application function. * The start_response() function set @ref response_status and * @ref response_headers globals. * @param char* python_entrypoint a path to a python entrypoint * @param int worker uid * @return 0 if exit avec max requests */ int work333(int); /**@brief the function that initialize the alternate python worker * @ingroup worker_process * * This function handles python worker using stdout to communicate with * FCGI. This function clones for each request, running worker_piper() * @param char* python_entrypoint a path to a python entrypoint * @param int worker uid * @return 0 if exit avec max requests */ int work(int); /**@brief function for a subprocess designed to read stdin & stdout from * python & forward them to syslog or FCGI * @ingroup worker_process * @param int worker id * @param int request id * @param int pystdout * @param int pystderr * @param int ctlpipe a pipe closed when the process is ready * @note Exit after signal sent by parent & when poll indicate the pipes are * empty */ /* void worker_piper(int, int, int, int, int, FCGX_Stream*); */ int worker_piper(void*); /**@brief worker piper sigaction handler */ void worker_piper_sighandler(int); /**@brief empty pipes and log content for pep333 workers * @todo enhance logging : 1 lines per logline + line counter ? * @todo sys.stdout & sys.stderr can have an implementation like * libpyfcgi.IoIn to avoir useless buffering * @param int pipes for stdout * @param int pipes for stderr * @param PyObject[2] python flush methods */ void worker_log_pipes(int, int, PyObject*[2]); /**@brief Attempt to read the request size from ctl pipe * @param int ctl pipe read fd * @param size_t* rep_sz * @return 0 if no error */ int ctl_get_rep_sz(int, size_t*); void worker_sighandler(int); void worker_sigalrmhandler(int signum); #endif