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 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 processes
  52. * @ingroup work_master_proc
  53. */
  54. /**@file pyworker.h
  55. * @ingroup worker_process
  56. */
  57. #ifndef _PYWORKER__H___
  58. #define _PYWORKER__H___
  59. #include "config.h"
  60. #include <fcgiapp.h>
  61. #include <fcgi_stdio.h> /* fcgi library; put it first*/
  62. #define PY_SSIZE_T_CLEAN
  63. #include <Python.h>
  64. #include <unistd.h>
  65. #include <fcntl.h>
  66. #include <syslog.h>
  67. #include <signal.h>
  68. #include <limits.h>
  69. #include <poll.h>
  70. #include <sched.h>
  71. #include <signal.h>
  72. #include <sys/types.h>
  73. #include <sys/ipc.h>
  74. #include <sys/sem.h>
  75. #include <sys/wait.h>
  76. #include "logger.h"
  77. #include "pyutils.h"
  78. #include "python_pyfcgi.h"
  79. #define WPIPER_SIG 30
  80. #define PIPER_STACK_SZ (1024 * 1024 * 4)
  81. //extern char **environ;
  82. typedef unsigned long int pywrkid_t;
  83. typedef struct piper_args_s piper_args_t;
  84. struct piper_args_s
  85. {
  86. int wrk_id, pystdout, pystderr, ctl_pipe;
  87. //int req_id;
  88. FCGX_Stream *out;
  89. struct sigaction *act;
  90. };
  91. extern PyObject* response_status;
  92. extern PyObject* response_headers;
  93. /**@brief The function that initialize the alternate python worker
  94. * @ingroup worker_process
  95. *
  96. * This function handles python worker by running a PEP333 application function.
  97. * The start_response() function set @ref response_status and
  98. * @ref response_headers globals.
  99. * @param char* python_entrypoint a path to a python entrypoint
  100. * @param int worker uid
  101. * @return 0 if exit avec max requests
  102. */
  103. int work333(int);
  104. /**@brief the function that initialize the alternate python worker
  105. * @ingroup worker_process
  106. *
  107. * This function handles python worker using stdout to communicate with
  108. * FCGI. This function clones for each request, running worker_piper()
  109. * @param char* python_entrypoint a path to a python entrypoint
  110. * @param int worker uid
  111. * @return 0 if exit avec max requests
  112. */
  113. int work(int);
  114. /**@brief function for a subprocess designed to read stdin & stdout from
  115. * python & forward them to syslog or FCGI
  116. * @ingroup worker_process
  117. * @param int worker id
  118. * @param int request id
  119. * @param int pystdout
  120. * @param int pystderr
  121. * @param int ctlpipe a pipe closed when the process is ready
  122. * @note Exit after signal sent by parent & when poll indicate the pipes are
  123. * empty
  124. */
  125. /*
  126. void worker_piper(int, int, int, int, int, FCGX_Stream*);
  127. */
  128. int worker_piper(void*);
  129. /**@brief worker piper sigaction handler
  130. */
  131. void worker_piper_sighandler(int);
  132. /**@brief empty pipes and log content for pep333 workers
  133. * @todo enhance logging : 1 lines per logline + line counter ?
  134. * @todo sys.stdout & sys.stderr can have an implementation like
  135. * libpyfcgi.IoIn to avoir useless buffering
  136. * @param int pipes for stdout
  137. * @param int pipes for stderr
  138. * @param PyObject[2] python flush methods
  139. */
  140. void worker_log_pipes(int, int, PyObject*[2]);
  141. /**@brief Attempt to read the request size from ctl pipe
  142. * @param int ctl pipe read fd
  143. * @param size_t* rep_sz
  144. * @return 0 if no error
  145. */
  146. int ctl_get_rep_sz(int, size_t*);
  147. void worker_sighandler(int);
  148. void worker_sigalrmhandler(int signum);
  149. #endif