Compare commits

...
226 Commits
Author SHA1 Message Date
Roberto De Ioris d248b290f2 added --php--allowed-script 2012-11-07 12:24:12 +01:00
Roberto De Ioris cb48070db1 fixed systemd support 2012-11-07 11:40:56 +01:00
unbit cd34bac104 Merge pull request #45 from prymitive/static_methods
disable static files offloading for methods other than GET and HEAD
2012-11-06 11:23:01 -08:00
Łukasz Mierzwa c966fbb163 disable static files offloading for methods other than GET and HEAD 2012-11-06 14:00:04 +01:00
Roberto De Ioris feac596efc fixed SSL buffer usage 2012-11-06 06:26:41 +01:00
Roberto De Ioris 981ddfcefe do not segfault on go if master-requiring api is called 2012-11-05 19:42:39 +01:00
Roberto De Ioris 5e561b6578 simplified go interface 2012-11-05 18:18:48 +01:00
unbit fab495fadc added Stephen Pierce to CONTRIBUTORS 2012-11-05 17:24:59 +01:00
Unbit ecbda6dc26 refactored go symbol loaders 2012-11-05 11:16:42 +01:00
Roberto De Ioris e23766e4d0 added go complextest 2012-11-05 10:37:07 +01:00
Roberto De Ioris 6d9de4c618 completed caching support for go 2012-11-05 10:32:37 +01:00
Roberto De Ioris 4ca14f6046 added two tests for go web apps, and completed request body advanced management 2012-11-05 09:09:38 +01:00
Roberto De Ioris d856c9920d added comments in uwsgi.go package 2012-11-05 07:51:00 +01:00
Roberto De Ioris fd62440265 Merge branch 'master' of github.com:unbit/uwsgi 2012-11-04 19:52:59 +01:00
Roberto De Ioris d4041c9e1d fixed goroutines support 2012-11-04 19:52:46 +01:00
unbit dc9e1bd324 Merge pull request #44 from StephenPierce/new-snmp-functions
New snmp functions
2012-11-04 10:44:39 -08:00
Roberto De Ioris 89bbd967ed added --goroutines shortcut 2012-11-04 11:00:06 +01:00
Roberto De Ioris 276ada315d fallback to DefaultServeMux if no RequestHandler has been defined 2012-11-04 10:54:06 +01:00
Roberto De Ioris bdd0d408a0 go modifier1 is officially assigned as 11 2012-11-04 10:41:51 +01:00
Roberta Giordano 5ddaa2e436 fixed go build in OSX 2012-11-04 10:31:12 +01:00
Roberto De Ioris f9d0e75056 automatically build uwsgi.go 2012-11-04 10:17:23 +01:00
Roberto De Ioris 7776a1f0be added preliminary go support 2012-11-04 09:24:06 +01:00
Stephen Pierce a33a57d8af Removed unneeded import 2012-11-02 16:02:46 -07:00
Stephen Pierce 9371e2b8de Added SNMP incr/decr functions for counter32/counter64/gauge types. Wrapped all operations (set/get/incr/decr) with lock to prevent contention. 2012-11-02 16:00:31 -07:00
Roberto De Ioris 6c1a842f7d improved reloading robustness 2012-11-02 14:30:14 +01:00
Roberto De Ioris d746deaf02 Merge branch 'master' of github.com:unbit/uwsgi 2012-11-02 12:38:09 +01:00
Roberto De Ioris 09fca72b4c fixed spooler max tasks handling 2012-11-02 12:37:41 +01:00
unbit 2ffc31e578 Merge pull request #41 from prymitive/valgrind
valgrind suppression file generator
2012-11-02 04:14:56 -07:00
unbit 2a254d195a Merge pull request #42 from prymitive/head
set http status on head static request
2012-11-02 04:14:33 -07:00
Roberto De Ioris 95d3ee4e61 added mongodb stats pusher 2012-11-02 12:06:08 +01:00
Roberto De Ioris 4d56474511 implemented stats pushers 2012-11-02 11:23:12 +01:00
Łukasz Mierzwa 46a33b268a set http status on head static request 2012-11-02 11:21:52 +01:00
Łukasz Mierzwa b0829cc2e3 more suppressions 2012-11-02 10:56:56 +01:00
Łukasz Mierzwa 93a0913182 valgrind suppression file generator 2012-11-02 10:38:00 +01:00
Roberto De Ioris 0605148e21 report signal_queue size in stats, fixed linux timerfd and inotify 2012-11-02 09:44:49 +01:00
Roberto De Ioris e7b5c7c8e4 allows generating minified json 2012-11-02 08:43:55 +01:00
Roberto De Ioris b2a0fd1914 truncate malformed/huge log lines 2012-10-31 19:55:21 +01:00
Roberto De Ioris 9cc89a6052 emperor is now tolerant to extreme Linux-OOM situations 2012-10-31 11:11:39 +01:00
Roberto De Ioris 1606b8b775 remove obsolete ruby threading definitions 2012-10-31 10:54:57 +01:00
unbit cfac385f8e Merge pull request #39 from prymitive/cppcheck
missing close() call in utils/uwsgi_num_from_file()
2012-10-31 02:29:54 -07:00
Łukasz Mierzwa 99fd4572cb missing close() call in utils/uwsgi_num_from_file() 2012-10-30 23:57:48 +01:00
Roberto De Ioris d3194ca011 remove monitored fd from async queue when in async mode 2012-10-30 18:31:04 +01:00
Roberto De Ioris af61a9e33f re-indented core/async.c 2012-10-30 18:01:35 +01:00
Roberto De Ioris 4896e22a62 preventively read a page of data in stats http mode 2012-10-30 09:42:17 +01:00
Roberto De Ioris 7882d12a80 better sockets management in stats servers 2012-10-30 09:31:15 +01:00
Roberto De Ioris 9342acc500 allows exported json stats in http format 2012-10-30 08:45:32 +01:00
Roberto De Ioris 929a919c9d exports spoolers data in stats server 2012-10-30 08:19:42 +01:00
Roberto De Ioris d1f6e97dd7 do not transfer static files if method is HEAD 2012-10-30 07:22:25 +01:00
Roberto De Ioris f9d76f90eb better configfile path management 2012-10-29 19:48:43 +01:00
Unbit 2de5e8994f allows building without routing 2012-10-29 16:51:21 +01:00
unbit 7e935253a2 Merge pull request #36 from prymitive/fr
count requests in (fast|http)router
2012-10-29 04:07:50 -07:00
Łukasz Mierzwa 4c20d83573 count requests in (fast|http)router / with cs->un checks 2012-10-29 11:44:56 +01:00
Łukasz Mierzwa 7035a676a2 count requests in (fast|http)router 2012-10-29 10:58:03 +01:00
Roberto De Ioris 736f99d10b added router_cache plugin 2012-10-29 10:11:42 +01:00
Roberto De Ioris ea422a4576 fixed cache size reporting in 32bit 2012-10-29 09:29:43 +01:00
Roberto De Ioris e274f53286 a couple of fedora17-specific fixes 2012-10-28 19:58:25 +01:00
Roberto De Ioris c03dcf4617 added logfile commodity plugin 2012-10-28 19:27:42 +01:00
Roberto De Ioris d70c7ceb89 added --log-route 2012-10-28 18:15:09 +01:00
Roberto De Ioris 9ae1354d1a added the systemd journal logger 2012-10-28 08:02:18 +01:00
Roberto De Ioris b29f0b9436 reimplemented --http-to-https 2012-10-27 20:12:19 +02:00
Roberto De Ioris e01cd802d8 re-implemented http expect/continue 2012-10-27 19:39:01 +02:00
Roberto De Ioris c7b57c9776 added --log-filter 2012-10-27 15:59:48 +02:00
Roberto De Ioris 3a48b898ad refactored router_access plugin 2012-10-27 15:37:14 +02:00
unbit 4f4771b527 Merge pull request #31 from brainbitsca/master
router_access - plugin to implement hosts_access
2012-10-27 06:03:58 -07:00
Roberto De Ioris b43df60d7f added uwsgi_kvlist_parse api function 2012-10-27 14:58:19 +02:00
Roberto De Ioris 10a5661218 added C Anthony Risinger as contributor 2012-10-27 12:15:53 +02:00
Roberto De Ioris a99670cfb5 fixed an incredibly stupid bug in http/https router 2012-10-27 11:58:10 +02:00
unbit 7967e8ac3c Merge pull request #33 from prymitive/harakiri
More accurate harakiri counting
2012-10-26 01:31:12 -07:00
colinlbc e105ebe273 remove stray uwsgi_log() 2012-10-25 14:47:50 -07:00
colinlbc 11d2c004c2 moved critical scrncpy out of #ifdef UWSGI_DEBUG 2012-10-25 14:30:47 -07:00
colinlbc e8bfa12372 Reworked things to get rid of several pointer errors.
Implemented svcname paramater for hosts access mode to set daemon name in hosts.allow,hosts.deny.
New router config syntax:

svcname defaults to uwsgi

uwsgi.ini:
router access:hosts
router access:hosts=svcname
router access:allow=addr
router access:deny=addr

hosts.deny:
svcname:ALL
2012-10-25 14:10:37 -07:00
Łukasz Mierzwa 317e9efa2d harakiri count is now accurate so we don't need to divide here 2012-10-25 15:23:35 +02:00
Łukasz Mierzwa 4b99bff520 don't increment harakiri counter on multiple SIGKILLs sent to the same process 2012-10-25 15:18:00 +02:00
colinlbc 99f584cff0 use char *remote_addr instead of wsgi_req->remote_addr 2012-10-24 03:03:13 -07:00
colinlbc fc6a79dcc9 corrected hosts_ctl to use STRING_UNKNOWN instead of wsgi_req->host. This
wants the remote_hostname, not the request host header.
2012-10-24 02:54:30 -07:00
colinlbc 75af812b83 Fixed a couple of silly mistakes in the access:action,host syntax parsing
Made changes based on unbit feedback:
- separated header, body output in 403 error
- used uwsgi_concat2n to copy strings out of wsgi_req->remote_addr and wsgi_req->host
2012-10-24 02:15:41 -07:00
Colin Ligertwood 0f4e1eb7e2 A simple access control router using libwrap. Currently only tested on OpenBSD 5.1.
I've used router_authbasic as a guide to write this. Placeholders exist for an
internal ACL scheme. Syntax follows:

router = ^/path acces:hosts         -- hosts access router using libwrap, works!
router = ^/path access:allow,ipaddr -- internal allow, unimplemented
router = ^/path access:deny,ipaddr  -- internal deny, unimplemented

It's just a few hours hacking and I'm not entirely sure how the internal access
control will work, but the hosts access stuff works in openbsd. It returns a 403
on denial.
2012-10-24 01:09:44 -07:00
Roberto De Ioris a3e0c2260f fixed a leak and a refcount bug in the tracebacker 2012-10-24 08:05:35 +02:00
Roberto De Ioris 3f63caa5eb fixed a typo 2012-10-24 07:13:33 +02:00
info@unbit.it 61bd3fb0e6 fixed kqueue support 2012-10-23 23:46:54 +02:00
Roberto De Ioris d6b4b8ea6e improved wsgi.input reports 2012-10-23 20:44:01 +02:00
Roberto De Ioris 3a451fb42f updates request switches at every gevent sleep/switch 2012-10-22 17:16:21 +02:00
Roberto De Ioris 7017712c6d non blocking wsgi.input in gevent 2012-10-22 15:58:36 +02:00
Roberto De Ioris 49140c3387 removed sendfile buildconf option 2012-10-22 14:07:33 +02:00
Roberto De Ioris 1d9edc3e34 ops, missing some ugly global vars 2012-10-22 10:03:56 +02:00
Roberto De Ioris fffe070e30 use threaded build only on build_uwsgi() 2012-10-22 09:41:24 +02:00
Roberto De Ioris 29ce04adce implemented reliable gevent non-blocking writes 2012-10-22 08:34:37 +02:00
unbit c487fb0cf0 Merge pull request #27 from xtfxme/improvement/gitignore-build-products
.gitignore build products and cache files
2012-10-21 21:29:47 -07:00
C Anthony Risinger 503fcd5ed5 .gitignore build products and cache files 2012-10-21 21:33:15 -05:00
Roberto De Ioris 7136beeff7 added uwsgi.offload_transfer() 2012-10-21 18:19:14 +02:00
Roberto De Ioris 64c7d71c35 completed https request body management 2012-10-21 14:04:10 +02:00
Roberto De Ioris d2d714e933 another series of https porting to the new api and ported multithread build system to python3 2012-10-21 12:36:15 +02:00
Roberto De Ioris f7399ef2ec use linux SOCK_NONBLOCK on uwsgi_connect() 2012-10-21 11:56:04 +02:00
Roberto De Ioris 4014bc53bd fixed handling of 'remaining' post data in http router 2012-10-21 11:31:47 +02:00
Roberto De Ioris b8f42a8d0b put a lock for print in multithreaded compilation 2012-10-21 10:31:24 +02:00
Roberto De Ioris b40442a0f8 fixed race condition on fork()/early-fail during worker respawn 2012-10-21 10:21:42 +02:00
Roberto De Ioris bee3bf5d43 added --so-send-timeout 2012-10-20 21:08:48 +02:00
Roberto De Ioris 59cc3d7c04 fixed PATH_INFO usage in embedded http mode 2012-10-20 20:58:19 +02:00
Roberto De Ioris 8dc072732b fixed building on ubuntu quantal 2012-10-20 19:45:09 +02:00
Roberto De Ioris 37b7c31849 fixed fastrouter leak with the new api 2012-10-20 19:39:08 +02:00
Roberto De Ioris 738b886267 get rid of ugly oracle/sun ifdef, will find a better solution later 2012-10-20 19:35:53 +02:00
Roberto De Ioris 8679f8b845 use accept4() if available 2012-10-20 19:20:52 +02:00
Roberta Giordano ecfae75886 fixed static-offload-to-thread on no-linux platforms 2012-10-20 18:52:07 +02:00
Roberto De Ioris cefc9fcc58 fixed http compilation 2012-10-20 18:17:50 +02:00
Roberto De Ioris 03104063cb improved http memory handling 2012-10-20 18:16:03 +02:00
Roberto De Ioris ef10dc054f fixed fastrouter 2012-10-20 17:55:04 +02:00
Roberto De Ioris 242497102e Merge branch 'master' of https://github.com/unbit/uwsgi 2012-10-20 17:30:58 +02:00
Roberto De Ioris 0242b464e7 another step for https porting 2012-10-20 17:29:45 +02:00
Roberto De Ioris 353b837f67 preliminary port of the http router to the new api 2012-10-20 16:54:16 +02:00
Roberto De Ioris d70ecab49f simplified the fastrouter 2012-10-20 13:47:23 +02:00
Roberto De Ioris c65adaaac7 first (destructive) commit for 1.4 2012-10-20 13:47:07 +02:00
unbit 4f0406c1cc Merge pull request #21 from akx/master
Add "include" config entry
2012-10-19 10:28:39 -07:00
Roberto De Ioris 6ea535a74d fixed gil usage in gevent plugin 2012-10-18 16:06:53 +02:00
Roberto De Ioris 2e66ae9abe added a test for static offloads 2012-10-18 14:55:49 +02:00
Aarni Koskela 39aa8ca8be Add "include" config entry (practically "inherit" with UWSGI_OPT_IMMEDIATE). 2012-10-18 15:26:38 +03:00
Roberto De Ioris ef80a7bba9 fixed offload to thread 2012-10-18 12:32:02 +02:00
Roberto De Ioris 8a65125ae5 added matheval support 2012-10-18 10:44:29 +02:00
Roberto De Ioris 86d9b4bc0e always get gil on python atexit 2012-10-18 08:27:51 +02:00
Roberto De Ioris 1d691139c7 ignore sockets presence on uwsgi.loop 2012-10-18 08:07:46 +02:00
Roberto De Ioris 94eb4f078e improved gevent usage of threads (it allows tracebacker and autoreloader to work in gevent) 2012-10-17 21:19:48 +02:00
Roberto De Ioris 47f3b39870 another refactoring for simple loop 2012-10-17 13:51:12 +02:00
Roberto De Ioris c67d26f8cc support for unlimited loop engines 2012-10-17 13:43:29 +02:00
Roberto De Ioris 9c99b29e47 refactored loop engines 2012-10-17 13:16:23 +02:00
unbit 5ce2020d6f Merge pull request #18 from dpetzold/master
Hard fail if --listen > somaxconn
2012-10-12 05:57:56 -07:00
Derrick Petzold d965587d9d uwsgi_linux_somaxconn -> uwsgi_num_from_file
Changed return type to long.
2012-10-09 19:15:44 +00:00
unbit 4f85c215cd Update CONTRIBUTORS
added Aarni Koskela to the CONTRIBUTORS
2012-10-09 21:04:05 +03:00
Unbit 1015ef9611 added (joke) alarm_speech plugin for OSX 2012-10-09 18:43:02 +02:00
Roberto De Ioris adcbc061b1 allows usage of objective-c in plugins 2012-10-09 14:50:14 +02:00
Roberto De Ioris 42229b08ce added shared require for rack 2012-10-09 13:32:22 +02:00
Roberto De Ioris 7bac625537 gevent plugin is now included in the default build profile 2012-10-09 10:28:28 +02:00
Roberto De Ioris a3e9a288d3 better usage of uwsgi_log_initial 2012-10-09 06:51:14 +02:00
Derrick Petzold 946a46df86 If the listen option is greater than the system max hard fail. 2012-10-08 19:57:44 +00:00
Roberto De Ioris e368b2da5e more reliable reloading system in cheaper modes 2012-10-07 10:54:33 +02:00
Roberto De Ioris 6b32ac086e improved lua plugin performance and status management 2012-10-07 08:45:50 +02:00
Roberto De Ioris 1651e3b0ef Merge branch 'master' of github.com:unbit/uwsgi 2012-10-06 19:18:45 +02:00
Roberto De Ioris fee6c65365 added --smart-attach-daemon/--smart-attach-daemon2 2012-10-06 19:18:26 +02:00
unbit 6070bd70a7 Merge pull request #15 from prymitive/wlrc
weighted least reference count (wlrc) load balancing algorithm
2012-10-06 04:54:42 -07:00
Łukasz Mierzwa 86ea390ba8 weighted least reference count (wlrc) load balancing algorithm 2012-10-06 12:27:56 +02:00
unbit e9158255a1 Merge pull request #13 from prymitive/lrc
make lrc act like rr under low load
2012-10-05 00:34:50 -07:00
Roberto De Ioris cd80885a49 Merge branch 'master' of github.com:unbit/uwsgi 2012-10-04 20:04:46 +02:00
Roberto De Ioris 8925ea06e1 improved router_http 2012-10-04 20:04:23 +02:00
unbit f1135c736a Merge pull request #12 from avar/pass_SERVER_ADDR_from_nginx
nginx/uwsgi_params: pass SERVER_ADDR to uwsgi
2012-10-04 01:41:18 -07:00
Łukasz Mierzwa c9f0786edd with this patch lrc acts more like rr algorithm when request rate is very low. Side effect is that when one adds new node to long running cluster, then lrc will try to catch new node request count up to other nodes value, but since it will only happen during low request rate, than I don't consider it as an issue 2012-10-04 10:31:47 +02:00
Roberto De Ioris 7e52f14786 improved development version string generation 2012-10-04 08:44:07 +02:00
Roberto De Ioris e35dcdbcdb migrated to github 2012-10-04 08:39:38 +02:00
roberto@quantal64 c59a3cb35a added support for PEP 405 virtualenvs 2012-10-03 20:49:58 +02:00
roberto@quantal64 a9703f8533 another fix for lrc 2012-10-03 08:51:36 +02:00
roberto@quantal64 0de510b777 fixed erlang plugin, improved xmpp alarm 2012-10-03 07:52:34 +02:00
roberto@quantal64 8a0fa1ffc4 fixed lrc algo 2012-10-03 07:02:32 +02:00
roberto@quantal64 4ca422a0a8 added --subscription-dotsplit 2012-10-03 06:56:37 +02:00
roberto@quantal64 a979abf0c6 added multiple algorithms support for subscription load balancing 2012-10-02 17:08:40 +02:00
roberto@quantal64 d12ddded55 added support for (working, high-performance) static file offloading in linux 2012-10-02 08:51:35 +02:00
roberto@quantal64 3beead6459 fixed leak in python3 headers management, prepare for truly working static file serving offload 2012-10-01 19:49:04 +02:00
roberto@sirius 248741a81f fixed non-blocking write on osx 2012-10-01 18:55:25 +02:00
roberto@quantal64 188b66e92c Added tag 1.3 for changeset 620e0cb6ccdb 2012-09-30 09:24:02 +02:00
roberto@quantal64 5ae1c6fbd1 uWSGI 1.3 2012-09-30 09:23:53 +02:00
roberto@quantal64 51b9b5d070 added cppcheck option, improved multicast 2012-09-29 09:16:09 +02:00
roberto@quantal64 dafe3bb12c fixed rack.input with buffered arg 2012-09-28 16:21:37 +02:00
roberto@mercury 973e508af7 reports details on memory allocation error, and bypass broken rack middlewares 2012-09-28 12:37:11 +02:00
roberto@mercury 8e31bb612e allows building the rack plugin without async support 2012-09-28 06:16:55 +02:00
roberto@longshot f920ac0fb0 use SSL_CTX_use_certificate_chain_file instead of SSL_CTX_use_certificate_file 2012-09-27 19:39:14 +02:00
roberto@longshot ae1b5afd7d reoved last libstrophe reference 2012-09-27 18:21:14 +02:00
roberto@quantal64 1f2bae130e added alarm_xmpp plugin 2012-09-27 17:45:42 +02:00
roberto@quantal64 4417e55862 completed http support for alarm_curl 2012-09-27 08:01:06 +02:00
roberto@quantal64 74a84bdd3a added support for mail subject in alarm_curl plugin 2012-09-26 19:55:58 +02:00
roberto@quantal64 b764252e7f applied verbose bind errors 2012-09-26 18:42:48 +02:00
roberto@quantal64 2fd71be9d9 allows building without alarms 2012-09-26 07:19:01 +02:00
roberto@quantal64 d65f873e77 sadly Rack::BodyProxy is still badly broken on 1.9 2012-09-26 07:10:13 +02:00
roberto@quantal64 1427c9ce1c added alarm_curl plugin 2012-09-24 08:36:04 +02:00
roberto@quantal64 c3de9320d7 pass alarm to stdin in cmd mode 2012-09-23 17:19:56 +02:00
roberto@quantal64 674151e485 added alarm subsystem 2012-09-23 16:25:40 +02:00
roberto@quantal64 9c042ffc1c Added tag 1.3-rc4 for changeset aeea5a5d2e8b 2012-09-22 09:48:11 +02:00
roberto@quantal64 c5dc74b021 uWSGI 1.3-rc4 2012-09-22 09:45:08 +02:00
roberto@quantal64 97137488f9 improved emperor mongodb tyrant mode 2012-09-22 09:38:15 +02:00
roberto@quantal64 8cff01a1c7 report imperial monitor in emperor statistics 2012-09-22 09:21:37 +02:00
roberto@quantal64 3c8452313e added emperor_mongodb plugin 2012-09-22 09:04:47 +02:00
roberto@quantal64 322b130fc9 refactored imperial monitors api 2012-09-22 08:58:17 +02:00
roberto@quantal64 6c001c2fda fixed usage of inlining 2012-09-22 07:57:42 +02:00
roberto@quantal64 5d4050817d added --dlopen 2012-09-22 05:52:28 +02:00
roberto@quantal64 0a1147a4f6 added --rb-patch-rack-bodyproxy for older ruby/rack versions 2012-09-21 11:02:29 +02:00
roberto@quantal64 f92cb0e6a2 fixed rack compilation 2012-09-21 09:51:36 +02:00
roberto@quantal64 8b79c76261 refactored daemonize2 2012-09-20 18:08:49 +02:00
roberto@quantal64 0015b51262 fixed POST-handling reports 2012-09-20 17:49:30 +02:00
roberto@quantal64 b1dc8cd9c6 improved async cores detection 2012-09-20 17:41:13 +02:00
roberto@quantal64 3269e2d288 added support for dependancies in plugins 2012-09-20 17:16:30 +02:00
roberto@quantal64 71a9747d96 applied latest carbon patches from Łukasz Mierzwa 2012-09-20 16:43:20 +02:00
roberto@quantal64 455d041ce4 fixed http router parser 2012-09-20 16:36:08 +02:00
roberto@arch 88205f8dd1 added mongodblog plugin 2012-09-19 15:15:03 +02:00
roberto@centos6 7d9dadddf6 support for loading file for elf sections 2012-09-18 00:42:53 +02:00
roberto@centos6 57e78dd76f implemented rack.input each 2012-09-17 16:26:44 +02:00
roberto@centos6 7d0d2b33f4 improved rack.input disk buffering (second part) 2012-09-17 15:51:31 +02:00
roberto@quantal64 03c739102d reimplementing rack.input without IO wrapper 2012-09-17 13:43:43 +02:00
roberto@quantal64 392bb8d7b1 allows building with python3 and without embedded module 2012-09-17 07:41:11 +02:00
roberto@quantal64 505b35be29 do not try to remove sockets in abstract namespace 2012-09-17 06:47:07 +02:00
roberto@quantal64 fdb002ad9b added %0 - %9 magic vars for splitting paths 2012-09-17 06:33:52 +02:00
roberto@quantal64 557c46373f improved %c 2012-09-15 16:15:47 +02:00
roberto@quantal64 3cde8be505 allows building without embedded and multiple interpreters 2012-09-15 12:14:12 +02:00
roberto@quantal64 c2cf1f3a62 fixed threading + lazy 2012-09-14 15:52:23 +02:00
roberto@quantal64 956cb1f13c Added tag 1.3-rc3 for changeset 883b946db903 2012-09-13 18:47:08 +02:00
roberto@quantal64 f698b558e1 uWSGI 1.3-rc3 2012-09-13 18:46:56 +02:00
roberto@quantal64 ca832900a0 ensure master_cleanup is run by the master 2012-09-13 16:58:05 +02:00
roberto@quantal64 6a6227a8e7 added a warning for --map-socket invalid syntax 2012-09-13 14:09:55 +02:00
roberto@quantal64 8539cdb5a7 ported build system to python 3.3 2012-09-13 14:05:47 +02:00
Ævar Arnfjörð Bjarmason 15194e6b55 nginx/uwsgi_params: pass SERVER_ADDR to uwsgi
nginx is capable of passing SERVER_ADDR to us like Apache would do via
mod_Ruwsgi, it just doesn't do so because that variable wasn't listed
in nginx/uwsgi_params.

This and other variables are passed from nginx from the nginx code in
src/http/ngx_http_variables.c. This was tested with nginx 1.0.15.
2012-09-13 08:17:22 +00:00
roberto@quantal64 5cea1de1ba added master_cleanup hook and carbon flush on stop/reload 2012-09-12 19:03:22 +02:00
roberto@quantal64 e735b9e31f applied busyness_backlog.diff by Łukasz Mierzwa 2012-09-12 18:12:55 +02:00
roberto@quantal64 9ff8f8899f added --log-drain 2012-09-12 08:08:32 +02:00
roberto@quantal64 d908c4ef35 allows building without udp 2012-09-07 19:45:58 +02:00
roberto@quantal64 207f50726d oops, use classic perl syntax for push 2012-09-07 19:36:21 +02:00
roberto@quantal64 212559fcce put sleep() in each psgi cleanup hook to show its power :P 2012-09-07 19:13:34 +02:00
roberto@quantal64 cf480e499c implemented psgi cleanup handlers, and fixed a leak in rpc call 2012-09-07 19:09:22 +02:00
roberto@quantal64 f2e27f5154 improved process limit detection 2012-09-07 14:54:57 +02:00
roberto@quantal64 d932a4feae fixed typcasting 2012-09-07 14:40:06 +02:00
roberto@quantal64 da6e05072f explicit link with librt for alternatives clock 2012-09-07 06:58:26 +02:00
roberto@quantal64 13277d9d71 improved cheaper_busyness 2012-09-06 17:10:03 +02:00
roberto@quantal64 f17f8b337f fixed idle mode 2012-09-06 16:21:12 +02:00
roberto@quantal64 ffb454e414 headers must be sent before close() 2012-09-06 15:22:17 +02:00
roberto@quantal64 424f5a09e7 call close() always, even if client disconnect 2012-09-06 15:02:12 +02:00
roberto@quantal64 c29a6f6446 removed STOP/TSTP signal from gateways 2012-09-06 11:20:21 +02:00
roberto@quantal64 6f7edf0941 fixed uwsgi_buffer realloc len 2012-09-04 19:18:38 +02:00
roberto@quantal64 a4c4b7e8d2 fixed uwsgi_buffer realloc 2012-09-04 18:13:16 +02:00
roberto@quantal64 837f6f3a54 initialize spooler locks before app loading 2012-09-04 08:21:40 +02:00
roberto@quantal64 13041da6bf fixed piping 2012-09-04 08:13:02 +02:00
roberto@quantal64 046824dae7 fixed usage of mmap() 2012-09-03 14:11:42 +02:00
roberto@quantal64 269a588d9d uWSGI 1.3-rc2 2012-09-01 11:42:42 +02:00
roberto@quantal64 50ae12518a Added tag 1.3-rc2 for changeset 14524da00a8b 2012-09-01 11:42:31 +02:00
130 changed files with 8747 additions and 3425 deletions
+5
View File
@@ -0,0 +1,5 @@
*.o
*.py[co]
/uwsgi
/uwsgibuild.*
+4
View File
@@ -52,3 +52,7 @@ e1568fd16b7b586cc72deb4dfccbbe64ae0b84df 1.1
24c8fe5a26e557db41cf1cee45b8964d5885e484 1.2-rc1
29de0fb320bc0a1ce84972f9f249360e315d3c10 1.2-rc2
c3cdecbf2bac591336baddd14f9ac22e18d6e200 1.2
14524da00a8b382dffb1d16a0e70cdf4a946f369 1.3-rc2
883b946db9038372cb1d76cb1d328a3093140e7b 1.3-rc3
aeea5a5d2e8b62ad55e23d539e1be02f2b6962af 1.3-rc4
620e0cb6ccdb0ce27561b4240cb3a0ef4c3527fd 1.3
+3
View File
@@ -18,3 +18,6 @@ Lukas Lalinsky
Steven Fernandez
Łukasz Mierzwa
Roy Marples
Aarni Koskela
C Anthony Risinger
Stephen Pierce
+16 -1
View File
@@ -10,12 +10,27 @@
- merged routers codebase (fastrouter, http, rawrouter)
- https support in the http router
- config report at the end of uWSGI build process
- support for keepalive in the http router
- improved subscription system (multicast and unix socket)
- custom options
- graceful reloads on shared sockets
- configurable log-master buffer size
- extreme-optimizations for the stats subsystem
- redislog and mongodblog plugins
- added python logger
- mongodb and postgres imperial monitors
- implemented psgix.logger and psgix.cleanup
- full rack spec compliance
- preliminary ipv6 support
- gevent graceful reloads
- support for multiple loggers and logformat
- lazy-apps to load apps after fork() but without changing reloading subsystem
- emperor heartbeat subsystem
- cheaper busyness plugin
- pluggable clock sources
- added router_rewrite and router_http plugins
- external spoolers
- support for section:// and fd:// loaders
- alarm subsystem (with curl and xmpp plugins)
*** april 2012 ***
+3
View File
@@ -3,3 +3,6 @@ all:
clean:
python uwsgiconfig.py --clean
check:
python uwsgiconfig.py --check
+2 -2
View File
@@ -12,12 +12,12 @@ ssl = auto
udp = true
multicast = true
threading = true
sendfile = true
minterpreters = true
async = true
ldap = auto
pcre = auto
routing = auto
alarm = auto
ipv6 = false
debug = false
unbit = false
@@ -29,7 +29,7 @@ plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, router_rewrite, router_http
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache
as_shared_library = false
locking = auto
+1 -1
View File
@@ -1,3 +1,3 @@
[uwsgi]
main_plugin = python
main_plugin = python,gevent
inherit = base
+5
View File
@@ -0,0 +1,5 @@
[uwsgi]
main_plugin = go
inherit = base
bin_name = libuwsgi.so
as_shared_library = true
-30
View File
@@ -1,30 +0,0 @@
[uwsgi]
xml = true
ini = true
snmp = true
erlang = false
spooler = true
embedded = true
udp = true
multicast = true
threading = true
sendfile = true
proxy = true
minterpreters = true
async = true
http = true
evdis = false
ldap = false
routing = false
stackless = false
debug = false
unbit = false
xml_implementation = libxml2
plugins =
bin_name = uwsgi
plugin_dir = .
embedded_plugins = python, ping, nagios, rack
[python]
paste = true
web3 = true
-29
View File
@@ -1,29 +0,0 @@
[uwsgi]
xml = true
ini = true
yaml = true
snmp = true
erlang = false
spooler = false
embedded = false
udp = true
multicast = false
threading = true
sendfile = true
nagios = true
proxy = true
minterpreters = true
async = true
ugreen = false
http = true
evdis = false
ldap = false
routing = false
stackless = false
debug = false
unbit = false
xml_implementation = libxml2
plugins = rack
bin_name = uwsgi
plugin_dir = .
embedded_plugins =
+1 -1
View File
@@ -11,12 +11,12 @@ embedded = true
udp = true
multicast = false
threading = true
sendfile = true
minterpreters = true
async = true
ldap = true
pcre = true
routing = true
alarm = true
debug = false
unbit = true
xml_implementation = expat
-44
View File
@@ -1,44 +0,0 @@
[uwsgi]
xml = false
ini = true
yaml = false
json = false
sqlite3 = false
zeromq = false
snmp = false
spooler = true
embedded = true
udp = true
multicast = false
threading = true
sendfile = true
minterpreters = true
async = true
evdis = false
ldap = false
pcre = true
routing = true
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = auto
malloc_implementation = libc
extras =
plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins =
as_shared_library = false
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
+266
View File
@@ -0,0 +1,266 @@
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
// generate a uwsgi signal on alarm
void uwsgi_alarm_init_signal(struct uwsgi_alarm_instance *uai) {
uai->data8 = atoi(uai->arg);
}
void uwsgi_alarm_func_signal(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
uwsgi_route_signal(uai->data8);
}
// run a command on alarm
void uwsgi_alarm_init_cmd(struct uwsgi_alarm_instance *uai) {
uai->data_ptr = uai->arg;
}
void uwsgi_alarm_func_cmd(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
int pipe[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe)) {
return;
}
uwsgi_socket_nb(pipe[0]);
uwsgi_socket_nb(pipe[1]);
if (write(pipe[1], msg, len) != (ssize_t) len) {
close(pipe[0]);
close(pipe[1]);
return;
}
uwsgi_run_command(uai->data_ptr, pipe, -1);
close(pipe[0]);
close(pipe[1]);
}
// pass the log line to a mule
void uwsgi_alarm_init_mule(struct uwsgi_alarm_instance *uai) {
uai->data32 = atoi(uai->arg);
if (uai->data32 > (uint32_t) uwsgi.mules_cnt) {
uwsgi_log_alarm("] invalid mule_id (%d mules available), fallback to 0\n", uwsgi.mules_cnt);
uai->data32 = 0;
}
}
void uwsgi_alarm_func_mule(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
// skip if mules are not available
if (uwsgi.mules_cnt == 0) return;
int fd = uwsgi.shared->mule_queue_pipe[0];
if (uai->data32 > 0) {
int mule_id = uai->data32-1;
fd = uwsgi.mules[mule_id].queue_pipe[0];
}
mule_send_msg(fd, msg, len);
}
// register a new alarm
void uwsgi_register_alarm(char *name, void (*init)(struct uwsgi_alarm_instance *), void (*func)(struct uwsgi_alarm_instance *, char *, size_t)) {
struct uwsgi_alarm *old_ua=NULL,*ua = uwsgi.alarms;
while(ua) {
// skip already initialized alarms
if (!strcmp(ua->name, name)) {
return;
}
old_ua = ua;
ua = ua->next;
}
ua = uwsgi_calloc(sizeof(struct uwsgi_alarm));
ua->name = name;
ua->init = init;
ua->func = func;
if (old_ua) {
old_ua->next = ua;
}
else {
uwsgi.alarms = ua;
}
}
// register embedded alarms
void uwsgi_register_embedded_alarms() {
uwsgi_register_alarm("signal", uwsgi_alarm_init_signal, uwsgi_alarm_func_signal);
uwsgi_register_alarm("cmd", uwsgi_alarm_init_cmd, uwsgi_alarm_func_cmd);
uwsgi_register_alarm("mule", uwsgi_alarm_init_mule, uwsgi_alarm_func_mule);
}
static int uwsgi_alarm_add(char *name, char *plugin, char *arg) {
struct uwsgi_alarm *ua = uwsgi.alarms;
while(ua) {
if (!strcmp(ua->name, plugin)) {
break;
}
ua = ua->next;
}
if (!ua) return -1;
struct uwsgi_alarm_instance *old_uai = NULL, *uai = uwsgi.alarm_instances;
while(uai) {
old_uai = uai;
uai = uai->next;
}
uai = uwsgi_calloc(sizeof(struct uwsgi_alarm_instance));
uai->name = name;
uai->alarm = ua;
uai->arg = arg;
uai->last_msg = uwsgi_malloc(uwsgi.log_master_bufsize);
if (old_uai) {
old_uai->next = uai;
}
else {
uwsgi.alarm_instances = uai;
}
ua->init(uai);
return 0;
}
// get an alarm instance by its name
static struct uwsgi_alarm_instance *uwsgi_alarm_get_instance(char *name) {
struct uwsgi_alarm_instance *uai = uwsgi.alarm_instances;
while(uai) {
if (!strcmp(name, uai->name)) {
return uai;
}
uai = uai->next;
}
return NULL;
}
static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
struct uwsgi_alarm_log *old_ual = NULL, *ual = uwsgi.alarm_logs;
while(ual) {
old_ual = ual;
ual = ual->next;
}
ual = uwsgi_calloc(sizeof(struct uwsgi_alarm_log));
if (uwsgi_regexp_build(regexp, &ual->pattern, &ual->pattern_extra)) {
return -1;
}
if (old_ual) {
old_ual->next = ual;
}
else {
uwsgi.alarm_logs = ual;
}
// map instances to the log
char *list = uwsgi_str(alarms);
char *p = strtok(list, ",");
while(p) {
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
if (!uai) return -1;
struct uwsgi_alarm_ll *old_uall=NULL,*uall = ual->alarms;
while(uall) {
old_uall = uall;
uall = uall->next;
}
uall = uwsgi_calloc(sizeof(struct uwsgi_alarm_ll));
uall->alarm = uai;
if (old_uall) {
old_uall->next = uall;
}
else {
ual->alarms = uall;
}
p = strtok(NULL, ",");
}
return 0;
}
// initialize alarms, instances and log regexps
void uwsgi_alarms_init() {
// first of all, create instance of alarms
struct uwsgi_string_list *usl = uwsgi.alarm_list;
while(usl) {
char *line = uwsgi_str(usl->value);
char *space = strchr(line, ' ');
if (!space) {
uwsgi_log("invalid alarm syntax: %s\n", usl->value);
exit(1);
}
*space = 0;
char *plugin = space+1;
char *colon = strchr(plugin, ':');
if (!colon) {
uwsgi_log("invalid alarm syntax: %s\n", usl->value);
exit(1);
}
*colon = 0;
char *arg = colon+1;
// here the alarm is mapped to a name and initialized
if (uwsgi_alarm_add(line, plugin, arg)) {
uwsgi_log("invalid alarm: %s\n", usl->value);
exit(1);
}
usl = usl->next;
}
// then map log-alarm
usl = uwsgi.alarm_logs_list;
while(usl) {
char *line = uwsgi_str(usl->value);
char *space = strchr(line, ' ');
if (!space) {
uwsgi_log("invalid log-alarm syntax: %s\n", usl->value);
exit(1);
}
*space = 0;
char *regexp = space+1;
// here the log-alarm is created
if (uwsgi_alarm_log_add(line, regexp)) {
uwsgi_log("invalid log-alarm: %s\n", usl->value);
exit(1);
}
usl = usl->next;
}
}
// check if a log should raise an alarm
void uwsgi_alarm_log_check(char *msg, size_t len) {
if (!uwsgi_strncmp(msg, len, "[uwsgi-alarm", 12)) return;
struct uwsgi_alarm_log *ual = uwsgi.alarm_logs;
while(ual) {
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
uwsgi_alarm_log_run(ual, msg, len);
}
ual = ual->next;
}
}
// call the alarm func
void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
time_t now = uwsgi_now();
// avoid alarm storming/loop if last message is the same
if (!uwsgi_strncmp(msg, len, uai->last_msg, uai->last_msg_size)) {
if (now - uai->last_run < uwsgi.alarm_freq) return;
}
uai->alarm->func(uai, msg, len);
uai->last_run = uwsgi_now();
memcpy(uai->last_msg, msg, len);
uai->last_msg_size = len;
}
// call the alarms mapped to a log line
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
struct uwsgi_alarm_ll *uall = ual->alarms;
while(uall) {
uwsgi_alarm_run(uall->alarm, msg, len);
uall = uall->next;
}
}
+121 -128
View File
@@ -7,21 +7,21 @@ void uwsgi_async_init() {
uwsgi.async_queue = event_queue_init();
if (uwsgi.async_queue < 0) {
exit(1);
}
if (uwsgi.async_queue < 0) {
exit(1);
}
uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1);
uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1);
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
for (i = 0; i < uwsgi.async; i++) {
uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
}
for (i = 0; i < uwsgi.async; i++) {
uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
}
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
}
@@ -37,23 +37,23 @@ void runqueue_remove(struct uwsgi_async_request *u_request) {
struct uwsgi_async_request *parent = u_request->prev;
struct uwsgi_async_request *child = u_request->next;
if (parent) {
parent->next = child;
}
if (child) {
child->prev = parent;
}
if (parent == NULL) {
uwsgi.async_runqueue = child;
}
if (parent) {
parent->next = child;
}
if (child) {
child->prev = parent;
}
if (parent == NULL) {
uwsgi.async_runqueue = child;
}
if (u_request == uwsgi.async_runqueue_last) {
uwsgi.async_runqueue_last = parent;
}
free(u_request);
free(u_request);
uwsgi.async_runqueue_cnt--;
}
@@ -63,21 +63,21 @@ void runqueue_push(struct wsgi_request *wsgi_req) {
struct uwsgi_async_request *uar;
if (uwsgi.async_runqueue == NULL) {
// empty runqueue, create a new one
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
uwsgi.async_runqueue->next = NULL;
uwsgi.async_runqueue->prev = NULL;
uwsgi.async_runqueue->wsgi_req = wsgi_req;
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
}
else {
// empty runqueue, create a new one
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
uwsgi.async_runqueue->next = NULL;
uwsgi.async_runqueue->prev = NULL;
uwsgi.async_runqueue->wsgi_req = wsgi_req;
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
}
else {
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
uar->prev = uwsgi.async_runqueue_last;
uar->next = NULL;
uar->wsgi_req = wsgi_req;
uwsgi.async_runqueue_last->next = uar;
uwsgi.async_runqueue_last = uar;
}
uar->prev = uwsgi.async_runqueue_last;
uar->next = NULL;
uar->wsgi_req = wsgi_req;
uwsgi.async_runqueue_last->next = uar;
uwsgi.async_runqueue_last = uar;
}
uwsgi.async_runqueue_cnt++;
@@ -104,14 +104,15 @@ void async_expire_timeouts() {
struct uwsgi_rb_timer *urbt;
for(;;) {
for (;;) {
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
if (urbt == NULL) return;
if (urbt == NULL)
return;
if (urbt->key <= current_time) {
wsgi_req = (struct wsgi_request *) urbt->data;
if (urbt->key <= current_time) {
wsgi_req = (struct wsgi_request *) urbt->data;
// timeout expired
wsgi_req->async_timed_out = 1;
rb_erase(&wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
@@ -119,7 +120,7 @@ void async_expire_timeouts() {
wsgi_req->async_timeout = NULL;
uaf = wsgi_req->waiting_fds;
// remove fds from monitoring (no problem modifying the queue here, as the function is executed only when there are no fd ready)
while(uaf) {
while (uaf) {
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
current_uaf = uaf;
@@ -129,11 +130,11 @@ void async_expire_timeouts() {
wsgi_req->waiting_fds = NULL;
// put th request in the runqueue
runqueue_push(wsgi_req);
continue;
}
continue;
}
break;
}
break;
}
}
@@ -141,10 +142,11 @@ void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
if (fd < 0) return ;
if (fd < 0)
return;
// find first slot
while(uad) {
while (uad) {
last_uad = uad;
uad = uad->next;
}
@@ -167,48 +169,49 @@ void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
}
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
event_queue_add_fd_read(uwsgi.async_queue, fd);
}
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
if (timeout > 0 && wsgi_req->async_timeout == NULL) {
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, uwsgi_now()+timeout, wsgi_req);
}
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, uwsgi_now() + timeout, wsgi_req);
}
}
void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
if (fd < 0) return ;
if (fd < 0)
return;
// find first slot
while(uad) {
last_uad = uad;
uad = uad->next;
}
// find first slot
while (uad) {
last_uad = uad;
uad = uad->next;
}
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
uad->fd = fd;
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
uad->fd = fd;
uad->event = event_queue_write();
uad->prev = last_uad;
uad->next = NULL;
uad->prev = last_uad;
uad->next = NULL;
if (last_uad) {
last_uad->next = uad;
}
else {
wsgi_req->waiting_fds = uad;
}
if (last_uad) {
last_uad->next = uad;
}
else {
wsgi_req->waiting_fds = uad;
}
if (timeout > 0) {
async_add_timeout(wsgi_req, timeout);
}
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
event_queue_add_fd_write(uwsgi.async_queue, fd);
event_queue_add_fd_write(uwsgi.async_queue, fd);
}
@@ -216,7 +219,12 @@ void async_schedule_to_req(void) {
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
}
void *async_loop(void *arg1) {
void async_loop() {
if (uwsgi.async < 2) {
uwsgi_log("the async loop engine requires async mode (--async <n>)\n");
exit(1);
}
struct uwsgi_async_fd *tmp_uaf;
int interesting_fd, i;
@@ -241,7 +249,8 @@ void *async_loop(void *arg1) {
}
// set a default request manager
if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req;
if (!uwsgi.schedule_to_req)
uwsgi.schedule_to_req = async_schedule_to_req;
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
@@ -251,36 +260,36 @@ void *async_loop(void *arg1) {
else {
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
if (uwsgi.async_runqueue_cnt) {
timeout = 0;
timeout = 0;
}
if (min_timeout) {
timeout = min_timeout->key - uwsgi_now();
if (timeout <= 0) {
async_expire_timeouts();
timeout = 0;
}
if (min_timeout) {
timeout = min_timeout->key - uwsgi_now();
if (timeout <= 0) {
async_expire_timeouts();
timeout = 0;
}
}
else {
timeout = -1;
}
}
}
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64);
// timeout ???
if (uwsgi.async_nevents == 0) {
async_expire_timeouts();
async_expire_timeouts();
}
for(i=0;i<uwsgi.async_nevents;i++) {
for (i = 0; i < uwsgi.async_nevents; i++) {
// manage events
interesting_fd = event_queue_interesting_fd(events, i);
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
continue;
}
}
is_a_new_connection = 0;
@@ -288,11 +297,11 @@ void *async_loop(void *arg1) {
// new request coming in ?
uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
while (uwsgi_sock) {
if (interesting_fd == uwsgi_sock->fd) {
is_a_new_connection = 1;
is_a_new_connection = 1;
uwsgi.wsgi_req = find_first_available_wsgi_req();
if (uwsgi.wsgi_req == NULL) {
@@ -304,30 +313,23 @@ void *async_loop(void *arg1) {
break;
}
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock );
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock);
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
#endif
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
#endif
// on linux we do not need to reset the socket to blocking state
#ifndef __linux__
/* re-set blocking socket */
int arg = uwsgi_sock->arg;
arg &= (~O_NONBLOCK);
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, arg) < 0) {
uwsgi_error("fcntl()");
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
/* re-set blocking socket */
int arg = uwsgi_sock->arg;
arg &= (~O_NONBLOCK);
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, arg) < 0) {
uwsgi_error("fcntl()");
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
#endif
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
@@ -357,10 +359,7 @@ void *async_loop(void *arg1) {
uwsgi.wsgi_req->async_timeout = NULL;
// parsing complete
if (!proto_parser_status) {
// remove fd from event poll and fd proto table
#ifndef UWSGI_EVENT_USE_PORT
event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read());
#endif
// remove fd from event poll and fd proto table
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
// put request in the runqueue
runqueue_push(uwsgi.wsgi_req);
@@ -387,21 +386,19 @@ void *async_loop(void *arg1) {
}
// remove all the fd monitors and timeout
while(uwsgi.wsgi_req->waiting_fds) {
#ifndef UWSGI_EVENT_USE_PORT
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
#endif
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
free(tmp_uaf);
}
while (uwsgi.wsgi_req->waiting_fds) {
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
free(tmp_uaf);
}
uwsgi.wsgi_req->waiting_fds = NULL;
if (uwsgi.wsgi_req->async_timeout) {
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
}
if (uwsgi.wsgi_req->async_timeout) {
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
}
uwsgi.wsgi_req->async_ready_fd = 1;
uwsgi.wsgi_req->async_last_ready_fd = interesting_fd;
@@ -426,20 +423,18 @@ void *async_loop(void *arg1) {
// request ended ?
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
// remove all the monitored fds and timeout
while(uwsgi.wsgi_req->waiting_fds) {
#ifndef UWSGI_EVENT_USE_PORT
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
#endif
while (uwsgi.wsgi_req->waiting_fds) {
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
free(tmp_uaf);
}
uwsgi.wsgi_req->waiting_fds = NULL;
if (uwsgi.wsgi_req->async_timeout) {
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
free(uwsgi.wsgi_req->async_timeout);
uwsgi.wsgi_req->async_timeout = NULL;
}
// remove from the list
@@ -453,7 +448,7 @@ void *async_loop(void *arg1) {
}
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
// remove this request from suspended list
// remove this request from suspended list
runqueue_remove(current_request);
}
@@ -464,6 +459,4 @@ void *async_loop(void *arg1) {
}
return NULL;
}
+47 -3
View File
@@ -13,16 +13,60 @@ struct uwsgi_buffer *uwsgi_buffer_new(size_t len) {
}
int uwsgi_buffer_fix(struct uwsgi_buffer *ub, size_t len) {
if (ub->limit >0 && len > ub->limit) return -1;
if (ub->len < len) {
char *new_buf = realloc(ub->buf, len);
if (!new_buf) {
uwsgi_error("uwsgi_buffer_fix()");
return -1;
}
ub->buf = new_buf;
ub->len = len;
}
return 0;
}
int uwsgi_buffer_ensure(struct uwsgi_buffer *ub, size_t len) {
size_t remains = ub->len - ub->pos;
if (remains < len) {
size_t new_len = ub->len + (len - remains);
if (ub->limit >0 && new_len > ub->limit) {
new_len = ub->limit;
if (new_len == ub->len) return -1;
}
char *new_buf = realloc(ub->buf, new_len);
if (!new_buf) {
uwsgi_error("uwsgi_buffer_ensure()");
return -1;
}
ub->buf = new_buf;
ub->len = new_len;
}
return 0;
}
int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
size_t remains = ub->len - ub->pos;
if (len > remains) {
char *new_buf = realloc(ub->buf, ub->len + UMAX(len, (size_t) uwsgi.page_size));
size_t chunk_size = UMAX(len, (size_t) uwsgi.page_size);
if (ub->limit >0 && ub->len + chunk_size > ub->limit) {
// retry with another minimal size
if (len < (size_t) uwsgi.page_size) {
chunk_size = len;
}
if (ub->len + chunk_size > ub->limit) return -1;
}
char *new_buf = realloc(ub->buf, ub->len + chunk_size);
if (!new_buf) {
uwsgi_error("realloc()");
uwsgi_error("uwsgi_buffer_append()");
return -1;
}
ub->buf = new_buf;
ub->len += chunk_size;
}
memcpy(ub->buf + ub->pos, buf, len);
@@ -51,7 +95,7 @@ int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
return -1;
}
else {
uwsgi_error("write()");
uwsgi_error("uwsgi_buffer_send()");
return -1;
}
}
+24 -6
View File
@@ -3,7 +3,6 @@
extern struct uwsgi_server uwsgi;
void uwsgi_init_cache() {
int i;
if (!uwsgi.cache_blocksize)
uwsgi.cache_blocksize = UMAX16;
@@ -64,6 +63,7 @@ void uwsgi_init_cache() {
}
else {
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
int i;
for (i = 0; i < (int) uwsgi.cache_max_items; i++) {
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
}
@@ -85,8 +85,11 @@ void uwsgi_init_cache() {
uwsgi.cache_lock = uwsgi_rwlock_init("cache");
uwsgi_log("*** Cache subsystem initialized: %dMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes) preallocated ***\n", ((uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024),
(unsigned long long) sizeof(struct uwsgi_cache_item), (unsigned long long) sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, (unsigned long long) uwsgi.cache_blocksize * uwsgi.cache_max_items);
uwsgi_log("*** Cache subsystem initialized: %lluMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes) preallocated ***\n",
(unsigned long long) ((uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024),
(unsigned long long) sizeof(struct uwsgi_cache_item),
(unsigned long long) (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items),
(unsigned long long) (uwsgi.cache_blocksize * uwsgi.cache_max_items));
}
uint32_t djb33x_hash(char *key, int keylen) {
@@ -102,7 +105,7 @@ uint32_t djb33x_hash(char *key, int keylen) {
}
inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
static inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
uint32_t hash = djb33x_hash(key, keylen);
@@ -243,7 +246,6 @@ int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint
struct uwsgi_cache_item *uci, *ucii;
int ret = -1;
int slot;
if (!keylen || !vallen) return -1;
@@ -283,7 +285,7 @@ int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint
uci->keysize = keylen;
ret = 0;
// now put the value in the 16bit hashtable
slot = uci->djbhash % 0xffff;
int slot = uci->djbhash % 0xffff;
// reset values
uci->prev = 0;
uci->next = 0;
@@ -441,3 +443,19 @@ int uwsgi_cache_server(char *socket, int threads) {
return *fd;
}
int uwsgi_cache_enabled() {
if (uwsgi.cache_max_items > 0) return 1;
return 0;
}
void uwsgi_cache_wlock() {
uwsgi.lock_ops.wlock(uwsgi.cache_lock);
}
void uwsgi_cache_rlock() {
uwsgi.lock_ops.rlock(uwsgi.cache_lock);
}
void uwsgi_cache_rwunlock() {
uwsgi.lock_ops.rwunlock(uwsgi.cache_lock);
}
+301
View File
@@ -0,0 +1,301 @@
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
/*
External uwsgi daemons
There are 3 kind of daemons (read: external applications) that can be managed
by uWSGI.
1) dumb daemons (attached with --attach-daemon)
they must not daemonize() and when they exit() the master is notified (via waitpid)
and the process is respawned
2) smart daemons with daemonization
you specify a pidfile and a command
- on startup - if the pidfile does not exists or contains a not-available pid (checked with kill(pid, 0))
the daemon is respawned
- on master ckeck - if the pidfile does not exist or if it point to a non-existent pid
the daemon is respawned
3) smart daemons without daemonization
same as 2, but the daemonization and pidfile creation is managed by uWSGI
status:
0 -> never started
1 -> just started
2 -> started and monitored (only in pidfile based)
*/
void uwsgi_daemons_smart_check() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pidfile) {
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
if (checked_pid <= 0) {
// monitored instance
if (ud->status == 2) {
uwsgi_spawn_daemon(ud);
}
else {
ud->pidfile_checks++;
if (ud->pidfile_checks >= (uint64_t) ud->freq) {
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
uwsgi_spawn_daemon(ud);
}
}
}
else if (checked_pid != ud->pid) {
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
ud->pid = checked_pid;
}
// all ok, pidfile and process found
else {
ud->status = 2;
}
}
ud = ud->next;
}
}
// this function is called when a dumb daemon dies and we do not wat to respawn it
int uwsgi_daemon_check_pid_death(pid_t diedpid) {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid == diedpid && !ud->pidfile) {
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
return -1;
}
ud = ud->next;
}
return 0;
}
// this function is called when a dumb daemon dies and we want to respawn it
int uwsgi_daemon_check_pid_reload(pid_t diedpid) {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid == diedpid && !ud->pidfile) {
uwsgi_spawn_daemon(ud);
return 1;
}
ud = ud->next;
}
return 0;
}
int uwsgi_check_pidfile(char *filename) {
struct stat st;
pid_t ret = -1;
int fd = open(filename, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(filename);
goto end;
}
if (fstat(fd, &st)) {
uwsgi_error("fstat()");
goto end2;
}
char *pidstr = uwsgi_calloc(st.st_size+1);
if (read(fd, pidstr, st.st_size) != st.st_size) {
uwsgi_error("read()");
goto end3;
}
pid_t pid = atoi(pidstr);
if (pid <= 0) goto end3;
if (!kill(pid, 0)) {
ret = pid;
}
end3:
free(pidstr);
end2:
close(fd);
end:
return ret;
}
void uwsgi_daemons_spawn_all() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (!ud->registered) {
if (ud->pidfile) {
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
if (checked_pid <= 0) {
uwsgi_spawn_daemon(ud);
}
else {
ud->pid = checked_pid;
uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid);
}
}
else {
uwsgi_spawn_daemon(ud);
}
ud->registered = 1;
}
ud = ud->next;
}
}
void uwsgi_detach_daemons() {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid > 0 && !ud->pidfile)
kill(-ud->pid, SIGKILL);
ud = ud->next;
}
}
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
int devnull = -1;
int throttle = 0;
if (uwsgi.current_time - ud->last_spawn <= 3) {
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
}
pid_t pid = uwsgi_fork("uWSGI external daemon");
if (pid < 0) {
uwsgi_error("fork()");
return;
}
if (pid > 0) {
ud->pid = pid;
ud->status = 1;
ud->pidfile_checks = 0;
if (ud->respawns == 0) {
ud->born = uwsgi_now();
}
ud->respawns++;
ud->last_spawn = uwsgi_now();
}
else {
// close uwsgi sockets
uwsgi_close_all_sockets();
if (ud->daemonize) {
/* refork... */
pid = fork();
if (pid < 0) {
uwsgi_error("fork()");
exit(1);
}
if (pid != 0) {
_exit(0);
}
uwsgi_write_pidfile(ud->pidfile);
}
// /dev/null will became stdin
devnull = open("/dev/null", O_RDONLY);
if (devnull < 0) {
uwsgi_error("/dev/null open()");
exit(1);
}
if (devnull != 0) {
if (dup2(devnull, 0)) {
uwsgi_error("dup2()");
exit(1);
}
close(devnull);
}
if (setsid() < 0) {
uwsgi_error("setsid()");
exit(1);
}
if (!ud->pidfile) {
#ifdef __linux__
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
uwsgi_error("prctl()");
}
#endif
}
if (throttle) {
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle);
sleep(throttle);
}
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\"\n", ud->respawns > 0 ? "re":"", ud->command);
uwsgi_exec_command_with_args(ud->command);
uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command);
// never here;
exit(1);
}
return;
}
void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud;
char *pidfile = NULL;
int daemonize = 0;
int freq = 10;
char *command = uwsgi_str(value);
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2")) {
char *space = strchr(command, ' ');
if (!space) {
uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command);
exit(1);
}
*space = 0;
pidfile = command;
// check for freq
char *comma = strchr(pidfile, ',');
if (comma) {
*comma = 0;
freq = atoi(comma+1);
}
command = space + 1;
if (!strcmp(opt, "smart-attach-daemon2")) {
daemonize = 1;
}
}
if (!uwsgi_ud) {
uwsgi.daemons = uwsgi_malloc(sizeof(struct uwsgi_daemon));
uwsgi_ud = uwsgi.daemons;
}
else {
while (uwsgi_ud) {
old_ud = uwsgi_ud;
uwsgi_ud = uwsgi_ud->next;
}
uwsgi_ud = uwsgi_malloc(sizeof(struct uwsgi_daemon));
old_ud->next = uwsgi_ud;
}
uwsgi_ud->command = command;
uwsgi_ud->pid = 0;
uwsgi_ud->status = 0;
uwsgi_ud->freq = freq;
uwsgi_ud->registered = 0;
uwsgi_ud->next = NULL;
uwsgi_ud->respawns = 0;
uwsgi_ud->last_spawn = 0;
uwsgi_ud->daemonize = daemonize;
uwsgi_ud->pidfile = pidfile;
uwsgi.daemons_cnt++;
}
+62 -2
View File
@@ -498,7 +498,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
if (uwsgi.emperor_tyrant) {
if (uid == 0 || gid == 0) {
uwsgi_log("[emperor-tyrant] invalid permissions for file %s\n", name);
uwsgi_log("[emperor-tyrant] invalid permissions for vassal %s\n", name);
return;
}
}
@@ -1076,7 +1076,20 @@ void emperor_loop() {
diedpid = 0;
}
if (diedpid < 0) {
uwsgi_error("waitpid()");
// it looks like it happens when OOM is triggered to Linux cgroup, but it could be a uWSGI bug :P
// by the way, fallback to a clean situation...
if (errno == ECHILD) {
uwsgi_log("--- MUTINY DETECTED !!! IMPALING VASSALS... ---\n");
ui_current = ui->ui_next;
while (ui_current) {
struct uwsgi_instance *rebel_vassal = ui_current;
ui_current = ui_current->ui_next;
emperor_del(rebel_vassal);
}
}
else {
uwsgi_error("waitpid()");
}
}
ui_current = ui;
while (ui_current->ui_next) {
@@ -1129,6 +1142,13 @@ void emperor_send_stats(int fd) {
return;
}
if (uwsgi.stats_http) {
if (uwsgi_send_http_stats(client_fd)) {
close(client_fd);
return;
}
}
struct uwsgi_stats *us = uwsgi_stats_new(8192);
if (uwsgi_stats_keyval_comma(us, "version", UWSGI_VERSION))
@@ -1208,6 +1228,9 @@ void emperor_send_stats(int fd) {
if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) c_ui->gid))
goto end0;
if (uwsgi_stats_keyval_comma(us, "monitor", c_ui->scanner->arg))
goto end0;
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) c_ui->respawns))
goto end0;
@@ -1277,6 +1300,10 @@ void emperor_send_stats(int fd) {
size_t remains = us->pos;
off_t pos = 0;
while (remains > 0) {
int ret = uwsgi_waitfd_write(client_fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) {
goto end0;
}
ssize_t res = write(client_fd, us->base + pos, remains);
if (res <= 0) {
if (res < 0) {
@@ -1338,3 +1365,36 @@ void uwsgi_check_emperor() {
}
}
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid) {
if (!uwsgi_emperor_is_valid(name))
return;
struct uwsgi_instance *ui_current = emperor_get(name);
if (ui_current) {
// check if uid or gid are changed, in such case, stop the instance
if (uwsgi.emperor_tyrant) {
if (uid != ui_current->uid || gid != ui_current->gid) {
uwsgi_log("[emperor-tyrant] !!! permissions of vassal %s changed. stopping the instance... !!!\n", name);
emperor_stop(ui_current);
return;
}
}
// check if mtime is changed and the uWSGI instance must be reloaded
if (ts > ui_current->last_mod) {
// make a new config (free the old one)
free(ui_current->config);
ui_current->config = config;
ui_current->config_len = strlen(config);
// always respawn (no need for amqp-style rules)
emperor_respawn(ui_current, ts);
}
}
else {
// make a copy of the config as it will be freed
emperor_add(ues, name, ts, uwsgi_str(config), strlen((const char *)config), uid, gid);
}
}
+247 -32
View File
@@ -28,7 +28,7 @@ int event_queue_del_fd(int eq, int fd, int event) {
return -1;
}
return fd;
return 0;
}
int event_queue_fd_write_to_read(int eq, int fd) {
@@ -38,7 +38,7 @@ int event_queue_fd_write_to_read(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
@@ -49,10 +49,53 @@ int event_queue_fd_read_to_write(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
int event_queue_fd_readwrite_to_read(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
uwsgi_error("port_associate");
return -1;
}
return 0;
}
int event_queue_fd_readwrite_to_write(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
uwsgi_error("port_associate");
return -1;
}
return 0;
}
int event_queue_fd_write_to_readwrite(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN|POLLOUT, NULL)) {
uwsgi_error("port_associate");
return -1;
}
return 0;
}
int event_queue_fd_read_to_readwrite(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN|POLLOUT, NULL)) {
uwsgi_error("port_associate");
return -1;
}
return 0;
}
int event_queue_interesting_fd_has_error(void *events, int id) {
@@ -63,16 +106,30 @@ int event_queue_interesting_fd_has_error(void *events, int id) {
return 0;
}
int event_queue_interesting_fd_is_read(void *events, int id) {
port_event_t *pe = (port_event_t *) events;
if (pe[id].portev_events = POLLIN) {
return 1;
}
return 0;
}
int event_queue_interesting_fd_is_write(void *events, int id) {
port_event_t *pe = (port_event_t *) events;
if (pe[id].portev_events == POLLOUT) {
return 1;
}
return 0;
}
int event_queue_add_fd_read(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *) eq)) {
uwsgi_error("port_associate");
return -1;
}
return fd;
return 0;
}
int event_queue_add_fd_write(int eq, int fd) {
@@ -82,7 +139,7 @@ int event_queue_add_fd_write(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
void *event_queue_alloc(int nevents) {
@@ -96,7 +153,17 @@ int event_queue_interesting_fd(void *events, int id) {
return (long) pe[id].portev_user;
}
return (int) pe[id].portev_object;
int fd = (int) pe[id].portev_object;
int eq = (int) pe[id].portev_user;
if (pe[id].portev_events == POLLOUT) {
event_queue_add_fd_write(eq, fd);
}
if (pe[id].portev_events == POLLIN) {
event_queue_add_fd_read(eq, fd);
}
return fd;
}
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
@@ -104,7 +171,6 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
int ret;
uint_t nget = 1;
timespec_t ts;
port_event_t *pe;
if (timeout >= 0) {
ts.tv_sec = timeout;
@@ -123,8 +189,6 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
return 0;
}
pe = (port_event_t *) events;
return nget;
}
@@ -209,7 +273,7 @@ int event_queue_add_fd_read(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
int event_queue_fd_write_to_read(int eq, int fd) {
@@ -225,7 +289,7 @@ int event_queue_fd_write_to_read(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
int event_queue_fd_read_to_write(int eq, int fd) {
@@ -241,9 +305,75 @@ int event_queue_fd_read_to_write(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
int event_queue_fd_readwrite_to_read(int eq, int fd) {
struct epoll_event ee;
memset(&ee, 0, sizeof(struct epoll_event));
ee.events = EPOLLIN;
ee.data.fd = fd;
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
uwsgi_error("epoll_ctl()");
return -1;
}
return 0;
}
int event_queue_fd_readwrite_to_write(int eq, int fd) {
struct epoll_event ee;
memset(&ee, 0, sizeof(struct epoll_event));
ee.events = EPOLLOUT;
ee.data.fd = fd;
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
uwsgi_error("epoll_ctl()");
return -1;
}
return 0;
}
int event_queue_fd_read_to_readwrite(int eq, int fd) {
struct epoll_event ee;
memset(&ee, 0, sizeof(struct epoll_event));
ee.events = EPOLLIN|EPOLLOUT;
ee.data.fd = fd;
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
uwsgi_error("epoll_ctl()");
return -1;
}
return 0;
}
int event_queue_fd_write_to_readwrite(int eq, int fd) {
struct epoll_event ee;
memset(&ee, 0, sizeof(struct epoll_event));
ee.events = EPOLLIN|EPOLLOUT;
ee.data.fd = fd;
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
uwsgi_error("epoll_ctl()");
return -1;
}
return 0;
}
int event_queue_del_fd(int eq, int fd, int event) {
@@ -258,7 +388,7 @@ int event_queue_del_fd(int eq, int fd, int event) {
return -1;
}
return fd;
return 0;
}
int event_queue_add_fd_write(int eq, int fd) {
@@ -274,7 +404,7 @@ int event_queue_add_fd_write(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
void *event_queue_alloc(int nevents) {
@@ -295,6 +425,23 @@ int event_queue_interesting_fd_has_error(void *events, int id) {
return 0;
}
int event_queue_interesting_fd_is_read(void *events, int id) {
struct epoll_event *ee = (struct epoll_event *) events;
if (ee[id].events & EPOLLIN) {
return 1;
}
return 0;
}
int event_queue_interesting_fd_is_write(void *events, int id) {
struct epoll_event *ee = (struct epoll_event *) events;
if (ee[id].events & EPOLLOUT) {
return 1;
}
return 0;
}
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
int ret;
@@ -357,13 +504,11 @@ int event_queue_fd_write_to_read(int eq, int fd) {
struct kevent kev;
#ifndef __FreeBSD__
EV_SET(&kev, fd, EVFILT_WRITE, EV_DISABLE, 0, 0, 0);
EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
#endif
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
@@ -371,20 +516,18 @@ int event_queue_fd_write_to_read(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
int event_queue_fd_read_to_write(int eq, int fd) {
struct kevent kev;
#ifndef __FreeBSD__
EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 0, 0, 0);
EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
#endif
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
@@ -392,9 +535,63 @@ int event_queue_fd_read_to_write(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
int event_queue_fd_readwrite_to_read(int eq, int fd) {
struct kevent kev;
EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
return 0;
}
int event_queue_fd_readwrite_to_write(int eq, int fd) {
struct kevent kev;
EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
return 0;
}
int event_queue_fd_read_to_readwrite(int eq, int fd) {
struct kevent kev;
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
return 0;
}
int event_queue_fd_write_to_readwrite(int eq, int fd) {
struct kevent kev;
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
return 0;
}
int event_queue_del_fd(int eq, int fd, int event) {
@@ -406,7 +603,7 @@ int event_queue_del_fd(int eq, int fd, int event) {
return -1;
}
return fd;
return 0;
}
int event_queue_add_fd_read(int eq, int fd) {
@@ -419,7 +616,7 @@ int event_queue_add_fd_read(int eq, int fd) {
return -1;
}
return fd;
return 0;
}
int event_queue_add_fd_write(int eq, int fd) {
@@ -479,8 +676,23 @@ int event_queue_interesting_fd_has_error(void *events, int id) {
return 0;
}
int event_queue_interesting_fd_is_read(void *events, int id) {
struct kevent *ev = (struct kevent *) events;
if ( ev[id].filter == EVFILT_READ ) {
return 1;
}
return 0;
}
int event_queue_interesting_fd_is_write(void *events, int id) {
struct kevent *ev = (struct kevent *) events;
if ( ev[id].filter == EVFILT_WRITE ) {
return 1;
}
return 0;
}
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
int ret;
@@ -663,11 +875,11 @@ int event_queue_add_file_monitor(int eq, char *filename, int *id) {
#endif
if (add_to_queue) {
return event_queue_add_fd_read(eq, ifd);
}
else {
return ifd;
if (event_queue_add_fd_read(eq, ifd)) {
return -1;
}
}
return ifd;
}
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
@@ -799,7 +1011,10 @@ int event_queue_add_timer(int eq, int *id, int sec) {
}
*id = tfd;
return event_queue_add_fd_read(eq, tfd);
if (event_queue_add_fd_read(eq, tfd)) {
return -1;
}
return tfd;
}
struct uwsgi_timer *event_queue_ack_timer(int id) {
@@ -926,10 +1141,10 @@ struct uwsgi_timer *event_queue_ack_timer(int id) {
}
#endif
inline int event_queue_read() {
int event_queue_read() {
return UWSGI_EVENT_IN;
}
inline int event_queue_write() {
int event_queue_write() {
return UWSGI_EVENT_OUT;
}
+2
View File
@@ -71,6 +71,8 @@ void gateway_respawn(int id) {
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
ug->loop(id, ug->data);
// never here !!! (i hope)
+63 -5
View File
@@ -16,6 +16,8 @@ void uwsgi_init_default() {
uwsgi.cache_server_fd = -1;
uwsgi.stats_fd = -1;
uwsgi.stats_pusher_default_freq = 3;
uwsgi.original_log_fd = -1;
uwsgi.emperor_fd_config = -1;
@@ -74,6 +76,15 @@ void uwsgi_init_default() {
uwsgi.subscriptions_sign_check_tolerance = 3600 * 24;
#endif
#ifdef UWSGI_ALARM
uwsgi.alarm_freq = 3;
#endif
#ifdef UWSGI_MULTICAST
uwsgi.multicast_ttl = 1;
#endif
}
void uwsgi_setup_reload() {
@@ -214,16 +225,26 @@ void uwsgi_setup_workers() {
// allocate memory for cores
uwsgi.workers[i].cores = (struct uwsgi_core *) uwsgi_calloc_shared(sizeof(struct uwsgi_core) * uwsgi.cores);
// this is a trick for avoiding too much memory areas
void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores);
void *buffers = uwsgi_malloc_shared(uwsgi.buffer_size * uwsgi.cores);
void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
void *post_buf = NULL;
if (uwsgi.post_buffering > 0)
post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize * uwsgi.cores);
for (j = 0; j < uwsgi.cores; j++) {
// allocate shared memory for thread states (required for some language, like python)
uwsgi.workers[i].cores[j].ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps);
uwsgi.workers[i].cores[j].ts = ts + ((sizeof(void *) * uwsgi.max_apps) * j);
// raw per-request buffer
uwsgi.workers[i].cores[j].buffer = uwsgi_malloc_shared(uwsgi.buffer_size);
uwsgi.workers[i].cores[j].buffer = buffers + (uwsgi.buffer_size * j);
// iovec for uwsgi vars
uwsgi.workers[i].cores[j].hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size);
if (uwsgi.post_buffering > 0)
uwsgi.workers[i].cores[j].post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize);
uwsgi.workers[i].cores[j].hvec = hvec + ((sizeof(struct iovec) * uwsgi.vec_size) * j);
if (post_buf)
uwsgi.workers[i].cores[j].post_buf = post_buf + (uwsgi.post_buffering_bufsize *j);
}
// master does not need to following steps...
if (i == 0) continue;
uwsgi.workers[i].signal_pipe[0] = -1;
@@ -232,4 +253,41 @@ void uwsgi_setup_workers() {
snprintf(uwsgi.workers[i].snapshot_name, 0xff, "uWSGI snapshot %d", i);
}
uint64_t total_memory = (sizeof(struct uwsgi_app) * uwsgi.max_apps) + (sizeof(struct uwsgi_core) * uwsgi.cores) + (sizeof(void *) * uwsgi.max_apps * uwsgi.cores) +
(uwsgi.buffer_size * uwsgi.cores) + (sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
if (uwsgi.post_buffering > 0) {
total_memory += (uwsgi.post_buffering_bufsize * uwsgi.cores);
}
total_memory *= (uwsgi.numproc + uwsgi.master_process);
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", total_memory, total_memory / 1024, uwsgi.cores*uwsgi.numproc);
}
pid_t uwsgi_daemonize2() {
if (uwsgi.has_emperor) {
logto(uwsgi.daemonize2);
}
else {
if (!uwsgi.is_a_reload) {
uwsgi_log("*** daemonizing uWSGI ***\n");
daemonize(uwsgi.daemonize2);
}
else if (uwsgi.log_reopen) {
logto(uwsgi.daemonize2);
}
}
uwsgi.mypid = getpid();
uwsgi.workers[0].pid = uwsgi.mypid;
if (uwsgi.pidfile && !uwsgi.is_a_reload) {
uwsgi_write_pidfile(uwsgi.pidfile);
}
if (uwsgi.pidfile2 && !uwsgi.is_a_reload) {
uwsgi_write_pidfile(uwsgi.pidfile2);
}
return uwsgi.mypid;
}
+9
View File
@@ -629,3 +629,12 @@ nextlock:
}
}
void uwsgi_user_lock(int lock_num) {
uwsgi_lock(uwsgi.user_lock[lock_num]);
}
void uwsgi_user_unlock(int lock_num) {
uwsgi_unlock(uwsgi.user_lock[lock_num]);
}
+55 -7
View File
@@ -298,14 +298,33 @@ void uwsgi_setup_log_master(void) {
struct uwsgi_string_list *usl = uwsgi.requested_logger;
while(usl) {
char *colon = strchr(usl->value, ':');
char *id = NULL;
char *name = usl->value;
char *space = strchr(name, ' ');
if (space) {
int is_id = 1;
int i;
for(i=0;i<(space-name);i++) {
if (!isalnum(name[i])) {
is_id = 0;
break;
}
}
if (is_id) {
id = uwsgi_concat2n(name, space-name, "", 0);
name = space+1;
}
}
char *colon = strchr(name, ':');
if (colon) {
*colon = 0;
}
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(usl->value);
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
if (!choosen_logger) {
uwsgi_log("unable to find logger %s\n", usl->value);
uwsgi_log("unable to find logger %s\n", name);
exit(1);
}
@@ -313,6 +332,7 @@ void uwsgi_setup_log_master(void) {
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
choosen_logger = copy_of_choosen_logger;
choosen_logger->id = id;
choosen_logger->next = NULL;
if (colon) {
@@ -330,6 +350,15 @@ void uwsgi_setup_log_master(void) {
}
#ifdef UWSGI_PCRE
// set logger by its id
struct uwsgi_regexp_list *url = uwsgi.log_route;
while(url) {
url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str);
url = url->next;
}
#endif
uwsgi.original_log_fd = dup(1);
create_logpipe();
}
@@ -529,9 +558,7 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
char *tsize = (char *) msecs;
#ifdef UWSGI_SENDFILE
char *msg1 = " via sendfile() ";
#endif
char *msg3 = " via route() ";
char *msg4 = " via offload() ";
@@ -544,11 +571,9 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
}
}
#ifdef UWSGI_SENDFILE
if (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result) { //wsgi_req->sendfile_fd_size > 0 ) {
via = msg1;
}
#endif
// mark route() requests
if (wsgi_req->status == -17) {
@@ -598,6 +623,15 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %llu %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->remote_user_len, wsgi_req->remote_user, wsgi_req->var_cnt, wsgi_req->uh.pktsize, 24, time_request, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->protocol_len, wsgi_req->protocol, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
// not enough space for logging the request, just log a (safe) minimal message
if (rlen > 4096) {
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %s%s(- %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->var_cnt, wsgi_req->uh.pktsize, 24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
// argh, last resort, truncate it
if (rlen > 4096) {
rlen = 4096;
}
}
logvec[logvecpos].iov_base = logpkt;
logvec[logvecpos].iov_len = rlen;
@@ -763,6 +797,20 @@ struct uwsgi_logger *uwsgi_get_logger(char *name) {
return NULL;
}
struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
struct uwsgi_logger *ul = uwsgi.choosen_logger;
while (ul) {
if (!strcmp(ul->id, id)) {
return ul;
}
ul = ul->next;
}
return NULL;
}
void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
struct uwsgi_logchunk *logchunk = uwsgi.logchunks;
ssize_t rlen = 0;
+92 -44
View File
@@ -10,70 +10,118 @@ struct wsgi_request *simple_current_wsgi_req() {
}
void uwsgi_register_loop(char *name, void *loop) {
void uwsgi_register_loop(char *name, void (*func)(void)) {
if (uwsgi.loops_cnt >= MAX_LOOPS) {
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
exit(1);
struct uwsgi_loop *old_loop = NULL, *loop = uwsgi.loops;
while(loop) {
// check if the loop engine is already registered
if (!strcmp(name, loop->name)) return;
old_loop = loop;
loop = loop->next;
}
uwsgi.loops[uwsgi.loops_cnt].name = name;
uwsgi.loops[uwsgi.loops_cnt].loop = loop;
uwsgi.loops_cnt++;
loop = uwsgi_calloc(sizeof(struct uwsgi_loop));
loop->name = name;
loop->loop = func;
if (old_loop) {
old_loop->next = loop;
}
else {
uwsgi.loops = loop;
}
}
void *uwsgi_get_loop(char *name) {
int i;
struct uwsgi_loop *loop = uwsgi.loops;
for (i = 0; i < uwsgi.loops_cnt; i++) {
if (!strcmp(name, uwsgi.loops[i].name)) {
return uwsgi.loops[i].loop;
while(loop) {
if (!strcmp(name, loop->name)) {
return loop->loop;
}
loop = loop->next;
}
return NULL;
}
void *simple_loop(void *arg1) {
/*
this is the default (simple) loop.
it will run simple_loop_run function for each spawned thread
simple_loop_run monitors sockets and signals descriptors
and manages them.
*/
void simple_loop() {
uwsgi_loop_cores_run(simple_loop_run);
}
void uwsgi_loop_cores_run(void *(*func)(void *)) {
int i;
#ifdef UWSGI_THREADING
for (i = 1; i < uwsgi.threads; i++) {
long j = i;
pthread_create(&uwsgi.workers[uwsgi.mywid].cores[i].thread_id, &uwsgi.threads_attr, func, (void *) j);
}
#endif
long y = 0;
func((void *) y);
}
void uwsgi_setup_thread_req(long core_id, struct wsgi_request *wsgi_req) {
int i;
sigset_t smask;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
if (core_id > 0) {
// block all signals on new threads
sigfillset(&smask);
#ifdef UWSGI_DEBUG
sigdelset(&smask, SIGSEGV);
#endif
pthread_sigmask(SIG_BLOCK, &smask, NULL);
// run per-thread socket hook
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->proto_thread_fixup) {
uwsgi_sock->proto_thread_fixup(uwsgi_sock, core_id);
}
uwsgi_sock = uwsgi_sock->next;
}
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->init_thread) {
uwsgi.p[i]->init_thread(core_id);
}
}
}
}
void simple_loop_run_int(int core_id) {
long y = core_id;
simple_loop_run((void *) y);
}
void *simple_loop_run(void *arg1) {
long core_id = (long) arg1;
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req;
#ifdef UWSGI_THREADING
int i;
sigset_t smask;
if (uwsgi.threads > 1) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
if (core_id > 0) {
// block all signals on new threads
sigfillset(&smask);
#ifdef UWSGI_DEBUG
sigdelset(&smask, SIGSEGV);
#endif
pthread_sigmask(SIG_BLOCK, &smask, NULL);
// run per-thread socket hook
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->proto_thread_fixup) {
uwsgi_sock->proto_thread_fixup(uwsgi_sock, core_id);
}
uwsgi_sock = uwsgi_sock->next;
}
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->init_thread) {
uwsgi.p[i]->init_thread(core_id);
}
}
}
uwsgi_setup_thread_req(core_id, wsgi_req);
}
#endif
+104 -46
View File
@@ -265,17 +265,62 @@ int uwsgi_master_log(void) {
ssize_t rlen = read(uwsgi.shared->worker_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
if (rlen > 0) {
if (uwsgi.choosen_logger) {
struct uwsgi_logger *ul = uwsgi.choosen_logger;
while(ul) {
ul->func(ul, uwsgi.log_master_buf, rlen);
ul = ul->next;
#ifdef UWSGI_ALARM
uwsgi_alarm_log_check(uwsgi.log_master_buf, rlen);
#endif
#ifdef UWSGI_PCRE
struct uwsgi_regexp_list *url = uwsgi.log_drain_rules;
while(url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
return 0;
}
url = url->next;
}
else {
if (uwsgi.log_filter_rules) {
int show = 0;
url = uwsgi.log_filter_rules;
while(url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
show = 1;
break;
}
url = url->next;
}
if (!show) return 0;
}
url = uwsgi.log_route;
int finish = 0;
while(url) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
if (ul_route) {
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
finish = 1;
}
}
url = url->next;
}
if (finish) return 0;
#endif
int raw_log = 1;
struct uwsgi_logger *ul = uwsgi.choosen_logger;
while(ul) {
// check for named logger
if (ul->id) {
goto next;
}
ul->func(ul, uwsgi.log_master_buf, rlen);
raw_log = 0;
next:
ul = ul->next;
}
if (raw_log) {
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
}
// TODO allow uwsgi.logger = func
return 0;
}
@@ -473,13 +518,13 @@ clear:
}
#ifdef __linux__
void get_linux_tcp_info(int fd) {
int get_linux_tcp_info(int fd) {
socklen_t tis = sizeof(struct tcp_info);
if (!getsockopt(fd, IPPROTO_TCP, TCP_INFO, &uwsgi.shared->ti, &tis)) {
// a check for older linux kernels
if (!uwsgi.shared->ti.tcpi_sacked) {
return;
return -1;
}
uwsgi.shared->load = uwsgi.shared->ti.tcpi_unacked;
@@ -501,7 +546,11 @@ void get_linux_tcp_info(int fd) {
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%d/%d) ***\n", fd, uwsgi.shared->ti.tcpi_unacked, uwsgi.shared->ti.tcpi_sacked);
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
}
return uwsgi.shared->ti.tcpi_unacked;
}
return -1;
}
#include <linux/sockios.h>
@@ -512,7 +561,7 @@ void get_linux_tcp_info(int fd) {
#ifdef SIOBKLGQ
void get_linux_unbit_SIOBKLGQ(int fd) {
int get_linux_unbit_SIOBKLGQ(int fd) {
int queue = 0;
if (ioctl(fd, SIOBKLGQ, &queue) >= 0) {
@@ -522,8 +571,11 @@ void get_linux_unbit_SIOBKLGQ(int fd) {
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%d/%d) ***\n", fd, queue, uwsgi.listen_queue);
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
}
return queue;
}
return -1;
}
#endif
#endif
@@ -600,6 +652,8 @@ int master_loop(char **argv, char **environ) {
uwsgi_unix_signal(SIGURG, uwsgi_restore_auto_snapshot);
}
atexit(uwsgi_master_cleanup_hooks);
uwsgi.master_queue = event_queue_init();
/* route signals to workers... */
@@ -634,6 +688,11 @@ int master_loop(char **argv, char **environ) {
uwsgi.threaded_logger = 0;
}
}
#ifdef UWSGI_ALARM
// initialize the alarm subsystem
uwsgi_alarms_init();
#endif
}
if (uwsgi.cache_max_items > 0 && !uwsgi.cache_no_expire) {
@@ -675,6 +734,15 @@ int master_loop(char **argv, char **environ) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.stats_fd);
uwsgi_log("*** Stats server enabled on %s fd: %d ***\n", uwsgi.stats, uwsgi.stats_fd);
}
if (uwsgi.requested_stats_pushers) {
if (!uwsgi_thread_new(uwsgi_stats_pusher_loop)) {
uwsgi_log("!!! unable to spawn stats pusher thread !!!\n");
exit(1);
}
}
#ifdef UWSGI_UDP
if (uwsgi.udp_socket) {
udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0);
@@ -723,15 +791,7 @@ int master_loop(char **argv, char **environ) {
}
// spawn daemons
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (!ud->registered) {
spawn_daemon(ud);
ud->registered = 1;
}
ud = ud->next;
}
uwsgi_daemons_spawn_all();
// first subscription
struct uwsgi_string_list *subscriptions = uwsgi.subscriptions;
@@ -795,9 +855,11 @@ int master_loop(char **argv, char **environ) {
}
}
uwsgi_daemons_smart_check();
if (uwsgi.to_outworld) {
//uwsgi_log("%d/%d\n", uwsgi.lazy_respawned, uwsgi.numproc);
if (uwsgi.lazy_respawned >= uwsgi.numproc || (uwsgi.cheaper && uwsgi.lazy_respawned == uwsgi.cheaper_count)) {
if (uwsgi.lazy_respawned >= uwsgi.marked_workers || uwsgi.lazy_respawned >= uwsgi.numproc) {
uwsgi.to_outworld = 0;
uwsgi.master_mercy = 0;
uwsgi.lazy_respawned = 0;
@@ -828,8 +890,7 @@ int master_loop(char **argv, char **environ) {
return 0;
}
if ((uwsgi.cheap || uwsgi.ready_to_die >= uwsgi.numproc) && uwsgi.to_hell) {
if ((uwsgi.cheap || uwsgi.ready_to_die >= uwsgi.marked_workers || uwsgi.ready_to_die >= uwsgi.numproc) && uwsgi.to_hell) {
// call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead
for (i = 0; i < (ushared->gateways_cnt + uwsgi.daemons_cnt + uwsgi.mules_cnt); i++) {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
@@ -839,7 +900,7 @@ int master_loop(char **argv, char **environ) {
exit(0);
}
if ((uwsgi.cheap || uwsgi.ready_to_reload >= uwsgi.numproc) && uwsgi.to_heaven) {
if ((uwsgi.cheap || uwsgi.ready_to_reload >= uwsgi.marked_workers || uwsgi.ready_to_reload >= uwsgi.numproc) && uwsgi.to_heaven) {
uwsgi_reload(argv);
// never here (unless in shared library mode)
return -1;
@@ -971,7 +1032,7 @@ int master_loop(char **argv, char **environ) {
if (uwsgi.stats && uwsgi.stats_fd > -1) {
if (interesting_fd == uwsgi.stats_fd) {
uwsgi_send_stats(uwsgi.stats_fd);
uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats);
goto health_cycle;
}
}
@@ -1179,12 +1240,23 @@ health_cycle:
uwsgi.current_time = uwsgi_now();
if (!last_request_timecheck)
last_request_timecheck = uwsgi.current_time;
int busy_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
if (uwsgi.workers[i].busy == 1) {
busy_workers = 1;
break;
}
}
}
if (last_request_count != uwsgi.workers[0].requests) {
last_request_timecheck = uwsgi.current_time;
last_request_count = uwsgi.workers[0].requests;
}
// a bit of over-engeneering to avoid clock skews
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle)) {
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle) && !busy_workers) {
uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck);
uwsgi.cheap = 1;
if (uwsgi.die_on_idle) {
@@ -1227,11 +1299,11 @@ health_cycle:
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->family == AF_INET) {
get_linux_tcp_info(uwsgi_sock->fd);
uwsgi_sock->queue = get_linux_tcp_info(uwsgi_sock->fd);
}
#ifdef SIOBKLGQ
else if (uwsgi_sock->family == AF_UNIX) {
get_linux_unbit_SIOBKLGQ(uwsgi_sock->fd);
uwsgi_sock->queue = get_linux_unbit_SIOBKLGQ(uwsgi_sock->fd);
}
#endif
uwsgi_sock = uwsgi_sock->next;
@@ -1415,17 +1487,7 @@ health_cycle:
continue;
/* reload the daemons */
// TODO reload_daemons(diedpid);
pid_found = 0;
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid == diedpid) {
spawn_daemon(ud);
pid_found = 1;
break;
}
ud = ud->next;
}
pid_found = uwsgi_daemon_check_pid_reload(diedpid);
if (pid_found)
continue;
@@ -1471,14 +1533,7 @@ health_cycle:
}
}
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid == diedpid) {
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
goto next;
}
ud = ud->next;
}
if (uwsgi_daemon_check_pid_death(diedpid)) goto next;
if (WIFEXITED(waitpid_status)) {
uwsgi_log("subprocess %d exited with code %d\n", (int) diedpid, WEXITSTATUS(waitpid_status));
@@ -1537,6 +1592,9 @@ next:
uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", uwsgi.mywid, (int) diedpid);
}
}
else {
uwsgi_log("DAMN ! worker %d (pid: %d) MISTERIOUSLY died :( trying respawn ...\n", uwsgi.mywid, (int) diedpid);
}
if (uwsgi.workers[uwsgi.mywid].cheaped == 1) {
uwsgi.workers[uwsgi.mywid].pid = 0;
+339 -200
View File
@@ -5,6 +5,30 @@ extern struct uwsgi_server uwsgi;
void worker_wakeup() {
}
void uwsgi_master_cleanup_hooks(void) {
int j;
// could be an inherited atexit hook
if (uwsgi.mywid > 0) return ;
uwsgi.cleaning = 1;
for (j = 0; j < uwsgi.gp_cnt; j++) {
if (uwsgi.gp[j]->master_cleanup) {
uwsgi.gp[j]->master_cleanup();
}
}
for (j = 0; j < 256; j++) {
if (uwsgi.p[j]->master_cleanup) {
uwsgi.p[j]->master_cleanup();
}
}
}
int uwsgi_calc_cheaper(void) {
int i;
@@ -240,6 +264,9 @@ void uwsgi_reload(char **argv) {
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
// call master cleanup hooks
uwsgi_master_cleanup_hooks();
// call atexit user exec
uwsgi_exec_atexit();
@@ -465,6 +492,27 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
int uwsgi_respawn_worker(int wid) {
int respawns = uwsgi.workers[wid].respawn_count;
// we count the respawns before errors...
uwsgi.workers[wid].respawn_count++;
// ... same for update time
uwsgi.workers[wid].last_spawn = uwsgi.current_time;
// ... and memory/harakiri
uwsgi.workers[wid].harakiri = 0;
uwsgi.workers[wid].user_harakiri = 0;
uwsgi.workers[wid].pending_harakiri = 0;
uwsgi.workers[wid].rss_size = 0;
uwsgi.workers[wid].vsz_size = 0;
// internal statuses should be reset too
uwsgi.workers[wid].cheaped = 0;
uwsgi.workers[wid].busy = 0;
uwsgi.workers[wid].suspended = 0;
uwsgi.workers[wid].sig = 0;
// this is required for various checks
uwsgi.workers[wid].delta_requests = 0;
int i;
if (uwsgi.threaded_logger) {
@@ -478,25 +526,30 @@ int uwsgi_respawn_worker(int wid) {
signal(SIGTSTP, worker_wakeup);
uwsgi.mywid = wid;
uwsgi.mypid = getpid();
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
// pid is updated by the master
//uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
// OVERENGINEERING (just to be safe)
uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid;
/*
uwsgi.workers[uwsgi.mywid].harakiri = 0;
uwsgi.workers[uwsgi.mywid].user_harakiri = 0;
uwsgi.workers[uwsgi.mywid].rss_size = 0;
uwsgi.workers[uwsgi.mywid].vsz_size = 0;
*/
// do not reset worker counters on reload !!!
//uwsgi.workers[uwsgi.mywid].requests = 0;
// ...but maintain a delta counter (yes this is racy in multithread)
uwsgi.workers[uwsgi.mywid].delta_requests = 0;
//uwsgi.workers[uwsgi.mywid].delta_requests = 0;
//uwsgi.workers[uwsgi.mywid].failed_requests = 0;
uwsgi.workers[uwsgi.mywid].respawn_count++;
uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time;
//uwsgi.workers[uwsgi.mywid].respawn_count++;
//uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time;
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
uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt;
@@ -521,6 +574,9 @@ int uwsgi_respawn_worker(int wid) {
uwsgi_error("fork()");
}
else {
// the pid is set only in the master, as the worker should never use it
uwsgi.workers[wid].pid = pid;
if (respawns > 0) {
uwsgi_log("Respawned uWSGI worker %d (new pid: %d)\n", wid, (int) pid);
}
@@ -709,18 +765,9 @@ void uwsgi_manage_command_cron(time_t now) {
}
void uwsgi_send_stats(int fd) {
struct uwsgi_stats *uwsgi_master_generate_stats() {
int i, j;
struct sockaddr_un client_src;
struct uwsgi_app *ua;
socklen_t client_src_len = 0;
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
if (client_fd < 0) {
uwsgi_error("accept()");
return;
}
int i;
struct uwsgi_stats *us = uwsgi_stats_new(8192);
@@ -734,6 +781,14 @@ void uwsgi_send_stats(int fd) {
goto end;
#endif
int signal_queue = 0;
if (ioctl(uwsgi.shared->worker_signal_pipe[1], FIONREAD, &signal_queue)) {
uwsgi_error("uwsgi_master_generate_stats() -> ioctl()\n");
}
if (uwsgi_stats_keylong_comma(us, "signal_queue", (unsigned long long) signal_queue))
goto end;
if (uwsgi_stats_keylong_comma(us, "load", (unsigned long long) uwsgi.shared->load))
goto end;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) getpid()))
@@ -744,248 +799,330 @@ void uwsgi_send_stats(int fd) {
goto end;
char *cwd = uwsgi_get_cwd();
if (uwsgi_stats_keyval_comma(us, "cwd", cwd))
goto end0;
if (uwsgi_stats_keyval_comma(us, "cwd", cwd)) {
free(cwd);
goto end;
}
free(cwd);
if (uwsgi.daemons) {
if (uwsgi_stats_key(us, "daemons"))
goto end0;
goto end;
if (uwsgi_stats_list_open(us))
goto end0;
goto end;
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (uwsgi_stats_object_open(us))
goto end0;
goto end;
if (uwsgi_stats_keyval_comma(us, "cmd", ud->command))
goto end0;
goto end;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) ud->pid))
goto end0;
goto end;
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) (ud->respawns - 1)))
goto end0;
goto end;
if (uwsgi_stats_object_close(us))
goto end0;
goto end;
if (ud->next) {
if (uwsgi_stats_comma(us))
goto end0;
goto end;
}
ud = ud->next;
}
if (uwsgi_stats_list_close(us))
goto end0;
goto end;
if (uwsgi_stats_comma(us))
goto end0;
goto end;
}
if (uwsgi_stats_key(us, "locks"))
goto end0;
goto end;
if (uwsgi_stats_list_open(us))
goto end0;
goto end;
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
while (uli) {
if (uwsgi_stats_object_open(us))
goto end0;
goto end;
if (uwsgi_stats_keylong(us, uli->id, (unsigned long long) uli->pid))
goto end0;
goto end;
if (uwsgi_stats_object_close(us))
goto end0;
goto end;
if (uli->next) {
if (uwsgi_stats_comma(us))
goto end0;
goto end;
}
uli = uli->next;
}
if (uwsgi_stats_list_close(us))
goto end0;
goto end;
if (uwsgi_stats_comma(us))
goto end0;
goto end;
if (uwsgi_stats_key(us, "sockets"))
goto end;
if (uwsgi_stats_key(us, "workers"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
goto end;
for (i = 0; i < uwsgi.numproc; i++) {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_stats_object_open(us))
goto end0;
goto end;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) uwsgi.workers[i + 1].id))
goto end0;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) uwsgi.workers[i + 1].pid))
goto end0;
if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uwsgi.workers[i + 1].requests))
goto end0;
if (uwsgi_stats_keylong_comma(us, "delta_requests", (unsigned long long) uwsgi.workers[i + 1].delta_requests))
goto end0;
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi.workers[i + 1].exceptions))
goto end0;
if (uwsgi_stats_keylong_comma(us, "harakiri_count", (unsigned long long) uwsgi.workers[i + 1].harakiri_count))
goto end0;
if (uwsgi_stats_keylong_comma(us, "signals", (unsigned long long) uwsgi.workers[i + 1].signals))
goto end0;
if (uwsgi_stats_keylong_comma(us, "static_offload_threads", (unsigned long long) uwsgi.workers[i + 1].static_offload_threads))
goto end0;
if (uwsgi_stats_keyval_comma(us, "name", uwsgi_sock->name))
goto end;
if (uwsgi.workers[i + 1].cheaped) {
if (uwsgi_stats_keyval_comma(us, "status", "cheap"))
goto end0;
}
else if (uwsgi.workers[i + 1].suspended && !uwsgi.workers[i + 1].busy) {
if (uwsgi_stats_keyval_comma(us, "status", "pause"))
goto end0;
}
else {
if (uwsgi.workers[i + 1].sig) {
if (uwsgi_stats_keyvalnum_comma(us, "status", "sig", (unsigned long long) uwsgi.workers[i + 1].signum))
goto end0;
}
else if (uwsgi.workers[i + 1].busy) {
if (uwsgi_stats_keyval_comma(us, "status", "busy"))
goto end0;
}
else {
if (uwsgi_stats_keyval_comma(us, "status", "idle"))
goto end0;
}
}
if (uwsgi_stats_keyval_comma(us, "proto", uwsgi_sock->proto_name ? uwsgi_sock->proto_name : "uwsgi"))
goto end;
if (uwsgi_stats_keylong_comma(us, "rss", (unsigned long long) uwsgi.workers[i + 1].rss_size))
goto end0;
if (uwsgi_stats_keylong_comma(us, "vsz", (unsigned long long) uwsgi.workers[i + 1].vsz_size))
goto end0;
if (uwsgi_stats_keylong_comma(us, "queue", (unsigned long long) uwsgi_sock->queue))
goto end;
if (uwsgi_stats_keylong_comma(us, "running_time", (unsigned long long) uwsgi.workers[i + 1].running_time))
goto end0;
if (uwsgi_stats_keylong_comma(us, "last_spawn", (unsigned long long) uwsgi.workers[i + 1].last_spawn))
goto end0;
if (uwsgi_stats_keylong_comma(us, "respawn_count", (unsigned long long) uwsgi.workers[i + 1].respawn_count))
goto end0;
if (uwsgi_stats_keylong_comma(us, "shared", (unsigned long long) uwsgi_sock->shared))
goto end;
if (uwsgi_stats_keylong_comma(us, "tx", (unsigned long long) uwsgi.workers[i + 1].tx))
goto end0;
if (uwsgi_stats_keylong_comma(us, "avg_rt", (unsigned long long) uwsgi.workers[i + 1].avg_response_time))
goto end0;
// applications list
if (uwsgi_stats_key(us, "apps"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
for (j = 0; j < uwsgi.workers[i + 1].apps_cnt; j++) {
ua = &uwsgi.workers[i + 1].apps[j];
if (uwsgi_stats_object_open(us))
goto end0;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j))
goto end0;
if (uwsgi_stats_keylong_comma(us, "modifier1", (unsigned long long) ua->modifier1))
goto end0;
if (uwsgi_stats_keyvaln_comma(us, "mountpoint", ua->mountpoint, ua->mountpoint_len))
goto end0;
if (uwsgi_stats_keylong_comma(us, "startup_time", ua->startup_time))
goto end0;
if (uwsgi_stats_keylong_comma(us, "requests", ua->requests))
goto end0;
if (uwsgi_stats_keylong_comma(us, "exceptions", ua->exceptions))
goto end0;
if (ua->chdir) {
if (uwsgi_stats_keyval(us, "chdir", ua->chdir))
goto end0;
}
else {
if (uwsgi_stats_keyval(us, "chdir", ""))
goto end0;
}
if (uwsgi_stats_object_close(us))
goto end0;
if (j < uwsgi.workers[i + 1].apps_cnt - 1) {
if (uwsgi_stats_comma(us))
goto end0;
}
}
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_comma(us))
goto end0;
// cores list
if (uwsgi_stats_key(us, "cores"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
for (j = 0; j < uwsgi.cores; j++) {
struct uwsgi_core *uc = &uwsgi.workers[i + 1].cores[j];
if (uwsgi_stats_object_open(us))
goto end0;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j))
goto end0;
if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uc->requests))
goto end0;
if (uwsgi_stats_keylong(us, "in_request", (unsigned long long) uc->in_request))
goto end0;
if (uwsgi_stats_object_close(us))
goto end0;
if (j < uwsgi.cores-1) {
if (uwsgi_stats_comma(us))
goto end0;
}
}
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_keylong(us, "can_offload", (unsigned long long) uwsgi_sock->can_offload))
goto end;
if (uwsgi_stats_object_close(us))
goto end0;
if (i < uwsgi.numproc - 1) {
goto end;
uwsgi_sock = uwsgi_sock->next;
if (uwsgi_sock) {
if (uwsgi_stats_comma(us))
goto end0;
goto end;
}
}
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_object_close(us))
goto end0;
goto end;
size_t remains = us->pos;
off_t pos = 0;
while (remains > 0) {
ssize_t res = write(client_fd, us->base + pos, remains);
if (res <= 0) {
if (res < 0) {
uwsgi_error("write()");
}
goto end0;
if (uwsgi_stats_comma(us))
goto end;
if (uwsgi_stats_key(us, "workers"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
for (i = 0; i < uwsgi.numproc; i++) {
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) uwsgi.workers[i + 1].id))
goto end;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) uwsgi.workers[i + 1].pid))
goto end;
if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uwsgi.workers[i + 1].requests))
goto end;
if (uwsgi_stats_keylong_comma(us, "delta_requests", (unsigned long long) uwsgi.workers[i + 1].delta_requests))
goto end;
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi.workers[i + 1].exceptions))
goto end;
if (uwsgi_stats_keylong_comma(us, "harakiri_count", (unsigned long long) uwsgi.workers[i + 1].harakiri_count))
goto end;
if (uwsgi_stats_keylong_comma(us, "signals", (unsigned long long) uwsgi.workers[i + 1].signals))
goto end;
if (ioctl(uwsgi.workers[i+1].signal_pipe[1], FIONREAD, &signal_queue)) {
uwsgi_error("uwsgi_master_generate_stats() -> ioctl()\n");
}
if (uwsgi_stats_keylong_comma(us, "signal_queue", (unsigned long long) signal_queue))
goto end;
/*
if (uwsgi_stats_keylong_comma(us, "static_offload_threads", (unsigned long long) uwsgi.workers[i + 1].static_offload_threads))
goto end;
*/
if (uwsgi.workers[i + 1].cheaped) {
if (uwsgi_stats_keyval_comma(us, "status", "cheap"))
goto end;
}
else if (uwsgi.workers[i + 1].suspended && !uwsgi.workers[i + 1].busy) {
if (uwsgi_stats_keyval_comma(us, "status", "pause"))
goto end;
}
else {
if (uwsgi.workers[i + 1].sig) {
if (uwsgi_stats_keyvalnum_comma(us, "status", "sig", (unsigned long long) uwsgi.workers[i + 1].signum))
goto end;
}
else if (uwsgi.workers[i + 1].busy) {
if (uwsgi_stats_keyval_comma(us, "status", "busy"))
goto end;
}
else {
if (uwsgi_stats_keyval_comma(us, "status", "idle"))
goto end;
}
}
if (uwsgi_stats_keylong_comma(us, "rss", (unsigned long long) uwsgi.workers[i + 1].rss_size))
goto end;
if (uwsgi_stats_keylong_comma(us, "vsz", (unsigned long long) uwsgi.workers[i + 1].vsz_size))
goto end;
if (uwsgi_stats_keylong_comma(us, "running_time", (unsigned long long) uwsgi.workers[i + 1].running_time))
goto end;
if (uwsgi_stats_keylong_comma(us, "last_spawn", (unsigned long long) uwsgi.workers[i + 1].last_spawn))
goto end;
if (uwsgi_stats_keylong_comma(us, "respawn_count", (unsigned long long) uwsgi.workers[i + 1].respawn_count))
goto end;
if (uwsgi_stats_keylong_comma(us, "tx", (unsigned long long) uwsgi.workers[i + 1].tx))
goto end;
if (uwsgi_stats_keylong_comma(us, "avg_rt", (unsigned long long) uwsgi.workers[i + 1].avg_response_time))
goto end;
// applications list
if (uwsgi_stats_key(us, "apps"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
int j;
for (j = 0; j < uwsgi.workers[i + 1].apps_cnt; j++) {
struct uwsgi_app *ua = &uwsgi.workers[i + 1].apps[j];
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j))
goto end;
if (uwsgi_stats_keylong_comma(us, "modifier1", (unsigned long long) ua->modifier1))
goto end;
if (uwsgi_stats_keyvaln_comma(us, "mountpoint", ua->mountpoint, ua->mountpoint_len))
goto end;
if (uwsgi_stats_keylong_comma(us, "startup_time", ua->startup_time))
goto end;
if (uwsgi_stats_keylong_comma(us, "requests", ua->requests))
goto end;
if (uwsgi_stats_keylong_comma(us, "exceptions", ua->exceptions))
goto end;
if (ua->chdir) {
if (uwsgi_stats_keyval(us, "chdir", ua->chdir))
goto end;
}
else {
if (uwsgi_stats_keyval(us, "chdir", ""))
goto end;
}
if (uwsgi_stats_object_close(us))
goto end;
if (j < uwsgi.workers[i + 1].apps_cnt - 1) {
if (uwsgi_stats_comma(us))
goto end;
}
}
if (uwsgi_stats_list_close(us))
goto end;
if (uwsgi_stats_comma(us))
goto end;
// cores list
if (uwsgi_stats_key(us, "cores"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
for (j = 0; j < uwsgi.cores; j++) {
struct uwsgi_core *uc = &uwsgi.workers[i + 1].cores[j];
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j))
goto end;
if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uc->requests))
goto end;
if (uwsgi_stats_keylong(us, "in_request", (unsigned long long) uc->in_request))
goto end;
if (uwsgi_stats_object_close(us))
goto end;
if (j < uwsgi.cores-1) {
if (uwsgi_stats_comma(us))
goto end;
}
}
if (uwsgi_stats_list_close(us))
goto end;
if (uwsgi_stats_object_close(us))
goto end;
if (i < uwsgi.numproc - 1) {
if (uwsgi_stats_comma(us))
goto end;
}
pos += res;
remains -= res;
}
end0:
free(cwd);
if (uwsgi_stats_list_close(us))
goto end;
#ifdef UWSGI_SPOOLER
struct uwsgi_spooler *uspool = uwsgi.spoolers;
if (uspool) {
if (uwsgi_stats_comma(us))
goto end;
if (uwsgi_stats_key(us, "spoolers"))
goto end;
if (uwsgi_stats_list_open(us))
goto end;
while (uspool) {
if (uwsgi_stats_object_open(us))
goto end;
if (uwsgi_stats_keyval_comma(us, "dir", uspool->dir))
goto end;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) uspool->pid))
goto end;
if (uwsgi_stats_keylong_comma(us, "tasks", (unsigned long long) uspool->tasks))
goto end;
if (uwsgi_stats_keylong_comma(us, "respawns", (unsigned long long) uspool->respawned))
goto end;
if (uwsgi_stats_keylong(us, "running", (unsigned long long) uspool->running))
goto end;
if (uwsgi_stats_object_close(us))
goto end;
uspool = uspool->next;
if (uspool) {
if (uwsgi_stats_comma(us))
goto end;
}
}
if (uwsgi_stats_list_close(us))
goto end;
}
#endif
if (uwsgi_stats_object_close(us))
goto end;
return us;
end:
free(us->base);
free(us);
close(client_fd);
return NULL;
}
void uwsgi_register_cheaper_algo(char *name, int (*func) (void)) {
@@ -1019,7 +1156,7 @@ void uwsgi_register_cheaper_algo(char *name, int (*func) (void)) {
void trigger_harakiri(int i) {
int j;
uwsgi_log("*** HARAKIRI ON WORKER %d (pid: %d) ***\n", i, uwsgi.workers[i].pid);
uwsgi_log("*** HARAKIRI ON WORKER %d (pid: %d, try: %d) ***\n", i, uwsgi.workers[i].pid, uwsgi.workers[i].pending_harakiri+1);
if (uwsgi.harakiri_verbose) {
#ifdef __linux__
int proc_file;
@@ -1071,7 +1208,9 @@ void trigger_harakiri(int i) {
// allow SIGUSR2 to be delivered
sleep(1);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].harakiri_count++;
if (!uwsgi.workers[i].pending_harakiri)
uwsgi.workers[i].harakiri_count++;
uwsgi.workers[i].pending_harakiri++;
}
// to avoid races
+3 -2
View File
@@ -49,10 +49,11 @@ void uwsgi_systemd_init(char *systemd_socket) {
return;
}
size_t len = strlen(systemd_socket);
sd_sun = uwsgi_malloc(sizeof(struct sockaddr_un));
memset(sd_sun, 0, sizeof(struct sockaddr_un));
sd_sun->sun_family = AF_UNIX;
strncpy(sd_sun->sun_path, systemd_socket, sizeof(sd_sun->sun_path));
strncpy(sd_sun->sun_path, systemd_socket, UMIN(len, sizeof(sd_sun->sun_path)));
if (sd_sun->sun_path[0] == '@') sd_sun->sun_path[0] = 0;
msghdr = uwsgi_malloc(sizeof(struct msghdr));
@@ -62,7 +63,7 @@ void uwsgi_systemd_init(char *systemd_socket) {
memset(msghdr->msg_iov, 0, sizeof(struct iovec)*3);
msghdr->msg_name = sd_sun;
msghdr->msg_namelen = sizeof(struct sockaddr_un);
msghdr->msg_namelen = sizeof(struct sockaddr_un) - (sizeof(sd_sun->sun_path)-len);
uwsgi.notification_object = msghdr;
+32 -2
View File
@@ -2,6 +2,28 @@
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_ELF
static void uwsgi_plugin_parse_section(char *filename) {
size_t s_len = 0;
char *buf = uwsgi_elf_section(filename, "uwsgi", &s_len);
if (buf) {
char *ctx = NULL;
char *p = strtok_r(buf, "\n", &ctx);
while(p) {
char *equal = strchr(p, '=');
if (equal) {
*equal = 0;
if (!strcmp(p, "requires")) {
uwsgi_load_plugin(-1, equal+1, NULL);
}
}
p = strtok_r(NULL, "\n", &ctx);
}
free(buf);
}
}
#endif
static int plugin_already_loaded(const char *plugin) {
int i;
@@ -57,7 +79,6 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
char *plugin_name = plugin;
char *plugin_symbol_name_start = plugin;
struct uwsgi_plugin *up;
char linkpath_buf[1024], linkpath[1024];
int linkpath_size;
@@ -79,6 +100,9 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
// step 1: check for absolute plugin (stop if it fails)
if (strchr(plugin_name, '/')) {
#ifdef UWSGI_ELF
uwsgi_plugin_parse_section(plugin_name);
#endif
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
if (!plugin_handle) {
if (!has_option)
@@ -95,6 +119,9 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
while(pdir) {
plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name);
#ifdef UWSGI_ELF
uwsgi_plugin_parse_section(plugin_filename);
#endif
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
if (plugin_handle) {
plugin_abs_path = plugin_filename;
@@ -109,6 +136,9 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
// last step: search in compile-time plugin_dir
if (!plugin_handle) {
plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name);
#ifdef UWSGI_ELF
uwsgi_plugin_parse_section(plugin_filename);
#endif
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
plugin_abs_path = plugin_filename;
//free(plugin_filename);
@@ -117,7 +147,7 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
success:
if (!plugin_handle) {
if (!has_option)
uwsgi_log( "%s\n", dlerror());
uwsgi_log( "!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror());
}
else {
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start)-3, "", 0);
+32 -78
View File
@@ -368,7 +368,11 @@ int uwsgi_enqueue_message(char *host, int port, uint8_t modifier1, uint8_t modif
return -1;
}
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0);
#else
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM, 0);
#endif
if (uwsgi_poll.fd < 0) {
uwsgi_error("socket()");
return -1;
@@ -475,7 +479,7 @@ ssize_t uwsgi_send_message(int fd, uint8_t modifier1, uint8_t modifier2, char *m
// transfer data from one socket to another
if (pfd >= 0 && plen > 0) {
ret = uwsgi_pipe_sized(pfd, fd, timeout, plen);
ret = uwsgi_pipe_sized(pfd, fd, plen, timeout);
if (ret < 0) return -1;
}
@@ -1024,9 +1028,14 @@ next:
}
}
// check for static files
// skip methods other than GET and HEAD
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3) &&
uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
return 0;
}
// skip extensions
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
while(sse) {
@@ -1037,6 +1046,7 @@ next:
}
sse = sse->next;
}
// check if a file named uwsgi.check_static+env['PATH_INFO'] exists
udd = uwsgi.check_static;
while(udd) {
@@ -1162,7 +1172,11 @@ int uwsgi_ping_node(int node, struct wsgi_request *wsgi_req) {
return 0;
}
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0);
#else
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM, 0);
#endif
if (uwsgi_poll.fd < 0) {
uwsgi_error("socket()");
return -1;
@@ -1908,42 +1922,31 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
headers_vec[3].iov_len = 48;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 4);
wsgi_req->header_cnt += 2;
// if it is a HEAD request just skip transfer
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
wsgi_req->status = 200;
return 0;
}
// Ok, the file must be transferred from uWSGI
if (wsgi_req->socket->can_offload) {
if (!uwsgi_offload_request_do(wsgi_req, real_filename, st->st_size)) {
wsgi_req->status = -30;
return 0;
}
}
wsgi_req->sendfile_fd = open(real_filename, O_RDONLY);
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
// here we need to close the sendfile fd (no-GC involved)
close(wsgi_req->sendfile_fd);
}
wsgi_req->status = 200;
return 0;
}
void *uwsgi_static_offload_thread(void *req) {
struct uwsgi_offload_request *uof_req = (struct uwsgi_offload_request *) req;
uwsgi_real_file_serve(&uof_req->wsgi_req, uof_req->real_filename, uof_req->real_filename_len, &uof_req->st);
// close the connection with the webserver
if (!uof_req->wsgi_req.fd_closed || !uof_req->wsgi_req.body_as_file) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
uof_req->wsgi_req.socket->proto_close(&uof_req->wsgi_req);
}
// free buffer
free(uof_req->buffer);
// free hvec
free(uof_req->hvec);
free(uof_req);
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uwsgi.workers[uwsgi.mywid].static_offload_threads--;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
return NULL;
}
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, int is_a_file) {
@@ -1996,56 +1999,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
sse = sse->next;
}
// Ok, the file must be served as static from uWSGI
if (uwsgi.static_offload_to_thread) {
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uint64_t offload_thread_count = uwsgi.workers[uwsgi.mywid].static_offload_threads;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
if (offload_thread_count > (uint64_t) uwsgi.static_offload_to_thread) {
uwsgi_log_verbose("OVERLOAD !!! unable to offload static file serving\n");
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request));
// buffer
uor->buffer = uwsgi_malloc(uwsgi.buffer_size); memcpy(uor->buffer, wsgi_req->buffer, uwsgi.buffer_size);
// iovec
uor->hvec = uwsgi_malloc(sizeof(struct iovec) * uwsgi.vec_size); memcpy(uor->hvec, wsgi_req->hvec, sizeof(struct iovec) * uwsgi.vec_size);
// wsgi_req
memcpy(&uor->wsgi_req, wsgi_req, sizeof(struct wsgi_request));
uor->wsgi_req.buffer = uor->buffer;
uor->wsgi_req.hvec = uor->hvec;
// stat
memcpy(&uor->st, &st, sizeof(struct stat));
// filename
memcpy(uor->real_filename, real_filename, real_filename_len);
uor->real_filename_len = real_filename_len;
uor->real_filename[uor->real_filename_len] = 0;
// avoid closing the connection
wsgi_req->fd_closed = 1;
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uwsgi.workers[uwsgi.mywid].static_offload_threads++;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
if (pthread_create(&uor->tid, &uwsgi.static_offload_thread_attr, uwsgi_static_offload_thread, (void *) uor)) {
uwsgi_error("pthread_create()");
// bad condition, better to exit...
exit(1);
}
wsgi_req->status = -30;
return 0;
}
else {
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
return -1;
+194 -4
View File
@@ -1,9 +1,201 @@
#ifdef UWSGI_SENDFILE
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
/*
enqueue a file transfer to the offload thread
*/
int uwsgi_offload_request_do(struct wsgi_request *wsgi_req, char *filename, size_t len) {
struct stat st;
// avoid closing the connection
wsgi_req->fd_closed = 1;
// fill offload request
struct uwsgi_offload_request uor;
uor.fd = open(filename, O_RDONLY | O_NONBLOCK);
if (uor.fd < 0) {
uwsgi_error_open(filename);
goto error;
}
uor.s = wsgi_req->poll.fd;
// make a fstat to get the file size
if (!len) {
if (fstat(uor.fd, &st)) {
uwsgi_error("fstat()");
goto error2;
}
len = st.st_size;
}
uor.pos = 0;
uor.len = len;
uor.written = 0;
uor.buf = NULL;
uor.prev = NULL;
uor.next = NULL;
// put socket in non-blocking mode
uwsgi_socket_nb(uor.s);
if (write(uwsgi.offload_thread->pipe[0], &uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) {
goto error2;
}
return 0;
error2:
close(uor.fd);
error:
wsgi_req->fd_closed = 0;
return -1;
}
static void uwsgi_offload_close(struct uwsgi_offload_request *uor) {
// close the socket and the file descriptor
close(uor->s);
close(uor->fd);
// remove the structure from the linked list;
struct uwsgi_offload_request *prev = uor->prev;
struct uwsgi_offload_request *next = uor->next;
if (uor == uwsgi.offload_requests_head) {
uwsgi.offload_requests_head = next;
}
if (uor == uwsgi.offload_requests_tail) {
uwsgi.offload_requests_tail = prev;
}
if (prev) {
prev->next = next;
}
if (next) {
next->prev = prev;
}
if (uor->buf) {
free(uor->buf);
}
free(uor);
}
static void uwsgi_offload_append(struct uwsgi_offload_request *uor) {
if (!uwsgi.offload_requests_head) {
uwsgi.offload_requests_head = uor;
}
if (uwsgi.offload_requests_tail) {
uwsgi.offload_requests_tail->next = uor;
uor->prev = uwsgi.offload_requests_tail;
}
uwsgi.offload_requests_tail = uor;
}
static struct uwsgi_offload_request *uwsgi_offload_get_by_socket(int s) {
struct uwsgi_offload_request *uor = uwsgi.offload_requests_head;
while(uor) {
if (uor->s == s) {
return uor;
}
uor = uor->next;
}
return NULL;
}
static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
int i;
void *events = event_queue_alloc(uwsgi.static_offload_to_thread);
for(;;) {
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.static_offload_to_thread);
for (i=0;i<nevents;i++) {
int interesting_fd = event_queue_interesting_fd(events, i);
if (interesting_fd == uwsgi.offload_thread->pipe[1]) {
struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request));
ssize_t len = read(uwsgi.offload_thread->pipe[1], uor, sizeof(struct uwsgi_offload_request));
if (len != sizeof(struct uwsgi_offload_request)) {
uwsgi_error("read()");
free(uor);
continue;
}
// start monitoring socket for write
if (event_queue_add_fd_write(ut->queue, uor->s)) {
free(uor);
continue;
}
uwsgi_offload_append(uor);
continue;
}
// ok check for socket writability
struct uwsgi_offload_request *uor = uwsgi_offload_get_by_socket(interesting_fd);
if (!uor) continue;
// sendfile() in chunks (128k is a good size...)
#if defined(__linux__)
ssize_t len = sendfile(uor->s, uor->fd, &uor->pos, 128*1024);
if (len > 0) {
uor->written += len;
if (uor->written >= uor->len) {
uwsgi_offload_close(uor);
}
continue;
}
else if (len < 0) {
if (errno == EAGAIN) continue;
uwsgi_error("sendfile()");
}
#else
if (!uor->buf) {
uor->buf = uwsgi_malloc(32768);
uor->to_write = 0;
}
if (uor->to_write == 0) {
ssize_t len = read(uor->fd, uor->buf, 32768);
if (len > 0) {
uor->to_write = len;
uor->buf_pos = 0;
continue;
}
else if (len < 0) {
uwsgi_error("read()");
}
uwsgi_offload_close(uor);
continue;
}
ssize_t len = write(uor->s, uor->buf + uor->buf_pos, uor->to_write);
if (len > 0) {
uor->written += len;
uor->to_write -= len;
uor->buf_pos += len;
if (uor->written >= uor->len) {
uwsgi_offload_close(uor);
}
continue;
}
else if (len < 0) {
if (errno == EAGAIN) continue;
uwsgi_error("write()");
}
#endif
uwsgi_offload_close(uor);
}
}
}
struct uwsgi_thread *uwsgi_offload_thread_start() {
return uwsgi_thread_new(uwsgi_offload_loop);
}
ssize_t uwsgi_sendfile(struct wsgi_request *wsgi_req) {
int fd = wsgi_req->sendfile_fd;
@@ -173,5 +365,3 @@ ssize_t uwsgi_do_sendfile(int sockfd, int filefd, size_t filesize, size_t chunk,
#endif
}
#endif
+227 -216
View File
@@ -4,13 +4,15 @@ extern struct uwsgi_server uwsgi;
int uwsgi_signal_handler(uint8_t sig) {
struct uwsgi_signal_entry *use = NULL;
struct uwsgi_signal_entry *use = NULL;
use = &uwsgi.shared->signal_table[sig];
if (!use->handler) return -1;
if (!uwsgi.p[use->modifier1]->signal_handler) {
return -1;
}
}
// check for COW
if (uwsgi.master_process) {
@@ -34,52 +36,52 @@ int uwsgi_signal_handler(uint8_t sig) {
}
}
// set harakiri here (if required and if i am a worker)
// set harakiri here (if required and if i am a worker)
if (uwsgi.mywid > 0) {
uwsgi.workers[uwsgi.mywid].sig = 1;
uwsgi.workers[uwsgi.mywid].signum = sig;
uwsgi.workers[uwsgi.mywid].sig = 1;
uwsgi.workers[uwsgi.mywid].signum = sig;
uwsgi.workers[uwsgi.mywid].signals++;
if(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
}
}
}
else if (uwsgi.muleid > 0) {
uwsgi.mules[uwsgi.muleid-1].sig = 1;
uwsgi.mules[uwsgi.muleid-1].signum = sig;
uwsgi.mules[uwsgi.muleid-1].signals++;
if(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI] > 0) {
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
uwsgi.mules[uwsgi.muleid - 1].sig = 1;
uwsgi.mules[uwsgi.muleid - 1].signum = sig;
uwsgi.mules[uwsgi.muleid - 1].signals++;
if (uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI] > 0) {
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
}
}
#ifdef UWSGI_SPOOLER
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
}
}
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
}
}
#endif
int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler);
if (uwsgi.mywid > 0) {
uwsgi.workers[uwsgi.mywid].sig = 0;
if(uwsgi.workers[uwsgi.mywid].harakiri > 0) {
set_harakiri(0);
uwsgi.workers[uwsgi.mywid].sig = 0;
if (uwsgi.workers[uwsgi.mywid].harakiri > 0) {
set_harakiri(0);
}
}
}
else if (uwsgi.muleid > 0) {
uwsgi.mules[uwsgi.muleid-1].sig = 0;
if(uwsgi.mules[uwsgi.muleid-1].harakiri > 0) {
set_mule_harakiri(0);
uwsgi.mules[uwsgi.muleid - 1].sig = 0;
if (uwsgi.mules[uwsgi.muleid - 1].harakiri > 0) {
set_mule_harakiri(0);
}
}
}
#ifdef UWSGI_SPOOLER
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(0);
}
}
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(0);
}
}
#endif
return ret;
@@ -97,7 +99,8 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
struct uwsgi_signal_entry *use = NULL;
if (strlen(receiver) > 63) return -1;
if (strlen(receiver) > 63)
return -1;
uwsgi_lock(uwsgi.signal_table_lock);
@@ -109,7 +112,7 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
return -1;
}
strncpy(use->receiver, receiver, strlen(receiver)+1);
strncpy(use->receiver, receiver, strlen(receiver) + 1);
use->handler = handler;
use->modifier1 = modifier1;
use->wid = uwsgi.mywid;
@@ -129,7 +132,7 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
if (strlen(filename) > (0xff-1)) {
if (strlen(filename) > (0xff - 1)) {
uwsgi_log("uwsgi_add_file_monitor: invalid filename length\n");
return -1;
}
@@ -140,9 +143,9 @@ int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
// fill the fmon table, the master will use it to add items to the event queue
memcpy(ushared->files_monitored[ushared->files_monitored_cnt].filename, filename, strlen(filename));
ushared->files_monitored[ushared->files_monitored_cnt].registered = 0;
ushared->files_monitored[ushared->files_monitored_cnt].registered = 0;
ushared->files_monitored[ushared->files_monitored_cnt].sig = sig;
ushared->files_monitored_cnt++;
}
else {
@@ -157,31 +160,31 @@ int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
}
struct uwsgi_probe *uwsgi_probe_register(struct uwsgi_probe **up, char *name, int (*func)(int, struct uwsgi_signal_probe *)) {
struct uwsgi_probe *uwsgi_probe_register(struct uwsgi_probe **up, char *name, int (*func) (int, struct uwsgi_signal_probe *)) {
struct uwsgi_probe *uwsgi_up = *up, *old_up;
struct uwsgi_probe *uwsgi_up = *up, *old_up;
if (!uwsgi_up) {
*up = uwsgi_malloc(sizeof(struct uwsgi_probe));
uwsgi_up = *up;
}
else {
while(uwsgi_up) {
old_up = uwsgi_up;
uwsgi_up = uwsgi_up->next;
}
if (!uwsgi_up) {
*up = uwsgi_malloc(sizeof(struct uwsgi_probe));
uwsgi_up = *up;
}
else {
while (uwsgi_up) {
old_up = uwsgi_up;
uwsgi_up = uwsgi_up->next;
}
uwsgi_up = uwsgi_malloc(sizeof(struct uwsgi_probe));
old_up->next = uwsgi_up;
}
uwsgi_up = uwsgi_malloc(sizeof(struct uwsgi_probe));
old_up->next = uwsgi_up;
}
uwsgi_up->name = name;
uwsgi_up->func = func;
uwsgi_up->next = NULL;
uwsgi_up->name = name;
uwsgi_up->func = func;
uwsgi_up->next = NULL;
uwsgi_log("registered new probe \"%s\" at %p\n", name, uwsgi_up);
return uwsgi_up;
return uwsgi_up;
}
@@ -189,10 +192,10 @@ int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq)
uwsgi_lock(uwsgi.probe_table_lock);
if (ushared->probes_cnt < MAX_PROBES) {
if (ushared->probes_cnt < MAX_PROBES) {
struct uwsgi_probe *up = uwsgi.probes;
while(up) {
while (up) {
if (!strcmp(up->name, kind)) {
break;
}
@@ -201,15 +204,15 @@ int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq)
if (!up) {
uwsgi_log("unable to find probe \"%s\" !!!\n", kind);
uwsgi_unlock(uwsgi.probe_table_lock);
return -1;
uwsgi_unlock(uwsgi.probe_table_lock);
return -1;
}
// fill the probe table
ushared->probes[ushared->probes_cnt].func = up->func;
strncpy(ushared->probes[ushared->probes_cnt].args, args, 1024-1);
ushared->probes[ushared->probes_cnt].registered = 0;
ushared->probes[ushared->probes_cnt].sig = sig;
// fill the probe table
ushared->probes[ushared->probes_cnt].func = up->func;
strncpy(ushared->probes[ushared->probes_cnt].args, args, 1024 - 1);
ushared->probes[ushared->probes_cnt].registered = 0;
ushared->probes[ushared->probes_cnt].sig = sig;
ushared->probes[ushared->probes_cnt].fd = -1;
ushared->probes[ushared->probes_cnt].state = 0;
ushared->probes[ushared->probes_cnt].last_event = 0;
@@ -225,15 +228,15 @@ int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq)
freq = 1;
}
ushared->probes[ushared->probes_cnt].freq = freq;
ushared->probes_cnt++;
}
else {
uwsgi_log("you can register max %d probes !!!\n", MAX_PROBES);
uwsgi_unlock(uwsgi.probe_table_lock);
return -1;
}
ushared->probes_cnt++;
}
else {
uwsgi_log("you can register max %d probes !!!\n", MAX_PROBES);
uwsgi_unlock(uwsgi.probe_table_lock);
return -1;
}
uwsgi_unlock(uwsgi.probe_table_lock);
uwsgi_unlock(uwsgi.probe_table_lock);
return 0;
}
@@ -267,107 +270,109 @@ void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
int i;
struct uwsgi_cron *old_uc, *uc = uwsgi.crons;
if (!uc) {
uc = uwsgi_malloc(sizeof(struct uwsgi_cron));
uwsgi.crons = uc;
}
else {
old_uc = uc;
while(uc->next) {
uc = uc->next;
old_uc = uc;
}
if (!uc) {
uc = uwsgi_malloc(sizeof(struct uwsgi_cron));
uwsgi.crons = uc;
}
else {
old_uc = uc;
while (uc->next) {
uc = uc->next;
old_uc = uc;
}
old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron));
uc = old_uc->next;
}
old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron));
uc = old_uc->next;
}
memset(uc, 0, sizeof(struct uwsgi_cron));
memset(uc, 0, sizeof(struct uwsgi_cron));
if (sscanf(value, "%d %d %d %d %d %n", &uc->minute, &uc->hour, &uc->day, &uc->month, &uc->week, &i) != 5) {
uwsgi_log("invalid cron syntax\n");
exit(1);
}
uc->command = value+i;
if (sscanf(value, "%d %d %d %d %d %n", &uc->minute, &uc->hour, &uc->day, &uc->month, &uc->week, &i) != 5) {
uwsgi_log("invalid cron syntax\n");
exit(1);
}
uc->command = value + i;
}
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) {
if (!uwsgi.master_process) return -1;
if (!uwsgi.master_process)
return -1;
uwsgi_lock(uwsgi.cron_table_lock);
if (ushared->cron_cnt < MAX_CRONS) {
if (ushared->cron_cnt < MAX_CRONS) {
ushared->cron[ushared->cron_cnt].sig = sig;
ushared->cron[ushared->cron_cnt].minute = minute;
ushared->cron[ushared->cron_cnt].hour = hour;
ushared->cron[ushared->cron_cnt].day = day;
ushared->cron[ushared->cron_cnt].month = month;
ushared->cron[ushared->cron_cnt].week = week;
ushared->cron_cnt++;
}
else {
uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS);
uwsgi_unlock(uwsgi.cron_table_lock);
return -1;
}
ushared->cron[ushared->cron_cnt].sig = sig;
ushared->cron[ushared->cron_cnt].minute = minute;
ushared->cron[ushared->cron_cnt].hour = hour;
ushared->cron[ushared->cron_cnt].day = day;
ushared->cron[ushared->cron_cnt].month = month;
ushared->cron[ushared->cron_cnt].week = week;
ushared->cron_cnt++;
}
else {
uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS);
uwsgi_unlock(uwsgi.cron_table_lock);
return -1;
}
uwsgi_unlock(uwsgi.cron_table_lock);
uwsgi_unlock(uwsgi.cron_table_lock);
return 0;
return 0;
}
int uwsgi_signal_add_rb_timer(uint8_t sig, int secs, int iterations) {
if (!uwsgi.master_process) return -1;
if (!uwsgi.master_process)
return -1;
uwsgi_lock(uwsgi.rb_timer_table_lock);
uwsgi_lock(uwsgi.rb_timer_table_lock);
if (ushared->rb_timers_cnt < 64) {
if (ushared->rb_timers_cnt < 64) {
// fill the timer table, the master will use it to add items to the event queue
ushared->rb_timers[ushared->rb_timers_cnt].value = secs;
ushared->rb_timers[ushared->rb_timers_cnt].registered = 0;
ushared->rb_timers[ushared->rb_timers_cnt].iterations = iterations;
ushared->rb_timers[ushared->rb_timers_cnt].iterations_done = 0;
ushared->rb_timers[ushared->rb_timers_cnt].sig = sig;
ushared->rb_timers_cnt++;
}
else {
uwsgi_log("you can register max 64 rb_timers !!!\n");
uwsgi_unlock(uwsgi.rb_timer_table_lock);
return -1;
}
// fill the timer table, the master will use it to add items to the event queue
ushared->rb_timers[ushared->rb_timers_cnt].value = secs;
ushared->rb_timers[ushared->rb_timers_cnt].registered = 0;
ushared->rb_timers[ushared->rb_timers_cnt].iterations = iterations;
ushared->rb_timers[ushared->rb_timers_cnt].iterations_done = 0;
ushared->rb_timers[ushared->rb_timers_cnt].sig = sig;
ushared->rb_timers_cnt++;
}
else {
uwsgi_log("you can register max 64 rb_timers !!!\n");
uwsgi_unlock(uwsgi.rb_timer_table_lock);
return -1;
}
uwsgi_unlock(uwsgi.rb_timer_table_lock);
uwsgi_unlock(uwsgi.rb_timer_table_lock);
return 0;
return 0;
}
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]);
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_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[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_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()");
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
uwsgi_error("setsockopt()");
}
}
}
@@ -379,9 +384,10 @@ int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
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 (fd < 0)
return -1;
if (write(fd, (char *) &uh, 4) != 4) {
uwsgi_error("uwsgi_remote_signal_send()");
@@ -403,16 +409,16 @@ int uwsgi_signal_send(int fd, uint8_t sig) {
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);
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;
}
@@ -430,7 +436,7 @@ void uwsgi_route_signal(uint8_t sig) {
}
// send to all workers
else if (!strcmp(use->receiver, "workers")) {
for(i=1;i<=uwsgi.numproc;i++) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
}
@@ -438,13 +444,13 @@ void uwsgi_route_signal(uint8_t sig) {
}
// route to specific worker
else if (!strncmp(use->receiver, "worker", 6)) {
i = atoi(use->receiver+6);
i = atoi(use->receiver + 6);
if (i > uwsgi.numproc) {
uwsgi_log("invalid signal target: %s\n", use->receiver);
}
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
}
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
}
}
// route to subscribed
else if (!strcmp(use->receiver, "subscribed")) {
@@ -454,54 +460,54 @@ void uwsgi_route_signal(uint8_t sig) {
else if (!strcmp(use->receiver, "spooler")) {
if (ushared->worker_signal_pipe[0] != -1) {
if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to the spooler\n", sig);
}
uwsgi_log("could not deliver signal %d to the spooler\n", sig);
}
}
}
#endif
else if (!strcmp(use->receiver, "mules")) {
for(i=0;i<uwsgi.mules_cnt;i++) {
for (i = 0; i < uwsgi.mules_cnt; i++) {
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);
}
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i + 1);
}
}
}
else if (!strncmp(use->receiver, "mule", 4)) {
i = atoi(use->receiver+4);
i = atoi(use->receiver + 4);
if (i > uwsgi.mules_cnt) {
uwsgi_log("invalid signal target: %s\n", use->receiver);
}
else if (i == 0) {
if (uwsgi_signal_send(ushared->mule_signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to a mule\n", sig);
}
uwsgi_log("could not deliver signal %d to a mule\n", sig);
}
}
else {
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);
}
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);
}
}
}
else if (!strncmp(use->receiver, "farm_", 5)) {
char *name = use->receiver+5;
char *name = use->receiver + 5;
struct uwsgi_farm *uf = get_farm_by_name(name);
if (!uf) {
uwsgi_log("unknown farm: %s\n", name);
return;
}
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);
}
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, uf->id, uf->name);
}
}
else if (!strncmp(use->receiver, "farm", 4)) {
i = atoi(use->receiver+4);
i = atoi(use->receiver + 4);
if (i > uwsgi.farms_cnt || i <= 0) {
uwsgi_log("invalid signal target: %s\n", use->receiver);
}
else {
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);
}
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);
}
}
}
@@ -512,51 +518,56 @@ void uwsgi_route_signal(uint8_t sig) {
}
uint8_t uwsgi_signal_wait(int signum) {
int 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];
int wait_for_specific_signal = 0;
uint8_t uwsgi_signal = 0;
int received_signal = -1;
int ret;
struct pollfd pfd[2];
if (signum > -1) {
wait_for_specific_signal = 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;
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;
}
}
ret = poll(pfd, 2, -1);
if (ret > 0) {
if (pfd[0].revents == POLLIN) {
if (read(uwsgi.signal_socket, &uwsgi_signal, 1) != 1) {
uwsgi_error("read()");
}
else {
(void) uwsgi_signal_handler(uwsgi_signal);
if (wait_for_specific_signal) {
if (signum != uwsgi_signal)
goto cycle;
}
received_signal = uwsgi_signal;
}
}
if (pfd[1].revents == POLLIN) {
if (read(uwsgi.my_signal_socket, &uwsgi_signal, 1) != 1) {
uwsgi_error("read()");
}
else {
(void) uwsgi_signal_handler(uwsgi_signal);
if (wait_for_specific_signal) {
if (signum != uwsgi_signal)
goto cycle;
}
}
received_signal = uwsgi_signal;
}
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;
return received_signal;
}
void uwsgi_receive_signal(int fd, char *name, int id) {
@@ -565,27 +576,27 @@ void uwsgi_receive_signal(int fd, char *name, int id) {
ssize_t ret = read(fd, &uwsgi_signal, 1);
if (ret == 0) {
if (ret == 0) {
goto destroy;
}
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
uwsgi_error("[uwsgi-signal] read()");
}
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
uwsgi_error("[uwsgi-signal] read()");
goto destroy;
}
else if (ret > 0) {
}
else if (ret > 0) {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id);
uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id);
}
}
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id);
}
}
return;
destroy:
// better to kill the whole worker...
uwsgi_log_verbose("uWSGI %s %d screams: UAAAAAAH my master disconnected: i will kill myself !!!\n", name, id);
uwsgi_log_verbose("uWSGI %s %d screams: UAAAAAAH my master disconnected: i will kill myself !!!\n", name, id);
end_me(0);
}
+3
View File
@@ -249,11 +249,14 @@ static uint64_t get_uwsgi_snmp_value(uint64_t val, uint8_t * oid_t) {
static uint64_t get_uwsgi_custom_snmp_value(uint64_t val, uint8_t * oid_t) {
val--;
uwsgi_wlock(uwsgi.snmp_lock);
if (uwsgi.shared->snmp_value[val].type) {
*oid_t = uwsgi.shared->snmp_value[val].type;
uwsgi_rwunlock(uwsgi.snmp_lock);
return uwsgi.shared->snmp_value[val].val;
}
uwsgi_rwunlock(uwsgi.snmp_lock);
*oid_t = SNMP_NULL;
return 0;
}
+63 -13
View File
@@ -174,6 +174,7 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
struct sockaddr_in uws_addr;
char *udp_port;
int bcast = 1;
int reuse = 1;
#ifdef UWSGI_MULTICAST
struct ip_mreq mc;
@@ -231,6 +232,10 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
return -1;
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
}
#ifdef UWSGI_MULTICAST
if (multicast) {
// if multicast is enabled remember to bind to INADDR_ANY
@@ -265,6 +270,10 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
uwsgi_error("setsockopt()");
}
if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_TTL, &uwsgi.multicast_ttl, sizeof(uwsgi.multicast_ttl))) {
uwsgi_error("setsockopt()");
}
}
#endif
@@ -325,7 +334,11 @@ int connect_to_unix(char *socket_name, int timeout, int async) {
memcpy(uws_addr.sun_path, socket_name, UMIN(strlen(socket_name), 102));
}
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
uwsgi_poll.fd = socket(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, 0);
#else
uwsgi_poll.fd = socket(AF_UNIX, SOCK_STREAM, 0);
#endif
if (uwsgi_poll.fd < 0) {
uwsgi_error("socket()");
return -1;
@@ -363,7 +376,11 @@ int connect_to_tcp(char *socket_name, int port, int timeout, int async) {
socket_name[strlen(socket_name)] = ':';
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0);
#else
uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM, 0);
#endif
if (uwsgi_poll.fd < 0) {
uwsgi_error("socket()");
return -1;
@@ -542,7 +559,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
uwsgi_error("SO_REUSEADDR setsockopt()");
uwsgi_nuclear_blast();
}
@@ -550,7 +567,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
#ifdef IP_FREEBIND
if (uwsgi.freebind) {
if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
uwsgi_error("IP_FREEBIND setsockopt()");
uwsgi_nuclear_blast();
}
}
@@ -560,7 +577,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (uwsgi.reuse_port) {
#ifdef SO_REUSEPORT
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
uwsgi_error("SO_REUSEPORT setsockopt()");
uwsgi_nuclear_blast();
}
#else
@@ -568,11 +585,21 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
#endif
}
if (uwsgi.so_send_timeout) {
struct timeval tv;
tv.tv_sec = uwsgi.so_send_timeout;
tv.tv_usec = 0;
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDTIMEO, (const void *) &tv, sizeof(struct timeval)) < 0) {
uwsgi_error("SO_SNDTIMEO setsockopt()");
uwsgi_nuclear_blast();
}
}
if (!uwsgi.no_defer_accept) {
#ifdef __linux__
if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], sizeof(int))) {
uwsgi_error("setsockopt()");
uwsgi_error("TCP_DEFER_ACCEPT setsockopt()");
}
// OSX has no SO_ACCEPTFILTER !!!
#elif defined(__freebsd__)
@@ -580,7 +607,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
strcpy(afa.af_name, "dataready");
afa.af_arg[0] = 0;
if (setsockopt(serverfd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(struct accept_filter_arg))) {
uwsgi_error("setsockopt()");
uwsgi_error("SO_ACCEPTFILTER setsockopt()");
}
#endif
@@ -588,19 +615,27 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (uwsgi.so_keepalive) {
if (setsockopt(serverfd, SOL_SOCKET, SO_KEEPALIVE, &uwsgi.so_keepalive, sizeof(int))) {
uwsgi_error("setsockopt()");
uwsgi_error("SO_KEEPALIVE setsockopt()");
}
}
if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) {
if (errno == EADDRINUSE) {
uwsgi_log("probably another instance of uWSGI is running on the same address.\n");
uwsgi_log("probably another instance of uWSGI is running on the same address (%s).\n", socket_name);
}
uwsgi_error("bind()");
uwsgi_nuclear_blast();
}
#ifdef __linux__
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn");
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%i).\n", somaxconn);
uwsgi_nuclear_blast();
}
#endif
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
@@ -650,13 +685,16 @@ void uwsgi_socket_b(int fd) {
int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_size, int timeout, int async) {
int arg, ret;
int ret;
int soopt = 0;
socklen_t solen = sizeof(int);
int cnt;
/* set non-blocking socket */
arg = fcntl(fdpoll->fd, F_GETFL, NULL);
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
// hmm, nothing to do, as we are already non-blocking
#else
int arg = fcntl(fdpoll->fd, F_GETFL, NULL);
if (arg < 0) {
uwsgi_error("fcntl()");
return -1;
@@ -666,6 +704,7 @@ int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_s
uwsgi_error("fcntl()");
return -1;
}
#endif
ret = connect(fdpoll->fd, addr, addr_size);
@@ -673,17 +712,20 @@ int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_s
if (ret < 0 && errno != EINPROGRESS) {
return -1;
}
return 0;
}
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
// hmm, nothing to do, as we are already non-blocking
#else
/* re-set blocking socket */
arg &= (~O_NONBLOCK);
if (fcntl(fdpoll->fd, F_SETFL, arg) < 0) {
uwsgi_error("fcntl()");
return -1;
}
if (async)
return 0;
#endif
if (ret < 0) {
/* check what happened */
@@ -1526,6 +1568,10 @@ void uwsgi_map_sockets() {
while (usl) {
char *colon = strchr(usl->value, ':');
if (!colon) {
uwsgi_log("invalid socket mapping, must be socket:worker[,worker...]\n");
exit(1);
}
if ((int) uwsgi_str_num(usl->value, colon - usl->value) == uwsgi_get_socket_num(uwsgi_sock)) {
enabled = 0;
char *p = strtok(colon + 1, ",");
@@ -1738,9 +1784,11 @@ setup_proto:
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
uwsgi_sock->proto_sendfile = NULL;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
if (uwsgi.static_offload_to_thread)
uwsgi_sock->can_offload = 1;
}
else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) {
if (!strcmp(uwsgi.protocol, "fastcgi") || !strcmp(uwsgi.protocol, "fcgi")) {
if (uwsgi.protocol && (!strcmp(uwsgi.protocol, "fastcgi") || !strcmp(uwsgi.protocol, "fcgi"))) {
uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] = 1;
}
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
@@ -1766,6 +1814,8 @@ setup_proto:
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
uwsgi_sock->proto_sendfile = NULL;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
if (uwsgi.static_offload_to_thread)
uwsgi_sock->can_offload = 1;
}
nextsock:
uwsgi_sock = uwsgi_sock->next;
+8 -6
View File
@@ -355,12 +355,6 @@ void spooler(struct uwsgi_spooler *uspool) {
}
wakeup = tmp_wakeup;
// need to recycle ?
if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t)uwsgi.spooler_max_tasks) {
uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks);
end_me(0);
}
}
}
@@ -551,6 +545,14 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
uwsgi_protected_close(spool_fd);
uspool->running = 0;
// need to recycle ?
if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t)uwsgi.spooler_max_tasks) {
uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks);
end_me(0);
}
if (chdir(dir)) {
uwsgi_error("chdir()");
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
+226 -9
View File
@@ -3,15 +3,21 @@
utility functions for fast generating json output for the stats subsystem
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_stats *uwsgi_stats_new(size_t chunk_size) {
struct uwsgi_stats *us = uwsgi_malloc(sizeof(struct uwsgi_stats));
us->base = uwsgi_malloc(chunk_size);
us->base[0] = '{';
us->base[1] = '\n';
us->pos = 2;
us->pos = 1;
us->chunk = chunk_size;
us->size = chunk_size;
us->tabs = 1;
us->minified = uwsgi.stats_minified;
if (!us->minified) {
us->base[1] = '\n';
us->pos++;
}
return us;
}
@@ -36,6 +42,7 @@ int uwsgi_stats_symbol_nl(struct uwsgi_stats *us, char sym) {
if (uwsgi_stats_symbol(us, sym)) {
return -1;
}
if (us->minified) return 0;
return uwsgi_stats_symbol(us, '\n');
}
@@ -45,6 +52,7 @@ int uwsgi_stats_comma(struct uwsgi_stats *us) {
}
int uwsgi_stats_apply_tabs(struct uwsgi_stats *us) {
if (us->minified) return 0;
size_t i;
for(i=0;i<us->tabs;i++) {
if (uwsgi_stats_symbol(us, '\t')) return -1;
@@ -55,14 +63,16 @@ int uwsgi_stats_apply_tabs(struct uwsgi_stats *us) {
int uwsgi_stats_object_open(struct uwsgi_stats *us) {
if (uwsgi_stats_apply_tabs(us)) return -1;
us->tabs++;
if (!us->minified) us->tabs++;
return uwsgi_stats_symbol_nl(us, '{');
}
int uwsgi_stats_object_close(struct uwsgi_stats *us) {
if (uwsgi_stats_symbol(us, '\n')) return -1;
us->tabs--;
if (uwsgi_stats_apply_tabs(us)) return -1;
if (!us->minified) {
if (uwsgi_stats_symbol(us, '\n')) return -1;
us->tabs--;
if (uwsgi_stats_apply_tabs(us)) return -1;
}
return uwsgi_stats_symbol(us, '}');
}
@@ -72,9 +82,11 @@ int uwsgi_stats_list_open(struct uwsgi_stats *us) {
}
int uwsgi_stats_list_close(struct uwsgi_stats *us) {
if (uwsgi_stats_symbol(us, '\n')) return -1;
us->tabs--;
if (uwsgi_stats_apply_tabs(us)) return -1;
if (!us->minified) {
if (uwsgi_stats_symbol(us, '\n')) return -1;
us->tabs--;
if (uwsgi_stats_apply_tabs(us)) return -1;
}
return uwsgi_stats_symbol(us, ']');
}
@@ -264,3 +276,208 @@ int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long l
if (ret) return -1;
return uwsgi_stats_comma(us);
}
void uwsgi_send_stats(int fd, struct uwsgi_stats * (*func)(void)) {
struct sockaddr_un client_src;
socklen_t client_src_len = 0;
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
if (client_fd < 0) {
uwsgi_error("accept()");
return;
}
if (uwsgi.stats_http) {
if (uwsgi_send_http_stats(client_fd)) {
close(client_fd);
return;
}
}
struct uwsgi_stats *us = func();
if (!us) goto end;
size_t remains = us->pos;
off_t pos = 0;
while (remains > 0) {
int ret = uwsgi_waitfd_write(client_fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) {
goto end0;
}
ssize_t res = write(client_fd, us->base + pos, remains);
if (res <= 0) {
if (res < 0) {
uwsgi_error("write()");
}
goto end0;
}
pos += res;
remains -= res;
}
end0:
free(us->base);
free(us);
end:
close(client_fd);
}
struct uwsgi_stats_pusher *uwsgi_stats_pusher_get(char *name) {
struct uwsgi_stats_pusher *usp = uwsgi.stats_pushers;
while(usp) {
if (!strcmp(usp->name, name)) {
return usp;
}
usp = usp->next;
}
return usp;
}
void uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
struct uwsgi_stats_pusher_instance *old_uspi = NULL, *uspi = uwsgi.stats_pusher_instances;
while(uspi) {
old_uspi = uspi;
uspi = uspi->next;
}
uspi = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_instance));
uspi->pusher = pusher;
uspi->arg = arg;
if (old_uspi) {
old_uspi->next = uspi;
}
else {
uwsgi.stats_pusher_instances = uspi;
}
}
void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
void *events = event_queue_alloc(1);
for(;;) {
int nevents = event_queue_wait_multi(ut->queue, 1, events, 1);
if (nevents > 0) {
int interesting_fd = event_queue_interesting_fd(events, 0);
char buf[4096];
ssize_t len = read(interesting_fd, buf, 4096);
if (len <= 0) {
uwsgi_log("[uwsgi-stats-pusher] goodbye...\n");
return;
}
uwsgi_log("[uwsgi-stats-pusher] message received from master: %.*s\n", (int) len, buf);
continue;
}
time_t now = uwsgi_now();
struct uwsgi_stats_pusher_instance *uspi = uwsgi.stats_pusher_instances;
struct uwsgi_stats *us = NULL;
while(uspi) {
int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq;
if ( (uspi->last_run + delta) <= now) {
if (!us) {
us = uwsgi_master_generate_stats();
if (!us) goto next;
}
uspi->pusher->func(uspi, us->base, us->pos);
uspi->last_run = now;
}
next:
uspi = uspi->next;
}
if (us) {
free(us->base);
free(us);
}
}
}
void uwsgi_stats_pusher_setup() {
struct uwsgi_string_list *usl = uwsgi.requested_stats_pushers;
while(usl) {
char *ssp = uwsgi_str(usl->value);
struct uwsgi_stats_pusher *pusher = NULL;
char *colon = strchr(ssp, ':');
if (colon) {
*colon = 0;
}
pusher = uwsgi_stats_pusher_get(ssp);
if (!pusher) {
uwsgi_log("unable to find \"%s\" stats_pusher\n", ssp);
exit(1);
}
char *arg = NULL;
if (colon) {
arg = colon+1;
*colon = ':';
}
uwsgi_stats_pusher_add(pusher, arg);
usl = usl->next;
}
}
void uwsgi_register_stats_pusher(char *name, void(*func) (struct uwsgi_stats_pusher_instance *, char *, size_t)) {
struct uwsgi_stats_pusher *pusher = uwsgi.stats_pushers, *old_pusher = NULL;
while(pusher) {
old_pusher = pusher;
pusher = pusher->next;
}
pusher = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher));
pusher->name = name;
pusher->func = func;
if (old_pusher) {
old_pusher->next = pusher;
}
else {
uwsgi.stats_pushers = pusher;
}
}
struct uwsgi_stats_pusher_file_conf {
char *path;
char *freq;
char *separator;
};
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, char *json, size_t json_len) {
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
if (!uspi->configured) {
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
if (uspi->arg) {
if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=',
"path", &uspic->path,
"separator", &uspic->separator,
"freq", &uspic->freq, NULL)) {
free(uspi);
return;
}
}
if (!uspic->path) uspic->path = "uwsgi.stats";
if (!uspic->separator) uspic->separator = "\n\n";
if (uspic->freq) uspi->freq = atoi(uspic->freq);
uspi->configured = 1;
uspi->data = uspic;
}
int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
uwsgi_error_open(uspic->path);
return;
}
ssize_t rlen = write(fd, json, json_len);
if (rlen != (ssize_t) json_len) {
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
}
rlen = write(fd, uspic->separator, strlen(uspic->separator));
if (rlen != (ssize_t ) strlen(uspic->separator)) {
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
}
close(fd);
}
+204 -186
View File
@@ -4,10 +4,9 @@
subscription subsystem
each subscription slot is as an auto-optmizing linked list. Originally it was a uwsgi_dict (now removed from uWSGI) but this
would have not be able to support regexp as keys.
each subscription slot is as an hashed item in a dictionary
each slot has another circular linked list containing the nodes names
each slot has a circular linked list containing the nodes names
the structure and system is very similar to uwsgi_dyn_dict already used by the mime type parser
@@ -21,7 +20,7 @@
extern struct uwsgi_server uwsgi;
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, int regexp) {
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
if (keylen > 0xff) return NULL;
@@ -42,43 +41,32 @@ struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slo
#endif
while(current_slot) {
#ifdef UWSGI_PCRE
if (regexp) {
if (uwsgi_regexp_match(current_slot->pattern, current_slot->pattern_extra, key, keylen) >= 0) {
return current_slot;
}
if (!uwsgi_strncmp(key, keylen, current_slot->key, current_slot->keylen)) {
// auto optimization
if (current_slot->prev) {
if (current_slot->hits > current_slot->prev->hits) {
struct uwsgi_subscribe_slot *slot_parent = current_slot->prev->prev, *slot_prev = current_slot->prev;
if (slot_parent) {
slot_parent->next = current_slot;
}
else {
slot[hash_key] = current_slot;
}
if (current_slot->next) {
current_slot->next->prev = slot_prev;
}
slot_prev->prev = current_slot;
slot_prev->next = current_slot->next;
current_slot->next = slot_prev;
current_slot->prev = slot_parent;
}
}
return current_slot;
}
else {
#endif
if (!uwsgi_strncmp(key, keylen, current_slot->key, current_slot->keylen)) {
// auto optimization
if (current_slot->prev) {
if (current_slot->hits > current_slot->prev->hits) {
struct uwsgi_subscribe_slot *slot_parent = current_slot->prev->prev, *slot_prev = current_slot->prev;
if (slot_parent) {
slot_parent->next = current_slot;
}
else {
slot[hash_key] = current_slot;
}
if (current_slot->next) {
current_slot->next->prev = slot_prev;
}
slot_prev->prev = current_slot;
slot_prev->next = current_slot->next;
current_slot->next = slot_prev;
current_slot->prev = slot_parent;
}
}
return current_slot;
}
#ifdef UWSGI_PCRE
}
#endif
current_slot = current_slot->next;
// check for loopy optimization
if (current_slot == slot[hash_key]) break;
@@ -87,80 +75,172 @@ struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slo
return NULL;
}
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, int regexp) {
// least reference count
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_lrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) {
// if node is NULL we are in the second step (in lrc mode we do not use the first step)
if (node) return NULL;
if (keylen > 0xff) return NULL;
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, key, keylen, regexp);
if (current_slot) {
// slot found, move up in the list increasing hits
current_slot->hits++;
time_t now = uwsgi_now();
struct uwsgi_subscribe_node *node = current_slot->nodes;
while(node) {
// is the node alive ?
if (now - node->last_check > uwsgi.subscription_tolerance) {
if (node->death_mark == 0)
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => marking %.*s as failed (no announce received in %d seconds)\n", (int) uwsgi.mypid, (int) keylen, key, (int) node->len, node->name, uwsgi.subscription_tolerance);
node->failcnt++;
node->death_mark = 1;
}
// is the node must be removed ?
if (node->death_mark && node->reference == 0) {
// remove the node and move to next
struct uwsgi_subscribe_node *dead_node = node;
node = node->next;
// if the slot has been removed, return NULL;
if (uwsgi_remove_subscribe_node(slot, dead_node) == 1) {
return NULL;
}
continue;
}
if (node->death_mark == 0 && node->wrr > 0) {
node->wrr--;
node->reference++;
return node;
}
node = node->next;
}
// no wrr > 0 node found, reset them
node = current_slot->nodes;
uint64_t min_weight = 0;
while(node) {
if (!node->death_mark) {
if (min_weight == 0 || node->weight < min_weight) min_weight = node->weight;
}
node = node->next;
}
// now set wrr
node = current_slot->nodes;
struct uwsgi_subscribe_node *choosen_node = NULL;
while(node) {
if (!node->death_mark) {
node->wrr = node->weight/min_weight;
struct uwsgi_subscribe_node *choosen_node = NULL;
node = current_slot->nodes;
uint64_t min_rc = 0;
while(node) {
if (!node->death_mark) {
if (min_rc == 0 || node->reference < min_rc) {
min_rc = node->reference;
choosen_node = node;
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->requests <= node->requests))
break;
}
node = node->next;
}
if (choosen_node) {
choosen_node->wrr--;
choosen_node->reference++;
}
return choosen_node;
node = node->next;
}
return NULL;
if (choosen_node) {
choosen_node->reference++;
}
return choosen_node;
}
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node_by_name(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, char *val, uint16_t vallen, int regexp) {
// weighted least reference count
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wlrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) {
// if node is NULL we are in the second step (in wlrc mode we do not use the first step)
if (node) return NULL;
struct uwsgi_subscribe_node *choosen_node = NULL;
node = current_slot->nodes;
double min_rc = 0;
while(node) {
if (!node->death_mark) {
// node->weight is always >= 1, we can safely use it as divider
double ref = (double) node->reference / (double) node->weight;
double next_node_ref = 0;
if (node->next)
next_node_ref = (double) node->next->reference / (double) node->next->weight;
if (min_rc == 0 || ref < min_rc) {
min_rc = ref;
choosen_node = node;
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->requests <= node->requests))
break;
}
}
node = node->next;
}
if (choosen_node) {
choosen_node->reference++;
}
return choosen_node;
}
// weighted round robin algo
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wrr(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) {
// if node is NULL we are in the second step
if (node) {
if (node->death_mark == 0 && node->wrr > 0) {
node->wrr--;
node->reference++;
return node;
}
return NULL;
}
// no wrr > 0 node found, reset them
node = current_slot->nodes;
uint64_t min_weight = 0;
while(node) {
if (!node->death_mark) {
if (min_weight == 0 || node->weight < min_weight) min_weight = node->weight;
}
node = node->next;
}
// now set wrr
node = current_slot->nodes;
struct uwsgi_subscribe_node *choosen_node = NULL;
while(node) {
if (!node->death_mark) {
node->wrr = node->weight/min_weight;
choosen_node = node;
}
node = node->next;
}
if (choosen_node) {
choosen_node->wrr--;
choosen_node->reference++;
}
return choosen_node;
}
void uwsgi_subscription_set_algo(char *algo) {
if (!algo) goto wrr;
if (!strcmp(algo,"wrr")) {
uwsgi.subscription_algo = uwsgi_subscription_algo_wrr;
return;
}
if (!strcmp(algo,"lrc")) {
uwsgi.subscription_algo = uwsgi_subscription_algo_lrc;
return;
}
if (!strcmp(algo,"wlrc")) {
uwsgi.subscription_algo = uwsgi_subscription_algo_wlrc;
return;
}
wrr:
uwsgi.subscription_algo = uwsgi_subscription_algo_wrr;
}
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
if (keylen > 0xff) return NULL;
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, key, keylen, regexp);
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, key, keylen);
if (!current_slot) return NULL;
// slot found, move up in the list increasing hits
current_slot->hits++;
time_t now = uwsgi_now();
struct uwsgi_subscribe_node *node = current_slot->nodes;
while(node) {
// is the node alive ?
if (now - node->last_check > uwsgi.subscription_tolerance) {
if (node->death_mark == 0)
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => marking %.*s as failed (no announce received in %d seconds)\n", (int) uwsgi.mypid, (int) keylen, key, (int) node->len, node->name, uwsgi.subscription_tolerance);
node->failcnt++;
node->death_mark = 1;
}
// do i need to remove the node ?
if (node->death_mark && node->reference == 0) {
// remove the node and move to next
struct uwsgi_subscribe_node *dead_node = node;
node = node->next;
// if the slot has been removed, return NULL;
if (uwsgi_remove_subscribe_node(slot, dead_node) == 1) {
return NULL;
}
continue;
}
struct uwsgi_subscribe_node *choosen_node = uwsgi.subscription_algo(current_slot, node);
if (choosen_node) return choosen_node;
node = node->next;
}
return uwsgi.subscription_algo(current_slot, node);
}
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node_by_name(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, char *val, uint16_t vallen) {
if (keylen > 0xff) return NULL;
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, key, keylen);
if (current_slot) {
struct uwsgi_subscribe_node *node = current_slot->nodes;
while(node) {
@@ -210,14 +290,6 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
// first check if i am the only node
if ((!prev_slot && !next_slot) || next_slot == node_slot) {
#ifdef UWSGI_PCRE
if (node_slot->pattern) {
pcre_free(node_slot->pattern);
}
if (node_slot->pattern_extra) {
pcre_free(node_slot->pattern_extra);
}
#endif
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
EVP_PKEY_free(node_slot->sign_public_key);
@@ -241,14 +313,6 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
next_slot->prev = prev_slot;
}
#ifdef UWSGI_PCRE
if (node_slot->pattern) {
pcre_free(node_slot->pattern);
}
if (node_slot->pattern_extra) {
pcre_free(node_slot->pattern_extra);
}
#endif
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
EVP_PKEY_free(node_slot->sign_public_key);
@@ -263,9 +327,9 @@ end:
return ret;
}
struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi_subscribe_req *usr, int regexp) {
struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi_subscribe_req *usr) {
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, usr->key, usr->keylen, 0), *old_slot = NULL, *a_slot;
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, usr->key, usr->keylen), *old_slot = NULL, *a_slot;
struct uwsgi_subscribe_node *node, *old_node = NULL;
if (usr->address_len > 0xff || usr->address_len == 0) return NULL;
@@ -386,17 +450,6 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->key[usr->keylen] = 0;
current_slot->hits = 0;
#ifdef UWSGI_PCRE
current_slot->pattern = NULL;
current_slot->pattern_extra = NULL;
if (regexp) {
if (uwsgi_regexp_build(current_slot->key, &current_slot->pattern, &current_slot->pattern_extra)) {
free(current_slot);
return NULL;
}
}
#endif
current_slot->nodes = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node));
current_slot->nodes->slot = current_slot;
current_slot->nodes->len = usr->address_len;
@@ -418,63 +471,20 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->nodes->next = NULL;
#ifdef UWSGI_PCRE
// if key is a regexp, order it by keylen
if (regexp) {
old_slot = NULL;
a_slot = slot[hash_key];
while(a_slot) {
if (a_slot->keylen > current_slot->keylen) {
old_slot = a_slot;
break;
}
a_slot = a_slot->next;
}
if (old_slot) {
current_slot->prev = old_slot->prev;
old_slot->prev = current_slot;
if (current_slot->prev) {
old_slot->prev->next = current_slot;
}
current_slot->next = old_slot;
}
else {
a_slot = slot[hash_key];
while(a_slot) {
old_slot = a_slot;
a_slot = a_slot->next;
}
if (old_slot) {
old_slot->next = current_slot;
}
current_slot->prev = old_slot;
current_slot->next = NULL;
}
a_slot = slot[hash_key];
while(a_slot) {
old_slot = a_slot;
a_slot = a_slot->next;
}
else {
#endif
a_slot = slot[hash_key];
while(a_slot) {
old_slot = a_slot;
a_slot = a_slot->next;
}
if (old_slot) {
old_slot->next = current_slot;
}
current_slot->prev = old_slot;
current_slot->next = NULL;
#ifdef UWSGI_PCRE
if (old_slot) {
old_slot->next = current_slot;
}
#endif
current_slot->prev = old_slot;
current_slot->next = NULL;
if (!slot[hash_key] || current_slot->prev == NULL) {
slot[hash_key] = current_slot;
@@ -488,6 +498,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
}
// TODO rewrite it using uwsgi buffers
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign) {
char value_cores[sizeof(UMAX64_STR)+1];
@@ -721,3 +732,10 @@ int uwsgi_no_subscriptions(struct uwsgi_subscribe_slot **slot) {
}
return 1;
}
struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
if (!uwsgi.subscription_algo) {
uwsgi_subscription_set_algo(NULL);
}
return uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16);
}
+427 -145
View File
@@ -840,6 +840,26 @@ void uwsgi_linux_ksm_map(void) {
#endif
#endif
#ifdef __linux__
long uwsgi_num_from_file(char *filename) {
char buf[16];
ssize_t len;
int fd = open(filename, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(filename);
return -1L;
}
len = read(fd, buf, sizeof(buf));
if (len == 0) {
uwsgi_log("read error %s\n", filename);
close(fd);
return -1L;
}
close(fd);
return strtol(buf, (char **)NULL, 10);
}
#endif
// setup for a new request
void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id, struct uwsgi_socket *uwsgi_sock) {
@@ -848,9 +868,7 @@ void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id, struct uwsgi_so
wsgi_req->app_id = uwsgi.default_app;
wsgi_req->async_id = async_id;
#ifdef UWSGI_SENDFILE
wsgi_req->sendfile_fd = -1;
#endif
wsgi_req->hvec = uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].hvec;
wsgi_req->buffer = uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].buffer;
@@ -1112,6 +1130,7 @@ void sanitize_args() {
uwsgi.ignore_write_errors = 1;
}
if (uwsgi.cheaper_count > 0 && uwsgi.cheaper_count >= uwsgi.numproc) {
uwsgi_log("invalid cheaper value: must be lower than processes\n");
exit(1);
@@ -1192,7 +1211,7 @@ char *uwsgi_str_contains(char *str, int slen, char what) {
}
// fast compare 2 sized strings
inline int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
if (slen != dlen)
return 1;
@@ -1202,7 +1221,7 @@ inline int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
}
// fast sized check of initial part of a string
inline int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
if (slen < dlen)
return -1;
@@ -1211,7 +1230,7 @@ inline int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
}
// unsized check
inline int uwsgi_startswith(char *src, char *what, int wlen) {
int uwsgi_startswith(char *src, char *what, int wlen) {
int i;
@@ -1473,7 +1492,7 @@ int uwsgi_get_app_id(char *app_name, int app_name_len, int modifier1) {
}
if (found) {
if (uwsgi_apps[i].touch_reload) {
if (uwsgi_apps[i].touch_reload[0]) {
if (!stat(uwsgi_apps[i].touch_reload, &st)) {
if (st.st_mtime != uwsgi_apps[i].touch_reload_mtime) {
// serve the new request and reload
@@ -2148,18 +2167,20 @@ int uwsgi_waitfd_event(int fd, int timeout, int event) {
return ret;
}
inline void *uwsgi_malloc(size_t size) {
void *uwsgi_malloc(size_t size) {
char *ptr = malloc(size);
if (ptr == NULL) {
uwsgi_error("malloc()");
uwsgi_log("!!! tried memory allocation of %llu bytes !!!\n", (unsigned long long) size);
uwsgi_backtrace(uwsgi.backtrace_depth);
exit(1);
}
return ptr;
}
inline void *uwsgi_calloc(size_t size) {
void *uwsgi_calloc(size_t size) {
char *ptr = uwsgi_malloc(size);
memset(ptr, 0, size);
@@ -2530,6 +2551,18 @@ char *uwsgi_open_and_read(char *url, int *size, int add_zero, char *magic_table[
memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr);
}
#ifdef UWSGI_ELF
else if (!strncmp("section://", url, 10)) {
size_t s_len = 0;
buffer = uwsgi_elf_section(uwsgi.binary_path, url+10, &s_len);
if (!buffer) {
uwsgi_log("unable to find section %s in %s\n", url+10, uwsgi.binary_path);
exit(1);
}
*size = s_len;
if (add_zero) *size += 1;
}
#endif
// fallback to file
else {
fd = open(url, O_RDONLY);
@@ -2642,105 +2675,6 @@ char *uwsgi_get_last_char(char *what, char c) {
return ptr;
}
void spawn_daemon(struct uwsgi_daemon *ud) {
char *argv[64];
char *a;
int cnt = 1;
int devnull = -1;
int throttle = 0;
if (uwsgi.current_time - ud->last_spawn <= 3) {
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
}
pid_t pid = uwsgi_fork("uWSGI external daemon");
if (pid < 0) {
uwsgi_error("fork()");
return;
}
if (pid > 0) {
ud->pid = pid;
ud->status = 1;
if (ud->respawns == 0) {
ud->born = uwsgi_now();
}
ud->respawns++;
ud->last_spawn = uwsgi_now();
}
else {
// close uwsgi sockets
uwsgi_close_all_sockets();
// /dev/null will became stdin
devnull = open("/dev/null", O_RDONLY);
if (devnull < 0) {
uwsgi_error("/dev/null open()");
exit(1);
}
if (devnull != 0) {
if (dup2(devnull, 0)) {
uwsgi_error("dup2()");
exit(1);
}
close(devnull);
}
if (setsid() < 0) {
uwsgi_error("setsid()");
exit(1);
}
#ifdef __linux__
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
uwsgi_error("prctl()");
}
#endif
// free the old area
if (ud->tmp_command)
free(ud->tmp_command);
ud->tmp_command = uwsgi_str(ud->command);
a = strtok(ud->tmp_command, " ");
if (a) {
argv[0] = a;
while (a != NULL) {
a = strtok(NULL, " ");
if (a) {
argv[cnt] = a;
cnt++;
}
}
}
else {
argv[0] = ud->tmp_command;
}
argv[cnt] = NULL;
if (throttle) {
uwsgi_log("[uwsgi-daemons] throttling \"%s\" (%s) for %d seconds\n", ud->command, argv[0], throttle);
sleep(throttle);
}
uwsgi_log("[uwsgi-daemons] spawning \"%s\" (%s)\n", ud->command, argv[0]);
if (execvp(argv[0], argv)) {
uwsgi_error("execvp()");
}
uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\" (%s)\n", ud->command, argv[0]);
// never here;
exit(1);
}
return;
}
char *uwsgi_num2str(int num) {
char *str = uwsgi_malloc(11);
@@ -3049,39 +2983,6 @@ char *uwsgi_netstring(char *buf, size_t len, char **netstring, size_t * netstrin
return NULL;
}
struct uwsgi_daemon *uwsgi_daemon_new(struct uwsgi_daemon **ud, char *command) {
struct uwsgi_daemon *uwsgi_ud = *ud, *old_ud;
if (!uwsgi_ud) {
*ud = uwsgi_malloc(sizeof(struct uwsgi_daemon));
uwsgi_ud = *ud;
}
else {
while (uwsgi_ud) {
old_ud = uwsgi_ud;
uwsgi_ud = uwsgi_ud->next;
}
uwsgi_ud = uwsgi_malloc(sizeof(struct uwsgi_daemon));
old_ud->next = uwsgi_ud;
}
uwsgi_ud->command = command;
uwsgi_ud->tmp_command = NULL;
uwsgi_ud->pid = 0;
uwsgi_ud->status = 0;
uwsgi_ud->registered = 0;
uwsgi_ud->next = NULL;
uwsgi_ud->respawns = 0;
uwsgi_ud->last_spawn = 0;
uwsgi.daemons_cnt++;
return uwsgi_ud;
}
struct uwsgi_dyn_dict *uwsgi_dyn_dict_new(struct uwsgi_dyn_dict **dd, char *key, int keylen, char *val, int vallen) {
struct uwsgi_dyn_dict *uwsgi_dd = *dd, *old_dd;
@@ -3133,7 +3034,8 @@ void *uwsgi_malloc_shared(size_t size) {
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (addr == NULL) {
if (addr == MAP_FAILED) {
uwsgi_log("unable to allocate %llu bytes (%lluMB)\n", (unsigned long long )size, (unsigned long long) (size/(1024*1024)));
uwsgi_error("mmap()");
exit(1);
}
@@ -3177,6 +3079,40 @@ struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **list,
return uwsgi_string;
}
#ifdef UWSGI_PCRE
struct uwsgi_regexp_list *uwsgi_regexp_custom_new_list(struct uwsgi_regexp_list **list, char *value, char *custom) {
struct uwsgi_regexp_list *url = *list, *old_url;
if (!url) {
*list = uwsgi_malloc(sizeof(struct uwsgi_regexp_list));
url = *list;
}
else {
while (url) {
old_url = url;
url = url->next;
}
url = uwsgi_malloc(sizeof(struct uwsgi_regexp_list));
old_url->next = url;
}
if (uwsgi_regexp_build(value, &url->pattern, &url->pattern_extra)) {
exit(1);
}
url->next = NULL;
url->custom = 0;
url->custom_ptr = NULL;
url->custom_str = custom;
return url;
}
#endif
char *uwsgi_string_get_list(struct uwsgi_string_list **list, int pos, size_t * len) {
struct uwsgi_string_list *uwsgi_string = *list;
@@ -3851,6 +3787,7 @@ void uwsgi_apply_config_pass(char symbol, char *(*hook) (char *)) {
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
int has_symbol = 0;
int depth = 0;
char *magic_key = NULL;
char *magic_val = NULL;
if (uwsgi.exported_opts[i]->value && !uwsgi.exported_opts[i]->configured) {
@@ -3860,10 +3797,20 @@ void uwsgi_apply_config_pass(char symbol, char *(*hook) (char *)) {
}
else if (uwsgi.exported_opts[i]->value[j] == '(' && has_symbol == 1) {
has_symbol = 2;
depth = 0;
magic_key = uwsgi.exported_opts[i]->value + j + 1;
}
else if (has_symbol > 1) {
if (uwsgi.exported_opts[i]->value[j] == ')') {
if (uwsgi.exported_opts[i]->value[j] == '(') {
has_symbol++;
depth++;
}
else if (uwsgi.exported_opts[i]->value[j] == ')') {
if (depth > 0) {
has_symbol++;
depth--;
continue;
}
if (has_symbol <= 2) {
magic_key = NULL;
has_symbol = 0;
@@ -3933,7 +3880,7 @@ void uwsgi_set_processname(char *name) {
// end with \0
memset(uwsgi.orig_argv[0] + amount + 1 + (uwsgi.max_procname - (amount)), '\0', 1);
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__) || defined(__NetBSD__)
if (uwsgi.procname_prefix) {
if (!uwsgi.procname_append) {
setproctitle("-%s%s", uwsgi.procname_prefix, name);
@@ -4341,7 +4288,7 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
if (SSL_CTX_use_certificate_file(ctx, crt, SSL_FILETYPE_PEM) <= 0) {
if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
uwsgi_log("unable to assign ssl certificate %s\n", crt);
exit(1);
}
@@ -4602,7 +4549,7 @@ timeout:
ssize_t uwsgi_pipe_sized(int src, int dst, size_t required, int timeout) {
char buf[8192];
size_t written = -1;
size_t written = 0;
ssize_t len;
while(written < required) {
@@ -4706,3 +4653,338 @@ void uwsgi_set_cpu_affinity() {
}
}
#ifdef UWSGI_ELF
#if defined(__linux__)
#include <elf.h>
#endif
char *uwsgi_elf_section(char *filename, char *s, size_t *len) {
struct stat st;
char *output = NULL;
int fd = open(filename, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(filename);
return NULL;
}
if (fstat(fd, &st)) {
uwsgi_error("stat()");
close(fd);
return NULL;
}
if (st.st_size < EI_NIDENT) {
uwsgi_log("invalid elf file: %s\n", filename);
close(fd);
return NULL;
}
char *addr = mmap(NULL, st.st_size , PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED) {
uwsgi_error("mmap()");
close(fd);
return NULL;
}
if (addr[0] != ELFMAG0) goto clear;
if (addr[1] != ELFMAG1) goto clear;
if (addr[2] != ELFMAG2) goto clear;
if (addr[3] != ELFMAG3) goto clear;
if (addr[4] == ELFCLASS32) {
// elf header
Elf32_Ehdr *elfh = (Elf32_Ehdr *) addr;
// first section
Elf32_Shdr *sections = ((Elf32_Shdr *) (addr + elfh->e_shoff));
// number of sections
int ns = elfh->e_shnum;
// the names table
Elf32_Shdr *table = &sections[elfh->e_shstrndx];
// string table session pointer
char *names = addr + table->sh_offset;
Elf32_Shdr *ss = NULL; int i;
for(i=0;i<ns;i++) {
char *name = names + sections[i].sh_name;
if (!strcmp(name, s)) {
ss = &sections[i];
break;
}
}
if (ss) {
*len = ss->sh_size;
output = uwsgi_concat2n(addr + ss->sh_offset, ss->sh_size, "", 0);
}
}
else if (addr[4] == ELFCLASS64) {
// elf header
Elf64_Ehdr *elfh = (Elf64_Ehdr *) addr;
// first section
Elf64_Shdr *sections = ((Elf64_Shdr *) (addr + elfh->e_shoff));
// number of sections
int ns = elfh->e_shnum;
// the names table
Elf64_Shdr *table = &sections[elfh->e_shstrndx];
// string table session pointer
char *names = addr + table->sh_offset;
Elf64_Shdr *ss = NULL; int i;
for(i=0;i<ns;i++) {
char *name = names + sections[i].sh_name;
if (!strcmp(name, s)) {
ss = &sections[i];
break;
}
}
if (ss) {
*len = ss->sh_size;
output = uwsgi_concat2n(addr + ss->sh_offset, ss->sh_size, "", 0);
}
}
clear:
close(fd);
munmap(addr, st.st_size);
return output;
}
#endif
static void *uwsgi_thread_run(void *arg) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) arg;
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
ut->queue = event_queue_init();
event_queue_add_fd_read(ut->queue, ut->pipe[1]);
ut->func(ut);
return NULL;
}
struct uwsgi_thread *uwsgi_thread_new(void (*func)(struct uwsgi_thread *)) {
struct uwsgi_thread *ut = uwsgi_malloc(sizeof(struct uwsgi_thread));
#if defined(SOCK_SEQPACKET) && defined(__linux__)
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ut->pipe)) {
#else
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ut->pipe)) {
#endif
free(ut);
return NULL;
}
uwsgi_socket_nb(ut->pipe[0]);
uwsgi_socket_nb(ut->pipe[1]);
ut->func = func;
pthread_attr_init(&ut->tattr);
pthread_attr_setdetachstate(&ut->tattr, PTHREAD_CREATE_DETACHED);
// 512K should be enough...
pthread_attr_setstacksize(&ut->tattr, 512 * 1024);
if (pthread_create(&ut->tid, &ut->tattr, uwsgi_thread_run, ut)) {
uwsgi_error("pthread_create()");
goto error;
}
return ut;
error:
close(ut->pipe[0]);
close(ut->pipe[1]);
free(ut);
return NULL;
}
// evaluate a math expression
#ifdef UWSGI_MATHEVAL
double uwsgi_matheval(char *expr) {
#ifdef UWSGI_DEBUG
uwsgi_log("matheval expr = %s\n", expr);
#endif
double ret = 0.0;
void *e = evaluator_create(expr);
if (!e) return ret;
ret = evaluator_evaluate(e, 0, NULL, NULL);
evaluator_destroy(e);
return ret;
}
char *uwsgi_matheval_str(char *expr) {
double ret = uwsgi_matheval(expr);
return uwsgi_num2str((int) ret);
}
#endif
int uwsgi_kvlist_parse(char *src, size_t len, char list_separator, char kv_separator, ...) {
size_t i;
va_list ap;
struct uwsgi_string_list *itemlist = NULL;
char *buf = uwsgi_calloc(len + 1);
// ok let's start splitting the string
int escaped = 0;
char *base = buf;
char *ptr = buf;
for(i=0;i<len;i++) {
if (src[i] == list_separator && !escaped) {
*ptr++= 0;
uwsgi_string_new_list(&itemlist, base);
base = ptr;
}
else if (src[i] == '\\' && !escaped) {
escaped = 1;
}
else if (escaped) {
escaped = 0;
}
else {
*ptr++= src[i];
}
}
if (ptr > base) {
uwsgi_string_new_list(&itemlist, base);
}
struct uwsgi_string_list *usl = itemlist;
while(usl) {
len = strlen(usl->value);
char *item_buf = uwsgi_calloc(len + 1);
base = item_buf;
ptr = item_buf;
escaped = 0;
for(i=0;i<len;i++) {
if (usl->value[i] == kv_separator && !escaped) {
*ptr++= 0;
va_start(ap, kv_separator);
for(;;) {
char *p = va_arg(ap, char *);
if (!p) break;
char **pp = va_arg(ap, char **);
if (!pp) break;
if (!strcmp(p, base)) {
*pp = uwsgi_str(usl->value+i+1);
}
}
va_end(ap);
base = ptr;
break;
}
else if (usl->value[i] == '\\' && !escaped) {
escaped = 1;
}
else if (escaped) {
escaped = 0;
}
else {
*ptr++= usl->value[i];
}
}
free(item_buf);
usl = usl->next;
}
free(buf);
return 0;
}
int uwsgi_send_http_stats(int fd) {
char buf[4096];
int ret = uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) return -1;
if (read(fd, buf, 4096) <= 0) return -1;
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (!ub) return -1;
if (uwsgi_buffer_append(ub, "HTTP/1.0 200 OK\r\n", 17)) goto error;
if (uwsgi_buffer_append(ub, "Connection: close\r\n", 19)) goto error;
if (uwsgi_buffer_append(ub, "Content-Type: application/json\r\n", 32)) goto error;
if (uwsgi_buffer_append(ub, "\r\n", 2)) goto error;
if (uwsgi_buffer_send(ub, fd)) goto error;
uwsgi_buffer_destroy(ub);
return 0;
error:
uwsgi_buffer_destroy(ub);
return -1;
}
void uwsgi_simple_set_status(struct wsgi_request *wsgi_req, int status) {
wsgi_req->status = status;
}
void uwsgi_simple_inc_headers(struct wsgi_request *wsgi_req) {
wsgi_req->header_cnt++;
}
void uwsgi_simple_response_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, buf, len);
}
void uwsgi_simple_response_write_header(struct wsgi_request *wsgi_req, char *buf, size_t len) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, buf, len);
}
ssize_t uwsgi_simple_request_read(struct wsgi_request *wsgi_req, char *buf, size_t len) {
if (wsgi_req->post_cl == 0) return 0;
if ((size_t)wsgi_req->post_pos >= wsgi_req->post_cl) return 0;
size_t remains = wsgi_req->post_cl - wsgi_req->post_pos;
remains = UMIN(len, remains);
int fd = -1;
if (wsgi_req->body_as_file) {
fd = fileno((FILE *)wsgi_req->async_post);
}
else if (uwsgi.post_buffering > 0) {
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
fd = fileno((FILE *)wsgi_req->async_post);
}
}
else {
fd = wsgi_req->poll.fd;
}
// data in memory ?
if (fd == -1) {
memcpy(buf, wsgi_req->post_buffering_buf + wsgi_req->post_buffering_read, remains);
wsgi_req->post_buffering_read+=remains;
wsgi_req->post_pos += remains;
return remains;
}
if (uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
uwsgi_log("error waiting for request body");
return -1;
}
ssize_t rlen = read(fd, buf, remains);
if (rlen < 0) {
uwsgi_error("error reading request body:");
return -1;
}
wsgi_req->post_pos += rlen;
return rlen;
}
int uwsgi_plugin_modifier1(char *plugin) {
int ret = -1;
char *symbol_name = uwsgi_concat2(plugin, "_plugin");
struct uwsgi_plugin *up = dlsym(RTLD_DEFAULT, symbol_name);
if (!up) goto end;
ret = up->modifier1;
end:
free(symbol_name);
return ret;
}
+245 -133
View File
@@ -95,6 +95,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"disable-write-exception", no_argument, 0, "disable exception generation on write()/writev()", uwsgi_opt_true, &uwsgi.disable_write_exception, 0},
{"inherit", required_argument, 0, "use the specified file as config template", uwsgi_opt_load, NULL, 0},
{"include", required_argument, 0, "include the specified file as immediate configuration", uwsgi_opt_load, NULL, UWSGI_OPT_IMMEDIATE},
{"daemonize", required_argument, 'd', "daemonize uWSGI", uwsgi_opt_set_str, &uwsgi.daemonize, 0},
{"daemonize2", required_argument, 0, "daemonize uWSGI after app loading", uwsgi_opt_set_str, &uwsgi.daemonize2, 0},
{"stop", required_argument, 0, "stop an instance", uwsgi_opt_pidfile_signal, (void *) SIGINT, UWSGI_OPT_IMMEDIATE},
@@ -263,6 +264,10 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"command-mode", no_argument, 0, "force command mode", uwsgi_opt_true, &uwsgi.command_mode, UWSGI_OPT_IMMEDIATE},
{"no-defer-accept", no_argument, 0, "disable deferred-accept on sockets", uwsgi_opt_true, &uwsgi.no_defer_accept, 0},
{"so-keepalive", no_argument, 0, "enable TCP KEEPALIVEs", uwsgi_opt_true, &uwsgi.so_keepalive, 0},
{"so-send-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
{"socket-send-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
{"so-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
{"socket-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0},
{"limit-as", required_argument, 0, "limit processes address space/vsz", uwsgi_opt_set_megabytes, &uwsgi.rl.rlim_max, 0},
{"limit-nproc", required_argument, 0, "limit the number of spawnable processes", uwsgi_opt_set_int, &uwsgi.rl_nproc.rlim_max, 0},
{"reload-on-as", required_argument, 0, "reload if address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_as, UWSGI_OPT_MEMORY},
@@ -300,8 +305,15 @@ static struct uwsgi_option uwsgi_base_options[] = {
#endif
{"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
{"stats-server", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
{"stats-http", no_argument, 0, "prefix stats server json output with http headers", uwsgi_opt_true, &uwsgi.stats_http, UWSGI_OPT_MASTER},
{"stats-minified", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
{"stats-min", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER},
{"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
{"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
#ifdef UWSGI_MULTICAST
{"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER},
{"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0},
{"cluster", required_argument, 0, "join specified uWSGI cluster", uwsgi_opt_set_str, &uwsgi.cluster, UWSGI_OPT_MASTER},
{"cluster-nodes", required_argument, 0, "get nodes list from the specified cluster", uwsgi_opt_true, &uwsgi.cluster_nodes, UWSGI_OPT_MASTER | UWSGI_OPT_CLUSTER},
{"cluster-reload", required_argument, 0, "send a reload message to the cluster", uwsgi_opt_cluster_reload, NULL, UWSGI_OPT_IMMEDIATE},
@@ -311,6 +323,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER},
{"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER},
#endif
{"subscription-algo", required_argument, 0, "set load balancing algorithm for the subscription system", uwsgi_opt_ssa, NULL, 0},
{"subscription-dotsplit", no_argument, 0, "try to fallback to the next part (dot based) in subscription key", uwsgi_opt_true, &uwsgi.subscription_dotsplit, 0},
{"subscribe-to", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
{"st", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
{"subscribe", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
@@ -349,6 +363,18 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"logger-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0},
{"loggers-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0},
{"threaded-logger", no_argument, 0, "offload log writing to a thread", uwsgi_opt_true, &uwsgi.threaded_logger, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
#ifdef UWSGI_PCRE
{"log-drain", required_argument, 0, "drain (do not show) log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_drain_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"log-filter", required_argument, 0, "show only log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_filter_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"log-route", required_argument, 0, "log to the specified named logger if regexp applied on logline matches", uwsgi_opt_add_regexp_custom_list, &uwsgi.log_route, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
#endif
#ifdef UWSGI_ALARM
{"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"alarm-freq", required_argument, 0, "tune the anti-loop alam system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
{"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"alarm-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
{"alarms-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
#endif
#ifdef UWSGI_ZEROMQ
{"log-zeromq", required_argument, 0, "send logs to a zeromq server", uwsgi_opt_set_logger, "zeromq", UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
#endif
@@ -470,6 +496,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"loops-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
{"worker-exec", required_argument, 0, "run the specified command as worker", uwsgi_opt_set_str, &uwsgi.worker_exec, 0},
{"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugins-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE},
@@ -477,6 +505,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"plugins-list", no_argument, 0, "list enabled plugins", uwsgi_opt_true, &uwsgi.plugins_list, 0},
{"plugin-list", no_argument, 0, "list enabled plugins", uwsgi_opt_true, &uwsgi.plugins_list, 0},
{"autoload", no_argument, 0, "try to automatically load plugins when unknown options are found", uwsgi_opt_true, &uwsgi.autoload, UWSGI_OPT_IMMEDIATE},
{"dlopen", required_argument, 0, "blindly load a shared library", uwsgi_opt_load_dl, NULL, UWSGI_OPT_IMMEDIATE},
{"allowed-modifiers", required_argument, 0, "comma separated list of allowed modifiers", uwsgi_opt_set_str, &uwsgi.allowed_modifiers, 0},
{"remap-modifier", required_argument, 0, "remap request modifier from one id to another", uwsgi_opt_set_str, &uwsgi.remap_modifier, 0},
@@ -641,14 +670,22 @@ void config_magic_table_fill(char *filename, char **magic_table) {
char *tmp = NULL;
magic_table['o'] = filename;
if (filename[0] == '/') {
magic_table['p'] = filename;
char *fullname = uwsgi_expand_path(filename, strlen(filename), NULL);
if (!fullname) {
fullname = filename;
}
// free unused memory
else {
magic_table['p'] = uwsgi_concat3(uwsgi.cwd, "/", filename);
char *minimal_name = uwsgi_malloc(strlen(fullname) + 1);
memcpy(minimal_name, fullname, strlen(fullname));
minimal_name[strlen(fullname)] = 0;
free(fullname);
fullname = minimal_name;
}
magic_table['s'] = uwsgi_get_last_char(magic_table['p'], '/') + 1;
magic_table['o'] = filename;
magic_table['p'] = fullname;
magic_table['s'] = uwsgi_get_last_char(fullname, '/') + 1;
magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s'] - magic_table['p'], "", 0);
if (magic_table['d'][strlen(magic_table['d']) - 1] == '/') {
tmp = magic_table['d'] + (strlen(magic_table['d']) - 1);
@@ -657,8 +694,21 @@ void config_magic_table_fill(char *filename, char **magic_table) {
#endif
*tmp = 0;
}
if (uwsgi_get_last_char(magic_table['d'], '/'))
magic_table['c'] = uwsgi_get_last_char(magic_table['d'], '/') + 1;
if (uwsgi_get_last_char(magic_table['d'], '/')) {
magic_table['c'] = uwsgi_str(uwsgi_get_last_char(magic_table['d'], '/') + 1);
if (magic_table['c'][strlen(magic_table['c']) - 1] == '/') {
magic_table['c'][strlen(magic_table['c']) - 1] = 0;
}
}
int base = '0';
char *to_split = uwsgi_str(magic_table['d']);
char *p = strtok(to_split,"/");
while(p && base <= '9') {
magic_table[base] = p;
base++;
p = strtok(NULL, "/");
}
if (tmp)
*tmp = '/';
@@ -801,6 +851,16 @@ void kill_them_all(int signum) {
if (uwsgi.to_hell == 1)
return;
// count the number of active workers
int active_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
active_workers++;
}
}
uwsgi.marked_workers = active_workers;
uwsgi.to_hell = 1;
if (uwsgi.reload_mercy > 0) {
@@ -837,12 +897,7 @@ void kill_them_all(int signum) {
}
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid > 0)
kill(-ud->pid, SIGKILL);
ud = ud->next;
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0)
@@ -863,6 +918,15 @@ void grace_them_all(int signum) {
if (uwsgi.to_heaven == 1 || uwsgi.to_outworld == 1 || uwsgi.lazy_respawned > 0)
return;
// count the number of active workers
int active_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
active_workers++;
}
}
uwsgi.marked_workers = active_workers;
if (!uwsgi.lazy)
uwsgi.to_heaven = 1;
else
@@ -886,12 +950,7 @@ void grace_them_all(int signum) {
uwsgi_log("killing the emperor with pid %d\n", uwsgi.emperor_pid);
}
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid > 0)
kill(-ud->pid, SIGKILL);
ud = ud->next;
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0)
@@ -972,17 +1031,21 @@ void reap_them_all(int signum) {
if (uwsgi.to_outworld == 1 || uwsgi.lazy_respawned > 0)
return;
// count the number of active workers
int active_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
active_workers++;
}
}
uwsgi.marked_workers = active_workers;
if (!uwsgi.lazy)
uwsgi.to_heaven = 1;
else
uwsgi.to_outworld = 1;
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid > 0)
kill(-ud->pid, SIGKILL);
ud = ud->next;
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0)
@@ -1200,7 +1263,7 @@ static void vacuum(void) {
}
}
while (uwsgi_sock) {
if (uwsgi_sock->family == AF_UNIX) {
if (uwsgi_sock->family == AF_UNIX && uwsgi_sock->name[0] != '@') {
if (unlink(uwsgi_sock->name)) {
uwsgi_error("unlink()");
}
@@ -1484,10 +1547,11 @@ static void router_list(void) {
#endif
static void loop_list(void) {
int i;
struct uwsgi_loop *loop = uwsgi.loops;
uwsgi_log("\n*** uWSGI loaded loop engines ***\n");
for(i=0;i<uwsgi.loops_cnt;i++) {
uwsgi_log("%s\n", uwsgi.loops[i].name);
while(loop) {
uwsgi_log("%s\n", loop->name);
loop = loop->next;
}
uwsgi_log("--- end of loop engines list ---\n\n");
}
@@ -1512,6 +1576,18 @@ static void clocks_list(void) {
uwsgi_log("--- end of clocks list ---\n\n");
}
#ifdef UWSGI_ALARM
static void alarms_list(void) {
struct uwsgi_alarm *alarms = uwsgi.alarms;
uwsgi_log("\n*** uWSGI loaded alarms ***\n");
while(alarms) {
uwsgi_log("%s\n", alarms->name);
alarms = alarms->next;
}
uwsgi_log("--- end of alarms list ---\n\n");
}
#endif
static time_t uwsgi_unix_seconds() {
return time(NULL);
}
@@ -1519,7 +1595,7 @@ static time_t uwsgi_unix_seconds() {
static uint64_t uwsgi_unix_microseconds() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000000) + tv.tv_usec;
return ((uint64_t)tv.tv_sec * 1000000) + tv.tv_usec;
}
static struct uwsgi_clock uwsgi_unix_clock = {
@@ -1689,6 +1765,11 @@ int main(int argc, char *argv[], char *envp[]) {
// last pass: REFERENCEs
uwsgi_apply_config_pass('%', uwsgi_get_exported_opt);
#ifdef UWSGI_MATHEVAL
// optional pass: MATH
uwsgi_apply_config_pass('=', uwsgi_matheval_str);
#endif
// ok, the options dictionary is available, lets manage it
uwsgi_configure();
@@ -1726,6 +1807,17 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_register_imperial_monitor("dir", uwsgi_imperial_monitor_directory_init, uwsgi_imperial_monitor_directory);
uwsgi_register_imperial_monitor("glob", uwsgi_imperial_monitor_glob_init, uwsgi_imperial_monitor_glob);
// setup stats pushers
uwsgi_register_stats_pusher("file", uwsgi_stats_pusher_file);
uwsgi_stats_pusher_setup();
#ifdef UWSGI_ALARM
// register embedded alarms
uwsgi_register_embedded_alarms();
#endif
/* uWSGI IS CONFIGURED !!! */
if (uwsgi.dump_options) {
@@ -1765,6 +1857,11 @@ int main(int argc, char *argv[], char *envp[]) {
if (uwsgi.clock_list)
clocks_list();
#ifdef UWSGI_ALARM
if (uwsgi.alarms_list)
alarms_list();
#endif
// set the clock
if (uwsgi.requested_clock)
uwsgi_set_clock(uwsgi.requested_clock);
@@ -1933,17 +2030,27 @@ int uwsgi_start(void *v_argv) {
#ifdef RLIMIT_NPROC
if (uwsgi.rl_nproc.rlim_max > 0) {
uwsgi.rl_nproc.rlim_cur = uwsgi.rl_nproc.rlim_max;
uwsgi_log("limiting number of processes to %d...\n", (int) uwsgi.rl_nproc.rlim_max);
uwsgi_log_initial("limiting number of processes to %d...\n", (int) uwsgi.rl_nproc.rlim_max);
if (setrlimit(RLIMIT_NPROC, &uwsgi.rl_nproc)) {
uwsgi_error("setrlimit()");
}
}
if (!getrlimit(RLIMIT_NPROC, &uwsgi.rl_nproc)) {
if (uwsgi.rl_nproc.rlim_cur != RLIM_INFINITY) {
uwsgi_log_initial("your processes number limit is %d\n", (int) uwsgi.rl_nproc.rlim_cur);
if ((int)uwsgi.rl_nproc.rlim_cur < uwsgi.numproc+uwsgi.master_process) {
uwsgi.numproc = uwsgi.rl_nproc.rlim_cur - 1;
uwsgi_log_initial("!!! number of workers adjusted to %d due to system limits !!!\n", uwsgi.numproc);
}
}
}
#endif
#ifndef __OpenBSD__
if (uwsgi.rl.rlim_max > 0) {
uwsgi.rl.rlim_cur = uwsgi.rl.rlim_max;
uwsgi_log("limiting address space of processes...\n");
uwsgi_log_initial("limiting address space of processes...\n");
if (setrlimit(RLIMIT_AS, &uwsgi.rl)) {
uwsgi_error("setrlimit()");
}
@@ -1959,7 +2066,7 @@ int uwsgi_start(void *v_argv) {
}
else {
uwsgi_log("scheduler priority set to %d\n", uwsgi.prio);
uwsgi_log_initial("scheduler priority set to %d\n", uwsgi.prio);
}
}
if (!getrlimit(RLIMIT_AS, &uwsgi.rl)) {
@@ -1970,7 +2077,6 @@ int uwsgi_start(void *v_argv) {
}
#endif
uwsgi_log_initial("your memory page size is %d bytes\n", uwsgi.page_size);
if (uwsgi.buffer_size > 65536) {
@@ -2005,43 +2111,6 @@ int uwsgi_start(void *v_argv) {
}
}
// prepare offload threads
if (uwsgi.static_offload_to_thread) {
pthread_attr_init(&uwsgi.static_offload_thread_attr);
pthread_attr_setdetachstate(&uwsgi.static_offload_thread_attr, PTHREAD_CREATE_DETACHED);
// 512K should be enough...
pthread_attr_setstacksize(&uwsgi.static_offload_thread_attr, 512 * 1024);
pthread_mutex_init(&uwsgi.static_offload_thread_lock, NULL);
}
#ifdef UWSGI_ASYNC
// TODO rewrite to use uwsgi.max_fd
if (uwsgi.async > 1) {
if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
if ((unsigned long) uwsgi.rl.rlim_cur < (unsigned long) uwsgi.async) {
uwsgi_log("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.rl.rlim_cur);
if (uwsgi.rl.rlim_cur < uwsgi.rl.rlim_max && (unsigned long) uwsgi.rl.rlim_max > (unsigned long) uwsgi.async) {
unsigned long tmp_nofile = (unsigned long) uwsgi.rl.rlim_cur;
uwsgi.rl.rlim_cur = uwsgi.async;
if (!setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi_log("max open files limit reset to %lu\n", (unsigned long) uwsgi.rl.rlim_cur);
uwsgi.async = uwsgi.rl.rlim_cur;
}
else {
uwsgi.async = (int) tmp_nofile;
}
}
else {
uwsgi.async = uwsgi.rl.rlim_cur;
}
uwsgi_log("- async cores set to %d -\n", uwsgi.async);
}
}
}
#endif
if (uwsgi.requested_max_fd) {
uwsgi.rl.rlim_cur = uwsgi.requested_max_fd;
uwsgi.rl.rlim_max = uwsgi.requested_max_fd;
@@ -2052,11 +2121,24 @@ int uwsgi_start(void *v_argv) {
if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi.max_fd = uwsgi.rl.rlim_cur;
uwsgi_log_initial("detected max file descriptor number: %d\n", (int) uwsgi.max_fd);
uwsgi_log_initial("detected max file descriptor number: %lu\n", (unsigned long) uwsgi.max_fd);
}
if (uwsgi.async > 1) {
uwsgi_log("async fd table size: %d\n", uwsgi.max_fd);
if ((unsigned long) uwsgi.max_fd < (unsigned long) uwsgi.async) {
uwsgi_log("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.max_fd);
uwsgi.rl.rlim_cur = uwsgi.async;
uwsgi.rl.rlim_max = uwsgi.async;
if (!setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
uwsgi_log("max open files limit raised to %lu\n", (unsigned long) uwsgi.rl.rlim_cur);
uwsgi.async = uwsgi.rl.rlim_cur;
uwsgi.max_fd = uwsgi.rl.rlim_cur;
}
else {
uwsgi.async = (int) uwsgi.max_fd;
}
}
uwsgi_log("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd);
uwsgi.async_waiting_fd_table = malloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_waiting_fd_table) {
uwsgi_error("malloc()");
@@ -2075,10 +2157,6 @@ int uwsgi_start(void *v_argv) {
uwsgi_log("cores allocated...\n");
#endif
if (uwsgi.cores > 1) {
uwsgi_log("allocated %llu bytes (%llu KB) for %d cores per worker.\n", (uint64_t) (sizeof(struct uwsgi_core) * uwsgi.cores), (uint64_t) ((sizeof(struct uwsgi_core) * uwsgi.cores) / 1024), uwsgi.cores);
}
if (uwsgi.vhost) {
uwsgi_log("VirtualHosting mode enabled.\n");
}
@@ -2094,6 +2172,10 @@ int uwsgi_start(void *v_argv) {
uwsgi.sa_lock = uwsgi_rwlock_init("sharedarea");
}
#ifdef UWSGI_SNMP
uwsgi.snmp_lock = uwsgi_lock_init("snmp");
#endif
// setup queue
if (uwsgi.queue_size > 0) {
uwsgi_init_queue();
@@ -2142,7 +2224,7 @@ int uwsgi_start(void *v_argv) {
// initialize request plugin only if workers or master are available
if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode) {
if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->init) {
uwsgi.p[i]->init();
@@ -2158,7 +2240,7 @@ int uwsgi_start(void *v_argv) {
}
// again check for workers/sockets...
if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode) {
if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->post_init) {
uwsgi.p[i]->post_init();
@@ -2186,7 +2268,7 @@ int uwsgi_start(void *v_argv) {
pthread_mutex_init(&uwsgi.lock_static, NULL);
// again check for workers/sockets...
if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode) {
if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->enable_threads)
uwsgi.p[i]->enable_threads();
@@ -2195,6 +2277,11 @@ int uwsgi_start(void *v_argv) {
}
#endif
// users of the --loop option should know what they are doing... really...
#ifndef UWSGI_DEBUG
if (uwsgi.loop) goto unsafe;
#endif
#ifdef UWSGI_UDP
if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.no_server && !uwsgi.udp_socket && !uwsgi.emperor && !uwsgi.command_mode) {
#else
@@ -2218,6 +2305,10 @@ int uwsgi_start(void *v_argv) {
uwsgi.to_hell = 1;
}
#ifndef UWSGI_DEBUG
unsafe:
#endif
#ifdef UWSGI_DEBUG
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
int so_bufsize;
@@ -2328,6 +2419,23 @@ int uwsgi_start(void *v_argv) {
}
}
#ifdef UWSGI_SPOOLER
// initialize locks and socket as soon as possibile, as the master could enqueue tasks
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
// lock is required even in EXTERNAL mode
uspool->lock = uwsgi_lock_init(uwsgi_concat2("spooler on ", uspool->dir));
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL) goto next;
create_signal_pipe(uspool->signal_pipe);
next:
uspool = uspool->next;
}
}
#endif
// preinit apps (create the language environment)
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->preinit_apps) {
@@ -2361,30 +2469,7 @@ int uwsgi_start(void *v_argv) {
if (uwsgi.daemonize2) {
if (uwsgi.has_emperor) {
logto(uwsgi.daemonize2);
}
else {
if (!uwsgi.is_a_reload) {
uwsgi_log("*** daemonizing uWSGI ***\n");
daemonize(uwsgi.daemonize2);
}
else if (uwsgi.log_reopen) {
logto(uwsgi.daemonize2);
}
}
uwsgi.mypid = getpid();
masterpid = uwsgi.mypid;
uwsgi.workers[0].pid = masterpid;
if (uwsgi.pidfile && !uwsgi.is_a_reload) {
uwsgi_write_pidfile(uwsgi.pidfile);
}
if (uwsgi.pidfile2 && !uwsgi.is_a_reload) {
uwsgi_write_pidfile(uwsgi.pidfile2);
}
masterpid = uwsgi_daemonize2();
}
if (uwsgi.no_server) {
@@ -2396,9 +2481,12 @@ int uwsgi_start(void *v_argv) {
if (!uwsgi.master_process && uwsgi.numproc == 0) {
exit(0);
}
#ifdef UWSGI_MINTERPRETERS
if (!uwsgi.single_interpreter && uwsgi.numproc > 0) {
uwsgi_log("*** uWSGI is running in multiple interpreter mode ***\n");
}
#endif
// check for request plugins, and eventually print a warning
int rp_available = 0;
@@ -2459,16 +2547,12 @@ int uwsgi_start(void *v_argv) {
#ifdef UWSGI_SPOOLER
if (uwsgi.spoolers != NULL && uwsgi.sockets) {
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
// lock is required even in EXTERNAL mode
uspool->lock = uwsgi_lock_init(uwsgi_concat2("spooler on ", uspool->dir));
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL) goto next;
create_signal_pipe(uspool->signal_pipe);
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL) goto next2;
uspool->pid = spooler_start(uspool);
next:
next2:
uspool = uspool->next;
}
}
@@ -2576,6 +2660,14 @@ next:
// set default wsgi_req (for loading apps);
uwsgi.wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req;
if (uwsgi.static_offload_to_thread) {
uwsgi.offload_thread = uwsgi_offload_thread_start();
if (!uwsgi.offload_thread) {
uwsgi_log("unable to offload static file serving !!!\n");
uwsgi.static_offload_to_thread = 0;
}
}
// must be run before running apps
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->post_fork) {
@@ -2706,6 +2798,16 @@ wait_for_call_of_duty:
}
}
#ifdef UWSGI_THREADING
// create a pthread key, storing per-thread wsgi_request structure
if (uwsgi.threads > 1) {
if (pthread_key_create(&uwsgi.tur_key, NULL)) {
uwsgi_error("pthread_key_create()");
exit(1);
}
}
#endif
if (uwsgi.loop) {
void (*u_loop) (void) = uwsgi_get_loop(uwsgi.loop);
@@ -2720,29 +2822,14 @@ wait_for_call_of_duty:
uwsgi_log("your loop engine died. R.I.P.\n");
}
else {
if (uwsgi.threads > 1) {
#ifdef UWSGI_THREADING
if (pthread_key_create(&uwsgi.tur_key, NULL)) {
uwsgi_error("pthread_key_create()");
exit(1);
}
for (i = 1; i < uwsgi.threads; i++) {
long j = i;
pthread_create(&uwsgi.workers[uwsgi.mywid].cores[i].thread_id, &uwsgi.threads_attr, simple_loop, (void *) j);
}
#endif
}
if (uwsgi.async < 2) {
long y = 0;
simple_loop((void *) y);
simple_loop();
}
#ifdef UWSGI_ASYNC
else {
async_loop(NULL);
async_loop();
}
#endif
}
if (uwsgi.snapshot) {
@@ -2896,7 +2983,7 @@ void uwsgi_stdin_sendto(char *socket_name, uint8_t modifier1, uint8_t modifier2)
#endif
ptr += rlen;
delta -= rlen;
if (delta <= 0)
if (delta == 0)
break;
rlen = read(0, ptr, delta);
}
@@ -3155,12 +3242,31 @@ void uwsgi_opt_add_string_list(char *opt, char *value, void *list) {
uwsgi_string_new_list(ptr, value);
}
#ifdef UWSGI_PCRE
void uwsgi_opt_add_regexp_list(char *opt, char *value, void *list) {
struct uwsgi_regexp_list **ptr = (struct uwsgi_regexp_list **) list;
uwsgi_regexp_new_list(ptr, value);
}
void uwsgi_opt_add_regexp_custom_list(char *opt, char *value, void *list) {
char *space = strchr(value, ' ');
if (!space) {
uwsgi_log("invalid custom regexp syntax: must be <custom> <regexp>\n");
exit(1);
}
char *custom = uwsgi_concat2n(value, space-value, "", 0);
struct uwsgi_regexp_list **ptr = (struct uwsgi_regexp_list **) list;
uwsgi_regexp_custom_new_list(ptr, space+1, custom);
}
#endif
void uwsgi_opt_add_shared_socket(char *opt, char *value, void *protocol) {
uwsgi_new_shared_socket(generate_socket_name(value));
}
void uwsgi_opt_add_socket(char *opt, char *value, void *protocol) {
struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value));
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
uwsgi_sock->proto_name = protocol;
}
@@ -3186,6 +3292,10 @@ void uwsgi_opt_set_placeholder(char *opt, char *value, void *none) {
}
void uwsgi_opt_ssa(char *opt, char *value, void *foobar) {
uwsgi_subscription_set_algo(value);
}
#ifdef UWSGI_SSL
void uwsgi_opt_scd(char *opt, char *value, void *foobar) {
// openssl could not be initialized
@@ -3268,10 +3378,6 @@ void uwsgi_opt_set_unshare(char *opt, char *value, void *none) {
}
#endif
void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
uwsgi_daemon_new(&uwsgi.daemons, value);
}
void uwsgi_opt_set_env(char *opt, char *value, void *none) {
if (putenv(value)) {
uwsgi_error("putenv()");
@@ -3292,6 +3398,12 @@ void uwsgi_opt_pidfile_signal(char *opt, char *pidfile, void *sig) {
exit(0);
}
void uwsgi_opt_load_dl(char *opt, char *value, void *none) {
if (!dlopen(value, RTLD_NOW | RTLD_GLOBAL)) {
uwsgi_log( "%s\n", dlerror());
}
}
void uwsgi_opt_load_plugin(char *opt, char *value, void *none) {
char *p = strtok(uwsgi_concat2(value, ""), ",");
-9
View File
@@ -1,9 +0,0 @@
// http:3:GET / HTTP/1.1:192.168.173.10:80,192.168.173.11:80,192.168.173.12:80,192.168.173.13:80
/*
write(arg1);
wait_for_fd()
get_data() == 200
*/
View File
View File
View File
View File
-1
View File
@@ -1 +0,0 @@
// uwsgi:3::192.168.173.1:3031,192.168.173.2:3031,192.168.173.3:3031,192.168.173.4:3031
+30
View File
@@ -2,6 +2,36 @@ import uwsgi
if uwsgi.loop == 'gevent':
import gevent
from threading import Thread
import time
from uwsgidecorators import postfork
def foobar():
while True:
time.sleep(3)
print "threee second elapsed in worker %d" % uwsgi.worker_id()
@postfork
def spawn_thread():
t = Thread(target=foobar)
t.daemon = True
t.start()
@postfork
def spawn_thread2():
t = Thread(target=foobar)
t.daemon = True
t.start()
def gl_func():
while True:
gevent.sleep(2)
print "i am a greenltet running in worker %d" % uwsgi.worker_id()
@postfork
def spawn_greenlet():
gevent.spawn(gl_func)
print uwsgi.version
print uwsgi.workers()
try:
+1
View File
@@ -11,5 +11,6 @@ uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
+203
View File
@@ -0,0 +1,203 @@
#include "../../uwsgi.h"
#include <curl/curl.h>
extern struct uwsgi_server uwsgi;
struct uwsgi_alarm_curl_config {
int first;
char *arg;
char *subject;
char *to;
};
struct uwsgi_alarm_curl_opt {
char *name;
CURLoption option;
void (*func)(CURL *, CURLoption, char *, struct uwsgi_alarm_curl_config*);
};
static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
uacc->to = arg;
struct curl_slist *list = NULL;
char *items = uwsgi_str(arg);
char *ctx = NULL;
char *p = strtok_r(items, ",", &ctx);
while(p) {
list = curl_slist_append(list, p);
p = strtok_r(NULL, ",", &ctx);
}
curl_easy_setopt(curl, option, list);
}
static void uwsgi_alarm_curl_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL);
}
static void uwsgi_alarm_curl_int(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
curl_easy_setopt(curl, option, atoi(arg));
}
static void uwsgi_alarm_curl_set_subject(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
uacc->subject = arg;
}
static struct uwsgi_alarm_curl_opt uaco[] = {
{"url", CURLOPT_URL, NULL},
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to },
{"mail_from", CURLOPT_MAIL_FROM, NULL},
{"subject", 0, uwsgi_alarm_curl_set_subject},
{"ssl", CURLOPT_USE_SSL, uwsgi_alarm_curl_ssl},
{"auth_user", CURLOPT_USERNAME, NULL},
{"auth_pass", CURLOPT_PASSWORD, NULL},
{"method", CURLOPT_CUSTOMREQUEST, NULL},
{"timeout", CURLOPT_TIMEOUT, uwsgi_alarm_curl_int},
{"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_alarm_curl_int},
{NULL, 0, NULL},
};
static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_curl_config *uacc) {
struct uwsgi_alarm_curl_opt *o = uaco;
char *equal = strchr(opt,'=');
if (!equal) {
if (!uacc->first) {
curl_easy_setopt(curl, CURLOPT_URL, opt);
uacc->first = 1;
}
return;
}
uacc->first = 1;
*equal = 0;
while(o->name) {
if (!strcmp(o->name, opt)) {
if (o->func) {
o->func(curl, o->option, equal+1, uacc);
}
else {
curl_easy_setopt(curl, o->option, equal+1);
}
goto end;
}
o++;
}
end:
*equal = '=';
}
static size_t uwsgi_alarm_curl_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) userp;
size_t full_size = size * nmemb;
size_t remains = ut->len - ut->pos;
struct uwsgi_alarm_curl_config *uacc = ut->data;
if (remains == 0) return 0;
if (ut->custom0 == 0) {
size_t newline = 0;
size_t required = 1;
char *addr = ptr;
if (uacc->to) required += 4 + strlen(uacc->to) + 1;
if (uacc->subject) required += 9 + strlen(uacc->subject) + 1;
if (required > full_size) goto skip;
if (uacc->to) {
memcpy(addr, "To: ", 4); addr+=4;
memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to);
*addr ++= '\n';
newline = 1;
}
if (uacc->subject) {
memcpy(addr, "Subject: ", 9); addr+=9;
memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject);
*addr ++= '\n';
newline = 1;
}
skip:
if (newline > 0) {
*addr = '\n';
}
ut->custom0 = 1;
return required;
}
if (full_size < remains) {
remains = full_size;
}
memcpy(ptr, ut->buf + ut->pos, remains);
ut->pos += remains;
return remains;
}
static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
int interesting_fd;
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
CURL *curl = curl_easy_init();
// ARGH !!!
if (!curl) return;
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_alarm_curl_read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
struct uwsgi_alarm_curl_config *uacc = (struct uwsgi_alarm_curl_config *) ut->data;
char *opts = uwsgi_str(uacc->arg);
// fill curl options
char *ctx = NULL;
char *p = strtok_r(opts, ";", &ctx);
while(p) {
uwsgi_alarm_curl_setopt(curl, uwsgi_str(p), uacc);
p = strtok_r(NULL, ";", &ctx);
}
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret <= 0) continue;
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
ut->pos = 0;
ut->len = (size_t) rlen;
ut->custom0 = 0;
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
}
}
static void uwsgi_alarm_curl_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_curl_loop);
if (!ut) return;
uai->data_ptr = ut;
struct uwsgi_alarm_curl_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_alarm_curl_config));
uacc->arg = uai->arg;
ut->data = uacc;
}
// pipe the message into the thread;
static void uwsgi_alarm_curl_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
ut->rlen = write(ut->pipe[0], msg, len);
}
static void uwsgi_alarm_curl_load(void) {
uwsgi_register_alarm("curl", uwsgi_alarm_curl_init, uwsgi_alarm_curl_func);
}
struct uwsgi_plugin alarm_curl_plugin = {
.name = "alarm_curl",
.on_load = uwsgi_alarm_curl_load,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='alarm_curl'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lcurl']
GCC_LIST = ['alarm_curl_plugin']
+52
View File
@@ -0,0 +1,52 @@
#include "../../uwsgi.h"
#import "Foundation/NSString.h"
#import "AppKit/NSSpeechSynthesizer.h"
@interface uWSGIAlarmSpeaker : NSObject {
NSSpeechSynthesizer *synth;
}
-(void)speak: (NSString *)phrase;
@end
@implementation uWSGIAlarmSpeaker
- (uWSGIAlarmSpeaker *) init {
self = [super init];
synth = [[NSSpeechSynthesizer alloc] initWithVoice:nil];
return self;
}
- (void)speak:(NSString *)phrase {
[synth startSpeakingString:phrase];
}
@end
// generate a uwsgi signal on alarm
void uwsgi_alarm_speech_init(struct uwsgi_alarm_instance *uai) {
uai->data_ptr = [[uWSGIAlarmSpeaker alloc] init];
}
void uwsgi_alarm_speech_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
uWSGIAlarmSpeaker *say = (uWSGIAlarmSpeaker *) uai->data_ptr;
NSString *phrase = [[NSString alloc] initWithBytes:msg
length:len
encoding:NSUTF8StringEncoding];
[say speak:phrase];
[phrase release];
}
static void uwsgi_alarm_speech_load(void) {
uwsgi_register_alarm("speech", uwsgi_alarm_speech_init, uwsgi_alarm_speech_func);
}
struct uwsgi_plugin alarm_speech_plugin = {
.name = "alarm_speech",
.on_load = uwsgi_alarm_speech_load,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='alarm_speech'
CFLAGS = []
LDFLAGS = []
LIBS = ['-framework appkit']
GCC_LIST = ['alarm_speech.m']
+26
View File
@@ -0,0 +1,26 @@
#include "../../uwsgi.h"
void uwsgi_alarm_xmpp_loop(struct uwsgi_thread *);
static void uwsgi_alarm_xmpp_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_xmpp_loop);
if (!ut) return;
uai->data_ptr = ut;
ut->data = uai->arg;
}
// pipe the message into the thread;
static void uwsgi_alarm_xmpp_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
ut->rlen = write(ut->pipe[0], msg, len);
}
static void uwsgi_alarm_xmpp_load(void) {
uwsgi_register_alarm("xmpp", uwsgi_alarm_xmpp_init, uwsgi_alarm_xmpp_func);
}
struct uwsgi_plugin alarm_xmpp_plugin = {
.name = "alarm_xmpp",
.on_load = uwsgi_alarm_xmpp_load,
};
+144
View File
@@ -0,0 +1,144 @@
#include "../../uwsgi.h"
#include <gloox/client.h>
#include <gloox/message.h>
#include <gloox/connectionlistener.h>
#include <gloox/connectiontcpclient.h>
extern struct uwsgi_server uwsgi;
using namespace gloox;
class Jabbo : public ConnectionListener{
public:
Jabbo(struct uwsgi_thread *ut, char *jab_username, char *jab_password, char *dests) {
u_thread = ut;
dest = NULL;
char *ctx = NULL;
char *p = strtok_r(dests, ",", &ctx);
while(p) {
uwsgi_string_new_list(&dest, p);
p = strtok_r(NULL, ",", &ctx);
}
JID jid(jab_username);
client = new Client( jid, jab_password );
client->registerConnectionListener(this);
u_connected = 0;
client->connect(false);
fd = static_cast<ConnectionTCPClient*>( client->connectionImpl() )->socket();
}
~Jabbo() {
delete client;
}
void send(char *buf, size_t len) {
struct uwsgi_string_list *usl = dest;
while(usl) {
JID jid(usl->value);
std::string text(buf, len);
Message msg(Message::Chat, jid, text);
client->send(msg);
usl = usl->next;
}
}
virtual void onConnect() {
event_queue_add_fd_read(u_thread->queue, fd);
event_queue_add_fd_read(u_thread->queue, u_thread->pipe[1]);
u_connected = 1;
}
virtual void onDisconnect(ConnectionError e) {
if (u_connected) {
event_queue_del_fd(u_thread->queue, fd, event_queue_read());
event_queue_del_fd(u_thread->queue, u_thread->pipe[1], event_queue_read());
}
sleep(1);
u_connected = 0;
client->connect(false);
fd = static_cast<ConnectionTCPClient*>( client->connectionImpl() )->socket();
}
virtual bool onTLSConnect(const CertInfo& info) {
return true;
}
Client* client;
int fd;
int u_connected;
struct uwsgi_thread *u_thread;
struct uwsgi_string_list *dest;
};
extern "C" void uwsgi_alarm_xmpp_loop(struct uwsgi_thread *ut) {
int interesting_fd;
ut->buf = (char *) uwsgi_malloc(uwsgi.log_master_bufsize);
char *xmpp_username = (char *) "";
char *xmpp_password = (char *) "";
char *xmpp_dests = (char *) "";
// 0 -> username, 1 -> password, 2-> dest list
int opt_state = 0;
// fill xmpp options
char *ctx = NULL;
char *opts = uwsgi_str((char *)ut->data);
char *p = strtok_r(opts, ";", &ctx);
while(p) {
switch(opt_state) {
case 0:
xmpp_username = p;
opt_state = 1;
break;
case 1:
xmpp_password = p;
opt_state = 2;
break;
case 2:
xmpp_dests = p;
opt_state = 3;
break;
default:
break;
}
p = strtok_r(NULL, ";", &ctx);
}
// do not process loglines til the jabber account is connected
event_queue_del_fd(ut->queue, ut->pipe[1], event_queue_read());
Jabbo j(ut, xmpp_username, xmpp_password, xmpp_dests);
int timeout = 0;
for(;;) {
if (j.u_connected) {
timeout = -1;
}
else {
timeout = 0;
}
int ret = event_queue_wait(ut->queue, timeout, &interesting_fd);
if (ret < 0) continue;
if (ret > 0 && interesting_fd == ut->pipe[1]) {
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
if (j.u_connected) {
j.send(ut->buf, rlen);
}
}
else if (ret == 0 || (ret > 0 && j.fd > -1 && interesting_fd == j.fd)) {
j.client->recv();
}
}
}
+6
View File
@@ -0,0 +1,6 @@
NAME='alarm_xmpp'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lgloox']
GCC_LIST = ['alarm_xmpp_plugin', 'gloox.cc']
+219 -145
View File
@@ -2,22 +2,37 @@
extern struct uwsgi_server uwsgi;
struct carbon_server_list {
char *value; // server address
int healthy;
int errors;
struct carbon_server_list *next;
};
struct uwsgi_carbon {
struct uwsgi_string_list *servers;
struct carbon_server_list *servers_data;
int freq;
int timeout;
char *id;
int no_workers;
unsigned long long *last_busyness_values;
unsigned long long *current_busyness_values;
int need_retry;
time_t last_update;
time_t next_retry;
int max_retries;
int retry_delay;
} u_carbon;
struct uwsgi_option carbon_options[] = {
{"carbon", required_argument, 0, "push statistics to the specified carbon server", uwsgi_opt_add_string_list, &u_carbon.servers, UWSGI_OPT_MASTER},
{"carbon-timeout", required_argument, 0, "set carbon connection timeout", uwsgi_opt_set_int, &u_carbon.timeout, 0},
{"carbon-freq", required_argument, 0, "set carbon push frequency", uwsgi_opt_set_int, &u_carbon.freq, 0},
{"carbon-timeout", required_argument, 0, "set carbon connection timeout in seconds (default 3)", uwsgi_opt_set_int, &u_carbon.timeout, 0},
{"carbon-freq", required_argument, 0, "set carbon push frequency in seconds (default 60)", uwsgi_opt_set_int, &u_carbon.freq, 0},
{"carbon-id", required_argument, 0, "set carbon id", uwsgi_opt_set_str, &u_carbon.id, 0},
{"carbon-no-workers", no_argument, 0, "disable generation of single worker metrics", uwsgi_opt_true, &u_carbon.no_workers, 0},
{"carbon-max-retry", required_argument, 0, "set maximum number of retries in case of connection errors (default 1)", uwsgi_opt_set_int, &u_carbon.max_retries, 0},
{"carbon-retry-delay", required_argument, 0, "set connection retry delay in seconds (default 7)", uwsgi_opt_set_int, &u_carbon.retry_delay, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -31,12 +46,23 @@ void carbon_post_init() {
if (!u_carbon.servers) return;
while(usl) {
uwsgi_log("added carbon server %s\n", usl->value);
struct carbon_server_list *u_server = uwsgi_calloc(sizeof(struct carbon_server_list));
u_server->value = usl->value;
u_server->healthy = 1;
u_server->errors = 0;
if (u_carbon.servers_data) {
u_server->next = u_carbon.servers_data;
}
u_carbon.servers_data = u_server;
uwsgi_log("[carbon] added 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.max_retries <= 0) u_carbon.max_retries = 1;
if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7;
if (!u_carbon.id) {
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
@@ -53,160 +79,208 @@ void carbon_post_init() {
u_carbon.current_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc);
}
// set next update to now()+retry_delay, this way we will have first flush just after start
u_carbon.last_update = uwsgi_now() - u_carbon.freq + u_carbon.retry_delay;
uwsgi_log("[carbon] carbon plugin started, %is frequency, %is timeout, max retries %i, retry delay %is",
u_carbon.freq, u_carbon.timeout, u_carbon.max_retries, u_carbon.retry_delay);
}
int carbon_write(int *fd, char *fmt,...) {
va_list ap;
va_start(ap, fmt);
char ptr[4096];
int rlen;
rlen = vsnprintf(ptr, 4096, fmt, ap);
if (rlen < 1) return 0;
if (write(*fd, ptr, rlen) <= 0) {
uwsgi_error("write()");
return 0;
}
return 1;
}
void carbon_push_stats(int retry_cycle) {
struct carbon_server_list *usl = u_carbon.servers_data;
int i;
int fd;
int wok;
for (i = 0; i < uwsgi.numproc; i++) {
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
u_carbon.last_busyness_values[i] = uwsgi.workers[i+1].running_time;
}
u_carbon.need_retry = 0;
while(usl) {
if (retry_cycle && usl->healthy)
// skip healthy servers during retry cycle
goto nxt;
if (retry_cycle && usl->healthy == 0)
uwsgi_log("[carbon] Retrying failed server at %s (%d)\n", usl->value, usl->errors);
if (!retry_cycle) {
usl->healthy = 1;
usl->errors = 0;
}
fd = uwsgi_connect(usl->value, u_carbon.timeout, 0);
if (fd < 0) {
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", usl->value);
if (usl->errors < u_carbon.max_retries) {
u_carbon.need_retry = 1;
u_carbon.next_retry = uwsgi_now() + u_carbon.retry_delay;
} else {
uwsgi_log("[carbon] Maximum number of retries for %s (1)\n",
usl->value, u_carbon.max_retries);
usl->healthy = 0;
usl->errors = 0;
}
usl->healthy = 0;
usl->errors++;
goto nxt;
}
// put the socket in non-blocking mode
uwsgi_socket_nb(fd);
unsigned long long total_rss = 0;
unsigned long long total_vsz = 0;
unsigned long long total_tx = 0;
unsigned long long total_avg_rt = 0; // total avg_rt
unsigned long long avg_rt = 0; // per worker avg_rt reported to carbon
unsigned long long active_workers = 0; // number of workers used to calculate total avg_rt
unsigned long long total_busyness = 0;
unsigned long long total_avg_busyness = 0;
unsigned long long worker_busyness = 0;
unsigned long long total_harakiri = 0;
wok = carbon_write(&fd, "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 (!wok) goto clear;
for(i=1;i<=uwsgi.numproc;i++) {
total_tx += uwsgi.workers[i].tx;
if (uwsgi.workers[i].cheaped) {
// also if worker is cheaped than we report its average response time as zero, sending last value might be confusing
avg_rt = 0;
worker_busyness = 0;
}
else {
// global average response time is calculated from active/idle workers, cheaped workers are excluded, otherwise it is not accurate
avg_rt = uwsgi.workers[i].avg_response_time;
active_workers++;
total_avg_rt += uwsgi.workers[i].avg_response_time;
// calculate worker busyness
worker_busyness = ((u_carbon.current_busyness_values[i-1]*100) / (u_carbon.freq*1000000));
if (worker_busyness > 100) worker_busyness = 100;
total_busyness += worker_busyness;
// only running workers are counted in total memory stats
total_rss += uwsgi.workers[i].rss_size;
total_vsz += uwsgi.workers[i].vsz_size;
total_harakiri += uwsgi.workers[i].harakiri_count;
}
//skip per worker metrics when disabled
if (u_carbon.no_workers) continue;
wok = carbon_write(&fd, "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 (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].rss_size, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].vsz_size, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) avg_rt, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].tx, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.busyness %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) worker_busyness, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.harakiri %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].harakiri_count, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
}
wok = carbon_write(&fd, "uwsgi.%s.%s.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_rss, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_vsz, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) (active_workers ? total_avg_rt / active_workers : 0), (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_tx, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
if (active_workers > 0) {
total_avg_busyness = total_busyness / active_workers;
if (total_avg_busyness > 100) total_avg_busyness = 100;
} else {
total_avg_busyness = 0;
}
wok = carbon_write(&fd, "uwsgi.%s.%s.busyness %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_avg_busyness, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.active_workers %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) active_workers, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
if (uwsgi.cheaper) {
wok = carbon_write(&fd, "uwsgi.%s.%s.cheaped_workers %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) uwsgi.numproc - active_workers, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
}
wok = carbon_write(&fd, "uwsgi.%s.%s.harakiri %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_harakiri, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
usl->healthy = 1;
usl->errors = 0;
clear:
close(fd);
nxt:
usl = usl->next;
}
if (!retry_cycle) u_carbon.last_update = uwsgi_now();
if (u_carbon.need_retry)
// timeouts and retries might cause additional lags in carbon cycles, we will adjust timer to fix that
u_carbon.last_update -= u_carbon.timeout;
}
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 (!u_carbon.servers) return ;
if (last_update == 0) last_update = uwsgi_now();
// update
if (uwsgi.current_time - last_update >= u_carbon.freq) {
for (i = 0; i < uwsgi.numproc; i++) {
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
u_carbon.last_busyness_values[i] = uwsgi.workers[i+1].running_time;
}
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);
unsigned long long total_rss = 0;
unsigned long long total_vsz = 0;
unsigned long long total_tx = 0;
unsigned long long total_avg_rt = 0; // total avg_rt
unsigned long long avg_rt = 0; // per worker avg_rt reported to carbon
unsigned long long active_workers = 0; // number of workers used to calculate total avg_rt
unsigned long long total_busyness = 0;
unsigned long long total_avg_busyness = 0;
unsigned long long worker_busyness = 0;
unsigned long long total_harakiri = 0;
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++) {
total_tx += uwsgi.workers[i].tx;
if (uwsgi.workers[i].cheaped) {
// also if worker is cheaped than we report its average response time as zero, sending last value might be confusing
avg_rt = 0;
worker_busyness = 0;
}
else {
// global average response time is calcucalted from active/idle workers, cheaped workers are excluded, otherwise it is not accurate
avg_rt = uwsgi.workers[i].avg_response_time;
active_workers++;
total_avg_rt += uwsgi.workers[i].avg_response_time;
// calculate worker busyness
worker_busyness = ((u_carbon.current_busyness_values[i-1]*100) / (u_carbon.freq*1000000));
if (worker_busyness > 100) worker_busyness = 100;
total_busyness += worker_busyness;
// only running workers are counted in total memory stats
total_rss += uwsgi.workers[i].rss_size;
total_vsz += uwsgi.workers[i].vsz_size;
total_harakiri += uwsgi.workers[i].harakiri_count/2;
}
//skip per worker metrics when disabled
if (u_carbon.no_workers) continue;
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;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].rss_size, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].vsz_size, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) avg_rt, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].tx, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.busyness %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) worker_busyness, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.harakiri %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].harakiri_count/2, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_rss, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_vsz, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) (active_workers ? total_avg_rt / active_workers : 0), (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_tx, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
if (active_workers > 0) {
total_avg_busyness = total_busyness / active_workers;
if (total_avg_busyness > 100) total_avg_busyness = 100;
} else {
total_avg_busyness = 0;
}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.busyness %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_avg_busyness, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.active_workers %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) active_workers, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
if (uwsgi.cheaper) {
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.cheaped_workers %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) uwsgi.numproc - active_workers, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.harakiri %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_harakiri, (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;
}
last_update = uwsgi_now();
if (uwsgi.current_time - u_carbon.last_update >= u_carbon.freq || uwsgi.cleaning) {
// update
u_carbon.need_retry = 0;
carbon_push_stats(0);
} else if (u_carbon.need_retry && (uwsgi.current_time >= u_carbon.next_retry)) {
// retry failed servers
carbon_push_stats(1);
}
}
struct uwsgi_plugin carbon_plugin = {
.name = "carbon",
.master_cleanup = carbon_master_cycle,
.options = carbon_options,
.master_cycle = carbon_master_cycle,
.post_init = carbon_post_init,
+69 -18
View File
@@ -22,8 +22,11 @@ struct uwsgi_cheaper_busyness_global {
int last_action; // 1 - spawn workers ; 2 - cheap worker
int verbose; // 1 - show debug logs, 0 - only important
uint64_t tolerance_counter; // used to keep track of what to do if min <= busyness <= max for few cycles in row
int emergency_workers; // counts the number of running emergency workers
#ifdef __linux__
int backlog_alert;
int backlog_step;
uint64_t backlog_multi; // multiplier used to cheap emergency workers
#endif
} uwsgi_cheaper_busyness_global;
@@ -52,6 +55,12 @@ struct uwsgi_option uwsgi_cheaper_busyness_options[] = {
{"cheaper-busyness-backlog-alert", required_argument, 0,
"spawn emergency worker if anytime listen queue is higher than this value (default 33)",
uwsgi_opt_set_int, &uwsgi_cheaper_busyness_global.backlog_alert, 0},
{"cheaper-busyness-backlog-multiplier", required_argument, 0,
"set cheaper multiplier used for emergency workers (default 3)",
uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.backlog_multi, 0},
{"cheaper-busyness-backlog-step", required_argument, 0,
"number of emergency workers to spawn at a time (default 1)",
uwsgi_opt_set_int, &uwsgi_cheaper_busyness_global.backlog_step, 0},
#endif
{0, 0, 0, 0, 0, 0 ,0},
@@ -63,10 +72,22 @@ struct uwsgi_option uwsgi_cheaper_busyness_options[] = {
void set_next_cheap_time(void) {
uint64_t now = uwsgi_micros();
// we will start workers now so we will set time when workers can be cheaped to
// some time in the future, so that workers are cheaped only if long term busyness
// is low enough
uwsgi_cheaper_busyness_global.next_cheap = now + uwsgi.cheaper_overload*uwsgi_cheaper_busyness_global.cheap_multi*1000000;
#ifdef __linux__
if (uwsgi_cheaper_busyness_global.emergency_workers > 0) {
// we have some emergency workers running, we will use minimum delay (2 cycles) to cheap workers
// to have quicker recovery from big but short load spikes
// otherwise we might wait a lot before cheaping all emergency workers
if (uwsgi_cheaper_busyness_global.verbose)
uwsgi_log("[busyness] %d emergency worker(s) running, using %d seconds cheaper timer\n",
uwsgi_cheaper_busyness_global.emergency_workers, uwsgi.cheaper_overload*uwsgi_cheaper_busyness_global.backlog_multi);
uwsgi_cheaper_busyness_global.next_cheap = now + uwsgi.cheaper_overload*uwsgi_cheaper_busyness_global.backlog_multi*1000000;
} else {
#endif
// no emergency workers running, we use normal math for setting timer
uwsgi_cheaper_busyness_global.next_cheap = now + uwsgi.cheaper_overload*uwsgi_cheaper_busyness_global.cheap_multi*1000000;
#ifdef __linux__
}
#endif
}
@@ -79,6 +100,36 @@ void decrease_multi(void) {
}
#ifdef __linux__
int spawn_emergency_worker(int backlog) {
// reset cheaper multiplier to minimum value so we can start cheaping workers sooner
// if this was just random spike
uwsgi_cheaper_busyness_global.cheap_multi = uwsgi_cheaper_busyness_global.min_multi;
// set last action to spawn
uwsgi_cheaper_busyness_global.last_action = 1;
int decheaped = 0;
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) {
decheaped++;
if (decheaped >= uwsgi_cheaper_busyness_global.backlog_step) break;
}
}
uwsgi_cheaper_busyness_global.emergency_workers += decheaped;
set_next_cheap_time();
uwsgi_log("[busyness] %d requests in listen queue, spawning %d emergency worker(s) (%d)!\n",
backlog, decheaped, uwsgi_cheaper_busyness_global.emergency_workers);
return decheaped;
}
#endif
int cheaper_busyness_algo(void) {
int i;
@@ -98,6 +149,8 @@ int cheaper_busyness_algo(void) {
#ifdef __linux__
if (!uwsgi_cheaper_busyness_global.backlog_alert) uwsgi_cheaper_busyness_global.backlog_alert = 33;
if (!uwsgi_cheaper_busyness_global.backlog_multi) uwsgi_cheaper_busyness_global.backlog_multi = 3;
if (!uwsgi_cheaper_busyness_global.backlog_step) uwsgi_cheaper_busyness_global.backlog_step = 1;
#endif
if (!uwsgi_cheaper_busyness_global.min_multi) {
@@ -108,7 +161,8 @@ int cheaper_busyness_algo(void) {
uwsgi_cheaper_busyness_global.busyness_min, uwsgi_cheaper_busyness_global.busyness_max,
uwsgi.cheaper_overload, uwsgi_cheaper_busyness_global.cheap_multi, uwsgi_cheaper_busyness_global.penalty);
#ifdef __linux__
uwsgi_log("[busyness] backlog alert is set to %d request(s)\n", uwsgi_cheaper_busyness_global.backlog_alert);
uwsgi_log("[busyness] backlog alert is set to %d request(s), step is %d\n",
uwsgi_cheaper_busyness_global.backlog_alert, uwsgi_cheaper_busyness_global.backlog_step);
#endif
}
@@ -195,12 +249,7 @@ int cheaper_busyness_algo(void) {
#ifdef __linux__
} else if (backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
// reset counters
set_next_cheap_time();
uwsgi_cheaper_busyness_global.last_action = 1;
uwsgi_log("[busyness] %d requests in listen queue, spawning emergency worker!\n", backlog);
return 1;
return spawn_emergency_worker(backlog);
#endif
} else if (avg_busyness < uwsgi_cheaper_busyness_global.busyness_min) {
@@ -226,6 +275,9 @@ int cheaper_busyness_algo(void) {
// store information that last action performed was cheaping worker
uwsgi_cheaper_busyness_global.last_action = 2;
if (uwsgi_cheaper_busyness_global.emergency_workers > 0)
uwsgi_cheaper_busyness_global.emergency_workers--;
return -1;
} else if (uwsgi_cheaper_busyness_global.verbose)
uwsgi_log("[busyness] need to wait %d more second(s) to cheap worker\n", (uwsgi_cheaper_busyness_global.next_cheap - now)/1000000);
@@ -235,6 +287,11 @@ int cheaper_busyness_algo(void) {
// with only 1 worker running there is no point in doing all that magic
if (active_workers == 1) return 0;
if (uwsgi_cheaper_busyness_global.emergency_workers > 0)
// we had emergency workers running and we went down to the busyness
// level that is high enough to slow down cheaping workers at extra speed
uwsgi_cheaper_busyness_global.emergency_workers--;
// we have min <= busyness <= max we need to check what happened before
uwsgi_cheaper_busyness_global.tolerance_counter++;
@@ -260,13 +317,7 @@ int cheaper_busyness_algo(void) {
#ifdef __linux__
} else if (backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
// we check for backlog overload every cycle
// reset counters
set_next_cheap_time();
uwsgi_cheaper_busyness_global.last_action = 1;
uwsgi_log("[busyness] %d requests in listen queue, spawning emergency worker!\n", backlog);
return 1;
return spawn_emergency_worker(backlog);
#endif
}
+1 -1
View File
@@ -11,7 +11,7 @@ time_t uwsgi_monotonic_seconds() {
uint64_t uwsgi_monotonic_microseconds() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
return ((uint64_t)ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
}
+1 -1
View File
@@ -2,5 +2,5 @@ NAME='clock_monotonic'
CFLAGS = []
LDFLAGS = []
LIBS = []
LIBS = ['-lrt']
GCC_LIST = ['clock_monotonic']
+1 -1
View File
@@ -11,7 +11,7 @@ time_t uwsgi_realtime_seconds() {
uint64_t uwsgi_realtime_microseconds() {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
}
+1 -1
View File
@@ -2,5 +2,5 @@ NAME='clock_realtime'
CFLAGS = []
LDFLAGS = []
LIBS = []
LIBS = ['-lrt']
GCC_LIST = ['clock_realtime']
+305 -35
View File
@@ -127,7 +127,7 @@ void uwsgi_opt_corerouter_ss(char *opt, char *value, void *cr) {
ucr->has_subscription_sockets++;
// this is the subscription hash table
ucr->subscriptions = uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16);
ucr->subscriptions = uwsgi_subscription_init_ht();
ucr->has_backends++;
@@ -199,6 +199,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se
}
else if (cr_session->timed_out) {
if (cr_session->instance_address_len > 0) {
/*
if (cr_session->status == COREROUTER_STATUS_CONNECTING) {
if (!ucr->quiet)
uwsgi_log("unable to connect() to uwsgi instance \"%.*s\": timeout\n", (int) cr_session->instance_address_len, cr_session->instance_address);
@@ -206,6 +207,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se
else if (cr_session->status == COREROUTER_STATUS_RESPONSE) {
uwsgi_log("timeout waiting for instance \"%.*s\"\n", (int) cr_session->instance_address_len, cr_session->instance_address);
}
*/
}
}
@@ -273,7 +275,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se
ucr->cr_table[cr_session->instance_fd] = cr_session;
cr_session->status = COREROUTER_STATUS_CONNECTING;
//cr_session->status = COREROUTER_STATUS_CONNECTING;
ucr->cr_table[cr_session->instance_fd] = cr_session;
event_queue_add_fd_write(ucr->queue, cr_session->instance_fd);
return;
@@ -297,24 +299,15 @@ end:
free(cr_session->buf_file_name);
}
if (cr_session->write_queue)
free(cr_session->write_queue);
if (cr_session->instance_write_queue)
free(cr_session->instance_write_queue);
// could be used to free additional resources
if (cr_session->close)
cr_session->close(ucr, cr_session);
if (cr_session->keepalive) {
cr_session->keepalive = 0;
return;
}
cr_session->close(cr_session);
close(cr_session->fd);
ucr->cr_table[cr_session->fd] = NULL;
uwsgi_buffer_destroy(cr_session->buffer);
cr_del_timeout(ucr, cr_session);
free(cr_session);
}
@@ -340,7 +333,10 @@ static void corerouter_expire_timeouts(struct uwsgi_corerouter *ucr) {
cr_session->timed_out = 1;
if (cr_session->retry) {
cr_session->retry = 0;
/*
TODO allows retry
ucr->switch_events(ucr, cr_session, -1);
*/
if (cr_session->retry) {
cr_del_timeout(ucr, cr_session);
cr_session->timeout = cr_add_fake_timeout(ucr, cr_session);
@@ -359,23 +355,235 @@ static void corerouter_expire_timeouts(struct uwsgi_corerouter *ucr) {
}
}
int uwsgi_cr_hook_read(struct corerouter_session *cs, ssize_t (*hook)(struct corerouter_session *)) {
struct uwsgi_corerouter *ucr = cs->corerouter;
// first check the case of event removal
if (hook == NULL) {
// nothing changed
if (!cs->event_hook_read) goto unchanged;
// if there is a write event defined, le'ts modify it
if (cs->event_hook_write) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_readwrite_to_write() for %d\n", cs->fd);
#endif
if (event_queue_fd_readwrite_to_write(ucr->queue, cs->fd)) return -1;
}
// simply remove the read event
else {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_del_fd() for %d\n", cs->fd);
#endif
if (event_queue_del_fd(ucr->queue, cs->fd, event_queue_read())) return -1;
}
}
else {
// set the hook
// if write is not defined, simply add a single monitor
if (cs->event_hook_write == NULL) {
if (!cs->event_hook_read) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_add_fd_read() for %d\n", cs->fd);
#endif
if (event_queue_add_fd_read(ucr->queue, cs->fd)) return -1;
}
}
else {
if (!cs->event_hook_read) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_write_to_readwrite() for %d\n", cs->fd);
#endif
if (event_queue_fd_write_to_readwrite(ucr->queue, cs->fd)) return -1;
}
}
}
unchanged:
#ifdef UWSGI_DEBUG
uwsgi_log("event_hook_read set to %p for %d\n", hook, cs->fd);
#endif
cs->event_hook_read = hook;
return 0;
}
int uwsgi_cr_hook_write(struct corerouter_session *cs, ssize_t (*hook)(struct corerouter_session *)) {
struct uwsgi_corerouter *ucr = cs->corerouter;
// first check the case of event removal
if (hook == NULL) {
// nothing changed
if (!cs->event_hook_write) goto unchanged;
// if there is a read event defined, le'ts modify it
if (cs->event_hook_read) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_readwrite_to_read() for %d\n", cs->fd);
#endif
if (event_queue_fd_readwrite_to_read(ucr->queue, cs->fd)) return -1;
}
// simply remove the write event
else {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_del_fd() for %d\n", cs->fd);
#endif
if (event_queue_del_fd(ucr->queue, cs->fd, event_queue_write())) return -1;
}
}
else {
// set the hook
// if read is not defined, simply add a single monitor
if (cs->event_hook_read == NULL) {
if (!cs->event_hook_write) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_add_fd_write() for %d\n", cs->fd);
#endif
if (event_queue_add_fd_write(ucr->queue, cs->fd)) return -1;
}
}
else {
if (!cs->event_hook_write) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_read_to_readwrite() for %d\n", cs->fd);
#endif
if (event_queue_fd_read_to_readwrite(ucr->queue, cs->fd)) return -1;
}
}
}
unchanged:
#ifdef UWSGI_DEBUG
uwsgi_log("event_hook_write set to %p for %d\n", hook, cs->fd);
#endif
cs->event_hook_write = hook;
return 0;
}
int uwsgi_cr_hook_instance_read(struct corerouter_session *cs, ssize_t (*hook)(struct corerouter_session *)) {
struct uwsgi_corerouter *ucr = cs->corerouter;
// first check the case of event removal
if (hook == NULL) {
// nothing changed
if (!cs->event_hook_instance_read) goto unchanged;
// if there is a write event defined, le'ts modify it
if (cs->event_hook_instance_write) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_readwrite_to_write() for %d\n", cs->instance_fd);
#endif
if (event_queue_fd_readwrite_to_write(ucr->queue, cs->instance_fd)) return -1;
}
// simply remove the read event
else {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_del_fd() for %d\n", cs->instance_fd);
#endif
if (event_queue_del_fd(ucr->queue, cs->instance_fd, event_queue_read())) return -1;
}
}
else {
// set the hook
// if write is not defined, simply add a single monitor
if (cs->event_hook_instance_write == NULL) {
if (!cs->event_hook_instance_read) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_add_fd_read() for %d\n", cs->instance_fd);
#endif
if (event_queue_add_fd_read(ucr->queue, cs->instance_fd)) return -1;
}
}
else {
if (!cs->event_hook_instance_read) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_write_to_readwrite() for %d\n", cs->instance_fd);
#endif
if (event_queue_fd_write_to_readwrite(ucr->queue, cs->instance_fd)) return -1;
}
}
}
unchanged:
#ifdef UWSGI_DEBUG
uwsgi_log("event_hook_instance_read set to %p for %d\n", hook, cs->instance_fd);
#endif
cs->event_hook_instance_read = hook;
return 0;
}
int uwsgi_cr_hook_instance_write(struct corerouter_session *cs, ssize_t (*hook)(struct corerouter_session *)) {
struct uwsgi_corerouter *ucr = cs->corerouter;
// first check the case of event removal
if (hook == NULL) {
// nothing changed
if (!cs->event_hook_instance_write) goto unchanged;
// if there is a read event defined, le'ts modify it
if (cs->event_hook_instance_read) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_readwrite_to_read() for %d\n", cs->instance_fd);
#endif
if (event_queue_fd_readwrite_to_read(ucr->queue, cs->instance_fd)) return -1;
}
// simply remove the write event
else {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_del_fd() for %d\n", cs->instance_fd);
#endif
if (event_queue_del_fd(ucr->queue, cs->instance_fd, event_queue_write())) return -1;
}
}
else {
// set the hook
// if read is not defined, simply add a single monitor
if (cs->event_hook_instance_read == NULL) {
if (!cs->event_hook_instance_write) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_add_fd_write() for %d\n", cs->instance_fd);
#endif
if (event_queue_add_fd_write(ucr->queue, cs->instance_fd)) return -1;
}
}
else {
if (!cs->event_hook_instance_write) {
#ifdef UWSGI_DEBUG
uwsgi_log("event_queue_fd_read_to_readwrite() for %d\n", cs->instance_fd);
#endif
if (event_queue_fd_read_to_readwrite(ucr->queue, cs->instance_fd)) return -1;
}
}
}
unchanged:
#ifdef UWSGI_DEBUG
uwsgi_log("event_hook_instance_write set to %p for %d\n", hook, cs->instance_fd);
#endif
cs->event_hook_instance_write = hook;
return 0;
}
struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, int new_connection, struct sockaddr *cr_addr, socklen_t cr_addr_len) {
ucr->cr_table[new_connection] = uwsgi_calloc(ucr->session_size);
ucr->cr_table[new_connection]->fd = new_connection;
ucr->cr_table[new_connection]->instance_fd = -1;
ucr->cr_table[new_connection]->status = COREROUTER_STATUS_RECV_HDR;
ucr->cr_table[new_connection]->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
// map courerouter and socket
ucr->cr_table[new_connection]->corerouter = ucr;
ucr->cr_table[new_connection]->ugs = ugs;
ucr->cr_table[new_connection]->recv = uwsgi_cr_simple_recv;
ucr->cr_table[new_connection]->send = uwsgi_cr_simple_send;
ucr->cr_table[new_connection]->instance_recv = uwsgi_cr_simple_instance_recv;
ucr->cr_table[new_connection]->instance_send = uwsgi_cr_simple_instance_send;
// set initial timeout
ucr->cr_table[new_connection]->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
// create dynamic buffer
ucr->cr_table[new_connection]->buffer = uwsgi_buffer_new(uwsgi.page_size);
// here we prepare the real session and set the hooks
ucr->alloc_session(ucr, ugs, ucr->cr_table[new_connection], cr_addr, cr_addr_len);
event_queue_add_fd_read(ucr->queue, new_connection);
return ucr->cr_table[new_connection];
}
@@ -479,6 +687,9 @@ void uwsgi_corerouter_loop(int id, void *data) {
}
else if (ucr->has_subscription_sockets) {
ucr->mapper = uwsgi_cr_map_use_subscription;
if (uwsgi.subscription_dotsplit) {
ucr->mapper = uwsgi_cr_map_use_subscription_dotsplit;
}
}
else if (ucr->base) {
ucr->mapper = uwsgi_cr_map_use_base;
@@ -501,6 +712,7 @@ void uwsgi_corerouter_loop(int id, void *data) {
for (;;) {
// set timeouts and harakiri
min_timeout = uwsgi_min_rb_timer(ucr->timeouts);
if (min_timeout == NULL) {
delta = -1;
@@ -517,6 +729,7 @@ void uwsgi_corerouter_loop(int id, void *data) {
ushared->gateways_harakiri[id] = 0;
}
// wait for events
nevents = event_queue_wait_multi(ucr->queue, delta, events, ucr->nevents);
if (uwsgi.master_process && ucr->harakiri > 0) {
@@ -529,25 +742,33 @@ void uwsgi_corerouter_loop(int id, void *data) {
for (i = 0; i < nevents; i++) {
// get the interesting fd
interesting_fd = event_queue_interesting_fd(events, i);
// something bad happened
if (interesting_fd < 0) continue;
// check if the interesting_fd matches a gateway socket
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
int taken = 0;
while (ugs) {
if (ugs->gateway == &ushared->gateways[id] && interesting_fd == ugs->fd) {
if (!ugs->subscription) {
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
new_connection = accept4(interesting_fd, (struct sockaddr *) &cr_addr, &cr_addr_len, SOCK_NONBLOCK);
if (new_connection < 0) {
taken = 1;
break;
}
#else
new_connection = accept(interesting_fd, (struct sockaddr *) &cr_addr, &cr_addr_len);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, interesting_fd);
#endif
if (new_connection < 0) {
taken = 1;
break;
}
// set socket in non-blocking mode, on non-linux platforms, clients get the server mode
#ifdef __linux__
uwsgi_socket_nb(new_connection);
#endif
#endif
corerouter_alloc_session(ucr, ugs, new_connection, (struct sockaddr *) &cr_addr, cr_addr_len);
@@ -568,9 +789,11 @@ void uwsgi_corerouter_loop(int id, void *data) {
continue;
}
// manage internal subscription
if (interesting_fd == ushared->gateways[id].internal_subscription_pipe[1]) {
uwsgi_corerouter_manage_internal_subscription(ucr, interesting_fd);
}
// manage a stats request
else if (interesting_fd == ucr->cr_stats_server) {
corerouter_send_stats(ucr);
}
@@ -581,17 +804,56 @@ void uwsgi_corerouter_loop(int id, void *data) {
if (cr_session == NULL)
continue;
// on error, destroy the session
if (event_queue_interesting_fd_has_error(events, i)) {
corerouter_close_session(ucr, cr_session);
continue;
if (interesting_fd == cr_session->instance_fd) {
cr_session->instance_failed = 1;
}
corerouter_close_session(ucr, cr_session);
continue;
}
cr_session->timeout = corerouter_reset_timeout(ucr, cr_session);
// implementation specific cycle;
ucr->switch_events(ucr, cr_session, interesting_fd);
// set timeout
cr_session->timeout = corerouter_reset_timeout(ucr, cr_session);
// call event hook
ssize_t (*hook)(struct corerouter_session *) = NULL;
if (interesting_fd == cr_session->fd) {
if (event_queue_interesting_fd_is_read(events, i)) {
hook = cr_session->event_hook_read;
}
else if (event_queue_interesting_fd_is_write(events, i)) {
hook = cr_session->event_hook_write;
}
}
else if (interesting_fd == cr_session->instance_fd) {
if (event_queue_interesting_fd_is_read(events, i)) {
hook = cr_session->event_hook_instance_read;
}
else if (event_queue_interesting_fd_is_write(events, i)) {
hook = cr_session->event_hook_instance_write;
}
}
if (!hook) {
uwsgi_log("[uwsgi-corerouter] BUG, unexpected event received !!!\n");
corerouter_close_session(ucr, cr_session);
continue;
}
// reset errno (as we use it for internal signalling)
errno = 0;
ssize_t ret = hook(cr_session);
// connection closed
if (ret == 0) {
corerouter_close_session(ucr, cr_session);
continue;
}
else if (ret < 0) {
if (errno == EINPROGRESS) continue;
corerouter_close_session(ucr, cr_session);
continue;
}
}
}
}
@@ -668,14 +930,18 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
socklen_t client_src_len = 0;
int client_fd = accept(ucr->cr_stats_server, (struct sockaddr *) &client_src, &client_src_len);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, ucr->cr_stats_server);
#endif
if (client_fd < 0) {
uwsgi_error("accept()");
return;
}
if (uwsgi.stats_http) {
if (uwsgi_send_http_stats(client_fd)) {
close(client_fd);
return;
}
}
struct uwsgi_stats *us = uwsgi_stats_new(8192);
if (uwsgi_stats_keyval_comma(us, "version", UWSGI_VERSION)) goto end;
@@ -773,6 +1039,10 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
size_t remains = us->pos;
off_t pos = 0;
while(remains > 0) {
int ret = uwsgi_waitfd_write(client_fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret <= 0) {
goto end0;
}
ssize_t res = write(client_fd, us->base + pos, remains);
if (res <= 0) {
if (res < 0) {
+31 -31
View File
@@ -9,6 +9,12 @@
#define cr_del_check_timeout(x) rb_erase(&x->rbt, timeouts);
#define cr_del_timeout(u, x) rb_erase(&x->timeout->rbt, u->timeouts); free(x->timeout);
#define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\
errno = EINPROGRESS;\
return -1;\
}
struct corerouter_session;
struct uwsgi_corerouter {
@@ -19,7 +25,6 @@ struct uwsgi_corerouter {
void (*alloc_session)(struct uwsgi_corerouter *, struct uwsgi_gateway_socket *, struct corerouter_session *, struct sockaddr *, socklen_t);
int (*mapper)(struct uwsgi_corerouter *, struct corerouter_session *);
void (*switch_events)(struct uwsgi_corerouter *, struct corerouter_session *, int);
int has_sockets;
int has_backends;
@@ -60,7 +65,6 @@ struct uwsgi_corerouter {
int use_cluster;
struct uwsgi_subscribe_slot **subscriptions;
int subscription_regexp;
struct uwsgi_string_list *fallback;
@@ -87,13 +91,13 @@ struct corerouter_session {
int fd;
int instance_fd;
int instance_stopped;
int status;
uint8_t h_pos;
uint16_t pos;
// corerouter related to this session
struct uwsgi_corerouter *corerouter;
// gateway socket related to this session
struct uwsgi_gateway_socket *ugs;
// parsed hostname
char *hostname;
uint16_t hostname_len;
@@ -109,13 +113,10 @@ struct corerouter_session {
int soopt;
int timed_out;
// used for tracking required event
int fd_state;
int instance_fd_state;
struct uwsgi_rb_timer *timeout;
int instance_failed;
// check content_length
size_t post_cl;
size_t post_remains;
@@ -124,30 +125,29 @@ struct corerouter_session {
char *buf_file_name;
FILE *buf_file;
uint8_t modifier1;
uint8_t modifier2;
char *tmp_socket_name;
// store the client address
struct sockaddr_un addr;
socklen_t addr_len;
int keepalive;
// async hooks:
// the session is watiting for this fd
ssize_t (*event_hook_read)(struct corerouter_session *);
ssize_t (*event_hook_write)(struct corerouter_session *);
ssize_t (*event_hook_instance_read)(struct corerouter_session *);
ssize_t (*event_hook_instance_write)(struct corerouter_session *);
char *write_queue;
size_t write_queue_len;
int write_queue_close;
void (*close)(struct corerouter_session *);
char *instance_write_queue;
size_t instance_write_queue_len;
struct uwsgi_buffer *buffer;
size_t buffer_len;
off_t buffer_pos;
void (*close)(struct uwsgi_corerouter *, struct corerouter_session *);
ssize_t (*recv)(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
ssize_t (*send)(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
ssize_t (*instance_recv)(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
ssize_t (*instance_send)(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
struct uwsgi_header uh;
uint8_t modifier1;
uint8_t modifier2;
};
void uwsgi_opt_corerouter(char *, char *, void *);
@@ -175,6 +175,7 @@ int uwsgi_cr_map_use_cache(struct uwsgi_corerouter *, struct corerouter_session
int uwsgi_cr_map_use_pattern(struct uwsgi_corerouter *, struct corerouter_session *);
int uwsgi_cr_map_use_cluster(struct uwsgi_corerouter *, struct corerouter_session *);
int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *, struct corerouter_session *);
int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *, struct corerouter_session *);
int uwsgi_cr_map_use_base(struct uwsgi_corerouter *, struct corerouter_session *);
int uwsgi_cr_map_use_cs(struct uwsgi_corerouter *, struct corerouter_session *);
int uwsgi_cr_map_use_to(struct uwsgi_corerouter *, struct corerouter_session *);
@@ -182,8 +183,7 @@ int uwsgi_cr_map_use_static_nodes(struct uwsgi_corerouter *, struct corerouter_s
int uwsgi_courerouter_has_has_backends(struct uwsgi_corerouter *);
ssize_t uwsgi_cr_simple_recv(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
ssize_t uwsgi_cr_simple_send(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
ssize_t uwsgi_cr_simple_instance_recv(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
ssize_t uwsgi_cr_simple_instance_send(struct uwsgi_corerouter *, struct corerouter_session *, char *, size_t);
int uwsgi_cr_hook_read(struct corerouter_session *, ssize_t (*)(struct corerouter_session *));
int uwsgi_cr_hook_write(struct corerouter_session *, ssize_t (*)(struct corerouter_session *));
int uwsgi_cr_hook_instance_read(struct corerouter_session *, ssize_t (*)(struct corerouter_session *));
int uwsgi_cr_hook_instance_write(struct corerouter_session *, ssize_t (*)(struct corerouter_session *));
+23 -213
View File
@@ -10,197 +10,6 @@ extern struct uwsgi_server uwsgi;
#include "cr.h"
ssize_t uwsgi_cr_simple_recv(struct uwsgi_corerouter *uc, struct corerouter_session *cs, char *buf, size_t len) {
ssize_t ret = recv(cs->fd, buf, len, 0);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
errno = EINPROGRESS;
return -1;
}
uwsgi_error("recv()");
}
return ret;
}
ssize_t uwsgi_cr_simple_instance_recv(struct uwsgi_corerouter *uc, struct corerouter_session *cs, char *buf, size_t len) {
ssize_t ret = recv(cs->instance_fd, buf, len, 0);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
errno = EINPROGRESS;
return -1;
}
uwsgi_error("recv()");
}
return ret;
}
ssize_t uwsgi_cr_simple_send(struct uwsgi_corerouter *uc, struct corerouter_session *cs, char *buf, size_t len) {
ssize_t ret = -1;
char *tmp_buf;
off_t pos = 0;
size_t partial_len = len;
off_t partial_pos = 0;
if (cs->write_queue_len > 0) {
ret = send(cs->fd, cs->write_queue, cs->write_queue_len, 0);
if (ret > 0) {
cs->write_queue_len-=ret;
pos = ret;
if (cs->write_queue_len == 0) {
free(cs->write_queue);
cs->write_queue = NULL;
if (cs->fd_state) {
event_queue_fd_write_to_read(uc->queue, cs->fd);
cs->fd_state = 0;
}
goto next;
}
goto blocking;
}
else if (ret == 0) {
return 0;
}
else {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto blocking;
}
uwsgi_error("send()");
return -1;
}
}
next:
if (len == 0) goto end;
ret = send(cs->fd, buf, len, 0);
if (ret > 0) {
if ((size_t)ret == len) return len;
partial_len-=ret;
partial_pos = ret;
goto blocking;
}
if (ret == 0) {
return 0;
}
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto blocking;
}
uwsgi_error("send()");
return -1;
end:
if (cs->write_queue_close) {
return 0;
}
return ret;
blocking:
// wait for write
if (!cs->fd_state) {
event_queue_fd_read_to_write(uc->queue, cs->fd);
cs->fd_state = 1;
}
// add new datas to the buffer
tmp_buf = malloc(cs->write_queue_len+partial_len);
if (!tmp_buf) {
uwsgi_error("malloc()");
return -1;
}
if (cs->write_queue_len>0) {
memcpy(tmp_buf, cs->write_queue+pos, cs->write_queue_len);
free(cs->write_queue);
}
memcpy(tmp_buf+cs->write_queue_len, buf+partial_pos, partial_len);
cs->write_queue = tmp_buf;
cs->write_queue_len+=partial_len;
errno = EINPROGRESS;
return -1;
}
ssize_t uwsgi_cr_simple_instance_send(struct uwsgi_corerouter *uc, struct corerouter_session *cs, char *buf, size_t len) {
ssize_t ret;
char *tmp_buf;
off_t pos = 0;
size_t partial_len = len;
off_t partial_pos = 0;
if (cs->instance_write_queue_len > 0) {
ret = send(cs->instance_fd, cs->instance_write_queue, cs->instance_write_queue_len, 0);
if (ret > 0) {
cs->instance_write_queue_len-=ret;
pos=ret;
if (cs->instance_write_queue_len == 0) {
free(cs->instance_write_queue);
cs->instance_write_queue = NULL;
if (cs->instance_fd_state) {
event_queue_fd_write_to_read(uc->queue, cs->instance_fd);
cs->instance_fd_state = 0;
}
goto next;
}
goto blocking;
}
else if (ret == 0) {
return 0;
}
else {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto blocking;
}
uwsgi_error("send()");
return -1;
}
}
next:
ret = send(cs->instance_fd, buf, len, 0);
if (ret > 0) {
if ((size_t)ret == len) return len;
partial_len-=ret;
partial_pos = ret;
goto blocking;
}
if (ret == 0) {
return 0;
}
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto blocking;
}
uwsgi_error("send()");
return -1;
blocking:
// wait for write
if (!cs->instance_fd_state) {
event_queue_fd_read_to_write(uc->queue, cs->instance_fd);
cs->instance_fd_state = 1;
}
// add new datas to the buffer
tmp_buf = malloc(cs->instance_write_queue_len+partial_len);
if (!tmp_buf) {
uwsgi_error("malloc()");
return -1;
}
if (cs->instance_write_queue_len>0) {
memcpy(tmp_buf, cs->instance_write_queue+pos, cs->instance_write_queue_len);
free(cs->instance_write_queue);
}
memcpy(tmp_buf+cs->instance_write_queue_len, buf+partial_pos, partial_len);
cs->instance_write_queue = tmp_buf;
cs->instance_write_queue_len+=partial_len;
errno = EINPROGRESS;
return -1;
}
void uwsgi_corerouter_setup_sockets(struct uwsgi_corerouter *ucr) {
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
@@ -208,24 +17,24 @@ void uwsgi_corerouter_setup_sockets(struct uwsgi_corerouter *ucr) {
if (!strcmp(ucr->name, ugs->owner)) {
if (!ugs->subscription) {
if (ugs->name[0] == '=') {
int shared_socket = atoi(ugs->name+1);
if (shared_socket >= 0) {
ugs->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket);
int shared_socket = atoi(ugs->name + 1);
if (shared_socket >= 0) {
ugs->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket);
ugs->shared = 1;
if (ugs->fd == -1) {
uwsgi_log("unable to use shared socket %d\n", shared_socket);
if (ugs->fd == -1) {
uwsgi_log("unable to use shared socket %d\n", shared_socket);
exit(1);
}
}
ugs->name = uwsgi_getsockname(ugs->fd);
}
}
}
else if (!uwsgi_startswith("fd://", ugs->name, 5 )) {
int fd_socket = atoi(ugs->name+5);
else if (!uwsgi_startswith("fd://", ugs->name, 5)) {
int fd_socket = atoi(ugs->name + 5);
if (fd_socket >= 0) {
ugs->fd = fd_socket;
ugs->name = uwsgi_getsockname(ugs->fd);
if (!ugs->name) {
uwsgi_log("unable to use file descriptor %d as socket\n", fd_socket);
uwsgi_log("unable to use file descriptor %d as socket\n", fd_socket);
exit(1);
}
}
@@ -250,7 +59,12 @@ void uwsgi_corerouter_setup_sockets(struct uwsgi_corerouter *ucr) {
else if (ugs->subscription) {
if (ugs->fd == -1) {
if (strchr(ugs->name, ':')) {
#ifdef UWSGI_UDP
ugs->fd = bind_to_udp(ugs->name, 0, 0);
#else
uwsgi_log("uWSGI has been built without UDP support !!!\n");
exit(1);
#endif
}
else {
ugs->fd = bind_to_unix_dgram(ugs->name);
@@ -290,9 +104,6 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
char bbuf[4096];
ssize_t len = recv(ugs->fd, bbuf, 4096, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, ugs->fd);
#endif
if (len > 0) {
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr);
@@ -304,7 +115,7 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
// subscribe request ?
if (bbuf[3] == 0) {
if (uwsgi_add_subscribe_node(ucr->subscriptions, &usr, ucr->subscription_regexp) && ucr->i_am_cheap) {
if (uwsgi_add_subscribe_node(ucr->subscriptions, &usr) && ucr->i_am_cheap) {
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
while (ugs) {
if (!strcmp(ugs->owner, ucr->name) && !ugs->subscription) {
@@ -318,12 +129,14 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
}
//unsubscribe
else {
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, ucr->subscription_regexp);
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len);
if (node && node->len) {
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
if (usr.sign_len == 0 || usr.base_len == 0) return;
if (usr.unix_check <= node->unix_check) return ;
if (usr.sign_len == 0 || usr.base_len == 0)
return;
if (usr.unix_check <= node->unix_check)
return;
if (!uwsgi_subscription_sign_check(node->slot, &usr)) {
return;
}
@@ -364,16 +177,13 @@ void uwsgi_corerouter_manage_internal_subscription(struct uwsgi_corerouter *ucr,
char bbuf[4096];
ssize_t len = recv(fd, bbuf, 4096, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, fd);
#endif
if (len > 0) {
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr);
// subscribe request ?
if (bbuf[3] == 0) {
if (uwsgi_add_subscribe_node(ucr->subscriptions, &usr, ucr->subscription_regexp) && ucr->i_am_cheap) {
if (uwsgi_add_subscribe_node(ucr->subscriptions, &usr) && ucr->i_am_cheap) {
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
while (ugs) {
if (!strcmp(ugs->owner, ucr->name) && !ugs->subscription) {
@@ -387,7 +197,7 @@ void uwsgi_corerouter_manage_internal_subscription(struct uwsgi_corerouter *ucr,
}
//unsubscribe
else {
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, ucr->subscription_regexp);
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len);
if (node && node->len) {
if (node->death_mark == 0)
uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", ucr->name, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address);
+37 -1
View File
@@ -31,7 +31,7 @@ int uwsgi_cr_map_use_pattern(struct uwsgi_corerouter *ucr, struct corerouter_ses
int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) {
cr_session->un = uwsgi_get_subscribe_node(ucr->subscriptions, cr_session->hostname, cr_session->hostname_len, ucr->subscription_regexp);
cr_session->un = uwsgi_get_subscribe_node(ucr->subscriptions, cr_session->hostname, cr_session->hostname_len);
if (cr_session->un && cr_session->un->len) {
cr_session->instance_address = cr_session->un->name;
cr_session->instance_address_len = cr_session->un->len;
@@ -44,6 +44,38 @@ int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct coreroute
return 0;
}
int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) {
char *name = cr_session->hostname;
uint16_t name_len = cr_session->hostname_len;
split:
#ifdef UWSGI_DEBUG
uwsgi_log("trying with %.*s\n", name_len, name);
#endif
cr_session->un = uwsgi_get_subscribe_node(ucr->subscriptions, name, name_len);
if (!cr_session->un) {
char *next = memchr(name+1, '.', name_len-1);
if (next) {
name_len -= next - name;
name = next;
goto split;
}
}
if (cr_session->un && cr_session->un->len) {
cr_session->instance_address = cr_session->un->name;
cr_session->instance_address_len = cr_session->un->len;
cr_session->modifier1 = cr_session->un->modifier1;
}
else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) {
uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap);
}
return 0;
}
int uwsgi_cr_map_use_base(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) {
int tmp_socket_name_len = 0;
@@ -80,10 +112,14 @@ int uwsgi_cr_map_use_to(struct uwsgi_corerouter *ucr, struct corerouter_session
}
int uwsgi_cr_map_use_cluster(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) {
#ifdef UWSGI_MULTICAST
cr_session->instance_address = uwsgi_cluster_best_node();
if (cr_session->instance_address) {
cr_session->instance_address_len = strlen(cr_session->instance_address);
}
#else
uwsgi_log("uWSGI has been built without multicast/clustering support !!!\n");
#endif
return 0;
}
+69
View File
@@ -0,0 +1,69 @@
#include "../../uwsgi.h"
extern struct uwsgi_server uwsgi;
// global variables for configuration
static uint8_t dumbloop_modifier1 = 0;
static char *dumbloop_code = "";
static char *dumbloop_function = "dumbloop";
struct uwsgi_option dumbloop_options[] = {
{"dumbloop-modifier1", required_argument, 0, "set the modifier1 for the code_string", uwsgi_opt_set_int, &dumbloop_modifier1, 0},
{"dumbloop-code", required_argument, 0, "set the script to load for the code_string", uwsgi_opt_set_str, &dumbloop_code, 0},
{"dumbloop-function", required_argument, 0, "set the function to run for the code_string", uwsgi_opt_set_str, &dumbloop_function, 0},
{0, 0, 0, 0, 0, 0, 0},
};
// this function is executed for each thread
static void *dumb_loop_run(void *arg1) {
// get the core id (pthreads take a void pointer as argument, so we need this ugly trick)
long core_id = (long) arg1;
#ifdef UWSGI_THREADING
// complete threads setup (this is required for fixing things like UNIX signal handling)
if (uwsgi.threads > 1) {
// wsgi_request mapped to the core
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req;
// fix it
uwsgi_setup_thread_req(core_id, wsgi_req);
}
#endif
// this strign will be passed to the code_string function
char *str_core = uwsgi_num2str(core_id);
// ok we are ready, let's run custom code
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
if (uwsgi.p[dumbloop_modifier1]->code_string) {
// "uwsgi_dumbloop" is the name of the module (will be used while importing the file, if needed)
uwsgi.p[dumbloop_modifier1]->code_string("uwsgi_dumbloop", dumbloop_code, dumbloop_function, str_core, strlen(str_core));
}
else {
uwsgi_log("the requested plugin does not support code_string hook\n");
exit(1);
}
}
return NULL;
}
static void dumb_loop() {
// this run the dumb_loop_run in each thread (core)
uwsgi_loop_cores_run(dumb_loop_run);
}
// register the new loop engine
static void dumbloop_register() {
uwsgi_register_loop( (char *) "dumb", dumb_loop);
}
struct uwsgi_plugin dumbloop_plugin = {
.name = "dumbloop",
.on_load = dumbloop_register,
.options = dumbloop_options,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='dumbloop'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['dumb']
+121
View File
@@ -0,0 +1,121 @@
#include "../../uwsgi.h"
#include "client/dbclient.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_instance *ui;
// one for each mongodb imperial monitor
struct uwsgi_emperor_mongodb_state {
char *address;
char *collection;
char *json;
};
extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues) {
struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data;
try {
// requested fields
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 );
mongo::BSONObj q = mongo::fromjson(uems->json);
// the connection object (will be automatically destroyed at each cycle)
mongo::DBClientConnection c;
// set the socket timeout
c.setSoTimeout(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
// connect
c.connect(uems->address);
// run the query
std::auto_ptr<mongo::DBClientCursor> cursor = c.query(uems->collection, q, 0, 0, &p);
while( cursor->more() ) {
mongo::BSONObj p = cursor->next();
// checking for an empty string is not required, but we reduce the load
// in case of badly strctured databases
const char *name = p.getStringField("name");
if (strlen(name) == 0) continue;
const char *config = p.getStringField("config");
time_t vassal_ts = 0;
// ts must be a Date object !!!
mongo::BSONElement ts = p.getField("ts");
if (ts.type() == mongo::Date) {
vassal_ts = ts.date();
}
uid_t vassal_uid = 0;
gid_t vassal_gid = 0;
// check for tyrant mode
if (uwsgi.emperor_tyrant) {
int tmp_uid = p.getIntField("uid");
int tmp_gid = p.getIntField("gid");
if (tmp_uid < 0) tmp_uid = 0;
if (tmp_gid < 0) tmp_gid = 0;
vassal_uid = tmp_uid;
vassal_gid = tmp_gid;
}
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid);
}
// now check for removed instances
struct uwsgi_instance *c_ui = ui->ui_next;
while (c_ui) {
if (c_ui->scanner == ues) {
mongo::BSONObjBuilder b;
b.appendElements(q);
b.append("name", c_ui->name);
mongo::BSONObj q2 = b.obj();
cursor = c.query(uems->collection, q2, 0, 0, &p);
#ifdef UWSGI_DEBUG
uwsgi_log("JSON: %s\n", q2.toString().c_str());
#endif
if (!cursor->more()) {
emperor_stop(c_ui);
}
}
c_ui = c_ui->ui_next;
}
}
catch ( mongo::DBException &e ) {
uwsgi_log("[emperor-mongodb] ERROR(%s/%s): %s\n", uems->address, uems->collection, e.what());
}
}
// setup a new mongodb imperial monitor
extern "C" void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *ues) {
// allocate a new state
ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state));
size_t arg_len = strlen(ues->arg);
struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data;
// parse args/ set defaults
uems->address = (char *) "127.0.0.1:27017";
uems->collection = (char *) "uwsgi.emperor.vassals";
uems->json = (char *) "";
if (arg_len > 10) {
uems->address = uwsgi_str(ues->arg+10);
char *comma = strchr(uems->address, ',');
if (!comma) goto done;
*comma = 0;
uems->collection = comma+1;
comma = strchr(uems->collection, ',');
if (!comma) goto done;
*comma = 0;
uems->json = comma+1;
}
done:
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
}
+14
View File
@@ -0,0 +1,14 @@
#include "../../uwsgi.h"
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
void emperor_mongodb_init(void) {
uwsgi_register_imperial_monitor("mongodb", uwsgi_imperial_monitor_mongodb_init, uwsgi_imperial_monitor_mongodb);
}
struct uwsgi_plugin emperor_mongodb_plugin = {
.name = "emperor_mongodb",
.on_load = emperor_mongodb_init,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='emperor_mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = ['-lmongoclient', '-lboost_thread','-lboost_filesystem']
GCC_LIST = ['plugin', 'emperor_mongodb.cc']
+1 -35
View File
@@ -7,7 +7,6 @@ extern struct uwsgi_instance *ui;
void uwsgi_imperial_monitor_pg_init(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *);
void emperor_pg_init(void);
void emperor_pg_do(struct uwsgi_emperor_scanner *, char *, char *, time_t, uid_t, gid_t);
void emperor_pg_init(void) {
uwsgi_register_imperial_monitor("pg", uwsgi_imperial_monitor_pg_init, uwsgi_imperial_monitor_pg);
@@ -17,39 +16,6 @@ void uwsgi_imperial_monitor_pg_init(struct uwsgi_emperor_scanner *ues) {
uwsgi_log("[emperor] enabled emperor PostgreSQL monitor\n");
}
void emperor_pg_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid) {
if (!uwsgi_emperor_is_valid(name))
return;
struct uwsgi_instance *ui_current = emperor_get(name);
if (ui_current) {
// check if uid or gid are changed, in such case, stop the instance
if (uwsgi.emperor_tyrant) {
if (uid != ui_current->uid || gid != ui_current->gid) {
uwsgi_log("[emperor-tyrant] !!! permissions of vassal %s changed. stopping the instance... !!!\n", name);
emperor_stop(ui_current);
return;
}
}
// check if mtime is changed and the uWSGI instance must be reloaded
if (ts > ui_current->last_mod) {
// make a new config (free the old one)
free(ui_current->config);
ui_current->config = config;
ui_current->config_len = strlen(config);
// always respawn (no need for amqp-style rules)
emperor_respawn(ui_current, ts);
}
}
else {
// make a copy of the config as it will be freed
emperor_add(ues, name, ts, uwsgi_str(config), strlen(config), uid, gid);
}
}
void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *ues) {
PGconn *conn = NULL;
@@ -102,7 +68,7 @@ void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *ues) {
vassal_uid = uwsgi_str_num(q_uid, strlen(q_uid));
vassal_gid = uwsgi_str_num(q_gid, strlen(q_gid));
}
emperor_pg_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid);
uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid);
}
}
+2 -2
View File
@@ -244,7 +244,7 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
}
void erlang_loop(int id) {
void erlang_loop(int id, void *data) {
ErlConnect econn;
//ErlMessage em;
@@ -422,7 +422,7 @@ int erlang_init() {
uwsgi_log("Erlang C-Node %s registered on port %d\n", ei_thisnodename(&uerl.cnode), ntohs(sin.sin_port));
if (register_gateway("uWSGI erlang c-node", erlang_loop) == NULL) {
if (register_gateway("uWSGI erlang c-node", erlang_loop, NULL) == NULL) {
uwsgi_log("unable to register the erlang gateway\n");
exit(1);
}
+300 -16
View File
@@ -2,35 +2,37 @@
uWSGI fastrouter
requires:
- async
- caching
- pcre (optional)
*/
#include "../../uwsgi.h"
#include "../corerouter/cr.h"
struct uwsgi_fastrouter {
struct uwsgi_corerouter cr;
} ufr;
extern struct uwsgi_server uwsgi;
#include "fr.h"
struct uwsgi_fastrouter ufr;
struct fastrouter_session {
struct corerouter_session crs;
struct uwsgi_buffer *post_buf;
size_t post_buf_max;
size_t post_buf_len;
off_t post_buf_pos;
};
struct uwsgi_option fastrouter_options[] = {
{"fastrouter", required_argument, 0, "run the fastrouter on the specified port", uwsgi_opt_corerouter, &ufr, 0},
{"fastrouter-processes", required_argument, 0, "prefork the specified number of fastrouter processes", uwsgi_opt_set_int, &ufr.cr.processes, 0},
{"fastrouter-workers", required_argument, 0, "prefork the specified number of fastrouter processes", uwsgi_opt_set_int, &ufr.cr.processes, 0},
{"fastrouter-zerg", required_argument, 0, "attach the fastrouter to a zerg server", uwsgi_opt_corerouter_zerg, &ufr, 0 },
{"fastrouter-zerg", required_argument, 0, "attach the fastrouter to a zerg server", uwsgi_opt_corerouter_zerg, &ufr, 0},
{"fastrouter-use-cache", no_argument, 0, "use uWSGI cache as hostname->server mapper for the fastrouter", uwsgi_opt_true, &ufr.cr.use_cache, 0},
{"fastrouter-use-pattern", required_argument, 0, "use a pattern for fastrouter hostname->server mapping", uwsgi_opt_corerouter_use_pattern, &ufr, 0},
{"fastrouter-use-base", required_argument, 0, "use a base dir for fastrouter hostname->server mapping", uwsgi_opt_corerouter_use_base, &ufr, 0},
{"fastrouter-fallback", required_argument, 0, "fallback to the specified node in case of error", uwsgi_opt_add_string_list, &ufr.cr.fallback, 0},
{"fastrouter-use-cluster", no_argument, 0, "load balance to nodes subscribed to the cluster", uwsgi_opt_true, &ufr.cr.use_cluster, 0},
{"fastrouter-use-code-string", required_argument, 0, "use code string as hostname->server mapper for the fastrouter", uwsgi_opt_corerouter_cs, &ufr, 0},
@@ -42,7 +44,6 @@ struct uwsgi_option fastrouter_options[] = {
{"fastrouter-cheap", no_argument, 0, "run the fastrouter in cheap mode", uwsgi_opt_true, &ufr.cr.cheap, 0},
{"fastrouter-subscription-server", required_argument, 0, "run the fastrouter subscription server on the spcified address", uwsgi_opt_corerouter_ss, &ufr, 0},
{"fastrouter-subscription-slot", required_argument, 0, "*** deprecated ***", uwsgi_opt_deprecated, (void *) "useless thanks to the new implementation", 0},
{"fastrouter-subscription-use-regexp", no_argument, 0, "enable regexp for subscription system", uwsgi_opt_true, &ufr.cr.subscription_regexp, 0},
{"fastrouter-timeout", required_argument, 0, "set fastrouter timeout", uwsgi_opt_set_int, &ufr.cr.socket_timeout, 0},
{"fastrouter-post-buffering", required_argument, 0, "enable fastrouter post buffering", uwsgi_opt_set_64bit, &ufr.cr.post_buffering, 0},
@@ -51,19 +52,302 @@ struct uwsgi_option fastrouter_options[] = {
{"fastrouter-stats", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
{"fastrouter-stats-server", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
{"fastrouter-ss", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
{"fastrouter-harakiri", required_argument, 0, "enable fastrouter harakiri", uwsgi_opt_set_int, &ufr.cr.harakiri, 0 },
{"fastrouter-harakiri", required_argument, 0, "enable fastrouter harakiri", uwsgi_opt_set_int, &ufr.cr.harakiri, 0},
{0, 0, 0, 0, 0, 0, 0},
};
ssize_t fr_recv_uwsgi_header(struct corerouter_session *);
ssize_t fr_instance_read_response(struct corerouter_session *);
ssize_t fr_read_body(struct corerouter_session *);
void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
// here i use directly corerouter_session
struct corerouter_session *cs = (struct corerouter_session *) data;
//uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
if (!uwsgi_strncmp("SERVER_NAME", 11, key, keylen) && !cs->hostname_len) {
cs->hostname = val;
cs->hostname_len = vallen;
return;
}
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen) && !cs->has_key) {
cs->hostname = val;
cs->hostname_len = vallen;
return;
}
if (!uwsgi_strncmp("UWSGI_FASTROUTER_KEY", 20, key, keylen)) {
cs->has_key = 1;
cs->hostname = val;
cs->hostname_len = vallen;
return;
}
if (!uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) {
cs->post_cl = uwsgi_str_num(val, vallen);
return;
}
}
ssize_t fr_write_body(struct corerouter_session * cs) {
struct fastrouter_session *fs = (struct fastrouter_session *) cs;
ssize_t len = write(cs->instance_fd, fs->post_buf->buf + fs->post_buf_pos, fs->post_buf_len - fs->post_buf_pos);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_write_body()");
return -1;
}
fs->post_buf_pos += len;
// the body chunk has been sent, start again reading from client and instance
if (fs->post_buf_pos == (ssize_t) fs->post_buf_len) {
uwsgi_cr_hook_instance_write(cs, NULL);
uwsgi_cr_hook_instance_read(cs, fr_instance_read_response);
uwsgi_cr_hook_read(cs, fr_read_body);
}
return len;
}
ssize_t fr_read_body(struct corerouter_session * cs) {
struct fastrouter_session *fs = (struct fastrouter_session *) cs;
ssize_t len = read(cs->fd, fs->post_buf->buf, fs->post_buf_max);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_read_body()");
return -1;
}
// connection closed
if (len == 0)
return 0;
fs->post_buf_len = len;
fs->post_buf_pos = 0;
// ok we have a body, stop reading from the client and the instance and start writing to the instance
uwsgi_cr_hook_read(cs, NULL);
uwsgi_cr_hook_instance_read(cs, NULL);
uwsgi_cr_hook_instance_write(cs, fr_write_body);
return len;
}
ssize_t fr_write_response(struct corerouter_session * cs) {
ssize_t len = write(cs->fd, cs->buffer->buf + cs->buffer_pos, cs->buffer_len - cs->buffer_pos);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_write_response()");
return -1;
}
cs->buffer_pos += len;
// ok this response chunk is sent, let's wait for another one
if (cs->buffer_pos == (ssize_t) cs->buffer_len) {
uwsgi_cr_hook_write(cs, NULL);
uwsgi_cr_hook_instance_read(cs, fr_instance_read_response);
}
return len;
}
ssize_t fr_instance_read_response(struct corerouter_session * cs) {
ssize_t len = read(cs->instance_fd, cs->buffer->buf, cs->buffer->len);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_instance_read_response()");
return -1;
}
// end of the response
if (len == 0) {
return 0;
}
cs->buffer_pos = 0;
cs->buffer_len = len;
// ok stop reading from the instance, and start writing to the client
uwsgi_cr_hook_instance_read(cs, NULL);
uwsgi_cr_hook_write(cs, fr_write_response);
return len;
}
ssize_t fr_instance_send_request(struct corerouter_session * cs) {
ssize_t len = write(cs->instance_fd, cs->buffer->buf + cs->buffer_pos, cs->uh.pktsize - cs->buffer_pos);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_instance_send_request()");
return -1;
}
cs->buffer_pos += len;
// ok the request is sent, we can start sending client body (if any) and we can start waiting
// for response
if (cs->buffer_pos == cs->uh.pktsize) {
cs->buffer_pos = 0;
// stop writing to the instance
uwsgi_cr_hook_instance_write(cs, NULL);
// start reading from the instance
uwsgi_cr_hook_instance_read(cs, fr_instance_read_response);
// re-start reading from the client (for body or connection close)
struct fastrouter_session *fs = (struct fastrouter_session *) cs;
// allocate a buffer for client body (could be delimited or dynamic)
fs->post_buf_max = UMAX16;
if (cs->post_cl > 0) {
fs->post_buf_max = UMIN(UMAX16, cs->post_cl);
}
fs->post_buf = uwsgi_buffer_new(fs->post_buf_max);
if (!fs->post_buf)
return -1;
uwsgi_cr_hook_read(cs, fr_read_body);
}
return len;
}
ssize_t fr_instance_send_request_header(struct corerouter_session * cs) {
ssize_t len = write(cs->instance_fd, &cs->uh + cs->buffer_pos, 4 - cs->buffer_pos);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_instance_send_request_header()");
return -1;
}
cs->buffer_pos += len;
// ok the request is sent, we can start sending client body (if any) and we can start waiting
// for response
if (cs->buffer_pos == 4) {
cs->buffer_pos = 0;
uwsgi_cr_hook_instance_write(cs, fr_instance_send_request);
}
return len;
}
ssize_t fr_instance_connected(struct corerouter_session * cs) {
socklen_t solen = sizeof(int);
// first check for errors
if (getsockopt(cs->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&cs->soopt), &solen) < 0) {
uwsgi_error("fr_instance_connected()/getsockopt()");
cs->instance_failed = 1;
return -1;
}
if (cs->soopt) {
cs->instance_failed = 1;
return -1;
}
cs->buffer_pos = 0;
// ok instance is connected, wait for write again
if (cs->un) cs->un->requests++;
uwsgi_cr_hook_instance_write(cs, fr_instance_send_request_header);
// return a value > 0
return 1;
}
ssize_t fr_recv_uwsgi_vars(struct corerouter_session * cs) {
// increase buffer if needed
if (uwsgi_buffer_fix(cs->buffer, cs->uh.pktsize))
return -1;
ssize_t len = read(cs->fd, cs->buffer->buf + cs->buffer_pos, cs->uh.pktsize - cs->buffer_pos);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_recv_uwsgi_vars()");
return -1;
}
cs->buffer_pos += len;
// headers received, ready to choose the instance
if (cs->buffer_pos == cs->uh.pktsize) {
struct uwsgi_corerouter *ucr = cs->corerouter;
// find the hostname
if (uwsgi_hooked_parse(cs->buffer->buf, cs->uh.pktsize, fr_get_hostname, (void *) cs)) {
return -1;
}
// check the hostname;
if (cs->hostname_len == 0)
return -1;
// find an instance using the key
if (cs->corerouter->mapper(cs->corerouter, cs))
return -1;
// check instance
if (cs->instance_address_len == 0) {
// if fallback nodes are configured, trigger them
if (ucr->fallback) {
cs->instance_failed = 1;
}
return -1;
}
// stop receiving from the client
uwsgi_cr_hook_read(cs, NULL);
// start async connect
cs->instance_fd = uwsgi_connectn(cs->instance_address, cs->instance_address_len, 0, 1);
if (cs->instance_fd < 0) {
cs->instance_failed = 1;
cs->soopt = errno;
return -1;
}
// map the instance
cs->corerouter->cr_table[cs->instance_fd] = cs;
// wait for connection
uwsgi_cr_hook_instance_write(cs, fr_instance_connected);
}
return len;
}
ssize_t fr_recv_uwsgi_header(struct corerouter_session * cs) {
ssize_t len = read(cs->fd, cs->buffer->buf + cs->buffer_pos, 4 - cs->buffer_pos);
if (len < 0) {
cr_try_again;
uwsgi_error("fr_recv_uwsgi_header()");
return -1;
}
cs->buffer_pos += len;
// header ready
if (cs->buffer_pos == 4) {
memcpy(&cs->uh, cs->buffer->buf, 4);
cs->buffer_pos = 0;
uwsgi_cr_hook_read(cs, fr_recv_uwsgi_vars);
}
return len;
}
void fr_session_close(struct corerouter_session *cs) {
struct fastrouter_session *fr = (struct fastrouter_session *) cs;
if (fr->post_buf) {
uwsgi_buffer_destroy(fr->post_buf);
}
}
void fastrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) {
cs->close = fr_session_close;
// set the first hook
uwsgi_cr_hook_read(cs, fr_recv_uwsgi_header);
}
int fastrouter_init() {
ufr.cr.session_size = sizeof(struct fastrouter_session);
ufr.cr.switch_events = uwsgi_fastrouter_switch_events;
ufr.cr.alloc_session = fastrouter_alloc_session;
uwsgi_corerouter_init((struct uwsgi_corerouter *) &ufr);
uwsgi_corerouter_init((struct uwsgi_corerouter *) &ufr);
return 0;
}
-20
View File
@@ -1,20 +0,0 @@
#include "../corerouter/cr.h"
#define FASTROUTER_STATUS_RECV_VARS 10
#define FASTROUTER_STATUS_BUFFERING 11
struct uwsgi_fastrouter {
struct uwsgi_corerouter cr;
};
struct fastrouter_session {
struct corerouter_session crs;
struct uwsgi_header uh;
char buffer[UMAX16];
};
void uwsgi_fastrouter_switch_events(struct uwsgi_corerouter *, struct corerouter_session *, int interesting_fd);
-356
View File
@@ -1,356 +0,0 @@
#include "../../uwsgi.h"
#include "fr.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_fastrouter ufr;
void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
// here i use directly corerouter_session
struct corerouter_session *fr_session = (struct corerouter_session *) data;
//uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
if (!uwsgi_strncmp("SERVER_NAME", 11, key, keylen) && !fr_session->hostname_len) {
fr_session->hostname = val;
fr_session->hostname_len = vallen;
return;
}
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen) && !fr_session->has_key) {
fr_session->hostname = val;
fr_session->hostname_len = vallen;
return;
}
if (!uwsgi_strncmp("UWSGI_FASTROUTER_KEY", 20, key, keylen)) {
fr_session->has_key = 1;
fr_session->hostname = val;
fr_session->hostname_len = vallen;
return;
}
if (ufr.cr.post_buffering > 0) {
if (!uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) {
fr_session->post_cl = uwsgi_str_num(val, vallen);
return;
}
}
}
void uwsgi_fastrouter_switch_events(struct uwsgi_corerouter *ucr, struct corerouter_session *cs, int interesting_fd) {
struct fastrouter_session *fr_session = (struct fastrouter_session *) cs;
socklen_t solen = sizeof(int);
struct iovec iov[2];
struct msghdr msg;
union {
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(int))];
} msg_control;
struct cmsghdr *cmsg;
ssize_t len;
char *post_tmp_buf[UMAX16];
switch (cs->status) {
case COREROUTER_STATUS_RECV_HDR:
len = recv(cs->fd, (char *) (&fr_session->uh) + cs->h_pos, 4 - cs->h_pos, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, cs->fd);
#endif
if (len <= 0) {
if (len < 0)
uwsgi_error("recv()");
corerouter_close_session(ucr, cs);
break;
}
cs->h_pos += len;
if (cs->h_pos == 4) {
#ifdef UWSGI_DEBUG
uwsgi_log("modifier1: %d pktsize: %d modifier2: %d\n", fr_session->uh.modifier1, fr_session->uh.pktsize, fr_session->uh.modifier2);
#endif
cs->status = FASTROUTER_STATUS_RECV_VARS;
}
break;
case FASTROUTER_STATUS_RECV_VARS:
if (interesting_fd == -1) {
goto choose_node;
}
len = recv(cs->fd, fr_session->buffer + cs->pos, fr_session->uh.pktsize - cs->pos, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, cs->fd);
#endif
if (len <= 0) {
uwsgi_error("recv()");
corerouter_close_session(ucr, cs);
break;
}
cs->pos += len;
if (cs->pos == fr_session->uh.pktsize) {
if (uwsgi_hooked_parse(fr_session->buffer, fr_session->uh.pktsize, fr_get_hostname, (void *) fr_session)) {
corerouter_close_session(ucr, cs);
break;
}
if (cs->hostname_len == 0) {
corerouter_close_session(ucr, cs);
break;
}
// the mapper hook
choose_node:
if (ucr->mapper(ucr, cs))
break;
// no address found
if (!cs->instance_address_len) {
// if fallback nodes are configured, trigger them
if (ucr->fallback) {
cs->instance_failed = 1;
}
corerouter_close_session(ucr, cs);
break;
}
if (ucr->post_buffering > 0 && cs->post_cl > ucr->post_buffering) {
cs->status = FASTROUTER_STATUS_BUFFERING;
cs->buf_file_name = uwsgi_tmpname(ucr->pb_base_dir, "uwsgiXXXXX");
if (!cs->buf_file_name) {
uwsgi_error("tempnam()");
corerouter_close_session(ucr, cs);
break;
}
cs->post_remains = cs->post_cl;
// 2 + UWSGI_POSTFILE + 2 + cs->buf_file_name
if (fr_session->uh.pktsize + (2 + 14 + 2 + strlen(cs->buf_file_name)) > UMAX16) {
uwsgi_log("unable to buffer request body to file %s: not enough space\n", cs->buf_file_name);
corerouter_close_session(ucr, cs);
break;
}
char *ptr = fr_session->buffer + fr_session->uh.pktsize;
uint16_t bfn_len = strlen(cs->buf_file_name);
*ptr++ = 14;
*ptr++ = 0;
memcpy(ptr, "UWSGI_POSTFILE", 14);
ptr += 14;
*ptr++ = (char) (bfn_len & 0xff);
*ptr++ = (char) ((bfn_len >> 8) & 0xff);
memcpy(ptr, cs->buf_file_name, bfn_len);
fr_session->uh.pktsize += 2 + 14 + 2 + bfn_len;
cs->buf_file = fopen(cs->buf_file_name, "w");
if (!cs->buf_file) {
uwsgi_error_open(cs->buf_file_name);
corerouter_close_session(ucr, cs);
break;
}
}
else {
cs->pass_fd = is_unix(cs->instance_address, cs->instance_address_len);
cs->instance_fd = uwsgi_connectn(cs->instance_address, cs->instance_address_len, 0, 1);
if (cs->instance_fd < 0) {
cs->instance_failed = 1;
cs->soopt = errno;
corerouter_close_session(ucr, cs);
break;
}
cs->status = COREROUTER_STATUS_CONNECTING;
ucr->cr_table[cs->instance_fd] = cs;
event_queue_add_fd_write(ucr->queue, cs->instance_fd);
}
}
break;
case COREROUTER_STATUS_CONNECTING:
if (interesting_fd == cs->instance_fd) {
if (getsockopt(cs->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&cs->soopt), &solen) < 0) {
uwsgi_error("getsockopt()");
cs->instance_failed = 1;
corerouter_close_session(ucr, cs);
break;
}
if (cs->soopt) {
cs->instance_failed = 1;
corerouter_close_session(ucr, cs);
break;
}
fr_session->uh.modifier1 = cs->modifier1;
iov[0].iov_base = &fr_session->uh;
iov[0].iov_len = 4;
iov[1].iov_base = fr_session->buffer;
iov[1].iov_len = fr_session->uh.pktsize;
// increment node requests counter
if (cs->un)
cs->un->requests++;
// fd passing: PERFORMANCE EXTREME BOOST !!!
if (cs->pass_fd && !uwsgi.no_fd_passing) {
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 2;
msg.msg_flags = 0;
msg.msg_control = &msg_control;
msg.msg_controllen = sizeof(msg_control);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmsg), &cs->fd, sizeof(int));
if (sendmsg(cs->instance_fd, &msg, 0) < 0) {
uwsgi_error("sendmsg()");
}
corerouter_close_session(ucr, cs);
break;
}
if (writev(cs->instance_fd, iov, 2) < 0) {
uwsgi_error("writev()");
corerouter_close_session(ucr, cs);
break;
}
event_queue_fd_write_to_read(ucr->queue, cs->instance_fd);
cs->status = COREROUTER_STATUS_RESPONSE;
}
break;
case COREROUTER_STATUS_RESPONSE:
// data from instance
if (interesting_fd == cs->instance_fd) {
len = recv(cs->instance_fd, fr_session->buffer, UMAX16, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, cs->instance_fd);
#endif
if (len <= 0) {
if (len < 0)
uwsgi_error("recv()");
corerouter_close_session(ucr, cs);
break;
}
len = send(cs->fd, fr_session->buffer, len, 0);
if (len <= 0) {
if (len < 0)
uwsgi_error("send()");
corerouter_close_session(ucr, cs);
break;
}
// update transfer statistics
if (cs->un)
cs->un->transferred += len;
}
// body from client
else if (interesting_fd == cs->fd) {
//uwsgi_log("receiving body...\n");
len = recv(cs->fd, fr_session->buffer, UMAX16, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, cs->fd);
#endif
if (len <= 0) {
if (len < 0)
uwsgi_error("recv()");
corerouter_close_session(ucr, cs);
break;
}
len = send(cs->instance_fd, fr_session->buffer, len, 0);
if (len <= 0) {
if (len < 0)
uwsgi_error("send()");
corerouter_close_session(ucr, cs);
break;
}
}
break;
case FASTROUTER_STATUS_BUFFERING:
len = recv(cs->fd, post_tmp_buf, UMIN(UMAX16, cs->post_remains), 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(ucr->queue, cs->fd);
#endif
if (len <= 0) {
if (len < 0)
uwsgi_error("recv()");
corerouter_close_session(ucr, cs);
break;
}
if (fwrite(post_tmp_buf, len, 1, cs->buf_file) != 1) {
uwsgi_error("fwrite()");
corerouter_close_session(ucr, cs);
break;
}
cs->post_remains -= len;
if (cs->post_remains == 0) {
// close the buf_file ASAP
fclose(cs->buf_file);
cs->buf_file = NULL;
cs->pass_fd = is_unix(cs->instance_address, cs->instance_address_len);
cs->instance_fd = uwsgi_connectn(cs->instance_address, cs->instance_address_len, 0, 1);
if (cs->instance_fd < 0) {
cs->instance_failed = 1;
corerouter_close_session(ucr, cs);
break;
}
cs->status = COREROUTER_STATUS_CONNECTING;
ucr->cr_table[cs->instance_fd] = cs;
event_queue_add_fd_write(ucr->queue, cs->instance_fd);
}
break;
// fallback to destroy !!!
default:
uwsgi_log("unknown event: closing session\n");
corerouter_close_session(ucr, cs);
break;
}
}
+3 -1
View File
@@ -4,4 +4,6 @@ CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['fastrouter', 'fr_events']
REQUIRES = ['corerouter']
GCC_LIST = ['fastrouter']
+2 -2
View File
@@ -15,7 +15,7 @@ VALUE uwsgi_fiber_request() {
return Qnil;
}
inline static void fiber_schedule_to_req() {
static inline void fiber_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
@@ -33,7 +33,7 @@ inline static void fiber_schedule_to_req() {
}
inline static void fiber_schedule_to_main(struct wsgi_request *wsgi_req) {
static inline void fiber_schedule_to_main(struct wsgi_request *wsgi_req) {
rb_fiber_yield(0, NULL);
uwsgi.wsgi_req = wsgi_req;
+10 -7
View File
@@ -1,27 +1,30 @@
import os
NAME='fiber'
try:
RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH']
except:
RUBYPATH = 'ruby'
NAME='fiber'
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
CFLAGS.append('-Wno-unused-parameter')
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['CFLAGS']\"").read().rstrip().split()
CFLAGS.append('-DRUBY19')
CFLAGS.append('-Wno-unused-parameter')
rbconfig = 'RbConfig'
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
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 Config::CONFIG['archdir']\"").read().rstrip()
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 Config::CONFIG['archdir']\"").read().rstrip()
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['arch']\"").read().rstrip()
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)
LDFLAGS = []
LIBS = []
+234 -7
View File
@@ -10,6 +10,10 @@ extern struct uwsgi_python up;
if (ret) { Py_DECREF(ret); }\
ret = PyObject_CallMethod(watcher, "stop", NULL);\
if (ret) { Py_DECREF(ret); }
#define stop_the_watchers_and_clear stop_the_watchers\
Py_DECREF(current); Py_DECREF(current_greenlet);\
Py_DECREF(watcher);\
Py_DECREF(timer);
struct uwsgi_gevent {
@@ -32,6 +36,9 @@ void uwsgi_opt_setup_gevent(char *opt, char *value, void *null) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 30;
}
// set loop engine
uwsgi.loop = "gevent";
@@ -173,9 +180,13 @@ edge:
goto edge;
}
goto clear;
}
// on linux we need to set the socket in non-blocking as it is not inherited
#ifdef __linux__
uwsgi_socket_nb(wsgi_req->poll.fd);
#endif
// hack to easily pass wsgi_req pointer to the greenlet
PyTuple_SetItem(ugevent.greenlet_args, 1, PyLong_FromLong((long)wsgi_req));
@@ -195,6 +206,210 @@ clear:
return Py_None;
}
ssize_t uwsgi_gevent_hook_input_read(struct wsgi_request *wsgi_req, char *tmp_buf, size_t remains, size_t *tmp_pos) {
/// create a watcher for reads
PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 1);
if (!watcher) return -1;
PyObject *timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (!timer) {
Py_DECREF(watcher);
return -1;
}
PyObject *current_greenlet = GET_CURRENT_GREENLET;
PyObject *current = PyObject_GetAttrString(current_greenlet, "switch");
while(remains) {
PyObject *ret = PyObject_CallMethod(watcher, "start", "OO", current, watcher);
if (!ret) {
stop_the_watchers_and_clear
return -1;
}
Py_DECREF(ret);
ret = PyObject_CallMethod(timer, "start", "OO", current, timer);
if (!ret) {
stop_the_watchers_and_clear
return -1;
}
Py_DECREF(ret);
ret = PyObject_CallMethod(ugevent.hub, "switch", NULL);
wsgi_req->switches++;
if (!ret) {
stop_the_watchers_and_clear
return -1;
}
Py_DECREF(ret);
if (ret == timer) {
stop_the_watchers_and_clear
return 0;
}
UWSGI_RELEASE_GIL;
ssize_t rlen = read(wsgi_req->poll.fd, tmp_buf+*tmp_pos, remains);
if (rlen <= 0) {
UWSGI_GET_GIL
stop_the_watchers_and_clear
return -1;
}
*tmp_pos += rlen;
remains -= rlen;
UWSGI_GET_GIL
stop_the_watchers
}
return *tmp_pos;
}
ssize_t uwsgi_gevent_hook_input_readline(struct wsgi_request *wsgi_req, char *readline, size_t max_size) {
ssize_t rlen = 0;
/// create a watcher for reads
PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 1);
if (!watcher) return -1;
PyObject *timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (!timer) {
Py_DECREF(watcher);
return -1;
}
PyObject *current_greenlet = GET_CURRENT_GREENLET;
PyObject *current = PyObject_GetAttrString(current_greenlet, "switch");
PyObject *ret = PyObject_CallMethod(watcher, "start", "OO", current, watcher);
if (!ret) {
stop_the_watchers_and_clear
return -1;
}
Py_DECREF(ret);
ret = PyObject_CallMethod(timer, "start", "OO", current, timer);
if (!ret) {
stop_the_watchers_and_clear
return -1;
}
Py_DECREF(ret);
ret = PyObject_CallMethod(ugevent.hub, "switch", NULL);
wsgi_req->switches++;
if (!ret) {
stop_the_watchers_and_clear
return -1;
}
Py_DECREF(ret);
if (ret == timer) {
stop_the_watchers_and_clear
return 0;
}
UWSGI_RELEASE_GIL;
if (max_size > 0 && max_size < UWSGI_PY_READLINE_BUFSIZE) {
rlen = read(wsgi_req->poll.fd, readline, max_size);
}
else {
rlen = read(wsgi_req->poll.fd, readline, UWSGI_PY_READLINE_BUFSIZE);
}
UWSGI_GET_GIL;
stop_the_watchers_and_clear
return rlen;
}
void uwsgi_gevent_nb_write(struct wsgi_request *wsgi_req, PyObject *str) {
PyObject *ret;
char *content = PyString_AsString(str);
size_t content_len = PyString_Size(str);
/// create a watcher for writes
PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 2);
if (!watcher) goto error;
PyObject *timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (!timer) {
Py_DECREF(watcher);
goto error;
}
PyObject *current_greenlet = GET_CURRENT_GREENLET;
PyObject *current = PyObject_GetAttrString(current_greenlet, "switch");
char *ptr = content;
size_t remains = content_len;
// this is the main writing cycle, wait for writability and send...
for(;;) {
ret = PyObject_CallMethod(watcher, "start", "OO", current, watcher);
if (!ret) {
stop_the_watchers_and_clear
goto error;
}
Py_DECREF(ret);
ret = PyObject_CallMethod(timer, "start", "OO", current, timer);
if (!ret) {
stop_the_watchers_and_clear
goto error;
}
Py_DECREF(ret);
ret = PyObject_CallMethod(ugevent.hub, "switch", NULL);
wsgi_req->switches++;
if (!ret) {
stop_the_watchers_and_clear
goto error;
}
Py_DECREF(ret);
if (ret == timer) {
goto fail;
}
// ok we can write a chunk to the socket
UWSGI_RELEASE_GIL
ssize_t len = write(wsgi_req->poll.fd, ptr, remains);
UWSGI_GET_GIL
if (len > 0) {
ptr += len;
remains -= len;
wsgi_req->response_size += len;
if (remains == 0) {
break;
}
stop_the_watchers
continue;
}
else if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
stop_the_watchers
continue;
}
}
fail:
stop_the_watchers_and_clear
goto error;
}
stop_the_watchers
Py_DECREF(current); Py_DECREF(current_greenlet);
Py_DECREF(watcher);
Py_DECREF(timer);
return ;
error:
if (PyErr_Occurred())
PyErr_Print();
wsgi_req->write_errors++;
}
PyObject *uwsgi_gevent_wait(PyObject *watcher, PyObject *timer, PyObject *current) {
PyObject *ret;
@@ -237,7 +452,7 @@ PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) {
watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 1);
if (!watcher) goto clear1;
// a timer to implement timeoit (thanks Denis)
// a timer to implement timeout (thanks Denis)
timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (!timer) goto clear0;
@@ -246,6 +461,7 @@ PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) {
for(;;) {
// wait for data in the socket
ret = uwsgi_gevent_wait(watcher, timer, greenlet_switch);
wsgi_req->switches++;
if (!ret) goto clear_and_stop;
// we can safely decref here as watcher and timer has got a +1 for start() method
@@ -316,6 +532,13 @@ PyMethodDef uwsgi_gevent_my_signal_def[] = { {"uwsgi_gevent_my_signal", py_uwsgi
PyMethodDef uwsgi_gevent_signal_handler_def[] = { {"uwsgi_gevent_signal_handler", py_uwsgi_gevent_signal_handler, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_unix_signal_handler_def[] = { {"uwsgi_gevent_unix_signal_handler", py_uwsgi_gevent_graceful, METH_VARARGS, ""} };
void gil_gevent_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
void gil_gevent_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
void gevent_loop() {
@@ -323,12 +546,15 @@ void gevent_loop() {
uwsgi_log("!!! Running gevent without threads IS NOT recommended, enable them with --enable-threads !!!\n");
}
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
uwsgi_log("!!! Running gevent with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
}
// get the GIL
UWSGI_GET_GIL
// ..then reset GIL subsystem as noop (gevent IO will take care of it...)
up.gil_get = gil_fake_get;
up.gil_release = gil_fake_release;
up.gil_get = gil_gevent_get;
up.gil_release = gil_gevent_release;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
@@ -338,6 +564,9 @@ void gevent_loop() {
}
uwsgi.current_wsgi_req = uwsgi_gevent_current_wsgi_req;
up.hook_write_string = uwsgi_gevent_nb_write;
up.hook_wsgi_input_read = uwsgi_gevent_hook_input_read;
up.hook_wsgi_input_readline = uwsgi_gevent_hook_input_readline;
PyObject *gevent_dict = get_uwsgi_pydict("gevent");
if (!gevent_dict) uwsgi_pyexit;
@@ -350,8 +579,6 @@ void gevent_loop() {
exit(1);
}
ugevent.spawn = PyDict_GetItemString(gevent_dict, "spawn");
if (!ugevent.spawn) uwsgi_pyexit;
+110
View File
@@ -0,0 +1,110 @@
#include "../../uwsgi.h"
extern struct uwsgi_server uwsgi;
void (*uwsgi_go_helper_post_fork_c)();
void (*uwsgi_go_helper_post_init_c)();
void * (*uwsgi_go_helper_env_new_c)(struct wsgi_request *);
void (*uwsgi_go_helper_env_add_c)(void *, char *, int, char *, int);
void (*uwsgi_go_helper_request_c)(void *, struct wsgi_request *);
int (*uwsgi_go_helper_signal_handler_c)(int, void *);
void (*uwsgi_go_helper_run_core_c)(int);
void uwsgi_go_post_fork() {
uwsgi_go_helper_post_fork_c();
}
void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
// set loop engine
uwsgi.loop = "goroutines";
}
struct uwsgi_option uwsgi_go_options[] = {
{"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
#define uwsgi_go_get_symbol(x) x ## _c = dlsym(RTLD_DEFAULT, #x);\
if (!x ## _c) {\
uwsgi_log("[uwsgi-go] unable to load " #x " function\n"); exit(1);\
}
int uwsgi_go_init() {
// build the functions table
uwsgi_go_get_symbol(uwsgi_go_helper_post_fork)
uwsgi_go_get_symbol(uwsgi_go_helper_post_init)
uwsgi_go_get_symbol(uwsgi_go_helper_env_new)
uwsgi_go_get_symbol(uwsgi_go_helper_env_add)
uwsgi_go_get_symbol(uwsgi_go_helper_request)
uwsgi_go_get_symbol(uwsgi_go_helper_signal_handler)
uwsgi_go_get_symbol(uwsgi_go_helper_run_core)
// call PostInit()
uwsgi_go_helper_post_init_c();
return 0;
}
int uwsgi_go_request(struct wsgi_request *wsgi_req) {
/* Standard GO request */
if (!wsgi_req->uh.pktsize) {
uwsgi_log("Invalid GO request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
wsgi_req->async_environ = uwsgi_go_helper_env_new_c(wsgi_req);
int i;
for(i=0;i<wsgi_req->var_cnt;i++) {
uwsgi_go_helper_env_add_c(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
i++;
}
uwsgi_go_helper_request_c(wsgi_req->async_environ, wsgi_req);
return UWSGI_OK;
}
void uwsgi_go_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
int uwsgi_go_signal_handler(uint8_t signum, void *handler) {
return uwsgi_go_helper_signal_handler_c((int)signum, handler);
}
void goroutines_loop() {
int i;
for (i = 1; i < uwsgi.async; i++) {
uwsgi_go_helper_run_core_c(i);
}
simple_loop_run_int(0);
}
void uwsgi_go_on_load() {
uwsgi_register_loop("goroutines", goroutines_loop);
}
struct uwsgi_plugin go_plugin = {
.name = "go",
.modifier1 = 11,
.request = uwsgi_go_request,
.after_request = uwsgi_go_after_request,
.post_fork = uwsgi_go_post_fork,
.init = uwsgi_go_init,
.signal_handler = uwsgi_go_signal_handler,
.on_load = uwsgi_go_on_load,
.options = uwsgi_go_options,
};
+402
View File
@@ -0,0 +1,402 @@
/*
uWSGI go integration package
*/
package uwsgi
/*
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
// commodity functions to simulate argc/argv
static char ** uwsgi_go_helper_create_argv(int len) {
return uwsgi_calloc(sizeof(char *) * len);
}
static void uwsgi_go_helper_set_argv(char **argv, int pos, char *item) {
argv[pos] = item;
}
*/
import "C"
import (
"os"
"net/http"
"net/http/cgi"
"unsafe"
"strings"
"strconv"
"io"
)
// this stores the modifier used by the go plugin (default 11)
var uwsgi_modifier1 int = -1;
// the following to objects are used to implement a sort of GC to avoid request environ and
// signal handlers to be garbage collected
var uwsgi_env_gc = make(map[*C.struct_wsgi_request](*map[string]string))
var uwsgi_signals_gc = make([]*func(int), 256)
var uwsgi_default_handler func(http.ResponseWriter, *http.Request) = nil
var uwsgi_post_fork_hook func() = nil
var uwsgi_post_init_hook func() = nil
/*
uWSGI api functions
*/
// raise a uWSGI signal
func Signal(signum int) {
if C.uwsgi.master_process == 0 {
return
}
C.uwsgi_signal_send(C.uwsgi.signal_socket, C.uint8_t(signum))
}
// set a user lock
func Lock(num int) {
C.uwsgi_user_lock(C.int(num));
}
// unset a user lock
func Unlock(num int) {
C.uwsgi_user_unlock(C.int(num));
}
// add a timer
func AddTimer(signum int, seconds int) bool {
if C.uwsgi.master_process == 0 {
return false
}
if int(C.uwsgi_add_timer(C.uint8_t(signum), C.int(seconds))) == 0 {
return true
}
return false
}
// add a red black timer
func AddRbTimer(signum int, seconds int) bool {
if C.uwsgi.master_process == 0 {
return false
}
if int(C.uwsgi_signal_add_rb_timer(C.uint8_t(signum), C.int(seconds), C.int(0))) == 0 {
return true
}
return false
}
// check if a signal is registered
func SignalRegistered(signum int) bool {
if C.uwsgi.master_process == 0 {
return false
}
if int(C.uwsgi_signal_registered(C.uint8_t(signum))) == 0 {
return false
}
return true
}
// register a signal
func RegisterSignal(signum int, who string, handler func(int)) bool {
if C.uwsgi.master_process == 0 {
return false
}
if uwsgi_modifier1 == -1 {
c_go := C.CString("go")
defer C.free(unsafe.Pointer(c_go))
uwsgi_modifier1 = int(C.uwsgi_plugin_modifier1(c_go))
if uwsgi_modifier1 == -1 {
return false
}
}
c_who := C.CString(who)
defer C.free(unsafe.Pointer(c_who))
if int(C.uwsgi_register_signal(C.uint8_t(signum), c_who, unsafe.Pointer(&handler), C.uint8_t(uwsgi_modifier1))) == 0 {
uwsgi_signals_gc[signum] = &handler
return true
}
return false
}
// get an item from the cache
func CacheGet(key string) []byte {
if int(C.uwsgi_cache_enabled()) == 0 {
return nil
}
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
var vl C.uint64_t = C.uint64_t(0)
C.uwsgi_cache_rlock()
c_value := C.uwsgi_cache_get(k, C.uint16_t(kl), &vl)
var p []byte
if vl > 0 {
p = C.GoBytes((unsafe.Pointer)(c_value), C.int(vl))
} else {
p = nil
}
C.uwsgi_cache_rwunlock()
return p
}
// remove an intem from the cache
func CacheDel(key string) bool {
if int(C.uwsgi_cache_enabled()) == 0 {
return false
}
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
C.uwsgi_cache_wlock()
if int(C.uwsgi_cache_del(k, C.uint16_t(kl), C.uint64_t(0))) < 0 {
C.uwsgi_cache_rwunlock();
return false;
}
C.uwsgi_cache_rwunlock();
return true
}
// check if an item exists in the cache
func CacheExists(key string) bool {
if int(C.uwsgi_cache_enabled()) == 0 {
return false
}
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
C.uwsgi_cache_rlock()
if int(C.uwsgi_cache_exists(k, C.uint16_t(kl))) > 0 {
C.uwsgi_cache_rwunlock();
return true;
}
C.uwsgi_cache_rwunlock();
return false
}
// put an item in the cache
func CacheSetFlags(key string, p []byte, expires uint64, flags int) bool {
if int(C.uwsgi_cache_enabled()) == 0 {
return false
}
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
v := unsafe.Pointer(&p[0])
vl := len(p)
C.uwsgi_cache_wlock()
if int(C.uwsgi_cache_set(k, C.uint16_t(kl), (*C.char)(v), C.uint64_t(vl), C.uint64_t(expires), C.uint16_t(flags))) < 0 {
C.uwsgi_cache_rwunlock();
return false;
}
C.uwsgi_cache_rwunlock();
return true
}
func CacheSet(key string, p []byte, expires uint64) bool {
return CacheSetFlags(key, p, expires, 0);
}
func CacheUpdate(key string, p []byte, expires uint64) bool {
return CacheSetFlags(key, p, expires, 2);
}
// get the current worker id
func WorkerId() int {
return int(C.uwsgi.mywid)
}
// get the current mule id
func MuleId() int {
return int(C.uwsgi.muleid)
}
// get the current logsize (if available)
func LogSize() int64 {
return int64(C.uwsgi.shared.logsize)
}
func PostFork(hook func()) {
uwsgi_post_fork_hook = hook
}
func PostInit(hook func()) {
uwsgi_post_init_hook = hook
}
func RequestHandler(hook func(http.ResponseWriter, *http.Request)) {
uwsgi_default_handler = hook
}
/*
C -> go and go -> C bridges
*/
//export uwsgi_go_helper_post_fork
func uwsgi_go_helper_post_fork() {
if uwsgi_post_fork_hook != nil {
uwsgi_post_fork_hook()
}
}
//export uwsgi_go_helper_post_init
func uwsgi_go_helper_post_init() {
if uwsgi_post_init_hook != nil {
uwsgi_post_init_hook()
}
}
//export uwsgi_go_helper_env_new
func uwsgi_go_helper_env_new(wsgi_req *C.struct_wsgi_request) *map[string]string {
var env map[string]string
env = make(map[string]string)
// track env to avoid it being garbage collected...
uwsgi_env_gc[wsgi_req] = &env
return &env
}
//export uwsgi_go_helper_env_add
func uwsgi_go_helper_env_add(env *map[string]string, k *C.char, kl C.int, v *C.char, vl C.int) {
var mk string = C.GoStringN(k, kl)
var mv string = C.GoStringN(v, vl)
(*env)[mk] = mv
}
/*
http.* implementations
*/
type ResponseWriter struct {
r *http.Request
wsgi_req *C.struct_wsgi_request
headers http.Header
wroteHeader bool
headers_chunk string
}
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
m := len(p)
C.uwsgi_simple_response_write(w.wsgi_req, (*C.char)(unsafe.Pointer(&p[0])), C.size_t(m))
return m+n, err
}
func (w *ResponseWriter) WriteHeader(status int) {
proto := "HTTP/1.0"
if w.r.ProtoAtLeast(1, 1) {
proto = "HTTP/1.1"
}
codestring := http.StatusText(status)
w.headers_chunk += proto + " " + strconv.Itoa(status) + " " + codestring + "\r\n"
C.uwsgi_simple_set_status(w.wsgi_req, C.int(status))
if w.headers.Get("Content-Type") == "" {
w.headers.Set("Content-Type", "text/html; charset=utf-8")
}
for k := range w.headers {
for _, v := range w.headers[k] {
v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v)
v = strings.TrimSpace(v)
w.headers_chunk += k + ": " + v + "\r\n"
C.uwsgi_simple_inc_headers(w.wsgi_req)
}
}
w.headers_chunk += "\r\n"
c_h_chunk := C.CString(w.headers_chunk)
defer C.free(unsafe.Pointer(c_h_chunk))
C.uwsgi_simple_response_write_header(w.wsgi_req, c_h_chunk, C.size_t(len(w.headers_chunk)))
w.wroteHeader = true
}
func (w *ResponseWriter) Header() http.Header {
return w.headers
}
type BodyReader struct {
wsgi_req *C.struct_wsgi_request
}
// there is no close in request body
func (br *BodyReader) Close() error {
return nil
}
func (br *BodyReader) Read(p []byte) (n int, err error) {
m := len(p)
rlen := int(C.uwsgi_simple_request_read(br.wsgi_req, (*C.char)(unsafe.Pointer(&p[0])), C.size_t(m)))
if rlen < 0 {
err = io.ErrUnexpectedEOF
rlen = 0
} else if rlen == 0 {
err = io.EOF
}
return rlen, err
}
//export uwsgi_go_helper_request
func uwsgi_go_helper_request(env *map[string]string, wsgi_req *C.struct_wsgi_request) {
httpReq, err := cgi.RequestFromMap(*env)
if err != nil {
} else {
httpReq.Body = &BodyReader{wsgi_req}
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false, ""}
if uwsgi_default_handler != nil {
uwsgi_default_handler(&w, httpReq)
} else {
http.DefaultServeMux.ServeHTTP(&w, httpReq)
}
}
}
//export uwsgi_go_helper_signal_handler
func uwsgi_go_helper_signal_handler(signum int, handler *func(int)) int {
(*handler)(signum)
return 0;
}
//export uwsgi_go_helper_run_core
func uwsgi_go_helper_run_core(core_id int) {
go C.simple_loop_run_int(C.int(core_id))
}
/*
the main function, running the uWSGI server via libuwsgi.so
*/
func Run() {
argc := len(os.Args)
argv := C.uwsgi_go_helper_create_argv(C.int(argc))
for i, s := range os.Args {
C.uwsgi_go_helper_set_argv(argv, C.int(i), C.CString(s))
}
C.uwsgi_init(C.int(argc), argv, nil)
}
+28
View File
@@ -0,0 +1,28 @@
import os
NAME='go'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['go_plugin']
def post_build(config):
os.environ['GOPATH'] = 'plugins/go'
cflags = ['-I'+os.getcwd()]
for c in config.cflags:
if not c.startswith('-DUWSGI_BUILD_DATE') and not c.startswith('-DUWSGI_CFLAGS'):
cflags.append(c)
cflags.append('-Wno-implicit-function-declaration')
cflags.append('-Wno-implicit-int')
cflags.append('-Wno-unused-function')
cflags.append('-Wno-unused-variable')
os.environ['CGO_CFLAGS'] = ' '.join(cflags).replace('\\"', '')
base = os.path.dirname(config.get('bin_name'))
if not base:
base = "."
os.environ['CGO_LDFLAGS'] = '-L' + base + ' -L'+os.getcwd() + ' -luwsgi'
if os.system("go install uwsgi") != 0:
os._exit(1)
print("*** uwsgi go module available in $GOPATH %s/plugins/go ***" % os.getcwd())
+2 -2
View File
@@ -28,7 +28,7 @@ PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
PyMethodDef uwsgi_greenlet_request_method[] = {{"uwsgi_greenlet_request", py_uwsgi_greenlet_request, METH_VARARGS, ""}};
inline static void greenlet_schedule_to_req() {
static inline void greenlet_schedule_to_req() {
int id = uwsgi.wsgi_req->async_id;
@@ -45,7 +45,7 @@ inline static void greenlet_schedule_to_req() {
}
inline static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
static inline void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
PyGreenlet_Switch(ugl.main, NULL, NULL);
uwsgi.wsgi_req = wsgi_req;
+782 -741
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -4,4 +4,6 @@ CFLAGS = []
LDFLAGS = []
LIBS = []
REQUIRES = ['corerouter']
GCC_LIST = ['http']
+31
View File
@@ -0,0 +1,31 @@
#include "../../uwsgi.h"
ssize_t uwsgi_file_logger(struct uwsgi_logger *ul, char *message, size_t len) {
if (!ul->configured) {
if (ul->arg) {
ul->fd = open(ul->arg, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (ul->fd >= 0) {
ul->configured = 1;
}
}
}
if (ul->fd >= 0) {
return write(ul->fd, message, len);
}
return 0;
}
void uwsgi_file_logger_register() {
uwsgi_register_logger("file", uwsgi_file_logger);
}
struct uwsgi_plugin logfile_plugin = {
.name = "logfile",
.on_load = uwsgi_file_logger_register,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='logfile'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['logfile']
+27 -60
View File
@@ -13,6 +13,8 @@ struct uwsgi_lua {
} ulua;
#define lca(L, n) ulua_check_args(L, __FUNCTION__, n)
#define response_append(x, y) if (uwsgi_buffer_append(status_and_headers, x, y)) { uwsgi_buffer_destroy(status_and_headers); lua_pushvalue(L, -1); goto clear;}
#define response_append_header(x, y) if (uwsgi_buffer_append(status_and_headers, x, y)) { uwsgi_buffer_destroy(status_and_headers); lua_pop(L, 2); lua_pushvalue(L, -1); goto clear;}
struct uwsgi_option uwsgi_lua_options[] = {
@@ -391,7 +393,6 @@ void uwsgi_lua_app() {
int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
int i;
int raw;
const char *http;
size_t slen;
ssize_t rlen;
@@ -467,38 +468,24 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
//uwsgi_log("%d %s %s %s\n",i,lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) , lua_typename(L, lua_type(L, -1)));
raw = 0;
// this buffer will contains the whole headers (+status)
struct uwsgi_buffer *status_and_headers = uwsgi_buffer_new(4096);
// send status
if (lua_type(L, -3) == LUA_TSTRING || lua_type(L, -3) == LUA_TNUMBER) {
http = lua_tolstring(L, -3, &slen);
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len)) != wsgi_req->protocol_len) {
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, " ", 1)) != 1) {
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
// a performance hack
ptrbuf = (char *) http;
ptrbuf[3] = 0;
wsgi_req->status = atoi(ptrbuf);
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2)) != 2) {
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
response_append(wsgi_req->protocol, wsgi_req->protocol_len);
response_append(" ", 1);
response_append((char *) http, slen);
response_append("\r\n", 2);
// transform the first 3 bytes of the string in a number
wsgi_req->status = uwsgi_str3_num((char *)http);
}
else {
raw = 1;
wsgi_req->status = -1;
uwsgi_log("[uwsgi-lua] invalid response status !!!\n");
// let's continue
}
// send headers
@@ -506,42 +493,23 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
lua_pushnil(L);
while(lua_next(L, -3) != 0) {
http = lua_tolstring(L, -2, &slen);
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
lua_pop(L, 2);
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, ": ", 2)) != 2) {
lua_pop(L, 2);
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
response_append_header((char *)http, slen);
response_append_header(": ", 2);
http = lua_tolstring(L, -1, &slen);
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
lua_pop(L, 2);
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2)) != 2) {
lua_pop(L, 2);
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
response_append_header((char *)http, slen);
response_append_header("\r\n", 2);
lua_pop(L, 1);
wsgi_req->header_cnt++;
}
if (!raw) {
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2)) != 2) {
lua_pushvalue(L, -1);
goto clear;
}
wsgi_req->headers_size += rlen;
}
response_append("\r\n", 2);
wsgi_req->headers_size = wsgi_req->socket->proto_write_header(wsgi_req, status_and_headers->buf, status_and_headers->pos);
uwsgi_buffer_destroy(status_and_headers);
// send body with coroutine
lua_pushvalue(L, -1);
@@ -566,7 +534,6 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
}
clear:
lua_pop(L, 4);
clear2:
+1 -1
View File
@@ -3,7 +3,7 @@ import os,sys
try:
LUALIB = os.environ['UWSGICONFIG_LUALIB']
except:
LUALIB = 'lua'
LUALIB = 'lua5.1'
try:
LUAINC = os.environ['UWSGICONFIG_LUAINC']
+164
View File
@@ -0,0 +1,164 @@
#include "../../uwsgi.h"
extern struct uwsgi_server uwsgi;
struct uwsgi_mongodb_header {
int32_t len;
int32_t request_id;
int32_t response_id;
int32_t opcode;
};
struct uwsgi_mongodb_state {
int fd;
char *address;
int32_t base_len;
struct uwsgi_mongodb_header header;
int32_t flags;
char *collection;
int32_t bson_base_len;
int32_t bson_len;
int64_t ts;
int32_t bson_node_len;
char *bson_node;
int32_t bson_msg_len;
struct iovec iovec[13];
};
ssize_t uwsgi_mongodb_logger(struct uwsgi_logger *ul, char *message, size_t len) {
struct uwsgi_mongodb_state *ums = NULL;
if (!ul->configured) {
ul->data = uwsgi_calloc(sizeof(struct uwsgi_mongodb_state));
ums = (struct uwsgi_mongodb_state *) ul->data;
// full default
if (ul->arg == NULL) {
ums->address = uwsgi_str("127.0.0.1:27017");
ums->collection = "uwsgi.logs";
ums->bson_node = uwsgi.hostname;
ums->bson_node_len = uwsgi.hostname_len;
goto done;
}
ums->address = uwsgi_str(ul->arg);
char *collection = strchr(ums->address, ',');
// default to uwsgi.logs
if (!collection) {
ums->collection = "uwsgi.logs";
ums->bson_node = uwsgi.hostname;
ums->bson_node_len = uwsgi.hostname_len;
goto done;
}
*collection = 0;
ums->collection = collection+1;
char *node = strchr(ums->collection, ',');
// default to hostname
if (!node) {
ums->bson_node = uwsgi.hostname;
ums->bson_node_len = uwsgi.hostname_len;
goto done;
}
*node = 0;
ums->bson_node = node+1;
ums->bson_node_len = strlen(ums->bson_node)+1;
done:
ums->fd = -1;
// header
ums->iovec[0].iov_base = &ums->header;
ums->iovec[0].iov_len = sizeof(struct uwsgi_mongodb_header);
// OPCODE INSERT
ums->header.opcode = 2002;
// flags
ums->iovec[1].iov_base = &ums->flags;
ums->iovec[1].iov_len = sizeof(int32_t);
// collection name
ums->iovec[2].iov_base = ums->collection;
ums->iovec[2].iov_len = strlen(ums->collection)+1;
// BSON len
ums->iovec[3].iov_base = &ums->bson_len;
ums->iovec[3].iov_len = sizeof(int32_t);
// BSON node
ums->iovec[4].iov_base = "\x02node\0";
ums->iovec[4].iov_len = 6;
ums->iovec[5].iov_base = &ums->bson_node_len;
ums->iovec[5].iov_len = sizeof(int32_t);
ums->iovec[6].iov_base = ums->bson_node;
ums->iovec[6].iov_len = ums->bson_node_len;
// BSON timestamp (ts)
ums->iovec[7].iov_base = "\x09ts\0";
ums->iovec[7].iov_len = 4;
ums->iovec[8].iov_base = &ums->ts;
ums->iovec[8].iov_len = sizeof(int64_t);
// BSON msg
ums->iovec[9].iov_base = "\2msg\0";
ums->iovec[9].iov_len = 5;
ums->iovec[10].iov_base = &ums->bson_msg_len;
ums->iovec[10].iov_len = sizeof(int32_t);
// iov 11 is reset at each cycle
// ...
// BSON end (msg_zero + bson_zero);
ums->iovec[12].iov_base = "\0\0";
ums->iovec[12].iov_len = 2;
ums->bson_base_len = ums->iovec[3].iov_len + ums->iovec[4].iov_len + ums->iovec[5].iov_len + ums->iovec[6].iov_len +
ums->iovec[7].iov_len + ums->iovec[8].iov_len + ums->iovec[9].iov_len + ums->iovec[10].iov_len +
ums->iovec[12].iov_len;
ums->base_len = ums->iovec[0].iov_len + ums->iovec[1].iov_len + ums->iovec[2].iov_len + ums->bson_base_len;
ul->configured = 1;
}
ums = (struct uwsgi_mongodb_state *) ul->data;
if (ums->fd == -1) {
ums->fd = uwsgi_connect(ums->address, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
}
if (ums->fd == -1) return -1;
// fix the packet
ums->bson_msg_len = len+1;
ums->bson_len = ums->bson_base_len + len;
ums->header.len = ums->base_len + len;
ums->header.request_id++;
// get milliseconds time
ums->ts = uwsgi_micros()/1000;
ums->iovec[11].iov_base = message;
ums->iovec[11].iov_len = len;
ssize_t ret = writev(ums->fd, ums->iovec, 13);
if (ret <= 0) {
close(ums->fd);
ums->fd = -1;
return -1;
}
return ret;
}
void uwsgi_mongodblog_register() {
uwsgi_register_logger("mongodblog", uwsgi_mongodb_logger);
}
struct uwsgi_plugin mongodblog_plugin = {
.name = "mongodblog",
.on_load = uwsgi_mongodblog_register,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='mongodblog'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['mongodblog_plugin']
+21 -1
View File
@@ -18,6 +18,7 @@ static sapi_module_struct uwsgi_sapi_module;
struct uwsgi_php {
struct uwsgi_string_list *allowed_docroot;
struct uwsgi_string_list *allowed_ext;
struct uwsgi_string_list *allowed_scripts;
struct uwsgi_string_list *index;
struct uwsgi_string_list *set;
struct uwsgi_string_list *append_config;
@@ -45,6 +46,7 @@ struct uwsgi_option uwsgi_php_options[] = {
{"php-docroot", required_argument, 0, "force php DOCUMENT_ROOT", uwsgi_opt_set_str, &uphp.docroot, 0},
{"php-allowed-docroot", required_argument, 0, "list the allowed document roots", uwsgi_opt_add_string_list, &uphp.allowed_docroot, 0},
{"php-allowed-ext", required_argument, 0, "list the allowed php file extensions", uwsgi_opt_add_string_list, &uphp.allowed_ext, 0},
{"php-allowed-script", required_argument, 0, "list the allowed php scripts (require absolute path)", uwsgi_opt_add_string_list, &uphp.allowed_scripts, 0},
{"php-server-software", required_argument, 0, "force php SERVER_SOFTWARE", uwsgi_opt_set_str, &uphp.server_software, 0},
{"php-app", required_argument, 0, "force the php file to run at each request", uwsgi_opt_set_str, &uphp.app, 0},
{"php-dump-config", no_argument, 0, "dump php config (if modified via --php-set or append options)", uwsgi_opt_true, &uphp.dump_config, 0},
@@ -208,7 +210,7 @@ static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers)
static int sapi_uwsgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
{
uint read_bytes = 0;
size_t len;
ssize_t len;
int fd = -1;
struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);
@@ -498,6 +500,7 @@ PHP_FUNCTION(uwsgi_rpc) {
argvs[i] = Z_STRLEN_P(z_current_obj);
}
// response must always be freed
char *response = uwsgi_do_rpc(node, func, num_args - 2, argv, argvs, &size);
if (size > 0) {
@@ -506,6 +509,7 @@ PHP_FUNCTION(uwsgi_rpc) {
free(response);
RETURN_STRING(ret, 0);
}
free(response);
clear:
efree(varargs);
@@ -872,6 +876,22 @@ secure2:
wsgi_req->file = real_filename;
wsgi_req->file_len = strlen(wsgi_req->file);
if (uphp.allowed_scripts) {
struct uwsgi_string_list *usl = uphp.allowed_scripts;
while(usl) {
if (!uwsgi_strncmp(wsgi_req->file, wsgi_req->file_len, usl->value, usl->len)) {
goto secure3;
}
usl = usl->next;
}
uwsgi_php_403(wsgi_req);
uwsgi_log("PHP security error: %s is not an allowed script\n", real_filename);
return -1;
}
secure3:
if (wsgi_req->document_root[wsgi_req->document_root_len-1] == '/') {
wsgi_req->script_name = real_filename + (wsgi_req->document_root_len-1);
}
+51 -11
View File
@@ -297,6 +297,12 @@ SV *build_psgi_env(struct wsgi_request *wsgi_req) {
if (!hv_store(env, "psgix.harakiri", 14, newSViv(1), 0)) goto clear;
}
if (!hv_store(env, "psgix.cleanup", 13, newSViv(1), 0)) goto clear;
// cleanup handlers array
av = newAV();
if (!hv_store(env, "psgix.cleanup.handlers", 22, newRV_noinc((SV *)av ), 0)) goto clear;
SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12);
if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear;
@@ -364,9 +370,9 @@ int uwsgi_perl_init(){
}
#ifdef PERL_VERSION_STRING
uwsgi_log("initialized Perl %s main interpreter at %p\n", PERL_VERSION_STRING, uperl.main[0]);
uwsgi_log_initial("initialized Perl %s main interpreter at %p\n", PERL_VERSION_STRING, uperl.main[0]);
#else
uwsgi_log("initialized Perl main interpreter at %p\n", uperl.main[0]);
uwsgi_log_initial("initialized Perl main interpreter at %p\n", uperl.main[0]);
#endif
return 1;
@@ -375,8 +381,6 @@ int uwsgi_perl_init(){
int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
SV **harakiri;
#ifdef UWSGI_ASYNC
if (wsgi_req->async_status == UWSGI_AGAIN) {
return psgi_response(wsgi_req, wsgi_req->async_placeholder);
@@ -457,13 +461,7 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
}
clear2:
// check for psgix.harakiri
harakiri = hv_fetch((HV*)SvRV( (SV*)wsgi_req->async_environ), "psgix.harakiri.commit", 21, 0);
if (harakiri) {
if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1;
}
SvREFCNT_dec(wsgi_req->async_environ);
// clear response
SvREFCNT_dec(wsgi_req->async_result);
clear:
@@ -478,16 +476,58 @@ clear:
return UWSGI_OK;
}
static void psgi_call_cleanup_hook(SV *hook, SV *env) {
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(env);
PUTBACK;
call_sv(hook, G_DISCARD);
if(SvTRUE(ERRSV)) {
uwsgi_log("[uwsgi-perl error] %s\n", SvPV_nolen(ERRSV));
}
FREETMPS;
LEAVE;
}
void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
// dereference %env
SV *env = SvRV((SV *) wsgi_req->async_environ);
// check for cleanup handlers
if (hv_exists((HV *)env, "psgix.cleanup.handlers", 22)) {
SV **cleanup_handlers = hv_fetch((HV *)env, "psgix.cleanup.handlers", 22, 0);
if (SvROK(*cleanup_handlers)) {
if (SvTYPE(SvRV(*cleanup_handlers)) == SVt_PVAV) {
I32 n = av_len((AV *)SvRV(*cleanup_handlers));
I32 i;
for(i=0;i<=n;i++) {
SV **hook = av_fetch((AV *)SvRV(*cleanup_handlers), i, 0);
psgi_call_cleanup_hook(*hook, (SV *) wsgi_req->async_environ);
}
}
}
}
// check for psgix.harakiri
if (hv_exists((HV *)env, "psgix.harakiri.commit", 21)) {
SV **harakiri = hv_fetch((HV *)env, "psgix.harakiri.commit", 21, 0);
if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1;
}
// async plagued could be defined in other areas...
if (wsgi_req->async_plagued) {
uwsgi_log("*** psgix.harakiri.commit requested ***\n");
goodbye_cruel_world();
}
// clear the env
SvREFCNT_dec(wsgi_req->async_environ);
}
int uwsgi_perl_magic(char *mountpoint, char *lazy) {
+2
View File
@@ -190,6 +190,7 @@ XS(XS_call) {
argvs[i] = arg_len;
}
// response must be always freed
char *response = uwsgi_do_rpc(NULL, func, items-1, argv, argvs, &size);
if (size > 0) {
@@ -198,6 +199,7 @@ XS(XS_call) {
free(response);
XSRETURN(1);
}
free(response);
XSRETURN_UNDEF;
}
+4 -4
View File
@@ -13,9 +13,7 @@ extern struct uwsgi_python up;
extern char **environ;
#ifdef UWSGI_SENDFILE
PyMethodDef uwsgi_sendfile_method[] = {{"uwsgi_sendfile", py_uwsgi_sendfile, METH_VARARGS, ""}};
#endif
#ifdef UWSGI_ASYNC
PyMethodDef uwsgi_eventfd_read_method[] = { {"uwsgi_eventfd_read", py_eventfd_read, METH_VARARGS, ""}};
@@ -331,10 +329,8 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
#endif
if (app_type == PYTHON_APP_TYPE_WSGI) {
#ifdef UWSGI_SENDFILE
// prepare sendfile() for WSGI app
wi->sendfile = PyCFunction_New(uwsgi_sendfile_method, NULL);
#endif
#ifdef UWSGI_ASYNC
wi->eventfd_read = PyCFunction_New(uwsgi_eventfd_read_method, NULL);
@@ -483,7 +479,9 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
PyObject *tmp_callable;
PyObject *applications;
#ifdef UWSGI_EMBEDDED
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
#endif
char *module = (char *) arg1;
@@ -506,8 +504,10 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
return NULL;
}
#ifdef UWSGI_EMBEDDED
applications = PyDict_GetItemString(uwsgi_dict, "applications");
if (applications && PyDict_Check(applications)) return applications;
#endif
applications = PyDict_GetItemString(wsgi_dict, "applications");
if (applications && PyDict_Check(applications)) return applications;
+55 -9
View File
@@ -9,6 +9,12 @@ extern struct http_status_codes hsc[];
extern PyTypeObject uwsgi_InputType;
void python_simple_hook_write_string(struct wsgi_request *wsgi_req, PyObject *str) {
UWSGI_RELEASE_GIL
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(str), PyString_Size(str));
UWSGI_GET_GIL
}
void uwsgi_opt_pythonpath(char *opt, char *value, void *foobar) {
int i;
@@ -71,6 +77,8 @@ struct uwsgi_option uwsgi_python_options[] = {
{"virtualenv", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0},
{"venv", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0},
{"pyhome", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0},
{"py-programname", required_argument, 0, "set python program name", uwsgi_opt_set_str, &up.programname, 0},
{"py-program-name", required_argument, 0, "set python program name", uwsgi_opt_set_str, &up.programname, 0},
{"pythonpath", required_argument, 0, "add directory (or glob) to pythonpath", uwsgi_opt_pythonpath, NULL, 0},
{"python-path", required_argument, 0, "add directory (or glob) to pythonpath", uwsgi_opt_pythonpath, NULL, 0},
@@ -169,6 +177,16 @@ int uwsgi_python_init() {
if (up.home != NULL) {
#ifdef PYTHREE
// check for PEP 405 virtualenv (starting from python 3.3)
char *pep405_env = uwsgi_concat2(up.home, "/pyvenv.cfg");
if (uwsgi_file_exists(pep405_env)) {
uwsgi_log("PEP 405 virtualenv detected: %s\n", up.home);
free(pep405_env);
goto pep405;
}
free(pep405_env);
// build the PYTHONHOME wchar path
wchar_t *wpyhome;
size_t len = strlen(up.home) + 1;
wpyhome = uwsgi_calloc(sizeof(wchar_t) * len );
@@ -180,19 +198,30 @@ int uwsgi_python_init() {
Py_SetPythonHome(wpyhome);
// do not free this memory !!!
//free(wpyhome);
pep405:
#else
Py_SetPythonHome(up.home);
#endif
uwsgi_log("Set PythonHome to %s\n", up.home);
}
char *program_name = up.programname;
if (!program_name) {
program_name = uwsgi.binary_path;
}
#ifdef PYTHREE
wchar_t pname[6];
mbstowcs(pname, "uWSGI", 6);
if (!up.programname) {
if (up.home) {
program_name = uwsgi_concat2(up.home, "/bin/python");
}
}
wchar_t *pname = uwsgi_calloc(sizeof(wchar_t) * (strlen(program_name)+1));
mbstowcs(pname, program_name, strlen(program_name)+1);
Py_SetProgramName(pname);
#else
Py_SetProgramName("uWSGI");
Py_SetProgramName(program_name);
#endif
@@ -203,12 +232,16 @@ int uwsgi_python_init() {
Py_Initialize();
if (!uwsgi.has_threads) {
uwsgi_log("*** Python threads support is disabled. You can enable it with --enable-threads ***\n");
uwsgi_log_initial("*** Python threads support is disabled. You can enable it with --enable-threads ***\n");
}
up.wsgi_spitout = PyCFunction_New(uwsgi_spit_method, NULL);
up.wsgi_writeout = PyCFunction_New(uwsgi_write_method, NULL);
up.hook_write_string = python_simple_hook_write_string;
up.hook_wsgi_input_read = uwsgi_python_hook_simple_input_read;
up.hook_wsgi_input_readline = uwsgi_python_hook_simple_input_readline;
up.main_thread = PyThreadState_Get();
// by default set a fake GIL (little impact on performance)
@@ -279,9 +312,11 @@ realstuff:
return;
}
if (uwsgi.has_threads)
PyGILState_Ensure();
// always call it
PyGILState_Ensure();
// no need to worry about freeing memory
#ifdef UWSGI_EMBEDDED
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
@@ -289,6 +324,7 @@ realstuff:
python_call(ae, PyTuple_New(0), 0, NULL);
}
}
#endif
// this part is a 1:1 copy of mod_wsgi 3.x
// it is required to fix some atexit bug with python 3
@@ -528,8 +564,6 @@ next:
#ifdef UWSGI_EMBEDDED
PyDoc_STRVAR(uwsgi_py_doc, "uWSGI api module.");
#endif
#ifdef PYTHREE
static PyModuleDef uwsgi_module3 = {
@@ -544,7 +578,6 @@ PyObject *init_uwsgi3(void) {
}
#endif
#ifdef UWSGI_EMBEDDED
void init_uwsgi_embedded_module() {
PyObject *new_uwsgi_module, *zero;
int i;
@@ -1050,6 +1083,11 @@ void uwsgi_python_init_apps() {
struct http_status_codes *http_sc;
// lazy ?
if (uwsgi.mywid > 0) {
UWSGI_GET_GIL;
}
#ifndef UWSGI_PYPY
// prepare for stack suspend/resume
if (uwsgi.async > 1) {
@@ -1160,6 +1198,7 @@ next:
}
#endif
#ifdef UWSGI_EMBEDDED
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
up.after_req_hook = PyDict_GetItemString(uwsgi_dict, "after_req_hook");
@@ -1169,6 +1208,12 @@ next:
Py_INCREF(up.after_req_hook_args);
}
}
#endif
// lazy ?
if (uwsgi.mywid > 0) {
UWSGI_RELEASE_GIL;
}
}
@@ -1295,6 +1340,7 @@ int uwsgi_check_python_mtime(PyObject *times_dict, char *filename) {
}
PyObject *uwsgi_python_setup_thread(char *name) {
// block signals on this thread
sigset_t smask;
sigfillset(&smask);
+11 -4
View File
@@ -28,10 +28,12 @@ char *uwsgi_python_get_thread_name(PyObject *thread_id) {
PyObject *thread_name = PyObject_GetAttrString(threads_list_next, "name");
if (!thread_name) goto clear2;
char *name = PyString_AsString(thread_name);
Py_DECREF(threads_list_next);
Py_DECREF(threads_list_iter);
Py_DECREF(threads_list);
return name;
}
Py_DECREF(threads_list_next);
threads_list_next = PyIter_Next(threads_list_iter);
}
@@ -110,22 +112,23 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
PyObject *arg_tuple = PyTuple_New(1);
PyTuple_SetItem(arg_tuple, 0, stack);
Py_INCREF(stack);
PyObject *stacktrace = PyEval_CallObject( extract_stack, arg_tuple);
Py_DECREF(arg_tuple);
if (!stacktrace) goto next2;
PyObject *stacktrace_iter = PyObject_GetIter(stacktrace);
if (!stacktrace_iter) goto next2;
if (!stacktrace_iter) { Py_DECREF(stacktrace); goto next2;}
PyObject *st_items = PyIter_Next(stacktrace_iter);
// we have the first traceback item
while(st_items) {
PyObject *st_filename = PyTuple_GetItem(st_items, 0);
if (!st_filename) goto next;
if (!st_filename) { Py_DECREF(st_items); goto next; }
PyObject *st_lineno = PyTuple_GetItem(st_items, 1);
if (!st_lineno) goto next;
if (!st_lineno) {Py_DECREF(st_items); goto next;}
PyObject *st_name = PyTuple_GetItem(st_items, 2);
if (!st_name) goto next;
if (!st_name) {Py_DECREF(st_items); goto next;}
PyObject *st_line = PyTuple_GetItem(st_items, 3);
@@ -178,6 +181,7 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
// free the line_no
free(iov[5].iov_base);
Py_DECREF(st_items);
st_items = PyIter_Next(stacktrace_iter);
}
if (write(client_fd, "\n", 1) < 0) {
@@ -185,10 +189,13 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
}
next:
Py_DECREF(stacktrace_iter);
Py_DECREF(stacktrace);
next2:
Py_DECREF(frame);
frame = PyIter_Next(frames_iter);
}
Py_DECREF(frames_iter);
end4:
Py_DECREF(frames_ret);
end3:
+269 -13
View File
@@ -10,7 +10,7 @@ PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
struct wsgi_request *wsgi_req = current_wsgi_req();
int wait_for_specific_signal = 0;
uint8_t uwsgi_signal = 0;
uint8_t received_signal;
int received_signal;
wsgi_req->signal_received = -1;
@@ -30,6 +30,11 @@ PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
received_signal = uwsgi_signal_wait(-1);
}
if (received_signal < 0) {
UWSGI_GET_GIL;
return PyErr_Format(PyExc_SystemError, "error waiting for signal");
}
wsgi_req->signal_received = received_signal;
UWSGI_GET_GIL;
@@ -313,6 +318,7 @@ PyObject *py_uwsgi_call(PyObject * self, PyObject * args) {
}
UWSGI_RELEASE_GIL;
// response must always be freed
char *response = uwsgi_do_rpc(NULL, func, argc - 1, argv, argvs, &size);
UWSGI_GET_GIL;
@@ -322,6 +328,7 @@ PyObject *py_uwsgi_call(PyObject * self, PyObject * args) {
return ret;
}
free(response);
Py_INCREF(Py_None);
return Py_None;
@@ -776,7 +783,36 @@ PyObject *py_uwsgi_send(PyObject * self, PyObject * args) {
}
#ifdef UWSGI_SENDFILE
PyObject *py_uwsgi_offload_transfer(PyObject * self, PyObject * args) {
size_t len = 0;
char *filename = NULL;
struct wsgi_request *wsgi_req = current_wsgi_req();
if (!PyArg_ParseTuple(args, "s|i:offload_transfer", &filename, &len)) {
return NULL;
}
if (!wsgi_req->socket->can_offload) {
return PyErr_Format(PyExc_ValueError, "The current socket does not support offloading");
}
if (!wsgi_req->headers_sent) {
if (uwsgi_python_do_send_headers(wsgi_req)) {
return PyErr_Format(PyExc_ValueError, "unable to send headers before offload transfer");
}
}
UWSGI_RELEASE_GIL
if (uwsgi_offload_request_do(wsgi_req, filename, len)) {
UWSGI_GET_GIL
return PyErr_Format(PyExc_ValueError, "Unable to offload the request");
}
UWSGI_GET_GIL
return PyString_FromString("");
}
PyObject *py_uwsgi_advanced_sendfile(PyObject * self, PyObject * args) {
PyObject *what;
@@ -868,7 +904,6 @@ PyObject *py_uwsgi_advanced_sendfile(PyObject * self, PyObject * args) {
return Py_None;
}
#endif
#ifdef UWSGI_ASYNC
@@ -3169,9 +3204,8 @@ static PyMethodDef uwsgi_advanced_methods[] = {
{"rpc", py_uwsgi_rpc, METH_VARARGS, ""},
{"rpc_list", py_uwsgi_rpc_list, METH_VARARGS, ""},
{"call", py_uwsgi_call, METH_VARARGS, ""},
#ifdef UWSGI_SENDFILE
{"sendfile", py_uwsgi_advanced_sendfile, METH_VARARGS, ""},
#endif
{"offload_transfer", py_uwsgi_offload_transfer, METH_VARARGS, ""},
{"set_warning_message", py_uwsgi_warning, METH_VARARGS, ""},
{"mem", py_uwsgi_mem, METH_VARARGS, ""},
{"has_hook", py_uwsgi_has_hook, METH_VARARGS, ""},
@@ -3890,7 +3924,7 @@ void init_uwsgi_module_sharedarea(PyObject * current_uwsgi_module) {
}
#ifdef UWSGI_SNMP
PyObject *py_snmp_counter32(PyObject * self, PyObject * args) {
PyObject *py_snmp_set_counter32(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint32_t oid_val = 0;
@@ -3902,9 +3936,15 @@ PyObject *py_snmp_counter32(PyObject * self, PyObject * args) {
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER32;
uwsgi.shared->snmp_value[oid_num - 1].val = oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
@@ -3914,7 +3954,7 @@ clear:
return Py_None;
}
PyObject *py_snmp_counter64(PyObject * self, PyObject * args) {
PyObject *py_snmp_set_counter64(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint64_t oid_val = 0;
@@ -3926,9 +3966,15 @@ PyObject *py_snmp_counter64(PyObject * self, PyObject * args) {
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER64;
uwsgi.shared->snmp_value[oid_num - 1].val = oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
@@ -3938,7 +3984,7 @@ clear:
return Py_None;
}
PyObject *py_snmp_gauge(PyObject * self, PyObject * args) {
PyObject *py_snmp_set_gauge(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint32_t oid_val = 0;
@@ -3950,9 +3996,15 @@ PyObject *py_snmp_gauge(PyObject * self, PyObject * args) {
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_GAUGE;
uwsgi.shared->snmp_value[oid_num - 1].val = oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
@@ -3962,7 +4014,205 @@ clear:
return Py_None;
}
PyObject *py_snmp_community(PyObject * self, PyObject * args) {
PyObject *py_snmp_incr_counter32(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint32_t oid_val = 1;
if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter32", &oid_num, &oid_val)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "b:snmp_incr_counter32", &oid_num)) {
return NULL;
}
}
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER32;
uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val + oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
clear:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_snmp_incr_counter64(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint64_t oid_val = 1;
if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter64", &oid_num, &oid_val)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "b:snmp_incr_counter64", &oid_num)) {
return NULL;
}
}
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER64;
uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val + oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
clear:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_snmp_incr_gauge(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint64_t oid_val = 1;
if (!PyArg_ParseTuple(args, "bI:snmp_incr_gauge", &oid_num, &oid_val)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "b:snmp_incr_gauge", &oid_num)) {
return NULL;
}
}
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_GAUGE;
uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val + oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
clear:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_snmp_decr_counter32(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint32_t oid_val = 1;
if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter32", &oid_num, &oid_val)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "b:snmp_incr_counter32", &oid_num)) {
return NULL;
}
}
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER32;
uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val - oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
clear:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_snmp_decr_counter64(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint64_t oid_val = 1;
if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter64", &oid_num, &oid_val)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "b:snmp_incr_counter64", &oid_num)) {
return NULL;
}
}
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER64;
uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val - oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
clear:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_snmp_decr_gauge(PyObject * self, PyObject * args) {
uint8_t oid_num;
uint64_t oid_val = 1;
if (!PyArg_ParseTuple(args, "bI:snmp_incr_gauge", &oid_num, &oid_val)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "b:snmp_incr_gauge", &oid_num)) {
return NULL;
}
}
if (oid_num > 100 || oid_num < 1)
goto clear;
UWSGI_RELEASE_GIL
uwsgi_wlock(uwsgi.snmp_lock);
uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_GAUGE;
uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val - oid_val;
uwsgi_rwunlock(uwsgi.snmp_lock);
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
clear:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_snmp_set_community(PyObject * self, PyObject * args) {
char *snmp_community;
@@ -3985,10 +4235,16 @@ PyObject *py_snmp_community(PyObject * self, PyObject * args) {
static PyMethodDef uwsgi_snmp_methods[] = {
{"snmp_set_counter32", py_snmp_counter32, METH_VARARGS, ""},
{"snmp_set_counter64", py_snmp_counter64, METH_VARARGS, ""},
{"snmp_set_gauge", py_snmp_gauge, METH_VARARGS, ""},
{"snmp_set_community", py_snmp_community, METH_VARARGS, ""},
{"snmp_set_counter32", py_snmp_set_counter32, METH_VARARGS, ""},
{"snmp_set_counter64", py_snmp_set_counter64, METH_VARARGS, ""},
{"snmp_set_gauge", py_snmp_set_gauge, METH_VARARGS, ""},
{"snmp_incr_counter32", py_snmp_incr_counter32, METH_VARARGS, ""},
{"snmp_incr_counter64", py_snmp_incr_counter64, METH_VARARGS, ""},
{"snmp_incr_gauge", py_snmp_incr_gauge, METH_VARARGS, ""},
{"snmp_decr_counter32", py_snmp_decr_counter32, METH_VARARGS, ""},
{"snmp_decr_counter64", py_snmp_decr_counter64, METH_VARARGS, ""},
{"snmp_decr_gauge", py_snmp_decr_gauge, METH_VARARGS, ""},
{"snmp_set_community", py_snmp_set_community, METH_VARARGS, ""},
{NULL, NULL},
};
+8 -2
View File
@@ -186,6 +186,11 @@ struct uwsgi_python {
char *pyrun;
int start_response_nodelay;
void (*hook_write_string)(struct wsgi_request *, PyObject *);
ssize_t (*hook_wsgi_input_read)(struct wsgi_request *, char *, size_t, size_t *);
ssize_t (*hook_wsgi_input_readline)(struct wsgi_request *, char *, size_t);
char *programname;
};
@@ -210,9 +215,7 @@ int manage_python_response(struct wsgi_request *);
int uwsgi_python_call(struct wsgi_request *, PyObject *, PyObject *);
PyObject *python_call(PyObject *, PyObject *, int, struct wsgi_request *);
#ifdef UWSGI_SENDFILE
PyObject *py_uwsgi_sendfile(PyObject *, PyObject *);
#endif
PyObject *py_uwsgi_write(PyObject *, PyObject *);
PyObject *py_uwsgi_spit(PyObject *, PyObject *);
@@ -278,6 +281,9 @@ int uwsgi_python_do_send_headers(struct wsgi_request *);
void *uwsgi_python_tracebacker_thread(void *);
PyObject *uwsgi_python_setup_thread(char *);
ssize_t uwsgi_python_hook_simple_input_read(struct wsgi_request *, char *, size_t, size_t *);
ssize_t uwsgi_python_hook_simple_input_readline(struct wsgi_request *, char *, size_t);
#ifdef UWSGI_PYPY
#undef UWSGI_MINTERPRETERS
#endif
+62 -39
View File
@@ -9,6 +9,24 @@ PyObject *uwsgi_Input_iter(PyObject *self) {
return self;
}
ssize_t uwsgi_python_hook_simple_input_readline(struct wsgi_request *wsgi_req, char *readline, size_t max_size) {
ssize_t rlen = 0;
UWSGI_RELEASE_GIL;
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
UWSGI_GET_GIL
return 0;
}
if (max_size > 0 && max_size < UWSGI_PY_READLINE_BUFSIZE) {
rlen = read(wsgi_req->poll.fd, readline, max_size);
}
else {
rlen = read(wsgi_req->poll.fd, readline, UWSGI_PY_READLINE_BUFSIZE);
}
UWSGI_GET_GIL;
return rlen;
}
PyObject *uwsgi_Input_getline(uwsgi_Input *self) {
size_t i;
ssize_t rlen;
@@ -40,29 +58,18 @@ PyObject *uwsgi_Input_getline(uwsgi_Input *self) {
}
UWSGI_RELEASE_GIL;
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
UWSGI_GET_GIL
rlen = up.hook_wsgi_input_readline(wsgi_req, self->readline, self->readline_max_size);
if (rlen < 0) {
return PyErr_Format(PyExc_IOError, "error reading for wsgi.input data (readline/getline)");
}
else if (rlen == 0) {
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data (readline/getline)");
}
if (self->readline_max_size > 0 && self->readline_max_size < UWSGI_PY_READLINE_BUFSIZE) {
rlen = read(wsgi_req->poll.fd, self->readline, self->readline_max_size);
}
else {
rlen = read(wsgi_req->poll.fd, self->readline, UWSGI_PY_READLINE_BUFSIZE);
}
if (rlen <= 0) {
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data (readline/getline)");
}
self->readline_size = rlen;
self->readline_pos = 0;
self->pos += rlen;
UWSGI_GET_GIL;
for(i=0;i<(size_t)rlen;i++) {
if (self->readline[i] == '\n') {
res = PyString_FromStringAndSize(self->readline, i+1);
@@ -91,11 +98,35 @@ static void uwsgi_Input_free(uwsgi_Input *self) {
PyObject_Del(self);
}
ssize_t uwsgi_python_hook_simple_input_read(struct wsgi_request *wsgi_req, char *tmp_buf, size_t remains, size_t *tmp_pos) {
UWSGI_RELEASE_GIL
while(remains) {
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
UWSGI_GET_GIL
return 0;
}
ssize_t rlen = read(wsgi_req->poll.fd, tmp_buf+*tmp_pos, remains);
if (rlen <= 0) {
UWSGI_GET_GIL
return -1;
}
*tmp_pos += rlen;
remains -= rlen;
}
UWSGI_GET_GIL
return *tmp_pos;
}
static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
long len = 0;
size_t remains, tmp_pos = 0;
ssize_t rlen;
size_t remains;
size_t tmp_pos = 0;
char *tmp_buf;
PyObject *res;
@@ -144,28 +175,18 @@ static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
return res;
}
UWSGI_RELEASE_GIL
tmp_buf = uwsgi_malloc(remains);
while(remains) {
if (uwsgi_waitfd(self->wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
free(tmp_buf);
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data: Content-Length %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) self->wsgi_req->post_cl - remains);
}
rlen = read(self->wsgi_req->poll.fd, tmp_buf+tmp_pos, remains);
if (rlen <= 0) {
free(tmp_buf);
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data: Content-Length %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) self->wsgi_req->post_cl - remains);
}
tmp_pos += rlen;
remains -= rlen;
ssize_t rlen = up.hook_wsgi_input_read(self->wsgi_req, tmp_buf, remains, &tmp_pos);
if (rlen < 0) {
free(tmp_buf);
return PyErr_Format(PyExc_IOError, "error reading for wsgi.input data: Content-Length %llu requested %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) (remains + tmp_pos), (unsigned long long) tmp_pos);
}
else if (tmp_pos == 0) {
free(tmp_buf);
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data: Content-Length %llu requested %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) (remains + tmp_pos), (unsigned long long) tmp_pos);
}
UWSGI_GET_GIL
self->pos += tmp_pos;
res = PyString_FromStringAndSize(tmp_buf, tmp_pos);
free(tmp_buf);
@@ -395,7 +416,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
}
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, 0)) == -1) {
wsgi_req->app_id = uwsgi.default_app;
if (uwsgi.no_default_app) {
@@ -433,6 +453,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
wi = &uwsgi_apps[wsgi_req->app_id];
up.swap_ts(wsgi_req, wi);
if (wi->chdir[0] != 0) {
#ifdef UWSGI_DEBUG
@@ -452,8 +473,10 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
// create WSGI environ
wsgi_req->async_environ = up.wsgi_env_create(wsgi_req, wi);
wsgi_req->async_result = wi->request_subhandler(wsgi_req, wi);
if (wsgi_req->async_result) {
@@ -510,7 +533,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
}
// this object must be freed/cleared always
#ifdef UWSGI_ASYNC
end:
#endif
if (wsgi_req->async_input) {
Py_DECREF((PyObject *)wsgi_req->async_input);
}
@@ -553,7 +578,6 @@ void uwsgi_after_request_wsgi(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
#ifdef UWSGI_SENDFILE
PyObject *py_uwsgi_sendfile(PyObject * self, PyObject * args) {
struct wsgi_request *wsgi_req = current_wsgi_req();
@@ -578,7 +602,6 @@ PyObject *py_uwsgi_sendfile(PyObject * self, PyObject * args) {
Py_INCREF((PyObject *) wsgi_req->sendfile_obj);
return (PyObject *) wsgi_req->sendfile_obj;
}
#endif
void threaded_swap_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
+34 -4
View File
@@ -35,6 +35,13 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->headers = NULL;
}
#ifdef PYTHREE
if (wsgi_req->gc_tracker) {
Py_DECREF((PyObject *)wsgi_req->gc_tracker);
wsgi_req->gc_tracker = NULL;
}
#endif
// this must be done before headers management
if (PyTuple_Size(args) > 2) {
exc_info = PyTuple_GetItem(args, 2);
@@ -72,6 +79,10 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
return PyErr_Format(PyExc_TypeError, "http status must be a string");
}
#ifdef PYTHREE
// this list maintains reference to encoded strings.. ugly hack, i know, but it works...
wsgi_req->gc_tracker = (void *) PyList_New(0);
#endif
if (uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] == 0) {
base = 4;
@@ -89,7 +100,10 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->hvec[1].iov_len = 1;
#ifdef PYTHREE
if (self != Py_None) {
wsgi_req->hvec[2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head));
PyObject *zero = PyUnicode_AsASCIIString(head);
wsgi_req->hvec[2].iov_base = PyBytes_AsString(zero);
PyList_Append((PyObject *) wsgi_req->gc_tracker, zero);
Py_DECREF(zero);
}
else {
wsgi_req->hvec[2].iov_base = PyBytes_AsString(head);
@@ -110,7 +124,10 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->hvec[0].iov_len = 8;
#ifdef PYTHREE
if (self != Py_None) {
wsgi_req->hvec[1].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head));
PyObject *zero = PyUnicode_AsASCIIString(head);
wsgi_req->hvec[1].iov_base = PyBytes_AsString(zero);
PyList_Append((PyObject *) wsgi_req->gc_tracker, zero);
Py_DECREF(zero);
}
else {
wsgi_req->hvec[1].iov_base = PyBytes_AsString(head);
@@ -181,7 +198,10 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
#ifdef PYTHREE
if (self != Py_None) {
wsgi_req->hvec[j].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(h_key));
PyObject *zero = PyUnicode_AsASCIIString(h_key);
wsgi_req->hvec[j].iov_base = PyBytes_AsString(zero);
PyList_Append((PyObject *) wsgi_req->gc_tracker, zero);
Py_DECREF(zero);
}
else {
wsgi_req->hvec[j].iov_base = PyBytes_AsString(h_key);
@@ -195,7 +215,10 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
wsgi_req->hvec[j + 1].iov_len = H_SEP_SIZE;
#ifdef PYTHREE
if (self != Py_None) {
wsgi_req->hvec[j + 2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(h_value));
PyObject *zero = PyUnicode_AsASCIIString(h_value);
wsgi_req->hvec[j + 2].iov_base = PyBytes_AsString(zero);
PyList_Append((PyObject *) wsgi_req->gc_tracker, zero);
Py_DECREF(zero);
}
else {
wsgi_req->hvec[j + 2].iov_base = PyBytes_AsString(h_value);
@@ -288,6 +311,13 @@ int uwsgi_python_do_send_headers(struct wsgi_request *wsgi_req) {
wsgi_req->headers = NULL;
}
#ifdef PYTHREE
if (wsgi_req->gc_tracker) {
Py_DECREF((PyObject *)wsgi_req->gc_tracker);
wsgi_req->gc_tracker = NULL;
}
#endif
if (wsgi_req->write_errors > uwsgi.write_errors_tolerance && !uwsgi.disable_write_exception) {
uwsgi_py_write_set_exception(wsgi_req);
return -1;
+22 -33
View File
@@ -6,6 +6,7 @@ extern PyTypeObject uwsgi_InputType;
void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
PyObject *zero;
int i;
PyObject *pydictkey, *pydictvalue;
@@ -69,9 +70,7 @@ void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_req->async_input);
#ifdef UWSGI_SENDFILE
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.file_wrapper", wi->sendfile);
#endif
#ifdef UWSGI_ASYNC
if (uwsgi.async > 1) {
@@ -157,22 +156,17 @@ void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_
int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
PyObject *pychunk;
#ifdef UWSGI_SENDFILE
ssize_t sf_len = 0;
#endif
// return or yield ?
if (PyString_Check((PyObject *)wsgi_req->async_result)) {
char *content = PyString_AsString(wsgi_req->async_result);
size_t content_len = PyString_Size(wsgi_req->async_result);
size_t content_len = PyString_Size((PyObject *)wsgi_req->async_result);
if (content_len > 0 && !wsgi_req->headers_sent) {
if (uwsgi_python_do_send_headers(wsgi_req)) {
goto clear;
}
}
UWSGI_RELEASE_GIL
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len);
UWSGI_GET_GIL
up.hook_write_string(wsgi_req, (PyObject *) wsgi_req->async_result);
uwsgi_py_check_write_errors {
uwsgi_py_write_exception(wsgi_req);
}
@@ -180,7 +174,6 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
}
#ifdef UWSGI_SENDFILE
#ifdef __FreeBSD__
if ( ((wsgi_req->sendfile_obj == wsgi_req->async_result) || ( wsgi_req->sendfile_fd_size > 0 && wsgi_req->response_size < wsgi_req->sendfile_fd_size)) && wsgi_req->sendfile_fd != -1) {
#else
@@ -202,8 +195,6 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
#endif
goto clear;
}
#endif
// ok its a yield
if (!wsgi_req->async_placeholder) {
@@ -234,20 +225,6 @@ exception:
exit(UWSGI_EXCEPTION_CODE);
}
}
if (PyObject_HasAttrString((PyObject *)wsgi_req->async_result, "close")) {
PyObject *close_method = PyObject_GetAttrString((PyObject *)wsgi_req->async_result, "close");
PyObject *close_method_args = PyTuple_New(0);
#ifdef UWSGI_DEBUG
uwsgi_log("calling close() for %.*s %p %p\n", wsgi_req->uri_len, wsgi_req->uri, close_method, close_method_args);
#endif
PyObject *close_method_output = PyEval_CallObject(close_method, close_method_args);
if (PyErr_Occurred()) {
PyErr_Print();
}
Py_DECREF(close_method_args);
Py_XDECREF(close_method_output);
Py_DECREF(close_method);
}
goto clear;
}
@@ -255,16 +232,13 @@ exception:
if (PyString_Check(pychunk)) {
char *content = PyString_AsString(pychunk);
size_t content_len = PyString_Size(pychunk);
if (content_len > 0 && !wsgi_req->headers_sent) {
if (uwsgi_python_do_send_headers(wsgi_req)) {
goto clear;
}
}
UWSGI_RELEASE_GIL
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len);
UWSGI_GET_GIL
up.hook_write_string(wsgi_req, pychunk);
uwsgi_py_check_write_errors {
uwsgi_py_write_exception(wsgi_req);
Py_DECREF(pychunk);
@@ -272,7 +246,6 @@ exception:
}
}
#ifdef UWSGI_SENDFILE
else if (wsgi_req->sendfile_obj == pychunk && wsgi_req->sendfile_fd != -1) {
// send the headers if not already sent
if (!wsgi_req->headers_sent && wsgi_req->headers_hvec > 0) {
@@ -282,7 +255,6 @@ exception:
if (sf_len < 1) goto clear;
wsgi_req->response_size += sf_len;
}
#endif
Py_DECREF(pychunk);
@@ -293,13 +265,30 @@ clear:
if (wsgi_req->sendfile_fd != -1) {
Py_DECREF((PyObject *)wsgi_req->async_sendfile);
}
Py_XDECREF((PyObject *)wsgi_req->async_placeholder);
// send the headers if not already sent
if (!wsgi_req->headers_sent && wsgi_req->headers_hvec > 0) {
uwsgi_python_do_send_headers(wsgi_req);
}
if (wsgi_req->async_placeholder) {
// CALL close() ALWAYS if we are working with an iterator !!!
if (PyObject_HasAttrString((PyObject *)wsgi_req->async_result, "close")) {
PyObject *close_method = PyObject_GetAttrString((PyObject *)wsgi_req->async_result, "close");
PyObject *close_method_args = PyTuple_New(0);
#ifdef UWSGI_DEBUG
uwsgi_log("calling close() for %.*s %p %p\n", wsgi_req->uri_len, wsgi_req->uri, close_method, close_method_args);
#endif
PyObject *close_method_output = PyEval_CallObject(close_method, close_method_args);
if (PyErr_Occurred()) {
PyErr_Print();
}
Py_DECREF(close_method_args);
Py_XDECREF(close_method_output);
Py_DECREF(close_method);
}
Py_DECREF((PyObject *)wsgi_req->async_placeholder);
}
Py_DECREF((PyObject *)wsgi_req->async_result);
PyErr_Clear();

Some files were not shown because too many files have changed in this diff Show More