/*
* 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 "logger.h"
#define EXIT_PYERR 42
#define WPIPER_SIG 30
#define PYENTRY_FUNNAME "entrypoint"
#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;
};
/**@todo TODO on all request (when updating env ?) update stdin so
* python will be able to read the request content */
/**@brief the function that initialize the python worker
* @ingroup worker_process
* @param char* python_entrypoint a path to a python entrypoint
* @param int worker uid
* @param int semid for FCGI access
* @param int max request before worker restart
* @return 0 if exit avec max requests
*/
int work(int, 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 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*);
/**@brief Import & return the python entrypoint callable
* from PyFCGI_conf.py_entrymod & PyFCGI_conf.py_entryfun
*/
PyObject* import_entrypoint();
/**@brief Fetch stdout & stderr python flush() function
* @param PyObject* pystdout_flush
* @param PyObject* pystderr_flush
*/
void fetch_pyflush(PyObject**, PyObject**);
/**@brief Add . to the embed pythonpath
*/
void update_python_path();
/**@brief Create two pipes for stdout & stderr
* @ingroup worker_process
* @params int[2] pystdout
* @params int[2] pystderr
*/
void update_python_fd(int[2], int[2]);
/**@brief Clear then update python sys.environ using current FCI environ
* @ingroup worker_process
* @note The environ has to be set without a call to os.putenv, the problem
* is that the os.environ is a special mapping calling putenv on setitem...
* For these reason the os.environ will be replaced by a new dict instance for
* each request...
* @param PyObject* os module
*/
void update_pyenv(PyObject*, char**);
void log_expt(int priority);
#endif