Repository URL to install this package:
|
Version:
2.0.17 ▾
|
#include "../python/uwsgi_python.h"
//FIXME: [upstream:python] needs PyAPI_FUNC(void)
extern void Py_GetArgcArgv(int *, char ***);
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
extern char **environ;
static int new_argc = -1;
static int orig_argc = -1;
static char **new_argv = NULL;
static char **orig_argv = NULL;
static char *new_argv_buf = NULL;
PyObject *
pyuwsgi_setup(PyObject *self, PyObject *args, PyObject *kwds)
{
if (new_argv) {
PyErr_SetString(
PyExc_RuntimeError,
"uWSGI already setup"
);
return NULL;
}
if (uwsgi.mywid) {
PyErr_SetString(
PyExc_RuntimeError,
"uWSGI must be setup by master"
);
return NULL;
}
PyObject *iterator;
if (args == NULL || PyObject_Size(args) == 0) {
PyObject *argv = PySys_GetObject("argv");
if (argv == NULL)
return NULL;
// during site.py maybe
if (argv == Py_None) {
argv = PyTuple_New(0);
iterator = PyObject_GetIter(argv);
Py_DECREF(argv);
}
else {
iterator = PyObject_GetIter(argv);
if (PyObject_Size(argv) > 0) {
// forward past argv0
PyObject *item = PyIter_Next(iterator);
Py_DECREF(item);
}
}
}
else if (
PyObject_Size(args) == 1
&& !PyString_Check(PyTuple_GetItem(args, 0))
) {
iterator = PyObject_GetIter(PyTuple_GetItem(args, 0));
}
else {
iterator = PyObject_GetIter(args);
}
if (iterator == NULL) {
return NULL;
}
size_t size = 1;
//FIXME: ARGS prior to and including -c/-m are REQUIRED!
PyObject *item = PyString_FromString(orig_argv[0]);
PyObject *args_li = PyList_New(0);
PyList_Append(args_li, item);
size += strlen(orig_argv[0]) + 1;
Py_DECREF(item);
while ((item = PyIter_Next(iterator))) {
//TODO: call str(...) on everything
PyList_Append(args_li, item);
size += PyObject_Length(item) + 1;
Py_DECREF(item);
}
Py_DECREF(iterator);
new_argc = PyObject_Length(args_li);
new_argv = uwsgi_calloc(sizeof(char *) * (new_argc + 1));
new_argv_buf = uwsgi_calloc(size);
int i = 0;
char *new_argv_ptr = new_argv_buf;
for(i=0; i < new_argc; i++) {
PyObject *arg = PyList_GetItem(args_li, i);
char *arg_str = PyString_AsString(arg);
new_argv[i] = new_argv_ptr;
strcpy(new_argv_ptr, arg_str);
new_argv_ptr += strlen(arg_str) + 1;
}
PyObject *args_tup = PyList_AsTuple(args_li);
PyObject_SetAttrString(self, "NEW_ARGV", args_tup);
Py_DECREF(args_tup);
Py_DECREF(args_li);
// TODO: convention here is a goto methinks?
if (PyErr_Occurred()) {
free(new_argv_buf);
free(new_argv);
new_argv = 0;
new_argc = 0;
return NULL;
}
//TODO: ...???
// actually do the thing!
PyThreadState *_tstate = PyThreadState_Get();
uwsgi_setup(orig_argc, orig_argv, environ);
PyThreadState_Swap(_tstate);
Py_INCREF(self);
return self;
}
PyObject *
pyuwsgi_init(PyObject *self, PyObject *args, PyObject *kwds)
{
if (pyuwsgi_setup(self, args, kwds) == NULL) {
return NULL;
}
int rc = uwsgi_run();
// never(?) here
return Py_BuildValue("i", rc);
}
PyObject *
pyuwsgi_run(PyObject *self, PyObject *args, PyObject *kwds)
{
// backcompat
if (new_argv == NULL &&
pyuwsgi_setup(self, args, kwds) == NULL) {
return NULL;
}
int rc = uwsgi_run();
// never(?) here
return Py_BuildValue("i", rc);
}
PyMethodDef methods[] = {
{"run",
(PyCFunction) pyuwsgi_run,
METH_VARARGS | METH_KEYWORDS,
"run(...)"
"\n>>> 0"
"\n"
"\n * Call setup(...) if not configured"
"\n * Begin uWSGI mainloop"
"\n NOTE: will not return"
"\n"
},
{"init",
(PyCFunction) pyuwsgi_init,
METH_VARARGS | METH_KEYWORDS,
"init(...)"
"\n>>> 0"
"\n"
"\n * Call setup(...)"
"\n * Begin uWSGI mainloop"
"\n NOTE: will not return"
"\n"
},
{"setup",
(PyCFunction) pyuwsgi_setup,
METH_VARARGS | METH_KEYWORDS,
"setup('--master', ...)"
"\n>>> <module 'uwsgi' from \"uwsgi.so\">"
"\n"
"\n * Initialize uWSGI core with (...)"
"\n MUST only call once [RuntimeException]"
"\n MUST only call from master [RuntimeException]"
"\n"
},
{NULL, NULL, 0, NULL}
};
static void
pyuwsgi_set_orig_argv(PyObject *self)
{
// ask python for the original argc/argv saved in Py_Main()
Py_GetArgcArgv(&orig_argc, &orig_argv);
// [re?]export to uwsgi.orig_argv
PyObject *m_orig_argv;
m_orig_argv = PyTuple_New(orig_argc);
int i = 0;
int i_cm = -1;
for(i=0; i < orig_argc; i++) {
char *arg = orig_argv[i];
//XXX: _PyOS_optarg != 0 also indicates python quit early...
//FIXME: [upstream:python] orig_argv could be mangled; reset
// rel: http://bugs.python.org/issue8202
orig_argv[i + 1] = arg + strlen(arg) + 1;
// look for -c or -m and record the offset
if (i_cm < 0) {
if (strcmp(arg, "-c") || strcmp(arg, "-m")) {
// python's getopt would've failed had + 1 not exist
i_cm = i + 1;
}
else if (!uwsgi_startswith(arg, "-c", 2) ||
!uwsgi_startswith(arg, "-m", 2)) {
//FIXME: ARGS prior to and including -c/-m are REQUIRED,
// but NOT a part of the uWSGI argv! Needed to make
// exec*() self-referential: exec*(...) -> uwsgi
//
// want: uwsgi.binary_argv[:] + uwsgi.argv[:]!
// binary_argv = [binary_path] + args
i_cm = i;
}
}
PyTuple_SetItem(m_orig_argv, i, PyString_FromString(arg));
}
//TODO: howto properly detect uwsgi already running...
// orig_argv == uwsgi.orig_argv (?)
// ^^^ but if Py_Main not called, python/main.c:orig_argv unset
// howto interact/detect things in general
PyObject *m_new_argv = PyTuple_New(0);
PyObject_SetAttrString(self, "NEW_ARGV", m_new_argv);
PyObject_SetAttrString(self, "ORIG_ARGV", m_orig_argv);
Py_DECREF(m_new_argv);
Py_DECREF(m_orig_argv);
}
static PyObject *
pyuwsgi_init_as(char *mod_name)
{
PyObject *m;
m = PyImport_GetModuleDict();
if (m == NULL) {
return NULL;
}
m = PyDict_GetItemString(m, mod_name);
if (!m) {
m = Py_InitModule(mod_name, NULL);
}
if (orig_argc < 0) {
pyuwsgi_set_orig_argv(m);
}
int i;
for (i=0; methods[i].ml_name != NULL; i++) {
PyObject *fun = PyObject_GetAttrString(m, methods[i].ml_name);
if (fun != NULL) {
// already exists
Py_DECREF(fun);
continue;
}
PyErr_Clear();
// rel: Python/modsupport.c:Py_InitModule4
PyObject* name = PyString_FromString(methods[i].ml_name);
// fun(self, ...)
fun = PyCFunction_NewEx(&methods[i], m, name);
Py_DECREF(name);
// module.fun
PyObject_SetAttrString(m, methods[i].ml_name, fun);
Py_DECREF(fun);
}
return m;
}
PyMODINIT_FUNC
initpyuwsgi()
{
(void) pyuwsgi_init_as("pyuwsgi");
}
// allow the module to be called `uwsgi`
PyMODINIT_FUNC
inituwsgi()
{
(void) pyuwsgi_init_as("uwsgi");
}
void pyuwsgi_load()
{
if (new_argc > -1) {
uwsgi.new_argc = new_argc;
uwsgi.new_argv = new_argv;
}
}
struct uwsgi_plugin pyuwsgi_plugin = {
.name = "pyuwsgi",
.on_load = pyuwsgi_load,
};