Compare commits

...
40 Commits
Author SHA1 Message Date
roberto@arch32 feb493158c a fix fir capability support on arch linux 2011-11-19 07:55:22 +01:00
roberto@debian32 a5c1556cb7 do not exit on realod if chdir() fail 2011-11-18 20:46:07 +01:00
roberto@longshot 89e640bdd9 better to not remove -g/-ggdb 2011-11-18 09:29:30 +01:00
roberto@longshot 3ade8daff8 fixed rack compilation 2011-11-18 09:23:06 +01:00
roberto@debian32 049ea3fbed added Linux KSM support 2011-11-17 11:16:48 +01:00
roberto@goyle 715d26beed added support for remote signalling in rack plugin 2011-11-16 18:30:00 +01:00
roberto@goyle 1f5064094c better signal registration reporting 2011-11-15 18:33:44 +01:00
roberto@goyle 7ed522dc29 added --signal 2011-11-15 18:18:42 +01:00
roberto@goyle 2086500405 added signal plugin 2011-11-15 18:06:37 +01:00
roberto@debian32 8f79409ed1 added uwsgi.route() 2011-11-14 15:05:23 +01:00
roberto@debian32 c2a3cd1476 added mule support to ruby DSL 2011-11-13 17:25:47 +01:00
roberto@debian32 e195a5d72c improved signal handling and rack mule_msg 2011-11-13 15:08:29 +01:00
roberto@debian32 c86b757904 use app_id in rack plugin 2011-11-12 16:24:47 +01:00
roberto@debian32 6800d2ac95 added lock/unlock to rack plugin 2011-11-12 11:31:22 +01:00
roberto@debian32 90fda2b4bb added UWSGI.mem 2011-11-12 11:18:25 +01:00
roberto@debian32 bf7ded9058 added a bunch of constant to rack plugin 2011-11-12 11:13:06 +01:00
roberto@debian32 6615dc3a62 added UWSGI.setprocname 2011-11-12 11:07:38 +01:00
roberto@debian32 c35054085c completed ruby cache support 2011-11-12 11:02:30 +01:00
roberto@debian32 fdf2bd7f96 fixed ruby 1.9 support 2011-11-12 10:53:19 +01:00
roberto@debian32 1c10b9dfe1 ported cache api to rack plugin 2011-11-12 10:44:23 +01:00
roberto@debian32 6854394e5c added rpc support to ruby 2011-11-11 12:29:04 +01:00
roberto@debian32 78a0d5f432 added postfork in uwsgidsl 2011-11-11 09:57:35 +01:00
roberto@debian32 5fe5aa70a4 added post_fork_hook to ruby 2011-11-11 09:49:17 +01:00
roberto@debian32 e9c0c6bd0b report GC frequency 2011-11-11 06:54:08 +01:00
roberto@debian32 5d12b3dc9c added --rbrequire 2011-11-11 06:51:29 +01:00
roberto@debian32 169a4b66db added UWSGI.signal_received to ruby 2011-11-10 16:32:26 +01:00
roberto@debian32 fbd6329db9 improved ruby signal handling 2011-11-10 16:11:48 +01:00
roberto@debian32 69c2e56857 ported python plugin to new signal_wait api 2011-11-10 15:36:36 +01:00
roberto@debian32 18f7d1edd3 refactored signal_wait 2011-11-10 15:34:19 +01:00
roberto@debian32 3f7cd5ff92 added rubydsl 2011-11-10 15:33:41 +01:00
roberto@debian32 785e1dbf83 re-thinked remap-modifier 2011-11-10 15:33:19 +01:00
roberto@debian32 bc6acf8d14 use SIGTSTP instead of SIGWINCH for pause/suspend/resume 2011-11-10 11:25:22 +01:00
roberto@sirius 3a099d0b2e added --pause/--suspend/--resume 2011-11-10 09:38:32 +01:00
roberto@longshot f9ad5e4144 fixed multi-option parser 2011-11-09 20:58:33 +01:00
roberto@debian32 ce9f6650a0 allows carbon-id to include dots 2011-11-09 07:08:44 +01:00
roberto@mrspurr fdeef04343 fixed a stupid bug in carbon plugin 2011-11-09 06:57:21 +01:00
roberto@debian32 fe72ec82e1 completed carbon plugin 2011-11-09 06:50:51 +01:00
roberto@debian32 fd0f308273 added carbon plugin 2011-11-09 06:25:38 +01:00
roberto@longshot f4e9ab43cb fixed rack compilation 2011-11-08 18:46:29 +01:00
roberto@debian32 3a141b523c Added tag 1.0-rc5 for changeset 043ba93dd69c 2011-11-03 09:40:07 +01:00
29 changed files with 2106 additions and 513 deletions
+1
View File
@@ -36,3 +36,4 @@ fb168b0b86169219aa9b8e40f0caa6297cf34dbc 0.9.9-rc1
7a4e021ea7ba2953e474326612c3bb82d6817f0e 1.0-rc2
4e4e781ef89ac33e71a7e92741d54549240ed156 1.0-rc3
24f7e260ea345c2cd73e2fd8191dddbd1b039062 1.0-rc4
043ba93dd69cf6924e98db3cb9a8759cce997367 1.0-rc5
+1 -1
View File
@@ -27,7 +27,7 @@ plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = python, ping, cache, nagios, rrdtool, rpc, fastrouter, http, ugreen
embedded_plugins = python, ping, cache, nagios, rrdtool, carbon, rpc, fastrouter, http, ugreen, signal
as_shared_library = false
locking = auto
+68
View File
@@ -0,0 +1,68 @@
require 'stringio'
require 'uwsgidsl'
signal 17,'mule5' do |signum|
end
puts UWSGI::VERSION
puts UWSGI::NUMPROC
puts UWSGI::HOSTNAME
puts UWSGI::OPT.inspect
timer 2 do |signum|
puts "ciao sono un dsl ruby: #{signum} #{UWSGI::OPT.inspect}"
end
timer 1,'mule1' do |signum|
puts "1 second elapsed (signum #{signum})"
end
filemon '/tmp' do |signum|
puts "/tmp has been modified"
end
cron 5,-1,-1,-1,-1 do |signum|
puts "cron ready #{signum}"
end
cron 58,-1,-1,-1,-1 do |signum|
puts "cron ready #{signum}"
end
postfork do
puts "fork() called"
end
rpc 'pippo' do
"i am an rpc function"
end
rpc 'pluto' do |x,y|
"i am another rpc function #{x} #{y}"
end
begin
foo_func
rescue
end
puts UWSGI.cache_exists('nilkey')
puts UWSGI.cache_exists?('nilkey')
UWSGI.cache_set!('foobar_key?a=1', UWSGI::OPT.inspect)
begin
puts UWSGI.cache_get(nil)
rescue
end
puts UWSGI.cache_get('foobar_key?a=1')
run lambda { |env|
puts env.inspect
UWSGI.setprocname("i am the uWSGI rack plugin")
UWSGI.signal(17)
[200, {'Content-Type'=>'text/plain'}, StringIO.new("Hello World! #{UWSGI.mem.inspect}\n")]
}
+6
View File
@@ -44,6 +44,7 @@ void log_request(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_SENDFILE
char *msg1 = " via sendfile() ";
#endif
char *msg3 = " via route() ";
struct uwsgi_app *wi;
@@ -62,6 +63,11 @@ void log_request(struct wsgi_request *wsgi_req) {
}
#endif
// mark route() requests
if (wsgi_req->status == -1) {
via = msg3;
}
time_request = ctime((const time_t *) &wsgi_req->start_of_request.tv_sec);
microseconds = wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec;
microseconds2 = wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec;
+36 -9
View File
@@ -13,6 +13,31 @@ void uwsgi_restore_auto_snapshot(int signum) {
}
void suspend_resume_them_all(int signum) {
int i;
int suspend = 0;
if (uwsgi.workers[0].suspended == 1) {
uwsgi_log_verbose("*** (SIGTSTP received) resuming workers ***\n");
uwsgi.workers[0].suspended = 0;
}
else {
uwsgi_log_verbose("*** PAUSE (press start to resume, if you do not have a joypad send SIGTSTP) ***\n");
suspend = 1;
uwsgi.workers[0].suspended = 1;
}
for(i=1;i<=uwsgi.numproc;i++) {
uwsgi.workers[i].suspended = suspend;
if (uwsgi.workers[i].pid > 0) {
if (kill(uwsgi.workers[i].pid, SIGTSTP)) {
uwsgi_error("kill()");
}
}
}
}
void expire_rb_timeouts(struct rb_root *root) {
time_t current = time(NULL);
@@ -308,6 +333,7 @@ int master_loop(char **argv, char **environ) {
uwsgi.current_time = time(NULL);
uwsgi_unix_signal(SIGTSTP, suspend_resume_them_all);
uwsgi_unix_signal(SIGHUP, grace_them_all);
if (uwsgi.die_on_term) {
uwsgi_unix_signal(SIGTERM, kill_them_all);
@@ -705,9 +731,9 @@ healthy:
}
uwsgi_log( "binary reloading uWSGI...\n");
uwsgi_log("chdir() to %s\n", uwsgi.cwd);
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
exit(1);
}
/* check fd table (a module can obviosly open some fd on initialization...) */
@@ -1406,6 +1432,14 @@ healthy:
}
#endif
#ifdef __linux__
#ifdef MADV_MERGEABLE
if (uwsgi.linux_ksm > 0 && (uwsgi.master_cycles % uwsgi.linux_ksm) == 0) {
uwsgi_linux_ksm_map();
}
#endif
#endif
#ifdef UWSGI_UDP
// check for cluster nodes
master_check_cluster_nodes();
@@ -1624,14 +1658,7 @@ next:
}
gettimeofday(&last_respawn, NULL);
uwsgi.respawn_delta = last_respawn.tv_sec;
// close the communication pipe
/*
close(uwsgi.workers[uwsgi.mywid].pipe[0]);
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.workers[uwsgi.mywid].pipe)) {
uwsgi_error("socketpair()\n");
continue;
}
*/
if (uwsgi_respawn_worker(uwsgi.mywid)) return 0;
}
+5
View File
@@ -96,6 +96,7 @@ int uwsgi_respawn_worker(int wid) {
if (pid == 0) {
signal(SIGWINCH, worker_wakeup);
signal(SIGTSTP, worker_wakeup);
uwsgi.mywid = wid;
uwsgi.mypid = getpid();
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
@@ -109,6 +110,7 @@ int uwsgi_respawn_worker(int wid) {
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
uwsgi.workers[uwsgi.mywid].cheaped = 0;
uwsgi.workers[uwsgi.mywid].busy = 0;
uwsgi.workers[uwsgi.mywid].suspended = 0;
uwsgi.workers[uwsgi.mywid].sig = 0;
// reset the apps count with a copy from the master
@@ -345,6 +347,9 @@ void uwsgi_send_stats(int fd) {
if (uwsgi.workers[i + 1].cheaped) {
fprintf(output,"\"status\": \"cheap\", ");
}
else if (uwsgi.workers[i + 1].suspended) {
fprintf(output,"\"status\": \"pause\", ");
}
else {
if (uwsgi.workers[i + 1].sig) {
fprintf(output,"\"status\": \"sig%d\", ", uwsgi.workers[i + 1].signum);
+123
View File
@@ -12,6 +12,24 @@ extern struct uwsgi_server uwsgi;
void uwsgi_mule_handler(void);
void mule_send_msg(int fd, char *message, size_t len) {
socklen_t so_bufsize_len = sizeof(int);
int so_bufsize = 0;
if (write(fd, message, len) != (ssize_t) len) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
uwsgi_error("getsockopt()");
}
uwsgi_log("*** MULE MSG QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
}
else {
uwsgi_error("mule_send_msg()");
}
}
}
void uwsgi_mule(int id) {
int i;
@@ -233,3 +251,108 @@ struct uwsgi_mule_farm *uwsgi_mule_farm_new(struct uwsgi_mule_farm **umf, struct
return uwsgi_mf;
}
ssize_t uwsgi_mule_get_msg(int manage_signals, int manage_farms, char *message, size_t buffer_size, int timeout) {
ssize_t len = 0;
struct pollfd *mulepoll;
int count = 4;
int farms_count = 0;
uint8_t uwsgi_signal;
int i;
if (uwsgi.muleid == 0) return -1;
if (manage_signals) count = 2;
if (!manage_farms) goto next;
for(i=0;i<uwsgi.farms_cnt;i++) {
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) farms_count++;
}
next:
if (timeout > -1) timeout = timeout*1000;
mulepoll = uwsgi_malloc(sizeof(struct pollfd) * (count+farms_count));
mulepoll[0].fd = uwsgi.mules[uwsgi.muleid-1].queue_pipe[1];
mulepoll[0].events = POLLIN;
mulepoll[1].fd = uwsgi.shared->mule_queue_pipe[1];
mulepoll[1].events = POLLIN;
if (count > 2) {
mulepoll[2].fd = uwsgi.signal_socket;
mulepoll[2].events = POLLIN;
mulepoll[3].fd = uwsgi.my_signal_socket;
mulepoll[3].events = POLLIN;
}
if (farms_count > 0) {
int tmp_cnt = 0;
for(i=0;i<uwsgi.farms_cnt;i++) {
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) {
mulepoll[count+tmp_cnt].fd = uwsgi.farms[i].queue_pipe[1];
mulepoll[count+tmp_cnt].events = POLLIN;
tmp_cnt++;
}
}
}
int ret = poll(mulepoll, count+farms_count, timeout);
if (ret <= 0) {
uwsgi_error("poll");
}
else {
if (mulepoll[0].revents & POLLIN) {
len = read(uwsgi.mules[uwsgi.muleid-1].queue_pipe[1], message, buffer_size);
}
else if (mulepoll[1].revents & POLLIN) {
len = read(uwsgi.shared->mule_queue_pipe[1], message, buffer_size);
}
else {
if (count > 2) {
int interesting_fd = -1;
if (mulepoll[2].revents & POLLIN) {
interesting_fd = mulepoll[2].fd;
}
else if (mulepoll[3].revents & POLLIN) {
interesting_fd = mulepoll[3].fd;
}
if (interesting_fd > -1) {
len = read(interesting_fd, &uwsgi_signal, 1);
if (len <= 0) {
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
end_me(0);
}
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.mywid);
}
// set the error condition
len = -1;
goto clear;
}
}
// read messages in the farm
for(i=0;i<farms_count;i++) {
if (mulepoll[count+i].revents & POLLIN) {
len = read(mulepoll[count+i].fd, message, buffer_size);
break;
}
}
}
}
if (len < 0) {
uwsgi_error("read()");
goto clear;
}
clear:
free(mulepoll);
return len;
}
+27
View File
@@ -0,0 +1,27 @@
from uwsgidecorators import *
@timer(3, target='mule1')
def hello_timer(signum):
print "3 seconds elapsed"
@mulefunc
def conto_fino_a_dieci(uno, due, tre):
print "MULE ID %d: conto_fino_a_dieci" % uwsgi.mule_id(),uno,due,tre
@mulefunc(2)
def conto_fino_a_venti(uno, due, tre):
print "MULE ID %d: conto_fino_a_venti" % uwsgi.mule_id(),uno,due,tre
@mulefunc('topogigio')
def conto_fino_a_trenta(uno, due, tre):
print "MULE ID %d: conto_fino_a_trenta" % uwsgi.mule_id(),uno,due,tre
def application(e, sr):
conto_fino_a_dieci(1,2,3)
conto_fino_a_venti(4,5,6)
conto_fino_a_trenta(7,8,9)
sr('200 OK', [('Content-Type','text/html')])
return "MULE !!!"
+123
View File
@@ -0,0 +1,123 @@
#include "../../uwsgi.h"
extern struct uwsgi_server uwsgi;
#define CARBON_OPT_BASE 178000
#define CARBON_OPT_CARBON CARBON_OPT_BASE+1
#define CARBON_OPT_CARBON_ID CARBON_OPT_BASE+2
#define CARBON_OPT_CARBON_FREQ CARBON_OPT_BASE+3
#define CARBON_OPT_CARBON_TIMEOUT CARBON_OPT_BASE+4
struct uwsgi_carbon {
struct uwsgi_string_list *servers;
int freq;
int timeout;
char *id;
} u_carbon;
struct option carbon_options[] = {
{"carbon", required_argument, 0, CARBON_OPT_CARBON},
{"carbon-timeout", required_argument, 0, CARBON_OPT_CARBON_TIMEOUT},
{"carbon-freq", required_argument, 0, CARBON_OPT_CARBON_FREQ},
{"carbon-id", required_argument, 0, CARBON_OPT_CARBON_ID},
{0, 0, 0, 0},
};
int carbon_init() {
return 0;
}
int carbon_opt(int i, char *optarg) {
switch(i) {
case CARBON_OPT_CARBON:
uwsgi.master_process = 1;
uwsgi_string_new_list(&u_carbon.servers, optarg);
return 1;
case CARBON_OPT_CARBON_ID:
u_carbon.id = optarg;
return 1;
case CARBON_OPT_CARBON_FREQ:
u_carbon.freq = atoi(optarg);
return 1;
case CARBON_OPT_CARBON_TIMEOUT:
u_carbon.timeout = atoi(optarg);
return 1;
}
return 0;
}
void carbon_post_init() {
int i;
struct uwsgi_string_list *usl = u_carbon.servers;
if (!uwsgi.sockets) return;
if (!u_carbon.servers) return;
while(usl) {
uwsgi_log("added carbon server %s\n", usl->value);
usl = usl->next;
}
if (u_carbon.freq < 1) u_carbon.freq = 60;
if (u_carbon.timeout < 1) u_carbon.timeout = 3;
if (!u_carbon.id) {
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
for(i=0;i<(int)strlen(u_carbon.id);i++) {
if (u_carbon.id[i] == '.') u_carbon.id[i] = '_';
}
}
}
void carbon_master_cycle() {
static time_t last_update = 0;
char ptr[4096];
int rlen, i;
int fd;
struct uwsgi_string_list *usl = u_carbon.servers;
if (!u_carbon.servers) return ;
if (last_update == 0) last_update = time(NULL);
// update
if (uwsgi.current_time - last_update >= u_carbon.freq) {
while(usl) {
fd = uwsgi_connect(usl->value, u_carbon.timeout, 0);
if (fd < 0) goto nxt;
// put the socket in non-blocking mode
uwsgi_socket_nb(fd);
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) uwsgi.workers[0].requests, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
for(i=1;i<=uwsgi.numproc;i++) {
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].requests, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
}
clear:
close(fd);
nxt:
usl = usl->next;
}
}
}
struct uwsgi_plugin carbon_plugin = {
.options = carbon_options,
.manage_opt = carbon_opt,
.master_cycle = carbon_master_cycle,
.post_init = carbon_post_init,
.init = carbon_init,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='carbon'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['carbon']
+1 -18
View File
@@ -300,26 +300,9 @@ void uwsgi_psgi_app() {
close(uperl.fd);
}
struct uwsgi_app *wi = &uwsgi_apps[id];
memset(wi, 0, sizeof(struct uwsgi_app));
wi->modifier1 = 5;
wi->mountpoint = "";
wi->mountpoint_len = 0;
uwsgi_add_app(id, 5, "", 0);
uwsgi_log("PSGI app %d (%s) loaded at %p\n", id, uperl.psgi, uperl.psgi_main);
uwsgi_apps_cnt++;
// check if we need to emulate fork() COW
int i;
if (uwsgi.mywid == 0) {
for(i=1;i<=uwsgi.numproc;i++) {
memcpy(&uwsgi.workers[i].apps[id], &uwsgi.workers[0].apps[id], sizeof(struct uwsgi_app));
uwsgi.workers[i].apps_cnt = uwsgi_apps_cnt;
}
}
}
+1 -1
View File
@@ -1263,7 +1263,7 @@ uint16_t uwsgi_python_rpc(void *func, uint8_t argc, char **argv, char *buffer) {
if (ret) {
if (PyString_Check(ret)) {
rv = PyString_AsString(ret);
rl = strlen(rv);
rl = PyString_Size(ret);
if (rl <= 0xffff) {
memcpy(buffer, rv, rl);
Py_DECREF(ret);
+97 -169
View File
@@ -11,8 +11,6 @@ PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
int wait_for_specific_signal = 0;
uint8_t uwsgi_signal = 0;
uint8_t received_signal;
int ret;
struct pollfd pfd[2];
wsgi_req->signal_received = -1;
@@ -23,60 +21,18 @@ PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
wait_for_specific_signal = 1;
}
#ifdef UWSGI_ASYNC
if (uwsgi.async > 1) {
wsgi_req->sigwait = 1;
UWSGI_RELEASE_GIL;
if (wait_for_specific_signal) {
received_signal = uwsgi_signal_wait(uwsgi_signal);
}
else {
#endif
UWSGI_RELEASE_GIL;
pfd[0].fd = uwsgi.signal_socket;
pfd[0].events = POLLIN;
pfd[1].fd = uwsgi.my_signal_socket;
pfd[1].events = POLLIN;
cycle:
ret = poll(pfd, 2, -1);
if (ret > 0) {
if (pfd[0].revents == POLLIN) {
if (read(uwsgi.signal_socket, &received_signal, 1) != 1) {
uwsgi_error("read()");
}
else {
if (uwsgi_signal_handler(received_signal)) {
uwsgi_log_verbose("error managing signal %d on worker %d\n", received_signal, uwsgi.mywid);
}
wsgi_req->signal_received = received_signal;
if (wait_for_specific_signal) {
if (received_signal != uwsgi_signal) goto cycle;
}
}
}
if (pfd[1].revents == POLLIN) {
if (read(uwsgi.my_signal_socket, &received_signal, 1) != 1) {
uwsgi_error("read()");
}
else {
if (uwsgi_signal_handler(received_signal)) {
uwsgi_log_verbose("error managing signal %d on worker %d\n", received_signal, uwsgi.mywid);
}
wsgi_req->signal_received = received_signal;
if (wait_for_specific_signal) {
if (received_signal != uwsgi_signal) goto cycle;
}
}
}
}
UWSGI_GET_GIL;
#ifdef UWSGI_ASYNC
received_signal = uwsgi_signal_wait(-1);
}
#endif
wsgi_req->signal_received = received_signal;
UWSGI_GET_GIL;
return PyString_FromString("");
}
@@ -562,22 +518,31 @@ PyObject *py_uwsgi_register_signal(PyObject * self, PyObject * args) {
PyObject *py_uwsgi_signal(PyObject * self, PyObject * args) {
uint8_t uwsgi_signal;
ssize_t rlen;
char *remote = NULL;
if (!PyArg_ParseTuple(args, "B:signal", &uwsgi_signal)) {
if (!PyArg_ParseTuple(args, "B|s:signal", &uwsgi_signal, &remote)) {
return NULL;
}
if (remote) {
#ifdef UWSGI_DEBUG
uwsgi_log("sending %d to master\n", uwsgi_signal);
uwsgi_log("sending signal %d to node %s\n", uwsgi_signal, remote);
#endif
rlen = write(uwsgi.signal_socket, &uwsgi_signal, 1);
if (rlen != 1) {
uwsgi_error("write()");
int ret = uwsgi_remote_signal_send(remote, uwsgi_signal);
if (ret == 1) goto clear;
if (ret == -1)
return PyErr_Format(PyExc_IOError, "unable to deliver signal %d to node %s", uwsgi_signal, remote);
if (ret == 0)
return PyErr_Format(PyExc_ValueError, "node %s rejected signal %d", remote, uwsgi_signal);
}
else {
#ifdef UWSGI_DEBUG
uwsgi_log("sending signal %d to master\n", uwsgi_signal);
#endif
uwsgi_signal_send(uwsgi.signal_socket, uwsgi_signal);
}
clear:
Py_INCREF(Py_None);
return Py_None;
@@ -1154,7 +1119,6 @@ PyObject *py_uwsgi_mule_msg(PyObject * self, PyObject * args) {
char *message = NULL;
Py_ssize_t message_len = 0;
PyObject *mule_obj = NULL;
ssize_t len;
int fd = -1;
int mule_id = -1;
@@ -1166,10 +1130,7 @@ PyObject *py_uwsgi_mule_msg(PyObject * self, PyObject * args) {
return PyErr_Format(PyExc_ValueError, "no mule configured");
if (mule_obj == NULL) {
len = write(uwsgi.shared->mule_queue_pipe[0], message, message_len);
if (len <= 0) {
uwsgi_error("write()");
}
mule_send_msg(uwsgi.shared->mule_queue_pipe[0], message, message_len);
}
else {
if (PyString_Check(mule_obj)) {
@@ -1196,10 +1157,7 @@ PyObject *py_uwsgi_mule_msg(PyObject * self, PyObject * args) {
}
if (fd > -1) {
len = write(fd, message, message_len);
if (len < 0) {
uwsgi_error("write()");
}
mule_send_msg(fd, message, message_len);
}
}
@@ -1211,17 +1169,13 @@ PyObject *py_uwsgi_mule_msg(PyObject * self, PyObject * args) {
PyObject *py_uwsgi_mule_get_msg(PyObject * self, PyObject * args, PyObject *kwargs) {
ssize_t len = 0;
// this buffer will be configurable
// this buffer is configurable (default 64k)
char *message;
struct pollfd *mulepoll;
int count = 4;
int farms_count = 0;
uint8_t uwsgi_signal;
PyObject *manage_signals = NULL;
PyObject *manage_farms = NULL;
int buffer_size = 65536;
PyObject *py_manage_signals = NULL;
PyObject *py_manage_farms = NULL;
size_t buffer_size = 65536;
int timeout = -1;
int i;
int manage_signals = 1, manage_farms = 1;
static char *kwlist[] = {"signals", "buffer_size", "timeout", "farms", NULL};
@@ -1229,109 +1183,34 @@ PyObject *py_uwsgi_mule_get_msg(PyObject * self, PyObject * args, PyObject *kwar
return PyErr_Format(PyExc_ValueError, "you can receive mule messages only in a mule !!!");
}
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii:mule_get_msg", kwlist, &manage_signals, &manage_farms, &buffer_size, &timeout)) {
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii:mule_get_msg", kwlist, &py_manage_signals, &py_manage_farms, &buffer_size, &timeout)) {
return NULL;
}
if (manage_signals == Py_None || manage_signals == Py_False) {
count = 2;
// signals and farms are managed by default
if (py_manage_signals == Py_None || py_manage_signals == Py_False) {
manage_signals = 0;
}
if (manage_farms == Py_None || manage_farms == Py_False) {
goto next;
if (py_manage_farms == Py_None || py_manage_farms == Py_False) {
manage_farms = 0;
}
for(i=0;i<uwsgi.farms_cnt;i++) {
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) farms_count++;
}
next:
UWSGI_RELEASE_GIL;
if (timeout > -1) timeout = timeout*1000;
message = uwsgi_malloc(buffer_size);
mulepoll = uwsgi_malloc(sizeof(struct pollfd) * (count+farms_count));
mulepoll[0].fd = uwsgi.mules[uwsgi.muleid-1].queue_pipe[1];
mulepoll[0].events = POLLIN;
mulepoll[1].fd = uwsgi.shared->mule_queue_pipe[1];
mulepoll[1].events = POLLIN;
if (count > 2) {
mulepoll[2].fd = uwsgi.signal_socket;
mulepoll[2].events = POLLIN;
mulepoll[3].fd = uwsgi.my_signal_socket;
mulepoll[3].events = POLLIN;
}
for(i=0;i<farms_count;i++) {
mulepoll[count+i].fd = uwsgi.farms[i].queue_pipe[1];
mulepoll[count+i].events = POLLIN;
}
int ret = poll(mulepoll, count+farms_count, timeout);
if (ret <= 0) {
uwsgi_error("poll");
}
else {
if (mulepoll[0].revents & POLLIN) {
len = read(uwsgi.mules[uwsgi.muleid-1].queue_pipe[1], message, buffer_size);
}
else if (mulepoll[1].revents & POLLIN) {
len = read(uwsgi.shared->mule_queue_pipe[1], message, buffer_size);
}
else {
if (count > 2) {
int interesting_fd = -1;
if (mulepoll[2].revents & POLLIN) {
interesting_fd = mulepoll[2].fd;
}
else if (mulepoll[3].revents & POLLIN) {
interesting_fd = mulepoll[3].fd;
}
if (interesting_fd > -1) {
len = read(interesting_fd, &uwsgi_signal, 1);
if (len <= 0) {
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
end_me(0);
}
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.mywid);
}
goto clear;
}
}
for(i=0;i<farms_count;i++) {
if (mulepoll[count+i].revents & POLLIN) {
len = read(mulepoll[count+i].fd, message, buffer_size);
break;
}
}
}
}
UWSGI_RELEASE_GIL;
len = uwsgi_mule_get_msg(manage_signals, manage_farms, message, buffer_size, timeout) ;
UWSGI_GET_GIL;
if (len < 0) {
uwsgi_error("read()");
goto clear2;
free(message);
Py_INCREF(Py_None);
return Py_None;
}
PyObject *msg = PyString_FromStringAndSize(message, len);
free(message);
free(mulepoll);
return msg;
clear:
UWSGI_GET_GIL;
clear2:
free(message);
free(mulepoll);
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_farm_get_msg(PyObject * self, PyObject * args) {
@@ -2419,6 +2298,51 @@ PyObject *py_uwsgi_fcgi(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_route(PyObject * self, PyObject * args) {
char *addr = NULL;
struct wsgi_request *wsgi_req = current_wsgi_req();
if (!PyArg_ParseTuple(args, "s:route", &addr)) {
return NULL;
}
UWSGI_RELEASE_GIL;
int uwsgi_fd = uwsgi_connect(addr, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
UWSGI_GET_GIL;
if (uwsgi_fd < 0) {
return PyErr_Format(PyExc_IOError, "unable to connect to host %s", addr);
}
if (uwsgi_send_message(uwsgi_fd, wsgi_req->uh.modifier1, wsgi_req->uh.modifier2, wsgi_req->buffer, wsgi_req->uh.pktsize, wsgi_req->poll.fd, wsgi_req->post_cl, 0) < 0) {
return PyErr_Format(PyExc_IOError, "unable to send uwsgi request to host %s", addr);
}
// request sent, return the iterator response
uwsgi_Iter *ui = PyObject_New(uwsgi_Iter, &uwsgi_IterType);
if (!ui) {
uwsgi_log("unable to create uwsgi response object, better to reap the process\n");
exit(1);
}
ui->fd = uwsgi_fd;
ui->timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
ui->close = 1;
ui->started = 0;
ui->has_cl = 0;
ui->sent = 0;
ui->size = 0;
ui->func = NULL;
// mark a route request
wsgi_req->status = -1;
return (PyObject *) ui;
}
PyObject *py_uwsgi_send_message(PyObject * self, PyObject * args) {
PyObject *destination = NULL, *pyobj = NULL;
@@ -2576,6 +2500,9 @@ PyObject *py_uwsgi_workers(PyObject * self, PyObject * args) {
if (uwsgi.workers[i + 1].cheaped) {
zero = PyString_FromString("cheap");
}
else if (uwsgi.workers[i + 1].suspended) {
zero = PyString_FromString("pause");
}
else {
if (uwsgi.workers[i + 1].sig) {
zero = PyString_FromFormat("sig%d",uwsgi.workers[i + 1].signum);
@@ -3055,6 +2982,7 @@ PyObject *py_uwsgi_cluster_best_node(PyObject * self, PyObject * args) {
static PyMethodDef uwsgi_advanced_methods[] = {
{"send_message", py_uwsgi_send_message, METH_VARARGS, ""},
{"route", py_uwsgi_route, METH_VARARGS, ""},
{"send_multi_message", py_uwsgi_send_multi_message, METH_VARARGS, ""},
{"reload", py_uwsgi_reload, METH_VARARGS, ""},
{"stop", py_uwsgi_stop, METH_VARARGS, ""},
@@ -3175,7 +3103,7 @@ PyObject *py_uwsgi_cache_del(PyObject * self, PyObject * args) {
}
else if (uwsgi.cache_max_items) {
uwsgi_wlock(uwsgi.cache_lock);
if (uwsgi_cache_del(key, strlen(key))) {
if (uwsgi_cache_del(key, keylen)) {
uwsgi_rwunlock(uwsgi.cache_lock);
Py_INCREF(Py_None);
return Py_None;
@@ -3204,7 +3132,7 @@ PyObject *py_uwsgi_cache_set(PyObject * self, PyObject * args) {
}
if ((uint64_t)vallen > uwsgi.cache_blocksize) {
return PyErr_Format(PyExc_ValueError, "uWSGI cache items size must be < %llu, requested %d bytes", (unsigned long long)uwsgi.cache_blocksize, (int) vallen);
return PyErr_Format(PyExc_ValueError, "uWSGI cache items size must be < %llu, requested %llu bytes", (unsigned long long)uwsgi.cache_blocksize, (unsigned long long) vallen);
}
if (remote && strlen(remote) > 0) {
@@ -3240,7 +3168,7 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) {
}
if ((uint64_t)vallen > uwsgi.cache_blocksize) {
return PyErr_Format(PyExc_ValueError, "uWSGI cache items size must be < %llu, requested %d bytes", (unsigned long long)uwsgi.cache_blocksize, (int) vallen);
return PyErr_Format(PyExc_ValueError, "uWSGI cache items size must be < %llu, requested %llu bytes", (unsigned long long)uwsgi.cache_blocksize, (unsigned long long) vallen);
}
if (remote && strlen(remote) > 0) {
@@ -3284,7 +3212,7 @@ PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) {
return Py_True;
}
}
else if (uwsgi_cache_exists(key, strlen(key))) {
else if (uwsgi_cache_exists(key, keylen)) {
Py_INCREF(Py_True);
return Py_True;
}
+755
View File
@@ -0,0 +1,755 @@
#include "uwsgi_rack.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_rack ur;
#define uwsgi_rack_api(x, y, z) rb_define_module_function(rb_uwsgi_embedded, x, y, z)
VALUE rack_uwsgi_setprocname(VALUE *class, VALUE rbname) {
Check_Type(rbname, T_STRING);
char *name = RSTRING_PTR(rbname);
uwsgi_set_processname(name);
return Qnil;
}
VALUE rack_uwsgi_mem(VALUE *class) {
uint64_t rss=0, vsz = 0;
VALUE ml = rb_ary_new2(2);
get_memusage(&rss, &vsz);
rb_ary_store(ml, 0, LONG2NUM(rss));
rb_ary_store(ml, 1, LONG2NUM(vsz));
return ml;
}
VALUE rack_uwsgi_request_id(VALUE *class) {
return ULONG2NUM(uwsgi.workers[uwsgi.mywid].requests);
}
VALUE rack_uwsgi_worker_id(VALUE *class) {
return INT2NUM(uwsgi.mywid);
}
VALUE rack_uwsgi_mule_id(VALUE *class) {
return INT2NUM(uwsgi.muleid);
}
VALUE rack_uwsgi_logsize(VALUE *class) {
return ULONG2NUM(uwsgi.shared->logsize);
}
VALUE rack_uwsgi_mule_msg(int argc, VALUE *argv, VALUE *class) {
int fd = -1;
int mule_id = -1;
if (argc == 0) return Qnil;
Check_Type(argv[0], T_STRING);
char *message = RSTRING_PTR(argv[0]);
size_t message_len = RSTRING_LEN(argv[0]);
if (uwsgi.mules_cnt < 1) {
rb_raise(rb_eRuntimeError, "no mule configured");
return Qnil;
}
if (argc == 1) {
mule_send_msg(uwsgi.shared->mule_queue_pipe[0], message, message_len);
}
else {
if (TYPE(argv[1]) == T_STRING) {
struct uwsgi_farm *uf = get_farm_by_name(RSTRING_PTR(argv[1]));
if (uf == NULL) {
rb_raise(rb_eRuntimeError, "unknown farm");
return Qnil;
}
fd = uf->queue_pipe[0];
}
else if (TYPE(argv[1]) == T_FIXNUM) {
mule_id = NUM2INT(argv[1]);
if (mule_id < 0 && mule_id > uwsgi.mules_cnt) {
rb_raise(rb_eRuntimeError, "invalid mule number");
return Qnil;
}
if (mule_id == 0) {
fd = uwsgi.shared->mule_queue_pipe[0];
}
else {
fd = uwsgi.mules[mule_id-1].queue_pipe[0];
}
}
else {
rb_raise(rb_eRuntimeError, "invalid mule");
return Qnil;
}
if (fd > -1) {
mule_send_msg(fd, message, message_len);
}
}
return Qnil;
}
int uwsgi_ruby_hash_mule_callback(VALUE key, VALUE val, VALUE arg_array) {
Check_Type(key, T_SYMBOL);
ID key_id = SYM2ID(key);
const char *key_name = rb_id2name(key_id);
if (!strcmp(key_name, "signals")) {
rb_ary_store(arg_array, 0, val);
}
else if (!strcmp(key_name, "farms")) {
rb_ary_store(arg_array, 1, val);
}
else if (!strcmp(key_name, "timeout")) {
rb_ary_store(arg_array, 2, val);
}
else if (!strcmp(key_name, "buffer_size")) {
rb_ary_store(arg_array, 3, val);
}
return 0;
}
VALUE rack_uwsgi_mule_get_msg(int argc, VALUE *argv, VALUE *class) {
int manage_signals = 1;
int manage_farms = 1;
int timeout = -1;
size_t buffer_size = 65536;
ssize_t len = 0;
char *message;
if (uwsgi.muleid == 0) {
rb_raise(rb_eRuntimeError, "you can receive mule messages only in a mule !!!");
return Qnil;
}
if (argc > 0) {
// 0 = manage_signals
// 1 = manage_farms
// 2 = timeout
// 3 = buffer_size
VALUE arg_array = rb_ary_new2(4);
Check_Type(argv[0], T_HASH);
rb_hash_foreach(argv[0], uwsgi_ruby_hash_mule_callback, arg_array);
if (rb_ary_entry(arg_array, 0) == Qfalse) {
manage_signals = 0;
}
if (rb_ary_entry(arg_array, 1) == Qfalse) {
manage_farms = 0;
}
if (TYPE(rb_ary_entry(arg_array,2)) == T_FIXNUM) {
timeout = NUM2INT(rb_ary_entry(arg_array,2));
}
if (TYPE(rb_ary_entry(arg_array,3)) == T_FIXNUM || TYPE(rb_ary_entry(arg_array,3)) == T_BIGNUM) {
buffer_size = NUM2ULONG(rb_ary_entry(arg_array,3));
}
}
message = uwsgi_malloc(buffer_size);
len = uwsgi_mule_get_msg(manage_signals, manage_farms, message, buffer_size, timeout) ;
if (len < 0) {
free(message);
return Qnil;
}
VALUE msg = rb_str_new(message, len);
free(message);
return msg;
}
VALUE rack_uwsgi_lock(int argc, VALUE *argv, VALUE *class) {
int lock_num = 0;
if (argc > 0) {
Check_Type(argv[0], T_FIXNUM);
lock_num = NUM2INT(argv[0]);
}
if (lock_num < 0 || lock_num > uwsgi.locks) {
rb_raise(rb_eRuntimeError, "Invalid lock number");
return Qnil;
}
uwsgi_lock(uwsgi.user_lock[lock_num]);
return Qnil;
}
VALUE rack_uwsgi_unlock(int argc, VALUE *argv, VALUE *class) {
int lock_num = 0;
if (argc > 0) {
Check_Type(argv[0], T_FIXNUM);
lock_num = NUM2INT(argv[0]);
}
if (lock_num < 0 || lock_num > uwsgi.locks) {
rb_raise(rb_eRuntimeError, "Invalid lock number");
return Qnil;
}
uwsgi_unlock(uwsgi.user_lock[lock_num]);
return Qnil;
}
VALUE rack_uwsgi_cache_set(VALUE *class, VALUE rbkey, VALUE rbvalue) {
Check_Type(rbkey, T_STRING);
Check_Type(rbvalue, T_STRING);
char *key = RSTRING_PTR(rbkey);
uint64_t keylen = RSTRING_LEN(rbkey);
char *value = RSTRING_PTR(rbvalue);
uint64_t vallen = RSTRING_LEN(rbvalue);
uint64_t expires = 0;
if (vallen > uwsgi.cache_blocksize) {
rb_raise(rb_eRuntimeError, "uWSGI cache items size must be < %llu, requested %llu bytes", (unsigned long long)uwsgi.cache_blocksize, (unsigned long long) vallen);
return Qnil;
}
uwsgi_wlock(uwsgi.cache_lock);
if (uwsgi_cache_set(key, keylen, value, vallen, expires, 0)) {
uwsgi_rwunlock(uwsgi.cache_lock);
return Qnil;
}
uwsgi_rwunlock(uwsgi.cache_lock);
return Qtrue;
}
VALUE rack_uwsgi_cache_update(VALUE *class, VALUE rbkey, VALUE rbvalue) {
Check_Type(rbkey, T_STRING);
Check_Type(rbvalue, T_STRING);
char *key = RSTRING_PTR(rbkey);
uint64_t keylen = RSTRING_LEN(rbkey);
char *value = RSTRING_PTR(rbvalue);
uint64_t vallen = RSTRING_LEN(rbvalue);
uint64_t expires = 0;
if (vallen > uwsgi.cache_blocksize) {
rb_raise(rb_eRuntimeError, "uWSGI cache items size must be < %llu, requested %llu bytes", (unsigned long long)uwsgi.cache_blocksize, (unsigned long long) vallen);
return Qnil;
}
uwsgi_wlock(uwsgi.cache_lock);
if (uwsgi_cache_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE)) {
uwsgi_rwunlock(uwsgi.cache_lock);
return Qnil;
}
uwsgi_rwunlock(uwsgi.cache_lock);
return Qtrue;
}
VALUE rack_uwsgi_cache_set_exc(VALUE *class, VALUE rbkey, VALUE rbvalue) {
VALUE ret;
ret = rack_uwsgi_cache_set(class, rbkey, rbvalue);
if (ret == Qnil) {
rb_raise(rb_eRuntimeError, "unable to set value in uWSGI cache");
}
return ret;
}
VALUE rack_uwsgi_cache_update_exc(VALUE *class, VALUE rbkey, VALUE rbvalue) {
VALUE ret;
ret = rack_uwsgi_cache_update(class, rbkey, rbvalue);
if (ret == Qnil) {
rb_raise(rb_eRuntimeError, "unable to update value in uWSGI cache");
}
return ret;
}
VALUE rack_uwsgi_cache_del(VALUE *class, VALUE rbkey) {
Check_Type(rbkey, T_STRING);
char *key = RSTRING_PTR(rbkey);
size_t keylen = RSTRING_LEN(rbkey);
uwsgi_wlock(uwsgi.cache_lock);
if (uwsgi_cache_del(key, keylen)) {
uwsgi_rwunlock(uwsgi.cache_lock);
return Qfalse;
}
uwsgi_rwunlock(uwsgi.cache_lock);
return Qtrue;
}
VALUE rack_uwsgi_cache_exists(VALUE *class, VALUE rbkey) {
Check_Type(rbkey, T_STRING);
char *key = RSTRING_PTR(rbkey);
size_t keylen = RSTRING_LEN(rbkey);
if (uwsgi_cache_exists(key, keylen)) {
return Qtrue;
}
return Qfalse;
}
VALUE rack_uwsgi_cache_get(VALUE *class, VALUE rbkey) {
Check_Type(rbkey, T_STRING);
char *key = RSTRING_PTR(rbkey);
size_t keylen = RSTRING_LEN(rbkey);
uint64_t valsize;
char *value = NULL;
uwsgi_rlock(uwsgi.cache_lock);
value = uwsgi_cache_get(key, keylen, &valsize);
if (!value) {
uwsgi_rwunlock(uwsgi.cache_lock);
return Qnil;
}
VALUE res = rb_str_new(value, valsize);
uwsgi_rwunlock(uwsgi.cache_lock);
return res;
}
VALUE rack_uwsgi_cache_get_exc(VALUE *class, VALUE rbkey) {
VALUE ret;
ret = rack_uwsgi_cache_get(class, rbkey);
if (ret == Qnil) {
rb_raise(rb_eRuntimeError, "unable to get value from uWSGI cache");
}
return ret;
}
VALUE rack_uwsgi_add_cron(VALUE *class, VALUE rbsignum, VALUE rbmin, VALUE rbhour, VALUE rbday, VALUE rbmon, VALUE rbweek) {
Check_Type(rbsignum, T_FIXNUM);
Check_Type(rbmin, T_FIXNUM);
Check_Type(rbhour, T_FIXNUM);
Check_Type(rbday, T_FIXNUM);
Check_Type(rbmon, T_FIXNUM);
Check_Type(rbweek, T_FIXNUM);
uint8_t uwsgi_signal = NUM2INT(rbsignum);
int minute = NUM2INT(rbmin);
int hour = NUM2INT(rbhour);
int day = NUM2INT(rbday);
int month = NUM2INT(rbmon);
int week = NUM2INT(rbweek);
if (uwsgi_signal_add_cron(uwsgi_signal, minute, hour, day, month, week)) {
rb_raise(rb_eRuntimeError, "unable to add cron");
return Qnil;
}
return Qtrue;
}
VALUE rack_uwsgi_add_timer(VALUE *class, VALUE rbsignum, VALUE secs) {
Check_Type(rbsignum, T_FIXNUM);
Check_Type(secs, T_FIXNUM);
uint8_t uwsgi_signal = NUM2INT(rbsignum);
int seconds = NUM2INT(secs);
if (uwsgi_add_timer(uwsgi_signal, seconds)) {
rb_raise(rb_eRuntimeError, "unable to add timer");
return Qnil;
}
return Qtrue;
}
VALUE rack_uwsgi_add_rb_timer(VALUE *class, VALUE rbsignum, VALUE secs) {
Check_Type(rbsignum, T_FIXNUM);
Check_Type(secs, T_FIXNUM);
uint8_t uwsgi_signal = NUM2INT(rbsignum);
int seconds = NUM2INT(secs);
if (uwsgi_signal_add_rb_timer(uwsgi_signal, seconds, 0)) {
rb_raise(rb_eRuntimeError, "unable to add rb_timer");
return Qnil;
}
return Qtrue;
}
VALUE rack_uwsgi_add_file_monitor(VALUE *class, VALUE rbsignum, VALUE rbfilename) {
Check_Type(rbsignum, T_FIXNUM);
Check_Type(rbfilename, T_STRING);
uint8_t uwsgi_signal = NUM2INT(rbsignum);
char *filename = RSTRING_PTR(rbfilename);
if (uwsgi_add_file_monitor(uwsgi_signal, filename)) {
rb_raise(rb_eRuntimeError, "unable to add file monitor");
return Qnil;
}
return Qtrue;
}
VALUE uwsgi_ruby_wait_fd_read(VALUE *class, VALUE arg1, VALUE arg2) {
Check_Type(arg1, T_FIXNUM);
Check_Type(arg2, T_FIXNUM);
struct wsgi_request *wsgi_req = current_wsgi_req();
int fd = NUM2INT(arg1);
int timeout = NUM2INT(arg2);
if (fd >= 0) {
async_add_fd_read(wsgi_req, fd, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_wait_fd_write(VALUE *class, VALUE arg1, VALUE arg2) {
Check_Type(arg1, T_FIXNUM);
Check_Type(arg2, T_FIXNUM);
struct wsgi_request *wsgi_req = current_wsgi_req();
int fd = NUM2INT(arg1);
int timeout = NUM2INT(arg2);
if (fd >= 0) {
async_add_fd_write(wsgi_req, fd, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_async_connect(VALUE *class, VALUE arg) {
Check_Type(arg, T_STRING);
int fd = uwsgi_connect(RSTRING_PTR(arg), 0, 1);
return INT2FIX(fd);
}
VALUE uwsgi_ruby_async_sleep(VALUE *class, VALUE arg) {
Check_Type(arg, T_FIXNUM);
struct wsgi_request *wsgi_req = current_wsgi_req();
int timeout = NUM2INT(arg);
if (timeout >= 0) {
async_add_timeout(wsgi_req, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_masterpid(VALUE *class) {
if (uwsgi.master_process) {
return INT2NUM(uwsgi.workers[0].pid);
}
return INT2NUM(0);
}
VALUE uwsgi_ruby_suspend(VALUE *class) {
struct wsgi_request *wsgi_req = current_wsgi_req();
uwsgi.schedule_to_main(wsgi_req);
return Qtrue;
}
VALUE uwsgi_ruby_signal_wait(int argc, VALUE *argv, VALUE *class) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int wait_for_specific_signal = 0;
uint8_t uwsgi_signal = 0;
uint8_t received_signal;
wsgi_req->signal_received = -1;
if (argc > 0) {
Check_Type(argv[0], T_FIXNUM);
uwsgi_signal = NUM2INT(argv[0]);
wait_for_specific_signal = 1;
}
if (wait_for_specific_signal) {
received_signal = uwsgi_signal_wait(uwsgi_signal);
}
else {
received_signal = uwsgi_signal_wait(-1);
}
wsgi_req->signal_received = received_signal;
return Qnil;
}
VALUE uwsgi_ruby_signal_received(VALUE *class) {
struct wsgi_request *wsgi_req = current_wsgi_req();
return INT2NUM(wsgi_req->signal_received);
}
VALUE uwsgi_ruby_signal_registered(VALUE *class, VALUE signum) {
Check_Type(signum, T_FIXNUM);
uint8_t uwsgi_signal = NUM2INT(signum);
if (uwsgi_signal_registered(uwsgi_signal)) {
return Qtrue;
}
return Qfalse;
}
VALUE uwsgi_ruby_register_rpc(int argc, VALUE *argv, VALUE *class) {
int rb_argc = 0;
if (argc < 2) goto clear;
if (argc > 2) {
Check_Type(argv[2], T_FIXNUM);
rb_argc = NUM2INT(argv[2]);
}
Check_Type(argv[0], T_STRING);
char *name = RSTRING_PTR(argv[0]);
void *func = (void *) argv[1];
if (uwsgi_register_rpc(name, 7, rb_argc, func)) {
clear:
rb_raise(rb_eRuntimeError, "unable to register rpc function");
return Qnil;
}
rb_gc_register_address(&argv[1]);
rb_ary_push(ur.rpc_protector, argv[1]);
return Qtrue;
}
VALUE uwsgi_ruby_register_signal(VALUE *class, VALUE signum, VALUE sigkind, VALUE rbhandler) {
Check_Type(signum, T_FIXNUM);
Check_Type(sigkind, T_STRING);
uint8_t uwsgi_signal = NUM2INT(signum);
char *signal_kind = RSTRING_PTR(sigkind);
if (uwsgi_register_signal(uwsgi_signal, signal_kind, (void *) rbhandler, 7)) {
rb_raise(rb_eRuntimeError, "unable to register signal %d", uwsgi_signal);
return Qnil;
}
rb_gc_register_address(&rbhandler);
rb_ary_push(ur.signals_protector, rbhandler);
return Qtrue;
}
VALUE uwsgi_ruby_signal(int argc, VALUE *argv, VALUE *class) {
if (argc < 1) {
rb_raise(rb_eRuntimeError, "you have to specify a signum");
return Qnil;
}
Check_Type(argv[0], T_FIXNUM);
uint8_t uwsgi_signal = NUM2INT(argv[0]);
if (argc > 1) {
Check_Type(argv[1], T_STRING);
char *remote = RSTRING_PTR(argv[1]);
int ret = uwsgi_remote_signal_send(remote, uwsgi_signal);
if (ret == 1) return Qtrue;
if (ret == -1) {
rb_raise(rb_eRuntimeError, "unable to deliver signal %d to node %s", uwsgi_signal, remote);
return Qnil;
}
if (ret == 0) {
rb_raise(rb_eRuntimeError, "node %s rejected signal %d", remote, uwsgi_signal);
return Qnil;
}
}
else {
uwsgi_signal_send(uwsgi.signal_socket, uwsgi_signal);
}
return Qtrue;
}
void uwsgi_rack_init_api() {
VALUE rb_uwsgi_embedded = rb_define_module("UWSGI");
uwsgi_rack_api("suspend", uwsgi_ruby_suspend, 0);
uwsgi_rack_api("masterpid", uwsgi_ruby_masterpid, 0);
uwsgi_rack_api("async_sleep", uwsgi_ruby_async_sleep, 1);
uwsgi_rack_api("wait_fd_read", uwsgi_ruby_wait_fd_read, 2);
uwsgi_rack_api("wait_fd_write", uwsgi_ruby_wait_fd_write, 2);
uwsgi_rack_api("async_connect", uwsgi_ruby_async_connect, 1);
uwsgi_rack_api("signal", uwsgi_ruby_signal, -1);
uwsgi_rack_api("register_signal", uwsgi_ruby_register_signal, 3);
uwsgi_rack_api("register_rpc", uwsgi_ruby_register_rpc, -1);
uwsgi_rack_api("signal_registered", uwsgi_ruby_signal_registered, 1);
uwsgi_rack_api("signal_wait", uwsgi_ruby_signal_wait, -1);
uwsgi_rack_api("signal_received", uwsgi_ruby_signal_received, 0);
uwsgi_rack_api("add_cron", rack_uwsgi_add_cron, 6);
uwsgi_rack_api("add_timer", rack_uwsgi_add_timer, 2);
uwsgi_rack_api("add_rb_timer", rack_uwsgi_add_rb_timer, 2);
uwsgi_rack_api("add_file_monitor", rack_uwsgi_add_file_monitor, 2);
uwsgi_rack_api("setprocname", rack_uwsgi_setprocname, 1);
uwsgi_rack_api("mem", rack_uwsgi_mem, 0);
uwsgi_rack_api("lock", rack_uwsgi_lock, -1);
uwsgi_rack_api("unlock", rack_uwsgi_unlock, -1);
uwsgi_rack_api("mule_get_msg", rack_uwsgi_mule_get_msg, -1);
uwsgi_rack_api("mule_msg", rack_uwsgi_mule_msg, -1);
uwsgi_rack_api("request_id", rack_uwsgi_request_id, 0);
uwsgi_rack_api("worker_id", rack_uwsgi_worker_id, 0);
uwsgi_rack_api("mule_id", rack_uwsgi_mule_id, 0);
uwsgi_rack_api("logsize", rack_uwsgi_logsize, 0);
if (uwsgi.cache_max_items > 0) {
uwsgi_rack_api("cache_get", rack_uwsgi_cache_get, 1);
uwsgi_rack_api("cache_get!", rack_uwsgi_cache_get_exc, 1);
uwsgi_rack_api("cache_exists", rack_uwsgi_cache_exists, 1);
uwsgi_rack_api("cache_exists?", rack_uwsgi_cache_exists, 1);
uwsgi_rack_api("cache_del", rack_uwsgi_cache_del, 1);
uwsgi_rack_api("cache_set", rack_uwsgi_cache_set, 2);
uwsgi_rack_api("cache_set!", rack_uwsgi_cache_set_exc, 2);
uwsgi_rack_api("cache_update", rack_uwsgi_cache_update, 2);
uwsgi_rack_api("cache_update!", rack_uwsgi_cache_update_exc, 2);
}
VALUE uwsgi_rb_opt_hash = rb_hash_new();
int i;
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
VALUE rb_uwsgi_opt_key = rb_str_new2(uwsgi.exported_opts[i]->key);
if ( rb_funcall(uwsgi_rb_opt_hash, rb_intern("has_key?"), 1, rb_uwsgi_opt_key) == Qtrue) {
VALUE rb_uwsgi_opt_item = rb_hash_aref(uwsgi_rb_opt_hash, rb_uwsgi_opt_key);
if (TYPE(rb_uwsgi_opt_item) == T_ARRAY) {
if (uwsgi.exported_opts[i]->value == NULL) {
rb_ary_push(rb_uwsgi_opt_item, Qtrue);
}
else {
rb_ary_push(rb_uwsgi_opt_item, rb_str_new2(uwsgi.exported_opts[i]->value));
}
}
else {
VALUE rb_uwsgi_opt_list = rb_ary_new();
rb_ary_push(rb_uwsgi_opt_list, rb_uwsgi_opt_item);
if (uwsgi.exported_opts[i]->value == NULL) {
rb_ary_push(rb_uwsgi_opt_list, Qtrue);
}
else {
rb_ary_push(rb_uwsgi_opt_list, rb_str_new2(uwsgi.exported_opts[i]->value));
}
rb_hash_aset(uwsgi_rb_opt_hash, rb_uwsgi_opt_key, rb_uwsgi_opt_list);
}
}
else {
if (uwsgi.exported_opts[i]->value == NULL) {
rb_hash_aset(uwsgi_rb_opt_hash, rb_uwsgi_opt_key, Qtrue);
}
else {
rb_hash_aset(uwsgi_rb_opt_hash, rb_uwsgi_opt_key, rb_str_new2(uwsgi.exported_opts[i]->value));
}
}
}
rb_const_set(rb_uwsgi_embedded, rb_intern("OPT"), uwsgi_rb_opt_hash);
rb_const_set(rb_uwsgi_embedded, rb_intern("VERSION"), rb_str_new2(UWSGI_VERSION));
rb_const_set(rb_uwsgi_embedded, rb_intern("HOSTNAME"), rb_str_new(uwsgi.hostname, uwsgi.hostname_len));
if (uwsgi.pidfile) {
rb_const_set(rb_uwsgi_embedded, rb_intern("PIDFILE"), rb_str_new2(uwsgi.pidfile));
}
rb_const_set(rb_uwsgi_embedded, rb_intern("NUMPROC"), INT2NUM(uwsgi.numproc));
}
+187 -204
View File
@@ -9,6 +9,12 @@ struct option uwsgi_rack_options[] = {
{"rails", required_argument, 0, LONG_ARGS_RAILS},
{"rack", required_argument, 0, LONG_ARGS_RACK},
{"ruby-gc-freq", required_argument, 0, LONG_ARGS_RUBY_GC_FREQ},
{"rb-gc-freq", required_argument, 0, LONG_ARGS_RUBY_GC_FREQ},
{"rb-require", required_argument, 0, LONG_ARGS_RUBY_REQUIRE},
{"ruby-require", required_argument, 0, LONG_ARGS_RUBY_REQUIRE},
{"rbrequire", required_argument, 0, LONG_ARGS_RUBY_REQUIRE},
{"rubyrequire", required_argument, 0, LONG_ARGS_RUBY_REQUIRE},
{"require", required_argument, 0, LONG_ARGS_RUBY_REQUIRE},
{"rbshell", optional_argument, 0, LONG_ARGS_RUBY_SHELL},
{0, 0, 0, 0},
@@ -127,6 +133,10 @@ VALUE rb_uwsgi_io_rewind(VALUE obj, VALUE args) {
RUBY_GLOBAL_SETUP
#endif
VALUE uwsgi_require_file(VALUE arg) {
return rb_funcall(rb_cObject, rb_intern("require"), 1, arg);
}
VALUE require_rack(VALUE arg) {
return rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("rack"));
}
@@ -141,200 +151,51 @@ VALUE require_rails(VALUE arg) {
VALUE init_rack_app(VALUE);
VALUE uwsgi_ruby_signal_registered(VALUE *class, VALUE signum) {
uint8_t uwsgi_signal = NUM2INT(signum);
if (uwsgi_signal_registered(uwsgi_signal)) {
return Qtrue;
}
return Qfalse;
VALUE rack_call_rpc_handler(VALUE args) {
VALUE rpc_args = rb_ary_entry(args, 1);
return rb_funcall2(rb_ary_entry(args, 0), rb_intern("call"), RARRAY_LEN(rpc_args), RARRAY_PTR(rpc_args));
}
VALUE uwsgi_ruby_register_signal(VALUE *class, VALUE signum, VALUE sigkind, VALUE rbhandler) {
uint8_t uwsgi_signal = NUM2INT(signum);
char *signal_kind = RSTRING_PTR(sigkind);
if (uwsgi_register_signal(uwsgi_signal, signal_kind, (void *) rbhandler, 7)) {
rb_raise(rb_eRuntimeError, "unable to register signal %d", uwsgi_signal);
return Qnil;
}
rb_gc_register_address(&rbhandler);
return Qtrue;
}
VALUE uwsgi_ruby_signal(VALUE *class, VALUE signum) {
uint8_t uwsgi_signal = NUM2INT(signum);
ssize_t rlen;
rlen = write(uwsgi.signal_socket, &uwsgi_signal, 1);
if (rlen != 1) {
uwsgi_error("write()");
}
return Qtrue;
}
VALUE rack_call_signal_handler(VALUE args) {
return rb_funcall(rb_ary_entry(args, 0), rb_intern("call"), 1, rb_ary_entry(args, 1));
}
int uwsgi_rack_signal_handler(uint8_t sig, void *handler) {
uint16_t uwsgi_ruby_rpc(void *func, uint8_t argc, char **argv, char *buffer) {
uint8_t i;
VALUE rb_args = rb_ary_new2(2);
VALUE rb_rpc_args = rb_ary_new2(argc);
VALUE ret;
int error = 0;
char *rv;
size_t rl;
VALUE rbhandler = (VALUE) handler;
VALUE args = rb_ary_new2(2);
rb_ary_store(args, 0, rbhandler);
VALUE rbsig = INT2NUM(sig);
rb_ary_store(args, 1, rbsig);
VALUE ret = rb_protect(rack_call_signal_handler, args, &error);
if (error) {
uwsgi_ruby_exception();
// free resources (useless ?)
rb_gc_unregister_address(&args);
rb_gc_unregister_address(&ret);
rb_gc_unregister_address(&rbsig);
return -1;
rb_ary_store(rb_args, 0, (VALUE) func);
for (i = 0; i < argc; i++) {
rb_ary_store(rb_rpc_args, i, rb_str_new2(argv[i]));
}
rb_ary_store(rb_args, 1, rb_rpc_args);
ret = rb_protect(rack_call_rpc_handler, rb_args, &error);
if (error) {
uwsgi_ruby_exception();
return 0;
}
// free resources (useless ?)
rb_gc_unregister_address(&args);
rb_gc_unregister_address(&ret);
rb_gc_unregister_address(&rbsig);
return 0;
}
VALUE rack_uwsgi_add_cron(VALUE *class, VALUE rbsignum, VALUE rbmin, VALUE rbhour, VALUE rbday, VALUE rbmon, VALUE rbweek) {
uint8_t uwsgi_signal = NUM2INT(rbsignum);
int minute = NUM2INT(rbmin);
int hour = NUM2INT(rbhour);
int day = NUM2INT(rbday);
int month = NUM2INT(rbmon);
int week = NUM2INT(rbweek);
if (uwsgi_signal_add_cron(uwsgi_signal, minute, hour, day, month, week)) {
rb_raise(rb_eRuntimeError, "unable to add cron");
return Qnil;
if (TYPE(ret) == T_STRING) {
rv = RSTRING_PTR(ret);
rl = RSTRING_LEN(ret);
if (rl <= 0xffff) {
memcpy(buffer, rv, rl);
return rl;
}
}
return Qtrue;
return 0;
}
VALUE rack_uwsgi_add_timer(VALUE *class, VALUE rbsignum, VALUE secs) {
uint8_t uwsgi_signal = NUM2INT(rbsignum);
int seconds = NUM2INT(secs);
if (uwsgi_add_timer(uwsgi_signal, seconds)) {
rb_raise(rb_eRuntimeError, "unable to add timer");
return Qnil;
}
return Qtrue;
}
VALUE rack_uwsgi_add_rb_timer(VALUE *class, VALUE rbsignum, VALUE secs) {
uint8_t uwsgi_signal = NUM2INT(rbsignum);
int seconds = NUM2INT(secs);
if (uwsgi_signal_add_rb_timer(uwsgi_signal, seconds, 0)) {
rb_raise(rb_eRuntimeError, "unable to add rb_timer");
return Qnil;
}
return Qtrue;
}
VALUE rack_uwsgi_add_file_monitor(VALUE *class, VALUE rbsignum, VALUE rbfilename) {
uint8_t uwsgi_signal = NUM2INT(rbsignum);
char *filename = RSTRING_PTR(rbfilename);
if (uwsgi_add_file_monitor(uwsgi_signal, filename)) {
rb_raise(rb_eRuntimeError, "unable to add file monitor");
return Qnil;
}
return Qtrue;
}
VALUE uwsgi_ruby_wait_fd_read(VALUE *class, VALUE arg1, VALUE arg2) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int fd = NUM2INT(arg1);
int timeout = NUM2INT(arg2);
if (fd >= 0) {
async_add_fd_read(wsgi_req, fd, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_wait_fd_write(VALUE *class, VALUE arg1, VALUE arg2) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int fd = NUM2INT(arg1);
int timeout = NUM2INT(arg2);
if (fd >= 0) {
async_add_fd_write(wsgi_req, fd, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_async_connect(VALUE *class, VALUE arg) {
int fd = uwsgi_connect(RSTRING_PTR(arg), 0, 1);
return INT2FIX(fd);
}
VALUE uwsgi_ruby_async_sleep(VALUE *class, VALUE arg) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int timeout = NUM2INT(arg);
if (timeout >= 0) {
async_add_timeout(wsgi_req, timeout);
}
return Qtrue;
}
VALUE uwsgi_ruby_suspend(VALUE *class) {
struct wsgi_request *wsgi_req = current_wsgi_req();
uwsgi.schedule_to_main(wsgi_req);
return Qtrue;
}
int uwsgi_rack_init(){
struct http_status_codes *http_sc;
@@ -358,7 +219,6 @@ int uwsgi_rack_init(){
ruby_init();
ruby_process_options(argc, argv);
#else
ruby_init();
ruby_init_loadpath();
#endif
@@ -366,19 +226,14 @@ int uwsgi_rack_init(){
ruby_script("uwsgi");
VALUE rb_uwsgi_embedded = rb_define_module("UWSGI");
rb_define_module_function(rb_uwsgi_embedded, "suspend", uwsgi_ruby_suspend, 0);
rb_define_module_function(rb_uwsgi_embedded, "async_sleep", uwsgi_ruby_async_sleep, 1);
rb_define_module_function(rb_uwsgi_embedded, "wait_fd_read", uwsgi_ruby_wait_fd_read, 2);
rb_define_module_function(rb_uwsgi_embedded, "wait_fd_write", uwsgi_ruby_wait_fd_write, 2);
rb_define_module_function(rb_uwsgi_embedded, "async_connect", uwsgi_ruby_async_connect, 1);
rb_define_module_function(rb_uwsgi_embedded, "signal", uwsgi_ruby_signal, 1);
rb_define_module_function(rb_uwsgi_embedded, "register_signal", uwsgi_ruby_register_signal, 3);
rb_define_module_function(rb_uwsgi_embedded, "signal_registered", uwsgi_ruby_signal_registered, 1);
rb_define_module_function(rb_uwsgi_embedded, "add_cron", rack_uwsgi_add_cron, 6);
rb_define_module_function(rb_uwsgi_embedded, "add_timer", rack_uwsgi_add_timer, 2);
rb_define_module_function(rb_uwsgi_embedded, "add_rb_timer", rack_uwsgi_add_rb_timer, 2);
rb_define_module_function(rb_uwsgi_embedded, "add_file_monitor", rack_uwsgi_add_file_monitor, 2);
ur.signals_protector = rb_ary_new();
ur.rpc_protector = rb_ary_new();
rb_gc_register_address(&ur.signals_protector);
rb_gc_register_address(&ur.rpc_protector);
#ifdef UWSGI_EMBEDDED
uwsgi_rack_init_api();
#endif
return 0;
}
@@ -386,6 +241,17 @@ int uwsgi_rack_init(){
void uwsgi_rack_init_apps(void) {
int error;
ur.app_id = uwsgi_apps_cnt;
struct uwsgi_string_list *usl = ur.rbrequire;
while(usl) {
error = 0;
rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ;
if (error) {
uwsgi_ruby_exception();
}
usl = usl->next;
}
if (ur.rack) {
ur.dispatcher = rb_protect(init_rack_app, rb_str_new2(ur.rack), &error);
@@ -448,6 +314,14 @@ ready:
rb_define_method(ur.rb_uwsgi_io_class, "read", rb_uwsgi_io_read, -2);
rb_define_method(ur.rb_uwsgi_io_class, "rewind", rb_uwsgi_io_rewind, 0);
uwsgi_add_app(ur.app_id, 7, (char*)"", 0);
if (ur.gc_freq <= 1) {
uwsgi_log("RACK app %d loaded at %p (GC frequency: AGGRESSIVE)\n", ur.app_id, ur.call);
}
else {
uwsgi_log("RACK app %d loaded at %p (GC frequency: %d)\n", ur.app_id, ur.call, ur.gc_freq);
}
}
VALUE call_dispatch(VALUE env) {
@@ -523,7 +397,7 @@ VALUE send_header(VALUE obj, VALUE headers) {
len = wsgi_req->socket->proto_write_header( wsgi_req, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
wsgi_req->headers_size += len;
len = wsgi_req->socket->proto_write_header( wsgi_req, ": ", 2);
len = wsgi_req->socket->proto_write_header( wsgi_req, (char *)": ", 2);
wsgi_req->headers_size += len;
char *header_value = RSTRING_PTR(hval);
@@ -534,7 +408,7 @@ VALUE send_header(VALUE obj, VALUE headers) {
if (!header_value_splitted) {
len = wsgi_req->socket->proto_write_header( wsgi_req, header_value, header_value_len);
wsgi_req->headers_size += len;
len = wsgi_req->socket->proto_write_header( wsgi_req, "\r\n", 2);
len = wsgi_req->socket->proto_write_header( wsgi_req, (char *)"\r\n", 2);
wsgi_req->headers_size += len;
wsgi_req->header_cnt++;
}
@@ -542,7 +416,7 @@ VALUE send_header(VALUE obj, VALUE headers) {
header_value_splitted[0] = 0;
len = wsgi_req->socket->proto_write_header( wsgi_req, header_value, header_value_splitted-header_value);
wsgi_req->headers_size += len;
len = wsgi_req->socket->proto_write_header( wsgi_req, "\r\n", 2);
len = wsgi_req->socket->proto_write_header( wsgi_req, (char *)"\r\n", 2);
wsgi_req->headers_size += len;
wsgi_req->header_cnt++;
@@ -554,12 +428,12 @@ VALUE send_header(VALUE obj, VALUE headers) {
len = wsgi_req->socket->proto_write( wsgi_req, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
wsgi_req->headers_size += len;
len = wsgi_req->socket->proto_write( wsgi_req, ": ", 2);
len = wsgi_req->socket->proto_write( wsgi_req, (char *)": ", 2);
wsgi_req->headers_size += len;
len = wsgi_req->socket->proto_write( wsgi_req, header_value, header_value_splitted-header_value);
wsgi_req->headers_size += len;
len = wsgi_req->socket->proto_write( wsgi_req, "\r\n", 2);
len = wsgi_req->socket->proto_write( wsgi_req, (char *)"\r\n", 2);
wsgi_req->headers_size += len;
wsgi_req->header_cnt++;
@@ -608,6 +482,9 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
return -1;
}
wsgi_req->app_id = ur.app_id;
uwsgi_apps[wsgi_req->app_id].requests++;
env = rb_hash_new();
@@ -741,7 +618,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
}
}
if (wsgi_req->socket->proto_write(wsgi_req, "\r\n", 2) != 2) {
if (wsgi_req->socket->proto_write(wsgi_req, (char *)"\r\n", 2) != 2) {
uwsgi_error("write()");
}
@@ -791,7 +668,7 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
}
else {
internal_server_error(wsgi_req, "Invalid RACK response");
internal_server_error(wsgi_req, (char *)"Invalid RACK response");
}
clear:
@@ -801,7 +678,9 @@ clear:
rb_gc_unregister_address(&env);
if (ur.gc_freq <= 1 || ur.cycles%ur.gc_freq == 0) {
//uwsgi_log("calling ruby GC\n");
#ifdef UWSGI_DEBUG
uwsgi_log("calling ruby GC\n");
#endif
rb_gc();
}
@@ -835,6 +714,9 @@ int uwsgi_rack_manage_options(int i, char *optarg) {
case LONG_ARGS_RUBY_GC_FREQ:
ur.gc_freq = atoi(optarg);
return 1;
case LONG_ARGS_RUBY_REQUIRE:
uwsgi_string_new_list(&ur.rbrequire, optarg);
return 1;
}
return 0;
@@ -924,6 +806,102 @@ int uwsgi_rack_mount_app(char *mountpoint, char *app) {
void uwsgi_rack_hijack(void) {
}
int uwsgi_rack_mule(char *opt) {
int error = 0;
if (uwsgi_endswith(opt, (char *)".rb")) {
rb_protect( uwsgi_require_file, rb_str_new2(opt), &error ) ;
if (error) {
uwsgi_ruby_exception();
return 0;
}
return 1;
}
return 0;
}
VALUE uwsgi_rb_pfh(VALUE args) {
VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI"));
if (rb_respond_to(uwsgi_rb_embedded, rb_intern("post_fork_hook"))) {
return rb_funcall(uwsgi_rb_embedded, rb_intern("post_fork_hook"), 0);
}
return Qnil;
}
void uwsgi_rb_post_fork() {
int error = 0;
// call the post_fork_hook
rb_protect(uwsgi_rb_pfh, 0, &error);
if (error) {
uwsgi_ruby_exception();
}
}
VALUE uwsgi_rb_mmh(VALUE args) {
VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI"));
return rb_funcall(uwsgi_rb_embedded, rb_intern("mule_msg_hook"), 1, args);
}
int uwsgi_rack_mule_msg(char *message, size_t len) {
int error = 0;
VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI"));
if (rb_respond_to(uwsgi_rb_embedded, rb_intern("mule_msg_hook"))) {
VALUE arg = rb_str_new(message, len);
rb_protect(uwsgi_rb_mmh, arg, &error);
if (error) {
uwsgi_ruby_exception();
}
return 1;
}
return 0;
}
VALUE rack_call_signal_handler(VALUE args) {
return rb_funcall(rb_ary_entry(args, 0), rb_intern("call"), 1, rb_ary_entry(args, 1));
}
int uwsgi_rack_signal_handler(uint8_t sig, void *handler) {
int error = 0;
VALUE rbhandler = (VALUE) handler;
VALUE args = rb_ary_new2(2);
rb_ary_store(args, 0, rbhandler);
VALUE rbsig = INT2NUM(sig);
rb_ary_store(args, 1, rbsig);
VALUE ret = rb_protect(rack_call_signal_handler, args, &error);
if (error) {
uwsgi_ruby_exception();
// free resources (useless ?)
rb_gc_unregister_address(&args);
rb_gc_unregister_address(&ret);
rb_gc_unregister_address(&rbsig);
rb_gc();
return -1;
}
// free resources (useless ?)
rb_gc_unregister_address(&args);
rb_gc_unregister_address(&ret);
rb_gc_unregister_address(&rbsig);
rb_gc();
return 0;
}
struct uwsgi_plugin rack_plugin = {
.name = "rack",
@@ -936,7 +914,8 @@ struct uwsgi_plugin rack_plugin = {
.signal_handler = uwsgi_rack_signal_handler,
.hijack = uwsgi_rack_hijack,
.hijack_worker = uwsgi_rack_hijack,
.post_fork = uwsgi_rb_post_fork,
.init_apps = uwsgi_rack_init_apps,
//.mount_app = uwsgi_rack_mount_app,
@@ -944,6 +923,10 @@ struct uwsgi_plugin rack_plugin = {
.magic = uwsgi_rack_magic,
.mule = uwsgi_rack_mule,
.mule_msg = uwsgi_rack_mule_msg,
.rpc = uwsgi_ruby_rpc,
.suspend = uwsgi_rack_suspend,
.resume = uwsgi_rack_resume,
};
+10
View File
@@ -7,6 +7,7 @@
#define LONG_ARGS_RUBY_GC_FREQ LONG_ARGS_RACK_BASE + 2
#define LONG_ARGS_RACK LONG_ARGS_RACK_BASE + 3
#define LONG_ARGS_RUBY_SHELL LONG_ARGS_RACK_BASE + 4
#define LONG_ARGS_RUBY_REQUIRE LONG_ARGS_RACK_BASE + 5
#ifndef RUBY19
#define rb_errinfo() ruby_errinfo
@@ -52,6 +53,11 @@ struct uwsgi_rack {
uint64_t cycles;
int call_gc;
// why why why !!!!????!!!???
VALUE signals_protector;
VALUE rpc_protector;
VALUE dispatcher;
VALUE rb_uwsgi_io_class;
ID call;
@@ -61,7 +67,11 @@ struct uwsgi_rack {
pthread_mutex_t gvl;
int rb_shell;
int app_id;
struct uwsgi_string_list *rbrequire;
};
void uwsgi_ruby_exception(void);
void uwsgi_rack_init_api(void);
+22 -18
View File
@@ -7,33 +7,37 @@ try:
except:
RUBYPATH = 'ruby'
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
rbconfig = 'Config'
version = os.popen(RUBYPATH + " -e \"print RUBY_VERSION\"").read().rstrip()
v = version.split('.')
GCC_LIST = ['rack_plugin']
GCC_LIST = ['rack_plugin', 'rack_api']
if v[0] == '1' and v[1] == '9':
CFLAGS.append('-DRUBY19')
CFLAGS.append('-Wno-unused-parameter')
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
if includedir == 'nil':
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
CFLAGS.append('-I' + includedir)
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['CFLAGS']\"").read().rstrip().split()
CFLAGS.append('-DRUBY19')
CFLAGS.append('-Wno-unused-parameter')
rbconfig = 'RbConfig'
else:
CFLAGS.append('-I' + includedir)
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['arch']\"").read().rstrip()
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['CFLAGS']\"" % rbconfig).read().rstrip().split()
LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['LDFLAGS']\"").read().rstrip().split()
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyhdrdir']\"" % rbconfig).read().rstrip()
if includedir == 'nil':
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip()
CFLAGS.append('-I' + includedir)
else:
CFLAGS.append('-I' + includedir)
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip()
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip()
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
libpath = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['libdir']\"").read().rstrip()
LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LDFLAGS']\"" % rbconfig).read().rstrip().split()
libpath = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['libdir']\"" % rbconfig).read().rstrip()
LDFLAGS.append('-L' + libpath )
os.environ['LD_RUN_PATH'] = libpath
LIBS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print '-l' + Config::CONFIG['RUBY_SO_NAME']\"").read().rstrip().split()
LIBS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print '-l' + %s::CONFIG['RUBY_SO_NAME']\"" % rbconfig).read().rstrip().split()
+10 -2
View File
@@ -5,6 +5,7 @@ extern struct uwsgi_server uwsgi;
#define RRDTOOL_OPT_BASE 177000
#define RRDTOOL_OPT_RRDTOOL RRDTOOL_OPT_BASE+1
#define RRDTOOL_OPT_RRDTOOL_MAX_DS RRDTOOL_OPT_BASE+2
#define RRDTOOL_OPT_RRDTOOL_FREQ RRDTOOL_OPT_BASE+3
struct uwsgi_rrdtool {
void *lib;
@@ -12,12 +13,14 @@ struct uwsgi_rrdtool {
int (*update)(int, char **);
struct uwsgi_string_list *rrd;
int max_ds;
int freq;
char *update_area;
} u_rrd;
struct option rrdtool_options[] = {
{"rrdtool", required_argument, 0, RRDTOOL_OPT_RRDTOOL},
{"rrdtool-freq", required_argument, 0, RRDTOOL_OPT_RRDTOOL_FREQ},
{"rrdtool-max-ds", required_argument, 0, RRDTOOL_OPT_RRDTOOL_MAX_DS},
{0, 0, 0, 0},
@@ -58,6 +61,9 @@ int rrdtool_opt(int i, char *optarg) {
case RRDTOOL_OPT_RRDTOOL_MAX_DS:
u_rrd.max_ds = atoi(optarg);
return 1;
case RRDTOOL_OPT_RRDTOOL_FREQ:
u_rrd.freq = atoi(optarg);
return 1;
}
return 0;
@@ -132,6 +138,8 @@ void rrdtool_post_init() {
u_rrd.update_area[0] = 'N';
if (u_rrd.freq < 1) u_rrd.freq = 300;
}
void rrdtool_master_cycle() {
@@ -146,8 +154,8 @@ void rrdtool_master_cycle() {
if (last_update == 0) last_update = time(NULL);
// update every 5 minutes
if (uwsgi.current_time - last_update >= 300) {
// update
if (uwsgi.current_time - last_update >= u_rrd.freq) {
ptr = u_rrd.update_area+1;
rlen = snprintf(ptr, 1+sizeof(UMAX64_STR), ":%llu", (unsigned long long )uwsgi.workers[0].requests);
if (rlen < 2) return;
+28 -19
View File
@@ -3,34 +3,43 @@ import os,sys
NAME='ruby19'
try:
RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH']
RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH']
except:
RUBYPATH = 'ruby'
RUBYPATH = 'ruby'
GCC_LIST = ['../rack/rack_plugin']
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
rbconfig = 'Config'
version = os.popen(RUBYPATH + " -e \"print RUBY_VERSION\"").read().rstrip()
v = version.split('.')
if v[0] == '1' and v[1] == '9':
CFLAGS.append('-DRUBY19')
GCC_LIST = ['../rack/rack_plugin', '../rack/rack_api']
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
if includedir == 'nil':
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
CFLAGS.append('-I' + includedir)
if v[0] == '1' and v[1] == '9':
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['CFLAGS']\"").read().rstrip().split()
CFLAGS.append('-DRUBY19')
CFLAGS.append('-Wno-unused-parameter')
rbconfig = 'RbConfig'
else:
CFLAGS.append('-I' + includedir)
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['arch']\"").read().rstrip()
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['CFLAGS']\"" % rbconfig).read().rstrip().split()
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyhdrdir']\"" % rbconfig).read().rstrip()
if includedir == 'nil':
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip()
CFLAGS.append('-I' + includedir)
else:
CFLAGS.append('-I' + includedir)
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip()
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip()
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
CFLAGS.append('-Drack_plugin=ruby19_plugin')
LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['LDFLAGS']\"").read().rstrip().split()
LDFLAGS.append('-L' + os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['libdir']\"").read().rstrip() )
LIBS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print '-l' + Config::CONFIG['RUBY_SO_NAME']\"").read().rstrip().split()
LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LDFLAGS']\"" % rbconfig).read().rstrip().split()
libpath = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['libdir']\"" % rbconfig).read().rstrip()
LDFLAGS.append('-L' + libpath )
os.environ['LD_RUN_PATH'] = libpath
LIBS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print '-l' + %s::CONFIG['RUBY_SO_NAME']\"" % rbconfig).read().rstrip().split()
+32
View File
@@ -0,0 +1,32 @@
#include "../../uwsgi.h"
extern struct uwsgi_server uwsgi;
/* request 110 */
int uwsgi_request_signal(struct wsgi_request *wsgi_req) {
ssize_t len;
uint8_t ret_status = 1;
if (uwsgi_signal_send(uwsgi.signal_socket, wsgi_req->uh.modifier2) < 0) {
ret_status = 0;
}
wsgi_req->uh.modifier1 = 255;
wsgi_req->uh.pktsize = 0;
wsgi_req->uh.modifier2 = ret_status;
len = write(wsgi_req->poll.fd, wsgi_req, 4);
if (len != 4) {
uwsgi_error("write()");
}
return UWSGI_OK;
}
struct uwsgi_plugin signal_plugin = {
.name = "signal",
.modifier1 = 110,
.request = uwsgi_request_signal,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='signal'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['signal_plugin']
+4
View File
@@ -280,7 +280,9 @@ ssize_t uwsgi_send_message(int fd, uint8_t modifier1, uint8_t modifier2, char *m
memcpy(CMSG_DATA(cmsg), &pfd, sizeof(int));
#ifdef UWSGI_DEBUG
uwsgi_log("passing fd\n");
#endif
cnt = sendmsg(fd, &msg, 0);
}
else {
@@ -403,7 +405,9 @@ int uwsgi_parse_array(char *buffer, uint16_t size, char **argv, uint8_t *argc) {
if (ptrbuf + strsize <= bufferend) {
// item
argv[*argc] = uwsgi_cheap_string(ptrbuf, strsize);
#ifdef UWSGI_DEBUG
uwsgi_log("arg %s\n", argv[*argc]);
#endif
ptrbuf += strsize;
*argc = *argc + 1;
}
+154 -21
View File
@@ -84,8 +84,13 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
strcpy(use->receiver, receiver);
use->handler = handler;
use->modifier1 = modifier1;
uwsgi_log("registered signal %d\n", sig);
if (use->receiver[0] == 0) {
uwsgi_log("[uwsgi-signal] signum %d registered (modifier1: %d target: default, any worker)\n", sig, modifier1);
}
else {
uwsgi_log("[uwsgi-signal] signum %d registered (modifier1: %d target: %s)\n", sig, modifier1, receiver);
}
uwsgi_unlock(uwsgi.signal_table_lock);
@@ -198,24 +203,110 @@ int uwsgi_signal_add_rb_timer(uint8_t sig, int secs, int iterations) {
}
void create_signal_pipe(int *sigpipe) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sigpipe)) {
uwsgi_error("socketpair()\n");
exit(1);
}
uwsgi_socket_nb(sigpipe[0]);
uwsgi_socket_nb(sigpipe[1]);
if (uwsgi.signal_bufsize) {
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
uwsgi_error("setsockopt()");
}
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
uwsgi_error("setsockopt()");
}
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
uwsgi_error("setsockopt()");
}
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
uwsgi_error("setsockopt()");
}
}
}
int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
struct uwsgi_header uh;
size_t remains = 4;
char *ptr = (char *) &uh;
uh.modifier1 = 110;
uh.pktsize = 0;
uh.modifier2 = sig;
int fd = uwsgi_connect(addr, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
if (fd < 0) return -1;
if (write(fd, (char *) &uh, 4) != 4) {
uwsgi_error("uwsgi_remote_signal_send()");
close(fd);
return -1;
}
while(remains > 0) {
int rlen = uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (rlen > 0) {
ssize_t len = read(fd, ptr, remains);
if (len <= 0) {
break;
}
remains -= len;
ptr += len;
if (remains == 0) {
close(fd);
return uh.modifier2;
}
continue;
}
break;
}
close(fd);
return -1;
}
int uwsgi_signal_send(int fd, uint8_t sig) {
socklen_t so_bufsize_len = sizeof(int);
int so_bufsize = 0;
if (write(fd, &sig, 1) != 1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
uwsgi_error("getsockopt()");
}
uwsgi_log("*** SIGNAL QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
}
else {
uwsgi_error("uwsgi_signal_send()");
}
return -1;
}
return 0;
}
void uwsgi_route_signal(uint8_t sig) {
int i;
struct uwsgi_signal_entry *use = &ushared->signal_table[sig];
int i;
// send to first available worker
if (use->receiver[0] == 0 || !strcmp(use->receiver, "worker") || !strcmp(use->receiver, "worker0")) {
if (write(ushared->worker_signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(ushared->worker_signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to workers pool\n", sig);
}
}
// send to all workers
else if (!strcmp(use->receiver, "workers")) {
for(i=1;i<=uwsgi.numproc;i++) {
if (write(uwsgi.workers[i].signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
}
}
@@ -226,8 +317,7 @@ void uwsgi_route_signal(uint8_t sig) {
if (i > uwsgi.numproc) {
uwsgi_log("invalid signal target: %s\n", use->receiver);
}
if (write(uwsgi.workers[i].signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
}
}
@@ -238,8 +328,7 @@ void uwsgi_route_signal(uint8_t sig) {
#ifdef UWSGI_SPOOLER
else if (!strcmp(use->receiver, "spooler")) {
if (ushared->worker_signal_pipe[0] != -1) {
if (write(ushared->spooler_signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to the spooler\n", sig);
}
}
@@ -247,8 +336,7 @@ void uwsgi_route_signal(uint8_t sig) {
#endif
else if (!strcmp(use->receiver, "mules")) {
for(i=0;i<uwsgi.mules_cnt;i++) {
if (write(uwsgi.mules[i].signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(uwsgi.mules[i].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i+1);
}
}
@@ -259,14 +347,12 @@ void uwsgi_route_signal(uint8_t sig) {
uwsgi_log("invalid signal target: %s\n", use->receiver);
}
else if (i == 0) {
if (write(ushared->mule_signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(ushared->mule_signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to a mule\n", sig);
}
}
else {
if (write(uwsgi.mules[i-1].signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(uwsgi.mules[i-1].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i);
}
}
@@ -278,8 +364,7 @@ void uwsgi_route_signal(uint8_t sig) {
uwsgi_log("unknown farm: %s\n", name);
return;
}
if (write(uf->signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(uf->signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, uf->id, uf->name);
}
}
@@ -289,8 +374,7 @@ void uwsgi_route_signal(uint8_t sig) {
uwsgi_log("invalid signal target: %s\n", use->receiver);
}
else {
if (write(uwsgi.farms[i-1].signal_pipe[0], &sig, 1) != 1) {
uwsgi_error("write()");
if (uwsgi_signal_send(uwsgi.farms[i-1].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, i, uwsgi.farms[i-1].name);
}
}
@@ -300,4 +384,53 @@ void uwsgi_route_signal(uint8_t sig) {
// unregistered signal, sending it to all the workers
uwsgi_log("^^^ UNSUPPORTED SIGNAL TARGET: %s ^^^\n", use->receiver);
}
}
uint8_t uwsgi_signal_wait(int signum) {
int wait_for_specific_signal = 0;
uint8_t uwsgi_signal = 0;
uint8_t received_signal;
int ret;
struct pollfd pfd[2];
if (signum > -1) {
wait_for_specific_signal = 1;
}
pfd[0].fd = uwsgi.signal_socket;
pfd[0].events = POLLIN;
pfd[1].fd = uwsgi.my_signal_socket;
pfd[1].events = POLLIN;
cycle:
ret = poll(pfd, 2, -1);
if (ret > 0) {
if (pfd[0].revents == POLLIN) {
if (read(uwsgi.signal_socket, &received_signal, 1) != 1) {
uwsgi_error("read()");
}
else {
(void)uwsgi_signal_handler(received_signal);
if (wait_for_specific_signal) {
if (received_signal != uwsgi_signal) goto cycle;
}
}
}
if (pfd[1].revents == POLLIN) {
if (read(uwsgi.my_signal_socket, &received_signal, 1) != 1) {
uwsgi_error("read()");
}
else {
(void)uwsgi_signal_handler(received_signal);
if (wait_for_specific_signal) {
if (received_signal != uwsgi_signal) goto cycle;
}
}
}
}
return received_signal;
}
+127
View File
@@ -717,8 +717,96 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uwsgi.loyal = 1;
}
#ifdef __linux__
#ifdef MADV_MERGEABLE
// run the ksm mapper
if (uwsgi.linux_ksm > 0 && (uwsgi.workers[uwsgi.mywid].requests % uwsgi.linux_ksm) == 0) {
uwsgi_linux_ksm_map();
}
#endif
#endif
}
#ifdef __linux__
#ifdef MADV_MERGEABLE
unsigned long long *ksm_mappings_last = NULL;
int ksm_mappings_last_lines = 0;
unsigned long long *ksm_mappings_current = NULL;
int ksm_mappings_current_lines = 0;
void uwsgi_linux_ksm_map(void) {
char map_line_buf[1024];
unsigned long long start, end;
int dirty = 0;
int i;
int errors = 0;
unsigned long long *tmp_ptr;
ksm_mappings_current = NULL;
ksm_mappings_current_lines = 0;
FILE *process_maps = fopen("/proc/self/maps", "r");
if (process_maps) {
while( fgets(map_line_buf, 1024, process_maps)) {
if (fscanf(process_maps, "%llx-%llx %*s", &start, &end) == 2) {
ksm_mappings_current_lines+=2;
tmp_ptr = ksm_mappings_current;
ksm_mappings_current = realloc(ksm_mappings_current, sizeof(unsigned long long) * ksm_mappings_current_lines);
if (!ksm_mappings_current) {
uwsgi_error("[uwsgi-KSM] /proc/self/maps realloc()");
fclose(process_maps);
if (tmp_ptr) {
free(tmp_ptr);
}
return;
}
ksm_mappings_current[ksm_mappings_current_lines-2] = start;
ksm_mappings_current[ksm_mappings_current_lines-1] = end;
}
}
fclose(process_maps);
if (ksm_mappings_last == NULL || ksm_mappings_last_lines == 0 || ksm_mappings_last_lines != ksm_mappings_current_lines) {
dirty = 1;
}
else {
for(i=0;i<ksm_mappings_current_lines;i+=2) {
if (ksm_mappings_current[i] != ksm_mappings_last[i]) {
dirty = 1;
break;
}
if (ksm_mappings_current[i+1] != ksm_mappings_last[i+1]) {
dirty = 1;
break;
}
}
}
if (dirty) {
for(i=0;i<ksm_mappings_current_lines;i+=2) {
if (madvise((void *) (long) ksm_mappings_current[i], (size_t) (ksm_mappings_current[i+1]-ksm_mappings_current[i]), MADV_MERGEABLE)) {
errors += 2;
}
}
free(ksm_mappings_last);
ksm_mappings_last = ksm_mappings_current;
ksm_mappings_last_lines = ksm_mappings_current_lines;
if (errors >= ksm_mappings_current_lines) {
uwsgi_error("[uwsgi-KSM] unable to share pages");
}
}
}
}
#endif
#endif
void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id, struct uwsgi_socket *uwsgi_sock) {
wsgi_req->poll.events = POLLIN;
@@ -747,6 +835,16 @@ void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id, struct uwsgi_so
uwsgi.core[wsgi_req->async_id]->in_request = 0;
uwsgi.workers[uwsgi.mywid].busy = 0;
// now check for suspend request
if (uwsgi.workers[uwsgi.mywid].suspended == 1) {
uwsgi_log_verbose("*** worker %d suspended ***\n", uwsgi.mywid);
cycle:
// wait for some signal (normally SIGTSTP) or 10 seconds (as fallback)
(void) poll(NULL, 0, 10*1000);
if (uwsgi.workers[uwsgi.mywid].suspended == 1) goto cycle;
uwsgi_log_verbose("*** worker %d resumed ***\n", uwsgi.mywid);
}
}
#ifdef UWSGI_ASYNC
@@ -1622,6 +1720,10 @@ void add_exported_option(char *key, char *value, int configured) {
char *v = value;
if (value && strchr(value, ';')) {
v = uwsgi_str(value);
if (v[0] == '\\') {
_add_exported_option(key, v+1, configured);
return;
}
}
if (v == NULL) {
@@ -3049,8 +3151,12 @@ static struct uwsgi_cap uwsgi_cap_list[] = {
{ "setfcap", CAP_SETFCAP},
{ "mac_override", CAP_MAC_OVERRIDE},
{ "mac_admin", CAP_MAC_ADMIN},
#ifdef CAP_SYSLOG
{ "syslog", CAP_SYSLOG},
#endif
#ifdef CAP_WAKE_ALARM
{ "wake_alarm", CAP_WAKE_ALARM},
#endif
{ NULL, -1}
};
@@ -3285,3 +3391,24 @@ void http_url_decode(char *buf, uint16_t *len, char *dst) {
*len = new_len;
}
void uwsgi_add_app(int id, uint8_t modifier1, char *mountpoint, int mountpoint_len) {
struct uwsgi_app *wi = &uwsgi_apps[id];
memset(wi, 0, sizeof(struct uwsgi_app));
wi->modifier1 = modifier1;
wi->mountpoint = mountpoint;
wi->mountpoint_len = mountpoint_len;
uwsgi_apps_cnt++;
// check if we need to emulate fork() COW
int i;
if (uwsgi.mywid == 0) {
for(i=1;i<=uwsgi.numproc;i++) {
memcpy(&uwsgi.workers[i].apps[id], &uwsgi.workers[0].apps[id], sizeof(struct uwsgi_app));
uwsgi.workers[i].apps_cnt = uwsgi_apps_cnt;
}
}
}
+95 -49
View File
@@ -61,6 +61,9 @@ static struct option long_base_options[] = {
{"daemonize", required_argument, 0, 'd'},
{"stop", required_argument, 0, LONG_ARGS_STOP},
{"reload", required_argument, 0, LONG_ARGS_RELOAD},
{"pause", required_argument, 0, LONG_ARGS_PAUSE},
{"suspend", required_argument, 0, LONG_ARGS_PAUSE},
{"resume", required_argument, 0, LONG_ARGS_PAUSE},
{"listen", required_argument, 0, 'l'},
{"max-vars", required_argument, 0, 'v'},
{"buffer-size", required_argument, 0, 'b'},
@@ -129,6 +132,9 @@ static struct option long_base_options[] = {
#endif
{"mule", optional_argument, 0, LONG_ARGS_MULE},
{"mules", required_argument, 0, LONG_ARGS_MULES},
{"signal", required_argument, 0, LONG_ARGS_SIGNAL},
{"signal-bufsize", required_argument, 0, LONG_ARGS_SIGNAL_BUFSIZE},
{"signals-bufsize", required_argument, 0, LONG_ARGS_SIGNAL_BUFSIZE},
{"farm", required_argument, 0, LONG_ARGS_FARM},
{"disable-logging", no_argument, 0, 'L'},
@@ -170,6 +176,11 @@ static struct option long_base_options[] = {
{"reload-on-rss", required_argument, 0, LONG_ARGS_RELOAD_ON_RSS},
{"evil-reload-on-as", required_argument, 0, LONG_ARGS_EVIL_RELOAD_ON_AS},
{"evil-reload-on-rss", required_argument, 0, LONG_ARGS_EVIL_RELOAD_ON_RSS},
#ifdef __linux__
#ifdef MADV_MERGEABLE
{"ksm", optional_argument, 0, LONG_ARGS_KSM},
#endif
#endif
{"touch-reload", required_argument, 0, LONG_ARGS_TOUCH_RELOAD},
{"propagate-touch", no_argument, &uwsgi.propagate_touch, 1},
{"limit-post", required_argument, 0, LONG_ARGS_LIMIT_POST},
@@ -857,6 +868,40 @@ void signal_pidfile(int sig, char *filename) {
}
}
static void uwsgi_command_signal(char *opt) {
int tmp_signal;
char *colon = strchr(opt, ',');
if (!colon) {
uwsgi_log("invalid syntax for signal, must be addr,signal\n");
exit(1);
}
colon[0] = 0;
tmp_signal = atoi(colon+1);
if (tmp_signal < 0 || tmp_signal > 255) {
uwsgi_log("invalid signal number\n");
exit(3);
}
uint8_t uwsgi_signal = tmp_signal;
int ret = uwsgi_remote_signal_send(opt, uwsgi_signal);
if (ret < 0) {
uwsgi_log("unable to deliver signal %d to node %s\n", uwsgi_signal, opt);
exit(1);
}
if (ret == 0) {
uwsgi_log("node %s rejected signal %d\n", opt, uwsgi_signal);
exit(2);
}
uwsgi_log("signal %d delivered to node %s\n", uwsgi_signal, opt);
exit(0);
}
void fixup_argv_and_environ(int argc, char **argv, char **environ) {
@@ -2255,10 +2300,7 @@ skipzero:
if (uwsgi.master_process) {
for(i=1;i<=uwsgi.numproc;i++) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.workers[i].signal_pipe)) {
uwsgi_error("socketpair()\n");
exit(1);
}
create_signal_pipe(uwsgi.workers[i].signal_pipe);
}
}
@@ -2275,26 +2317,13 @@ skipzero:
}
memset(uwsgi.mules, 0, sizeof(struct uwsgi_mule) * uwsgi.mules_cnt);
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->mule_signal_pipe)) {
uwsgi_error("socketpair()");
exit(1);
}
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->mule_queue_pipe)) {
uwsgi_error("socketpair()");
exit(1);
}
create_signal_pipe(uwsgi.shared->mule_signal_pipe);
create_signal_pipe(uwsgi.shared->mule_queue_pipe);
for(i=0;i<uwsgi.mules_cnt;i++) {
// create the socket pipe
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.mules[i].signal_pipe)) {
uwsgi_error("socketpair()\n");
}
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.mules[i].queue_pipe)) {
uwsgi_error("socketpair()");
exit(1);
}
create_signal_pipe(uwsgi.mules[i].signal_pipe);
create_signal_pipe(uwsgi.mules[i].queue_pipe);
uwsgi.mules[i].id = i+1;
@@ -2327,15 +2356,8 @@ skipzero:
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
// create the socket pipe
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.farms[i].signal_pipe)) {
uwsgi_error("socketpair()\n");
}
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.farms[i].queue_pipe)) {
uwsgi_error("socketpair()");
exit(1);
}
create_signal_pipe(uwsgi.farms[i].signal_pipe);
create_signal_pipe(uwsgi.farms[i].queue_pipe);
char *p = strtok(mules_list, ",");
while(p != NULL) {
@@ -2425,6 +2447,7 @@ skipzero:
}
if (!uwsgi.master_process && uwsgi.numproc == 0) {
exit(0);
}
@@ -2432,6 +2455,16 @@ skipzero:
uwsgi_log("*** uWSGI is running in multiple interpreter mode ***\n");
}
#ifdef __linux__
#ifdef MADV_MERGEABLE
if (uwsgi.linux_ksm > 0) {
uwsgi_log("[uwsgi-KSM] enabled with frequency: %d\n", uwsgi.linux_ksm);
}
#endif
#endif
if (uwsgi.master_process) {
if (uwsgi.is_a_reload) {
uwsgi_log("gracefully (RE)spawned uWSGI master process (pid: %d)\n", uwsgi.mypid);
@@ -2464,10 +2497,7 @@ skipzero:
#ifdef UWSGI_SPOOLER
if (uwsgi.spool_dir != NULL && uwsgi.sockets) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->spooler_signal_pipe)) {
uwsgi_error("socketpair()\n");
exit(1);
}
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
uwsgi.shared->spooler_pid = spooler_start();
}
#endif
@@ -2496,11 +2526,7 @@ skipzero:
}
else {
// setup internal signalling system
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->worker_signal_pipe)) {
uwsgi_error("socketpair()\n");
exit(1);
}
create_signal_pipe(uwsgi.shared->worker_signal_pipe);
uwsgi.signal_socket = uwsgi.shared->worker_signal_pipe[1];
}
@@ -2531,6 +2557,8 @@ skipzero:
}
}
if (getpid() == masterpid && uwsgi.master_process == 1) {
#ifdef UWSGI_AS_SHARED_LIBRARY
int ml_ret = master_loop(uwsgi.argv, uwsgi.environ);
@@ -2828,15 +2856,8 @@ skipzero:
int rm_src = atoi(map);
int rm_dst = atoi(colon + 1);
up_tmp = uwsgi.p[rm_dst];
uwsgi.p[rm_dst] = uwsgi.p[rm_src];
uwsgi.p[rm_src] = up_tmp;
// fix rpc
for (i = 0; i < uwsgi.shared->rpc_count; i++) {
if (uwsgi.shared->rpc_table[i].modifier1 == rm_src)
uwsgi.shared->rpc_table[i].modifier1 = rm_dst;
else if (uwsgi.shared->rpc_table[i].modifier1 == rm_dst)
uwsgi.shared->rpc_table[i].modifier1 = rm_src;
}
uwsgi.p[rm_dst]->request = uwsgi.p[rm_src]->request;
uwsgi.p[rm_src]->after_request = up_tmp->after_request;
}
map = strtok(NULL, ",");
}
@@ -3375,6 +3396,9 @@ static int manage_base_opt(int i, char *optarg) {
case LONG_ARGS_RELOAD:
signal_pidfile(SIGHUP, optarg);
exit(0);
case LONG_ARGS_PAUSE:
signal_pidfile(SIGTSTP, optarg);
exit(0);
case LONG_ARGS_ATTACH_DAEMON:
if (uwsgi.startup_daemons_cnt < MAX_DAEMONS) {
uwsgi.startup_daemons[uwsgi.startup_daemons_cnt] = optarg;
@@ -3409,6 +3433,16 @@ static int manage_base_opt(int i, char *optarg) {
case LONG_ARGS_LIMIT_POST:
uwsgi.limit_post = (int) strtol(optarg, NULL, 10);
return 1;
#ifdef __linux__
#ifdef MADV_MERGEABLE
case LONG_ARGS_KSM:
uwsgi.linux_ksm = 1;
if (optarg) {
uwsgi.linux_ksm = atoi(optarg);
}
return 1;
#endif
#endif
case LONG_ARGS_RELOAD_ON_AS:
uwsgi.force_get_memusage = 1;
uwsgi.reload_on_as = (strtoul(optarg, NULL, 10)) * 1024 * 1024;
@@ -3469,6 +3503,12 @@ static int manage_base_opt(int i, char *optarg) {
uwsgi.mules_cnt++;
uwsgi_string_new_list(&uwsgi.mules_patches, optarg);
return 1;
case LONG_ARGS_SIGNAL:
uwsgi_command_signal(optarg);
return 1;
case LONG_ARGS_SIGNAL_BUFSIZE:
uwsgi.signal_bufsize = atoi(optarg);
return 1;
case LONG_ARGS_MULES:
uwsgi.master_process = 1;
for(i=0;i<atoi(optarg);i++) {
@@ -3829,9 +3869,15 @@ int _manage_opt(int i, char *p) {
void manage_opt(int i, char *optarg) {
char *value = optarg;
if (value && strchr(optarg, ';')) {
value = uwsgi_str(optarg);
if (value[0] == '\\') {
if (!_manage_opt(i, value+1)) {
exit(1);
}
return;
}
}
if (!value) {
+27
View File
@@ -537,6 +537,10 @@ struct uwsgi_opt {
#define LONG_ARGS_MULES 17158
#define LONG_ARGS_PROCNAME_PREFIX_SP 17159
#define LONG_ARGS_UMASK 17160
#define LONG_ARGS_PAUSE 17161
#define LONG_ARGS_SIGNAL_BUFSIZE 17162
#define LONG_ARGS_SIGNAL 17163
#define LONG_ARGS_KSM 17164
#define UWSGI_OK 0
@@ -1251,6 +1255,7 @@ struct uwsgi_server {
int lazy_respawned;
int buffer_size;
int signal_bufsize;
// post buffering
int post_buffering;
@@ -1521,6 +1526,12 @@ struct uwsgi_server {
// subscription client
struct uwsgi_string_list *subscriptions;
#ifdef __linux__
#ifdef MADV_MERGEABLE
int linux_ksm;
#endif
#endif
};
struct uwsgi_rpc {
@@ -1728,6 +1739,7 @@ struct uwsgi_worker {
int busy;
int cheaped;
int suspended;
int sig;
uint8_t signum;
@@ -2439,12 +2451,27 @@ struct uwsgi_subscribe_slot {
struct uwsgi_subscribe_slot *next;
};
void mule_send_msg(int, char *, size_t);
void create_signal_pipe(int *);
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **, char *, uint16_t, int);
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **, char *, uint16_t, int);
void uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **, struct uwsgi_subscribe_node *);
struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **, struct uwsgi_subscribe_req *, int);
ssize_t uwsgi_mule_get_msg(int, int, char *, size_t, int);
uint8_t uwsgi_signal_wait(int);
void uwsgi_add_app(int, uint8_t, char *, int);
int uwsgi_signal_send(int, uint8_t);
int uwsgi_remote_signal_send(char *, uint8_t);
#ifdef __linux__
#ifdef MADV_MERGEABLE
void uwsgi_linux_ksm_map(void);
#endif
#endif
#ifdef UWSGI_CAP
void uwsgi_build_cap(char *);
#endif
+10
View File
@@ -160,6 +160,11 @@ def build_uwsgi(uc):
except:
pass
try:
p_cflags.remove('-Werror=declaration-after-statement')
except:
pass
for cfile in up.GCC_LIST:
if not cfile.endswith('.a'):
compile(' '.join(p_cflags),
@@ -789,6 +794,11 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
except:
pass
try:
p_cflags.remove('-Werror=declaration-after-statement')
except:
pass
#for ofile in up.OBJ_LIST:
# gcc_list.insert(0,ofile)
+14 -2
View File
@@ -155,7 +155,7 @@ class farm(object):
def __call__(self, f):
postfork_chain.append(farm_loop(f, self.name))
class mule_loop(object):
class mule_brain(object):
def __init__(self, f, num):
self.f = f
@@ -165,12 +165,24 @@ class mule_loop(object):
if uwsgi.mule_id() == self.num:
self.f()
class mule_brainloop(mule_brain):
def __call__(self):
if uwsgi.mule_id() == self.num:
while True:
self.f()
class mule(object):
def __init__(self, num):
self.num = num
def __call__(self, f):
postfork_chain.append(mule_loop(f, self.num))
postfork_chain.append(mule_brain(f, self.num))
class muleloop(mule):
def __call__(self, f):
postfork_chain.append(mule_brainloop(f, self.num))
class mulemsg_loop(object):
+128
View File
@@ -0,0 +1,128 @@
# based on uwsgidecorators.py
if UWSGI.masterpid == 0
raise "you have to enable the uWSGI master process to use this module"
end
def get_free_signal()
for signum in 0..255
if not UWSGI.signal_registered(signum)
return signum
end
end
end
$postfork_chain = []
$mulefunc_list = []
module UWSGI
module_function
def post_fork_hook()
$postfork_chain.each {|func| func.call }
end
module_function
def mule_msg_hook(message)
service = Marshal.load(message)
if service['service'] == 'uwsgi_mulefunc'
mulefunc_manager(service)
end
end
end
def timer(secs, target='', &block)
freesig = get_free_signal
UWSGI.register_signal(freesig, target, block)
UWSGI.add_timer(freesig, secs)
end
def rbtimer(secs, target='', &block)
freesig = get_free_signal
UWSGI.register_signal(freesig, target, block)
UWSGI.add_rb_timer(freesig, secs)
end
def filemon(file, target='', &block)
freesig = get_free_signal
UWSGI.register_signal(freesig, target, block)
UWSGI.add_file_monitor(freesig, file)
end
def cron(minute, hour, day, month, dayweek, target='', &block)
freesig = get_free_signal
UWSGI.register_signal(freesig, target, block)
UWSGI.add_cron(freesig, minute, hour, day, month, dayweek)
end
def signal(signum, target='', &block)
UWSGI.register_signal(signum, target, block)
end
def postfork(&block)
$postfork_chain << block
end
def rpc(name, &block)
if block.arity <= 0
UWSGI.register_rpc(name, block, 0)
else
UWSGI.register_rpc(name, block, block.arity)
end
end
def mulefunc_manager(service)
$mulefunc_list[service['func']].real_call(service['args'])
end
class MuleFunc < Proc
def initialize(id=0, &block)
@id = id
@block = block
@func_pos = (($mulefunc_list << self).length)-1
end
def real_call(*args)
@block.call(*args)
end
def call(*args)
UWSGI.mule_msg( Marshal.dump( {
'service' => 'uwsgi_mulefunc',
'func' => @func_pos,
'args'=> args
}), @id)
end
end
class MuleProc < Proc
def initialize(id, block)
@id = id
@block = block
end
def call()
if UWSGI.mule_id == @id
@block.call
end
end
end
class MuleLoopProc < MuleProc
def call()
if UWSGI.mule_id == @id
loop do
@block.call
end
end
end
end
def mule(id, &block)
$postfork_chain << MuleProc.new(id, block)
end
def muleloop(id, &block)
$postfork_chain << MuleLoopProc.new(id, block)
end