Tests about a simple python3 fastcgi runner using libfcgi and the Python-C API.
python
c
wsgi
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pyworker.h 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Copyright (C) 2019 Weber Yann
  3. *
  4. * This file is part of PyFCGI.
  5. *
  6. * PyFCGI is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * any later version.
  10. *
  11. * PyFCGI is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with PyFCGI. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /**@defgroup worker_process Worker processes
  20. * @brief Processus handling python execution with @ref work() function
  21. *
  22. * This kind of process are @ref spawn() by a @ref work_master_proc
  23. * @section Running Python
  24. * Running embed python in FCGI mean serving multiple requests with a single
  25. * python process, meaning :
  26. * - environnement variable of the living Python process need to be updated
  27. * - we need a way to communicate with python code
  28. *
  29. * @subsection worker_proc_ipc Communicating with python
  30. * sys.stdout & sys.stderr will be used to communicate in python. Shortly
  31. * after python initialize @ref update_python_fd() update these two file
  32. * objects with freshly created pipes.
  33. *
  34. * @subsubsection worker_proc_ipc_piper The piper process
  35. *
  36. * When a request arrive, the worker process fork again in a @ref worker_piper() child
  37. * process that will read the two pipes. Sending stdout to FCGI using printf
  38. * and stderr to syslog.
  39. *
  40. * @subsection worker_proc_environ Updating os.environ
  41. * os.environ is a special kind of dictionnary, automatically calling
  42. * os.putenv() function. This function will attempt (and succeed) to update
  43. * the real process environnement, making a nasty conflict with libfcgi (trying
  44. * to free an environnement it did not create anymore...).
  45. *
  46. * The os.environ is replaced by a simple python dict by @ref update_pyenv()
  47. * once a request.
  48. *
  49. * @see update_python_path()
  50. *
  51. * @ingroup work_master_proc
  52. */
  53. /**@file pyworker.h
  54. * @ingroup worker_process
  55. */
  56. #ifndef _PYWORKER__H___
  57. #define _PYWORKER__H___
  58. #include "config.h"
  59. #include <fcgiapp.h>
  60. #include <fcgi_stdio.h> /* fcgi library; put it first*/
  61. #define PY_SSIZE_T_CLEAN
  62. #include <Python.h>
  63. #include <unistd.h>
  64. #include <fcntl.h>
  65. #include <syslog.h>
  66. #include <signal.h>
  67. #include <limits.h>
  68. #include <poll.h>
  69. #include <sched.h>
  70. #include <signal.h>
  71. #include <sys/types.h>
  72. #include <sys/ipc.h>
  73. #include <sys/sem.h>
  74. #include <sys/wait.h>
  75. #include "logger.h"
  76. #include "pyutils.h"
  77. #include "python_pyfcgi.h"
  78. #define WPIPER_SIG 30
  79. #define PIPER_STACK_SZ (1024 * 1024 * 4)
  80. //extern char **environ;
  81. typedef unsigned long int pywrkid_t;
  82. typedef struct piper_args_s piper_args_t;
  83. struct piper_args_s
  84. {
  85. int wrk_id, pystdout, pystderr, ctl_pipe;
  86. //int req_id;
  87. FCGX_Stream *out;
  88. struct sigaction *act;
  89. };
  90. extern PyObject* response_status;
  91. extern PyObject* response_headers;
  92. /**@brief The function that initialize the alternate python worker
  93. * @ingroup worker_process
  94. *
  95. * This function handles python worker by running a PEP333 application function.
  96. * The start_response() function set @ref response_status and
  97. * @ref response_headers globals.
  98. * @param wrk_id worker id
  99. * @return 0 if exit avec max requests
  100. */
  101. int work333(int wrk_id);
  102. /**@brief the function that initialize the alternate python worker
  103. * @ingroup worker_process
  104. *
  105. * This function handles python worker using stdout to communicate with
  106. * FCGI. This function clones for each request, running worker_piper()
  107. * @param wrk_id worker id
  108. * @return 0 if exit avec max requests
  109. */
  110. int work(int wrk_id);
  111. /*/**@brief function for a subprocess designed to read stdin & stdout from
  112. * python & forward them to syslog or FCGI
  113. * @ingroup worker_process
  114. * @param int worker id
  115. * @param int request id
  116. * @param int pystdout
  117. * @param int pystderr
  118. * @param int ctlpipe a pipe closed when the process is ready
  119. * @note Exit after signal sent by parent & when poll indicate the pipes are
  120. * empty
  121. */
  122. /*
  123. void worker_piper(int, int, int, int, int, FCGX_Stream*);
  124. */
  125. int worker_piper(void*);
  126. /**@brief worker piper sigaction handler
  127. */
  128. void worker_piper_sighandler(int);
  129. /**@brief empty pipes and log content for pep333 workers
  130. * @todo enhance logging : 1 lines per logline + line counter ?
  131. * @todo sys.stdout & sys.stderr can have an implementation like
  132. * libpyfcgi.IoIn to avoir useless buffering
  133. * @param pipe_std pipe for stdout
  134. * @param pipe_err pipe for stderr
  135. * @param flush python flush methods
  136. */
  137. void worker_log_pipes(int pipe_std, int pipe_err, PyObject* flush[2]);
  138. /**@brief Attempt to read the request size from ctl pipe
  139. * @param ctl_pipe read fd
  140. * @param rep_sz response size
  141. * @return 0 if no error
  142. */
  143. int ctl_get_rep_sz(int ctl_pipe, size_t* rep_sz);
  144. void worker_sighandler(int);
  145. void worker_sigalrmhandler(int signum);
  146. #endif