mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-08-19 03:57:21 +00:00
7a9d281994
Add `uwsgi.get_logvar()` and `uwsgi.set_logvar()` support to the PyPy plugin
1064 lines
30 KiB
Python
1064 lines
30 KiB
Python
import sys
|
|
import os
|
|
sys.path.insert(0, '.')
|
|
sys.path.extend(os.environ.get('PYTHONPATH', '').split(os.pathsep))
|
|
import imp
|
|
import traceback
|
|
|
|
|
|
__name__ = '__main__'
|
|
mainmodule = type(sys)('__main__')
|
|
sys.modules['__main__'] = mainmodule
|
|
|
|
import cffi
|
|
|
|
# this is a list holding object we do not want to be freed (like callback and handlers)
|
|
uwsgi_gc = []
|
|
# the main ffi
|
|
ffi = cffi.FFI()
|
|
|
|
# the hooks we need to patch
|
|
hooks = '''
|
|
void free(void *);
|
|
ssize_t read(int, void *, size_t);
|
|
ssize_t write(int, const void *, size_t);
|
|
int close(int);
|
|
|
|
extern void (*uwsgi_pypy_hook_execute_source)(char *);
|
|
extern void (*uwsgi_pypy_hook_loader)(char *);
|
|
extern void (*uwsgi_pypy_hook_file_loader)(char *);
|
|
extern void (*uwsgi_pypy_hook_paste_loader)(char *);
|
|
extern void (*uwsgi_pypy_hook_pythonpath)(char *);
|
|
extern void (*uwsgi_pypy_hook_request)(struct wsgi_request *);
|
|
extern void (*uwsgi_pypy_post_fork_hook)(void);
|
|
'''
|
|
|
|
# here we load CFLAGS and uwsgi.h from the binary
|
|
defines0 = '''
|
|
char *uwsgi_get_cflags();
|
|
char *uwsgi_get_dot_h();
|
|
'''
|
|
ffi.cdef(defines0)
|
|
lib0 = ffi.verify(defines0)
|
|
|
|
|
|
# this is ugly, we should find a better approach
|
|
# basically it build a list of #define from binary CFLAGS
|
|
uwsgi_cdef = []
|
|
uwsgi_defines = []
|
|
uwsgi_cflags = ffi.string(lib0.uwsgi_get_cflags()).split()
|
|
for cflag in uwsgi_cflags:
|
|
if cflag.startswith('-D'):
|
|
line = cflag[2:]
|
|
if '=' in line:
|
|
(key, value) = line.split('=', 1)
|
|
uwsgi_cdef.append('#define %s ...' % key)
|
|
uwsgi_defines.append('#define %s %s' % (key, value.replace('\\"', '"').replace('""', '"')))
|
|
else:
|
|
uwsgi_cdef.append('#define %s ...' % line)
|
|
uwsgi_defines.append('#define %s 1' % line)
|
|
uwsgi_dot_h = ffi.string(lib0.uwsgi_get_dot_h())
|
|
|
|
# uwsgi definitions
|
|
cdefines = '''
|
|
%s
|
|
|
|
struct iovec {
|
|
void *iov_base;
|
|
size_t iov_len;
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_header {
|
|
uint8_t modifier1;
|
|
...;
|
|
};
|
|
|
|
struct wsgi_request {
|
|
int fd;
|
|
int async_id;
|
|
uint16_t var_cnt;
|
|
struct iovec *hvec;
|
|
|
|
int async_ready_fd;
|
|
int async_last_ready_fd;
|
|
|
|
int suspended;
|
|
|
|
struct uwsgi_header *uh;
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_opt {
|
|
char *key;
|
|
char *value;
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_worker {
|
|
int id;
|
|
int pid;
|
|
uint64_t requests;
|
|
uint64_t delta_requests;
|
|
uint64_t signals;
|
|
|
|
int cheaped;
|
|
int suspended;
|
|
int sig;
|
|
uint8_t signum;
|
|
|
|
uint64_t running_time;
|
|
uint64_t avg_response_time;
|
|
uint64_t tx;
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_plugin {
|
|
uint8_t modifier1;
|
|
|
|
void (*suspend) (struct wsgi_request *);
|
|
void (*resume) (struct wsgi_request *);
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_buffer {
|
|
char *buf;
|
|
size_t pos;
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_lock_item {
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_cache {
|
|
struct uwsgi_lock_item *lock;
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_cache_item {
|
|
uint64_t keysize;
|
|
...;
|
|
};
|
|
|
|
struct uwsgi_server {
|
|
char hostname[];
|
|
int mywid;
|
|
int muleid;
|
|
int master_process;
|
|
|
|
struct uwsgi_opt **exported_opts;
|
|
int exported_opts_cnt;
|
|
|
|
struct uwsgi_worker *workers;
|
|
|
|
int signal_socket;
|
|
int numproc;
|
|
int async;
|
|
|
|
void (*schedule_to_main) (struct wsgi_request *);
|
|
void (*schedule_to_req) (void);
|
|
|
|
struct wsgi_request *(*current_wsgi_req) (void);
|
|
|
|
struct wsgi_request *wsgi_req;
|
|
|
|
struct uwsgi_plugin *p[];
|
|
...;
|
|
};
|
|
struct uwsgi_server uwsgi;
|
|
|
|
struct uwsgi_plugin pypy_plugin;
|
|
|
|
const char *uwsgi_pypy_version;
|
|
|
|
char *uwsgi_binary_path();
|
|
|
|
void *uwsgi_malloc(size_t);
|
|
|
|
struct uwsgi_logvar {
|
|
char key[256];
|
|
uint8_t keylen;
|
|
char val[256];
|
|
uint8_t vallen;
|
|
struct uwsgi_logvar *next;
|
|
};
|
|
|
|
struct uwsgi_logvar *uwsgi_logvar_get(struct wsgi_request *, char *, uint8_t);
|
|
void uwsgi_logvar_add(struct wsgi_request *, char *, uint8_t, char *, uint8_t);
|
|
|
|
int uwsgi_response_prepare_headers(struct wsgi_request *, char *, size_t);
|
|
int uwsgi_response_add_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
|
int uwsgi_response_write_body_do(struct wsgi_request *, char *, size_t);
|
|
int uwsgi_response_sendfile_do_can_close(struct wsgi_request *, int, size_t, size_t, int);
|
|
|
|
char *uwsgi_request_body_read(struct wsgi_request *, ssize_t , ssize_t *);
|
|
char *uwsgi_request_body_readline(struct wsgi_request *, ssize_t, ssize_t *);
|
|
|
|
void uwsgi_buffer_destroy(struct uwsgi_buffer *);
|
|
int uwsgi_is_again();
|
|
|
|
int uwsgi_register_rpc(char *, struct uwsgi_plugin *, uint8_t, void *);
|
|
int uwsgi_register_signal(uint8_t, char *, void *, uint8_t);
|
|
|
|
char *uwsgi_do_rpc(char *, char *, uint8_t, char **, uint16_t *, uint64_t *);
|
|
|
|
void uwsgi_set_processname(char *);
|
|
int uwsgi_signal_send(int, uint8_t);
|
|
uint64_t uwsgi_worker_exceptions(int);
|
|
int uwsgi_worker_is_busy(int);
|
|
|
|
char *uwsgi_cache_magic_get(char *, uint16_t, uint64_t *, uint64_t *, char *);
|
|
int uwsgi_cache_magic_set(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t, char *);
|
|
int uwsgi_cache_magic_del(char *, uint16_t, char *);
|
|
int uwsgi_cache_magic_exists(char *, uint16_t, char *);
|
|
int uwsgi_cache_magic_clear(char *);
|
|
struct uwsgi_cache *uwsgi_cache_by_name(char *);
|
|
void uwsgi_cache_rlock(struct uwsgi_cache *);
|
|
void uwsgi_cache_rwunlock(struct uwsgi_cache *);
|
|
char *uwsgi_cache_item_key(struct uwsgi_cache_item *);
|
|
struct uwsgi_cache_item *uwsgi_cache_keys(struct uwsgi_cache *, uint64_t *, struct uwsgi_cache_item **);
|
|
|
|
int uwsgi_add_file_monitor(uint8_t, char *);
|
|
int uwsgi_add_timer(uint8_t, int);
|
|
int uwsgi_signal_add_rb_timer(uint8_t, int, int);
|
|
|
|
int uwsgi_user_lock(int);
|
|
int uwsgi_user_unlock(int);
|
|
|
|
int uwsgi_signal_registered(uint8_t);
|
|
|
|
int uwsgi_signal_add_cron(uint8_t, int, int, int, int, int);
|
|
void uwsgi_alarm_trigger(char *, char *, size_t);
|
|
|
|
void async_schedule_to_req_green(void);
|
|
void async_add_timeout(struct wsgi_request *, int);
|
|
int async_add_fd_write(struct wsgi_request *, int, int);
|
|
int async_add_fd_read(struct wsgi_request *, int, int);
|
|
int uwsgi_connect(char *, int, int);
|
|
|
|
int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, uint16_t, char *, uint16_t);
|
|
int uwsgi_websocket_send(struct wsgi_request *, char *, size_t);
|
|
struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *);
|
|
struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *);
|
|
|
|
char *uwsgi_chunked_read(struct wsgi_request *, size_t *, int, int);
|
|
|
|
void uwsgi_disconnect(struct wsgi_request *);
|
|
|
|
int uwsgi_ready_fd(struct wsgi_request *);
|
|
|
|
void set_user_harakiri(struct wsgi_request *, int);
|
|
|
|
int uwsgi_metric_set(char *, char *, int64_t);
|
|
int uwsgi_metric_inc(char *, char *, int64_t);
|
|
int uwsgi_metric_dec(char *, char *, int64_t);
|
|
int uwsgi_metric_mul(char *, char *, int64_t);
|
|
int uwsgi_metric_div(char *, char *, int64_t);
|
|
int64_t uwsgi_metric_get(char *, char *);
|
|
|
|
%s
|
|
|
|
''' % ('\n'.join(uwsgi_cdef), hooks)
|
|
|
|
cverify = '''
|
|
%s
|
|
|
|
const char *uwsgi_pypy_version = UWSGI_VERSION;
|
|
|
|
%s
|
|
|
|
extern struct uwsgi_server uwsgi;
|
|
extern struct uwsgi_plugin pypy_plugin;
|
|
%s
|
|
''' % ('\n'.join(uwsgi_defines), uwsgi_dot_h, hooks)
|
|
|
|
ffi.cdef(cdefines)
|
|
lib = ffi.verify(cverify)
|
|
libc = ffi.dlopen(None)
|
|
|
|
|
|
"""
|
|
this is a global object point the the WSGI callable
|
|
it sucks, i will fix it in the near future...
|
|
"""
|
|
wsgi_application = None
|
|
|
|
# fix argv if needed
|
|
if len(sys.argv) == 0:
|
|
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
|
|
|
|
|
|
@ffi.callback("void(char *)")
|
|
def uwsgi_pypy_execute_source(s):
|
|
"""
|
|
execute source, we expose it as cffi callback to avoid deadlocks
|
|
after GIL initialization
|
|
"""
|
|
source = ffi.string(s)
|
|
exec(source)
|
|
|
|
|
|
@ffi.callback("void(char *)")
|
|
def uwsgi_pypy_loader(module):
|
|
"""
|
|
load a wsgi module
|
|
"""
|
|
global wsgi_application
|
|
m = ffi.string(module)
|
|
c = 'application'
|
|
if ':' in m:
|
|
m, c = m.split(':')
|
|
if '.' in m:
|
|
mod = __import__(m, None, None, '*')
|
|
else:
|
|
mod = __import__(m)
|
|
wsgi_application = getattr(mod, c)
|
|
|
|
|
|
@ffi.callback("void(char *)")
|
|
def uwsgi_pypy_file_loader(filename):
|
|
"""
|
|
load a mod_wsgi compliant .wsgi file
|
|
"""
|
|
global wsgi_application
|
|
w = ffi.string(filename)
|
|
c = 'application'
|
|
mod = imp.load_source('uwsgi_file_wsgi', w)
|
|
wsgi_application = getattr(mod, c)
|
|
|
|
|
|
@ffi.callback("void(char *)")
|
|
def uwsgi_pypy_paste_loader(config):
|
|
"""
|
|
load a .ini paste app
|
|
"""
|
|
global wsgi_application
|
|
c = ffi.string(config)
|
|
if c.startswith('config:'):
|
|
c = c[7:]
|
|
if c[0] != '/':
|
|
c = os.getcwd() + '/' + c
|
|
try:
|
|
from paste.script.util.logging_config import fileConfig
|
|
fileConfig(c)
|
|
except ImportError:
|
|
print "PyPy WARNING: unable to load paste.script.util.logging_config"
|
|
from paste.deploy import loadapp
|
|
wsgi_application = loadapp('config:%s' % c)
|
|
|
|
|
|
@ffi.callback("void()")
|
|
def uwsgi_pypy_post_fork_hook():
|
|
"""
|
|
.post_fork_hook
|
|
"""
|
|
import uwsgi
|
|
if hasattr(uwsgi, 'post_fork_hook'):
|
|
uwsgi.post_fork_hook()
|
|
|
|
|
|
@ffi.callback("void(char *)")
|
|
def uwsgi_pypy_pythonpath(item):
|
|
"""
|
|
add an item to the pythonpath
|
|
"""
|
|
path = ffi.string(item)
|
|
sys.path.append(path)
|
|
print "added %s to pythonpath" % path
|
|
|
|
|
|
class WSGIfilewrapper(object):
|
|
"""
|
|
class implementing wsgi.file_wrapper
|
|
"""
|
|
def __init__(self, wsgi_req, f, chunksize=0):
|
|
self.wsgi_req = wsgi_req
|
|
self.f = f
|
|
self.chunksize = chunksize
|
|
if hasattr(f, 'close'):
|
|
self.close = f.close
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def sendfile(self):
|
|
if hasattr(self.f, 'fileno'):
|
|
lib.uwsgi_response_sendfile_do_can_close(self.wsgi_req, self.f.fileno(), 0, 0, 0)
|
|
elif hasattr(self.f, 'read'):
|
|
if self.chunksize == 0:
|
|
chunk = self.f.read()
|
|
if len(chunk) > 0:
|
|
lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk))
|
|
return
|
|
while True:
|
|
chunk = self.f.read(self.chunksize)
|
|
if chunk is None or len(chunk) == 0:
|
|
break
|
|
lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk))
|
|
|
|
|
|
class WSGIinput(object):
|
|
"""
|
|
class implementing wsgi.input
|
|
"""
|
|
def __init__(self, wsgi_req):
|
|
self.wsgi_req = wsgi_req
|
|
|
|
def read(self, size=0):
|
|
rlen = ffi.new('ssize_t*')
|
|
chunk = lib.uwsgi_request_body_read(self.wsgi_req, size, rlen)
|
|
if chunk != ffi.NULL:
|
|
return ffi.buffer(chunk, rlen[0])[:]
|
|
if rlen[0] < 0:
|
|
raise IOError("error reading wsgi.input")
|
|
raise IOError("error waiting for wsgi.input")
|
|
|
|
def getline(self, hint=0):
|
|
rlen = ffi.new('ssize_t*')
|
|
chunk = lib.uwsgi_request_body_readline(self.wsgi_req, hint, rlen)
|
|
if chunk != ffi.NULL:
|
|
return ffi.buffer(chunk, rlen[0])[:]
|
|
if rlen[0] < 0:
|
|
raise IOError("error reading line from wsgi.input")
|
|
raise IOError("error waiting for line on wsgi.input")
|
|
|
|
def readline(self, hint=0):
|
|
return self.getline(hint)
|
|
|
|
def readlines(self, hint=0):
|
|
lines = []
|
|
while True:
|
|
chunk = self.getline(hint)
|
|
if len(chunk) == 0:
|
|
break
|
|
lines.append(chunk)
|
|
return lines
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
chunk = self.getline()
|
|
if len(chunk) == 0:
|
|
raise StopIteration
|
|
return chunk
|
|
|
|
|
|
@ffi.callback("void(struct wsgi_request *)")
|
|
def uwsgi_pypy_wsgi_handler(wsgi_req):
|
|
"""
|
|
the WSGI request handler
|
|
"""
|
|
import uwsgi
|
|
global wsgi_application
|
|
|
|
def writer(data):
|
|
lib.uwsgi_response_write_body_do(wsgi_req, ffi.new("char[]", data), len(data))
|
|
|
|
def start_response(status, headers, exc_info=None):
|
|
if exc_info:
|
|
traceback.print_exception(*exc_info)
|
|
lib.uwsgi_response_prepare_headers(wsgi_req, ffi.new("char[]", status), len(status))
|
|
for hh in headers:
|
|
lib.uwsgi_response_add_header(wsgi_req, ffi.new("char[]", hh[0]), len(hh[0]), ffi.new("char[]", hh[1]), len(hh[1]))
|
|
return writer
|
|
|
|
environ = {}
|
|
iov = wsgi_req.hvec
|
|
for i in range(0, wsgi_req.var_cnt, 2):
|
|
environ[ffi.string(ffi.cast("char*", iov[i].iov_base), iov[i].iov_len)] = ffi.string(ffi.cast("char*", iov[i+1].iov_base), iov[i+1].iov_len)
|
|
|
|
environ['wsgi.version'] = (1, 0)
|
|
scheme = 'http'
|
|
if 'HTTPS' in environ:
|
|
if environ['HTTPS'] in ('on', 'ON', 'On', '1', 'true', 'TRUE', 'True'):
|
|
scheme = 'https'
|
|
environ['wsgi.url_scheme'] = environ.get('UWSGI_SCHEME', scheme)
|
|
environ['wsgi.input'] = WSGIinput(wsgi_req)
|
|
environ['wsgi.errors'] = sys.stderr
|
|
environ['wsgi.run_once'] = False
|
|
environ['wsgi.file_wrapper'] = lambda f, chunksize=0: WSGIfilewrapper(wsgi_req, f, chunksize)
|
|
environ['wsgi.multithread'] = True
|
|
environ['wsgi.multiprocess'] = True
|
|
|
|
environ['uwsgi.core'] = wsgi_req.async_id
|
|
environ['uwsgi.node'] = uwsgi.hostname
|
|
|
|
response = wsgi_application(environ, start_response)
|
|
if type(response) is str:
|
|
writer(response)
|
|
else:
|
|
try:
|
|
if isinstance(response, WSGIfilewrapper):
|
|
response.sendfile()
|
|
else:
|
|
for chunk in response:
|
|
if isinstance(chunk, WSGIfilewrapper):
|
|
try:
|
|
chunk.sendfile()
|
|
finally:
|
|
chunk.close()
|
|
else:
|
|
writer(chunk)
|
|
finally:
|
|
if hasattr(response, 'close'):
|
|
response.close()
|
|
|
|
lib.uwsgi_pypy_hook_execute_source = uwsgi_pypy_execute_source
|
|
lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader
|
|
lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader
|
|
lib.uwsgi_pypy_hook_paste_loader = uwsgi_pypy_paste_loader
|
|
lib.uwsgi_pypy_hook_pythonpath = uwsgi_pypy_pythonpath
|
|
lib.uwsgi_pypy_hook_request = uwsgi_pypy_wsgi_handler
|
|
lib.uwsgi_pypy_post_fork_hook = uwsgi_pypy_post_fork_hook
|
|
|
|
"""
|
|
Here we define the "uwsgi" virtual module
|
|
"""
|
|
|
|
uwsgi = imp.new_module('uwsgi')
|
|
sys.modules['uwsgi'] = uwsgi
|
|
uwsgi.version = ffi.string(lib.uwsgi_pypy_version)
|
|
uwsgi.hostname = ffi.string(lib.uwsgi.hostname)
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_register_signal(signum, kind, handler):
|
|
cb = ffi.callback('void(int)', handler)
|
|
uwsgi_gc.append(cb)
|
|
if lib.uwsgi_register_signal(signum, ffi.new("char[]", kind), cb, lib.pypy_plugin.modifier1) < 0:
|
|
raise Exception("unable to register signal %d" % signum)
|
|
uwsgi.register_signal = uwsgi_pypy_uwsgi_register_signal
|
|
|
|
|
|
class uwsgi_pypy_RPC(object):
|
|
def __init__(self, func):
|
|
self.func = func
|
|
|
|
def __call__(self, argc, argv, argvs, buf):
|
|
pargs = []
|
|
for i in range(0, argc):
|
|
pargs.append(ffi.buffer(argv[i], argvs[i])[:])
|
|
response = self.func(*pargs)
|
|
if len(response) > 0:
|
|
buf[0] = lib.uwsgi_malloc(len(response))
|
|
dst = ffi.buffer(buf[0], len(response))
|
|
dst[:len(response)] = response
|
|
return len(response)
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_register_rpc(name, func, argc=0):
|
|
rpc_func = uwsgi_pypy_RPC(func)
|
|
cb = ffi.callback("int(int, char*[], int[], char**)", rpc_func)
|
|
uwsgi_gc.append(cb)
|
|
if lib.uwsgi_register_rpc(ffi.new("char[]", name), ffi.addressof(lib.pypy_plugin), argc, cb) < 0:
|
|
raise Exception("unable to register rpc func %s" % name)
|
|
uwsgi.register_rpc = uwsgi_pypy_uwsgi_register_rpc
|
|
|
|
|
|
def uwsgi_pypy_rpc(node, func, *args):
|
|
argc = 0
|
|
argv = ffi.new('char*[256]')
|
|
argvs = ffi.new('uint16_t[256]')
|
|
rsize = ffi.new('uint64_t*')
|
|
|
|
for arg in args:
|
|
if argc >= 255:
|
|
raise Exception('invalid number of rpc arguments')
|
|
if len(arg) >= 65535:
|
|
raise Exception('invalid rpc argument size (must be < 65535)')
|
|
argv[argc] = ffi.new('char[]', arg)
|
|
argvs[argc] = len(arg)
|
|
argc += 1
|
|
|
|
if node:
|
|
c_node = ffi.new("char[]", node)
|
|
else:
|
|
c_node = ffi.NULL
|
|
|
|
response = lib.uwsgi_do_rpc(c_node, ffi.new("char[]", func), argc, argv, argvs, rsize)
|
|
if response:
|
|
ret = ffi.buffer(response, rsize[0])[:]
|
|
lib.free(response)
|
|
return ret
|
|
return None
|
|
uwsgi.rpc = uwsgi_pypy_rpc
|
|
|
|
|
|
def uwsgi_pypy_call(func, *args):
|
|
node = None
|
|
if '@' in func:
|
|
(func, node) = func.split('@')
|
|
return uwsgi_pypy_rpc(node, func, *args)
|
|
uwsgi.call = uwsgi_pypy_call
|
|
|
|
uwsgi.signal = lambda x: lib.uwsgi_signal_send(lib.uwsgi.signal_socket, x)
|
|
|
|
uwsgi.metric_get = lambda x: lib.uwsgi_metric_get(x, ffi.NULL)
|
|
uwsgi.metric_set = lambda x, y: lib.uwsgi_metric_set(x, ffi.NULL, y)
|
|
uwsgi.metric_inc = lambda x, y=1: lib.uwsgi_metric_inc(x, ffi.NULL, y)
|
|
uwsgi.metric_dec = lambda x, y=1: lib.uwsgi_metric_dec(x, ffi.NULL, y)
|
|
uwsgi.metric_mul = lambda x, y=1: lib.uwsgi_metric_mul(x, ffi.NULL, y)
|
|
uwsgi.metric_div = lambda x, y=1: lib.uwsgi_metric_div(x, ffi.NULL, y)
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_cache_get(key, cache=ffi.NULL):
|
|
vallen = ffi.new('uint64_t*')
|
|
value = lib.uwsgi_cache_magic_get(key, len(key), vallen, ffi.NULL, cache)
|
|
if value == ffi.NULL:
|
|
return None
|
|
ret = ffi.buffer(value, vallen[0])[:]
|
|
libc.free(value)
|
|
return ret
|
|
uwsgi.cache_get = uwsgi_pypy_uwsgi_cache_get
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_cache_set(key, value, expires=0, cache=ffi.NULL):
|
|
if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 0, cache) < 0:
|
|
raise Exception('unable to store item in the cache')
|
|
uwsgi.cache_set = uwsgi_pypy_uwsgi_cache_set
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_cache_update(key, value, expires=0, cache=ffi.NULL):
|
|
if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 1 << 1, cache) < 0:
|
|
raise Exception('unable to store item in the cache')
|
|
uwsgi.cache_update = uwsgi_pypy_uwsgi_cache_update
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_cache_del(key, cache=ffi.NULL):
|
|
if lib.uwsgi_cache_magic_del(key, len(key), cache) < 0:
|
|
raise Exception('unable to delete item from the cache')
|
|
uwsgi.cache_del = uwsgi_pypy_uwsgi_cache_del
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_cache_keys(cache=ffi.NULL):
|
|
uc = lib.uwsgi_cache_by_name(cache)
|
|
if uc == ffi.NULL:
|
|
raise Exception('no local uWSGI cache available')
|
|
l = []
|
|
lib.uwsgi_cache_rlock(uc)
|
|
pos = ffi.new('uint64_t *')
|
|
uci = ffi.new('struct uwsgi_cache_item **')
|
|
while True:
|
|
uci[0] = lib.uwsgi_cache_keys(uc, pos, uci)
|
|
if uci[0] == ffi.NULL:
|
|
break
|
|
l.append(ffi.buffer(lib.uwsgi_cache_item_key(uci[0]), uci[0].keysize)[:])
|
|
lib.uwsgi_cache_rwunlock(uc)
|
|
return l
|
|
uwsgi.cache_keys = uwsgi_pypy_uwsgi_cache_keys
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_add_timer(signum, secs):
|
|
if lib.uwsgi_add_timer(signum, secs) < 0:
|
|
raise Exception("unable to register timer")
|
|
uwsgi.add_timer = uwsgi_pypy_uwsgi_add_timer
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_add_rb_timer(signum, secs):
|
|
if lib.uwsgi_signal_add_rb_timer(signum, secs, 0) < 0:
|
|
raise Exception("unable to register redblack timer")
|
|
uwsgi.add_rb_timer = uwsgi_pypy_uwsgi_add_rb_timer
|
|
|
|
|
|
def uwsgi_pypy_uwsgi_add_file_monitor(signum, filename):
|
|
if lib.uwsgi_add_file_monitor(signum, ffi.new("char[]", filename)) < 0:
|
|
raise Exception("unable to register file monitor")
|
|
uwsgi.add_file_monitor = uwsgi_pypy_uwsgi_add_file_monitor
|
|
|
|
|
|
def uwsgi_pypy_lock(num=0):
|
|
if lib.uwsgi_user_lock(num) < 0:
|
|
raise Exception("invalid lock")
|
|
uwsgi.lock = uwsgi_pypy_lock
|
|
|
|
|
|
def uwsgi_pypy_unlock(num=0):
|
|
if lib.uwsgi_user_unlock(num) < 0:
|
|
raise Exception("invalid lock")
|
|
uwsgi.unlock = uwsgi_pypy_unlock
|
|
|
|
|
|
def uwsgi_pypy_masterpid():
|
|
if lib.uwsgi.master_process:
|
|
return lib.uwsgi.workers[0].pid
|
|
return 0
|
|
uwsgi.masterpid = uwsgi_pypy_masterpid
|
|
|
|
uwsgi.worker_id = lambda: lib.uwsgi.mywid
|
|
|
|
uwsgi.mule_id = lambda: lib.uwsgi.muleid
|
|
|
|
|
|
def uwsgi_pypy_signal_registered(signum):
|
|
if lib.uwsgi_signal_registered(signum) > 0:
|
|
return True
|
|
return False
|
|
uwsgi.signal_registered = uwsgi_pypy_signal_registered
|
|
|
|
|
|
def uwsgi_pypy_alarm(alarm, msg):
|
|
lib.uwsgi_alarm_trigger(ffi.new('char[]', alarm), ffi.new('char[]', msg), len(msg))
|
|
uwsgi.alarm = uwsgi_pypy_alarm
|
|
|
|
uwsgi.setprocname = lambda name: lib.uwsgi_set_processname(ffi.new('char[]', name))
|
|
|
|
|
|
def uwsgi_pypy_add_cron(signum, minute, hour, day, month, week):
|
|
if lib.uwsgi_signal_add_cron(signum, minute, hour, day, month, week) < 0:
|
|
raise Exception("unable to register cron")
|
|
uwsgi.add_cron = uwsgi_pypy_add_cron
|
|
|
|
"""
|
|
populate uwsgi.opt
|
|
"""
|
|
uwsgi.opt = {}
|
|
for i in range(0, lib.uwsgi.exported_opts_cnt):
|
|
uo = lib.uwsgi.exported_opts[i]
|
|
k = ffi.string(uo.key)
|
|
if uo.value == ffi.NULL:
|
|
v = True
|
|
else:
|
|
v = ffi.string(uo.value)
|
|
if k in uwsgi.opt:
|
|
if type(uwsgi.opt[k]) is list:
|
|
uwsgi.opt[k].append(v)
|
|
else:
|
|
uwsgi.opt[k] = [uwsgi.opt[k], v]
|
|
else:
|
|
uwsgi.opt[k] = v
|
|
|
|
|
|
def uwsgi_pypy_current_wsgi_req():
|
|
wsgi_req = lib.uwsgi.current_wsgi_req()
|
|
if wsgi_req == ffi.NULL:
|
|
raise Exception("unable to get current wsgi_request, check your setup !!!")
|
|
return wsgi_req
|
|
|
|
|
|
def uwsgi_pypy_suspend():
|
|
"""
|
|
uwsgi.suspend()
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
if lib.uwsgi.schedule_to_main:
|
|
lib.uwsgi.schedule_to_main(wsgi_req)
|
|
uwsgi.suspend = uwsgi_pypy_suspend
|
|
|
|
|
|
def uwsgi_pypy_workers():
|
|
"""
|
|
uwsgi.workers()
|
|
"""
|
|
workers = []
|
|
for i in range(1, lib.uwsgi.numproc+1):
|
|
worker = {}
|
|
worker['id'] = lib.uwsgi.workers[i].id
|
|
worker['pid'] = lib.uwsgi.workers[i].pid
|
|
worker['requests'] = lib.uwsgi.workers[i].requests
|
|
worker['delta_requests'] = lib.uwsgi.workers[i].delta_requests
|
|
worker['signals'] = lib.uwsgi.workers[i].signals
|
|
worker['exceptions'] = lib.uwsgi_worker_exceptions(i)
|
|
worker['apps'] = []
|
|
if lib.uwsgi.workers[i].cheaped:
|
|
worker['status'] == 'cheap'
|
|
elif lib.uwsgi.workers[i].suspended and not lib.uwsgi_worker_is_busy(i):
|
|
worker['status'] == 'pause'
|
|
else:
|
|
if lib.uwsgi.workers[i].sig:
|
|
worker['status'] = 'sig%d' % lib.uwsgi.workers[i].signum
|
|
elif lib.uwsgi_worker_is_busy(i):
|
|
worker['status'] = 'busy'
|
|
else:
|
|
worker['status'] = 'idle'
|
|
worker['running_time'] = lib.uwsgi.workers[i].running_time
|
|
worker['avg_rt'] = lib.uwsgi.workers[i].avg_response_time
|
|
worker['tx'] = lib.uwsgi.workers[i].tx
|
|
|
|
workers.append(worker)
|
|
return workers
|
|
|
|
uwsgi.workers = uwsgi_pypy_workers
|
|
|
|
|
|
def uwsgi_pypy_async_sleep(timeout):
|
|
"""
|
|
uwsgi.async_sleep(timeout)
|
|
"""
|
|
if timeout > 0:
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
lib.async_add_timeout(wsgi_req, timeout)
|
|
uwsgi.async_sleep = uwsgi_pypy_async_sleep
|
|
|
|
|
|
def uwsgi_pypy_async_connect(addr):
|
|
"""
|
|
uwsgi.async_connect(addr)
|
|
"""
|
|
fd = lib.uwsgi_connect(ffi.new('char[]', addr), 0, 1)
|
|
if fd < 0:
|
|
raise Exception("unable to connect to %s" % addr)
|
|
return fd
|
|
uwsgi.async_connect = uwsgi_pypy_async_connect
|
|
|
|
uwsgi.connection_fd = lambda: uwsgi_pypy_current_wsgi_req().fd
|
|
|
|
|
|
def uwsgi_pypy_wait_fd_read(fd, timeout=0):
|
|
"""
|
|
uwsgi.wait_fd_read(fd, timeout=0)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
if lib.async_add_fd_read(wsgi_req, fd, timeout) < 0:
|
|
raise Exception("unable to add fd %d to the event queue" % fd)
|
|
uwsgi.wait_fd_read = uwsgi_pypy_wait_fd_read
|
|
|
|
|
|
def uwsgi_pypy_wait_fd_write(fd, timeout=0):
|
|
"""
|
|
uwsgi.wait_fd_write(fd, timeout=0)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
if lib.async_add_fd_write(wsgi_req, fd, timeout) < 0:
|
|
raise Exception("unable to add fd %d to the event queue" % fd)
|
|
uwsgi.wait_fd_write = uwsgi_pypy_wait_fd_write
|
|
|
|
|
|
def uwsgi_pypy_ready_fd():
|
|
"""
|
|
uwsgi.ready_fd()
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
return lib.uwsgi_ready_fd(wsgi_req)
|
|
uwsgi.ready_fd = uwsgi_pypy_ready_fd
|
|
|
|
|
|
def uwsgi_pypy_send(*args):
|
|
"""
|
|
uwsgi.send(fd=None,data)
|
|
"""
|
|
if len(args) == 0:
|
|
raise ValueError("uwsgi.send() takes at least 1 argument")
|
|
elif len(args) == 1:
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
fd = wsgi_req.fd
|
|
data = args[0]
|
|
else:
|
|
fd = args[0]
|
|
data = args[1]
|
|
rlen = libc.write(fd, data, len(data))
|
|
if rlen <= 0:
|
|
raise IOError("unable to send data")
|
|
return rlen
|
|
uwsgi.send = uwsgi_pypy_send
|
|
|
|
|
|
def uwsgi_pypy_recv(*args):
|
|
"""
|
|
uwsgi.recv(fd=None,len)
|
|
"""
|
|
if len(args) == 0:
|
|
raise ValueError("uwsgi.recv() takes at least 1 argument")
|
|
elif len(args) == 1:
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
fd = wsgi_req.fd
|
|
l = args[0]
|
|
else:
|
|
fd = args[0]
|
|
l = args[1]
|
|
data = ffi.new('char[%d]' % l)
|
|
rlen = libc.read(fd, data, l)
|
|
if rlen <= 0:
|
|
raise IOError("unable to receive data")
|
|
return ffi.string(data[0:rlen])
|
|
uwsgi.recv = uwsgi_pypy_recv
|
|
|
|
"""
|
|
uwsgi.close(fd)
|
|
"""
|
|
uwsgi.close = lambda fd: lib.close(fd)
|
|
|
|
"""
|
|
uwsgi.disconnect()
|
|
"""
|
|
uwsgi.disconnect = lambda: lib.uwsgi_disconnect(uwsgi_pypy_current_wsgi_req())
|
|
|
|
|
|
def uwsgi_pypy_websocket_recv():
|
|
"""
|
|
uwsgi.websocket_recv()
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
ub = lib.uwsgi_websocket_recv(wsgi_req)
|
|
if ub == ffi.NULL:
|
|
raise IOError("unable to receive websocket message")
|
|
ret = ffi.buffer(ub.buf, ub.pos)[:]
|
|
lib.uwsgi_buffer_destroy(ub)
|
|
return ret
|
|
uwsgi.websocket_recv = uwsgi_pypy_websocket_recv
|
|
|
|
|
|
def uwsgi_pypy_websocket_recv_nb():
|
|
"""
|
|
uwsgi.websocket_recv_nb()
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
ub = lib.uwsgi_websocket_recv_nb(wsgi_req)
|
|
if ub == ffi.NULL:
|
|
raise IOError("unable to receive websocket message")
|
|
ret = ffi.buffer(ub.buf, ub.pos)[:]
|
|
lib.uwsgi_buffer_destroy(ub)
|
|
return ret
|
|
uwsgi.websocket_recv_nb = uwsgi_pypy_websocket_recv_nb
|
|
|
|
|
|
def uwsgi_pypy_websocket_handshake(key='', origin='', proto=''):
|
|
"""
|
|
uwsgi.websocket_handshake(key, origin)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
c_key = ffi.new('char[]', key)
|
|
c_origin = ffi.new('char[]', origin)
|
|
c_proto = ffi.new('char[]', proto)
|
|
if lib.uwsgi_websocket_handshake(wsgi_req, c_key, len(key), c_origin, len(origin), c_proto, len(proto)) < 0:
|
|
raise IOError("unable to complete websocket handshake")
|
|
uwsgi.websocket_handshake = uwsgi_pypy_websocket_handshake
|
|
|
|
|
|
def uwsgi_pypy_websocket_send(msg):
|
|
"""
|
|
uwsgi.websocket_send(msg)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
if lib.uwsgi_websocket_send(wsgi_req, ffi.new('char[]', msg), len(msg)) < 0:
|
|
raise IOError("unable to send websocket message")
|
|
uwsgi.websocket_send = uwsgi_pypy_websocket_send
|
|
|
|
|
|
def uwsgi_pypy_chunked_read(timeout=0):
|
|
"""
|
|
uwsgi.chunked_read(timeout=0)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
rlen = ffi.new("size_t*")
|
|
chunk = lib.uwsgi_chunked_read(wsgi_req, rlen, timeout, 0)
|
|
if chunk == ffi.NULL:
|
|
raise IOError("unable to receive chunked part")
|
|
return ffi.buffer(chunk, rlen[0])[:]
|
|
uwsgi.chunked_read = uwsgi_pypy_chunked_read
|
|
|
|
|
|
def uwsgi_pypy_chunked_read_nb():
|
|
"""
|
|
uwsgi.chunked_read_nb()
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
rlen = ffi.new("size_t*")
|
|
chunk = lib.uwsgi_chunked_read(wsgi_req, rlen, 0, 1)
|
|
if chunk == ffi.NULL:
|
|
if lib.uwsgi_is_again() > 0:
|
|
return None
|
|
raise IOError("unable to receive chunked part")
|
|
|
|
return ffi.buffer(chunk, rlen[0])[:]
|
|
uwsgi.chunked_read_nb = uwsgi_pypy_chunked_read_nb
|
|
|
|
|
|
def uwsgi_pypy_set_user_harakiri(x):
|
|
"""
|
|
uwsgi.set_user_harakiri(sec)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
lib.set_user_harakiri(wsgi_req, x)
|
|
uwsgi.set_user_harakiri = uwsgi_pypy_set_user_harakiri
|
|
|
|
|
|
def uwsgi_pypy_get_logvar(key):
|
|
"""
|
|
uwsgi.get_logvar(key)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
c_key = ffi.new('char[]', key)
|
|
lv = lib.uwsgi_logvar_get(wsgi_req, c_key, len(key))
|
|
if lv:
|
|
return ffi.string(lv.val[0:lv.vallen])
|
|
return None
|
|
uwsgi.get_logvar = uwsgi_pypy_get_logvar
|
|
|
|
|
|
def uwsgi_pypy_set_logvar(key, val):
|
|
"""
|
|
uwsgi.set_logvar(key, value)
|
|
"""
|
|
wsgi_req = uwsgi_pypy_current_wsgi_req()
|
|
c_key = ffi.new('char[]', key)
|
|
c_val = ffi.new('char[]', val)
|
|
lib.uwsgi_logvar_add(wsgi_req, c_key, len(key), c_val, len(val))
|
|
uwsgi.set_logvar = uwsgi_pypy_set_logvar
|
|
|
|
|
|
print "Initialized PyPy with Python", sys.version
|
|
print "PyPy Home:", sys.prefix
|
|
|
|
|
|
"""
|
|
Continulets support
|
|
"""
|
|
|
|
# this is the dictionary of continulets (one per-core)
|
|
uwsgi_pypy_continulets = {}
|
|
|
|
|
|
def uwsgi_pypy_continulet_wrapper(cont):
|
|
lib.async_schedule_to_req_green()
|
|
|
|
|
|
@ffi.callback("void()")
|
|
def uwsgi_pypy_continulet_schedule():
|
|
id = lib.uwsgi.wsgi_req.async_id
|
|
modifier1 = lib.uwsgi.wsgi_req.uh.modifier1
|
|
|
|
# generate a new continulet
|
|
if not lib.uwsgi.wsgi_req.suspended:
|
|
from _continuation import continulet
|
|
uwsgi_pypy_continulets[id] = continulet(uwsgi_pypy_continulet_wrapper)
|
|
lib.uwsgi.wsgi_req.suspended = 1
|
|
|
|
# this is called in the main stack
|
|
if lib.uwsgi.p[modifier1].suspend:
|
|
lib.uwsgi.p[modifier1].suspend(ffi.NULL)
|
|
|
|
# let's switch
|
|
uwsgi_pypy_continulets[id].switch()
|
|
|
|
# back to the main stack
|
|
if lib.uwsgi.p[modifier1].resume:
|
|
lib.uwsgi.p[modifier1].resume(ffi.NULL)
|
|
|
|
|
|
@ffi.callback("void(struct wsgi_request *)")
|
|
def uwsgi_pypy_continulet_switch(wsgi_req):
|
|
id = wsgi_req.async_id
|
|
modifier1 = wsgi_req.uh.modifier1
|
|
|
|
# this is called in the current continulet
|
|
if lib.uwsgi.p[modifier1].suspend:
|
|
lib.uwsgi.p[modifier1].suspend(wsgi_req)
|
|
|
|
uwsgi_pypy_continulets[id].switch()
|
|
|
|
# back to the continulet
|
|
if lib.uwsgi.p[modifier1].resume:
|
|
lib.uwsgi.p[modifier1].resume(wsgi_req)
|
|
|
|
# update current running continulet
|
|
lib.uwsgi.wsgi_req = wsgi_req
|
|
|
|
|
|
def uwsgi_pypy_setup_continulets():
|
|
if lib.uwsgi.async < 1:
|
|
raise Exception("pypy continulets require async mode !!!")
|
|
lib.uwsgi.schedule_to_main = uwsgi_pypy_continulet_switch
|
|
lib.uwsgi.schedule_to_req = uwsgi_pypy_continulet_schedule
|
|
print "*** PyPy Continulets engine loaded ***"
|